xref: /openbsd/gnu/gcc/gcc/config/frv/frv.c (revision 404b540a)
1*404b540aSrobert /* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
2*404b540aSrobert    Free Software Foundation, Inc.
3*404b540aSrobert    Contributed by Red Hat, Inc.
4*404b540aSrobert 
5*404b540aSrobert This file is part of GCC.
6*404b540aSrobert 
7*404b540aSrobert GCC is free software; you can redistribute it and/or modify
8*404b540aSrobert it under the terms of the GNU General Public License as published by
9*404b540aSrobert the Free Software Foundation; either version 2, or (at your option)
10*404b540aSrobert any later version.
11*404b540aSrobert 
12*404b540aSrobert GCC is distributed in the hope that it will be useful,
13*404b540aSrobert but WITHOUT ANY WARRANTY; without even the implied warranty of
14*404b540aSrobert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*404b540aSrobert GNU General Public License for more details.
16*404b540aSrobert 
17*404b540aSrobert You should have received a copy of the GNU General Public License
18*404b540aSrobert along with GCC; see the file COPYING.  If not, write to
19*404b540aSrobert the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20*404b540aSrobert Boston, MA 02110-1301, USA.  */
21*404b540aSrobert 
22*404b540aSrobert #include "config.h"
23*404b540aSrobert #include "system.h"
24*404b540aSrobert #include "coretypes.h"
25*404b540aSrobert #include "tm.h"
26*404b540aSrobert #include "rtl.h"
27*404b540aSrobert #include "tree.h"
28*404b540aSrobert #include "regs.h"
29*404b540aSrobert #include "hard-reg-set.h"
30*404b540aSrobert #include "real.h"
31*404b540aSrobert #include "insn-config.h"
32*404b540aSrobert #include "conditions.h"
33*404b540aSrobert #include "insn-flags.h"
34*404b540aSrobert #include "output.h"
35*404b540aSrobert #include "insn-attr.h"
36*404b540aSrobert #include "flags.h"
37*404b540aSrobert #include "recog.h"
38*404b540aSrobert #include "reload.h"
39*404b540aSrobert #include "expr.h"
40*404b540aSrobert #include "obstack.h"
41*404b540aSrobert #include "except.h"
42*404b540aSrobert #include "function.h"
43*404b540aSrobert #include "optabs.h"
44*404b540aSrobert #include "toplev.h"
45*404b540aSrobert #include "basic-block.h"
46*404b540aSrobert #include "tm_p.h"
47*404b540aSrobert #include "ggc.h"
48*404b540aSrobert #include <ctype.h>
49*404b540aSrobert #include "target.h"
50*404b540aSrobert #include "target-def.h"
51*404b540aSrobert #include "targhooks.h"
52*404b540aSrobert #include "integrate.h"
53*404b540aSrobert #include "langhooks.h"
54*404b540aSrobert 
55*404b540aSrobert #ifndef FRV_INLINE
56*404b540aSrobert #define FRV_INLINE inline
57*404b540aSrobert #endif
58*404b540aSrobert 
59*404b540aSrobert /* The maximum number of distinct NOP patterns.  There are three:
60*404b540aSrobert    nop, fnop and mnop.  */
61*404b540aSrobert #define NUM_NOP_PATTERNS 3
62*404b540aSrobert 
63*404b540aSrobert /* Classification of instructions and units: integer, floating-point/media,
64*404b540aSrobert    branch and control.  */
65*404b540aSrobert enum frv_insn_group { GROUP_I, GROUP_FM, GROUP_B, GROUP_C, NUM_GROUPS };
66*404b540aSrobert 
67*404b540aSrobert /* The DFA names of the units, in packet order.  */
68*404b540aSrobert static const char *const frv_unit_names[] =
69*404b540aSrobert {
70*404b540aSrobert   "c",
71*404b540aSrobert   "i0", "f0",
72*404b540aSrobert   "i1", "f1",
73*404b540aSrobert   "i2", "f2",
74*404b540aSrobert   "i3", "f3",
75*404b540aSrobert   "b0", "b1"
76*404b540aSrobert };
77*404b540aSrobert 
78*404b540aSrobert /* The classification of each unit in frv_unit_names[].  */
79*404b540aSrobert static const enum frv_insn_group frv_unit_groups[ARRAY_SIZE (frv_unit_names)] =
80*404b540aSrobert {
81*404b540aSrobert   GROUP_C,
82*404b540aSrobert   GROUP_I, GROUP_FM,
83*404b540aSrobert   GROUP_I, GROUP_FM,
84*404b540aSrobert   GROUP_I, GROUP_FM,
85*404b540aSrobert   GROUP_I, GROUP_FM,
86*404b540aSrobert   GROUP_B, GROUP_B
87*404b540aSrobert };
88*404b540aSrobert 
89*404b540aSrobert /* Return the DFA unit code associated with the Nth unit of integer
90*404b540aSrobert    or floating-point group GROUP,  */
91*404b540aSrobert #define NTH_UNIT(GROUP, N) frv_unit_codes[(GROUP) + (N) * 2 + 1]
92*404b540aSrobert 
93*404b540aSrobert /* Return the number of integer or floating-point unit UNIT
94*404b540aSrobert    (1 for I1, 2 for F2, etc.).  */
95*404b540aSrobert #define UNIT_NUMBER(UNIT) (((UNIT) - 1) / 2)
96*404b540aSrobert 
97*404b540aSrobert /* The DFA unit number for each unit in frv_unit_names[].  */
98*404b540aSrobert static int frv_unit_codes[ARRAY_SIZE (frv_unit_names)];
99*404b540aSrobert 
100*404b540aSrobert /* FRV_TYPE_TO_UNIT[T] is the last unit in frv_unit_names[] that can issue
101*404b540aSrobert    an instruction of type T.  The value is ARRAY_SIZE (frv_unit_names) if
102*404b540aSrobert    no instruction of type T has been seen.  */
103*404b540aSrobert static unsigned int frv_type_to_unit[TYPE_UNKNOWN + 1];
104*404b540aSrobert 
105*404b540aSrobert /* An array of dummy nop INSNs, one for each type of nop that the
106*404b540aSrobert    target supports.  */
107*404b540aSrobert static GTY(()) rtx frv_nops[NUM_NOP_PATTERNS];
108*404b540aSrobert 
109*404b540aSrobert /* The number of nop instructions in frv_nops[].  */
110*404b540aSrobert static unsigned int frv_num_nops;
111*404b540aSrobert 
112*404b540aSrobert /* Information about one __builtin_read or __builtin_write access, or
113*404b540aSrobert    the combination of several such accesses.  The most general value
114*404b540aSrobert    is all-zeros (an unknown access to an unknown address).  */
115*404b540aSrobert struct frv_io {
116*404b540aSrobert   /* The type of access.  FRV_IO_UNKNOWN means the access can be either
117*404b540aSrobert      a read or a write.  */
118*404b540aSrobert   enum { FRV_IO_UNKNOWN, FRV_IO_READ, FRV_IO_WRITE } type;
119*404b540aSrobert 
120*404b540aSrobert   /* The constant address being accessed, or zero if not known.  */
121*404b540aSrobert   HOST_WIDE_INT const_address;
122*404b540aSrobert 
123*404b540aSrobert   /* The run-time address, as used in operand 0 of the membar pattern.  */
124*404b540aSrobert   rtx var_address;
125*404b540aSrobert };
126*404b540aSrobert 
127*404b540aSrobert /* Return true if instruction INSN should be packed with the following
128*404b540aSrobert    instruction.  */
129*404b540aSrobert #define PACKING_FLAG_P(INSN) (GET_MODE (INSN) == TImode)
130*404b540aSrobert 
131*404b540aSrobert /* Set the value of PACKING_FLAG_P(INSN).  */
132*404b540aSrobert #define SET_PACKING_FLAG(INSN) PUT_MODE (INSN, TImode)
133*404b540aSrobert #define CLEAR_PACKING_FLAG(INSN) PUT_MODE (INSN, VOIDmode)
134*404b540aSrobert 
135*404b540aSrobert /* Loop with REG set to each hard register in rtx X.  */
136*404b540aSrobert #define FOR_EACH_REGNO(REG, X)						\
137*404b540aSrobert   for (REG = REGNO (X);							\
138*404b540aSrobert        REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X));	\
139*404b540aSrobert        REG++)
140*404b540aSrobert 
141*404b540aSrobert /* This structure contains machine specific function data.  */
142*404b540aSrobert struct machine_function GTY(())
143*404b540aSrobert {
144*404b540aSrobert   /* True if we have created an rtx that relies on the stack frame.  */
145*404b540aSrobert   int frame_needed;
146*404b540aSrobert 
147*404b540aSrobert   /* True if this function contains at least one __builtin_{read,write}*.  */
148*404b540aSrobert   bool has_membar_p;
149*404b540aSrobert };
150*404b540aSrobert 
151*404b540aSrobert /* Temporary register allocation support structure.  */
152*404b540aSrobert typedef struct frv_tmp_reg_struct
153*404b540aSrobert   {
154*404b540aSrobert     HARD_REG_SET regs;		/* possible registers to allocate */
155*404b540aSrobert     int next_reg[N_REG_CLASSES];	/* next register to allocate per class */
156*404b540aSrobert   }
157*404b540aSrobert frv_tmp_reg_t;
158*404b540aSrobert 
159*404b540aSrobert /* Register state information for VLIW re-packing phase.  */
160*404b540aSrobert #define REGSTATE_CC_MASK	0x07	/* Mask to isolate CCn for cond exec */
161*404b540aSrobert #define REGSTATE_MODIFIED	0x08	/* reg modified in current VLIW insn */
162*404b540aSrobert #define REGSTATE_IF_TRUE	0x10	/* reg modified in cond exec true */
163*404b540aSrobert #define REGSTATE_IF_FALSE	0x20	/* reg modified in cond exec false */
164*404b540aSrobert 
165*404b540aSrobert #define REGSTATE_IF_EITHER	(REGSTATE_IF_TRUE | REGSTATE_IF_FALSE)
166*404b540aSrobert 
167*404b540aSrobert typedef unsigned char regstate_t;
168*404b540aSrobert 
169*404b540aSrobert /* Used in frv_frame_accessor_t to indicate the direction of a register-to-
170*404b540aSrobert    memory move.  */
171*404b540aSrobert enum frv_stack_op
172*404b540aSrobert {
173*404b540aSrobert   FRV_LOAD,
174*404b540aSrobert   FRV_STORE
175*404b540aSrobert };
176*404b540aSrobert 
177*404b540aSrobert /* Information required by frv_frame_access.  */
178*404b540aSrobert typedef struct
179*404b540aSrobert {
180*404b540aSrobert   /* This field is FRV_LOAD if registers are to be loaded from the stack and
181*404b540aSrobert      FRV_STORE if they should be stored onto the stack.  FRV_STORE implies
182*404b540aSrobert      the move is being done by the prologue code while FRV_LOAD implies it
183*404b540aSrobert      is being done by the epilogue.  */
184*404b540aSrobert   enum frv_stack_op op;
185*404b540aSrobert 
186*404b540aSrobert   /* The base register to use when accessing the stack.  This may be the
187*404b540aSrobert      frame pointer, stack pointer, or a temporary.  The choice of register
188*404b540aSrobert      depends on which part of the frame is being accessed and how big the
189*404b540aSrobert      frame is.  */
190*404b540aSrobert   rtx base;
191*404b540aSrobert 
192*404b540aSrobert   /* The offset of BASE from the bottom of the current frame, in bytes.  */
193*404b540aSrobert   int base_offset;
194*404b540aSrobert } frv_frame_accessor_t;
195*404b540aSrobert 
196*404b540aSrobert /* Define the information needed to generate branch and scc insns.  This is
197*404b540aSrobert    stored from the compare operation.  */
198*404b540aSrobert rtx frv_compare_op0;
199*404b540aSrobert rtx frv_compare_op1;
200*404b540aSrobert 
201*404b540aSrobert /* Conditional execution support gathered together in one structure.  */
202*404b540aSrobert typedef struct
203*404b540aSrobert   {
204*404b540aSrobert     /* Linked list of insns to add if the conditional execution conversion was
205*404b540aSrobert        successful.  Each link points to an EXPR_LIST which points to the pattern
206*404b540aSrobert        of the insn to add, and the insn to be inserted before.  */
207*404b540aSrobert     rtx added_insns_list;
208*404b540aSrobert 
209*404b540aSrobert     /* Identify which registers are safe to allocate for if conversions to
210*404b540aSrobert        conditional execution.  We keep the last allocated register in the
211*404b540aSrobert        register classes between COND_EXEC statements.  This will mean we allocate
212*404b540aSrobert        different registers for each different COND_EXEC group if we can.  This
213*404b540aSrobert        might allow the scheduler to intermix two different COND_EXEC sections.  */
214*404b540aSrobert     frv_tmp_reg_t tmp_reg;
215*404b540aSrobert 
216*404b540aSrobert     /* For nested IFs, identify which CC registers are used outside of setting
217*404b540aSrobert        via a compare isnsn, and using via a check insn.  This will allow us to
218*404b540aSrobert        know if we can rewrite the register to use a different register that will
219*404b540aSrobert        be paired with the CR register controlling the nested IF-THEN blocks.  */
220*404b540aSrobert     HARD_REG_SET nested_cc_ok_rewrite;
221*404b540aSrobert 
222*404b540aSrobert     /* Temporary registers allocated to hold constants during conditional
223*404b540aSrobert        execution.  */
224*404b540aSrobert     rtx scratch_regs[FIRST_PSEUDO_REGISTER];
225*404b540aSrobert 
226*404b540aSrobert     /* Current number of temp registers available.  */
227*404b540aSrobert     int cur_scratch_regs;
228*404b540aSrobert 
229*404b540aSrobert     /* Number of nested conditional execution blocks.  */
230*404b540aSrobert     int num_nested_cond_exec;
231*404b540aSrobert 
232*404b540aSrobert     /* Map of insns that set up constants in scratch registers.  */
233*404b540aSrobert     bitmap scratch_insns_bitmap;
234*404b540aSrobert 
235*404b540aSrobert     /* Conditional execution test register (CC0..CC7).  */
236*404b540aSrobert     rtx cr_reg;
237*404b540aSrobert 
238*404b540aSrobert     /* Conditional execution compare register that is paired with cr_reg, so that
239*404b540aSrobert        nested compares can be done.  The csubcc and caddcc instructions don't
240*404b540aSrobert        have enough bits to specify both a CC register to be set and a CR register
241*404b540aSrobert        to do the test on, so the same bit number is used for both.  Needless to
242*404b540aSrobert        say, this is rather inconvenient for GCC.  */
243*404b540aSrobert     rtx nested_cc_reg;
244*404b540aSrobert 
245*404b540aSrobert     /* Extra CR registers used for &&, ||.  */
246*404b540aSrobert     rtx extra_int_cr;
247*404b540aSrobert     rtx extra_fp_cr;
248*404b540aSrobert 
249*404b540aSrobert     /* Previous CR used in nested if, to make sure we are dealing with the same
250*404b540aSrobert        nested if as the previous statement.  */
251*404b540aSrobert     rtx last_nested_if_cr;
252*404b540aSrobert   }
253*404b540aSrobert frv_ifcvt_t;
254*404b540aSrobert 
255*404b540aSrobert static /* GTY(()) */ frv_ifcvt_t frv_ifcvt;
256*404b540aSrobert 
257*404b540aSrobert /* Map register number to smallest register class.  */
258*404b540aSrobert enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
259*404b540aSrobert 
260*404b540aSrobert /* Map class letter into register class.  */
261*404b540aSrobert enum reg_class reg_class_from_letter[256];
262*404b540aSrobert 
263*404b540aSrobert /* Cached value of frv_stack_info.  */
264*404b540aSrobert static frv_stack_t *frv_stack_cache = (frv_stack_t *)0;
265*404b540aSrobert 
266*404b540aSrobert /* -mcpu= support */
267*404b540aSrobert frv_cpu_t frv_cpu_type = CPU_TYPE;	/* value of -mcpu= */
268*404b540aSrobert 
269*404b540aSrobert /* Forward references */
270*404b540aSrobert 
271*404b540aSrobert static bool frv_handle_option			(size_t, const char *, int);
272*404b540aSrobert static int frv_default_flags_for_cpu		(void);
273*404b540aSrobert static int frv_string_begins_with		(tree, const char *);
274*404b540aSrobert static FRV_INLINE bool frv_small_data_reloc_p	(rtx, int);
275*404b540aSrobert static void frv_print_operand_memory_reference_reg
276*404b540aSrobert 						(FILE *, rtx);
277*404b540aSrobert static void frv_print_operand_memory_reference	(FILE *, rtx, int);
278*404b540aSrobert static int frv_print_operand_jump_hint		(rtx);
279*404b540aSrobert static const char *comparison_string		(enum rtx_code, rtx);
280*404b540aSrobert static FRV_INLINE int frv_regno_ok_for_base_p	(int, int);
281*404b540aSrobert static rtx single_set_pattern			(rtx);
282*404b540aSrobert static int frv_function_contains_far_jump	(void);
283*404b540aSrobert static rtx frv_alloc_temp_reg			(frv_tmp_reg_t *,
284*404b540aSrobert 						 enum reg_class,
285*404b540aSrobert 						 enum machine_mode,
286*404b540aSrobert 						 int, int);
287*404b540aSrobert static rtx frv_frame_offset_rtx			(int);
288*404b540aSrobert static rtx frv_frame_mem			(enum machine_mode, rtx, int);
289*404b540aSrobert static rtx frv_dwarf_store			(rtx, int);
290*404b540aSrobert static void frv_frame_insn			(rtx, rtx);
291*404b540aSrobert static void frv_frame_access			(frv_frame_accessor_t*,
292*404b540aSrobert 						 rtx, int);
293*404b540aSrobert static void frv_frame_access_multi		(frv_frame_accessor_t*,
294*404b540aSrobert 						 frv_stack_t *, int);
295*404b540aSrobert static void frv_frame_access_standard_regs	(enum frv_stack_op,
296*404b540aSrobert 						 frv_stack_t *);
297*404b540aSrobert static struct machine_function *frv_init_machine_status		(void);
298*404b540aSrobert static rtx frv_int_to_acc			(enum insn_code, int, rtx);
299*404b540aSrobert static enum machine_mode frv_matching_accg_mode	(enum machine_mode);
300*404b540aSrobert static rtx frv_read_argument			(tree *);
301*404b540aSrobert static rtx frv_read_iacc_argument		(enum machine_mode, tree *);
302*404b540aSrobert static int frv_check_constant_argument		(enum insn_code, int, rtx);
303*404b540aSrobert static rtx frv_legitimize_target		(enum insn_code, rtx);
304*404b540aSrobert static rtx frv_legitimize_argument		(enum insn_code, int, rtx);
305*404b540aSrobert static rtx frv_legitimize_tls_address		(rtx, enum tls_model);
306*404b540aSrobert static rtx frv_expand_set_builtin		(enum insn_code, tree, rtx);
307*404b540aSrobert static rtx frv_expand_unop_builtin		(enum insn_code, tree, rtx);
308*404b540aSrobert static rtx frv_expand_binop_builtin		(enum insn_code, tree, rtx);
309*404b540aSrobert static rtx frv_expand_cut_builtin		(enum insn_code, tree, rtx);
310*404b540aSrobert static rtx frv_expand_binopimm_builtin		(enum insn_code, tree, rtx);
311*404b540aSrobert static rtx frv_expand_voidbinop_builtin		(enum insn_code, tree);
312*404b540aSrobert static rtx frv_expand_int_void2arg		(enum insn_code, tree);
313*404b540aSrobert static rtx frv_expand_prefetches		(enum insn_code, tree);
314*404b540aSrobert static rtx frv_expand_voidtriop_builtin		(enum insn_code, tree);
315*404b540aSrobert static rtx frv_expand_voidaccop_builtin		(enum insn_code, tree);
316*404b540aSrobert static rtx frv_expand_mclracc_builtin		(tree);
317*404b540aSrobert static rtx frv_expand_mrdacc_builtin		(enum insn_code, tree);
318*404b540aSrobert static rtx frv_expand_mwtacc_builtin		(enum insn_code, tree);
319*404b540aSrobert static rtx frv_expand_noargs_builtin		(enum insn_code);
320*404b540aSrobert static void frv_split_iacc_move			(rtx, rtx);
321*404b540aSrobert static rtx frv_emit_comparison			(enum rtx_code, rtx, rtx);
322*404b540aSrobert static int frv_clear_registers_used		(rtx *, void *);
323*404b540aSrobert static void frv_ifcvt_add_insn			(rtx, rtx, int);
324*404b540aSrobert static rtx frv_ifcvt_rewrite_mem		(rtx, enum machine_mode, rtx);
325*404b540aSrobert static rtx frv_ifcvt_load_value			(rtx, rtx);
326*404b540aSrobert static int frv_acc_group_1			(rtx *, void *);
327*404b540aSrobert static unsigned int frv_insn_unit		(rtx);
328*404b540aSrobert static bool frv_issues_to_branch_unit_p		(rtx);
329*404b540aSrobert static int frv_cond_flags 			(rtx);
330*404b540aSrobert static bool frv_regstate_conflict_p 		(regstate_t, regstate_t);
331*404b540aSrobert static int frv_registers_conflict_p_1 		(rtx *, void *);
332*404b540aSrobert static bool frv_registers_conflict_p 		(rtx);
333*404b540aSrobert static void frv_registers_update_1 		(rtx, rtx, void *);
334*404b540aSrobert static void frv_registers_update 		(rtx);
335*404b540aSrobert static void frv_start_packet 			(void);
336*404b540aSrobert static void frv_start_packet_block 		(void);
337*404b540aSrobert static void frv_finish_packet 			(void (*) (void));
338*404b540aSrobert static bool frv_pack_insn_p 			(rtx);
339*404b540aSrobert static void frv_add_insn_to_packet		(rtx);
340*404b540aSrobert static void frv_insert_nop_in_packet		(rtx);
341*404b540aSrobert static bool frv_for_each_packet 		(void (*) (void));
342*404b540aSrobert static bool frv_sort_insn_group_1		(enum frv_insn_group,
343*404b540aSrobert 						 unsigned int, unsigned int,
344*404b540aSrobert 						 unsigned int, unsigned int,
345*404b540aSrobert 						 state_t);
346*404b540aSrobert static int frv_compare_insns			(const void *, const void *);
347*404b540aSrobert static void frv_sort_insn_group			(enum frv_insn_group);
348*404b540aSrobert static void frv_reorder_packet 			(void);
349*404b540aSrobert static void frv_fill_unused_units		(enum frv_insn_group);
350*404b540aSrobert static void frv_align_label 			(void);
351*404b540aSrobert static void frv_reorg_packet 			(void);
352*404b540aSrobert static void frv_register_nop			(rtx);
353*404b540aSrobert static void frv_reorg 				(void);
354*404b540aSrobert static void frv_pack_insns			(void);
355*404b540aSrobert static void frv_function_prologue		(FILE *, HOST_WIDE_INT);
356*404b540aSrobert static void frv_function_epilogue		(FILE *, HOST_WIDE_INT);
357*404b540aSrobert static bool frv_assemble_integer		(rtx, unsigned, int);
358*404b540aSrobert static void frv_init_builtins			(void);
359*404b540aSrobert static rtx frv_expand_builtin			(tree, rtx, rtx, enum machine_mode, int);
360*404b540aSrobert static void frv_init_libfuncs			(void);
361*404b540aSrobert static bool frv_in_small_data_p			(tree);
362*404b540aSrobert static void frv_asm_output_mi_thunk
363*404b540aSrobert   (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
364*404b540aSrobert static void frv_setup_incoming_varargs		(CUMULATIVE_ARGS *,
365*404b540aSrobert 						 enum machine_mode,
366*404b540aSrobert 						 tree, int *, int);
367*404b540aSrobert static rtx frv_expand_builtin_saveregs		(void);
368*404b540aSrobert static bool frv_rtx_costs			(rtx, int, int, int*);
369*404b540aSrobert static void frv_asm_out_constructor		(rtx, int);
370*404b540aSrobert static void frv_asm_out_destructor		(rtx, int);
371*404b540aSrobert static bool frv_function_symbol_referenced_p	(rtx);
372*404b540aSrobert static bool frv_cannot_force_const_mem		(rtx);
373*404b540aSrobert static const char *unspec_got_name		(int);
374*404b540aSrobert static void frv_output_const_unspec		(FILE *,
375*404b540aSrobert 						 const struct frv_unspec *);
376*404b540aSrobert static bool frv_function_ok_for_sibcall		(tree, tree);
377*404b540aSrobert static rtx frv_struct_value_rtx			(tree, int);
378*404b540aSrobert static bool frv_must_pass_in_stack (enum machine_mode mode, tree type);
379*404b540aSrobert static int frv_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
380*404b540aSrobert 				  tree, bool);
381*404b540aSrobert static void frv_output_dwarf_dtprel		(FILE *, int, rtx)
382*404b540aSrobert   ATTRIBUTE_UNUSED;
383*404b540aSrobert 
384*404b540aSrobert /* Allow us to easily change the default for -malloc-cc.  */
385*404b540aSrobert #ifndef DEFAULT_NO_ALLOC_CC
386*404b540aSrobert #define MASK_DEFAULT_ALLOC_CC	MASK_ALLOC_CC
387*404b540aSrobert #else
388*404b540aSrobert #define MASK_DEFAULT_ALLOC_CC	0
389*404b540aSrobert #endif
390*404b540aSrobert 
391*404b540aSrobert /* Initialize the GCC target structure.  */
392*404b540aSrobert #undef  TARGET_ASM_FUNCTION_PROLOGUE
393*404b540aSrobert #define TARGET_ASM_FUNCTION_PROLOGUE frv_function_prologue
394*404b540aSrobert #undef  TARGET_ASM_FUNCTION_EPILOGUE
395*404b540aSrobert #define TARGET_ASM_FUNCTION_EPILOGUE frv_function_epilogue
396*404b540aSrobert #undef  TARGET_ASM_INTEGER
397*404b540aSrobert #define TARGET_ASM_INTEGER frv_assemble_integer
398*404b540aSrobert #undef TARGET_DEFAULT_TARGET_FLAGS
399*404b540aSrobert #define TARGET_DEFAULT_TARGET_FLAGS		\
400*404b540aSrobert   (MASK_DEFAULT_ALLOC_CC			\
401*404b540aSrobert    | MASK_COND_MOVE				\
402*404b540aSrobert    | MASK_SCC					\
403*404b540aSrobert    | MASK_COND_EXEC				\
404*404b540aSrobert    | MASK_VLIW_BRANCH				\
405*404b540aSrobert    | MASK_MULTI_CE				\
406*404b540aSrobert    | MASK_NESTED_CE)
407*404b540aSrobert #undef TARGET_HANDLE_OPTION
408*404b540aSrobert #define TARGET_HANDLE_OPTION frv_handle_option
409*404b540aSrobert #undef TARGET_INIT_BUILTINS
410*404b540aSrobert #define TARGET_INIT_BUILTINS frv_init_builtins
411*404b540aSrobert #undef TARGET_EXPAND_BUILTIN
412*404b540aSrobert #define TARGET_EXPAND_BUILTIN frv_expand_builtin
413*404b540aSrobert #undef TARGET_INIT_LIBFUNCS
414*404b540aSrobert #define TARGET_INIT_LIBFUNCS frv_init_libfuncs
415*404b540aSrobert #undef TARGET_IN_SMALL_DATA_P
416*404b540aSrobert #define TARGET_IN_SMALL_DATA_P frv_in_small_data_p
417*404b540aSrobert #undef TARGET_RTX_COSTS
418*404b540aSrobert #define TARGET_RTX_COSTS frv_rtx_costs
419*404b540aSrobert #undef TARGET_ASM_CONSTRUCTOR
420*404b540aSrobert #define TARGET_ASM_CONSTRUCTOR frv_asm_out_constructor
421*404b540aSrobert #undef TARGET_ASM_DESTRUCTOR
422*404b540aSrobert #define TARGET_ASM_DESTRUCTOR frv_asm_out_destructor
423*404b540aSrobert 
424*404b540aSrobert #undef TARGET_ASM_OUTPUT_MI_THUNK
425*404b540aSrobert #define TARGET_ASM_OUTPUT_MI_THUNK frv_asm_output_mi_thunk
426*404b540aSrobert #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
427*404b540aSrobert #define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
428*404b540aSrobert 
429*404b540aSrobert #undef  TARGET_SCHED_ISSUE_RATE
430*404b540aSrobert #define TARGET_SCHED_ISSUE_RATE frv_issue_rate
431*404b540aSrobert 
432*404b540aSrobert #undef TARGET_FUNCTION_OK_FOR_SIBCALL
433*404b540aSrobert #define TARGET_FUNCTION_OK_FOR_SIBCALL frv_function_ok_for_sibcall
434*404b540aSrobert #undef TARGET_CANNOT_FORCE_CONST_MEM
435*404b540aSrobert #define TARGET_CANNOT_FORCE_CONST_MEM frv_cannot_force_const_mem
436*404b540aSrobert 
437*404b540aSrobert #undef TARGET_HAVE_TLS
438*404b540aSrobert #define TARGET_HAVE_TLS HAVE_AS_TLS
439*404b540aSrobert 
440*404b540aSrobert #undef TARGET_STRUCT_VALUE_RTX
441*404b540aSrobert #define TARGET_STRUCT_VALUE_RTX frv_struct_value_rtx
442*404b540aSrobert #undef TARGET_MUST_PASS_IN_STACK
443*404b540aSrobert #define TARGET_MUST_PASS_IN_STACK frv_must_pass_in_stack
444*404b540aSrobert #undef TARGET_PASS_BY_REFERENCE
445*404b540aSrobert #define TARGET_PASS_BY_REFERENCE hook_pass_by_reference_must_pass_in_stack
446*404b540aSrobert #undef TARGET_ARG_PARTIAL_BYTES
447*404b540aSrobert #define TARGET_ARG_PARTIAL_BYTES frv_arg_partial_bytes
448*404b540aSrobert 
449*404b540aSrobert #undef TARGET_EXPAND_BUILTIN_SAVEREGS
450*404b540aSrobert #define TARGET_EXPAND_BUILTIN_SAVEREGS frv_expand_builtin_saveregs
451*404b540aSrobert #undef TARGET_SETUP_INCOMING_VARARGS
452*404b540aSrobert #define TARGET_SETUP_INCOMING_VARARGS frv_setup_incoming_varargs
453*404b540aSrobert #undef TARGET_MACHINE_DEPENDENT_REORG
454*404b540aSrobert #define TARGET_MACHINE_DEPENDENT_REORG frv_reorg
455*404b540aSrobert 
456*404b540aSrobert #if HAVE_AS_TLS
457*404b540aSrobert #undef TARGET_ASM_OUTPUT_DWARF_DTPREL
458*404b540aSrobert #define TARGET_ASM_OUTPUT_DWARF_DTPREL frv_output_dwarf_dtprel
459*404b540aSrobert #endif
460*404b540aSrobert 
461*404b540aSrobert struct gcc_target targetm = TARGET_INITIALIZER;
462*404b540aSrobert 
463*404b540aSrobert #define FRV_SYMBOL_REF_TLS_P(RTX) \
464*404b540aSrobert   (GET_CODE (RTX) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (RTX) != 0)
465*404b540aSrobert 
466*404b540aSrobert 
467*404b540aSrobert /* Any function call that satisfies the machine-independent
468*404b540aSrobert    requirements is eligible on FR-V.  */
469*404b540aSrobert 
470*404b540aSrobert static bool
frv_function_ok_for_sibcall(tree decl ATTRIBUTE_UNUSED,tree exp ATTRIBUTE_UNUSED)471*404b540aSrobert frv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
472*404b540aSrobert 			     tree exp ATTRIBUTE_UNUSED)
473*404b540aSrobert {
474*404b540aSrobert   return true;
475*404b540aSrobert }
476*404b540aSrobert 
477*404b540aSrobert /* Return true if SYMBOL is a small data symbol and relocation RELOC
478*404b540aSrobert    can be used to access it directly in a load or store.  */
479*404b540aSrobert 
480*404b540aSrobert static FRV_INLINE bool
frv_small_data_reloc_p(rtx symbol,int reloc)481*404b540aSrobert frv_small_data_reloc_p (rtx symbol, int reloc)
482*404b540aSrobert {
483*404b540aSrobert   return (GET_CODE (symbol) == SYMBOL_REF
484*404b540aSrobert 	  && SYMBOL_REF_SMALL_P (symbol)
485*404b540aSrobert 	  && (!TARGET_FDPIC || flag_pic == 1)
486*404b540aSrobert 	  && (reloc == R_FRV_GOTOFF12 || reloc == R_FRV_GPREL12));
487*404b540aSrobert }
488*404b540aSrobert 
489*404b540aSrobert /* Return true if X is a valid relocation unspec.  If it is, fill in UNSPEC
490*404b540aSrobert    appropriately.  */
491*404b540aSrobert 
492*404b540aSrobert bool
frv_const_unspec_p(rtx x,struct frv_unspec * unspec)493*404b540aSrobert frv_const_unspec_p (rtx x, struct frv_unspec *unspec)
494*404b540aSrobert {
495*404b540aSrobert   if (GET_CODE (x) == CONST)
496*404b540aSrobert     {
497*404b540aSrobert       unspec->offset = 0;
498*404b540aSrobert       x = XEXP (x, 0);
499*404b540aSrobert       if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
500*404b540aSrobert 	{
501*404b540aSrobert 	  unspec->offset += INTVAL (XEXP (x, 1));
502*404b540aSrobert 	  x = XEXP (x, 0);
503*404b540aSrobert 	}
504*404b540aSrobert       if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_GOT)
505*404b540aSrobert 	{
506*404b540aSrobert 	  unspec->symbol = XVECEXP (x, 0, 0);
507*404b540aSrobert 	  unspec->reloc = INTVAL (XVECEXP (x, 0, 1));
508*404b540aSrobert 
509*404b540aSrobert 	  if (unspec->offset == 0)
510*404b540aSrobert 	    return true;
511*404b540aSrobert 
512*404b540aSrobert 	  if (frv_small_data_reloc_p (unspec->symbol, unspec->reloc)
513*404b540aSrobert 	      && unspec->offset > 0
514*404b540aSrobert 	      && (unsigned HOST_WIDE_INT) unspec->offset < g_switch_value)
515*404b540aSrobert 	    return true;
516*404b540aSrobert 	}
517*404b540aSrobert     }
518*404b540aSrobert   return false;
519*404b540aSrobert }
520*404b540aSrobert 
521*404b540aSrobert /* Decide whether we can force certain constants to memory.  If we
522*404b540aSrobert    decide we can't, the caller should be able to cope with it in
523*404b540aSrobert    another way.
524*404b540aSrobert 
525*404b540aSrobert    We never allow constants to be forced into memory for TARGET_FDPIC.
526*404b540aSrobert    This is necessary for several reasons:
527*404b540aSrobert 
528*404b540aSrobert    1. Since LEGITIMATE_CONSTANT_P rejects constant pool addresses, the
529*404b540aSrobert       target-independent code will try to force them into the constant
530*404b540aSrobert       pool, thus leading to infinite recursion.
531*404b540aSrobert 
532*404b540aSrobert    2. We can never introduce new constant pool references during reload.
533*404b540aSrobert       Any such reference would require use of the pseudo FDPIC register.
534*404b540aSrobert 
535*404b540aSrobert    3. We can't represent a constant added to a function pointer (which is
536*404b540aSrobert       not the same as a pointer to a function+constant).
537*404b540aSrobert 
538*404b540aSrobert    4. In many cases, it's more efficient to calculate the constant in-line.  */
539*404b540aSrobert 
540*404b540aSrobert static bool
frv_cannot_force_const_mem(rtx x ATTRIBUTE_UNUSED)541*404b540aSrobert frv_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
542*404b540aSrobert {
543*404b540aSrobert   return TARGET_FDPIC;
544*404b540aSrobert }
545*404b540aSrobert 
546*404b540aSrobert /* Implement TARGET_HANDLE_OPTION.  */
547*404b540aSrobert 
548*404b540aSrobert static bool
frv_handle_option(size_t code,const char * arg,int value ATTRIBUTE_UNUSED)549*404b540aSrobert frv_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
550*404b540aSrobert {
551*404b540aSrobert   switch (code)
552*404b540aSrobert     {
553*404b540aSrobert     case OPT_mcpu_:
554*404b540aSrobert       if (strcmp (arg, "simple") == 0)
555*404b540aSrobert 	frv_cpu_type = FRV_CPU_SIMPLE;
556*404b540aSrobert       else if (strcmp (arg, "tomcat") == 0)
557*404b540aSrobert 	frv_cpu_type = FRV_CPU_TOMCAT;
558*404b540aSrobert       else if (strcmp (arg, "fr550") == 0)
559*404b540aSrobert 	frv_cpu_type = FRV_CPU_FR550;
560*404b540aSrobert       else if (strcmp (arg, "fr500") == 0)
561*404b540aSrobert 	frv_cpu_type = FRV_CPU_FR500;
562*404b540aSrobert       else if (strcmp (arg, "fr450") == 0)
563*404b540aSrobert 	frv_cpu_type = FRV_CPU_FR450;
564*404b540aSrobert       else if (strcmp (arg, "fr405") == 0)
565*404b540aSrobert 	frv_cpu_type = FRV_CPU_FR405;
566*404b540aSrobert       else if (strcmp (arg, "fr400") == 0)
567*404b540aSrobert 	frv_cpu_type = FRV_CPU_FR400;
568*404b540aSrobert       else if (strcmp (arg, "fr300") == 0)
569*404b540aSrobert 	frv_cpu_type = FRV_CPU_FR300;
570*404b540aSrobert       else if (strcmp (arg, "frv") == 0)
571*404b540aSrobert 	frv_cpu_type = FRV_CPU_GENERIC;
572*404b540aSrobert       else
573*404b540aSrobert 	return false;
574*404b540aSrobert       return true;
575*404b540aSrobert 
576*404b540aSrobert     default:
577*404b540aSrobert       return true;
578*404b540aSrobert     }
579*404b540aSrobert }
580*404b540aSrobert 
581*404b540aSrobert static int
frv_default_flags_for_cpu(void)582*404b540aSrobert frv_default_flags_for_cpu (void)
583*404b540aSrobert {
584*404b540aSrobert   switch (frv_cpu_type)
585*404b540aSrobert     {
586*404b540aSrobert     case FRV_CPU_GENERIC:
587*404b540aSrobert       return MASK_DEFAULT_FRV;
588*404b540aSrobert 
589*404b540aSrobert     case FRV_CPU_FR550:
590*404b540aSrobert       return MASK_DEFAULT_FR550;
591*404b540aSrobert 
592*404b540aSrobert     case FRV_CPU_FR500:
593*404b540aSrobert     case FRV_CPU_TOMCAT:
594*404b540aSrobert       return MASK_DEFAULT_FR500;
595*404b540aSrobert 
596*404b540aSrobert     case FRV_CPU_FR450:
597*404b540aSrobert       return MASK_DEFAULT_FR450;
598*404b540aSrobert 
599*404b540aSrobert     case FRV_CPU_FR405:
600*404b540aSrobert     case FRV_CPU_FR400:
601*404b540aSrobert       return MASK_DEFAULT_FR400;
602*404b540aSrobert 
603*404b540aSrobert     case FRV_CPU_FR300:
604*404b540aSrobert     case FRV_CPU_SIMPLE:
605*404b540aSrobert       return MASK_DEFAULT_SIMPLE;
606*404b540aSrobert 
607*404b540aSrobert     default:
608*404b540aSrobert       gcc_unreachable ();
609*404b540aSrobert     }
610*404b540aSrobert }
611*404b540aSrobert 
612*404b540aSrobert /* Sometimes certain combinations of command options do not make
613*404b540aSrobert    sense on a particular target machine.  You can define a macro
614*404b540aSrobert    `OVERRIDE_OPTIONS' to take account of this.  This macro, if
615*404b540aSrobert    defined, is executed once just after all the command options have
616*404b540aSrobert    been parsed.
617*404b540aSrobert 
618*404b540aSrobert    Don't use this macro to turn on various extra optimizations for
619*404b540aSrobert    `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
620*404b540aSrobert 
621*404b540aSrobert void
frv_override_options(void)622*404b540aSrobert frv_override_options (void)
623*404b540aSrobert {
624*404b540aSrobert   int regno;
625*404b540aSrobert   unsigned int i;
626*404b540aSrobert 
627*404b540aSrobert   target_flags |= (frv_default_flags_for_cpu () & ~target_flags_explicit);
628*404b540aSrobert 
629*404b540aSrobert   /* -mlibrary-pic sets -fPIC and -G0 and also suppresses warnings from the
630*404b540aSrobert      linker about linking pic and non-pic code.  */
631*404b540aSrobert   if (TARGET_LIBPIC)
632*404b540aSrobert     {
633*404b540aSrobert       if (!flag_pic)		/* -fPIC */
634*404b540aSrobert 	flag_pic = 2;
635*404b540aSrobert 
636*404b540aSrobert       if (! g_switch_set)	/* -G0 */
637*404b540aSrobert 	{
638*404b540aSrobert 	  g_switch_set = 1;
639*404b540aSrobert 	  g_switch_value = 0;
640*404b540aSrobert 	}
641*404b540aSrobert     }
642*404b540aSrobert 
643*404b540aSrobert   /* A C expression whose value is a register class containing hard
644*404b540aSrobert      register REGNO.  In general there is more than one such class;
645*404b540aSrobert      choose a class which is "minimal", meaning that no smaller class
646*404b540aSrobert      also contains the register.  */
647*404b540aSrobert 
648*404b540aSrobert   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
649*404b540aSrobert     {
650*404b540aSrobert       enum reg_class class;
651*404b540aSrobert 
652*404b540aSrobert       if (GPR_P (regno))
653*404b540aSrobert 	{
654*404b540aSrobert 	  int gpr_reg = regno - GPR_FIRST;
655*404b540aSrobert 
656*404b540aSrobert 	  if (gpr_reg == GR8_REG)
657*404b540aSrobert 	    class = GR8_REGS;
658*404b540aSrobert 
659*404b540aSrobert 	  else if (gpr_reg == GR9_REG)
660*404b540aSrobert 	    class = GR9_REGS;
661*404b540aSrobert 
662*404b540aSrobert 	  else if (gpr_reg == GR14_REG)
663*404b540aSrobert 	    class = FDPIC_FPTR_REGS;
664*404b540aSrobert 
665*404b540aSrobert 	  else if (gpr_reg == FDPIC_REGNO)
666*404b540aSrobert 	    class = FDPIC_REGS;
667*404b540aSrobert 
668*404b540aSrobert 	  else if ((gpr_reg & 3) == 0)
669*404b540aSrobert 	    class = QUAD_REGS;
670*404b540aSrobert 
671*404b540aSrobert 	  else if ((gpr_reg & 1) == 0)
672*404b540aSrobert 	    class = EVEN_REGS;
673*404b540aSrobert 
674*404b540aSrobert 	  else
675*404b540aSrobert 	    class = GPR_REGS;
676*404b540aSrobert 	}
677*404b540aSrobert 
678*404b540aSrobert       else if (FPR_P (regno))
679*404b540aSrobert 	{
680*404b540aSrobert 	  int fpr_reg = regno - GPR_FIRST;
681*404b540aSrobert 	  if ((fpr_reg & 3) == 0)
682*404b540aSrobert 	    class = QUAD_FPR_REGS;
683*404b540aSrobert 
684*404b540aSrobert 	  else if ((fpr_reg & 1) == 0)
685*404b540aSrobert 	    class = FEVEN_REGS;
686*404b540aSrobert 
687*404b540aSrobert 	  else
688*404b540aSrobert 	    class = FPR_REGS;
689*404b540aSrobert 	}
690*404b540aSrobert 
691*404b540aSrobert       else if (regno == LR_REGNO)
692*404b540aSrobert 	class = LR_REG;
693*404b540aSrobert 
694*404b540aSrobert       else if (regno == LCR_REGNO)
695*404b540aSrobert 	class = LCR_REG;
696*404b540aSrobert 
697*404b540aSrobert       else if (ICC_P (regno))
698*404b540aSrobert 	class = ICC_REGS;
699*404b540aSrobert 
700*404b540aSrobert       else if (FCC_P (regno))
701*404b540aSrobert 	class = FCC_REGS;
702*404b540aSrobert 
703*404b540aSrobert       else if (ICR_P (regno))
704*404b540aSrobert 	class = ICR_REGS;
705*404b540aSrobert 
706*404b540aSrobert       else if (FCR_P (regno))
707*404b540aSrobert 	class = FCR_REGS;
708*404b540aSrobert 
709*404b540aSrobert       else if (ACC_P (regno))
710*404b540aSrobert 	{
711*404b540aSrobert 	  int r = regno - ACC_FIRST;
712*404b540aSrobert 	  if ((r & 3) == 0)
713*404b540aSrobert 	    class = QUAD_ACC_REGS;
714*404b540aSrobert 	  else if ((r & 1) == 0)
715*404b540aSrobert 	    class = EVEN_ACC_REGS;
716*404b540aSrobert 	  else
717*404b540aSrobert 	    class = ACC_REGS;
718*404b540aSrobert 	}
719*404b540aSrobert 
720*404b540aSrobert       else if (ACCG_P (regno))
721*404b540aSrobert 	class = ACCG_REGS;
722*404b540aSrobert 
723*404b540aSrobert       else
724*404b540aSrobert 	class = NO_REGS;
725*404b540aSrobert 
726*404b540aSrobert       regno_reg_class[regno] = class;
727*404b540aSrobert     }
728*404b540aSrobert 
729*404b540aSrobert   /* Check for small data option */
730*404b540aSrobert   if (!g_switch_set)
731*404b540aSrobert     g_switch_value = SDATA_DEFAULT_SIZE;
732*404b540aSrobert 
733*404b540aSrobert   /* A C expression which defines the machine-dependent operand
734*404b540aSrobert      constraint letters for register classes.  If CHAR is such a
735*404b540aSrobert      letter, the value should be the register class corresponding to
736*404b540aSrobert      it.  Otherwise, the value should be `NO_REGS'.  The register
737*404b540aSrobert      letter `r', corresponding to class `GENERAL_REGS', will not be
738*404b540aSrobert      passed to this macro; you do not need to handle it.
739*404b540aSrobert 
740*404b540aSrobert      The following letters are unavailable, due to being used as
741*404b540aSrobert      constraints:
742*404b540aSrobert 	'0'..'9'
743*404b540aSrobert 	'<', '>'
744*404b540aSrobert 	'E', 'F', 'G', 'H'
745*404b540aSrobert 	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P'
746*404b540aSrobert 	'Q', 'R', 'S', 'T', 'U'
747*404b540aSrobert 	'V', 'X'
748*404b540aSrobert 	'g', 'i', 'm', 'n', 'o', 'p', 'r', 's' */
749*404b540aSrobert 
750*404b540aSrobert   for (i = 0; i < 256; i++)
751*404b540aSrobert     reg_class_from_letter[i] = NO_REGS;
752*404b540aSrobert 
753*404b540aSrobert   reg_class_from_letter['a'] = ACC_REGS;
754*404b540aSrobert   reg_class_from_letter['b'] = EVEN_ACC_REGS;
755*404b540aSrobert   reg_class_from_letter['c'] = CC_REGS;
756*404b540aSrobert   reg_class_from_letter['d'] = GPR_REGS;
757*404b540aSrobert   reg_class_from_letter['e'] = EVEN_REGS;
758*404b540aSrobert   reg_class_from_letter['f'] = FPR_REGS;
759*404b540aSrobert   reg_class_from_letter['h'] = FEVEN_REGS;
760*404b540aSrobert   reg_class_from_letter['l'] = LR_REG;
761*404b540aSrobert   reg_class_from_letter['q'] = QUAD_REGS;
762*404b540aSrobert   reg_class_from_letter['t'] = ICC_REGS;
763*404b540aSrobert   reg_class_from_letter['u'] = FCC_REGS;
764*404b540aSrobert   reg_class_from_letter['v'] = ICR_REGS;
765*404b540aSrobert   reg_class_from_letter['w'] = FCR_REGS;
766*404b540aSrobert   reg_class_from_letter['x'] = QUAD_FPR_REGS;
767*404b540aSrobert   reg_class_from_letter['y'] = LCR_REG;
768*404b540aSrobert   reg_class_from_letter['z'] = SPR_REGS;
769*404b540aSrobert   reg_class_from_letter['A'] = QUAD_ACC_REGS;
770*404b540aSrobert   reg_class_from_letter['B'] = ACCG_REGS;
771*404b540aSrobert   reg_class_from_letter['C'] = CR_REGS;
772*404b540aSrobert   reg_class_from_letter['W'] = FDPIC_CALL_REGS; /* gp14+15 */
773*404b540aSrobert   reg_class_from_letter['Z'] = FDPIC_REGS; /* gp15 */
774*404b540aSrobert 
775*404b540aSrobert   /* There is no single unaligned SI op for PIC code.  Sometimes we
776*404b540aSrobert      need to use ".4byte" and sometimes we need to use ".picptr".
777*404b540aSrobert      See frv_assemble_integer for details.  */
778*404b540aSrobert   if (flag_pic || TARGET_FDPIC)
779*404b540aSrobert     targetm.asm_out.unaligned_op.si = 0;
780*404b540aSrobert 
781*404b540aSrobert   if ((target_flags_explicit & MASK_LINKED_FP) == 0)
782*404b540aSrobert     target_flags |= MASK_LINKED_FP;
783*404b540aSrobert 
784*404b540aSrobert   if ((target_flags_explicit & MASK_OPTIMIZE_MEMBAR) == 0)
785*404b540aSrobert     target_flags |= MASK_OPTIMIZE_MEMBAR;
786*404b540aSrobert 
787*404b540aSrobert   for (i = 0; i < ARRAY_SIZE (frv_unit_names); i++)
788*404b540aSrobert     frv_unit_codes[i] = get_cpu_unit_code (frv_unit_names[i]);
789*404b540aSrobert 
790*404b540aSrobert   for (i = 0; i < ARRAY_SIZE (frv_type_to_unit); i++)
791*404b540aSrobert     frv_type_to_unit[i] = ARRAY_SIZE (frv_unit_codes);
792*404b540aSrobert 
793*404b540aSrobert   init_machine_status = frv_init_machine_status;
794*404b540aSrobert }
795*404b540aSrobert 
796*404b540aSrobert 
797*404b540aSrobert /* Some machines may desire to change what optimizations are performed for
798*404b540aSrobert    various optimization levels.  This macro, if defined, is executed once just
799*404b540aSrobert    after the optimization level is determined and before the remainder of the
800*404b540aSrobert    command options have been parsed.  Values set in this macro are used as the
801*404b540aSrobert    default values for the other command line options.
802*404b540aSrobert 
803*404b540aSrobert    LEVEL is the optimization level specified; 2 if `-O2' is specified, 1 if
804*404b540aSrobert    `-O' is specified, and 0 if neither is specified.
805*404b540aSrobert 
806*404b540aSrobert    SIZE is nonzero if `-Os' is specified, 0 otherwise.
807*404b540aSrobert 
808*404b540aSrobert    You should not use this macro to change options that are not
809*404b540aSrobert    machine-specific.  These should uniformly selected by the same optimization
810*404b540aSrobert    level on all supported machines.  Use this macro to enable machine-specific
811*404b540aSrobert    optimizations.
812*404b540aSrobert 
813*404b540aSrobert    *Do not examine `write_symbols' in this macro!* The debugging options are
814*404b540aSrobert    *not supposed to alter the generated code.  */
815*404b540aSrobert 
816*404b540aSrobert /* On the FRV, possibly disable VLIW packing which is done by the 2nd
817*404b540aSrobert    scheduling pass at the current time.  */
818*404b540aSrobert void
frv_optimization_options(int level,int size ATTRIBUTE_UNUSED)819*404b540aSrobert frv_optimization_options (int level, int size ATTRIBUTE_UNUSED)
820*404b540aSrobert {
821*404b540aSrobert   if (level >= 2)
822*404b540aSrobert     {
823*404b540aSrobert #ifdef DISABLE_SCHED2
824*404b540aSrobert       flag_schedule_insns_after_reload = 0;
825*404b540aSrobert #endif
826*404b540aSrobert #ifdef ENABLE_RCSP
827*404b540aSrobert       flag_rcsp = 1;
828*404b540aSrobert #endif
829*404b540aSrobert     }
830*404b540aSrobert }
831*404b540aSrobert 
832*404b540aSrobert 
833*404b540aSrobert /* Return true if NAME (a STRING_CST node) begins with PREFIX.  */
834*404b540aSrobert 
835*404b540aSrobert static int
frv_string_begins_with(tree name,const char * prefix)836*404b540aSrobert frv_string_begins_with (tree name, const char *prefix)
837*404b540aSrobert {
838*404b540aSrobert   int prefix_len = strlen (prefix);
839*404b540aSrobert 
840*404b540aSrobert   /* Remember: NAME's length includes the null terminator.  */
841*404b540aSrobert   return (TREE_STRING_LENGTH (name) > prefix_len
842*404b540aSrobert 	  && strncmp (TREE_STRING_POINTER (name), prefix, prefix_len) == 0);
843*404b540aSrobert }
844*404b540aSrobert 
845*404b540aSrobert /* Zero or more C statements that may conditionally modify two variables
846*404b540aSrobert    `fixed_regs' and `call_used_regs' (both of type `char []') after they have
847*404b540aSrobert    been initialized from the two preceding macros.
848*404b540aSrobert 
849*404b540aSrobert    This is necessary in case the fixed or call-clobbered registers depend on
850*404b540aSrobert    target flags.
851*404b540aSrobert 
852*404b540aSrobert    You need not define this macro if it has no work to do.
853*404b540aSrobert 
854*404b540aSrobert    If the usage of an entire class of registers depends on the target flags,
855*404b540aSrobert    you may indicate this to GCC by using this macro to modify `fixed_regs' and
856*404b540aSrobert    `call_used_regs' to 1 for each of the registers in the classes which should
857*404b540aSrobert    not be used by GCC.  Also define the macro `REG_CLASS_FROM_LETTER' to return
858*404b540aSrobert    `NO_REGS' if it is called with a letter for a class that shouldn't be used.
859*404b540aSrobert 
860*404b540aSrobert    (However, if this class is not included in `GENERAL_REGS' and all of the
861*404b540aSrobert    insn patterns whose constraints permit this class are controlled by target
862*404b540aSrobert    switches, then GCC will automatically avoid using these registers when the
863*404b540aSrobert    target switches are opposed to them.)  */
864*404b540aSrobert 
865*404b540aSrobert void
frv_conditional_register_usage(void)866*404b540aSrobert frv_conditional_register_usage (void)
867*404b540aSrobert {
868*404b540aSrobert   int i;
869*404b540aSrobert 
870*404b540aSrobert   for (i = GPR_FIRST + NUM_GPRS; i <= GPR_LAST; i++)
871*404b540aSrobert     fixed_regs[i] = call_used_regs[i] = 1;
872*404b540aSrobert 
873*404b540aSrobert   for (i = FPR_FIRST + NUM_FPRS; i <= FPR_LAST; i++)
874*404b540aSrobert     fixed_regs[i] = call_used_regs[i] = 1;
875*404b540aSrobert 
876*404b540aSrobert   /* Reserve the registers used for conditional execution.  At present, we need
877*404b540aSrobert      1 ICC and 1 ICR register.  */
878*404b540aSrobert   fixed_regs[ICC_TEMP] = call_used_regs[ICC_TEMP] = 1;
879*404b540aSrobert   fixed_regs[ICR_TEMP] = call_used_regs[ICR_TEMP] = 1;
880*404b540aSrobert 
881*404b540aSrobert   if (TARGET_FIXED_CC)
882*404b540aSrobert     {
883*404b540aSrobert       fixed_regs[ICC_FIRST] = call_used_regs[ICC_FIRST] = 1;
884*404b540aSrobert       fixed_regs[FCC_FIRST] = call_used_regs[FCC_FIRST] = 1;
885*404b540aSrobert       fixed_regs[ICR_FIRST] = call_used_regs[ICR_FIRST] = 1;
886*404b540aSrobert       fixed_regs[FCR_FIRST] = call_used_regs[FCR_FIRST] = 1;
887*404b540aSrobert     }
888*404b540aSrobert 
889*404b540aSrobert   if (TARGET_FDPIC)
890*404b540aSrobert     fixed_regs[GPR_FIRST + 16] = fixed_regs[GPR_FIRST + 17] =
891*404b540aSrobert       call_used_regs[GPR_FIRST + 16] = call_used_regs[GPR_FIRST + 17] = 0;
892*404b540aSrobert 
893*404b540aSrobert #if 0
894*404b540aSrobert   /* If -fpic, SDA_BASE_REG is the PIC register.  */
895*404b540aSrobert   if (g_switch_value == 0 && !flag_pic)
896*404b540aSrobert     fixed_regs[SDA_BASE_REG] = call_used_regs[SDA_BASE_REG] = 0;
897*404b540aSrobert 
898*404b540aSrobert   if (!flag_pic)
899*404b540aSrobert     fixed_regs[PIC_REGNO] = call_used_regs[PIC_REGNO] = 0;
900*404b540aSrobert #endif
901*404b540aSrobert }
902*404b540aSrobert 
903*404b540aSrobert 
904*404b540aSrobert /*
905*404b540aSrobert  * Compute the stack frame layout
906*404b540aSrobert  *
907*404b540aSrobert  * Register setup:
908*404b540aSrobert  * +---------------+-----------------------+-----------------------+
909*404b540aSrobert  * |Register       |type                   |caller-save/callee-save|
910*404b540aSrobert  * +---------------+-----------------------+-----------------------+
911*404b540aSrobert  * |GR0            |Zero register          |        -              |
912*404b540aSrobert  * |GR1            |Stack pointer(SP)      |        -              |
913*404b540aSrobert  * |GR2            |Frame pointer(FP)      |        -              |
914*404b540aSrobert  * |GR3            |Hidden parameter       |        caller save    |
915*404b540aSrobert  * |GR4-GR7        |        -              |        caller save    |
916*404b540aSrobert  * |GR8-GR13       |Argument register      |        caller save    |
917*404b540aSrobert  * |GR14-GR15      |        -              |        caller save    |
918*404b540aSrobert  * |GR16-GR31      |        -              |        callee save    |
919*404b540aSrobert  * |GR32-GR47      |        -              |        caller save    |
920*404b540aSrobert  * |GR48-GR63      |        -              |        callee save    |
921*404b540aSrobert  * |FR0-FR15       |        -              |        caller save    |
922*404b540aSrobert  * |FR16-FR31      |        -              |        callee save    |
923*404b540aSrobert  * |FR32-FR47      |        -              |        caller save    |
924*404b540aSrobert  * |FR48-FR63      |        -              |        callee save    |
925*404b540aSrobert  * +---------------+-----------------------+-----------------------+
926*404b540aSrobert  *
927*404b540aSrobert  * Stack frame setup:
928*404b540aSrobert  * Low
929*404b540aSrobert  *     SP-> |-----------------------------------|
930*404b540aSrobert  *	    |         Argument area		|
931*404b540aSrobert  *	    |-----------------------------------|
932*404b540aSrobert  *	    |	 Register save area		|
933*404b540aSrobert  *	    |-----------------------------------|
934*404b540aSrobert  *	    |	Local variable save area	|
935*404b540aSrobert  *     FP-> |-----------------------------------|
936*404b540aSrobert  *	    |	    Old FP			|
937*404b540aSrobert  *	    |-----------------------------------|
938*404b540aSrobert  *	    |    Hidden parameter save area     |
939*404b540aSrobert  *	    |-----------------------------------|
940*404b540aSrobert  *	    | Return address(LR) storage area   |
941*404b540aSrobert  *	    |-----------------------------------|
942*404b540aSrobert  *	    |     Padding for alignment         |
943*404b540aSrobert  *	    |-----------------------------------|
944*404b540aSrobert  *	    |     Register argument area	|
945*404b540aSrobert  * OLD SP-> |-----------------------------------|
946*404b540aSrobert  *          |       Parameter area		|
947*404b540aSrobert  *          |-----------------------------------|
948*404b540aSrobert  * High
949*404b540aSrobert  *
950*404b540aSrobert  * Argument area/Parameter area:
951*404b540aSrobert  *
952*404b540aSrobert  * When a function is called, this area is used for argument transfer.  When
953*404b540aSrobert  * the argument is set up by the caller function, this area is referred to as
954*404b540aSrobert  * the argument area.  When the argument is referenced by the callee function,
955*404b540aSrobert  * this area is referred to as the parameter area.  The area is allocated when
956*404b540aSrobert  * all arguments cannot be placed on the argument register at the time of
957*404b540aSrobert  * argument transfer.
958*404b540aSrobert  *
959*404b540aSrobert  * Register save area:
960*404b540aSrobert  *
961*404b540aSrobert  * This is a register save area that must be guaranteed for the caller
962*404b540aSrobert  * function.  This area is not secured when the register save operation is not
963*404b540aSrobert  * needed.
964*404b540aSrobert  *
965*404b540aSrobert  * Local variable save area:
966*404b540aSrobert  *
967*404b540aSrobert  * This is the area for local variables and temporary variables.
968*404b540aSrobert  *
969*404b540aSrobert  * Old FP:
970*404b540aSrobert  *
971*404b540aSrobert  * This area stores the FP value of the caller function.
972*404b540aSrobert  *
973*404b540aSrobert  * Hidden parameter save area:
974*404b540aSrobert  *
975*404b540aSrobert  * This area stores the start address of the return value storage
976*404b540aSrobert  * area for a struct/union return function.
977*404b540aSrobert  * When a struct/union is used as the return value, the caller
978*404b540aSrobert  * function stores the return value storage area start address in
979*404b540aSrobert  * register GR3 and passes it to the caller function.
980*404b540aSrobert  * The callee function interprets the address stored in the GR3
981*404b540aSrobert  * as the return value storage area start address.
982*404b540aSrobert  * When register GR3 needs to be saved into memory, the callee
983*404b540aSrobert  * function saves it in the hidden parameter save area.  This
984*404b540aSrobert  * area is not secured when the save operation is not needed.
985*404b540aSrobert  *
986*404b540aSrobert  * Return address(LR) storage area:
987*404b540aSrobert  *
988*404b540aSrobert  * This area saves the LR.  The LR stores the address of a return to the caller
989*404b540aSrobert  * function for the purpose of function calling.
990*404b540aSrobert  *
991*404b540aSrobert  * Argument register area:
992*404b540aSrobert  *
993*404b540aSrobert  * This area saves the argument register.  This area is not secured when the
994*404b540aSrobert  * save operation is not needed.
995*404b540aSrobert  *
996*404b540aSrobert  * Argument:
997*404b540aSrobert  *
998*404b540aSrobert  * Arguments, the count of which equals the count of argument registers (6
999*404b540aSrobert  * words), are positioned in registers GR8 to GR13 and delivered to the callee
1000*404b540aSrobert  * function.  When a struct/union return function is called, the return value
1001*404b540aSrobert  * area address is stored in register GR3.  Arguments not placed in the
1002*404b540aSrobert  * argument registers will be stored in the stack argument area for transfer
1003*404b540aSrobert  * purposes.  When an 8-byte type argument is to be delivered using registers,
1004*404b540aSrobert  * it is divided into two and placed in two registers for transfer.  When
1005*404b540aSrobert  * argument registers must be saved to memory, the callee function secures an
1006*404b540aSrobert  * argument register save area in the stack.  In this case, a continuous
1007*404b540aSrobert  * argument register save area must be established in the parameter area.  The
1008*404b540aSrobert  * argument register save area must be allocated as needed to cover the size of
1009*404b540aSrobert  * the argument register to be saved.  If the function has a variable count of
1010*404b540aSrobert  * arguments, it saves all argument registers in the argument register save
1011*404b540aSrobert  * area.
1012*404b540aSrobert  *
1013*404b540aSrobert  * Argument Extension Format:
1014*404b540aSrobert  *
1015*404b540aSrobert  * When an argument is to be stored in the stack, its type is converted to an
1016*404b540aSrobert  * extended type in accordance with the individual argument type.  The argument
1017*404b540aSrobert  * is freed by the caller function after the return from the callee function is
1018*404b540aSrobert  * made.
1019*404b540aSrobert  *
1020*404b540aSrobert  * +-----------------------+---------------+------------------------+
1021*404b540aSrobert  * |    Argument Type      |Extended Type  |Stack Storage Size(byte)|
1022*404b540aSrobert  * +-----------------------+---------------+------------------------+
1023*404b540aSrobert  * |char                   |int            |        4		    |
1024*404b540aSrobert  * |signed char            |int            |        4		    |
1025*404b540aSrobert  * |unsigned char          |int            |        4		    |
1026*404b540aSrobert  * |[signed] short int     |int            |        4		    |
1027*404b540aSrobert  * |unsigned short int     |int            |        4		    |
1028*404b540aSrobert  * |[signed] int           |No extension   |        4		    |
1029*404b540aSrobert  * |unsigned int           |No extension   |        4		    |
1030*404b540aSrobert  * |[signed] long int      |No extension   |        4		    |
1031*404b540aSrobert  * |unsigned long int      |No extension   |        4		    |
1032*404b540aSrobert  * |[signed] long long int |No extension   |        8		    |
1033*404b540aSrobert  * |unsigned long long int |No extension   |        8		    |
1034*404b540aSrobert  * |float                  |double         |        8		    |
1035*404b540aSrobert  * |double                 |No extension   |        8		    |
1036*404b540aSrobert  * |long double            |No extension   |        8		    |
1037*404b540aSrobert  * |pointer                |No extension   |        4		    |
1038*404b540aSrobert  * |struct/union           |-              |        4 (*1)	    |
1039*404b540aSrobert  * +-----------------------+---------------+------------------------+
1040*404b540aSrobert  *
1041*404b540aSrobert  * When a struct/union is to be delivered as an argument, the caller copies it
1042*404b540aSrobert  * to the local variable area and delivers the address of that area.
1043*404b540aSrobert  *
1044*404b540aSrobert  * Return Value:
1045*404b540aSrobert  *
1046*404b540aSrobert  * +-------------------------------+----------------------+
1047*404b540aSrobert  * |Return Value Type              |Return Value Interface|
1048*404b540aSrobert  * +-------------------------------+----------------------+
1049*404b540aSrobert  * |void                           |None                  |
1050*404b540aSrobert  * |[signed|unsigned] char         |GR8                   |
1051*404b540aSrobert  * |[signed|unsigned] short int    |GR8                   |
1052*404b540aSrobert  * |[signed|unsigned] int          |GR8                   |
1053*404b540aSrobert  * |[signed|unsigned] long int     |GR8                   |
1054*404b540aSrobert  * |pointer                        |GR8                   |
1055*404b540aSrobert  * |[signed|unsigned] long long int|GR8 & GR9             |
1056*404b540aSrobert  * |float                          |GR8                   |
1057*404b540aSrobert  * |double                         |GR8 & GR9             |
1058*404b540aSrobert  * |long double                    |GR8 & GR9             |
1059*404b540aSrobert  * |struct/union                   |(*1)                  |
1060*404b540aSrobert  * +-------------------------------+----------------------+
1061*404b540aSrobert  *
1062*404b540aSrobert  * When a struct/union is used as the return value, the caller function stores
1063*404b540aSrobert  * the start address of the return value storage area into GR3 and then passes
1064*404b540aSrobert  * it to the callee function.  The callee function interprets GR3 as the start
1065*404b540aSrobert  * address of the return value storage area.  When this address needs to be
1066*404b540aSrobert  * saved in memory, the callee function secures the hidden parameter save area
1067*404b540aSrobert  * and saves the address in that area.
1068*404b540aSrobert  */
1069*404b540aSrobert 
1070*404b540aSrobert frv_stack_t *
frv_stack_info(void)1071*404b540aSrobert frv_stack_info (void)
1072*404b540aSrobert {
1073*404b540aSrobert   static frv_stack_t info, zero_info;
1074*404b540aSrobert   frv_stack_t *info_ptr	= &info;
1075*404b540aSrobert   tree fndecl		= current_function_decl;
1076*404b540aSrobert   int varargs_p		= 0;
1077*404b540aSrobert   tree cur_arg;
1078*404b540aSrobert   tree next_arg;
1079*404b540aSrobert   int range;
1080*404b540aSrobert   int alignment;
1081*404b540aSrobert   int offset;
1082*404b540aSrobert 
1083*404b540aSrobert   /* If we've already calculated the values and reload is complete,
1084*404b540aSrobert      just return now.  */
1085*404b540aSrobert   if (frv_stack_cache)
1086*404b540aSrobert     return frv_stack_cache;
1087*404b540aSrobert 
1088*404b540aSrobert   /* Zero all fields.  */
1089*404b540aSrobert   info = zero_info;
1090*404b540aSrobert 
1091*404b540aSrobert   /* Set up the register range information.  */
1092*404b540aSrobert   info_ptr->regs[STACK_REGS_GPR].name         = "gpr";
1093*404b540aSrobert   info_ptr->regs[STACK_REGS_GPR].first        = LAST_ARG_REGNUM + 1;
1094*404b540aSrobert   info_ptr->regs[STACK_REGS_GPR].last         = GPR_LAST;
1095*404b540aSrobert   info_ptr->regs[STACK_REGS_GPR].dword_p      = TRUE;
1096*404b540aSrobert 
1097*404b540aSrobert   info_ptr->regs[STACK_REGS_FPR].name         = "fpr";
1098*404b540aSrobert   info_ptr->regs[STACK_REGS_FPR].first        = FPR_FIRST;
1099*404b540aSrobert   info_ptr->regs[STACK_REGS_FPR].last         = FPR_LAST;
1100*404b540aSrobert   info_ptr->regs[STACK_REGS_FPR].dword_p      = TRUE;
1101*404b540aSrobert 
1102*404b540aSrobert   info_ptr->regs[STACK_REGS_LR].name          = "lr";
1103*404b540aSrobert   info_ptr->regs[STACK_REGS_LR].first         = LR_REGNO;
1104*404b540aSrobert   info_ptr->regs[STACK_REGS_LR].last          = LR_REGNO;
1105*404b540aSrobert   info_ptr->regs[STACK_REGS_LR].special_p     = 1;
1106*404b540aSrobert 
1107*404b540aSrobert   info_ptr->regs[STACK_REGS_CC].name          = "cc";
1108*404b540aSrobert   info_ptr->regs[STACK_REGS_CC].first         = CC_FIRST;
1109*404b540aSrobert   info_ptr->regs[STACK_REGS_CC].last          = CC_LAST;
1110*404b540aSrobert   info_ptr->regs[STACK_REGS_CC].field_p       = TRUE;
1111*404b540aSrobert 
1112*404b540aSrobert   info_ptr->regs[STACK_REGS_LCR].name         = "lcr";
1113*404b540aSrobert   info_ptr->regs[STACK_REGS_LCR].first        = LCR_REGNO;
1114*404b540aSrobert   info_ptr->regs[STACK_REGS_LCR].last         = LCR_REGNO;
1115*404b540aSrobert 
1116*404b540aSrobert   info_ptr->regs[STACK_REGS_STDARG].name      = "stdarg";
1117*404b540aSrobert   info_ptr->regs[STACK_REGS_STDARG].first     = FIRST_ARG_REGNUM;
1118*404b540aSrobert   info_ptr->regs[STACK_REGS_STDARG].last      = LAST_ARG_REGNUM;
1119*404b540aSrobert   info_ptr->regs[STACK_REGS_STDARG].dword_p   = 1;
1120*404b540aSrobert   info_ptr->regs[STACK_REGS_STDARG].special_p = 1;
1121*404b540aSrobert 
1122*404b540aSrobert   info_ptr->regs[STACK_REGS_STRUCT].name      = "struct";
1123*404b540aSrobert   info_ptr->regs[STACK_REGS_STRUCT].first     = FRV_STRUCT_VALUE_REGNUM;
1124*404b540aSrobert   info_ptr->regs[STACK_REGS_STRUCT].last      = FRV_STRUCT_VALUE_REGNUM;
1125*404b540aSrobert   info_ptr->regs[STACK_REGS_STRUCT].special_p = 1;
1126*404b540aSrobert 
1127*404b540aSrobert   info_ptr->regs[STACK_REGS_FP].name          = "fp";
1128*404b540aSrobert   info_ptr->regs[STACK_REGS_FP].first         = FRAME_POINTER_REGNUM;
1129*404b540aSrobert   info_ptr->regs[STACK_REGS_FP].last          = FRAME_POINTER_REGNUM;
1130*404b540aSrobert   info_ptr->regs[STACK_REGS_FP].special_p     = 1;
1131*404b540aSrobert 
1132*404b540aSrobert   /* Determine if this is a stdarg function.  If so, allocate space to store
1133*404b540aSrobert      the 6 arguments.  */
1134*404b540aSrobert   if (cfun->stdarg)
1135*404b540aSrobert     varargs_p = 1;
1136*404b540aSrobert 
1137*404b540aSrobert   else
1138*404b540aSrobert     {
1139*404b540aSrobert       /* Find the last argument, and see if it is __builtin_va_alist.  */
1140*404b540aSrobert       for (cur_arg = DECL_ARGUMENTS (fndecl); cur_arg != (tree)0; cur_arg = next_arg)
1141*404b540aSrobert 	{
1142*404b540aSrobert 	  next_arg = TREE_CHAIN (cur_arg);
1143*404b540aSrobert 	  if (next_arg == (tree)0)
1144*404b540aSrobert 	    {
1145*404b540aSrobert 	      if (DECL_NAME (cur_arg)
1146*404b540aSrobert 		  && !strcmp (IDENTIFIER_POINTER (DECL_NAME (cur_arg)), "__builtin_va_alist"))
1147*404b540aSrobert 		varargs_p = 1;
1148*404b540aSrobert 
1149*404b540aSrobert 	      break;
1150*404b540aSrobert 	    }
1151*404b540aSrobert 	}
1152*404b540aSrobert     }
1153*404b540aSrobert 
1154*404b540aSrobert   /* Iterate over all of the register ranges.  */
1155*404b540aSrobert   for (range = 0; range < STACK_REGS_MAX; range++)
1156*404b540aSrobert     {
1157*404b540aSrobert       frv_stack_regs_t *reg_ptr = &(info_ptr->regs[range]);
1158*404b540aSrobert       int first = reg_ptr->first;
1159*404b540aSrobert       int last = reg_ptr->last;
1160*404b540aSrobert       int size_1word = 0;
1161*404b540aSrobert       int size_2words = 0;
1162*404b540aSrobert       int regno;
1163*404b540aSrobert 
1164*404b540aSrobert       /* Calculate which registers need to be saved & save area size.  */
1165*404b540aSrobert       switch (range)
1166*404b540aSrobert 	{
1167*404b540aSrobert 	default:
1168*404b540aSrobert 	  for (regno = first; regno <= last; regno++)
1169*404b540aSrobert 	    {
1170*404b540aSrobert 	      if ((regs_ever_live[regno] && !call_used_regs[regno])
1171*404b540aSrobert 		  || (current_function_calls_eh_return
1172*404b540aSrobert 		      && (regno >= FIRST_EH_REGNUM && regno <= LAST_EH_REGNUM))
1173*404b540aSrobert 		  || (!TARGET_FDPIC && flag_pic
1174*404b540aSrobert 		      && cfun->uses_pic_offset_table && regno == PIC_REGNO))
1175*404b540aSrobert 		{
1176*404b540aSrobert 		  info_ptr->save_p[regno] = REG_SAVE_1WORD;
1177*404b540aSrobert 		  size_1word += UNITS_PER_WORD;
1178*404b540aSrobert 		}
1179*404b540aSrobert 	    }
1180*404b540aSrobert 	  break;
1181*404b540aSrobert 
1182*404b540aSrobert 	  /* Calculate whether we need to create a frame after everything else
1183*404b540aSrobert              has been processed.  */
1184*404b540aSrobert 	case STACK_REGS_FP:
1185*404b540aSrobert 	  break;
1186*404b540aSrobert 
1187*404b540aSrobert 	case STACK_REGS_LR:
1188*404b540aSrobert 	  if (regs_ever_live[LR_REGNO]
1189*404b540aSrobert               || profile_flag
1190*404b540aSrobert 	      /* This is set for __builtin_return_address, etc.  */
1191*404b540aSrobert 	      || cfun->machine->frame_needed
1192*404b540aSrobert               || (TARGET_LINKED_FP && frame_pointer_needed)
1193*404b540aSrobert               || (!TARGET_FDPIC && flag_pic
1194*404b540aSrobert 		  && cfun->uses_pic_offset_table))
1195*404b540aSrobert 	    {
1196*404b540aSrobert 	      info_ptr->save_p[LR_REGNO] = REG_SAVE_1WORD;
1197*404b540aSrobert 	      size_1word += UNITS_PER_WORD;
1198*404b540aSrobert 	    }
1199*404b540aSrobert 	  break;
1200*404b540aSrobert 
1201*404b540aSrobert 	case STACK_REGS_STDARG:
1202*404b540aSrobert 	  if (varargs_p)
1203*404b540aSrobert 	    {
1204*404b540aSrobert 	      /* If this is a stdarg function with a non varardic
1205*404b540aSrobert 		 argument split between registers and the stack,
1206*404b540aSrobert 		 adjust the saved registers downward.  */
1207*404b540aSrobert 	      last -= (ADDR_ALIGN (cfun->pretend_args_size, UNITS_PER_WORD)
1208*404b540aSrobert 		       / UNITS_PER_WORD);
1209*404b540aSrobert 
1210*404b540aSrobert 	      for (regno = first; regno <= last; regno++)
1211*404b540aSrobert 		{
1212*404b540aSrobert 		  info_ptr->save_p[regno] = REG_SAVE_1WORD;
1213*404b540aSrobert 		  size_1word += UNITS_PER_WORD;
1214*404b540aSrobert 		}
1215*404b540aSrobert 
1216*404b540aSrobert 	      info_ptr->stdarg_size = size_1word;
1217*404b540aSrobert 	    }
1218*404b540aSrobert 	  break;
1219*404b540aSrobert 
1220*404b540aSrobert 	case STACK_REGS_STRUCT:
1221*404b540aSrobert 	  if (cfun->returns_struct)
1222*404b540aSrobert 	    {
1223*404b540aSrobert 	      info_ptr->save_p[FRV_STRUCT_VALUE_REGNUM] = REG_SAVE_1WORD;
1224*404b540aSrobert 	      size_1word += UNITS_PER_WORD;
1225*404b540aSrobert 	    }
1226*404b540aSrobert 	  break;
1227*404b540aSrobert 	}
1228*404b540aSrobert 
1229*404b540aSrobert 
1230*404b540aSrobert       if (size_1word)
1231*404b540aSrobert 	{
1232*404b540aSrobert 	  /* If this is a field, it only takes one word.  */
1233*404b540aSrobert 	  if (reg_ptr->field_p)
1234*404b540aSrobert 	    size_1word = UNITS_PER_WORD;
1235*404b540aSrobert 
1236*404b540aSrobert 	  /* Determine which register pairs can be saved together.  */
1237*404b540aSrobert 	  else if (reg_ptr->dword_p && TARGET_DWORD)
1238*404b540aSrobert 	    {
1239*404b540aSrobert 	      for (regno = first; regno < last; regno += 2)
1240*404b540aSrobert 		{
1241*404b540aSrobert 		  if (info_ptr->save_p[regno] && info_ptr->save_p[regno+1])
1242*404b540aSrobert 		    {
1243*404b540aSrobert 		      size_2words += 2 * UNITS_PER_WORD;
1244*404b540aSrobert 		      size_1word -= 2 * UNITS_PER_WORD;
1245*404b540aSrobert 		      info_ptr->save_p[regno] = REG_SAVE_2WORDS;
1246*404b540aSrobert 		      info_ptr->save_p[regno+1] = REG_SAVE_NO_SAVE;
1247*404b540aSrobert 		    }
1248*404b540aSrobert 		}
1249*404b540aSrobert 	    }
1250*404b540aSrobert 
1251*404b540aSrobert 	  reg_ptr->size_1word = size_1word;
1252*404b540aSrobert 	  reg_ptr->size_2words = size_2words;
1253*404b540aSrobert 
1254*404b540aSrobert 	  if (! reg_ptr->special_p)
1255*404b540aSrobert 	    {
1256*404b540aSrobert 	      info_ptr->regs_size_1word += size_1word;
1257*404b540aSrobert 	      info_ptr->regs_size_2words += size_2words;
1258*404b540aSrobert 	    }
1259*404b540aSrobert 	}
1260*404b540aSrobert     }
1261*404b540aSrobert 
1262*404b540aSrobert   /* Set up the sizes of each each field in the frame body, making the sizes
1263*404b540aSrobert      of each be divisible by the size of a dword if dword operations might
1264*404b540aSrobert      be used, or the size of a word otherwise.  */
1265*404b540aSrobert   alignment = (TARGET_DWORD? 2 * UNITS_PER_WORD : UNITS_PER_WORD);
1266*404b540aSrobert 
1267*404b540aSrobert   info_ptr->parameter_size = ADDR_ALIGN (cfun->outgoing_args_size, alignment);
1268*404b540aSrobert   info_ptr->regs_size = ADDR_ALIGN (info_ptr->regs_size_2words
1269*404b540aSrobert 				    + info_ptr->regs_size_1word,
1270*404b540aSrobert 				    alignment);
1271*404b540aSrobert   info_ptr->vars_size = ADDR_ALIGN (get_frame_size (), alignment);
1272*404b540aSrobert 
1273*404b540aSrobert   info_ptr->pretend_size = cfun->pretend_args_size;
1274*404b540aSrobert 
1275*404b540aSrobert   /* Work out the size of the frame, excluding the header.  Both the frame
1276*404b540aSrobert      body and register parameter area will be dword-aligned.  */
1277*404b540aSrobert   info_ptr->total_size
1278*404b540aSrobert     = (ADDR_ALIGN (info_ptr->parameter_size
1279*404b540aSrobert 		   + info_ptr->regs_size
1280*404b540aSrobert 		   + info_ptr->vars_size,
1281*404b540aSrobert 		   2 * UNITS_PER_WORD)
1282*404b540aSrobert        + ADDR_ALIGN (info_ptr->pretend_size
1283*404b540aSrobert 		     + info_ptr->stdarg_size,
1284*404b540aSrobert 		     2 * UNITS_PER_WORD));
1285*404b540aSrobert 
1286*404b540aSrobert   /* See if we need to create a frame at all, if so add header area.  */
1287*404b540aSrobert   if (info_ptr->total_size  > 0
1288*404b540aSrobert       || frame_pointer_needed
1289*404b540aSrobert       || info_ptr->regs[STACK_REGS_LR].size_1word > 0
1290*404b540aSrobert       || info_ptr->regs[STACK_REGS_STRUCT].size_1word > 0)
1291*404b540aSrobert     {
1292*404b540aSrobert       offset = info_ptr->parameter_size;
1293*404b540aSrobert       info_ptr->header_size = 4 * UNITS_PER_WORD;
1294*404b540aSrobert       info_ptr->total_size += 4 * UNITS_PER_WORD;
1295*404b540aSrobert 
1296*404b540aSrobert       /* Calculate the offsets to save normal register pairs.  */
1297*404b540aSrobert       for (range = 0; range < STACK_REGS_MAX; range++)
1298*404b540aSrobert 	{
1299*404b540aSrobert 	  frv_stack_regs_t *reg_ptr = &(info_ptr->regs[range]);
1300*404b540aSrobert 	  if (! reg_ptr->special_p)
1301*404b540aSrobert 	    {
1302*404b540aSrobert 	      int first = reg_ptr->first;
1303*404b540aSrobert 	      int last = reg_ptr->last;
1304*404b540aSrobert 	      int regno;
1305*404b540aSrobert 
1306*404b540aSrobert 	      for (regno = first; regno <= last; regno++)
1307*404b540aSrobert 		if (info_ptr->save_p[regno] == REG_SAVE_2WORDS
1308*404b540aSrobert 		    && regno != FRAME_POINTER_REGNUM
1309*404b540aSrobert 		    && (regno < FIRST_ARG_REGNUM
1310*404b540aSrobert 			|| regno > LAST_ARG_REGNUM))
1311*404b540aSrobert 		  {
1312*404b540aSrobert 		    info_ptr->reg_offset[regno] = offset;
1313*404b540aSrobert 		    offset += 2 * UNITS_PER_WORD;
1314*404b540aSrobert 		  }
1315*404b540aSrobert 	    }
1316*404b540aSrobert 	}
1317*404b540aSrobert 
1318*404b540aSrobert       /* Calculate the offsets to save normal single registers.  */
1319*404b540aSrobert       for (range = 0; range < STACK_REGS_MAX; range++)
1320*404b540aSrobert 	{
1321*404b540aSrobert 	  frv_stack_regs_t *reg_ptr = &(info_ptr->regs[range]);
1322*404b540aSrobert 	  if (! reg_ptr->special_p)
1323*404b540aSrobert 	    {
1324*404b540aSrobert 	      int first = reg_ptr->first;
1325*404b540aSrobert 	      int last = reg_ptr->last;
1326*404b540aSrobert 	      int regno;
1327*404b540aSrobert 
1328*404b540aSrobert 	      for (regno = first; regno <= last; regno++)
1329*404b540aSrobert 		if (info_ptr->save_p[regno] == REG_SAVE_1WORD
1330*404b540aSrobert 		    && regno != FRAME_POINTER_REGNUM
1331*404b540aSrobert 		    && (regno < FIRST_ARG_REGNUM
1332*404b540aSrobert 			|| regno > LAST_ARG_REGNUM))
1333*404b540aSrobert 		  {
1334*404b540aSrobert 		    info_ptr->reg_offset[regno] = offset;
1335*404b540aSrobert 		    offset += UNITS_PER_WORD;
1336*404b540aSrobert 		  }
1337*404b540aSrobert 	    }
1338*404b540aSrobert 	}
1339*404b540aSrobert 
1340*404b540aSrobert       /* Calculate the offset to save the local variables at.  */
1341*404b540aSrobert       offset = ADDR_ALIGN (offset, alignment);
1342*404b540aSrobert       if (info_ptr->vars_size)
1343*404b540aSrobert 	{
1344*404b540aSrobert 	  info_ptr->vars_offset = offset;
1345*404b540aSrobert 	  offset += info_ptr->vars_size;
1346*404b540aSrobert 	}
1347*404b540aSrobert 
1348*404b540aSrobert       /* Align header to a dword-boundary.  */
1349*404b540aSrobert       offset = ADDR_ALIGN (offset, 2 * UNITS_PER_WORD);
1350*404b540aSrobert 
1351*404b540aSrobert       /* Calculate the offsets in the fixed frame.  */
1352*404b540aSrobert       info_ptr->save_p[FRAME_POINTER_REGNUM] = REG_SAVE_1WORD;
1353*404b540aSrobert       info_ptr->reg_offset[FRAME_POINTER_REGNUM] = offset;
1354*404b540aSrobert       info_ptr->regs[STACK_REGS_FP].size_1word = UNITS_PER_WORD;
1355*404b540aSrobert 
1356*404b540aSrobert       info_ptr->save_p[LR_REGNO] = REG_SAVE_1WORD;
1357*404b540aSrobert       info_ptr->reg_offset[LR_REGNO] = offset + 2*UNITS_PER_WORD;
1358*404b540aSrobert       info_ptr->regs[STACK_REGS_LR].size_1word = UNITS_PER_WORD;
1359*404b540aSrobert 
1360*404b540aSrobert       if (cfun->returns_struct)
1361*404b540aSrobert 	{
1362*404b540aSrobert 	  info_ptr->save_p[FRV_STRUCT_VALUE_REGNUM] = REG_SAVE_1WORD;
1363*404b540aSrobert 	  info_ptr->reg_offset[FRV_STRUCT_VALUE_REGNUM] = offset + UNITS_PER_WORD;
1364*404b540aSrobert 	  info_ptr->regs[STACK_REGS_STRUCT].size_1word = UNITS_PER_WORD;
1365*404b540aSrobert 	}
1366*404b540aSrobert 
1367*404b540aSrobert       /* Calculate the offsets to store the arguments passed in registers
1368*404b540aSrobert          for stdarg functions.  The register pairs are first and the single
1369*404b540aSrobert          register if any is last.  The register save area starts on a
1370*404b540aSrobert          dword-boundary.  */
1371*404b540aSrobert       if (info_ptr->stdarg_size)
1372*404b540aSrobert 	{
1373*404b540aSrobert 	  int first = info_ptr->regs[STACK_REGS_STDARG].first;
1374*404b540aSrobert 	  int last  = info_ptr->regs[STACK_REGS_STDARG].last;
1375*404b540aSrobert 	  int regno;
1376*404b540aSrobert 
1377*404b540aSrobert 	  /* Skip the header.  */
1378*404b540aSrobert 	  offset += 4 * UNITS_PER_WORD;
1379*404b540aSrobert 	  for (regno = first; regno <= last; regno++)
1380*404b540aSrobert 	    {
1381*404b540aSrobert 	      if (info_ptr->save_p[regno] == REG_SAVE_2WORDS)
1382*404b540aSrobert 		{
1383*404b540aSrobert 		  info_ptr->reg_offset[regno] = offset;
1384*404b540aSrobert 		  offset += 2 * UNITS_PER_WORD;
1385*404b540aSrobert 		}
1386*404b540aSrobert 	      else if (info_ptr->save_p[regno] == REG_SAVE_1WORD)
1387*404b540aSrobert 		{
1388*404b540aSrobert 		  info_ptr->reg_offset[regno] = offset;
1389*404b540aSrobert 		  offset += UNITS_PER_WORD;
1390*404b540aSrobert 		}
1391*404b540aSrobert 	    }
1392*404b540aSrobert 	}
1393*404b540aSrobert     }
1394*404b540aSrobert 
1395*404b540aSrobert   if (reload_completed)
1396*404b540aSrobert     frv_stack_cache = info_ptr;
1397*404b540aSrobert 
1398*404b540aSrobert   return info_ptr;
1399*404b540aSrobert }
1400*404b540aSrobert 
1401*404b540aSrobert 
1402*404b540aSrobert /* Print the information about the frv stack offsets, etc. when debugging.  */
1403*404b540aSrobert 
1404*404b540aSrobert void
frv_debug_stack(frv_stack_t * info)1405*404b540aSrobert frv_debug_stack (frv_stack_t *info)
1406*404b540aSrobert {
1407*404b540aSrobert   int range;
1408*404b540aSrobert 
1409*404b540aSrobert   if (!info)
1410*404b540aSrobert     info = frv_stack_info ();
1411*404b540aSrobert 
1412*404b540aSrobert   fprintf (stderr, "\nStack information for function %s:\n",
1413*404b540aSrobert 	   ((current_function_decl && DECL_NAME (current_function_decl))
1414*404b540aSrobert 	    ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
1415*404b540aSrobert 	    : "<unknown>"));
1416*404b540aSrobert 
1417*404b540aSrobert   fprintf (stderr, "\ttotal_size\t= %6d\n", info->total_size);
1418*404b540aSrobert   fprintf (stderr, "\tvars_size\t= %6d\n", info->vars_size);
1419*404b540aSrobert   fprintf (stderr, "\tparam_size\t= %6d\n", info->parameter_size);
1420*404b540aSrobert   fprintf (stderr, "\tregs_size\t= %6d, 1w = %3d, 2w = %3d\n",
1421*404b540aSrobert 	   info->regs_size, info->regs_size_1word, info->regs_size_2words);
1422*404b540aSrobert 
1423*404b540aSrobert   fprintf (stderr, "\theader_size\t= %6d\n", info->header_size);
1424*404b540aSrobert   fprintf (stderr, "\tpretend_size\t= %6d\n", info->pretend_size);
1425*404b540aSrobert   fprintf (stderr, "\tvars_offset\t= %6d\n", info->vars_offset);
1426*404b540aSrobert   fprintf (stderr, "\tregs_offset\t= %6d\n", info->regs_offset);
1427*404b540aSrobert 
1428*404b540aSrobert   for (range = 0; range < STACK_REGS_MAX; range++)
1429*404b540aSrobert     {
1430*404b540aSrobert       frv_stack_regs_t *regs = &(info->regs[range]);
1431*404b540aSrobert       if ((regs->size_1word + regs->size_2words) > 0)
1432*404b540aSrobert 	{
1433*404b540aSrobert 	  int first = regs->first;
1434*404b540aSrobert 	  int last  = regs->last;
1435*404b540aSrobert 	  int regno;
1436*404b540aSrobert 
1437*404b540aSrobert 	  fprintf (stderr, "\t%s\tsize\t= %6d, 1w = %3d, 2w = %3d, save =",
1438*404b540aSrobert 		   regs->name, regs->size_1word + regs->size_2words,
1439*404b540aSrobert 		   regs->size_1word, regs->size_2words);
1440*404b540aSrobert 
1441*404b540aSrobert 	  for (regno = first; regno <= last; regno++)
1442*404b540aSrobert 	    {
1443*404b540aSrobert 	      if (info->save_p[regno] == REG_SAVE_1WORD)
1444*404b540aSrobert 		fprintf (stderr, " %s (%d)", reg_names[regno],
1445*404b540aSrobert 			 info->reg_offset[regno]);
1446*404b540aSrobert 
1447*404b540aSrobert 	      else if (info->save_p[regno] == REG_SAVE_2WORDS)
1448*404b540aSrobert 		fprintf (stderr, " %s-%s (%d)", reg_names[regno],
1449*404b540aSrobert 			 reg_names[regno+1], info->reg_offset[regno]);
1450*404b540aSrobert 	    }
1451*404b540aSrobert 
1452*404b540aSrobert 	  fputc ('\n', stderr);
1453*404b540aSrobert 	}
1454*404b540aSrobert     }
1455*404b540aSrobert 
1456*404b540aSrobert   fflush (stderr);
1457*404b540aSrobert }
1458*404b540aSrobert 
1459*404b540aSrobert 
1460*404b540aSrobert 
1461*404b540aSrobert 
1462*404b540aSrobert /* Used during final to control the packing of insns.  The value is
1463*404b540aSrobert    1 if the current instruction should be packed with the next one,
1464*404b540aSrobert    0 if it shouldn't or -1 if packing is disabled altogether.  */
1465*404b540aSrobert 
1466*404b540aSrobert static int frv_insn_packing_flag;
1467*404b540aSrobert 
1468*404b540aSrobert /* True if the current function contains a far jump.  */
1469*404b540aSrobert 
1470*404b540aSrobert static int
frv_function_contains_far_jump(void)1471*404b540aSrobert frv_function_contains_far_jump (void)
1472*404b540aSrobert {
1473*404b540aSrobert   rtx insn = get_insns ();
1474*404b540aSrobert   while (insn != NULL
1475*404b540aSrobert 	 && !(GET_CODE (insn) == JUMP_INSN
1476*404b540aSrobert 	      /* Ignore tablejump patterns.  */
1477*404b540aSrobert 	      && GET_CODE (PATTERN (insn)) != ADDR_VEC
1478*404b540aSrobert 	      && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
1479*404b540aSrobert 	      && get_attr_far_jump (insn) == FAR_JUMP_YES))
1480*404b540aSrobert     insn = NEXT_INSN (insn);
1481*404b540aSrobert   return (insn != NULL);
1482*404b540aSrobert }
1483*404b540aSrobert 
1484*404b540aSrobert /* For the FRV, this function makes sure that a function with far jumps
1485*404b540aSrobert    will return correctly.  It also does the VLIW packing.  */
1486*404b540aSrobert 
1487*404b540aSrobert static void
frv_function_prologue(FILE * file,HOST_WIDE_INT size ATTRIBUTE_UNUSED)1488*404b540aSrobert frv_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1489*404b540aSrobert {
1490*404b540aSrobert   /* If no frame was created, check whether the function uses a call
1491*404b540aSrobert      instruction to implement a far jump.  If so, save the link in gr3 and
1492*404b540aSrobert      replace all returns to LR with returns to GR3.  GR3 is used because it
1493*404b540aSrobert      is call-clobbered, because is not available to the register allocator,
1494*404b540aSrobert      and because all functions that take a hidden argument pointer will have
1495*404b540aSrobert      a stack frame.  */
1496*404b540aSrobert   if (frv_stack_info ()->total_size == 0 && frv_function_contains_far_jump ())
1497*404b540aSrobert     {
1498*404b540aSrobert       rtx insn;
1499*404b540aSrobert 
1500*404b540aSrobert       /* Just to check that the above comment is true.  */
1501*404b540aSrobert       gcc_assert (!regs_ever_live[GPR_FIRST + 3]);
1502*404b540aSrobert 
1503*404b540aSrobert       /* Generate the instruction that saves the link register.  */
1504*404b540aSrobert       fprintf (file, "\tmovsg lr,gr3\n");
1505*404b540aSrobert 
1506*404b540aSrobert       /* Replace the LR with GR3 in *return_internal patterns.  The insn
1507*404b540aSrobert 	 will now return using jmpl @(gr3,0) rather than bralr.  We cannot
1508*404b540aSrobert 	 simply emit a different assembly directive because bralr and jmpl
1509*404b540aSrobert 	 execute in different units.  */
1510*404b540aSrobert       for (insn = get_insns(); insn != NULL; insn = NEXT_INSN (insn))
1511*404b540aSrobert 	if (GET_CODE (insn) == JUMP_INSN)
1512*404b540aSrobert 	  {
1513*404b540aSrobert 	    rtx pattern = PATTERN (insn);
1514*404b540aSrobert 	    if (GET_CODE (pattern) == PARALLEL
1515*404b540aSrobert 		&& XVECLEN (pattern, 0) >= 2
1516*404b540aSrobert 		&& GET_CODE (XVECEXP (pattern, 0, 0)) == RETURN
1517*404b540aSrobert 		&& GET_CODE (XVECEXP (pattern, 0, 1)) == USE)
1518*404b540aSrobert 	      {
1519*404b540aSrobert 		rtx address = XEXP (XVECEXP (pattern, 0, 1), 0);
1520*404b540aSrobert 		if (GET_CODE (address) == REG && REGNO (address) == LR_REGNO)
1521*404b540aSrobert 		  REGNO (address) = GPR_FIRST + 3;
1522*404b540aSrobert 	      }
1523*404b540aSrobert 	  }
1524*404b540aSrobert     }
1525*404b540aSrobert 
1526*404b540aSrobert   frv_pack_insns ();
1527*404b540aSrobert 
1528*404b540aSrobert   /* Allow the garbage collector to free the nops created by frv_reorg.  */
1529*404b540aSrobert   memset (frv_nops, 0, sizeof (frv_nops));
1530*404b540aSrobert }
1531*404b540aSrobert 
1532*404b540aSrobert 
1533*404b540aSrobert /* Return the next available temporary register in a given class.  */
1534*404b540aSrobert 
1535*404b540aSrobert static rtx
frv_alloc_temp_reg(frv_tmp_reg_t * info,enum reg_class class,enum machine_mode mode,int mark_as_used,int no_abort)1536*404b540aSrobert frv_alloc_temp_reg (
1537*404b540aSrobert      frv_tmp_reg_t *info,	/* which registers are available */
1538*404b540aSrobert      enum reg_class class,	/* register class desired */
1539*404b540aSrobert      enum machine_mode mode,	/* mode to allocate register with */
1540*404b540aSrobert      int mark_as_used,		/* register not available after allocation */
1541*404b540aSrobert      int no_abort)		/* return NULL instead of aborting */
1542*404b540aSrobert {
1543*404b540aSrobert   int regno = info->next_reg[ (int)class ];
1544*404b540aSrobert   int orig_regno = regno;
1545*404b540aSrobert   HARD_REG_SET *reg_in_class = &reg_class_contents[ (int)class ];
1546*404b540aSrobert   int i, nr;
1547*404b540aSrobert 
1548*404b540aSrobert   for (;;)
1549*404b540aSrobert     {
1550*404b540aSrobert       if (TEST_HARD_REG_BIT (*reg_in_class, regno)
1551*404b540aSrobert 	  && TEST_HARD_REG_BIT (info->regs, regno))
1552*404b540aSrobert 	  break;
1553*404b540aSrobert 
1554*404b540aSrobert       if (++regno >= FIRST_PSEUDO_REGISTER)
1555*404b540aSrobert 	regno = 0;
1556*404b540aSrobert       if (regno == orig_regno)
1557*404b540aSrobert 	{
1558*404b540aSrobert 	  gcc_assert (no_abort);
1559*404b540aSrobert 	  return NULL_RTX;
1560*404b540aSrobert 	}
1561*404b540aSrobert     }
1562*404b540aSrobert 
1563*404b540aSrobert   nr = HARD_REGNO_NREGS (regno, mode);
1564*404b540aSrobert   info->next_reg[ (int)class ] = regno + nr;
1565*404b540aSrobert 
1566*404b540aSrobert   if (mark_as_used)
1567*404b540aSrobert     for (i = 0; i < nr; i++)
1568*404b540aSrobert       CLEAR_HARD_REG_BIT (info->regs, regno+i);
1569*404b540aSrobert 
1570*404b540aSrobert   return gen_rtx_REG (mode, regno);
1571*404b540aSrobert }
1572*404b540aSrobert 
1573*404b540aSrobert 
1574*404b540aSrobert /* Return an rtx with the value OFFSET, which will either be a register or a
1575*404b540aSrobert    signed 12-bit integer.  It can be used as the second operand in an "add"
1576*404b540aSrobert    instruction, or as the index in a load or store.
1577*404b540aSrobert 
1578*404b540aSrobert    The function returns a constant rtx if OFFSET is small enough, otherwise
1579*404b540aSrobert    it loads the constant into register OFFSET_REGNO and returns that.  */
1580*404b540aSrobert static rtx
frv_frame_offset_rtx(int offset)1581*404b540aSrobert frv_frame_offset_rtx (int offset)
1582*404b540aSrobert {
1583*404b540aSrobert   rtx offset_rtx = GEN_INT (offset);
1584*404b540aSrobert   if (IN_RANGE_P (offset, -2048, 2047))
1585*404b540aSrobert     return offset_rtx;
1586*404b540aSrobert   else
1587*404b540aSrobert     {
1588*404b540aSrobert       rtx reg_rtx = gen_rtx_REG (SImode, OFFSET_REGNO);
1589*404b540aSrobert       if (IN_RANGE_P (offset, -32768, 32767))
1590*404b540aSrobert 	emit_insn (gen_movsi (reg_rtx, offset_rtx));
1591*404b540aSrobert       else
1592*404b540aSrobert 	{
1593*404b540aSrobert 	  emit_insn (gen_movsi_high (reg_rtx, offset_rtx));
1594*404b540aSrobert 	  emit_insn (gen_movsi_lo_sum (reg_rtx, offset_rtx));
1595*404b540aSrobert 	}
1596*404b540aSrobert       return reg_rtx;
1597*404b540aSrobert     }
1598*404b540aSrobert }
1599*404b540aSrobert 
1600*404b540aSrobert /* Generate (mem:MODE (plus:Pmode BASE (frv_frame_offset OFFSET)))).  The
1601*404b540aSrobert    prologue and epilogue uses such expressions to access the stack.  */
1602*404b540aSrobert static rtx
frv_frame_mem(enum machine_mode mode,rtx base,int offset)1603*404b540aSrobert frv_frame_mem (enum machine_mode mode, rtx base, int offset)
1604*404b540aSrobert {
1605*404b540aSrobert   return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode,
1606*404b540aSrobert 					  base,
1607*404b540aSrobert 					  frv_frame_offset_rtx (offset)));
1608*404b540aSrobert }
1609*404b540aSrobert 
1610*404b540aSrobert /* Generate a frame-related expression:
1611*404b540aSrobert 
1612*404b540aSrobert 	(set REG (mem (plus (sp) (const_int OFFSET)))).
1613*404b540aSrobert 
1614*404b540aSrobert    Such expressions are used in FRAME_RELATED_EXPR notes for more complex
1615*404b540aSrobert    instructions.  Marking the expressions as frame-related is superfluous if
1616*404b540aSrobert    the note contains just a single set.  But if the note contains a PARALLEL
1617*404b540aSrobert    or SEQUENCE that has several sets, each set must be individually marked
1618*404b540aSrobert    as frame-related.  */
1619*404b540aSrobert static rtx
frv_dwarf_store(rtx reg,int offset)1620*404b540aSrobert frv_dwarf_store (rtx reg, int offset)
1621*404b540aSrobert {
1622*404b540aSrobert   rtx set = gen_rtx_SET (VOIDmode,
1623*404b540aSrobert 			 gen_rtx_MEM (GET_MODE (reg),
1624*404b540aSrobert 				      plus_constant (stack_pointer_rtx,
1625*404b540aSrobert 						     offset)),
1626*404b540aSrobert 			 reg);
1627*404b540aSrobert   RTX_FRAME_RELATED_P (set) = 1;
1628*404b540aSrobert   return set;
1629*404b540aSrobert }
1630*404b540aSrobert 
1631*404b540aSrobert /* Emit a frame-related instruction whose pattern is PATTERN.  The
1632*404b540aSrobert    instruction is the last in a sequence that cumulatively performs the
1633*404b540aSrobert    operation described by DWARF_PATTERN.  The instruction is marked as
1634*404b540aSrobert    frame-related and has a REG_FRAME_RELATED_EXPR note containing
1635*404b540aSrobert    DWARF_PATTERN.  */
1636*404b540aSrobert static void
frv_frame_insn(rtx pattern,rtx dwarf_pattern)1637*404b540aSrobert frv_frame_insn (rtx pattern, rtx dwarf_pattern)
1638*404b540aSrobert {
1639*404b540aSrobert   rtx insn = emit_insn (pattern);
1640*404b540aSrobert   RTX_FRAME_RELATED_P (insn) = 1;
1641*404b540aSrobert   REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1642*404b540aSrobert 				      dwarf_pattern,
1643*404b540aSrobert 				      REG_NOTES (insn));
1644*404b540aSrobert }
1645*404b540aSrobert 
1646*404b540aSrobert /* Emit instructions that transfer REG to or from the memory location (sp +
1647*404b540aSrobert    STACK_OFFSET).  The register is stored in memory if ACCESSOR->OP is
1648*404b540aSrobert    FRV_STORE and loaded if it is FRV_LOAD.  Only the prologue uses this
1649*404b540aSrobert    function to store registers and only the epilogue uses it to load them.
1650*404b540aSrobert 
1651*404b540aSrobert    The caller sets up ACCESSOR so that BASE is equal to (sp + BASE_OFFSET).
1652*404b540aSrobert    The generated instruction will use BASE as its base register.  BASE may
1653*404b540aSrobert    simply be the stack pointer, but if several accesses are being made to a
1654*404b540aSrobert    region far away from the stack pointer, it may be more efficient to set
1655*404b540aSrobert    up a temporary instead.
1656*404b540aSrobert 
1657*404b540aSrobert    Store instructions will be frame-related and will be annotated with the
1658*404b540aSrobert    overall effect of the store.  Load instructions will be followed by a
1659*404b540aSrobert    (use) to prevent later optimizations from zapping them.
1660*404b540aSrobert 
1661*404b540aSrobert    The function takes care of the moves to and from SPRs, using TEMP_REGNO
1662*404b540aSrobert    as a temporary in such cases.  */
1663*404b540aSrobert static void
frv_frame_access(frv_frame_accessor_t * accessor,rtx reg,int stack_offset)1664*404b540aSrobert frv_frame_access (frv_frame_accessor_t *accessor, rtx reg, int stack_offset)
1665*404b540aSrobert {
1666*404b540aSrobert   enum machine_mode mode = GET_MODE (reg);
1667*404b540aSrobert   rtx mem = frv_frame_mem (mode,
1668*404b540aSrobert 			   accessor->base,
1669*404b540aSrobert 			   stack_offset - accessor->base_offset);
1670*404b540aSrobert 
1671*404b540aSrobert   if (accessor->op == FRV_LOAD)
1672*404b540aSrobert     {
1673*404b540aSrobert       if (SPR_P (REGNO (reg)))
1674*404b540aSrobert 	{
1675*404b540aSrobert 	  rtx temp = gen_rtx_REG (mode, TEMP_REGNO);
1676*404b540aSrobert 	  emit_insn (gen_rtx_SET (VOIDmode, temp, mem));
1677*404b540aSrobert 	  emit_insn (gen_rtx_SET (VOIDmode, reg, temp));
1678*404b540aSrobert 	}
1679*404b540aSrobert       else
1680*404b540aSrobert 	emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
1681*404b540aSrobert       emit_insn (gen_rtx_USE (VOIDmode, reg));
1682*404b540aSrobert     }
1683*404b540aSrobert   else
1684*404b540aSrobert     {
1685*404b540aSrobert       if (SPR_P (REGNO (reg)))
1686*404b540aSrobert 	{
1687*404b540aSrobert 	  rtx temp = gen_rtx_REG (mode, TEMP_REGNO);
1688*404b540aSrobert 	  emit_insn (gen_rtx_SET (VOIDmode, temp, reg));
1689*404b540aSrobert 	  frv_frame_insn (gen_rtx_SET (Pmode, mem, temp),
1690*404b540aSrobert 			  frv_dwarf_store (reg, stack_offset));
1691*404b540aSrobert 	}
1692*404b540aSrobert       else if (GET_MODE (reg) == DImode)
1693*404b540aSrobert 	{
1694*404b540aSrobert 	  /* For DImode saves, the dwarf2 version needs to be a SEQUENCE
1695*404b540aSrobert 	     with a separate save for each register.  */
1696*404b540aSrobert 	  rtx reg1 = gen_rtx_REG (SImode, REGNO (reg));
1697*404b540aSrobert 	  rtx reg2 = gen_rtx_REG (SImode, REGNO (reg) + 1);
1698*404b540aSrobert 	  rtx set1 = frv_dwarf_store (reg1, stack_offset);
1699*404b540aSrobert 	  rtx set2 = frv_dwarf_store (reg2, stack_offset + 4);
1700*404b540aSrobert 	  frv_frame_insn (gen_rtx_SET (Pmode, mem, reg),
1701*404b540aSrobert 			  gen_rtx_PARALLEL (VOIDmode,
1702*404b540aSrobert 					    gen_rtvec (2, set1, set2)));
1703*404b540aSrobert 	}
1704*404b540aSrobert       else
1705*404b540aSrobert 	frv_frame_insn (gen_rtx_SET (Pmode, mem, reg),
1706*404b540aSrobert 			frv_dwarf_store (reg, stack_offset));
1707*404b540aSrobert     }
1708*404b540aSrobert }
1709*404b540aSrobert 
1710*404b540aSrobert /* A function that uses frv_frame_access to transfer a group of registers to
1711*404b540aSrobert    or from the stack.  ACCESSOR is passed directly to frv_frame_access, INFO
1712*404b540aSrobert    is the stack information generated by frv_stack_info, and REG_SET is the
1713*404b540aSrobert    number of the register set to transfer.  */
1714*404b540aSrobert static void
frv_frame_access_multi(frv_frame_accessor_t * accessor,frv_stack_t * info,int reg_set)1715*404b540aSrobert frv_frame_access_multi (frv_frame_accessor_t *accessor,
1716*404b540aSrobert                         frv_stack_t *info,
1717*404b540aSrobert                         int reg_set)
1718*404b540aSrobert {
1719*404b540aSrobert   frv_stack_regs_t *regs_info;
1720*404b540aSrobert   int regno;
1721*404b540aSrobert 
1722*404b540aSrobert   regs_info = &info->regs[reg_set];
1723*404b540aSrobert   for (regno = regs_info->first; regno <= regs_info->last; regno++)
1724*404b540aSrobert     if (info->save_p[regno])
1725*404b540aSrobert       frv_frame_access (accessor,
1726*404b540aSrobert 			info->save_p[regno] == REG_SAVE_2WORDS
1727*404b540aSrobert 			? gen_rtx_REG (DImode, regno)
1728*404b540aSrobert 			: gen_rtx_REG (SImode, regno),
1729*404b540aSrobert 			info->reg_offset[regno]);
1730*404b540aSrobert }
1731*404b540aSrobert 
1732*404b540aSrobert /* Save or restore callee-saved registers that are kept outside the frame
1733*404b540aSrobert    header.  The function saves the registers if OP is FRV_STORE and restores
1734*404b540aSrobert    them if OP is FRV_LOAD.  INFO is the stack information generated by
1735*404b540aSrobert    frv_stack_info.  */
1736*404b540aSrobert static void
frv_frame_access_standard_regs(enum frv_stack_op op,frv_stack_t * info)1737*404b540aSrobert frv_frame_access_standard_regs (enum frv_stack_op op, frv_stack_t *info)
1738*404b540aSrobert {
1739*404b540aSrobert   frv_frame_accessor_t accessor;
1740*404b540aSrobert 
1741*404b540aSrobert   accessor.op = op;
1742*404b540aSrobert   accessor.base = stack_pointer_rtx;
1743*404b540aSrobert   accessor.base_offset = 0;
1744*404b540aSrobert   frv_frame_access_multi (&accessor, info, STACK_REGS_GPR);
1745*404b540aSrobert   frv_frame_access_multi (&accessor, info, STACK_REGS_FPR);
1746*404b540aSrobert   frv_frame_access_multi (&accessor, info, STACK_REGS_LCR);
1747*404b540aSrobert }
1748*404b540aSrobert 
1749*404b540aSrobert 
1750*404b540aSrobert /* Called after register allocation to add any instructions needed for the
1751*404b540aSrobert    prologue.  Using a prologue insn is favored compared to putting all of the
1752*404b540aSrobert    instructions in the TARGET_ASM_FUNCTION_PROLOGUE target hook, since
1753*404b540aSrobert    it allows the scheduler to intermix instructions with the saves of
1754*404b540aSrobert    the caller saved registers.  In some cases, it might be necessary
1755*404b540aSrobert    to emit a barrier instruction as the last insn to prevent such
1756*404b540aSrobert    scheduling.
1757*404b540aSrobert 
1758*404b540aSrobert    Also any insns generated here should have RTX_FRAME_RELATED_P(insn) = 1
1759*404b540aSrobert    so that the debug info generation code can handle them properly.  */
1760*404b540aSrobert void
frv_expand_prologue(void)1761*404b540aSrobert frv_expand_prologue (void)
1762*404b540aSrobert {
1763*404b540aSrobert   frv_stack_t *info = frv_stack_info ();
1764*404b540aSrobert   rtx sp = stack_pointer_rtx;
1765*404b540aSrobert   rtx fp = frame_pointer_rtx;
1766*404b540aSrobert   frv_frame_accessor_t accessor;
1767*404b540aSrobert 
1768*404b540aSrobert   if (TARGET_DEBUG_STACK)
1769*404b540aSrobert     frv_debug_stack (info);
1770*404b540aSrobert 
1771*404b540aSrobert   if (info->total_size == 0)
1772*404b540aSrobert     return;
1773*404b540aSrobert 
1774*404b540aSrobert   /* We're interested in three areas of the frame here:
1775*404b540aSrobert 
1776*404b540aSrobert          A: the register save area
1777*404b540aSrobert 	 B: the old FP
1778*404b540aSrobert 	 C: the header after B
1779*404b540aSrobert 
1780*404b540aSrobert      If the frame pointer isn't used, we'll have to set up A, B and C
1781*404b540aSrobert      using the stack pointer.  If the frame pointer is used, we'll access
1782*404b540aSrobert      them as follows:
1783*404b540aSrobert 
1784*404b540aSrobert          A: set up using sp
1785*404b540aSrobert 	 B: set up using sp or a temporary (see below)
1786*404b540aSrobert 	 C: set up using fp
1787*404b540aSrobert 
1788*404b540aSrobert      We set up B using the stack pointer if the frame is small enough.
1789*404b540aSrobert      Otherwise, it's more efficient to copy the old stack pointer into a
1790*404b540aSrobert      temporary and use that.
1791*404b540aSrobert 
1792*404b540aSrobert      Note that it's important to make sure the prologue and epilogue use the
1793*404b540aSrobert      same registers to access A and C, since doing otherwise will confuse
1794*404b540aSrobert      the aliasing code.  */
1795*404b540aSrobert 
1796*404b540aSrobert   /* Set up ACCESSOR for accessing region B above.  If the frame pointer
1797*404b540aSrobert      isn't used, the same method will serve for C.  */
1798*404b540aSrobert   accessor.op = FRV_STORE;
1799*404b540aSrobert   if (frame_pointer_needed && info->total_size > 2048)
1800*404b540aSrobert     {
1801*404b540aSrobert       rtx insn;
1802*404b540aSrobert 
1803*404b540aSrobert       accessor.base = gen_rtx_REG (Pmode, OLD_SP_REGNO);
1804*404b540aSrobert       accessor.base_offset = info->total_size;
1805*404b540aSrobert       insn = emit_insn (gen_movsi (accessor.base, sp));
1806*404b540aSrobert     }
1807*404b540aSrobert   else
1808*404b540aSrobert     {
1809*404b540aSrobert       accessor.base = stack_pointer_rtx;
1810*404b540aSrobert       accessor.base_offset = 0;
1811*404b540aSrobert     }
1812*404b540aSrobert 
1813*404b540aSrobert   /* Allocate the stack space.  */
1814*404b540aSrobert   {
1815*404b540aSrobert     rtx asm_offset = frv_frame_offset_rtx (-info->total_size);
1816*404b540aSrobert     rtx dwarf_offset = GEN_INT (-info->total_size);
1817*404b540aSrobert 
1818*404b540aSrobert     frv_frame_insn (gen_stack_adjust (sp, sp, asm_offset),
1819*404b540aSrobert 		    gen_rtx_SET (Pmode,
1820*404b540aSrobert 				 sp,
1821*404b540aSrobert 				 gen_rtx_PLUS (Pmode, sp, dwarf_offset)));
1822*404b540aSrobert   }
1823*404b540aSrobert 
1824*404b540aSrobert   /* If the frame pointer is needed, store the old one at (sp + FP_OFFSET)
1825*404b540aSrobert      and point the new one to that location.  */
1826*404b540aSrobert   if (frame_pointer_needed)
1827*404b540aSrobert     {
1828*404b540aSrobert       int fp_offset = info->reg_offset[FRAME_POINTER_REGNUM];
1829*404b540aSrobert 
1830*404b540aSrobert       /* ASM_SRC and DWARF_SRC both point to the frame header.  ASM_SRC is
1831*404b540aSrobert 	 based on ACCESSOR.BASE but DWARF_SRC is always based on the stack
1832*404b540aSrobert 	 pointer.  */
1833*404b540aSrobert       rtx asm_src = plus_constant (accessor.base,
1834*404b540aSrobert 				   fp_offset - accessor.base_offset);
1835*404b540aSrobert       rtx dwarf_src = plus_constant (sp, fp_offset);
1836*404b540aSrobert 
1837*404b540aSrobert       /* Store the old frame pointer at (sp + FP_OFFSET).  */
1838*404b540aSrobert       frv_frame_access (&accessor, fp, fp_offset);
1839*404b540aSrobert 
1840*404b540aSrobert       /* Set up the new frame pointer.  */
1841*404b540aSrobert       frv_frame_insn (gen_rtx_SET (VOIDmode, fp, asm_src),
1842*404b540aSrobert 		      gen_rtx_SET (VOIDmode, fp, dwarf_src));
1843*404b540aSrobert 
1844*404b540aSrobert       /* Access region C from the frame pointer.  */
1845*404b540aSrobert       accessor.base = fp;
1846*404b540aSrobert       accessor.base_offset = fp_offset;
1847*404b540aSrobert     }
1848*404b540aSrobert 
1849*404b540aSrobert   /* Set up region C.  */
1850*404b540aSrobert   frv_frame_access_multi (&accessor, info, STACK_REGS_STRUCT);
1851*404b540aSrobert   frv_frame_access_multi (&accessor, info, STACK_REGS_LR);
1852*404b540aSrobert   frv_frame_access_multi (&accessor, info, STACK_REGS_STDARG);
1853*404b540aSrobert 
1854*404b540aSrobert   /* Set up region A.  */
1855*404b540aSrobert   frv_frame_access_standard_regs (FRV_STORE, info);
1856*404b540aSrobert 
1857*404b540aSrobert   /* If this is a varargs/stdarg function, issue a blockage to prevent the
1858*404b540aSrobert      scheduler from moving loads before the stores saving the registers.  */
1859*404b540aSrobert   if (info->stdarg_size > 0)
1860*404b540aSrobert     emit_insn (gen_blockage ());
1861*404b540aSrobert 
1862*404b540aSrobert   /* Set up pic register/small data register for this function.  */
1863*404b540aSrobert   if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table)
1864*404b540aSrobert     emit_insn (gen_pic_prologue (gen_rtx_REG (Pmode, PIC_REGNO),
1865*404b540aSrobert 				 gen_rtx_REG (Pmode, LR_REGNO),
1866*404b540aSrobert 				 gen_rtx_REG (SImode, OFFSET_REGNO)));
1867*404b540aSrobert }
1868*404b540aSrobert 
1869*404b540aSrobert 
1870*404b540aSrobert /* Under frv, all of the work is done via frv_expand_epilogue, but
1871*404b540aSrobert    this function provides a convenient place to do cleanup.  */
1872*404b540aSrobert 
1873*404b540aSrobert static void
frv_function_epilogue(FILE * file ATTRIBUTE_UNUSED,HOST_WIDE_INT size ATTRIBUTE_UNUSED)1874*404b540aSrobert frv_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
1875*404b540aSrobert                        HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1876*404b540aSrobert {
1877*404b540aSrobert   frv_stack_cache = (frv_stack_t *)0;
1878*404b540aSrobert 
1879*404b540aSrobert   /* Zap last used registers for conditional execution.  */
1880*404b540aSrobert   memset (&frv_ifcvt.tmp_reg, 0, sizeof (frv_ifcvt.tmp_reg));
1881*404b540aSrobert 
1882*404b540aSrobert   /* Release the bitmap of created insns.  */
1883*404b540aSrobert   BITMAP_FREE (frv_ifcvt.scratch_insns_bitmap);
1884*404b540aSrobert }
1885*404b540aSrobert 
1886*404b540aSrobert 
1887*404b540aSrobert /* Called after register allocation to add any instructions needed for the
1888*404b540aSrobert    epilogue.  Using an epilogue insn is favored compared to putting all of the
1889*404b540aSrobert    instructions in the TARGET_ASM_FUNCTION_PROLOGUE target hook, since
1890*404b540aSrobert    it allows the scheduler to intermix instructions with the saves of
1891*404b540aSrobert    the caller saved registers.  In some cases, it might be necessary
1892*404b540aSrobert    to emit a barrier instruction as the last insn to prevent such
1893*404b540aSrobert    scheduling.  */
1894*404b540aSrobert 
1895*404b540aSrobert void
frv_expand_epilogue(bool emit_return)1896*404b540aSrobert frv_expand_epilogue (bool emit_return)
1897*404b540aSrobert {
1898*404b540aSrobert   frv_stack_t *info = frv_stack_info ();
1899*404b540aSrobert   rtx fp = frame_pointer_rtx;
1900*404b540aSrobert   rtx sp = stack_pointer_rtx;
1901*404b540aSrobert   rtx return_addr;
1902*404b540aSrobert   int fp_offset;
1903*404b540aSrobert 
1904*404b540aSrobert   fp_offset = info->reg_offset[FRAME_POINTER_REGNUM];
1905*404b540aSrobert 
1906*404b540aSrobert   /* Restore the stack pointer to its original value if alloca or the like
1907*404b540aSrobert      is used.  */
1908*404b540aSrobert   if (! current_function_sp_is_unchanging)
1909*404b540aSrobert     emit_insn (gen_addsi3 (sp, fp, frv_frame_offset_rtx (-fp_offset)));
1910*404b540aSrobert 
1911*404b540aSrobert   /* Restore the callee-saved registers that were used in this function.  */
1912*404b540aSrobert   frv_frame_access_standard_regs (FRV_LOAD, info);
1913*404b540aSrobert 
1914*404b540aSrobert   /* Set RETURN_ADDR to the address we should return to.  Set it to NULL if
1915*404b540aSrobert      no return instruction should be emitted.  */
1916*404b540aSrobert   if (info->save_p[LR_REGNO])
1917*404b540aSrobert     {
1918*404b540aSrobert       int lr_offset;
1919*404b540aSrobert       rtx mem;
1920*404b540aSrobert 
1921*404b540aSrobert       /* Use the same method to access the link register's slot as we did in
1922*404b540aSrobert 	 the prologue.  In other words, use the frame pointer if available,
1923*404b540aSrobert 	 otherwise use the stack pointer.
1924*404b540aSrobert 
1925*404b540aSrobert 	 LR_OFFSET is the offset of the link register's slot from the start
1926*404b540aSrobert 	 of the frame and MEM is a memory rtx for it.  */
1927*404b540aSrobert       lr_offset = info->reg_offset[LR_REGNO];
1928*404b540aSrobert       if (frame_pointer_needed)
1929*404b540aSrobert 	mem = frv_frame_mem (Pmode, fp, lr_offset - fp_offset);
1930*404b540aSrobert       else
1931*404b540aSrobert 	mem = frv_frame_mem (Pmode, sp, lr_offset);
1932*404b540aSrobert 
1933*404b540aSrobert       /* Load the old link register into a GPR.  */
1934*404b540aSrobert       return_addr = gen_rtx_REG (Pmode, TEMP_REGNO);
1935*404b540aSrobert       emit_insn (gen_rtx_SET (VOIDmode, return_addr, mem));
1936*404b540aSrobert     }
1937*404b540aSrobert   else
1938*404b540aSrobert     return_addr = gen_rtx_REG (Pmode, LR_REGNO);
1939*404b540aSrobert 
1940*404b540aSrobert   /* Restore the old frame pointer.  Emit a USE afterwards to make sure
1941*404b540aSrobert      the load is preserved.  */
1942*404b540aSrobert   if (frame_pointer_needed)
1943*404b540aSrobert     {
1944*404b540aSrobert       emit_insn (gen_rtx_SET (VOIDmode, fp, gen_rtx_MEM (Pmode, fp)));
1945*404b540aSrobert       emit_insn (gen_rtx_USE (VOIDmode, fp));
1946*404b540aSrobert     }
1947*404b540aSrobert 
1948*404b540aSrobert   /* Deallocate the stack frame.  */
1949*404b540aSrobert   if (info->total_size != 0)
1950*404b540aSrobert     {
1951*404b540aSrobert       rtx offset = frv_frame_offset_rtx (info->total_size);
1952*404b540aSrobert       emit_insn (gen_stack_adjust (sp, sp, offset));
1953*404b540aSrobert     }
1954*404b540aSrobert 
1955*404b540aSrobert   /* If this function uses eh_return, add the final stack adjustment now.  */
1956*404b540aSrobert   if (current_function_calls_eh_return)
1957*404b540aSrobert     emit_insn (gen_stack_adjust (sp, sp, EH_RETURN_STACKADJ_RTX));
1958*404b540aSrobert 
1959*404b540aSrobert   if (emit_return)
1960*404b540aSrobert     emit_jump_insn (gen_epilogue_return (return_addr));
1961*404b540aSrobert   else
1962*404b540aSrobert     {
1963*404b540aSrobert       rtx lr = return_addr;
1964*404b540aSrobert 
1965*404b540aSrobert       if (REGNO (return_addr) != LR_REGNO)
1966*404b540aSrobert 	{
1967*404b540aSrobert 	  lr = gen_rtx_REG (Pmode, LR_REGNO);
1968*404b540aSrobert 	  emit_move_insn (lr, return_addr);
1969*404b540aSrobert 	}
1970*404b540aSrobert 
1971*404b540aSrobert       emit_insn (gen_rtx_USE (VOIDmode, lr));
1972*404b540aSrobert     }
1973*404b540aSrobert }
1974*404b540aSrobert 
1975*404b540aSrobert 
1976*404b540aSrobert /* Worker function for TARGET_ASM_OUTPUT_MI_THUNK.  */
1977*404b540aSrobert 
1978*404b540aSrobert static void
frv_asm_output_mi_thunk(FILE * file,tree thunk_fndecl ATTRIBUTE_UNUSED,HOST_WIDE_INT delta,HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,tree function)1979*404b540aSrobert frv_asm_output_mi_thunk (FILE *file,
1980*404b540aSrobert                          tree thunk_fndecl ATTRIBUTE_UNUSED,
1981*404b540aSrobert                          HOST_WIDE_INT delta,
1982*404b540aSrobert                          HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
1983*404b540aSrobert                          tree function)
1984*404b540aSrobert {
1985*404b540aSrobert   const char *name_func = XSTR (XEXP (DECL_RTL (function), 0), 0);
1986*404b540aSrobert   const char *name_arg0 = reg_names[FIRST_ARG_REGNUM];
1987*404b540aSrobert   const char *name_jmp = reg_names[JUMP_REGNO];
1988*404b540aSrobert   const char *parallel = (frv_issue_rate () > 1 ? ".p" : "");
1989*404b540aSrobert 
1990*404b540aSrobert   /* Do the add using an addi if possible.  */
1991*404b540aSrobert   if (IN_RANGE_P (delta, -2048, 2047))
1992*404b540aSrobert     fprintf (file, "\taddi %s,#%d,%s\n", name_arg0, (int) delta, name_arg0);
1993*404b540aSrobert   else
1994*404b540aSrobert     {
1995*404b540aSrobert       const char *const name_add = reg_names[TEMP_REGNO];
1996*404b540aSrobert       fprintf (file, "\tsethi%s #hi(" HOST_WIDE_INT_PRINT_DEC "),%s\n",
1997*404b540aSrobert 	       parallel, delta, name_add);
1998*404b540aSrobert       fprintf (file, "\tsetlo #lo(" HOST_WIDE_INT_PRINT_DEC "),%s\n",
1999*404b540aSrobert 	       delta, name_add);
2000*404b540aSrobert       fprintf (file, "\tadd %s,%s,%s\n", name_add, name_arg0, name_arg0);
2001*404b540aSrobert     }
2002*404b540aSrobert 
2003*404b540aSrobert   if (TARGET_FDPIC)
2004*404b540aSrobert     {
2005*404b540aSrobert       const char *name_pic = reg_names[FDPIC_REGNO];
2006*404b540aSrobert       name_jmp = reg_names[FDPIC_FPTR_REGNO];
2007*404b540aSrobert 
2008*404b540aSrobert       if (flag_pic != 1)
2009*404b540aSrobert 	{
2010*404b540aSrobert 	  fprintf (file, "\tsethi%s #gotofffuncdeschi(", parallel);
2011*404b540aSrobert 	  assemble_name (file, name_func);
2012*404b540aSrobert 	  fprintf (file, "),%s\n", name_jmp);
2013*404b540aSrobert 
2014*404b540aSrobert 	  fprintf (file, "\tsetlo #gotofffuncdesclo(");
2015*404b540aSrobert 	  assemble_name (file, name_func);
2016*404b540aSrobert 	  fprintf (file, "),%s\n", name_jmp);
2017*404b540aSrobert 
2018*404b540aSrobert 	  fprintf (file, "\tldd @(%s,%s), %s\n", name_jmp, name_pic, name_jmp);
2019*404b540aSrobert 	}
2020*404b540aSrobert       else
2021*404b540aSrobert 	{
2022*404b540aSrobert 	  fprintf (file, "\tlddo @(%s,#gotofffuncdesc12(", name_pic);
2023*404b540aSrobert 	  assemble_name (file, name_func);
2024*404b540aSrobert 	  fprintf (file, "\t)), %s\n", name_jmp);
2025*404b540aSrobert 	}
2026*404b540aSrobert     }
2027*404b540aSrobert   else if (!flag_pic)
2028*404b540aSrobert     {
2029*404b540aSrobert       fprintf (file, "\tsethi%s #hi(", parallel);
2030*404b540aSrobert       assemble_name (file, name_func);
2031*404b540aSrobert       fprintf (file, "),%s\n", name_jmp);
2032*404b540aSrobert 
2033*404b540aSrobert       fprintf (file, "\tsetlo #lo(");
2034*404b540aSrobert       assemble_name (file, name_func);
2035*404b540aSrobert       fprintf (file, "),%s\n", name_jmp);
2036*404b540aSrobert     }
2037*404b540aSrobert   else
2038*404b540aSrobert     {
2039*404b540aSrobert       /* Use JUMP_REGNO as a temporary PIC register.  */
2040*404b540aSrobert       const char *name_lr = reg_names[LR_REGNO];
2041*404b540aSrobert       const char *name_gppic = name_jmp;
2042*404b540aSrobert       const char *name_tmp = reg_names[TEMP_REGNO];
2043*404b540aSrobert 
2044*404b540aSrobert       fprintf (file, "\tmovsg %s,%s\n", name_lr, name_tmp);
2045*404b540aSrobert       fprintf (file, "\tcall 1f\n");
2046*404b540aSrobert       fprintf (file, "1:\tmovsg %s,%s\n", name_lr, name_gppic);
2047*404b540aSrobert       fprintf (file, "\tmovgs %s,%s\n", name_tmp, name_lr);
2048*404b540aSrobert       fprintf (file, "\tsethi%s #gprelhi(1b),%s\n", parallel, name_tmp);
2049*404b540aSrobert       fprintf (file, "\tsetlo #gprello(1b),%s\n", name_tmp);
2050*404b540aSrobert       fprintf (file, "\tsub %s,%s,%s\n", name_gppic, name_tmp, name_gppic);
2051*404b540aSrobert 
2052*404b540aSrobert       fprintf (file, "\tsethi%s #gprelhi(", parallel);
2053*404b540aSrobert       assemble_name (file, name_func);
2054*404b540aSrobert       fprintf (file, "),%s\n", name_tmp);
2055*404b540aSrobert 
2056*404b540aSrobert       fprintf (file, "\tsetlo #gprello(");
2057*404b540aSrobert       assemble_name (file, name_func);
2058*404b540aSrobert       fprintf (file, "),%s\n", name_tmp);
2059*404b540aSrobert 
2060*404b540aSrobert       fprintf (file, "\tadd %s,%s,%s\n", name_gppic, name_tmp, name_jmp);
2061*404b540aSrobert     }
2062*404b540aSrobert 
2063*404b540aSrobert   /* Jump to the function address.  */
2064*404b540aSrobert   fprintf (file, "\tjmpl @(%s,%s)\n", name_jmp, reg_names[GPR_FIRST+0]);
2065*404b540aSrobert }
2066*404b540aSrobert 
2067*404b540aSrobert 
2068*404b540aSrobert /* A C expression which is nonzero if a function must have and use a frame
2069*404b540aSrobert    pointer.  This expression is evaluated in the reload pass.  If its value is
2070*404b540aSrobert    nonzero the function will have a frame pointer.
2071*404b540aSrobert 
2072*404b540aSrobert    The expression can in principle examine the current function and decide
2073*404b540aSrobert    according to the facts, but on most machines the constant 0 or the constant
2074*404b540aSrobert    1 suffices.  Use 0 when the machine allows code to be generated with no
2075*404b540aSrobert    frame pointer, and doing so saves some time or space.  Use 1 when there is
2076*404b540aSrobert    no possible advantage to avoiding a frame pointer.
2077*404b540aSrobert 
2078*404b540aSrobert    In certain cases, the compiler does not know how to produce valid code
2079*404b540aSrobert    without a frame pointer.  The compiler recognizes those cases and
2080*404b540aSrobert    automatically gives the function a frame pointer regardless of what
2081*404b540aSrobert    `FRAME_POINTER_REQUIRED' says.  You don't need to worry about them.
2082*404b540aSrobert 
2083*404b540aSrobert    In a function that does not require a frame pointer, the frame pointer
2084*404b540aSrobert    register can be allocated for ordinary usage, unless you mark it as a fixed
2085*404b540aSrobert    register.  See `FIXED_REGISTERS' for more information.  */
2086*404b540aSrobert 
2087*404b540aSrobert /* On frv, create a frame whenever we need to create stack.  */
2088*404b540aSrobert 
2089*404b540aSrobert int
frv_frame_pointer_required(void)2090*404b540aSrobert frv_frame_pointer_required (void)
2091*404b540aSrobert {
2092*404b540aSrobert   /* If we forgoing the usual linkage requirements, we only need
2093*404b540aSrobert      a frame pointer if the stack pointer might change.  */
2094*404b540aSrobert   if (!TARGET_LINKED_FP)
2095*404b540aSrobert     return !current_function_sp_is_unchanging;
2096*404b540aSrobert 
2097*404b540aSrobert   if (! current_function_is_leaf)
2098*404b540aSrobert     return TRUE;
2099*404b540aSrobert 
2100*404b540aSrobert   if (get_frame_size () != 0)
2101*404b540aSrobert     return TRUE;
2102*404b540aSrobert 
2103*404b540aSrobert   if (cfun->stdarg)
2104*404b540aSrobert     return TRUE;
2105*404b540aSrobert 
2106*404b540aSrobert   if (!current_function_sp_is_unchanging)
2107*404b540aSrobert     return TRUE;
2108*404b540aSrobert 
2109*404b540aSrobert   if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table)
2110*404b540aSrobert     return TRUE;
2111*404b540aSrobert 
2112*404b540aSrobert   if (profile_flag)
2113*404b540aSrobert     return TRUE;
2114*404b540aSrobert 
2115*404b540aSrobert   if (cfun->machine->frame_needed)
2116*404b540aSrobert     return TRUE;
2117*404b540aSrobert 
2118*404b540aSrobert   return FALSE;
2119*404b540aSrobert }
2120*404b540aSrobert 
2121*404b540aSrobert 
2122*404b540aSrobert /* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'.  It specifies the
2123*404b540aSrobert    initial difference between the specified pair of registers.  This macro must
2124*404b540aSrobert    be defined if `ELIMINABLE_REGS' is defined.  */
2125*404b540aSrobert 
2126*404b540aSrobert /* See frv_stack_info for more details on the frv stack frame.  */
2127*404b540aSrobert 
2128*404b540aSrobert int
frv_initial_elimination_offset(int from,int to)2129*404b540aSrobert frv_initial_elimination_offset (int from, int to)
2130*404b540aSrobert {
2131*404b540aSrobert   frv_stack_t *info = frv_stack_info ();
2132*404b540aSrobert   int ret = 0;
2133*404b540aSrobert 
2134*404b540aSrobert   if (to == STACK_POINTER_REGNUM && from == ARG_POINTER_REGNUM)
2135*404b540aSrobert     ret = info->total_size - info->pretend_size;
2136*404b540aSrobert 
2137*404b540aSrobert   else if (to == STACK_POINTER_REGNUM && from == FRAME_POINTER_REGNUM)
2138*404b540aSrobert     ret = info->reg_offset[FRAME_POINTER_REGNUM];
2139*404b540aSrobert 
2140*404b540aSrobert   else if (to == FRAME_POINTER_REGNUM && from == ARG_POINTER_REGNUM)
2141*404b540aSrobert     ret = (info->total_size
2142*404b540aSrobert 	   - info->reg_offset[FRAME_POINTER_REGNUM]
2143*404b540aSrobert 	   - info->pretend_size);
2144*404b540aSrobert 
2145*404b540aSrobert   else
2146*404b540aSrobert     gcc_unreachable ();
2147*404b540aSrobert 
2148*404b540aSrobert   if (TARGET_DEBUG_STACK)
2149*404b540aSrobert     fprintf (stderr, "Eliminate %s to %s by adding %d\n",
2150*404b540aSrobert 	     reg_names [from], reg_names[to], ret);
2151*404b540aSrobert 
2152*404b540aSrobert   return ret;
2153*404b540aSrobert }
2154*404b540aSrobert 
2155*404b540aSrobert 
2156*404b540aSrobert /* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
2157*404b540aSrobert 
2158*404b540aSrobert static void
frv_setup_incoming_varargs(CUMULATIVE_ARGS * cum,enum machine_mode mode,tree type ATTRIBUTE_UNUSED,int * pretend_size,int second_time)2159*404b540aSrobert frv_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
2160*404b540aSrobert                             enum machine_mode mode,
2161*404b540aSrobert                             tree type ATTRIBUTE_UNUSED,
2162*404b540aSrobert                             int *pretend_size,
2163*404b540aSrobert                             int second_time)
2164*404b540aSrobert {
2165*404b540aSrobert   if (TARGET_DEBUG_ARG)
2166*404b540aSrobert     fprintf (stderr,
2167*404b540aSrobert 	     "setup_vararg: words = %2d, mode = %4s, pretend_size = %d, second_time = %d\n",
2168*404b540aSrobert 	     *cum, GET_MODE_NAME (mode), *pretend_size, second_time);
2169*404b540aSrobert }
2170*404b540aSrobert 
2171*404b540aSrobert 
2172*404b540aSrobert /* Worker function for TARGET_EXPAND_BUILTIN_SAVEREGS.  */
2173*404b540aSrobert 
2174*404b540aSrobert static rtx
frv_expand_builtin_saveregs(void)2175*404b540aSrobert frv_expand_builtin_saveregs (void)
2176*404b540aSrobert {
2177*404b540aSrobert   int offset = UNITS_PER_WORD * FRV_NUM_ARG_REGS;
2178*404b540aSrobert 
2179*404b540aSrobert   if (TARGET_DEBUG_ARG)
2180*404b540aSrobert     fprintf (stderr, "expand_builtin_saveregs: offset from ap = %d\n",
2181*404b540aSrobert 	     offset);
2182*404b540aSrobert 
2183*404b540aSrobert   return gen_rtx_PLUS (Pmode, virtual_incoming_args_rtx, GEN_INT (- offset));
2184*404b540aSrobert }
2185*404b540aSrobert 
2186*404b540aSrobert 
2187*404b540aSrobert /* Expand __builtin_va_start to do the va_start macro.  */
2188*404b540aSrobert 
2189*404b540aSrobert void
frv_expand_builtin_va_start(tree valist,rtx nextarg)2190*404b540aSrobert frv_expand_builtin_va_start (tree valist, rtx nextarg)
2191*404b540aSrobert {
2192*404b540aSrobert   tree t;
2193*404b540aSrobert   int num = cfun->args_info - FIRST_ARG_REGNUM - FRV_NUM_ARG_REGS;
2194*404b540aSrobert 
2195*404b540aSrobert   nextarg = gen_rtx_PLUS (Pmode, virtual_incoming_args_rtx,
2196*404b540aSrobert 			  GEN_INT (UNITS_PER_WORD * num));
2197*404b540aSrobert 
2198*404b540aSrobert   if (TARGET_DEBUG_ARG)
2199*404b540aSrobert     {
2200*404b540aSrobert       fprintf (stderr, "va_start: args_info = %d, num = %d\n",
2201*404b540aSrobert 	       cfun->args_info, num);
2202*404b540aSrobert 
2203*404b540aSrobert       debug_rtx (nextarg);
2204*404b540aSrobert     }
2205*404b540aSrobert 
2206*404b540aSrobert   t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
2207*404b540aSrobert 	      make_tree (ptr_type_node, nextarg));
2208*404b540aSrobert   TREE_SIDE_EFFECTS (t) = 1;
2209*404b540aSrobert 
2210*404b540aSrobert   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2211*404b540aSrobert }
2212*404b540aSrobert 
2213*404b540aSrobert 
2214*404b540aSrobert /* Expand a block move operation, and return 1 if successful.  Return 0
2215*404b540aSrobert    if we should let the compiler generate normal code.
2216*404b540aSrobert 
2217*404b540aSrobert    operands[0] is the destination
2218*404b540aSrobert    operands[1] is the source
2219*404b540aSrobert    operands[2] is the length
2220*404b540aSrobert    operands[3] is the alignment */
2221*404b540aSrobert 
2222*404b540aSrobert /* Maximum number of loads to do before doing the stores */
2223*404b540aSrobert #ifndef MAX_MOVE_REG
2224*404b540aSrobert #define MAX_MOVE_REG 4
2225*404b540aSrobert #endif
2226*404b540aSrobert 
2227*404b540aSrobert /* Maximum number of total loads to do.  */
2228*404b540aSrobert #ifndef TOTAL_MOVE_REG
2229*404b540aSrobert #define TOTAL_MOVE_REG 8
2230*404b540aSrobert #endif
2231*404b540aSrobert 
2232*404b540aSrobert int
frv_expand_block_move(rtx operands[])2233*404b540aSrobert frv_expand_block_move (rtx operands[])
2234*404b540aSrobert {
2235*404b540aSrobert   rtx orig_dest = operands[0];
2236*404b540aSrobert   rtx orig_src	= operands[1];
2237*404b540aSrobert   rtx bytes_rtx	= operands[2];
2238*404b540aSrobert   rtx align_rtx = operands[3];
2239*404b540aSrobert   int constp	= (GET_CODE (bytes_rtx) == CONST_INT);
2240*404b540aSrobert   int align;
2241*404b540aSrobert   int bytes;
2242*404b540aSrobert   int offset;
2243*404b540aSrobert   int num_reg;
2244*404b540aSrobert   int i;
2245*404b540aSrobert   rtx src_reg;
2246*404b540aSrobert   rtx dest_reg;
2247*404b540aSrobert   rtx src_addr;
2248*404b540aSrobert   rtx dest_addr;
2249*404b540aSrobert   rtx src_mem;
2250*404b540aSrobert   rtx dest_mem;
2251*404b540aSrobert   rtx tmp_reg;
2252*404b540aSrobert   rtx stores[MAX_MOVE_REG];
2253*404b540aSrobert   int move_bytes;
2254*404b540aSrobert   enum machine_mode mode;
2255*404b540aSrobert 
2256*404b540aSrobert   /* If this is not a fixed size move, just call memcpy.  */
2257*404b540aSrobert   if (! constp)
2258*404b540aSrobert     return FALSE;
2259*404b540aSrobert 
2260*404b540aSrobert   /* This should be a fixed size alignment.  */
2261*404b540aSrobert   gcc_assert (GET_CODE (align_rtx) == CONST_INT);
2262*404b540aSrobert 
2263*404b540aSrobert   align = INTVAL (align_rtx);
2264*404b540aSrobert 
2265*404b540aSrobert   /* Anything to move? */
2266*404b540aSrobert   bytes = INTVAL (bytes_rtx);
2267*404b540aSrobert   if (bytes <= 0)
2268*404b540aSrobert     return TRUE;
2269*404b540aSrobert 
2270*404b540aSrobert   /* Don't support real large moves.  */
2271*404b540aSrobert   if (bytes > TOTAL_MOVE_REG*align)
2272*404b540aSrobert     return FALSE;
2273*404b540aSrobert 
2274*404b540aSrobert   /* Move the address into scratch registers.  */
2275*404b540aSrobert   dest_reg = copy_addr_to_reg (XEXP (orig_dest, 0));
2276*404b540aSrobert   src_reg  = copy_addr_to_reg (XEXP (orig_src,  0));
2277*404b540aSrobert 
2278*404b540aSrobert   num_reg = offset = 0;
2279*404b540aSrobert   for ( ; bytes > 0; (bytes -= move_bytes), (offset += move_bytes))
2280*404b540aSrobert     {
2281*404b540aSrobert       /* Calculate the correct offset for src/dest.  */
2282*404b540aSrobert       if (offset == 0)
2283*404b540aSrobert 	{
2284*404b540aSrobert 	  src_addr  = src_reg;
2285*404b540aSrobert 	  dest_addr = dest_reg;
2286*404b540aSrobert 	}
2287*404b540aSrobert       else
2288*404b540aSrobert 	{
2289*404b540aSrobert 	  src_addr = plus_constant (src_reg, offset);
2290*404b540aSrobert 	  dest_addr = plus_constant (dest_reg, offset);
2291*404b540aSrobert 	}
2292*404b540aSrobert 
2293*404b540aSrobert       /* Generate the appropriate load and store, saving the stores
2294*404b540aSrobert 	 for later.  */
2295*404b540aSrobert       if (bytes >= 4 && align >= 4)
2296*404b540aSrobert 	mode = SImode;
2297*404b540aSrobert       else if (bytes >= 2 && align >= 2)
2298*404b540aSrobert 	mode = HImode;
2299*404b540aSrobert       else
2300*404b540aSrobert 	mode = QImode;
2301*404b540aSrobert 
2302*404b540aSrobert       move_bytes = GET_MODE_SIZE (mode);
2303*404b540aSrobert       tmp_reg = gen_reg_rtx (mode);
2304*404b540aSrobert       src_mem = change_address (orig_src, mode, src_addr);
2305*404b540aSrobert       dest_mem = change_address (orig_dest, mode, dest_addr);
2306*404b540aSrobert       emit_insn (gen_rtx_SET (VOIDmode, tmp_reg, src_mem));
2307*404b540aSrobert       stores[num_reg++] = gen_rtx_SET (VOIDmode, dest_mem, tmp_reg);
2308*404b540aSrobert 
2309*404b540aSrobert       if (num_reg >= MAX_MOVE_REG)
2310*404b540aSrobert 	{
2311*404b540aSrobert 	  for (i = 0; i < num_reg; i++)
2312*404b540aSrobert 	    emit_insn (stores[i]);
2313*404b540aSrobert 	  num_reg = 0;
2314*404b540aSrobert 	}
2315*404b540aSrobert     }
2316*404b540aSrobert 
2317*404b540aSrobert   for (i = 0; i < num_reg; i++)
2318*404b540aSrobert     emit_insn (stores[i]);
2319*404b540aSrobert 
2320*404b540aSrobert   return TRUE;
2321*404b540aSrobert }
2322*404b540aSrobert 
2323*404b540aSrobert 
2324*404b540aSrobert /* Expand a block clear operation, and return 1 if successful.  Return 0
2325*404b540aSrobert    if we should let the compiler generate normal code.
2326*404b540aSrobert 
2327*404b540aSrobert    operands[0] is the destination
2328*404b540aSrobert    operands[1] is the length
2329*404b540aSrobert    operands[3] is the alignment */
2330*404b540aSrobert 
2331*404b540aSrobert int
frv_expand_block_clear(rtx operands[])2332*404b540aSrobert frv_expand_block_clear (rtx operands[])
2333*404b540aSrobert {
2334*404b540aSrobert   rtx orig_dest = operands[0];
2335*404b540aSrobert   rtx bytes_rtx	= operands[1];
2336*404b540aSrobert   rtx align_rtx = operands[3];
2337*404b540aSrobert   int constp	= (GET_CODE (bytes_rtx) == CONST_INT);
2338*404b540aSrobert   int align;
2339*404b540aSrobert   int bytes;
2340*404b540aSrobert   int offset;
2341*404b540aSrobert   int num_reg;
2342*404b540aSrobert   rtx dest_reg;
2343*404b540aSrobert   rtx dest_addr;
2344*404b540aSrobert   rtx dest_mem;
2345*404b540aSrobert   int clear_bytes;
2346*404b540aSrobert   enum machine_mode mode;
2347*404b540aSrobert 
2348*404b540aSrobert   /* If this is not a fixed size move, just call memcpy.  */
2349*404b540aSrobert   if (! constp)
2350*404b540aSrobert     return FALSE;
2351*404b540aSrobert 
2352*404b540aSrobert   /* This should be a fixed size alignment.  */
2353*404b540aSrobert   gcc_assert (GET_CODE (align_rtx) == CONST_INT);
2354*404b540aSrobert 
2355*404b540aSrobert   align = INTVAL (align_rtx);
2356*404b540aSrobert 
2357*404b540aSrobert   /* Anything to move? */
2358*404b540aSrobert   bytes = INTVAL (bytes_rtx);
2359*404b540aSrobert   if (bytes <= 0)
2360*404b540aSrobert     return TRUE;
2361*404b540aSrobert 
2362*404b540aSrobert   /* Don't support real large clears.  */
2363*404b540aSrobert   if (bytes > TOTAL_MOVE_REG*align)
2364*404b540aSrobert     return FALSE;
2365*404b540aSrobert 
2366*404b540aSrobert   /* Move the address into a scratch register.  */
2367*404b540aSrobert   dest_reg = copy_addr_to_reg (XEXP (orig_dest, 0));
2368*404b540aSrobert 
2369*404b540aSrobert   num_reg = offset = 0;
2370*404b540aSrobert   for ( ; bytes > 0; (bytes -= clear_bytes), (offset += clear_bytes))
2371*404b540aSrobert     {
2372*404b540aSrobert       /* Calculate the correct offset for src/dest.  */
2373*404b540aSrobert       dest_addr = ((offset == 0)
2374*404b540aSrobert 		   ? dest_reg
2375*404b540aSrobert 		   : plus_constant (dest_reg, offset));
2376*404b540aSrobert 
2377*404b540aSrobert       /* Generate the appropriate store of gr0.  */
2378*404b540aSrobert       if (bytes >= 4 && align >= 4)
2379*404b540aSrobert 	mode = SImode;
2380*404b540aSrobert       else if (bytes >= 2 && align >= 2)
2381*404b540aSrobert 	mode = HImode;
2382*404b540aSrobert       else
2383*404b540aSrobert 	mode = QImode;
2384*404b540aSrobert 
2385*404b540aSrobert       clear_bytes = GET_MODE_SIZE (mode);
2386*404b540aSrobert       dest_mem = change_address (orig_dest, mode, dest_addr);
2387*404b540aSrobert       emit_insn (gen_rtx_SET (VOIDmode, dest_mem, const0_rtx));
2388*404b540aSrobert     }
2389*404b540aSrobert 
2390*404b540aSrobert   return TRUE;
2391*404b540aSrobert }
2392*404b540aSrobert 
2393*404b540aSrobert 
2394*404b540aSrobert /* The following variable is used to output modifiers of assembler
2395*404b540aSrobert    code of the current output insn.  */
2396*404b540aSrobert 
2397*404b540aSrobert static rtx *frv_insn_operands;
2398*404b540aSrobert 
2399*404b540aSrobert /* The following function is used to add assembler insn code suffix .p
2400*404b540aSrobert    if it is necessary.  */
2401*404b540aSrobert 
2402*404b540aSrobert const char *
frv_asm_output_opcode(FILE * f,const char * ptr)2403*404b540aSrobert frv_asm_output_opcode (FILE *f, const char *ptr)
2404*404b540aSrobert {
2405*404b540aSrobert   int c;
2406*404b540aSrobert 
2407*404b540aSrobert   if (frv_insn_packing_flag <= 0)
2408*404b540aSrobert     return ptr;
2409*404b540aSrobert 
2410*404b540aSrobert   for (; *ptr && *ptr != ' ' && *ptr != '\t';)
2411*404b540aSrobert     {
2412*404b540aSrobert       c = *ptr++;
2413*404b540aSrobert       if (c == '%' && ((*ptr >= 'a' && *ptr <= 'z')
2414*404b540aSrobert 		       || (*ptr >= 'A' && *ptr <= 'Z')))
2415*404b540aSrobert 	{
2416*404b540aSrobert 	  int letter = *ptr++;
2417*404b540aSrobert 
2418*404b540aSrobert 	  c = atoi (ptr);
2419*404b540aSrobert 	  frv_print_operand (f, frv_insn_operands [c], letter);
2420*404b540aSrobert 	  while ((c = *ptr) >= '0' && c <= '9')
2421*404b540aSrobert 	    ptr++;
2422*404b540aSrobert 	}
2423*404b540aSrobert       else
2424*404b540aSrobert 	fputc (c, f);
2425*404b540aSrobert     }
2426*404b540aSrobert 
2427*404b540aSrobert   fprintf (f, ".p");
2428*404b540aSrobert 
2429*404b540aSrobert   return ptr;
2430*404b540aSrobert }
2431*404b540aSrobert 
2432*404b540aSrobert /* Set up the packing bit for the current output insn.  Note that this
2433*404b540aSrobert    function is not called for asm insns.  */
2434*404b540aSrobert 
2435*404b540aSrobert void
frv_final_prescan_insn(rtx insn,rtx * opvec,int noperands ATTRIBUTE_UNUSED)2436*404b540aSrobert frv_final_prescan_insn (rtx insn, rtx *opvec,
2437*404b540aSrobert 			int noperands ATTRIBUTE_UNUSED)
2438*404b540aSrobert {
2439*404b540aSrobert   if (INSN_P (insn))
2440*404b540aSrobert     {
2441*404b540aSrobert       if (frv_insn_packing_flag >= 0)
2442*404b540aSrobert 	{
2443*404b540aSrobert 	  frv_insn_operands = opvec;
2444*404b540aSrobert 	  frv_insn_packing_flag = PACKING_FLAG_P (insn);
2445*404b540aSrobert 	}
2446*404b540aSrobert       else if (recog_memoized (insn) >= 0
2447*404b540aSrobert 	       && get_attr_acc_group (insn) == ACC_GROUP_ODD)
2448*404b540aSrobert 	/* Packing optimizations have been disabled, but INSN can only
2449*404b540aSrobert 	   be issued in M1.  Insert an mnop in M0.  */
2450*404b540aSrobert 	fprintf (asm_out_file, "\tmnop.p\n");
2451*404b540aSrobert     }
2452*404b540aSrobert }
2453*404b540aSrobert 
2454*404b540aSrobert 
2455*404b540aSrobert 
2456*404b540aSrobert /* A C expression whose value is RTL representing the address in a stack frame
2457*404b540aSrobert    where the pointer to the caller's frame is stored.  Assume that FRAMEADDR is
2458*404b540aSrobert    an RTL expression for the address of the stack frame itself.
2459*404b540aSrobert 
2460*404b540aSrobert    If you don't define this macro, the default is to return the value of
2461*404b540aSrobert    FRAMEADDR--that is, the stack frame address is also the address of the stack
2462*404b540aSrobert    word that points to the previous frame.  */
2463*404b540aSrobert 
2464*404b540aSrobert /* The default is correct, but we need to make sure the frame gets created.  */
2465*404b540aSrobert rtx
frv_dynamic_chain_address(rtx frame)2466*404b540aSrobert frv_dynamic_chain_address (rtx frame)
2467*404b540aSrobert {
2468*404b540aSrobert   cfun->machine->frame_needed = 1;
2469*404b540aSrobert   return frame;
2470*404b540aSrobert }
2471*404b540aSrobert 
2472*404b540aSrobert 
2473*404b540aSrobert /* A C expression whose value is RTL representing the value of the return
2474*404b540aSrobert    address for the frame COUNT steps up from the current frame, after the
2475*404b540aSrobert    prologue.  FRAMEADDR is the frame pointer of the COUNT frame, or the frame
2476*404b540aSrobert    pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
2477*404b540aSrobert    defined.
2478*404b540aSrobert 
2479*404b540aSrobert    The value of the expression must always be the correct address when COUNT is
2480*404b540aSrobert    zero, but may be `NULL_RTX' if there is not way to determine the return
2481*404b540aSrobert    address of other frames.  */
2482*404b540aSrobert 
2483*404b540aSrobert rtx
frv_return_addr_rtx(int count,rtx frame)2484*404b540aSrobert frv_return_addr_rtx (int count, rtx frame)
2485*404b540aSrobert {
2486*404b540aSrobert   if (count != 0)
2487*404b540aSrobert     return const0_rtx;
2488*404b540aSrobert   cfun->machine->frame_needed = 1;
2489*404b540aSrobert   return gen_rtx_MEM (Pmode, plus_constant (frame, 8));
2490*404b540aSrobert }
2491*404b540aSrobert 
2492*404b540aSrobert /* Given a memory reference MEMREF, interpret the referenced memory as
2493*404b540aSrobert    an array of MODE values, and return a reference to the element
2494*404b540aSrobert    specified by INDEX.  Assume that any pre-modification implicit in
2495*404b540aSrobert    MEMREF has already happened.
2496*404b540aSrobert 
2497*404b540aSrobert    MEMREF must be a legitimate operand for modes larger than SImode.
2498*404b540aSrobert    GO_IF_LEGITIMATE_ADDRESS forbids register+register addresses, which
2499*404b540aSrobert    this function cannot handle.  */
2500*404b540aSrobert rtx
frv_index_memory(rtx memref,enum machine_mode mode,int index)2501*404b540aSrobert frv_index_memory (rtx memref, enum machine_mode mode, int index)
2502*404b540aSrobert {
2503*404b540aSrobert   rtx base = XEXP (memref, 0);
2504*404b540aSrobert   if (GET_CODE (base) == PRE_MODIFY)
2505*404b540aSrobert     base = XEXP (base, 0);
2506*404b540aSrobert   return change_address (memref, mode,
2507*404b540aSrobert 			 plus_constant (base, index * GET_MODE_SIZE (mode)));
2508*404b540aSrobert }
2509*404b540aSrobert 
2510*404b540aSrobert 
2511*404b540aSrobert /* Print a memory address as an operand to reference that memory location.  */
2512*404b540aSrobert void
frv_print_operand_address(FILE * stream,rtx x)2513*404b540aSrobert frv_print_operand_address (FILE * stream, rtx x)
2514*404b540aSrobert {
2515*404b540aSrobert   if (GET_CODE (x) == MEM)
2516*404b540aSrobert     x = XEXP (x, 0);
2517*404b540aSrobert 
2518*404b540aSrobert   switch (GET_CODE (x))
2519*404b540aSrobert     {
2520*404b540aSrobert     case REG:
2521*404b540aSrobert       fputs (reg_names [ REGNO (x)], stream);
2522*404b540aSrobert       return;
2523*404b540aSrobert 
2524*404b540aSrobert     case CONST_INT:
2525*404b540aSrobert       fprintf (stream, "%ld", (long) INTVAL (x));
2526*404b540aSrobert       return;
2527*404b540aSrobert 
2528*404b540aSrobert     case SYMBOL_REF:
2529*404b540aSrobert       assemble_name (stream, XSTR (x, 0));
2530*404b540aSrobert       return;
2531*404b540aSrobert 
2532*404b540aSrobert     case LABEL_REF:
2533*404b540aSrobert     case CONST:
2534*404b540aSrobert       output_addr_const (stream, x);
2535*404b540aSrobert       return;
2536*404b540aSrobert 
2537*404b540aSrobert     default:
2538*404b540aSrobert       break;
2539*404b540aSrobert     }
2540*404b540aSrobert 
2541*404b540aSrobert   fatal_insn ("bad insn to frv_print_operand_address:", x);
2542*404b540aSrobert }
2543*404b540aSrobert 
2544*404b540aSrobert 
2545*404b540aSrobert static void
frv_print_operand_memory_reference_reg(FILE * stream,rtx x)2546*404b540aSrobert frv_print_operand_memory_reference_reg (FILE * stream, rtx x)
2547*404b540aSrobert {
2548*404b540aSrobert   int regno = true_regnum (x);
2549*404b540aSrobert   if (GPR_P (regno))
2550*404b540aSrobert     fputs (reg_names[regno], stream);
2551*404b540aSrobert   else
2552*404b540aSrobert     fatal_insn ("bad register to frv_print_operand_memory_reference_reg:", x);
2553*404b540aSrobert }
2554*404b540aSrobert 
2555*404b540aSrobert /* Print a memory reference suitable for the ld/st instructions.  */
2556*404b540aSrobert 
2557*404b540aSrobert static void
frv_print_operand_memory_reference(FILE * stream,rtx x,int addr_offset)2558*404b540aSrobert frv_print_operand_memory_reference (FILE * stream, rtx x, int addr_offset)
2559*404b540aSrobert {
2560*404b540aSrobert   struct frv_unspec unspec;
2561*404b540aSrobert   rtx x0 = NULL_RTX;
2562*404b540aSrobert   rtx x1 = NULL_RTX;
2563*404b540aSrobert 
2564*404b540aSrobert   switch (GET_CODE (x))
2565*404b540aSrobert     {
2566*404b540aSrobert     case SUBREG:
2567*404b540aSrobert     case REG:
2568*404b540aSrobert       x0 = x;
2569*404b540aSrobert       break;
2570*404b540aSrobert 
2571*404b540aSrobert     case PRE_MODIFY:		/* (pre_modify (reg) (plus (reg) (reg))) */
2572*404b540aSrobert       x0 = XEXP (x, 0);
2573*404b540aSrobert       x1 = XEXP (XEXP (x, 1), 1);
2574*404b540aSrobert       break;
2575*404b540aSrobert 
2576*404b540aSrobert     case CONST_INT:
2577*404b540aSrobert       x1 = x;
2578*404b540aSrobert       break;
2579*404b540aSrobert 
2580*404b540aSrobert     case PLUS:
2581*404b540aSrobert       x0 = XEXP (x, 0);
2582*404b540aSrobert       x1 = XEXP (x, 1);
2583*404b540aSrobert       if (GET_CODE (x0) == CONST_INT)
2584*404b540aSrobert 	{
2585*404b540aSrobert 	  x0 = XEXP (x, 1);
2586*404b540aSrobert 	  x1 = XEXP (x, 0);
2587*404b540aSrobert 	}
2588*404b540aSrobert       break;
2589*404b540aSrobert 
2590*404b540aSrobert     default:
2591*404b540aSrobert       fatal_insn ("bad insn to frv_print_operand_memory_reference:", x);
2592*404b540aSrobert       break;
2593*404b540aSrobert 
2594*404b540aSrobert     }
2595*404b540aSrobert 
2596*404b540aSrobert   if (addr_offset)
2597*404b540aSrobert     {
2598*404b540aSrobert       if (!x1)
2599*404b540aSrobert 	x1 = const0_rtx;
2600*404b540aSrobert       else if (GET_CODE (x1) != CONST_INT)
2601*404b540aSrobert 	fatal_insn ("bad insn to frv_print_operand_memory_reference:", x);
2602*404b540aSrobert     }
2603*404b540aSrobert 
2604*404b540aSrobert   fputs ("@(", stream);
2605*404b540aSrobert   if (!x0)
2606*404b540aSrobert     fputs (reg_names[GPR_R0], stream);
2607*404b540aSrobert   else if (GET_CODE (x0) == REG || GET_CODE (x0) == SUBREG)
2608*404b540aSrobert     frv_print_operand_memory_reference_reg (stream, x0);
2609*404b540aSrobert   else
2610*404b540aSrobert     fatal_insn ("bad insn to frv_print_operand_memory_reference:", x);
2611*404b540aSrobert 
2612*404b540aSrobert   fputs (",", stream);
2613*404b540aSrobert   if (!x1)
2614*404b540aSrobert     fputs (reg_names [GPR_R0], stream);
2615*404b540aSrobert 
2616*404b540aSrobert   else
2617*404b540aSrobert     {
2618*404b540aSrobert       switch (GET_CODE (x1))
2619*404b540aSrobert 	{
2620*404b540aSrobert 	case SUBREG:
2621*404b540aSrobert 	case REG:
2622*404b540aSrobert 	  frv_print_operand_memory_reference_reg (stream, x1);
2623*404b540aSrobert 	  break;
2624*404b540aSrobert 
2625*404b540aSrobert 	case CONST_INT:
2626*404b540aSrobert 	  fprintf (stream, "%ld", (long) (INTVAL (x1) + addr_offset));
2627*404b540aSrobert 	  break;
2628*404b540aSrobert 
2629*404b540aSrobert 	case CONST:
2630*404b540aSrobert 	  if (!frv_const_unspec_p (x1, &unspec))
2631*404b540aSrobert 	    fatal_insn ("bad insn to frv_print_operand_memory_reference:", x1);
2632*404b540aSrobert 	  frv_output_const_unspec (stream, &unspec);
2633*404b540aSrobert 	  break;
2634*404b540aSrobert 
2635*404b540aSrobert 	default:
2636*404b540aSrobert 	  fatal_insn ("bad insn to frv_print_operand_memory_reference:", x);
2637*404b540aSrobert 	}
2638*404b540aSrobert     }
2639*404b540aSrobert 
2640*404b540aSrobert   fputs (")", stream);
2641*404b540aSrobert }
2642*404b540aSrobert 
2643*404b540aSrobert 
2644*404b540aSrobert /* Return 2 for likely branches and 0 for non-likely branches  */
2645*404b540aSrobert 
2646*404b540aSrobert #define FRV_JUMP_LIKELY 2
2647*404b540aSrobert #define FRV_JUMP_NOT_LIKELY 0
2648*404b540aSrobert 
2649*404b540aSrobert static int
frv_print_operand_jump_hint(rtx insn)2650*404b540aSrobert frv_print_operand_jump_hint (rtx insn)
2651*404b540aSrobert {
2652*404b540aSrobert   rtx note;
2653*404b540aSrobert   rtx labelref;
2654*404b540aSrobert   int ret;
2655*404b540aSrobert   HOST_WIDE_INT prob = -1;
2656*404b540aSrobert   enum { UNKNOWN, BACKWARD, FORWARD } jump_type = UNKNOWN;
2657*404b540aSrobert 
2658*404b540aSrobert   gcc_assert (GET_CODE (insn) == JUMP_INSN);
2659*404b540aSrobert 
2660*404b540aSrobert   /* Assume any non-conditional jump is likely.  */
2661*404b540aSrobert   if (! any_condjump_p (insn))
2662*404b540aSrobert     ret = FRV_JUMP_LIKELY;
2663*404b540aSrobert 
2664*404b540aSrobert   else
2665*404b540aSrobert     {
2666*404b540aSrobert       labelref = condjump_label (insn);
2667*404b540aSrobert       if (labelref)
2668*404b540aSrobert 	{
2669*404b540aSrobert 	  rtx label = XEXP (labelref, 0);
2670*404b540aSrobert 	  jump_type = (insn_current_address > INSN_ADDRESSES (INSN_UID (label))
2671*404b540aSrobert 		       ? BACKWARD
2672*404b540aSrobert 		       : FORWARD);
2673*404b540aSrobert 	}
2674*404b540aSrobert 
2675*404b540aSrobert       note = find_reg_note (insn, REG_BR_PROB, 0);
2676*404b540aSrobert       if (!note)
2677*404b540aSrobert 	ret = ((jump_type == BACKWARD) ? FRV_JUMP_LIKELY : FRV_JUMP_NOT_LIKELY);
2678*404b540aSrobert 
2679*404b540aSrobert       else
2680*404b540aSrobert 	{
2681*404b540aSrobert 	  prob = INTVAL (XEXP (note, 0));
2682*404b540aSrobert 	  ret = ((prob >= (REG_BR_PROB_BASE / 2))
2683*404b540aSrobert 		 ? FRV_JUMP_LIKELY
2684*404b540aSrobert 		 : FRV_JUMP_NOT_LIKELY);
2685*404b540aSrobert 	}
2686*404b540aSrobert     }
2687*404b540aSrobert 
2688*404b540aSrobert #if 0
2689*404b540aSrobert   if (TARGET_DEBUG)
2690*404b540aSrobert     {
2691*404b540aSrobert       char *direction;
2692*404b540aSrobert 
2693*404b540aSrobert       switch (jump_type)
2694*404b540aSrobert 	{
2695*404b540aSrobert 	default:
2696*404b540aSrobert 	case UNKNOWN:	direction = "unknown jump direction";	break;
2697*404b540aSrobert 	case BACKWARD:	direction = "jump backward";		break;
2698*404b540aSrobert 	case FORWARD:	direction = "jump forward";		break;
2699*404b540aSrobert 	}
2700*404b540aSrobert 
2701*404b540aSrobert       fprintf (stderr,
2702*404b540aSrobert 	       "%s: uid %ld, %s, probability = %ld, max prob. = %ld, hint = %d\n",
2703*404b540aSrobert 	       IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
2704*404b540aSrobert 	       (long)INSN_UID (insn), direction, (long)prob,
2705*404b540aSrobert 	       (long)REG_BR_PROB_BASE, ret);
2706*404b540aSrobert     }
2707*404b540aSrobert #endif
2708*404b540aSrobert 
2709*404b540aSrobert   return ret;
2710*404b540aSrobert }
2711*404b540aSrobert 
2712*404b540aSrobert 
2713*404b540aSrobert /* Return the comparison operator to use for CODE given that the ICC
2714*404b540aSrobert    register is OP0.  */
2715*404b540aSrobert 
2716*404b540aSrobert static const char *
comparison_string(enum rtx_code code,rtx op0)2717*404b540aSrobert comparison_string (enum rtx_code code, rtx op0)
2718*404b540aSrobert {
2719*404b540aSrobert   bool is_nz_p = GET_MODE (op0) == CC_NZmode;
2720*404b540aSrobert   switch (code)
2721*404b540aSrobert     {
2722*404b540aSrobert     default:  output_operand_lossage ("bad condition code");
2723*404b540aSrobert     case EQ:  return "eq";
2724*404b540aSrobert     case NE:  return "ne";
2725*404b540aSrobert     case LT:  return is_nz_p ? "n" : "lt";
2726*404b540aSrobert     case LE:  return "le";
2727*404b540aSrobert     case GT:  return "gt";
2728*404b540aSrobert     case GE:  return is_nz_p ? "p" : "ge";
2729*404b540aSrobert     case LTU: return is_nz_p ? "no" : "c";
2730*404b540aSrobert     case LEU: return is_nz_p ? "eq" : "ls";
2731*404b540aSrobert     case GTU: return is_nz_p ? "ne" : "hi";
2732*404b540aSrobert     case GEU: return is_nz_p ? "ra" : "nc";
2733*404b540aSrobert     }
2734*404b540aSrobert }
2735*404b540aSrobert 
2736*404b540aSrobert /* Print an operand to an assembler instruction.
2737*404b540aSrobert 
2738*404b540aSrobert    `%' followed by a letter and a digit says to output an operand in an
2739*404b540aSrobert    alternate fashion.  Four letters have standard, built-in meanings described
2740*404b540aSrobert    below.  The machine description macro `PRINT_OPERAND' can define additional
2741*404b540aSrobert    letters with nonstandard meanings.
2742*404b540aSrobert 
2743*404b540aSrobert    `%cDIGIT' can be used to substitute an operand that is a constant value
2744*404b540aSrobert    without the syntax that normally indicates an immediate operand.
2745*404b540aSrobert 
2746*404b540aSrobert    `%nDIGIT' is like `%cDIGIT' except that the value of the constant is negated
2747*404b540aSrobert    before printing.
2748*404b540aSrobert 
2749*404b540aSrobert    `%aDIGIT' can be used to substitute an operand as if it were a memory
2750*404b540aSrobert    reference, with the actual operand treated as the address.  This may be
2751*404b540aSrobert    useful when outputting a "load address" instruction, because often the
2752*404b540aSrobert    assembler syntax for such an instruction requires you to write the operand
2753*404b540aSrobert    as if it were a memory reference.
2754*404b540aSrobert 
2755*404b540aSrobert    `%lDIGIT' is used to substitute a `label_ref' into a jump instruction.
2756*404b540aSrobert 
2757*404b540aSrobert    `%=' outputs a number which is unique to each instruction in the entire
2758*404b540aSrobert    compilation.  This is useful for making local labels to be referred to more
2759*404b540aSrobert    than once in a single template that generates multiple assembler
2760*404b540aSrobert    instructions.
2761*404b540aSrobert 
2762*404b540aSrobert    `%' followed by a punctuation character specifies a substitution that does
2763*404b540aSrobert    not use an operand.  Only one case is standard: `%%' outputs a `%' into the
2764*404b540aSrobert    assembler code.  Other nonstandard cases can be defined in the
2765*404b540aSrobert    `PRINT_OPERAND' macro.  You must also define which punctuation characters
2766*404b540aSrobert    are valid with the `PRINT_OPERAND_PUNCT_VALID_P' macro.  */
2767*404b540aSrobert 
2768*404b540aSrobert void
frv_print_operand(FILE * file,rtx x,int code)2769*404b540aSrobert frv_print_operand (FILE * file, rtx x, int code)
2770*404b540aSrobert {
2771*404b540aSrobert   struct frv_unspec unspec;
2772*404b540aSrobert   HOST_WIDE_INT value;
2773*404b540aSrobert   int offset;
2774*404b540aSrobert 
2775*404b540aSrobert   if (code != 0 && !isalpha (code))
2776*404b540aSrobert     value = 0;
2777*404b540aSrobert 
2778*404b540aSrobert   else if (GET_CODE (x) == CONST_INT)
2779*404b540aSrobert     value = INTVAL (x);
2780*404b540aSrobert 
2781*404b540aSrobert   else if (GET_CODE (x) == CONST_DOUBLE)
2782*404b540aSrobert     {
2783*404b540aSrobert       if (GET_MODE (x) == SFmode)
2784*404b540aSrobert 	{
2785*404b540aSrobert 	  REAL_VALUE_TYPE rv;
2786*404b540aSrobert 	  long l;
2787*404b540aSrobert 
2788*404b540aSrobert 	  REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
2789*404b540aSrobert 	  REAL_VALUE_TO_TARGET_SINGLE (rv, l);
2790*404b540aSrobert 	  value = l;
2791*404b540aSrobert 	}
2792*404b540aSrobert 
2793*404b540aSrobert       else if (GET_MODE (x) == VOIDmode)
2794*404b540aSrobert 	value = CONST_DOUBLE_LOW (x);
2795*404b540aSrobert 
2796*404b540aSrobert       else
2797*404b540aSrobert         fatal_insn ("bad insn in frv_print_operand, bad const_double", x);
2798*404b540aSrobert     }
2799*404b540aSrobert 
2800*404b540aSrobert   else
2801*404b540aSrobert     value = 0;
2802*404b540aSrobert 
2803*404b540aSrobert   switch (code)
2804*404b540aSrobert     {
2805*404b540aSrobert 
2806*404b540aSrobert     case '.':
2807*404b540aSrobert       /* Output r0.  */
2808*404b540aSrobert       fputs (reg_names[GPR_R0], file);
2809*404b540aSrobert       break;
2810*404b540aSrobert 
2811*404b540aSrobert     case '#':
2812*404b540aSrobert       fprintf (file, "%d", frv_print_operand_jump_hint (current_output_insn));
2813*404b540aSrobert       break;
2814*404b540aSrobert 
2815*404b540aSrobert     case '@':
2816*404b540aSrobert       /* Output small data area base register (gr16).  */
2817*404b540aSrobert       fputs (reg_names[SDA_BASE_REG], file);
2818*404b540aSrobert       break;
2819*404b540aSrobert 
2820*404b540aSrobert     case '~':
2821*404b540aSrobert       /* Output pic register (gr17).  */
2822*404b540aSrobert       fputs (reg_names[PIC_REGNO], file);
2823*404b540aSrobert       break;
2824*404b540aSrobert 
2825*404b540aSrobert     case '*':
2826*404b540aSrobert       /* Output the temporary integer CCR register.  */
2827*404b540aSrobert       fputs (reg_names[ICR_TEMP], file);
2828*404b540aSrobert       break;
2829*404b540aSrobert 
2830*404b540aSrobert     case '&':
2831*404b540aSrobert       /* Output the temporary integer CC register.  */
2832*404b540aSrobert       fputs (reg_names[ICC_TEMP], file);
2833*404b540aSrobert       break;
2834*404b540aSrobert 
2835*404b540aSrobert     /* case 'a': print an address.  */
2836*404b540aSrobert 
2837*404b540aSrobert     case 'C':
2838*404b540aSrobert       /* Print appropriate test for integer branch false operation.  */
2839*404b540aSrobert       fputs (comparison_string (reverse_condition (GET_CODE (x)),
2840*404b540aSrobert 				XEXP (x, 0)), file);
2841*404b540aSrobert       break;
2842*404b540aSrobert 
2843*404b540aSrobert     case 'c':
2844*404b540aSrobert       /* Print appropriate test for integer branch true operation.  */
2845*404b540aSrobert       fputs (comparison_string (GET_CODE (x), XEXP (x, 0)), file);
2846*404b540aSrobert       break;
2847*404b540aSrobert 
2848*404b540aSrobert     case 'e':
2849*404b540aSrobert       /* Print 1 for a NE and 0 for an EQ to give the final argument
2850*404b540aSrobert 	 for a conditional instruction.  */
2851*404b540aSrobert       if (GET_CODE (x) == NE)
2852*404b540aSrobert 	fputs ("1", file);
2853*404b540aSrobert 
2854*404b540aSrobert       else if (GET_CODE (x) == EQ)
2855*404b540aSrobert 	fputs ("0", file);
2856*404b540aSrobert 
2857*404b540aSrobert       else
2858*404b540aSrobert 	fatal_insn ("bad insn to frv_print_operand, 'e' modifier:", x);
2859*404b540aSrobert       break;
2860*404b540aSrobert 
2861*404b540aSrobert     case 'F':
2862*404b540aSrobert       /* Print appropriate test for floating point branch false operation.  */
2863*404b540aSrobert       switch (GET_CODE (x))
2864*404b540aSrobert 	{
2865*404b540aSrobert 	default:
2866*404b540aSrobert 	  fatal_insn ("bad insn to frv_print_operand, 'F' modifier:", x);
2867*404b540aSrobert 
2868*404b540aSrobert 	case EQ:  fputs ("ne",  file); break;
2869*404b540aSrobert 	case NE:  fputs ("eq",  file); break;
2870*404b540aSrobert 	case LT:  fputs ("uge", file); break;
2871*404b540aSrobert 	case LE:  fputs ("ug",  file); break;
2872*404b540aSrobert 	case GT:  fputs ("ule", file); break;
2873*404b540aSrobert 	case GE:  fputs ("ul",  file); break;
2874*404b540aSrobert 	}
2875*404b540aSrobert       break;
2876*404b540aSrobert 
2877*404b540aSrobert     case 'f':
2878*404b540aSrobert       /* Print appropriate test for floating point branch true operation.  */
2879*404b540aSrobert       switch (GET_CODE (x))
2880*404b540aSrobert 	{
2881*404b540aSrobert 	default:
2882*404b540aSrobert 	  fatal_insn ("bad insn to frv_print_operand, 'f' modifier:", x);
2883*404b540aSrobert 
2884*404b540aSrobert 	case EQ:  fputs ("eq",  file); break;
2885*404b540aSrobert 	case NE:  fputs ("ne",  file); break;
2886*404b540aSrobert 	case LT:  fputs ("lt",  file); break;
2887*404b540aSrobert 	case LE:  fputs ("le",  file); break;
2888*404b540aSrobert 	case GT:  fputs ("gt",  file); break;
2889*404b540aSrobert 	case GE:  fputs ("ge",  file); break;
2890*404b540aSrobert 	}
2891*404b540aSrobert       break;
2892*404b540aSrobert 
2893*404b540aSrobert     case 'g':
2894*404b540aSrobert       /* Print appropriate GOT function.  */
2895*404b540aSrobert       if (GET_CODE (x) != CONST_INT)
2896*404b540aSrobert 	fatal_insn ("bad insn to frv_print_operand, 'g' modifier:", x);
2897*404b540aSrobert       fputs (unspec_got_name (INTVAL (x)), file);
2898*404b540aSrobert       break;
2899*404b540aSrobert 
2900*404b540aSrobert     case 'I':
2901*404b540aSrobert       /* Print 'i' if the operand is a constant, or is a memory reference that
2902*404b540aSrobert          adds a constant.  */
2903*404b540aSrobert       if (GET_CODE (x) == MEM)
2904*404b540aSrobert 	x = ((GET_CODE (XEXP (x, 0)) == PLUS)
2905*404b540aSrobert 	     ? XEXP (XEXP (x, 0), 1)
2906*404b540aSrobert 	     : XEXP (x, 0));
2907*404b540aSrobert       else if (GET_CODE (x) == PLUS)
2908*404b540aSrobert 	x = XEXP (x, 1);
2909*404b540aSrobert 
2910*404b540aSrobert       switch (GET_CODE (x))
2911*404b540aSrobert 	{
2912*404b540aSrobert 	default:
2913*404b540aSrobert 	  break;
2914*404b540aSrobert 
2915*404b540aSrobert 	case CONST_INT:
2916*404b540aSrobert 	case SYMBOL_REF:
2917*404b540aSrobert 	case CONST:
2918*404b540aSrobert 	  fputs ("i", file);
2919*404b540aSrobert 	  break;
2920*404b540aSrobert 	}
2921*404b540aSrobert       break;
2922*404b540aSrobert 
2923*404b540aSrobert     case 'i':
2924*404b540aSrobert       /* For jump instructions, print 'i' if the operand is a constant or
2925*404b540aSrobert          is an expression that adds a constant.  */
2926*404b540aSrobert       if (GET_CODE (x) == CONST_INT)
2927*404b540aSrobert         fputs ("i", file);
2928*404b540aSrobert 
2929*404b540aSrobert       else
2930*404b540aSrobert         {
2931*404b540aSrobert           if (GET_CODE (x) == CONST_INT
2932*404b540aSrobert               || (GET_CODE (x) == PLUS
2933*404b540aSrobert                   && (GET_CODE (XEXP (x, 1)) == CONST_INT
2934*404b540aSrobert                       || GET_CODE (XEXP (x, 0)) == CONST_INT)))
2935*404b540aSrobert             fputs ("i", file);
2936*404b540aSrobert         }
2937*404b540aSrobert       break;
2938*404b540aSrobert 
2939*404b540aSrobert     case 'L':
2940*404b540aSrobert       /* Print the lower register of a double word register pair */
2941*404b540aSrobert       if (GET_CODE (x) == REG)
2942*404b540aSrobert 	fputs (reg_names[ REGNO (x)+1 ], file);
2943*404b540aSrobert       else
2944*404b540aSrobert 	fatal_insn ("bad insn to frv_print_operand, 'L' modifier:", x);
2945*404b540aSrobert       break;
2946*404b540aSrobert 
2947*404b540aSrobert     /* case 'l': print a LABEL_REF.  */
2948*404b540aSrobert 
2949*404b540aSrobert     case 'M':
2950*404b540aSrobert     case 'N':
2951*404b540aSrobert       /* Print a memory reference for ld/st/jmp, %N prints a memory reference
2952*404b540aSrobert          for the second word of double memory operations.  */
2953*404b540aSrobert       offset = (code == 'M') ? 0 : UNITS_PER_WORD;
2954*404b540aSrobert       switch (GET_CODE (x))
2955*404b540aSrobert 	{
2956*404b540aSrobert 	default:
2957*404b540aSrobert 	  fatal_insn ("bad insn to frv_print_operand, 'M/N' modifier:", x);
2958*404b540aSrobert 
2959*404b540aSrobert 	case MEM:
2960*404b540aSrobert 	  frv_print_operand_memory_reference (file, XEXP (x, 0), offset);
2961*404b540aSrobert 	  break;
2962*404b540aSrobert 
2963*404b540aSrobert 	case REG:
2964*404b540aSrobert 	case SUBREG:
2965*404b540aSrobert 	case CONST_INT:
2966*404b540aSrobert 	case PLUS:
2967*404b540aSrobert         case SYMBOL_REF:
2968*404b540aSrobert 	  frv_print_operand_memory_reference (file, x, offset);
2969*404b540aSrobert 	  break;
2970*404b540aSrobert 	}
2971*404b540aSrobert       break;
2972*404b540aSrobert 
2973*404b540aSrobert     case 'O':
2974*404b540aSrobert       /* Print the opcode of a command.  */
2975*404b540aSrobert       switch (GET_CODE (x))
2976*404b540aSrobert 	{
2977*404b540aSrobert 	default:
2978*404b540aSrobert 	  fatal_insn ("bad insn to frv_print_operand, 'O' modifier:", x);
2979*404b540aSrobert 
2980*404b540aSrobert 	case PLUS:     fputs ("add", file); break;
2981*404b540aSrobert 	case MINUS:    fputs ("sub", file); break;
2982*404b540aSrobert 	case AND:      fputs ("and", file); break;
2983*404b540aSrobert 	case IOR:      fputs ("or",  file); break;
2984*404b540aSrobert 	case XOR:      fputs ("xor", file); break;
2985*404b540aSrobert 	case ASHIFT:   fputs ("sll", file); break;
2986*404b540aSrobert 	case ASHIFTRT: fputs ("sra", file); break;
2987*404b540aSrobert 	case LSHIFTRT: fputs ("srl", file); break;
2988*404b540aSrobert 	}
2989*404b540aSrobert       break;
2990*404b540aSrobert 
2991*404b540aSrobert     /* case 'n': negate and print a constant int.  */
2992*404b540aSrobert 
2993*404b540aSrobert     case 'P':
2994*404b540aSrobert       /* Print PIC label using operand as the number.  */
2995*404b540aSrobert       if (GET_CODE (x) != CONST_INT)
2996*404b540aSrobert 	fatal_insn ("bad insn to frv_print_operand, P modifier:", x);
2997*404b540aSrobert 
2998*404b540aSrobert       fprintf (file, ".LCF%ld", (long)INTVAL (x));
2999*404b540aSrobert       break;
3000*404b540aSrobert 
3001*404b540aSrobert     case 'U':
3002*404b540aSrobert       /* Print 'u' if the operand is a update load/store.  */
3003*404b540aSrobert       if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
3004*404b540aSrobert 	fputs ("u", file);
3005*404b540aSrobert       break;
3006*404b540aSrobert 
3007*404b540aSrobert     case 'z':
3008*404b540aSrobert       /* If value is 0, print gr0, otherwise it must be a register.  */
3009*404b540aSrobert       if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0)
3010*404b540aSrobert 	fputs (reg_names[GPR_R0], file);
3011*404b540aSrobert 
3012*404b540aSrobert       else if (GET_CODE (x) == REG)
3013*404b540aSrobert         fputs (reg_names [REGNO (x)], file);
3014*404b540aSrobert 
3015*404b540aSrobert       else
3016*404b540aSrobert         fatal_insn ("bad insn in frv_print_operand, z case", x);
3017*404b540aSrobert       break;
3018*404b540aSrobert 
3019*404b540aSrobert     case 'x':
3020*404b540aSrobert       /* Print constant in hex.  */
3021*404b540aSrobert       if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
3022*404b540aSrobert         {
3023*404b540aSrobert 	  fprintf (file, "%s0x%.4lx", IMMEDIATE_PREFIX, (long) value);
3024*404b540aSrobert 	  break;
3025*404b540aSrobert 	}
3026*404b540aSrobert 
3027*404b540aSrobert       /* Fall through.  */
3028*404b540aSrobert 
3029*404b540aSrobert     case '\0':
3030*404b540aSrobert       if (GET_CODE (x) == REG)
3031*404b540aSrobert         fputs (reg_names [REGNO (x)], file);
3032*404b540aSrobert 
3033*404b540aSrobert       else if (GET_CODE (x) == CONST_INT
3034*404b540aSrobert               || GET_CODE (x) == CONST_DOUBLE)
3035*404b540aSrobert         fprintf (file, "%s%ld", IMMEDIATE_PREFIX, (long) value);
3036*404b540aSrobert 
3037*404b540aSrobert       else if (frv_const_unspec_p (x, &unspec))
3038*404b540aSrobert 	frv_output_const_unspec (file, &unspec);
3039*404b540aSrobert 
3040*404b540aSrobert       else if (GET_CODE (x) == MEM)
3041*404b540aSrobert         frv_print_operand_address (file, XEXP (x, 0));
3042*404b540aSrobert 
3043*404b540aSrobert       else if (CONSTANT_ADDRESS_P (x))
3044*404b540aSrobert         frv_print_operand_address (file, x);
3045*404b540aSrobert 
3046*404b540aSrobert       else
3047*404b540aSrobert         fatal_insn ("bad insn in frv_print_operand, 0 case", x);
3048*404b540aSrobert 
3049*404b540aSrobert       break;
3050*404b540aSrobert 
3051*404b540aSrobert     default:
3052*404b540aSrobert       fatal_insn ("frv_print_operand: unknown code", x);
3053*404b540aSrobert       break;
3054*404b540aSrobert     }
3055*404b540aSrobert 
3056*404b540aSrobert   return;
3057*404b540aSrobert }
3058*404b540aSrobert 
3059*404b540aSrobert 
3060*404b540aSrobert /* A C statement (sans semicolon) for initializing the variable CUM for the
3061*404b540aSrobert    state at the beginning of the argument list.  The variable has type
3062*404b540aSrobert    `CUMULATIVE_ARGS'.  The value of FNTYPE is the tree node for the data type
3063*404b540aSrobert    of the function which will receive the args, or 0 if the args are to a
3064*404b540aSrobert    compiler support library function.  The value of INDIRECT is nonzero when
3065*404b540aSrobert    processing an indirect call, for example a call through a function pointer.
3066*404b540aSrobert    The value of INDIRECT is zero for a call to an explicitly named function, a
3067*404b540aSrobert    library function call, or when `INIT_CUMULATIVE_ARGS' is used to find
3068*404b540aSrobert    arguments for the function being compiled.
3069*404b540aSrobert 
3070*404b540aSrobert    When processing a call to a compiler support library function, LIBNAME
3071*404b540aSrobert    identifies which one.  It is a `symbol_ref' rtx which contains the name of
3072*404b540aSrobert    the function, as a string.  LIBNAME is 0 when an ordinary C function call is
3073*404b540aSrobert    being processed.  Thus, each time this macro is called, either LIBNAME or
3074*404b540aSrobert    FNTYPE is nonzero, but never both of them at once.  */
3075*404b540aSrobert 
3076*404b540aSrobert void
frv_init_cumulative_args(CUMULATIVE_ARGS * cum,tree fntype,rtx libname,tree fndecl,int incoming)3077*404b540aSrobert frv_init_cumulative_args (CUMULATIVE_ARGS *cum,
3078*404b540aSrobert                           tree fntype,
3079*404b540aSrobert                           rtx libname,
3080*404b540aSrobert                           tree fndecl,
3081*404b540aSrobert                           int incoming)
3082*404b540aSrobert {
3083*404b540aSrobert   *cum = FIRST_ARG_REGNUM;
3084*404b540aSrobert 
3085*404b540aSrobert   if (TARGET_DEBUG_ARG)
3086*404b540aSrobert     {
3087*404b540aSrobert       fprintf (stderr, "\ninit_cumulative_args:");
3088*404b540aSrobert       if (!fndecl && fntype)
3089*404b540aSrobert 	fputs (" indirect", stderr);
3090*404b540aSrobert 
3091*404b540aSrobert       if (incoming)
3092*404b540aSrobert 	fputs (" incoming", stderr);
3093*404b540aSrobert 
3094*404b540aSrobert       if (fntype)
3095*404b540aSrobert 	{
3096*404b540aSrobert 	  tree ret_type = TREE_TYPE (fntype);
3097*404b540aSrobert 	  fprintf (stderr, " return=%s,",
3098*404b540aSrobert 		   tree_code_name[ (int)TREE_CODE (ret_type) ]);
3099*404b540aSrobert 	}
3100*404b540aSrobert 
3101*404b540aSrobert       if (libname && GET_CODE (libname) == SYMBOL_REF)
3102*404b540aSrobert 	fprintf (stderr, " libname=%s", XSTR (libname, 0));
3103*404b540aSrobert 
3104*404b540aSrobert       if (cfun->returns_struct)
3105*404b540aSrobert 	fprintf (stderr, " return-struct");
3106*404b540aSrobert 
3107*404b540aSrobert       putc ('\n', stderr);
3108*404b540aSrobert     }
3109*404b540aSrobert }
3110*404b540aSrobert 
3111*404b540aSrobert 
3112*404b540aSrobert /* Return true if we should pass an argument on the stack rather than
3113*404b540aSrobert    in registers.  */
3114*404b540aSrobert 
3115*404b540aSrobert static bool
frv_must_pass_in_stack(enum machine_mode mode,tree type)3116*404b540aSrobert frv_must_pass_in_stack (enum machine_mode mode, tree type)
3117*404b540aSrobert {
3118*404b540aSrobert   if (mode == BLKmode)
3119*404b540aSrobert     return true;
3120*404b540aSrobert   if (type == NULL)
3121*404b540aSrobert     return false;
3122*404b540aSrobert   return AGGREGATE_TYPE_P (type);
3123*404b540aSrobert }
3124*404b540aSrobert 
3125*404b540aSrobert /* If defined, a C expression that gives the alignment boundary, in bits, of an
3126*404b540aSrobert    argument with the specified mode and type.  If it is not defined,
3127*404b540aSrobert    `PARM_BOUNDARY' is used for all arguments.  */
3128*404b540aSrobert 
3129*404b540aSrobert int
frv_function_arg_boundary(enum machine_mode mode ATTRIBUTE_UNUSED,tree type ATTRIBUTE_UNUSED)3130*404b540aSrobert frv_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED,
3131*404b540aSrobert                            tree type ATTRIBUTE_UNUSED)
3132*404b540aSrobert {
3133*404b540aSrobert   return BITS_PER_WORD;
3134*404b540aSrobert }
3135*404b540aSrobert 
3136*404b540aSrobert rtx
frv_function_arg(CUMULATIVE_ARGS * cum,enum machine_mode mode,tree type ATTRIBUTE_UNUSED,int named,int incoming ATTRIBUTE_UNUSED)3137*404b540aSrobert frv_function_arg (CUMULATIVE_ARGS *cum,
3138*404b540aSrobert                   enum machine_mode mode,
3139*404b540aSrobert                   tree type ATTRIBUTE_UNUSED,
3140*404b540aSrobert                   int named,
3141*404b540aSrobert                   int incoming ATTRIBUTE_UNUSED)
3142*404b540aSrobert {
3143*404b540aSrobert   enum machine_mode xmode = (mode == BLKmode) ? SImode : mode;
3144*404b540aSrobert   int arg_num = *cum;
3145*404b540aSrobert   rtx ret;
3146*404b540aSrobert   const char *debstr;
3147*404b540aSrobert 
3148*404b540aSrobert   /* Return a marker for use in the call instruction.  */
3149*404b540aSrobert   if (xmode == VOIDmode)
3150*404b540aSrobert     {
3151*404b540aSrobert       ret = const0_rtx;
3152*404b540aSrobert       debstr = "<0>";
3153*404b540aSrobert     }
3154*404b540aSrobert 
3155*404b540aSrobert   else if (arg_num <= LAST_ARG_REGNUM)
3156*404b540aSrobert     {
3157*404b540aSrobert       ret = gen_rtx_REG (xmode, arg_num);
3158*404b540aSrobert       debstr = reg_names[arg_num];
3159*404b540aSrobert     }
3160*404b540aSrobert 
3161*404b540aSrobert   else
3162*404b540aSrobert     {
3163*404b540aSrobert       ret = NULL_RTX;
3164*404b540aSrobert       debstr = "memory";
3165*404b540aSrobert     }
3166*404b540aSrobert 
3167*404b540aSrobert   if (TARGET_DEBUG_ARG)
3168*404b540aSrobert     fprintf (stderr,
3169*404b540aSrobert 	     "function_arg: words = %2d, mode = %4s, named = %d, size = %3d, arg = %s\n",
3170*404b540aSrobert 	     arg_num, GET_MODE_NAME (mode), named, GET_MODE_SIZE (mode), debstr);
3171*404b540aSrobert 
3172*404b540aSrobert   return ret;
3173*404b540aSrobert }
3174*404b540aSrobert 
3175*404b540aSrobert 
3176*404b540aSrobert /* A C statement (sans semicolon) to update the summarizer variable CUM to
3177*404b540aSrobert    advance past an argument in the argument list.  The values MODE, TYPE and
3178*404b540aSrobert    NAMED describe that argument.  Once this is done, the variable CUM is
3179*404b540aSrobert    suitable for analyzing the *following* argument with `FUNCTION_ARG', etc.
3180*404b540aSrobert 
3181*404b540aSrobert    This macro need not do anything if the argument in question was passed on
3182*404b540aSrobert    the stack.  The compiler knows how to track the amount of stack space used
3183*404b540aSrobert    for arguments without any special help.  */
3184*404b540aSrobert 
3185*404b540aSrobert void
frv_function_arg_advance(CUMULATIVE_ARGS * cum,enum machine_mode mode,tree type ATTRIBUTE_UNUSED,int named)3186*404b540aSrobert frv_function_arg_advance (CUMULATIVE_ARGS *cum,
3187*404b540aSrobert                           enum machine_mode mode,
3188*404b540aSrobert                           tree type ATTRIBUTE_UNUSED,
3189*404b540aSrobert                           int named)
3190*404b540aSrobert {
3191*404b540aSrobert   enum machine_mode xmode = (mode == BLKmode) ? SImode : mode;
3192*404b540aSrobert   int bytes = GET_MODE_SIZE (xmode);
3193*404b540aSrobert   int words = (bytes + UNITS_PER_WORD  - 1) / UNITS_PER_WORD;
3194*404b540aSrobert   int arg_num = *cum;
3195*404b540aSrobert 
3196*404b540aSrobert   *cum = arg_num + words;
3197*404b540aSrobert 
3198*404b540aSrobert   if (TARGET_DEBUG_ARG)
3199*404b540aSrobert     fprintf (stderr,
3200*404b540aSrobert 	     "function_adv: words = %2d, mode = %4s, named = %d, size = %3d\n",
3201*404b540aSrobert 	     arg_num, GET_MODE_NAME (mode), named, words * UNITS_PER_WORD);
3202*404b540aSrobert }
3203*404b540aSrobert 
3204*404b540aSrobert 
3205*404b540aSrobert /* A C expression for the number of words, at the beginning of an argument,
3206*404b540aSrobert    must be put in registers.  The value must be zero for arguments that are
3207*404b540aSrobert    passed entirely in registers or that are entirely pushed on the stack.
3208*404b540aSrobert 
3209*404b540aSrobert    On some machines, certain arguments must be passed partially in registers
3210*404b540aSrobert    and partially in memory.  On these machines, typically the first N words of
3211*404b540aSrobert    arguments are passed in registers, and the rest on the stack.  If a
3212*404b540aSrobert    multi-word argument (a `double' or a structure) crosses that boundary, its
3213*404b540aSrobert    first few words must be passed in registers and the rest must be pushed.
3214*404b540aSrobert    This macro tells the compiler when this occurs, and how many of the words
3215*404b540aSrobert    should go in registers.
3216*404b540aSrobert 
3217*404b540aSrobert    `FUNCTION_ARG' for these arguments should return the first register to be
3218*404b540aSrobert    used by the caller for this argument; likewise `FUNCTION_INCOMING_ARG', for
3219*404b540aSrobert    the called function.  */
3220*404b540aSrobert 
3221*404b540aSrobert static int
frv_arg_partial_bytes(CUMULATIVE_ARGS * cum,enum machine_mode mode,tree type ATTRIBUTE_UNUSED,bool named ATTRIBUTE_UNUSED)3222*404b540aSrobert frv_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
3223*404b540aSrobert 		       tree type ATTRIBUTE_UNUSED, bool named ATTRIBUTE_UNUSED)
3224*404b540aSrobert {
3225*404b540aSrobert   enum machine_mode xmode = (mode == BLKmode) ? SImode : mode;
3226*404b540aSrobert   int bytes = GET_MODE_SIZE (xmode);
3227*404b540aSrobert   int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
3228*404b540aSrobert   int arg_num = *cum;
3229*404b540aSrobert   int ret;
3230*404b540aSrobert 
3231*404b540aSrobert   ret = ((arg_num <= LAST_ARG_REGNUM && arg_num + words > LAST_ARG_REGNUM+1)
3232*404b540aSrobert 	 ? LAST_ARG_REGNUM - arg_num + 1
3233*404b540aSrobert 	 : 0);
3234*404b540aSrobert   ret *= UNITS_PER_WORD;
3235*404b540aSrobert 
3236*404b540aSrobert   if (TARGET_DEBUG_ARG && ret)
3237*404b540aSrobert     fprintf (stderr, "frv_arg_partial_bytes: %d\n", ret);
3238*404b540aSrobert 
3239*404b540aSrobert   return ret;
3240*404b540aSrobert }
3241*404b540aSrobert 
3242*404b540aSrobert 
3243*404b540aSrobert /* Return true if a register is ok to use as a base or index register.  */
3244*404b540aSrobert 
3245*404b540aSrobert static FRV_INLINE int
frv_regno_ok_for_base_p(int regno,int strict_p)3246*404b540aSrobert frv_regno_ok_for_base_p (int regno, int strict_p)
3247*404b540aSrobert {
3248*404b540aSrobert   if (GPR_P (regno))
3249*404b540aSrobert     return TRUE;
3250*404b540aSrobert 
3251*404b540aSrobert   if (strict_p)
3252*404b540aSrobert     return (reg_renumber[regno] >= 0 && GPR_P (reg_renumber[regno]));
3253*404b540aSrobert 
3254*404b540aSrobert   if (regno == ARG_POINTER_REGNUM)
3255*404b540aSrobert     return TRUE;
3256*404b540aSrobert 
3257*404b540aSrobert   return (regno >= FIRST_PSEUDO_REGISTER);
3258*404b540aSrobert }
3259*404b540aSrobert 
3260*404b540aSrobert 
3261*404b540aSrobert /* A C compound statement with a conditional `goto LABEL;' executed if X (an
3262*404b540aSrobert    RTX) is a legitimate memory address on the target machine for a memory
3263*404b540aSrobert    operand of mode MODE.
3264*404b540aSrobert 
3265*404b540aSrobert    It usually pays to define several simpler macros to serve as subroutines for
3266*404b540aSrobert    this one.  Otherwise it may be too complicated to understand.
3267*404b540aSrobert 
3268*404b540aSrobert    This macro must exist in two variants: a strict variant and a non-strict
3269*404b540aSrobert    one.  The strict variant is used in the reload pass.  It must be defined so
3270*404b540aSrobert    that any pseudo-register that has not been allocated a hard register is
3271*404b540aSrobert    considered a memory reference.  In contexts where some kind of register is
3272*404b540aSrobert    required, a pseudo-register with no hard register must be rejected.
3273*404b540aSrobert 
3274*404b540aSrobert    The non-strict variant is used in other passes.  It must be defined to
3275*404b540aSrobert    accept all pseudo-registers in every context where some kind of register is
3276*404b540aSrobert    required.
3277*404b540aSrobert 
3278*404b540aSrobert    Compiler source files that want to use the strict variant of this macro
3279*404b540aSrobert    define the macro `REG_OK_STRICT'.  You should use an `#ifdef REG_OK_STRICT'
3280*404b540aSrobert    conditional to define the strict variant in that case and the non-strict
3281*404b540aSrobert    variant otherwise.
3282*404b540aSrobert 
3283*404b540aSrobert    Subroutines to check for acceptable registers for various purposes (one for
3284*404b540aSrobert    base registers, one for index registers, and so on) are typically among the
3285*404b540aSrobert    subroutines used to define `GO_IF_LEGITIMATE_ADDRESS'.  Then only these
3286*404b540aSrobert    subroutine macros need have two variants; the higher levels of macros may be
3287*404b540aSrobert    the same whether strict or not.
3288*404b540aSrobert 
3289*404b540aSrobert    Normally, constant addresses which are the sum of a `symbol_ref' and an
3290*404b540aSrobert    integer are stored inside a `const' RTX to mark them as constant.
3291*404b540aSrobert    Therefore, there is no need to recognize such sums specifically as
3292*404b540aSrobert    legitimate addresses.  Normally you would simply recognize any `const' as
3293*404b540aSrobert    legitimate.
3294*404b540aSrobert 
3295*404b540aSrobert    Usually `PRINT_OPERAND_ADDRESS' is not prepared to handle constant sums that
3296*404b540aSrobert    are not marked with `const'.  It assumes that a naked `plus' indicates
3297*404b540aSrobert    indexing.  If so, then you *must* reject such naked constant sums as
3298*404b540aSrobert    illegitimate addresses, so that none of them will be given to
3299*404b540aSrobert    `PRINT_OPERAND_ADDRESS'.
3300*404b540aSrobert 
3301*404b540aSrobert    On some machines, whether a symbolic address is legitimate depends on the
3302*404b540aSrobert    section that the address refers to.  On these machines, define the macro
3303*404b540aSrobert    `ENCODE_SECTION_INFO' to store the information into the `symbol_ref', and
3304*404b540aSrobert    then check for it here.  When you see a `const', you will have to look
3305*404b540aSrobert    inside it to find the `symbol_ref' in order to determine the section.
3306*404b540aSrobert 
3307*404b540aSrobert    The best way to modify the name string is by adding text to the beginning,
3308*404b540aSrobert    with suitable punctuation to prevent any ambiguity.  Allocate the new name
3309*404b540aSrobert    in `saveable_obstack'.  You will have to modify `ASM_OUTPUT_LABELREF' to
3310*404b540aSrobert    remove and decode the added text and output the name accordingly, and define
3311*404b540aSrobert    `(* targetm.strip_name_encoding)' to access the original name string.
3312*404b540aSrobert 
3313*404b540aSrobert    You can check the information stored here into the `symbol_ref' in the
3314*404b540aSrobert    definitions of the macros `GO_IF_LEGITIMATE_ADDRESS' and
3315*404b540aSrobert    `PRINT_OPERAND_ADDRESS'.  */
3316*404b540aSrobert 
3317*404b540aSrobert int
frv_legitimate_address_p(enum machine_mode mode,rtx x,int strict_p,int condexec_p,int allow_double_reg_p)3318*404b540aSrobert frv_legitimate_address_p (enum machine_mode mode,
3319*404b540aSrobert                           rtx x,
3320*404b540aSrobert                           int strict_p,
3321*404b540aSrobert                           int condexec_p,
3322*404b540aSrobert 			  int allow_double_reg_p)
3323*404b540aSrobert {
3324*404b540aSrobert   rtx x0, x1;
3325*404b540aSrobert   int ret = 0;
3326*404b540aSrobert   HOST_WIDE_INT value;
3327*404b540aSrobert   unsigned regno0;
3328*404b540aSrobert 
3329*404b540aSrobert   if (FRV_SYMBOL_REF_TLS_P (x))
3330*404b540aSrobert     return 0;
3331*404b540aSrobert 
3332*404b540aSrobert   switch (GET_CODE (x))
3333*404b540aSrobert     {
3334*404b540aSrobert     default:
3335*404b540aSrobert       break;
3336*404b540aSrobert 
3337*404b540aSrobert     case SUBREG:
3338*404b540aSrobert       x = SUBREG_REG (x);
3339*404b540aSrobert       if (GET_CODE (x) != REG)
3340*404b540aSrobert         break;
3341*404b540aSrobert 
3342*404b540aSrobert       /* Fall through.  */
3343*404b540aSrobert 
3344*404b540aSrobert     case REG:
3345*404b540aSrobert       ret = frv_regno_ok_for_base_p (REGNO (x), strict_p);
3346*404b540aSrobert       break;
3347*404b540aSrobert 
3348*404b540aSrobert     case PRE_MODIFY:
3349*404b540aSrobert       x0 = XEXP (x, 0);
3350*404b540aSrobert       x1 = XEXP (x, 1);
3351*404b540aSrobert       if (GET_CODE (x0) != REG
3352*404b540aSrobert 	  || ! frv_regno_ok_for_base_p (REGNO (x0), strict_p)
3353*404b540aSrobert 	  || GET_CODE (x1) != PLUS
3354*404b540aSrobert 	  || ! rtx_equal_p (x0, XEXP (x1, 0))
3355*404b540aSrobert 	  || GET_CODE (XEXP (x1, 1)) != REG
3356*404b540aSrobert 	  || ! frv_regno_ok_for_base_p (REGNO (XEXP (x1, 1)), strict_p))
3357*404b540aSrobert 	break;
3358*404b540aSrobert 
3359*404b540aSrobert       ret = 1;
3360*404b540aSrobert       break;
3361*404b540aSrobert 
3362*404b540aSrobert     case CONST_INT:
3363*404b540aSrobert       /* 12 bit immediate */
3364*404b540aSrobert       if (condexec_p)
3365*404b540aSrobert 	ret = FALSE;
3366*404b540aSrobert       else
3367*404b540aSrobert 	{
3368*404b540aSrobert 	  ret = IN_RANGE_P (INTVAL (x), -2048, 2047);
3369*404b540aSrobert 
3370*404b540aSrobert 	  /* If we can't use load/store double operations, make sure we can
3371*404b540aSrobert 	     address the second word.  */
3372*404b540aSrobert 	  if (ret && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
3373*404b540aSrobert 	    ret = IN_RANGE_P (INTVAL (x) + GET_MODE_SIZE (mode) - 1,
3374*404b540aSrobert 			      -2048, 2047);
3375*404b540aSrobert 	}
3376*404b540aSrobert       break;
3377*404b540aSrobert 
3378*404b540aSrobert     case PLUS:
3379*404b540aSrobert       x0 = XEXP (x, 0);
3380*404b540aSrobert       x1 = XEXP (x, 1);
3381*404b540aSrobert 
3382*404b540aSrobert       if (GET_CODE (x0) == SUBREG)
3383*404b540aSrobert 	x0 = SUBREG_REG (x0);
3384*404b540aSrobert 
3385*404b540aSrobert       if (GET_CODE (x0) != REG)
3386*404b540aSrobert 	break;
3387*404b540aSrobert 
3388*404b540aSrobert       regno0 = REGNO (x0);
3389*404b540aSrobert       if (!frv_regno_ok_for_base_p (regno0, strict_p))
3390*404b540aSrobert 	break;
3391*404b540aSrobert 
3392*404b540aSrobert       switch (GET_CODE (x1))
3393*404b540aSrobert 	{
3394*404b540aSrobert 	default:
3395*404b540aSrobert 	  break;
3396*404b540aSrobert 
3397*404b540aSrobert 	case SUBREG:
3398*404b540aSrobert 	  x1 = SUBREG_REG (x1);
3399*404b540aSrobert 	  if (GET_CODE (x1) != REG)
3400*404b540aSrobert 	    break;
3401*404b540aSrobert 
3402*404b540aSrobert 	  /* Fall through.  */
3403*404b540aSrobert 
3404*404b540aSrobert 	case REG:
3405*404b540aSrobert 	  /* Do not allow reg+reg addressing for modes > 1 word if we
3406*404b540aSrobert 	     can't depend on having move double instructions.  */
3407*404b540aSrobert 	  if (!allow_double_reg_p && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
3408*404b540aSrobert 	    ret = FALSE;
3409*404b540aSrobert 	  else
3410*404b540aSrobert 	    ret = frv_regno_ok_for_base_p (REGNO (x1), strict_p);
3411*404b540aSrobert 	  break;
3412*404b540aSrobert 
3413*404b540aSrobert 	case CONST_INT:
3414*404b540aSrobert           /* 12 bit immediate */
3415*404b540aSrobert 	  if (condexec_p)
3416*404b540aSrobert 	    ret = FALSE;
3417*404b540aSrobert 	  else
3418*404b540aSrobert 	    {
3419*404b540aSrobert 	      value = INTVAL (x1);
3420*404b540aSrobert 	      ret = IN_RANGE_P (value, -2048, 2047);
3421*404b540aSrobert 
3422*404b540aSrobert 	      /* If we can't use load/store double operations, make sure we can
3423*404b540aSrobert 		 address the second word.  */
3424*404b540aSrobert 	      if (ret && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
3425*404b540aSrobert 		ret = IN_RANGE_P (value + GET_MODE_SIZE (mode) - 1, -2048, 2047);
3426*404b540aSrobert 	    }
3427*404b540aSrobert 	  break;
3428*404b540aSrobert 
3429*404b540aSrobert 	case CONST:
3430*404b540aSrobert 	  if (!condexec_p && got12_operand (x1, VOIDmode))
3431*404b540aSrobert 	    ret = TRUE;
3432*404b540aSrobert 	  break;
3433*404b540aSrobert 
3434*404b540aSrobert 	}
3435*404b540aSrobert       break;
3436*404b540aSrobert     }
3437*404b540aSrobert 
3438*404b540aSrobert   if (TARGET_DEBUG_ADDR)
3439*404b540aSrobert     {
3440*404b540aSrobert       fprintf (stderr, "\n========== GO_IF_LEGITIMATE_ADDRESS, mode = %s, result = %d, addresses are %sstrict%s\n",
3441*404b540aSrobert 	       GET_MODE_NAME (mode), ret, (strict_p) ? "" : "not ",
3442*404b540aSrobert 	       (condexec_p) ? ", inside conditional code" : "");
3443*404b540aSrobert       debug_rtx (x);
3444*404b540aSrobert     }
3445*404b540aSrobert 
3446*404b540aSrobert   return ret;
3447*404b540aSrobert }
3448*404b540aSrobert 
3449*404b540aSrobert /* Given an ADDR, generate code to inline the PLT.  */
3450*404b540aSrobert static rtx
gen_inlined_tls_plt(rtx addr)3451*404b540aSrobert gen_inlined_tls_plt (rtx addr)
3452*404b540aSrobert {
3453*404b540aSrobert   rtx retval, dest;
3454*404b540aSrobert   rtx picreg = get_hard_reg_initial_val (Pmode, FDPIC_REG);
3455*404b540aSrobert 
3456*404b540aSrobert 
3457*404b540aSrobert   dest = gen_reg_rtx (DImode);
3458*404b540aSrobert 
3459*404b540aSrobert   if (flag_pic == 1)
3460*404b540aSrobert     {
3461*404b540aSrobert       /*
3462*404b540aSrobert 	-fpic version:
3463*404b540aSrobert 
3464*404b540aSrobert 	lddi.p  @(gr15, #gottlsdesc12(ADDR)), gr8
3465*404b540aSrobert 	calll    #gettlsoff(ADDR)@(gr8, gr0)
3466*404b540aSrobert       */
3467*404b540aSrobert       emit_insn (gen_tls_lddi (dest, addr, picreg));
3468*404b540aSrobert     }
3469*404b540aSrobert   else
3470*404b540aSrobert     {
3471*404b540aSrobert       /*
3472*404b540aSrobert 	-fPIC version:
3473*404b540aSrobert 
3474*404b540aSrobert 	sethi.p #gottlsdeschi(ADDR), gr8
3475*404b540aSrobert 	setlo   #gottlsdesclo(ADDR), gr8
3476*404b540aSrobert 	ldd     #tlsdesc(ADDR)@(gr15, gr8), gr8
3477*404b540aSrobert 	calll   #gettlsoff(ADDR)@(gr8, gr0)
3478*404b540aSrobert       */
3479*404b540aSrobert       rtx reguse = gen_reg_rtx (Pmode);
3480*404b540aSrobert       emit_insn (gen_tlsoff_hilo (reguse, addr, GEN_INT (R_FRV_GOTTLSDESCHI)));
3481*404b540aSrobert       emit_insn (gen_tls_tlsdesc_ldd (dest, picreg, reguse, addr));
3482*404b540aSrobert     }
3483*404b540aSrobert 
3484*404b540aSrobert   retval = gen_reg_rtx (Pmode);
3485*404b540aSrobert   emit_insn (gen_tls_indirect_call (retval, addr, dest, picreg));
3486*404b540aSrobert   return retval;
3487*404b540aSrobert }
3488*404b540aSrobert 
3489*404b540aSrobert /* Emit a TLSMOFF or TLSMOFF12 offset, depending on -mTLS.  Returns
3490*404b540aSrobert    the destination address.  */
3491*404b540aSrobert static rtx
gen_tlsmoff(rtx addr,rtx reg)3492*404b540aSrobert gen_tlsmoff (rtx addr, rtx reg)
3493*404b540aSrobert {
3494*404b540aSrobert   rtx dest = gen_reg_rtx (Pmode);
3495*404b540aSrobert 
3496*404b540aSrobert   if (TARGET_BIG_TLS)
3497*404b540aSrobert     {
3498*404b540aSrobert       /* sethi.p #tlsmoffhi(x), grA
3499*404b540aSrobert 	 setlo   #tlsmofflo(x), grA
3500*404b540aSrobert       */
3501*404b540aSrobert       dest = gen_reg_rtx (Pmode);
3502*404b540aSrobert       emit_insn (gen_tlsoff_hilo (dest, addr,
3503*404b540aSrobert 				  GEN_INT (R_FRV_TLSMOFFHI)));
3504*404b540aSrobert       dest = gen_rtx_PLUS (Pmode, dest, reg);
3505*404b540aSrobert     }
3506*404b540aSrobert   else
3507*404b540aSrobert     {
3508*404b540aSrobert       /* addi grB, #tlsmoff12(x), grC
3509*404b540aSrobert 	   -or-
3510*404b540aSrobert 	 ld/st @(grB, #tlsmoff12(x)), grC
3511*404b540aSrobert       */
3512*404b540aSrobert       dest = gen_reg_rtx (Pmode);
3513*404b540aSrobert       emit_insn (gen_symGOTOFF2reg_i (dest, addr, reg,
3514*404b540aSrobert 				      GEN_INT (R_FRV_TLSMOFF12)));
3515*404b540aSrobert     }
3516*404b540aSrobert   return dest;
3517*404b540aSrobert }
3518*404b540aSrobert 
3519*404b540aSrobert /* Generate code for a TLS address.  */
3520*404b540aSrobert static rtx
frv_legitimize_tls_address(rtx addr,enum tls_model model)3521*404b540aSrobert frv_legitimize_tls_address (rtx addr, enum tls_model model)
3522*404b540aSrobert {
3523*404b540aSrobert   rtx dest, tp = gen_rtx_REG (Pmode, 29);
3524*404b540aSrobert   rtx picreg = get_hard_reg_initial_val (Pmode, 15);
3525*404b540aSrobert 
3526*404b540aSrobert   switch (model)
3527*404b540aSrobert     {
3528*404b540aSrobert     case TLS_MODEL_INITIAL_EXEC:
3529*404b540aSrobert       if (flag_pic == 1)
3530*404b540aSrobert 	{
3531*404b540aSrobert 	  /* -fpic version.
3532*404b540aSrobert 	     ldi @(gr15, #gottlsoff12(x)), gr5
3533*404b540aSrobert 	   */
3534*404b540aSrobert 	  dest = gen_reg_rtx (Pmode);
3535*404b540aSrobert 	  emit_insn (gen_tls_load_gottlsoff12 (dest, addr, picreg));
3536*404b540aSrobert 	  dest = gen_rtx_PLUS (Pmode, tp, dest);
3537*404b540aSrobert 	}
3538*404b540aSrobert       else
3539*404b540aSrobert 	{
3540*404b540aSrobert 	  /* -fPIC or anything else.
3541*404b540aSrobert 
3542*404b540aSrobert 	    sethi.p #gottlsoffhi(x), gr14
3543*404b540aSrobert 	    setlo   #gottlsofflo(x), gr14
3544*404b540aSrobert 	    ld      #tlsoff(x)@(gr15, gr14), gr9
3545*404b540aSrobert 	  */
3546*404b540aSrobert 	  rtx tmp = gen_reg_rtx (Pmode);
3547*404b540aSrobert 	  dest = gen_reg_rtx (Pmode);
3548*404b540aSrobert 	  emit_insn (gen_tlsoff_hilo (tmp, addr,
3549*404b540aSrobert 				      GEN_INT (R_FRV_GOTTLSOFF_HI)));
3550*404b540aSrobert 
3551*404b540aSrobert 	  emit_insn (gen_tls_tlsoff_ld (dest, picreg, tmp, addr));
3552*404b540aSrobert 	  dest = gen_rtx_PLUS (Pmode, tp, dest);
3553*404b540aSrobert 	}
3554*404b540aSrobert       break;
3555*404b540aSrobert     case TLS_MODEL_LOCAL_DYNAMIC:
3556*404b540aSrobert       {
3557*404b540aSrobert 	rtx reg, retval;
3558*404b540aSrobert 
3559*404b540aSrobert 	if (TARGET_INLINE_PLT)
3560*404b540aSrobert 	  retval = gen_inlined_tls_plt (GEN_INT (0));
3561*404b540aSrobert 	else
3562*404b540aSrobert 	  {
3563*404b540aSrobert 	    /* call #gettlsoff(0) */
3564*404b540aSrobert 	    retval = gen_reg_rtx (Pmode);
3565*404b540aSrobert 	    emit_insn (gen_call_gettlsoff (retval, GEN_INT (0), picreg));
3566*404b540aSrobert 	  }
3567*404b540aSrobert 
3568*404b540aSrobert 	reg = gen_reg_rtx (Pmode);
3569*404b540aSrobert 	emit_insn (gen_rtx_SET (VOIDmode, reg,
3570*404b540aSrobert 				gen_rtx_PLUS (Pmode,
3571*404b540aSrobert 					      retval, tp)));
3572*404b540aSrobert 
3573*404b540aSrobert 	dest = gen_tlsmoff (addr, reg);
3574*404b540aSrobert 
3575*404b540aSrobert 	/*
3576*404b540aSrobert 	dest = gen_reg_rtx (Pmode);
3577*404b540aSrobert 	emit_insn (gen_tlsoff_hilo (dest, addr,
3578*404b540aSrobert 				    GEN_INT (R_FRV_TLSMOFFHI)));
3579*404b540aSrobert 	dest = gen_rtx_PLUS (Pmode, dest, reg);
3580*404b540aSrobert 	*/
3581*404b540aSrobert 	break;
3582*404b540aSrobert       }
3583*404b540aSrobert     case TLS_MODEL_LOCAL_EXEC:
3584*404b540aSrobert       dest = gen_tlsmoff (addr, gen_rtx_REG (Pmode, 29));
3585*404b540aSrobert       break;
3586*404b540aSrobert     case TLS_MODEL_GLOBAL_DYNAMIC:
3587*404b540aSrobert       {
3588*404b540aSrobert 	rtx retval;
3589*404b540aSrobert 
3590*404b540aSrobert 	if (TARGET_INLINE_PLT)
3591*404b540aSrobert 	  retval = gen_inlined_tls_plt (addr);
3592*404b540aSrobert 	else
3593*404b540aSrobert 	  {
3594*404b540aSrobert 	    /* call #gettlsoff(x) */
3595*404b540aSrobert 	    retval = gen_reg_rtx (Pmode);
3596*404b540aSrobert 	    emit_insn (gen_call_gettlsoff (retval, addr, picreg));
3597*404b540aSrobert 	  }
3598*404b540aSrobert 	dest = gen_rtx_PLUS (Pmode, retval, tp);
3599*404b540aSrobert 	break;
3600*404b540aSrobert       }
3601*404b540aSrobert     default:
3602*404b540aSrobert       gcc_unreachable ();
3603*404b540aSrobert     }
3604*404b540aSrobert 
3605*404b540aSrobert   return dest;
3606*404b540aSrobert }
3607*404b540aSrobert 
3608*404b540aSrobert rtx
frv_legitimize_address(rtx x,rtx oldx ATTRIBUTE_UNUSED,enum machine_mode mode ATTRIBUTE_UNUSED)3609*404b540aSrobert frv_legitimize_address (rtx x,
3610*404b540aSrobert 			rtx oldx ATTRIBUTE_UNUSED,
3611*404b540aSrobert 			enum machine_mode mode ATTRIBUTE_UNUSED)
3612*404b540aSrobert {
3613*404b540aSrobert   if (GET_CODE (x) == SYMBOL_REF)
3614*404b540aSrobert     {
3615*404b540aSrobert       enum tls_model model = SYMBOL_REF_TLS_MODEL (x);
3616*404b540aSrobert       if (model != 0)
3617*404b540aSrobert         return frv_legitimize_tls_address (x, model);
3618*404b540aSrobert     }
3619*404b540aSrobert 
3620*404b540aSrobert   return NULL_RTX;
3621*404b540aSrobert }
3622*404b540aSrobert 
3623*404b540aSrobert /* Test whether a local function descriptor is canonical, i.e.,
3624*404b540aSrobert    whether we can use FUNCDESC_GOTOFF to compute the address of the
3625*404b540aSrobert    function.  */
3626*404b540aSrobert 
3627*404b540aSrobert static bool
frv_local_funcdesc_p(rtx fnx)3628*404b540aSrobert frv_local_funcdesc_p (rtx fnx)
3629*404b540aSrobert {
3630*404b540aSrobert   tree fn;
3631*404b540aSrobert   enum symbol_visibility vis;
3632*404b540aSrobert   bool ret;
3633*404b540aSrobert 
3634*404b540aSrobert   if (! SYMBOL_REF_LOCAL_P (fnx))
3635*404b540aSrobert     return FALSE;
3636*404b540aSrobert 
3637*404b540aSrobert   fn = SYMBOL_REF_DECL (fnx);
3638*404b540aSrobert 
3639*404b540aSrobert   if (! fn)
3640*404b540aSrobert     return FALSE;
3641*404b540aSrobert 
3642*404b540aSrobert   vis = DECL_VISIBILITY (fn);
3643*404b540aSrobert 
3644*404b540aSrobert   if (vis == VISIBILITY_PROTECTED)
3645*404b540aSrobert     /* Private function descriptors for protected functions are not
3646*404b540aSrobert        canonical.  Temporarily change the visibility to global.  */
3647*404b540aSrobert     vis = VISIBILITY_DEFAULT;
3648*404b540aSrobert   else if (flag_shlib)
3649*404b540aSrobert     /* If we're already compiling for a shared library (that, unlike
3650*404b540aSrobert        executables, can't assume that the existence of a definition
3651*404b540aSrobert        implies local binding), we can skip the re-testing.  */
3652*404b540aSrobert     return TRUE;
3653*404b540aSrobert 
3654*404b540aSrobert   ret = default_binds_local_p_1 (fn, flag_pic);
3655*404b540aSrobert 
3656*404b540aSrobert   DECL_VISIBILITY (fn) = vis;
3657*404b540aSrobert 
3658*404b540aSrobert   return ret;
3659*404b540aSrobert }
3660*404b540aSrobert 
3661*404b540aSrobert /* Load the _gp symbol into DEST.  SRC is supposed to be the FDPIC
3662*404b540aSrobert    register.  */
3663*404b540aSrobert 
3664*404b540aSrobert rtx
frv_gen_GPsym2reg(rtx dest,rtx src)3665*404b540aSrobert frv_gen_GPsym2reg (rtx dest, rtx src)
3666*404b540aSrobert {
3667*404b540aSrobert   tree gp = get_identifier ("_gp");
3668*404b540aSrobert   rtx gp_sym = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (gp));
3669*404b540aSrobert 
3670*404b540aSrobert   return gen_symGOT2reg (dest, gp_sym, src, GEN_INT (R_FRV_GOT12));
3671*404b540aSrobert }
3672*404b540aSrobert 
3673*404b540aSrobert static const char *
unspec_got_name(int i)3674*404b540aSrobert unspec_got_name (int i)
3675*404b540aSrobert {
3676*404b540aSrobert   switch (i)
3677*404b540aSrobert     {
3678*404b540aSrobert     case R_FRV_GOT12: return "got12";
3679*404b540aSrobert     case R_FRV_GOTHI: return "gothi";
3680*404b540aSrobert     case R_FRV_GOTLO: return "gotlo";
3681*404b540aSrobert     case R_FRV_FUNCDESC: return "funcdesc";
3682*404b540aSrobert     case R_FRV_FUNCDESC_GOT12: return "gotfuncdesc12";
3683*404b540aSrobert     case R_FRV_FUNCDESC_GOTHI: return "gotfuncdeschi";
3684*404b540aSrobert     case R_FRV_FUNCDESC_GOTLO: return "gotfuncdesclo";
3685*404b540aSrobert     case R_FRV_FUNCDESC_VALUE: return "funcdescvalue";
3686*404b540aSrobert     case R_FRV_FUNCDESC_GOTOFF12: return "gotofffuncdesc12";
3687*404b540aSrobert     case R_FRV_FUNCDESC_GOTOFFHI: return "gotofffuncdeschi";
3688*404b540aSrobert     case R_FRV_FUNCDESC_GOTOFFLO: return "gotofffuncdesclo";
3689*404b540aSrobert     case R_FRV_GOTOFF12: return "gotoff12";
3690*404b540aSrobert     case R_FRV_GOTOFFHI: return "gotoffhi";
3691*404b540aSrobert     case R_FRV_GOTOFFLO: return "gotofflo";
3692*404b540aSrobert     case R_FRV_GPREL12: return "gprel12";
3693*404b540aSrobert     case R_FRV_GPRELHI: return "gprelhi";
3694*404b540aSrobert     case R_FRV_GPRELLO: return "gprello";
3695*404b540aSrobert     case R_FRV_GOTTLSOFF_HI: return "gottlsoffhi";
3696*404b540aSrobert     case R_FRV_GOTTLSOFF_LO: return "gottlsofflo";
3697*404b540aSrobert     case R_FRV_TLSMOFFHI: return "tlsmoffhi";
3698*404b540aSrobert     case R_FRV_TLSMOFFLO: return "tlsmofflo";
3699*404b540aSrobert     case R_FRV_TLSMOFF12: return "tlsmoff12";
3700*404b540aSrobert     case R_FRV_TLSDESCHI: return "tlsdeschi";
3701*404b540aSrobert     case R_FRV_TLSDESCLO: return "tlsdesclo";
3702*404b540aSrobert     case R_FRV_GOTTLSDESCHI: return "gottlsdeschi";
3703*404b540aSrobert     case R_FRV_GOTTLSDESCLO: return "gottlsdesclo";
3704*404b540aSrobert     default: gcc_unreachable ();
3705*404b540aSrobert     }
3706*404b540aSrobert }
3707*404b540aSrobert 
3708*404b540aSrobert /* Write the assembler syntax for UNSPEC to STREAM.  Note that any offset
3709*404b540aSrobert    is added inside the relocation operator.  */
3710*404b540aSrobert 
3711*404b540aSrobert static void
frv_output_const_unspec(FILE * stream,const struct frv_unspec * unspec)3712*404b540aSrobert frv_output_const_unspec (FILE *stream, const struct frv_unspec *unspec)
3713*404b540aSrobert {
3714*404b540aSrobert   fprintf (stream, "#%s(", unspec_got_name (unspec->reloc));
3715*404b540aSrobert   output_addr_const (stream, plus_constant (unspec->symbol, unspec->offset));
3716*404b540aSrobert   fputs (")", stream);
3717*404b540aSrobert }
3718*404b540aSrobert 
3719*404b540aSrobert /* Implement FIND_BASE_TERM.  See whether ORIG_X represents #gprel12(foo)
3720*404b540aSrobert    or #gotoff12(foo) for some small data symbol foo.  If so, return foo,
3721*404b540aSrobert    otherwise return ORIG_X.  */
3722*404b540aSrobert 
3723*404b540aSrobert rtx
frv_find_base_term(rtx x)3724*404b540aSrobert frv_find_base_term (rtx x)
3725*404b540aSrobert {
3726*404b540aSrobert   struct frv_unspec unspec;
3727*404b540aSrobert 
3728*404b540aSrobert   if (frv_const_unspec_p (x, &unspec)
3729*404b540aSrobert       && frv_small_data_reloc_p (unspec.symbol, unspec.reloc))
3730*404b540aSrobert     return plus_constant (unspec.symbol, unspec.offset);
3731*404b540aSrobert 
3732*404b540aSrobert   return x;
3733*404b540aSrobert }
3734*404b540aSrobert 
3735*404b540aSrobert /* Return 1 if operand is a valid FRV address.  CONDEXEC_P is true if
3736*404b540aSrobert    the operand is used by a predicated instruction.  */
3737*404b540aSrobert 
3738*404b540aSrobert int
frv_legitimate_memory_operand(rtx op,enum machine_mode mode,int condexec_p)3739*404b540aSrobert frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p)
3740*404b540aSrobert {
3741*404b540aSrobert   return ((GET_MODE (op) == mode || mode == VOIDmode)
3742*404b540aSrobert 	  && GET_CODE (op) == MEM
3743*404b540aSrobert 	  && frv_legitimate_address_p (mode, XEXP (op, 0),
3744*404b540aSrobert 				       reload_completed, condexec_p, FALSE));
3745*404b540aSrobert }
3746*404b540aSrobert 
3747*404b540aSrobert void
frv_expand_fdpic_call(rtx * operands,bool ret_value,bool sibcall)3748*404b540aSrobert frv_expand_fdpic_call (rtx *operands, bool ret_value, bool sibcall)
3749*404b540aSrobert {
3750*404b540aSrobert   rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
3751*404b540aSrobert   rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REG);
3752*404b540aSrobert   rtx c, rvrtx=0;
3753*404b540aSrobert   rtx addr;
3754*404b540aSrobert 
3755*404b540aSrobert   if (ret_value)
3756*404b540aSrobert     {
3757*404b540aSrobert       rvrtx = operands[0];
3758*404b540aSrobert       operands ++;
3759*404b540aSrobert     }
3760*404b540aSrobert 
3761*404b540aSrobert   addr = XEXP (operands[0], 0);
3762*404b540aSrobert 
3763*404b540aSrobert   /* Inline PLTs if we're optimizing for speed.  We'd like to inline
3764*404b540aSrobert      any calls that would involve a PLT, but can't tell, since we
3765*404b540aSrobert      don't know whether an extern function is going to be provided by
3766*404b540aSrobert      a separate translation unit or imported from a separate module.
3767*404b540aSrobert      When compiling for shared libraries, if the function has default
3768*404b540aSrobert      visibility, we assume it's overridable, so we inline the PLT, but
3769*404b540aSrobert      for executables, we don't really have a way to make a good
3770*404b540aSrobert      decision: a function is as likely to be imported from a shared
3771*404b540aSrobert      library as it is to be defined in the executable itself.  We
3772*404b540aSrobert      assume executables will get global functions defined locally,
3773*404b540aSrobert      whereas shared libraries will have them potentially overridden,
3774*404b540aSrobert      so we only inline PLTs when compiling for shared libraries.
3775*404b540aSrobert 
3776*404b540aSrobert      In order to mark a function as local to a shared library, any
3777*404b540aSrobert      non-default visibility attribute suffices.  Unfortunately,
3778*404b540aSrobert      there's no simple way to tag a function declaration as ``in a
3779*404b540aSrobert      different module'', which we could then use to trigger PLT
3780*404b540aSrobert      inlining on executables.  There's -minline-plt, but it affects
3781*404b540aSrobert      all external functions, so one would have to also mark function
3782*404b540aSrobert      declarations available in the same module with non-default
3783*404b540aSrobert      visibility, which is advantageous in itself.  */
3784*404b540aSrobert   if (GET_CODE (addr) == SYMBOL_REF
3785*404b540aSrobert       && ((!SYMBOL_REF_LOCAL_P (addr) && TARGET_INLINE_PLT)
3786*404b540aSrobert 	  || sibcall))
3787*404b540aSrobert     {
3788*404b540aSrobert       rtx x, dest;
3789*404b540aSrobert       dest = gen_reg_rtx (SImode);
3790*404b540aSrobert       if (flag_pic != 1)
3791*404b540aSrobert 	x = gen_symGOTOFF2reg_hilo (dest, addr, OUR_FDPIC_REG,
3792*404b540aSrobert 				    GEN_INT (R_FRV_FUNCDESC_GOTOFF12));
3793*404b540aSrobert       else
3794*404b540aSrobert 	x = gen_symGOTOFF2reg (dest, addr, OUR_FDPIC_REG,
3795*404b540aSrobert 			       GEN_INT (R_FRV_FUNCDESC_GOTOFF12));
3796*404b540aSrobert       emit_insn (x);
3797*404b540aSrobert       cfun->uses_pic_offset_table = TRUE;
3798*404b540aSrobert       addr = dest;
3799*404b540aSrobert     }
3800*404b540aSrobert   else if (GET_CODE (addr) == SYMBOL_REF)
3801*404b540aSrobert     {
3802*404b540aSrobert       /* These are always either local, or handled through a local
3803*404b540aSrobert 	 PLT.  */
3804*404b540aSrobert       if (ret_value)
3805*404b540aSrobert 	c = gen_call_value_fdpicsi (rvrtx, addr, operands[1],
3806*404b540aSrobert 				    operands[2], picreg, lr);
3807*404b540aSrobert       else
3808*404b540aSrobert 	c = gen_call_fdpicsi (addr, operands[1], operands[2], picreg, lr);
3809*404b540aSrobert       emit_call_insn (c);
3810*404b540aSrobert       return;
3811*404b540aSrobert     }
3812*404b540aSrobert   else if (! ldd_address_operand (addr, Pmode))
3813*404b540aSrobert     addr = force_reg (Pmode, addr);
3814*404b540aSrobert 
3815*404b540aSrobert   picreg = gen_reg_rtx (DImode);
3816*404b540aSrobert   emit_insn (gen_movdi_ldd (picreg, addr));
3817*404b540aSrobert 
3818*404b540aSrobert   if (sibcall && ret_value)
3819*404b540aSrobert     c = gen_sibcall_value_fdpicdi (rvrtx, picreg, const0_rtx);
3820*404b540aSrobert   else if (sibcall)
3821*404b540aSrobert     c = gen_sibcall_fdpicdi (picreg, const0_rtx);
3822*404b540aSrobert   else if (ret_value)
3823*404b540aSrobert     c = gen_call_value_fdpicdi (rvrtx, picreg, const0_rtx, lr);
3824*404b540aSrobert   else
3825*404b540aSrobert     c = gen_call_fdpicdi (picreg, const0_rtx, lr);
3826*404b540aSrobert   emit_call_insn (c);
3827*404b540aSrobert }
3828*404b540aSrobert 
3829*404b540aSrobert /* Look for a SYMBOL_REF of a function in an rtx.  We always want to
3830*404b540aSrobert    process these separately from any offsets, such that we add any
3831*404b540aSrobert    offsets to the function descriptor (the actual pointer), not to the
3832*404b540aSrobert    function address.  */
3833*404b540aSrobert 
3834*404b540aSrobert static bool
frv_function_symbol_referenced_p(rtx x)3835*404b540aSrobert frv_function_symbol_referenced_p (rtx x)
3836*404b540aSrobert {
3837*404b540aSrobert   const char *format;
3838*404b540aSrobert   int length;
3839*404b540aSrobert   int j;
3840*404b540aSrobert 
3841*404b540aSrobert   if (GET_CODE (x) == SYMBOL_REF)
3842*404b540aSrobert     return SYMBOL_REF_FUNCTION_P (x);
3843*404b540aSrobert 
3844*404b540aSrobert   length = GET_RTX_LENGTH (GET_CODE (x));
3845*404b540aSrobert   format = GET_RTX_FORMAT (GET_CODE (x));
3846*404b540aSrobert 
3847*404b540aSrobert   for (j = 0; j < length; ++j)
3848*404b540aSrobert     {
3849*404b540aSrobert       switch (format[j])
3850*404b540aSrobert 	{
3851*404b540aSrobert 	case 'e':
3852*404b540aSrobert 	  if (frv_function_symbol_referenced_p (XEXP (x, j)))
3853*404b540aSrobert 	    return TRUE;
3854*404b540aSrobert 	  break;
3855*404b540aSrobert 
3856*404b540aSrobert 	case 'V':
3857*404b540aSrobert 	case 'E':
3858*404b540aSrobert 	  if (XVEC (x, j) != 0)
3859*404b540aSrobert 	    {
3860*404b540aSrobert 	      int k;
3861*404b540aSrobert 	      for (k = 0; k < XVECLEN (x, j); ++k)
3862*404b540aSrobert 		if (frv_function_symbol_referenced_p (XVECEXP (x, j, k)))
3863*404b540aSrobert 		  return TRUE;
3864*404b540aSrobert 	    }
3865*404b540aSrobert 	  break;
3866*404b540aSrobert 
3867*404b540aSrobert 	default:
3868*404b540aSrobert 	  /* Nothing to do.  */
3869*404b540aSrobert 	  break;
3870*404b540aSrobert 	}
3871*404b540aSrobert     }
3872*404b540aSrobert 
3873*404b540aSrobert   return FALSE;
3874*404b540aSrobert }
3875*404b540aSrobert 
3876*404b540aSrobert /* Return true if the memory operand is one that can be conditionally
3877*404b540aSrobert    executed.  */
3878*404b540aSrobert 
3879*404b540aSrobert int
condexec_memory_operand(rtx op,enum machine_mode mode)3880*404b540aSrobert condexec_memory_operand (rtx op, enum machine_mode mode)
3881*404b540aSrobert {
3882*404b540aSrobert   enum machine_mode op_mode = GET_MODE (op);
3883*404b540aSrobert   rtx addr;
3884*404b540aSrobert 
3885*404b540aSrobert   if (mode != VOIDmode && op_mode != mode)
3886*404b540aSrobert     return FALSE;
3887*404b540aSrobert 
3888*404b540aSrobert   switch (op_mode)
3889*404b540aSrobert     {
3890*404b540aSrobert     default:
3891*404b540aSrobert       return FALSE;
3892*404b540aSrobert 
3893*404b540aSrobert     case QImode:
3894*404b540aSrobert     case HImode:
3895*404b540aSrobert     case SImode:
3896*404b540aSrobert     case SFmode:
3897*404b540aSrobert       break;
3898*404b540aSrobert     }
3899*404b540aSrobert 
3900*404b540aSrobert   if (GET_CODE (op) != MEM)
3901*404b540aSrobert     return FALSE;
3902*404b540aSrobert 
3903*404b540aSrobert   addr = XEXP (op, 0);
3904*404b540aSrobert   return frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE);
3905*404b540aSrobert }
3906*404b540aSrobert 
3907*404b540aSrobert /* Return true if the bare return instruction can be used outside of the
3908*404b540aSrobert    epilog code.  For frv, we only do it if there was no stack allocation.  */
3909*404b540aSrobert 
3910*404b540aSrobert int
direct_return_p(void)3911*404b540aSrobert direct_return_p (void)
3912*404b540aSrobert {
3913*404b540aSrobert   frv_stack_t *info;
3914*404b540aSrobert 
3915*404b540aSrobert   if (!reload_completed)
3916*404b540aSrobert     return FALSE;
3917*404b540aSrobert 
3918*404b540aSrobert   info = frv_stack_info ();
3919*404b540aSrobert   return (info->total_size == 0);
3920*404b540aSrobert }
3921*404b540aSrobert 
3922*404b540aSrobert 
3923*404b540aSrobert void
frv_emit_move(enum machine_mode mode,rtx dest,rtx src)3924*404b540aSrobert frv_emit_move (enum machine_mode mode, rtx dest, rtx src)
3925*404b540aSrobert {
3926*404b540aSrobert   if (GET_CODE (src) == SYMBOL_REF)
3927*404b540aSrobert     {
3928*404b540aSrobert       enum tls_model model = SYMBOL_REF_TLS_MODEL (src);
3929*404b540aSrobert       if (model != 0)
3930*404b540aSrobert 	src = frv_legitimize_tls_address (src, model);
3931*404b540aSrobert     }
3932*404b540aSrobert 
3933*404b540aSrobert   switch (mode)
3934*404b540aSrobert     {
3935*404b540aSrobert     case SImode:
3936*404b540aSrobert       if (frv_emit_movsi (dest, src))
3937*404b540aSrobert 	return;
3938*404b540aSrobert       break;
3939*404b540aSrobert 
3940*404b540aSrobert     case QImode:
3941*404b540aSrobert     case HImode:
3942*404b540aSrobert     case DImode:
3943*404b540aSrobert     case SFmode:
3944*404b540aSrobert     case DFmode:
3945*404b540aSrobert       if (!reload_in_progress
3946*404b540aSrobert 	  && !reload_completed
3947*404b540aSrobert 	  && !register_operand (dest, mode)
3948*404b540aSrobert 	  && !reg_or_0_operand (src, mode))
3949*404b540aSrobert 	src = copy_to_mode_reg (mode, src);
3950*404b540aSrobert       break;
3951*404b540aSrobert 
3952*404b540aSrobert     default:
3953*404b540aSrobert       gcc_unreachable ();
3954*404b540aSrobert     }
3955*404b540aSrobert 
3956*404b540aSrobert   emit_insn (gen_rtx_SET (VOIDmode, dest, src));
3957*404b540aSrobert }
3958*404b540aSrobert 
3959*404b540aSrobert /* Emit code to handle a MOVSI, adding in the small data register or pic
3960*404b540aSrobert    register if needed to load up addresses.  Return TRUE if the appropriate
3961*404b540aSrobert    instructions are emitted.  */
3962*404b540aSrobert 
3963*404b540aSrobert int
frv_emit_movsi(rtx dest,rtx src)3964*404b540aSrobert frv_emit_movsi (rtx dest, rtx src)
3965*404b540aSrobert {
3966*404b540aSrobert   int base_regno = -1;
3967*404b540aSrobert   int unspec = 0;
3968*404b540aSrobert   rtx sym = src;
3969*404b540aSrobert   struct frv_unspec old_unspec;
3970*404b540aSrobert 
3971*404b540aSrobert   if (!reload_in_progress
3972*404b540aSrobert       && !reload_completed
3973*404b540aSrobert       && !register_operand (dest, SImode)
3974*404b540aSrobert       && (!reg_or_0_operand (src, SImode)
3975*404b540aSrobert 	     /* Virtual registers will almost always be replaced by an
3976*404b540aSrobert 		add instruction, so expose this to CSE by copying to
3977*404b540aSrobert 		an intermediate register.  */
3978*404b540aSrobert 	  || (GET_CODE (src) == REG
3979*404b540aSrobert 	      && IN_RANGE_P (REGNO (src),
3980*404b540aSrobert 			     FIRST_VIRTUAL_REGISTER,
3981*404b540aSrobert 			     LAST_VIRTUAL_REGISTER))))
3982*404b540aSrobert     {
3983*404b540aSrobert       emit_insn (gen_rtx_SET (VOIDmode, dest, copy_to_mode_reg (SImode, src)));
3984*404b540aSrobert       return TRUE;
3985*404b540aSrobert     }
3986*404b540aSrobert 
3987*404b540aSrobert   /* Explicitly add in the PIC or small data register if needed.  */
3988*404b540aSrobert   switch (GET_CODE (src))
3989*404b540aSrobert     {
3990*404b540aSrobert     default:
3991*404b540aSrobert       break;
3992*404b540aSrobert 
3993*404b540aSrobert     case LABEL_REF:
3994*404b540aSrobert     handle_label:
3995*404b540aSrobert       if (TARGET_FDPIC)
3996*404b540aSrobert 	{
3997*404b540aSrobert 	  /* Using GPREL12, we use a single GOT entry for all symbols
3998*404b540aSrobert 	     in read-only sections, but trade sequences such as:
3999*404b540aSrobert 
4000*404b540aSrobert 	     sethi #gothi(label), gr#
4001*404b540aSrobert 	     setlo #gotlo(label), gr#
4002*404b540aSrobert 	     ld    @(gr15,gr#), gr#
4003*404b540aSrobert 
4004*404b540aSrobert 	     for
4005*404b540aSrobert 
4006*404b540aSrobert 	     ld    @(gr15,#got12(_gp)), gr#
4007*404b540aSrobert 	     sethi #gprelhi(label), gr##
4008*404b540aSrobert 	     setlo #gprello(label), gr##
4009*404b540aSrobert 	     add   gr#, gr##, gr##
4010*404b540aSrobert 
4011*404b540aSrobert 	     We may often be able to share gr# for multiple
4012*404b540aSrobert 	     computations of GPREL addresses, and we may often fold
4013*404b540aSrobert 	     the final add into the pair of registers of a load or
4014*404b540aSrobert 	     store instruction, so it's often profitable.  Even when
4015*404b540aSrobert 	     optimizing for size, we're trading a GOT entry for an
4016*404b540aSrobert 	     additional instruction, which trades GOT space
4017*404b540aSrobert 	     (read-write) for code size (read-only, shareable), as
4018*404b540aSrobert 	     long as the symbol is not used in more than two different
4019*404b540aSrobert 	     locations.
4020*404b540aSrobert 
4021*404b540aSrobert 	     With -fpie/-fpic, we'd be trading a single load for a
4022*404b540aSrobert 	     sequence of 4 instructions, because the offset of the
4023*404b540aSrobert 	     label can't be assumed to be addressable with 12 bits, so
4024*404b540aSrobert 	     we don't do this.  */
4025*404b540aSrobert 	  if (TARGET_GPREL_RO)
4026*404b540aSrobert 	    unspec = R_FRV_GPREL12;
4027*404b540aSrobert 	  else
4028*404b540aSrobert 	    unspec = R_FRV_GOT12;
4029*404b540aSrobert 	}
4030*404b540aSrobert       else if (flag_pic)
4031*404b540aSrobert 	base_regno = PIC_REGNO;
4032*404b540aSrobert 
4033*404b540aSrobert       break;
4034*404b540aSrobert 
4035*404b540aSrobert     case CONST:
4036*404b540aSrobert       if (frv_const_unspec_p (src, &old_unspec))
4037*404b540aSrobert 	break;
4038*404b540aSrobert 
4039*404b540aSrobert       if (TARGET_FDPIC && frv_function_symbol_referenced_p (XEXP (src, 0)))
4040*404b540aSrobert 	{
4041*404b540aSrobert 	handle_whatever:
4042*404b540aSrobert 	  src = force_reg (GET_MODE (XEXP (src, 0)), XEXP (src, 0));
4043*404b540aSrobert 	  emit_move_insn (dest, src);
4044*404b540aSrobert 	  return TRUE;
4045*404b540aSrobert 	}
4046*404b540aSrobert       else
4047*404b540aSrobert 	{
4048*404b540aSrobert 	  sym = XEXP (sym, 0);
4049*404b540aSrobert 	  if (GET_CODE (sym) == PLUS
4050*404b540aSrobert 	      && GET_CODE (XEXP (sym, 0)) == SYMBOL_REF
4051*404b540aSrobert 	      && GET_CODE (XEXP (sym, 1)) == CONST_INT)
4052*404b540aSrobert 	    sym = XEXP (sym, 0);
4053*404b540aSrobert 	  if (GET_CODE (sym) == SYMBOL_REF)
4054*404b540aSrobert 	    goto handle_sym;
4055*404b540aSrobert 	  else if (GET_CODE (sym) == LABEL_REF)
4056*404b540aSrobert 	    goto handle_label;
4057*404b540aSrobert 	  else
4058*404b540aSrobert 	    goto handle_whatever;
4059*404b540aSrobert 	}
4060*404b540aSrobert       break;
4061*404b540aSrobert 
4062*404b540aSrobert     case SYMBOL_REF:
4063*404b540aSrobert     handle_sym:
4064*404b540aSrobert       if (TARGET_FDPIC)
4065*404b540aSrobert 	{
4066*404b540aSrobert 	  enum tls_model model = SYMBOL_REF_TLS_MODEL (sym);
4067*404b540aSrobert 
4068*404b540aSrobert 	  if (model != 0)
4069*404b540aSrobert 	    {
4070*404b540aSrobert 	      src = frv_legitimize_tls_address (src, model);
4071*404b540aSrobert 	      emit_move_insn (dest, src);
4072*404b540aSrobert 	      return TRUE;
4073*404b540aSrobert 	    }
4074*404b540aSrobert 
4075*404b540aSrobert 	  if (SYMBOL_REF_FUNCTION_P (sym))
4076*404b540aSrobert 	    {
4077*404b540aSrobert 	      if (frv_local_funcdesc_p (sym))
4078*404b540aSrobert 		unspec = R_FRV_FUNCDESC_GOTOFF12;
4079*404b540aSrobert 	      else
4080*404b540aSrobert 		unspec = R_FRV_FUNCDESC_GOT12;
4081*404b540aSrobert 	    }
4082*404b540aSrobert 	  else
4083*404b540aSrobert 	    {
4084*404b540aSrobert 	      if (CONSTANT_POOL_ADDRESS_P (sym))
4085*404b540aSrobert 		switch (GET_CODE (get_pool_constant (sym)))
4086*404b540aSrobert 		  {
4087*404b540aSrobert 		  case CONST:
4088*404b540aSrobert 		  case SYMBOL_REF:
4089*404b540aSrobert 		  case LABEL_REF:
4090*404b540aSrobert 		    if (flag_pic)
4091*404b540aSrobert 		      {
4092*404b540aSrobert 			unspec = R_FRV_GOTOFF12;
4093*404b540aSrobert 			break;
4094*404b540aSrobert 		      }
4095*404b540aSrobert 		    /* Fall through.  */
4096*404b540aSrobert 		  default:
4097*404b540aSrobert 		    if (TARGET_GPREL_RO)
4098*404b540aSrobert 		      unspec = R_FRV_GPREL12;
4099*404b540aSrobert 		    else
4100*404b540aSrobert 		      unspec = R_FRV_GOT12;
4101*404b540aSrobert 		    break;
4102*404b540aSrobert 		  }
4103*404b540aSrobert 	      else if (SYMBOL_REF_LOCAL_P (sym)
4104*404b540aSrobert 		       && !SYMBOL_REF_EXTERNAL_P (sym)
4105*404b540aSrobert 		       && SYMBOL_REF_DECL (sym)
4106*404b540aSrobert 		       && (!DECL_P (SYMBOL_REF_DECL (sym))
4107*404b540aSrobert 			   || !DECL_COMMON (SYMBOL_REF_DECL (sym))))
4108*404b540aSrobert 		{
4109*404b540aSrobert 		  tree decl = SYMBOL_REF_DECL (sym);
4110*404b540aSrobert 		  tree init = TREE_CODE (decl) == VAR_DECL
4111*404b540aSrobert 		    ? DECL_INITIAL (decl)
4112*404b540aSrobert 		    : TREE_CODE (decl) == CONSTRUCTOR
4113*404b540aSrobert 		    ? decl : 0;
4114*404b540aSrobert 		  int reloc = 0;
4115*404b540aSrobert 		  bool named_section, readonly;
4116*404b540aSrobert 
4117*404b540aSrobert 		  if (init && init != error_mark_node)
4118*404b540aSrobert 		    reloc = compute_reloc_for_constant (init);
4119*404b540aSrobert 
4120*404b540aSrobert 		  named_section = TREE_CODE (decl) == VAR_DECL
4121*404b540aSrobert 		    && lookup_attribute ("section", DECL_ATTRIBUTES (decl));
4122*404b540aSrobert 		  readonly = decl_readonly_section (decl, reloc);
4123*404b540aSrobert 
4124*404b540aSrobert 		  if (named_section)
4125*404b540aSrobert 		    unspec = R_FRV_GOT12;
4126*404b540aSrobert 		  else if (!readonly)
4127*404b540aSrobert 		    unspec = R_FRV_GOTOFF12;
4128*404b540aSrobert 		  else if (readonly && TARGET_GPREL_RO)
4129*404b540aSrobert 		    unspec = R_FRV_GPREL12;
4130*404b540aSrobert 		  else
4131*404b540aSrobert 		    unspec = R_FRV_GOT12;
4132*404b540aSrobert 		}
4133*404b540aSrobert 	      else
4134*404b540aSrobert 		unspec = R_FRV_GOT12;
4135*404b540aSrobert 	    }
4136*404b540aSrobert 	}
4137*404b540aSrobert 
4138*404b540aSrobert       else if (SYMBOL_REF_SMALL_P (sym))
4139*404b540aSrobert 	base_regno = SDA_BASE_REG;
4140*404b540aSrobert 
4141*404b540aSrobert       else if (flag_pic)
4142*404b540aSrobert 	base_regno = PIC_REGNO;
4143*404b540aSrobert 
4144*404b540aSrobert       break;
4145*404b540aSrobert     }
4146*404b540aSrobert 
4147*404b540aSrobert   if (base_regno >= 0)
4148*404b540aSrobert     {
4149*404b540aSrobert       if (GET_CODE (sym) == SYMBOL_REF && SYMBOL_REF_SMALL_P (sym))
4150*404b540aSrobert 	emit_insn (gen_symGOTOFF2reg (dest, src,
4151*404b540aSrobert 				      gen_rtx_REG (Pmode, base_regno),
4152*404b540aSrobert 				      GEN_INT (R_FRV_GPREL12)));
4153*404b540aSrobert       else
4154*404b540aSrobert 	emit_insn (gen_symGOTOFF2reg_hilo (dest, src,
4155*404b540aSrobert 					   gen_rtx_REG (Pmode, base_regno),
4156*404b540aSrobert 					   GEN_INT (R_FRV_GPREL12)));
4157*404b540aSrobert       if (base_regno == PIC_REGNO)
4158*404b540aSrobert 	cfun->uses_pic_offset_table = TRUE;
4159*404b540aSrobert       return TRUE;
4160*404b540aSrobert     }
4161*404b540aSrobert 
4162*404b540aSrobert   if (unspec)
4163*404b540aSrobert     {
4164*404b540aSrobert       rtx x;
4165*404b540aSrobert 
4166*404b540aSrobert       /* Since OUR_FDPIC_REG is a pseudo register, we can't safely introduce
4167*404b540aSrobert 	 new uses of it once reload has begun.  */
4168*404b540aSrobert       gcc_assert (!reload_in_progress && !reload_completed);
4169*404b540aSrobert 
4170*404b540aSrobert       switch (unspec)
4171*404b540aSrobert 	{
4172*404b540aSrobert 	case R_FRV_GOTOFF12:
4173*404b540aSrobert 	  if (!frv_small_data_reloc_p (sym, unspec))
4174*404b540aSrobert 	    x = gen_symGOTOFF2reg_hilo (dest, src, OUR_FDPIC_REG,
4175*404b540aSrobert 					GEN_INT (unspec));
4176*404b540aSrobert 	  else
4177*404b540aSrobert 	    x = gen_symGOTOFF2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
4178*404b540aSrobert 	  break;
4179*404b540aSrobert 	case R_FRV_GPREL12:
4180*404b540aSrobert 	  if (!frv_small_data_reloc_p (sym, unspec))
4181*404b540aSrobert 	    x = gen_symGPREL2reg_hilo (dest, src, OUR_FDPIC_REG,
4182*404b540aSrobert 				       GEN_INT (unspec));
4183*404b540aSrobert 	  else
4184*404b540aSrobert 	    x = gen_symGPREL2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
4185*404b540aSrobert 	  break;
4186*404b540aSrobert 	case R_FRV_FUNCDESC_GOTOFF12:
4187*404b540aSrobert 	  if (flag_pic != 1)
4188*404b540aSrobert 	    x = gen_symGOTOFF2reg_hilo (dest, src, OUR_FDPIC_REG,
4189*404b540aSrobert 					GEN_INT (unspec));
4190*404b540aSrobert 	  else
4191*404b540aSrobert 	    x = gen_symGOTOFF2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
4192*404b540aSrobert 	  break;
4193*404b540aSrobert 	default:
4194*404b540aSrobert 	  if (flag_pic != 1)
4195*404b540aSrobert 	    x = gen_symGOT2reg_hilo (dest, src, OUR_FDPIC_REG,
4196*404b540aSrobert 				     GEN_INT (unspec));
4197*404b540aSrobert 	  else
4198*404b540aSrobert 	    x = gen_symGOT2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
4199*404b540aSrobert 	  break;
4200*404b540aSrobert 	}
4201*404b540aSrobert       emit_insn (x);
4202*404b540aSrobert       cfun->uses_pic_offset_table = TRUE;
4203*404b540aSrobert       return TRUE;
4204*404b540aSrobert     }
4205*404b540aSrobert 
4206*404b540aSrobert 
4207*404b540aSrobert   return FALSE;
4208*404b540aSrobert }
4209*404b540aSrobert 
4210*404b540aSrobert 
4211*404b540aSrobert /* Return a string to output a single word move.  */
4212*404b540aSrobert 
4213*404b540aSrobert const char *
output_move_single(rtx operands[],rtx insn)4214*404b540aSrobert output_move_single (rtx operands[], rtx insn)
4215*404b540aSrobert {
4216*404b540aSrobert   rtx dest = operands[0];
4217*404b540aSrobert   rtx src  = operands[1];
4218*404b540aSrobert 
4219*404b540aSrobert   if (GET_CODE (dest) == REG)
4220*404b540aSrobert     {
4221*404b540aSrobert       int dest_regno = REGNO (dest);
4222*404b540aSrobert       enum machine_mode mode = GET_MODE (dest);
4223*404b540aSrobert 
4224*404b540aSrobert       if (GPR_P (dest_regno))
4225*404b540aSrobert 	{
4226*404b540aSrobert 	  if (GET_CODE (src) == REG)
4227*404b540aSrobert 	    {
4228*404b540aSrobert 	      /* gpr <- some sort of register */
4229*404b540aSrobert 	      int src_regno = REGNO (src);
4230*404b540aSrobert 
4231*404b540aSrobert 	      if (GPR_P (src_regno))
4232*404b540aSrobert 		return "mov %1, %0";
4233*404b540aSrobert 
4234*404b540aSrobert 	      else if (FPR_P (src_regno))
4235*404b540aSrobert 		return "movfg %1, %0";
4236*404b540aSrobert 
4237*404b540aSrobert 	      else if (SPR_P (src_regno))
4238*404b540aSrobert 		return "movsg %1, %0";
4239*404b540aSrobert 	    }
4240*404b540aSrobert 
4241*404b540aSrobert 	  else if (GET_CODE (src) == MEM)
4242*404b540aSrobert 	    {
4243*404b540aSrobert 	      /* gpr <- memory */
4244*404b540aSrobert 	      switch (mode)
4245*404b540aSrobert 		{
4246*404b540aSrobert 		default:
4247*404b540aSrobert 		  break;
4248*404b540aSrobert 
4249*404b540aSrobert 		case QImode:
4250*404b540aSrobert 		  return "ldsb%I1%U1 %M1,%0";
4251*404b540aSrobert 
4252*404b540aSrobert 		case HImode:
4253*404b540aSrobert 		  return "ldsh%I1%U1 %M1,%0";
4254*404b540aSrobert 
4255*404b540aSrobert 		case SImode:
4256*404b540aSrobert 		case SFmode:
4257*404b540aSrobert 		  return "ld%I1%U1 %M1, %0";
4258*404b540aSrobert 		}
4259*404b540aSrobert 	    }
4260*404b540aSrobert 
4261*404b540aSrobert 	  else if (GET_CODE (src) == CONST_INT
4262*404b540aSrobert 		   || GET_CODE (src) == CONST_DOUBLE)
4263*404b540aSrobert 	    {
4264*404b540aSrobert 	      /* gpr <- integer/floating constant */
4265*404b540aSrobert 	      HOST_WIDE_INT value;
4266*404b540aSrobert 
4267*404b540aSrobert 	      if (GET_CODE (src) == CONST_INT)
4268*404b540aSrobert 		value = INTVAL (src);
4269*404b540aSrobert 
4270*404b540aSrobert 	      else if (mode == SFmode)
4271*404b540aSrobert 		{
4272*404b540aSrobert 		  REAL_VALUE_TYPE rv;
4273*404b540aSrobert 		  long l;
4274*404b540aSrobert 
4275*404b540aSrobert 		  REAL_VALUE_FROM_CONST_DOUBLE (rv, src);
4276*404b540aSrobert 		  REAL_VALUE_TO_TARGET_SINGLE (rv, l);
4277*404b540aSrobert 		  value = l;
4278*404b540aSrobert 		}
4279*404b540aSrobert 
4280*404b540aSrobert 	      else
4281*404b540aSrobert 		value = CONST_DOUBLE_LOW (src);
4282*404b540aSrobert 
4283*404b540aSrobert 	      if (IN_RANGE_P (value, -32768, 32767))
4284*404b540aSrobert 		return "setlos %1, %0";
4285*404b540aSrobert 
4286*404b540aSrobert 	      return "#";
4287*404b540aSrobert 	    }
4288*404b540aSrobert 
4289*404b540aSrobert           else if (GET_CODE (src) == SYMBOL_REF
4290*404b540aSrobert 		   || GET_CODE (src) == LABEL_REF
4291*404b540aSrobert 		   || GET_CODE (src) == CONST)
4292*404b540aSrobert 	    {
4293*404b540aSrobert 	      return "#";
4294*404b540aSrobert 	    }
4295*404b540aSrobert 	}
4296*404b540aSrobert 
4297*404b540aSrobert       else if (FPR_P (dest_regno))
4298*404b540aSrobert 	{
4299*404b540aSrobert 	  if (GET_CODE (src) == REG)
4300*404b540aSrobert 	    {
4301*404b540aSrobert 	      /* fpr <- some sort of register */
4302*404b540aSrobert 	      int src_regno = REGNO (src);
4303*404b540aSrobert 
4304*404b540aSrobert 	      if (GPR_P (src_regno))
4305*404b540aSrobert 		return "movgf %1, %0";
4306*404b540aSrobert 
4307*404b540aSrobert 	      else if (FPR_P (src_regno))
4308*404b540aSrobert 		{
4309*404b540aSrobert 		  if (TARGET_HARD_FLOAT)
4310*404b540aSrobert 		    return "fmovs %1, %0";
4311*404b540aSrobert 		  else
4312*404b540aSrobert 		    return "mor %1, %1, %0";
4313*404b540aSrobert 		}
4314*404b540aSrobert 	    }
4315*404b540aSrobert 
4316*404b540aSrobert 	  else if (GET_CODE (src) == MEM)
4317*404b540aSrobert 	    {
4318*404b540aSrobert 	      /* fpr <- memory */
4319*404b540aSrobert 	      switch (mode)
4320*404b540aSrobert 		{
4321*404b540aSrobert 		default:
4322*404b540aSrobert 		  break;
4323*404b540aSrobert 
4324*404b540aSrobert 		case QImode:
4325*404b540aSrobert 		  return "ldbf%I1%U1 %M1,%0";
4326*404b540aSrobert 
4327*404b540aSrobert 		case HImode:
4328*404b540aSrobert 		  return "ldhf%I1%U1 %M1,%0";
4329*404b540aSrobert 
4330*404b540aSrobert 		case SImode:
4331*404b540aSrobert 		case SFmode:
4332*404b540aSrobert 		  return "ldf%I1%U1 %M1, %0";
4333*404b540aSrobert 		}
4334*404b540aSrobert 	    }
4335*404b540aSrobert 
4336*404b540aSrobert 	  else if (ZERO_P (src))
4337*404b540aSrobert 	    return "movgf %., %0";
4338*404b540aSrobert 	}
4339*404b540aSrobert 
4340*404b540aSrobert       else if (SPR_P (dest_regno))
4341*404b540aSrobert 	{
4342*404b540aSrobert 	  if (GET_CODE (src) == REG)
4343*404b540aSrobert 	    {
4344*404b540aSrobert 	      /* spr <- some sort of register */
4345*404b540aSrobert 	      int src_regno = REGNO (src);
4346*404b540aSrobert 
4347*404b540aSrobert 	      if (GPR_P (src_regno))
4348*404b540aSrobert 		return "movgs %1, %0";
4349*404b540aSrobert 	    }
4350*404b540aSrobert 	  else if (ZERO_P (src))
4351*404b540aSrobert 	    return "movgs %., %0";
4352*404b540aSrobert 	}
4353*404b540aSrobert     }
4354*404b540aSrobert 
4355*404b540aSrobert   else if (GET_CODE (dest) == MEM)
4356*404b540aSrobert     {
4357*404b540aSrobert       if (GET_CODE (src) == REG)
4358*404b540aSrobert 	{
4359*404b540aSrobert 	  int src_regno = REGNO (src);
4360*404b540aSrobert 	  enum machine_mode mode = GET_MODE (dest);
4361*404b540aSrobert 
4362*404b540aSrobert 	  if (GPR_P (src_regno))
4363*404b540aSrobert 	    {
4364*404b540aSrobert 	      switch (mode)
4365*404b540aSrobert 		{
4366*404b540aSrobert 		default:
4367*404b540aSrobert 		  break;
4368*404b540aSrobert 
4369*404b540aSrobert 		case QImode:
4370*404b540aSrobert 		  return "stb%I0%U0 %1, %M0";
4371*404b540aSrobert 
4372*404b540aSrobert 		case HImode:
4373*404b540aSrobert 		  return "sth%I0%U0 %1, %M0";
4374*404b540aSrobert 
4375*404b540aSrobert 		case SImode:
4376*404b540aSrobert 		case SFmode:
4377*404b540aSrobert 		  return "st%I0%U0 %1, %M0";
4378*404b540aSrobert 		}
4379*404b540aSrobert 	    }
4380*404b540aSrobert 
4381*404b540aSrobert 	  else if (FPR_P (src_regno))
4382*404b540aSrobert 	    {
4383*404b540aSrobert 	      switch (mode)
4384*404b540aSrobert 		{
4385*404b540aSrobert 		default:
4386*404b540aSrobert 		  break;
4387*404b540aSrobert 
4388*404b540aSrobert 		case QImode:
4389*404b540aSrobert 		  return "stbf%I0%U0 %1, %M0";
4390*404b540aSrobert 
4391*404b540aSrobert 		case HImode:
4392*404b540aSrobert 		  return "sthf%I0%U0 %1, %M0";
4393*404b540aSrobert 
4394*404b540aSrobert 		case SImode:
4395*404b540aSrobert 		case SFmode:
4396*404b540aSrobert 		  return "stf%I0%U0 %1, %M0";
4397*404b540aSrobert 		}
4398*404b540aSrobert 	    }
4399*404b540aSrobert 	}
4400*404b540aSrobert 
4401*404b540aSrobert       else if (ZERO_P (src))
4402*404b540aSrobert 	{
4403*404b540aSrobert 	  switch (GET_MODE (dest))
4404*404b540aSrobert 	    {
4405*404b540aSrobert 	    default:
4406*404b540aSrobert 	      break;
4407*404b540aSrobert 
4408*404b540aSrobert 	    case QImode:
4409*404b540aSrobert 	      return "stb%I0%U0 %., %M0";
4410*404b540aSrobert 
4411*404b540aSrobert 	    case HImode:
4412*404b540aSrobert 	      return "sth%I0%U0 %., %M0";
4413*404b540aSrobert 
4414*404b540aSrobert 	    case SImode:
4415*404b540aSrobert 	    case SFmode:
4416*404b540aSrobert 	      return "st%I0%U0 %., %M0";
4417*404b540aSrobert 	    }
4418*404b540aSrobert 	}
4419*404b540aSrobert     }
4420*404b540aSrobert 
4421*404b540aSrobert   fatal_insn ("bad output_move_single operand", insn);
4422*404b540aSrobert   return "";
4423*404b540aSrobert }
4424*404b540aSrobert 
4425*404b540aSrobert 
4426*404b540aSrobert /* Return a string to output a double word move.  */
4427*404b540aSrobert 
4428*404b540aSrobert const char *
output_move_double(rtx operands[],rtx insn)4429*404b540aSrobert output_move_double (rtx operands[], rtx insn)
4430*404b540aSrobert {
4431*404b540aSrobert   rtx dest = operands[0];
4432*404b540aSrobert   rtx src  = operands[1];
4433*404b540aSrobert   enum machine_mode mode = GET_MODE (dest);
4434*404b540aSrobert 
4435*404b540aSrobert   if (GET_CODE (dest) == REG)
4436*404b540aSrobert     {
4437*404b540aSrobert       int dest_regno = REGNO (dest);
4438*404b540aSrobert 
4439*404b540aSrobert       if (GPR_P (dest_regno))
4440*404b540aSrobert 	{
4441*404b540aSrobert 	  if (GET_CODE (src) == REG)
4442*404b540aSrobert 	    {
4443*404b540aSrobert 	      /* gpr <- some sort of register */
4444*404b540aSrobert 	      int src_regno = REGNO (src);
4445*404b540aSrobert 
4446*404b540aSrobert 	      if (GPR_P (src_regno))
4447*404b540aSrobert 		return "#";
4448*404b540aSrobert 
4449*404b540aSrobert 	      else if (FPR_P (src_regno))
4450*404b540aSrobert 		{
4451*404b540aSrobert 		  if (((dest_regno - GPR_FIRST) & 1) == 0
4452*404b540aSrobert 		      && ((src_regno - FPR_FIRST) & 1) == 0)
4453*404b540aSrobert 		    return "movfgd %1, %0";
4454*404b540aSrobert 
4455*404b540aSrobert 		  return "#";
4456*404b540aSrobert 		}
4457*404b540aSrobert 	    }
4458*404b540aSrobert 
4459*404b540aSrobert 	  else if (GET_CODE (src) == MEM)
4460*404b540aSrobert 	    {
4461*404b540aSrobert 	      /* gpr <- memory */
4462*404b540aSrobert 	      if (dbl_memory_one_insn_operand (src, mode))
4463*404b540aSrobert 		return "ldd%I1%U1 %M1, %0";
4464*404b540aSrobert 
4465*404b540aSrobert 	      return "#";
4466*404b540aSrobert 	    }
4467*404b540aSrobert 
4468*404b540aSrobert 	  else if (GET_CODE (src) == CONST_INT
4469*404b540aSrobert 		   || GET_CODE (src) == CONST_DOUBLE)
4470*404b540aSrobert 	    return "#";
4471*404b540aSrobert 	}
4472*404b540aSrobert 
4473*404b540aSrobert       else if (FPR_P (dest_regno))
4474*404b540aSrobert 	{
4475*404b540aSrobert 	  if (GET_CODE (src) == REG)
4476*404b540aSrobert 	    {
4477*404b540aSrobert 	      /* fpr <- some sort of register */
4478*404b540aSrobert 	      int src_regno = REGNO (src);
4479*404b540aSrobert 
4480*404b540aSrobert 	      if (GPR_P (src_regno))
4481*404b540aSrobert 		{
4482*404b540aSrobert 		  if (((dest_regno - FPR_FIRST) & 1) == 0
4483*404b540aSrobert 		      && ((src_regno - GPR_FIRST) & 1) == 0)
4484*404b540aSrobert 		    return "movgfd %1, %0";
4485*404b540aSrobert 
4486*404b540aSrobert 		  return "#";
4487*404b540aSrobert 		}
4488*404b540aSrobert 
4489*404b540aSrobert 	      else if (FPR_P (src_regno))
4490*404b540aSrobert 		{
4491*404b540aSrobert 		  if (TARGET_DOUBLE
4492*404b540aSrobert 		      && ((dest_regno - FPR_FIRST) & 1) == 0
4493*404b540aSrobert 		      && ((src_regno - FPR_FIRST) & 1) == 0)
4494*404b540aSrobert 		    return "fmovd %1, %0";
4495*404b540aSrobert 
4496*404b540aSrobert 		  return "#";
4497*404b540aSrobert 		}
4498*404b540aSrobert 	    }
4499*404b540aSrobert 
4500*404b540aSrobert 	  else if (GET_CODE (src) == MEM)
4501*404b540aSrobert 	    {
4502*404b540aSrobert 	      /* fpr <- memory */
4503*404b540aSrobert 	      if (dbl_memory_one_insn_operand (src, mode))
4504*404b540aSrobert 		return "lddf%I1%U1 %M1, %0";
4505*404b540aSrobert 
4506*404b540aSrobert 	      return "#";
4507*404b540aSrobert 	    }
4508*404b540aSrobert 
4509*404b540aSrobert 	  else if (ZERO_P (src))
4510*404b540aSrobert 	    return "#";
4511*404b540aSrobert 	}
4512*404b540aSrobert     }
4513*404b540aSrobert 
4514*404b540aSrobert   else if (GET_CODE (dest) == MEM)
4515*404b540aSrobert     {
4516*404b540aSrobert       if (GET_CODE (src) == REG)
4517*404b540aSrobert 	{
4518*404b540aSrobert 	  int src_regno = REGNO (src);
4519*404b540aSrobert 
4520*404b540aSrobert 	  if (GPR_P (src_regno))
4521*404b540aSrobert 	    {
4522*404b540aSrobert 	      if (((src_regno - GPR_FIRST) & 1) == 0
4523*404b540aSrobert 		  && dbl_memory_one_insn_operand (dest, mode))
4524*404b540aSrobert 		return "std%I0%U0 %1, %M0";
4525*404b540aSrobert 
4526*404b540aSrobert 	      return "#";
4527*404b540aSrobert 	    }
4528*404b540aSrobert 
4529*404b540aSrobert 	  if (FPR_P (src_regno))
4530*404b540aSrobert 	    {
4531*404b540aSrobert 	      if (((src_regno - FPR_FIRST) & 1) == 0
4532*404b540aSrobert 		  && dbl_memory_one_insn_operand (dest, mode))
4533*404b540aSrobert 		return "stdf%I0%U0 %1, %M0";
4534*404b540aSrobert 
4535*404b540aSrobert 	      return "#";
4536*404b540aSrobert 	    }
4537*404b540aSrobert 	}
4538*404b540aSrobert 
4539*404b540aSrobert       else if (ZERO_P (src))
4540*404b540aSrobert 	{
4541*404b540aSrobert 	  if (dbl_memory_one_insn_operand (dest, mode))
4542*404b540aSrobert 	    return "std%I0%U0 %., %M0";
4543*404b540aSrobert 
4544*404b540aSrobert 	  return "#";
4545*404b540aSrobert 	}
4546*404b540aSrobert     }
4547*404b540aSrobert 
4548*404b540aSrobert   fatal_insn ("bad output_move_double operand", insn);
4549*404b540aSrobert   return "";
4550*404b540aSrobert }
4551*404b540aSrobert 
4552*404b540aSrobert 
4553*404b540aSrobert /* Return a string to output a single word conditional move.
4554*404b540aSrobert    Operand0 -- EQ/NE of ccr register and 0
4555*404b540aSrobert    Operand1 -- CCR register
4556*404b540aSrobert    Operand2 -- destination
4557*404b540aSrobert    Operand3 -- source  */
4558*404b540aSrobert 
4559*404b540aSrobert const char *
output_condmove_single(rtx operands[],rtx insn)4560*404b540aSrobert output_condmove_single (rtx operands[], rtx insn)
4561*404b540aSrobert {
4562*404b540aSrobert   rtx dest = operands[2];
4563*404b540aSrobert   rtx src  = operands[3];
4564*404b540aSrobert 
4565*404b540aSrobert   if (GET_CODE (dest) == REG)
4566*404b540aSrobert     {
4567*404b540aSrobert       int dest_regno = REGNO (dest);
4568*404b540aSrobert       enum machine_mode mode = GET_MODE (dest);
4569*404b540aSrobert 
4570*404b540aSrobert       if (GPR_P (dest_regno))
4571*404b540aSrobert 	{
4572*404b540aSrobert 	  if (GET_CODE (src) == REG)
4573*404b540aSrobert 	    {
4574*404b540aSrobert 	      /* gpr <- some sort of register */
4575*404b540aSrobert 	      int src_regno = REGNO (src);
4576*404b540aSrobert 
4577*404b540aSrobert 	      if (GPR_P (src_regno))
4578*404b540aSrobert 		return "cmov %z3, %2, %1, %e0";
4579*404b540aSrobert 
4580*404b540aSrobert 	      else if (FPR_P (src_regno))
4581*404b540aSrobert 		return "cmovfg %3, %2, %1, %e0";
4582*404b540aSrobert 	    }
4583*404b540aSrobert 
4584*404b540aSrobert 	  else if (GET_CODE (src) == MEM)
4585*404b540aSrobert 	    {
4586*404b540aSrobert 	      /* gpr <- memory */
4587*404b540aSrobert 	      switch (mode)
4588*404b540aSrobert 		{
4589*404b540aSrobert 		default:
4590*404b540aSrobert 		  break;
4591*404b540aSrobert 
4592*404b540aSrobert 		case QImode:
4593*404b540aSrobert 		  return "cldsb%I3%U3 %M3, %2, %1, %e0";
4594*404b540aSrobert 
4595*404b540aSrobert 		case HImode:
4596*404b540aSrobert 		  return "cldsh%I3%U3 %M3, %2, %1, %e0";
4597*404b540aSrobert 
4598*404b540aSrobert 		case SImode:
4599*404b540aSrobert 		case SFmode:
4600*404b540aSrobert 		  return "cld%I3%U3 %M3, %2, %1, %e0";
4601*404b540aSrobert 		}
4602*404b540aSrobert 	    }
4603*404b540aSrobert 
4604*404b540aSrobert 	  else if (ZERO_P (src))
4605*404b540aSrobert 	    return "cmov %., %2, %1, %e0";
4606*404b540aSrobert 	}
4607*404b540aSrobert 
4608*404b540aSrobert       else if (FPR_P (dest_regno))
4609*404b540aSrobert 	{
4610*404b540aSrobert 	  if (GET_CODE (src) == REG)
4611*404b540aSrobert 	    {
4612*404b540aSrobert 	      /* fpr <- some sort of register */
4613*404b540aSrobert 	      int src_regno = REGNO (src);
4614*404b540aSrobert 
4615*404b540aSrobert 	      if (GPR_P (src_regno))
4616*404b540aSrobert 		return "cmovgf %3, %2, %1, %e0";
4617*404b540aSrobert 
4618*404b540aSrobert 	      else if (FPR_P (src_regno))
4619*404b540aSrobert 		{
4620*404b540aSrobert 		  if (TARGET_HARD_FLOAT)
4621*404b540aSrobert 		    return "cfmovs %3,%2,%1,%e0";
4622*404b540aSrobert 		  else
4623*404b540aSrobert 		    return "cmor %3, %3, %2, %1, %e0";
4624*404b540aSrobert 		}
4625*404b540aSrobert 	    }
4626*404b540aSrobert 
4627*404b540aSrobert 	  else if (GET_CODE (src) == MEM)
4628*404b540aSrobert 	    {
4629*404b540aSrobert 	      /* fpr <- memory */
4630*404b540aSrobert 	      if (mode == SImode || mode == SFmode)
4631*404b540aSrobert 		return "cldf%I3%U3 %M3, %2, %1, %e0";
4632*404b540aSrobert 	    }
4633*404b540aSrobert 
4634*404b540aSrobert 	  else if (ZERO_P (src))
4635*404b540aSrobert 	    return "cmovgf %., %2, %1, %e0";
4636*404b540aSrobert 	}
4637*404b540aSrobert     }
4638*404b540aSrobert 
4639*404b540aSrobert   else if (GET_CODE (dest) == MEM)
4640*404b540aSrobert     {
4641*404b540aSrobert       if (GET_CODE (src) == REG)
4642*404b540aSrobert 	{
4643*404b540aSrobert 	  int src_regno = REGNO (src);
4644*404b540aSrobert 	  enum machine_mode mode = GET_MODE (dest);
4645*404b540aSrobert 
4646*404b540aSrobert 	  if (GPR_P (src_regno))
4647*404b540aSrobert 	    {
4648*404b540aSrobert 	      switch (mode)
4649*404b540aSrobert 		{
4650*404b540aSrobert 		default:
4651*404b540aSrobert 		  break;
4652*404b540aSrobert 
4653*404b540aSrobert 		case QImode:
4654*404b540aSrobert 		  return "cstb%I2%U2 %3, %M2, %1, %e0";
4655*404b540aSrobert 
4656*404b540aSrobert 		case HImode:
4657*404b540aSrobert 		  return "csth%I2%U2 %3, %M2, %1, %e0";
4658*404b540aSrobert 
4659*404b540aSrobert 		case SImode:
4660*404b540aSrobert 		case SFmode:
4661*404b540aSrobert 		  return "cst%I2%U2 %3, %M2, %1, %e0";
4662*404b540aSrobert 		}
4663*404b540aSrobert 	    }
4664*404b540aSrobert 
4665*404b540aSrobert 	  else if (FPR_P (src_regno) && (mode == SImode || mode == SFmode))
4666*404b540aSrobert 	    return "cstf%I2%U2 %3, %M2, %1, %e0";
4667*404b540aSrobert 	}
4668*404b540aSrobert 
4669*404b540aSrobert       else if (ZERO_P (src))
4670*404b540aSrobert 	{
4671*404b540aSrobert 	  enum machine_mode mode = GET_MODE (dest);
4672*404b540aSrobert 	  switch (mode)
4673*404b540aSrobert 	    {
4674*404b540aSrobert 	    default:
4675*404b540aSrobert 	      break;
4676*404b540aSrobert 
4677*404b540aSrobert 	    case QImode:
4678*404b540aSrobert 	      return "cstb%I2%U2 %., %M2, %1, %e0";
4679*404b540aSrobert 
4680*404b540aSrobert 	    case HImode:
4681*404b540aSrobert 	      return "csth%I2%U2 %., %M2, %1, %e0";
4682*404b540aSrobert 
4683*404b540aSrobert 	    case SImode:
4684*404b540aSrobert 	    case SFmode:
4685*404b540aSrobert 	      return "cst%I2%U2 %., %M2, %1, %e0";
4686*404b540aSrobert 	    }
4687*404b540aSrobert 	}
4688*404b540aSrobert     }
4689*404b540aSrobert 
4690*404b540aSrobert   fatal_insn ("bad output_condmove_single operand", insn);
4691*404b540aSrobert   return "";
4692*404b540aSrobert }
4693*404b540aSrobert 
4694*404b540aSrobert 
4695*404b540aSrobert /* Emit the appropriate code to do a comparison, returning the register the
4696*404b540aSrobert    comparison was done it.  */
4697*404b540aSrobert 
4698*404b540aSrobert static rtx
frv_emit_comparison(enum rtx_code test,rtx op0,rtx op1)4699*404b540aSrobert frv_emit_comparison (enum rtx_code test, rtx op0, rtx op1)
4700*404b540aSrobert {
4701*404b540aSrobert   enum machine_mode cc_mode;
4702*404b540aSrobert   rtx cc_reg;
4703*404b540aSrobert 
4704*404b540aSrobert   /* Floating point doesn't have comparison against a constant.  */
4705*404b540aSrobert   if (GET_MODE (op0) == CC_FPmode && GET_CODE (op1) != REG)
4706*404b540aSrobert     op1 = force_reg (GET_MODE (op0), op1);
4707*404b540aSrobert 
4708*404b540aSrobert   /* Possibly disable using anything but a fixed register in order to work
4709*404b540aSrobert      around cse moving comparisons past function calls.  */
4710*404b540aSrobert   cc_mode = SELECT_CC_MODE (test, op0, op1);
4711*404b540aSrobert   cc_reg = ((TARGET_ALLOC_CC)
4712*404b540aSrobert 	    ? gen_reg_rtx (cc_mode)
4713*404b540aSrobert 	    : gen_rtx_REG (cc_mode,
4714*404b540aSrobert 			   (cc_mode == CC_FPmode) ? FCC_FIRST : ICC_FIRST));
4715*404b540aSrobert 
4716*404b540aSrobert   emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
4717*404b540aSrobert 			  gen_rtx_COMPARE (cc_mode, op0, op1)));
4718*404b540aSrobert 
4719*404b540aSrobert   return cc_reg;
4720*404b540aSrobert }
4721*404b540aSrobert 
4722*404b540aSrobert 
4723*404b540aSrobert /* Emit code for a conditional branch.  The comparison operands were previously
4724*404b540aSrobert    stored in frv_compare_op0 and frv_compare_op1.
4725*404b540aSrobert 
4726*404b540aSrobert    XXX: I originally wanted to add a clobber of a CCR register to use in
4727*404b540aSrobert    conditional execution, but that confuses the rest of the compiler.  */
4728*404b540aSrobert 
4729*404b540aSrobert int
frv_emit_cond_branch(enum rtx_code test,rtx label)4730*404b540aSrobert frv_emit_cond_branch (enum rtx_code test, rtx label)
4731*404b540aSrobert {
4732*404b540aSrobert   rtx test_rtx;
4733*404b540aSrobert   rtx label_ref;
4734*404b540aSrobert   rtx if_else;
4735*404b540aSrobert   rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1);
4736*404b540aSrobert   enum machine_mode cc_mode = GET_MODE (cc_reg);
4737*404b540aSrobert 
4738*404b540aSrobert   /* Branches generate:
4739*404b540aSrobert 	(set (pc)
4740*404b540aSrobert 	     (if_then_else (<test>, <cc_reg>, (const_int 0))
4741*404b540aSrobert 			    (label_ref <branch_label>)
4742*404b540aSrobert 			    (pc))) */
4743*404b540aSrobert   label_ref = gen_rtx_LABEL_REF (VOIDmode, label);
4744*404b540aSrobert   test_rtx = gen_rtx_fmt_ee (test, cc_mode, cc_reg, const0_rtx);
4745*404b540aSrobert   if_else = gen_rtx_IF_THEN_ELSE (cc_mode, test_rtx, label_ref, pc_rtx);
4746*404b540aSrobert   emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, if_else));
4747*404b540aSrobert   return TRUE;
4748*404b540aSrobert }
4749*404b540aSrobert 
4750*404b540aSrobert 
4751*404b540aSrobert /* Emit code to set a gpr to 1/0 based on a comparison.  The comparison
4752*404b540aSrobert    operands were previously stored in frv_compare_op0 and frv_compare_op1.  */
4753*404b540aSrobert 
4754*404b540aSrobert int
frv_emit_scc(enum rtx_code test,rtx target)4755*404b540aSrobert frv_emit_scc (enum rtx_code test, rtx target)
4756*404b540aSrobert {
4757*404b540aSrobert   rtx set;
4758*404b540aSrobert   rtx test_rtx;
4759*404b540aSrobert   rtx clobber;
4760*404b540aSrobert   rtx cr_reg;
4761*404b540aSrobert   rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1);
4762*404b540aSrobert 
4763*404b540aSrobert   /* SCC instructions generate:
4764*404b540aSrobert 	(parallel [(set <target> (<test>, <cc_reg>, (const_int 0))
4765*404b540aSrobert 		   (clobber (<ccr_reg>))])  */
4766*404b540aSrobert   test_rtx = gen_rtx_fmt_ee (test, SImode, cc_reg, const0_rtx);
4767*404b540aSrobert   set = gen_rtx_SET (VOIDmode, target, test_rtx);
4768*404b540aSrobert 
4769*404b540aSrobert   cr_reg = ((TARGET_ALLOC_CC)
4770*404b540aSrobert 	    ? gen_reg_rtx (CC_CCRmode)
4771*404b540aSrobert 	    : gen_rtx_REG (CC_CCRmode,
4772*404b540aSrobert 			   ((GET_MODE (cc_reg) == CC_FPmode)
4773*404b540aSrobert 			    ? FCR_FIRST
4774*404b540aSrobert 			    : ICR_FIRST)));
4775*404b540aSrobert 
4776*404b540aSrobert   clobber = gen_rtx_CLOBBER (VOIDmode, cr_reg);
4777*404b540aSrobert   emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
4778*404b540aSrobert   return TRUE;
4779*404b540aSrobert }
4780*404b540aSrobert 
4781*404b540aSrobert 
4782*404b540aSrobert /* Split a SCC instruction into component parts, returning a SEQUENCE to hold
4783*404b540aSrobert    the separate insns.  */
4784*404b540aSrobert 
4785*404b540aSrobert rtx
frv_split_scc(rtx dest,rtx test,rtx cc_reg,rtx cr_reg,HOST_WIDE_INT value)4786*404b540aSrobert frv_split_scc (rtx dest, rtx test, rtx cc_reg, rtx cr_reg, HOST_WIDE_INT value)
4787*404b540aSrobert {
4788*404b540aSrobert   rtx ret;
4789*404b540aSrobert 
4790*404b540aSrobert   start_sequence ();
4791*404b540aSrobert 
4792*404b540aSrobert   /* Set the appropriate CCR bit.  */
4793*404b540aSrobert   emit_insn (gen_rtx_SET (VOIDmode,
4794*404b540aSrobert 			  cr_reg,
4795*404b540aSrobert 			  gen_rtx_fmt_ee (GET_CODE (test),
4796*404b540aSrobert 					  GET_MODE (cr_reg),
4797*404b540aSrobert 					  cc_reg,
4798*404b540aSrobert 					  const0_rtx)));
4799*404b540aSrobert 
4800*404b540aSrobert   /* Move the value into the destination.  */
4801*404b540aSrobert   emit_move_insn (dest, GEN_INT (value));
4802*404b540aSrobert 
4803*404b540aSrobert   /* Move 0 into the destination if the test failed */
4804*404b540aSrobert   emit_insn (gen_rtx_COND_EXEC (VOIDmode,
4805*404b540aSrobert 				gen_rtx_EQ (GET_MODE (cr_reg),
4806*404b540aSrobert 					    cr_reg,
4807*404b540aSrobert 					    const0_rtx),
4808*404b540aSrobert 				gen_rtx_SET (VOIDmode, dest, const0_rtx)));
4809*404b540aSrobert 
4810*404b540aSrobert   /* Finish up, return sequence.  */
4811*404b540aSrobert   ret = get_insns ();
4812*404b540aSrobert   end_sequence ();
4813*404b540aSrobert   return ret;
4814*404b540aSrobert }
4815*404b540aSrobert 
4816*404b540aSrobert 
4817*404b540aSrobert /* Emit the code for a conditional move, return TRUE if we could do the
4818*404b540aSrobert    move.  */
4819*404b540aSrobert 
4820*404b540aSrobert int
frv_emit_cond_move(rtx dest,rtx test_rtx,rtx src1,rtx src2)4821*404b540aSrobert frv_emit_cond_move (rtx dest, rtx test_rtx, rtx src1, rtx src2)
4822*404b540aSrobert {
4823*404b540aSrobert   rtx set;
4824*404b540aSrobert   rtx clobber_cc;
4825*404b540aSrobert   rtx test2;
4826*404b540aSrobert   rtx cr_reg;
4827*404b540aSrobert   rtx if_rtx;
4828*404b540aSrobert   enum rtx_code test = GET_CODE (test_rtx);
4829*404b540aSrobert   rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1);
4830*404b540aSrobert   enum machine_mode cc_mode = GET_MODE (cc_reg);
4831*404b540aSrobert 
4832*404b540aSrobert   /* Conditional move instructions generate:
4833*404b540aSrobert 	(parallel [(set <target>
4834*404b540aSrobert 			(if_then_else (<test> <cc_reg> (const_int 0))
4835*404b540aSrobert 				      <src1>
4836*404b540aSrobert 				      <src2>))
4837*404b540aSrobert 		   (clobber (<ccr_reg>))])  */
4838*404b540aSrobert 
4839*404b540aSrobert   /* Handle various cases of conditional move involving two constants.  */
4840*404b540aSrobert   if (GET_CODE (src1) == CONST_INT && GET_CODE (src2) == CONST_INT)
4841*404b540aSrobert     {
4842*404b540aSrobert       HOST_WIDE_INT value1 = INTVAL (src1);
4843*404b540aSrobert       HOST_WIDE_INT value2 = INTVAL (src2);
4844*404b540aSrobert 
4845*404b540aSrobert       /* Having 0 as one of the constants can be done by loading the other
4846*404b540aSrobert          constant, and optionally moving in gr0.  */
4847*404b540aSrobert       if (value1 == 0 || value2 == 0)
4848*404b540aSrobert 	;
4849*404b540aSrobert 
4850*404b540aSrobert       /* If the first value is within an addi range and also the difference
4851*404b540aSrobert          between the two fits in an addi's range, load up the difference, then
4852*404b540aSrobert          conditionally move in 0, and then unconditionally add the first
4853*404b540aSrobert 	 value.  */
4854*404b540aSrobert       else if (IN_RANGE_P (value1, -2048, 2047)
4855*404b540aSrobert 	       && IN_RANGE_P (value2 - value1, -2048, 2047))
4856*404b540aSrobert 	;
4857*404b540aSrobert 
4858*404b540aSrobert       /* If neither condition holds, just force the constant into a
4859*404b540aSrobert 	 register.  */
4860*404b540aSrobert       else
4861*404b540aSrobert 	{
4862*404b540aSrobert 	  src1 = force_reg (GET_MODE (dest), src1);
4863*404b540aSrobert 	  src2 = force_reg (GET_MODE (dest), src2);
4864*404b540aSrobert 	}
4865*404b540aSrobert     }
4866*404b540aSrobert 
4867*404b540aSrobert   /* If one value is a register, insure the other value is either 0 or a
4868*404b540aSrobert      register.  */
4869*404b540aSrobert   else
4870*404b540aSrobert     {
4871*404b540aSrobert       if (GET_CODE (src1) == CONST_INT && INTVAL (src1) != 0)
4872*404b540aSrobert 	src1 = force_reg (GET_MODE (dest), src1);
4873*404b540aSrobert 
4874*404b540aSrobert       if (GET_CODE (src2) == CONST_INT && INTVAL (src2) != 0)
4875*404b540aSrobert 	src2 = force_reg (GET_MODE (dest), src2);
4876*404b540aSrobert     }
4877*404b540aSrobert 
4878*404b540aSrobert   test2 = gen_rtx_fmt_ee (test, cc_mode, cc_reg, const0_rtx);
4879*404b540aSrobert   if_rtx = gen_rtx_IF_THEN_ELSE (GET_MODE (dest), test2, src1, src2);
4880*404b540aSrobert 
4881*404b540aSrobert   set = gen_rtx_SET (VOIDmode, dest, if_rtx);
4882*404b540aSrobert 
4883*404b540aSrobert   cr_reg = ((TARGET_ALLOC_CC)
4884*404b540aSrobert 	    ? gen_reg_rtx (CC_CCRmode)
4885*404b540aSrobert 	    : gen_rtx_REG (CC_CCRmode,
4886*404b540aSrobert 			   (cc_mode == CC_FPmode) ? FCR_FIRST : ICR_FIRST));
4887*404b540aSrobert 
4888*404b540aSrobert   clobber_cc = gen_rtx_CLOBBER (VOIDmode, cr_reg);
4889*404b540aSrobert   emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber_cc)));
4890*404b540aSrobert   return TRUE;
4891*404b540aSrobert }
4892*404b540aSrobert 
4893*404b540aSrobert 
4894*404b540aSrobert /* Split a conditional move into constituent parts, returning a SEQUENCE
4895*404b540aSrobert    containing all of the insns.  */
4896*404b540aSrobert 
4897*404b540aSrobert rtx
frv_split_cond_move(rtx operands[])4898*404b540aSrobert frv_split_cond_move (rtx operands[])
4899*404b540aSrobert {
4900*404b540aSrobert   rtx dest	= operands[0];
4901*404b540aSrobert   rtx test	= operands[1];
4902*404b540aSrobert   rtx cc_reg	= operands[2];
4903*404b540aSrobert   rtx src1	= operands[3];
4904*404b540aSrobert   rtx src2	= operands[4];
4905*404b540aSrobert   rtx cr_reg	= operands[5];
4906*404b540aSrobert   rtx ret;
4907*404b540aSrobert   enum machine_mode cr_mode = GET_MODE (cr_reg);
4908*404b540aSrobert 
4909*404b540aSrobert   start_sequence ();
4910*404b540aSrobert 
4911*404b540aSrobert   /* Set the appropriate CCR bit.  */
4912*404b540aSrobert   emit_insn (gen_rtx_SET (VOIDmode,
4913*404b540aSrobert 			  cr_reg,
4914*404b540aSrobert 			  gen_rtx_fmt_ee (GET_CODE (test),
4915*404b540aSrobert 					  GET_MODE (cr_reg),
4916*404b540aSrobert 					  cc_reg,
4917*404b540aSrobert 					  const0_rtx)));
4918*404b540aSrobert 
4919*404b540aSrobert   /* Handle various cases of conditional move involving two constants.  */
4920*404b540aSrobert   if (GET_CODE (src1) == CONST_INT && GET_CODE (src2) == CONST_INT)
4921*404b540aSrobert     {
4922*404b540aSrobert       HOST_WIDE_INT value1 = INTVAL (src1);
4923*404b540aSrobert       HOST_WIDE_INT value2 = INTVAL (src2);
4924*404b540aSrobert 
4925*404b540aSrobert       /* Having 0 as one of the constants can be done by loading the other
4926*404b540aSrobert          constant, and optionally moving in gr0.  */
4927*404b540aSrobert       if (value1 == 0)
4928*404b540aSrobert 	{
4929*404b540aSrobert 	  emit_move_insn (dest, src2);
4930*404b540aSrobert 	  emit_insn (gen_rtx_COND_EXEC (VOIDmode,
4931*404b540aSrobert 					gen_rtx_NE (cr_mode, cr_reg,
4932*404b540aSrobert 						    const0_rtx),
4933*404b540aSrobert 					gen_rtx_SET (VOIDmode, dest, src1)));
4934*404b540aSrobert 	}
4935*404b540aSrobert 
4936*404b540aSrobert       else if (value2 == 0)
4937*404b540aSrobert 	{
4938*404b540aSrobert 	  emit_move_insn (dest, src1);
4939*404b540aSrobert 	  emit_insn (gen_rtx_COND_EXEC (VOIDmode,
4940*404b540aSrobert 					gen_rtx_EQ (cr_mode, cr_reg,
4941*404b540aSrobert 						    const0_rtx),
4942*404b540aSrobert 					gen_rtx_SET (VOIDmode, dest, src2)));
4943*404b540aSrobert 	}
4944*404b540aSrobert 
4945*404b540aSrobert       /* If the first value is within an addi range and also the difference
4946*404b540aSrobert          between the two fits in an addi's range, load up the difference, then
4947*404b540aSrobert          conditionally move in 0, and then unconditionally add the first
4948*404b540aSrobert 	 value.  */
4949*404b540aSrobert       else if (IN_RANGE_P (value1, -2048, 2047)
4950*404b540aSrobert 	       && IN_RANGE_P (value2 - value1, -2048, 2047))
4951*404b540aSrobert 	{
4952*404b540aSrobert 	  rtx dest_si = ((GET_MODE (dest) == SImode)
4953*404b540aSrobert 			 ? dest
4954*404b540aSrobert 			 : gen_rtx_SUBREG (SImode, dest, 0));
4955*404b540aSrobert 
4956*404b540aSrobert 	  emit_move_insn (dest_si, GEN_INT (value2 - value1));
4957*404b540aSrobert 	  emit_insn (gen_rtx_COND_EXEC (VOIDmode,
4958*404b540aSrobert 					gen_rtx_NE (cr_mode, cr_reg,
4959*404b540aSrobert 						    const0_rtx),
4960*404b540aSrobert 					gen_rtx_SET (VOIDmode, dest_si,
4961*404b540aSrobert 						     const0_rtx)));
4962*404b540aSrobert 	  emit_insn (gen_addsi3 (dest_si, dest_si, src1));
4963*404b540aSrobert 	}
4964*404b540aSrobert 
4965*404b540aSrobert       else
4966*404b540aSrobert 	gcc_unreachable ();
4967*404b540aSrobert     }
4968*404b540aSrobert   else
4969*404b540aSrobert     {
4970*404b540aSrobert       /* Emit the conditional move for the test being true if needed.  */
4971*404b540aSrobert       if (! rtx_equal_p (dest, src1))
4972*404b540aSrobert 	emit_insn (gen_rtx_COND_EXEC (VOIDmode,
4973*404b540aSrobert 				      gen_rtx_NE (cr_mode, cr_reg, const0_rtx),
4974*404b540aSrobert 				      gen_rtx_SET (VOIDmode, dest, src1)));
4975*404b540aSrobert 
4976*404b540aSrobert       /* Emit the conditional move for the test being false if needed.  */
4977*404b540aSrobert       if (! rtx_equal_p (dest, src2))
4978*404b540aSrobert 	emit_insn (gen_rtx_COND_EXEC (VOIDmode,
4979*404b540aSrobert 				      gen_rtx_EQ (cr_mode, cr_reg, const0_rtx),
4980*404b540aSrobert 				      gen_rtx_SET (VOIDmode, dest, src2)));
4981*404b540aSrobert     }
4982*404b540aSrobert 
4983*404b540aSrobert   /* Finish up, return sequence.  */
4984*404b540aSrobert   ret = get_insns ();
4985*404b540aSrobert   end_sequence ();
4986*404b540aSrobert   return ret;
4987*404b540aSrobert }
4988*404b540aSrobert 
4989*404b540aSrobert 
4990*404b540aSrobert /* Split (set DEST SOURCE), where DEST is a double register and SOURCE is a
4991*404b540aSrobert    memory location that is not known to be dword-aligned.  */
4992*404b540aSrobert void
frv_split_double_load(rtx dest,rtx source)4993*404b540aSrobert frv_split_double_load (rtx dest, rtx source)
4994*404b540aSrobert {
4995*404b540aSrobert   int regno = REGNO (dest);
4996*404b540aSrobert   rtx dest1 = gen_highpart (SImode, dest);
4997*404b540aSrobert   rtx dest2 = gen_lowpart (SImode, dest);
4998*404b540aSrobert   rtx address = XEXP (source, 0);
4999*404b540aSrobert 
5000*404b540aSrobert   /* If the address is pre-modified, load the lower-numbered register
5001*404b540aSrobert      first, then load the other register using an integer offset from
5002*404b540aSrobert      the modified base register.  This order should always be safe,
5003*404b540aSrobert      since the pre-modification cannot affect the same registers as the
5004*404b540aSrobert      load does.
5005*404b540aSrobert 
5006*404b540aSrobert      The situation for other loads is more complicated.  Loading one
5007*404b540aSrobert      of the registers could affect the value of ADDRESS, so we must
5008*404b540aSrobert      be careful which order we do them in.  */
5009*404b540aSrobert   if (GET_CODE (address) == PRE_MODIFY
5010*404b540aSrobert       || ! refers_to_regno_p (regno, regno + 1, address, NULL))
5011*404b540aSrobert     {
5012*404b540aSrobert       /* It is safe to load the lower-numbered register first.  */
5013*404b540aSrobert       emit_move_insn (dest1, change_address (source, SImode, NULL));
5014*404b540aSrobert       emit_move_insn (dest2, frv_index_memory (source, SImode, 1));
5015*404b540aSrobert     }
5016*404b540aSrobert   else
5017*404b540aSrobert     {
5018*404b540aSrobert       /* ADDRESS is not pre-modified and the address depends on the
5019*404b540aSrobert          lower-numbered register.  Load the higher-numbered register
5020*404b540aSrobert          first.  */
5021*404b540aSrobert       emit_move_insn (dest2, frv_index_memory (source, SImode, 1));
5022*404b540aSrobert       emit_move_insn (dest1, change_address (source, SImode, NULL));
5023*404b540aSrobert     }
5024*404b540aSrobert }
5025*404b540aSrobert 
5026*404b540aSrobert /* Split (set DEST SOURCE), where DEST refers to a dword memory location
5027*404b540aSrobert    and SOURCE is either a double register or the constant zero.  */
5028*404b540aSrobert void
frv_split_double_store(rtx dest,rtx source)5029*404b540aSrobert frv_split_double_store (rtx dest, rtx source)
5030*404b540aSrobert {
5031*404b540aSrobert   rtx dest1 = change_address (dest, SImode, NULL);
5032*404b540aSrobert   rtx dest2 = frv_index_memory (dest, SImode, 1);
5033*404b540aSrobert   if (ZERO_P (source))
5034*404b540aSrobert     {
5035*404b540aSrobert       emit_move_insn (dest1, CONST0_RTX (SImode));
5036*404b540aSrobert       emit_move_insn (dest2, CONST0_RTX (SImode));
5037*404b540aSrobert     }
5038*404b540aSrobert   else
5039*404b540aSrobert     {
5040*404b540aSrobert       emit_move_insn (dest1, gen_highpart (SImode, source));
5041*404b540aSrobert       emit_move_insn (dest2, gen_lowpart (SImode, source));
5042*404b540aSrobert     }
5043*404b540aSrobert }
5044*404b540aSrobert 
5045*404b540aSrobert 
5046*404b540aSrobert /* Split a min/max operation returning a SEQUENCE containing all of the
5047*404b540aSrobert    insns.  */
5048*404b540aSrobert 
5049*404b540aSrobert rtx
frv_split_minmax(rtx operands[])5050*404b540aSrobert frv_split_minmax (rtx operands[])
5051*404b540aSrobert {
5052*404b540aSrobert   rtx dest	= operands[0];
5053*404b540aSrobert   rtx minmax	= operands[1];
5054*404b540aSrobert   rtx src1	= operands[2];
5055*404b540aSrobert   rtx src2	= operands[3];
5056*404b540aSrobert   rtx cc_reg	= operands[4];
5057*404b540aSrobert   rtx cr_reg	= operands[5];
5058*404b540aSrobert   rtx ret;
5059*404b540aSrobert   enum rtx_code test_code;
5060*404b540aSrobert   enum machine_mode cr_mode = GET_MODE (cr_reg);
5061*404b540aSrobert 
5062*404b540aSrobert   start_sequence ();
5063*404b540aSrobert 
5064*404b540aSrobert   /* Figure out which test to use.  */
5065*404b540aSrobert   switch (GET_CODE (minmax))
5066*404b540aSrobert     {
5067*404b540aSrobert     default:
5068*404b540aSrobert       gcc_unreachable ();
5069*404b540aSrobert 
5070*404b540aSrobert     case SMIN: test_code = LT;  break;
5071*404b540aSrobert     case SMAX: test_code = GT;  break;
5072*404b540aSrobert     case UMIN: test_code = LTU; break;
5073*404b540aSrobert     case UMAX: test_code = GTU; break;
5074*404b540aSrobert     }
5075*404b540aSrobert 
5076*404b540aSrobert   /* Issue the compare instruction.  */
5077*404b540aSrobert   emit_insn (gen_rtx_SET (VOIDmode,
5078*404b540aSrobert 			  cc_reg,
5079*404b540aSrobert 			  gen_rtx_COMPARE (GET_MODE (cc_reg),
5080*404b540aSrobert 					   src1, src2)));
5081*404b540aSrobert 
5082*404b540aSrobert   /* Set the appropriate CCR bit.  */
5083*404b540aSrobert   emit_insn (gen_rtx_SET (VOIDmode,
5084*404b540aSrobert 			  cr_reg,
5085*404b540aSrobert 			  gen_rtx_fmt_ee (test_code,
5086*404b540aSrobert 					  GET_MODE (cr_reg),
5087*404b540aSrobert 					  cc_reg,
5088*404b540aSrobert 					  const0_rtx)));
5089*404b540aSrobert 
5090*404b540aSrobert   /* If are taking the min/max of a nonzero constant, load that first, and
5091*404b540aSrobert      then do a conditional move of the other value.  */
5092*404b540aSrobert   if (GET_CODE (src2) == CONST_INT && INTVAL (src2) != 0)
5093*404b540aSrobert     {
5094*404b540aSrobert       gcc_assert (!rtx_equal_p (dest, src1));
5095*404b540aSrobert 
5096*404b540aSrobert       emit_move_insn (dest, src2);
5097*404b540aSrobert       emit_insn (gen_rtx_COND_EXEC (VOIDmode,
5098*404b540aSrobert 				    gen_rtx_NE (cr_mode, cr_reg, const0_rtx),
5099*404b540aSrobert 				    gen_rtx_SET (VOIDmode, dest, src1)));
5100*404b540aSrobert     }
5101*404b540aSrobert 
5102*404b540aSrobert   /* Otherwise, do each half of the move.  */
5103*404b540aSrobert   else
5104*404b540aSrobert     {
5105*404b540aSrobert       /* Emit the conditional move for the test being true if needed.  */
5106*404b540aSrobert       if (! rtx_equal_p (dest, src1))
5107*404b540aSrobert 	emit_insn (gen_rtx_COND_EXEC (VOIDmode,
5108*404b540aSrobert 				      gen_rtx_NE (cr_mode, cr_reg, const0_rtx),
5109*404b540aSrobert 				      gen_rtx_SET (VOIDmode, dest, src1)));
5110*404b540aSrobert 
5111*404b540aSrobert       /* Emit the conditional move for the test being false if needed.  */
5112*404b540aSrobert       if (! rtx_equal_p (dest, src2))
5113*404b540aSrobert 	emit_insn (gen_rtx_COND_EXEC (VOIDmode,
5114*404b540aSrobert 				      gen_rtx_EQ (cr_mode, cr_reg, const0_rtx),
5115*404b540aSrobert 				      gen_rtx_SET (VOIDmode, dest, src2)));
5116*404b540aSrobert     }
5117*404b540aSrobert 
5118*404b540aSrobert   /* Finish up, return sequence.  */
5119*404b540aSrobert   ret = get_insns ();
5120*404b540aSrobert   end_sequence ();
5121*404b540aSrobert   return ret;
5122*404b540aSrobert }
5123*404b540aSrobert 
5124*404b540aSrobert 
5125*404b540aSrobert /* Split an integer abs operation returning a SEQUENCE containing all of the
5126*404b540aSrobert    insns.  */
5127*404b540aSrobert 
5128*404b540aSrobert rtx
frv_split_abs(rtx operands[])5129*404b540aSrobert frv_split_abs (rtx operands[])
5130*404b540aSrobert {
5131*404b540aSrobert   rtx dest	= operands[0];
5132*404b540aSrobert   rtx src	= operands[1];
5133*404b540aSrobert   rtx cc_reg	= operands[2];
5134*404b540aSrobert   rtx cr_reg	= operands[3];
5135*404b540aSrobert   rtx ret;
5136*404b540aSrobert 
5137*404b540aSrobert   start_sequence ();
5138*404b540aSrobert 
5139*404b540aSrobert   /* Issue the compare < 0 instruction.  */
5140*404b540aSrobert   emit_insn (gen_rtx_SET (VOIDmode,
5141*404b540aSrobert 			  cc_reg,
5142*404b540aSrobert 			  gen_rtx_COMPARE (CCmode, src, const0_rtx)));
5143*404b540aSrobert 
5144*404b540aSrobert   /* Set the appropriate CCR bit.  */
5145*404b540aSrobert   emit_insn (gen_rtx_SET (VOIDmode,
5146*404b540aSrobert 			  cr_reg,
5147*404b540aSrobert 			  gen_rtx_fmt_ee (LT, CC_CCRmode, cc_reg, const0_rtx)));
5148*404b540aSrobert 
5149*404b540aSrobert   /* Emit the conditional negate if the value is negative.  */
5150*404b540aSrobert   emit_insn (gen_rtx_COND_EXEC (VOIDmode,
5151*404b540aSrobert 				gen_rtx_NE (CC_CCRmode, cr_reg, const0_rtx),
5152*404b540aSrobert 				gen_negsi2 (dest, src)));
5153*404b540aSrobert 
5154*404b540aSrobert   /* Emit the conditional move for the test being false if needed.  */
5155*404b540aSrobert   if (! rtx_equal_p (dest, src))
5156*404b540aSrobert     emit_insn (gen_rtx_COND_EXEC (VOIDmode,
5157*404b540aSrobert 				  gen_rtx_EQ (CC_CCRmode, cr_reg, const0_rtx),
5158*404b540aSrobert 				  gen_rtx_SET (VOIDmode, dest, src)));
5159*404b540aSrobert 
5160*404b540aSrobert   /* Finish up, return sequence.  */
5161*404b540aSrobert   ret = get_insns ();
5162*404b540aSrobert   end_sequence ();
5163*404b540aSrobert   return ret;
5164*404b540aSrobert }
5165*404b540aSrobert 
5166*404b540aSrobert 
5167*404b540aSrobert /* An internal function called by for_each_rtx to clear in a hard_reg set each
5168*404b540aSrobert    register used in an insn.  */
5169*404b540aSrobert 
5170*404b540aSrobert static int
frv_clear_registers_used(rtx * ptr,void * data)5171*404b540aSrobert frv_clear_registers_used (rtx *ptr, void *data)
5172*404b540aSrobert {
5173*404b540aSrobert   if (GET_CODE (*ptr) == REG)
5174*404b540aSrobert     {
5175*404b540aSrobert       int regno = REGNO (*ptr);
5176*404b540aSrobert       HARD_REG_SET *p_regs = (HARD_REG_SET *)data;
5177*404b540aSrobert 
5178*404b540aSrobert       if (regno < FIRST_PSEUDO_REGISTER)
5179*404b540aSrobert 	{
5180*404b540aSrobert 	  int reg_max = regno + HARD_REGNO_NREGS (regno, GET_MODE (*ptr));
5181*404b540aSrobert 
5182*404b540aSrobert 	  while (regno < reg_max)
5183*404b540aSrobert 	    {
5184*404b540aSrobert 	      CLEAR_HARD_REG_BIT (*p_regs, regno);
5185*404b540aSrobert 	      regno++;
5186*404b540aSrobert 	    }
5187*404b540aSrobert 	}
5188*404b540aSrobert     }
5189*404b540aSrobert 
5190*404b540aSrobert   return 0;
5191*404b540aSrobert }
5192*404b540aSrobert 
5193*404b540aSrobert 
5194*404b540aSrobert /* Initialize the extra fields provided by IFCVT_EXTRA_FIELDS.  */
5195*404b540aSrobert 
5196*404b540aSrobert /* On the FR-V, we don't have any extra fields per se, but it is useful hook to
5197*404b540aSrobert    initialize the static storage.  */
5198*404b540aSrobert void
frv_ifcvt_init_extra_fields(ce_if_block_t * ce_info ATTRIBUTE_UNUSED)5199*404b540aSrobert frv_ifcvt_init_extra_fields (ce_if_block_t *ce_info ATTRIBUTE_UNUSED)
5200*404b540aSrobert {
5201*404b540aSrobert   frv_ifcvt.added_insns_list = NULL_RTX;
5202*404b540aSrobert   frv_ifcvt.cur_scratch_regs = 0;
5203*404b540aSrobert   frv_ifcvt.num_nested_cond_exec = 0;
5204*404b540aSrobert   frv_ifcvt.cr_reg = NULL_RTX;
5205*404b540aSrobert   frv_ifcvt.nested_cc_reg = NULL_RTX;
5206*404b540aSrobert   frv_ifcvt.extra_int_cr = NULL_RTX;
5207*404b540aSrobert   frv_ifcvt.extra_fp_cr = NULL_RTX;
5208*404b540aSrobert   frv_ifcvt.last_nested_if_cr = NULL_RTX;
5209*404b540aSrobert }
5210*404b540aSrobert 
5211*404b540aSrobert 
5212*404b540aSrobert /* Internal function to add a potential insn to the list of insns to be inserted
5213*404b540aSrobert    if the conditional execution conversion is successful.  */
5214*404b540aSrobert 
5215*404b540aSrobert static void
frv_ifcvt_add_insn(rtx pattern,rtx insn,int before_p)5216*404b540aSrobert frv_ifcvt_add_insn (rtx pattern, rtx insn, int before_p)
5217*404b540aSrobert {
5218*404b540aSrobert   rtx link = alloc_EXPR_LIST (VOIDmode, pattern, insn);
5219*404b540aSrobert 
5220*404b540aSrobert   link->jump = before_p;	/* Mark to add this before or after insn.  */
5221*404b540aSrobert   frv_ifcvt.added_insns_list = alloc_EXPR_LIST (VOIDmode, link,
5222*404b540aSrobert 						frv_ifcvt.added_insns_list);
5223*404b540aSrobert 
5224*404b540aSrobert   if (TARGET_DEBUG_COND_EXEC)
5225*404b540aSrobert     {
5226*404b540aSrobert       fprintf (stderr,
5227*404b540aSrobert 	       "\n:::::::::: frv_ifcvt_add_insn: add the following %s insn %d:\n",
5228*404b540aSrobert 	       (before_p) ? "before" : "after",
5229*404b540aSrobert 	       (int)INSN_UID (insn));
5230*404b540aSrobert 
5231*404b540aSrobert       debug_rtx (pattern);
5232*404b540aSrobert     }
5233*404b540aSrobert }
5234*404b540aSrobert 
5235*404b540aSrobert 
5236*404b540aSrobert /* A C expression to modify the code described by the conditional if
5237*404b540aSrobert    information CE_INFO, possibly updating the tests in TRUE_EXPR, and
5238*404b540aSrobert    FALSE_EXPR for converting if-then and if-then-else code to conditional
5239*404b540aSrobert    instructions.  Set either TRUE_EXPR or FALSE_EXPR to a null pointer if the
5240*404b540aSrobert    tests cannot be converted.  */
5241*404b540aSrobert 
5242*404b540aSrobert void
frv_ifcvt_modify_tests(ce_if_block_t * ce_info,rtx * p_true,rtx * p_false)5243*404b540aSrobert frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
5244*404b540aSrobert {
5245*404b540aSrobert   basic_block test_bb = ce_info->test_bb;	/* test basic block */
5246*404b540aSrobert   basic_block then_bb = ce_info->then_bb;	/* THEN */
5247*404b540aSrobert   basic_block else_bb = ce_info->else_bb;	/* ELSE or NULL */
5248*404b540aSrobert   basic_block join_bb = ce_info->join_bb;	/* join block or NULL */
5249*404b540aSrobert   rtx true_expr = *p_true;
5250*404b540aSrobert   rtx cr;
5251*404b540aSrobert   rtx cc;
5252*404b540aSrobert   rtx nested_cc;
5253*404b540aSrobert   enum machine_mode mode = GET_MODE (true_expr);
5254*404b540aSrobert   int j;
5255*404b540aSrobert   basic_block *bb;
5256*404b540aSrobert   int num_bb;
5257*404b540aSrobert   frv_tmp_reg_t *tmp_reg = &frv_ifcvt.tmp_reg;
5258*404b540aSrobert   rtx check_insn;
5259*404b540aSrobert   rtx sub_cond_exec_reg;
5260*404b540aSrobert   enum rtx_code code;
5261*404b540aSrobert   enum rtx_code code_true;
5262*404b540aSrobert   enum rtx_code code_false;
5263*404b540aSrobert   enum reg_class cc_class;
5264*404b540aSrobert   enum reg_class cr_class;
5265*404b540aSrobert   int cc_first;
5266*404b540aSrobert   int cc_last;
5267*404b540aSrobert   reg_set_iterator rsi;
5268*404b540aSrobert 
5269*404b540aSrobert   /* Make sure we are only dealing with hard registers.  Also honor the
5270*404b540aSrobert      -mno-cond-exec switch, and -mno-nested-cond-exec switches if
5271*404b540aSrobert      applicable.  */
5272*404b540aSrobert   if (!reload_completed || !TARGET_COND_EXEC
5273*404b540aSrobert       || (!TARGET_NESTED_CE && ce_info->pass > 1))
5274*404b540aSrobert     goto fail;
5275*404b540aSrobert 
5276*404b540aSrobert   /* Figure out which registers we can allocate for our own purposes.  Only
5277*404b540aSrobert      consider registers that are not preserved across function calls and are
5278*404b540aSrobert      not fixed.  However, allow the ICC/ICR temporary registers to be allocated
5279*404b540aSrobert      if we did not need to use them in reloading other registers.  */
5280*404b540aSrobert   memset (&tmp_reg->regs, 0, sizeof (tmp_reg->regs));
5281*404b540aSrobert   COPY_HARD_REG_SET (tmp_reg->regs, call_used_reg_set);
5282*404b540aSrobert   AND_COMPL_HARD_REG_SET (tmp_reg->regs, fixed_reg_set);
5283*404b540aSrobert   SET_HARD_REG_BIT (tmp_reg->regs, ICC_TEMP);
5284*404b540aSrobert   SET_HARD_REG_BIT (tmp_reg->regs, ICR_TEMP);
5285*404b540aSrobert 
5286*404b540aSrobert   /* If this is a nested IF, we need to discover whether the CC registers that
5287*404b540aSrobert      are set/used inside of the block are used anywhere else.  If not, we can
5288*404b540aSrobert      change them to be the CC register that is paired with the CR register that
5289*404b540aSrobert      controls the outermost IF block.  */
5290*404b540aSrobert   if (ce_info->pass > 1)
5291*404b540aSrobert     {
5292*404b540aSrobert       CLEAR_HARD_REG_SET (frv_ifcvt.nested_cc_ok_rewrite);
5293*404b540aSrobert       for (j = CC_FIRST; j <= CC_LAST; j++)
5294*404b540aSrobert 	if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
5295*404b540aSrobert 	  {
5296*404b540aSrobert 	    if (REGNO_REG_SET_P (then_bb->il.rtl->global_live_at_start, j))
5297*404b540aSrobert 	      continue;
5298*404b540aSrobert 
5299*404b540aSrobert 	    if (else_bb
5300*404b540aSrobert 		&& REGNO_REG_SET_P (else_bb->il.rtl->global_live_at_start, j))
5301*404b540aSrobert 	      continue;
5302*404b540aSrobert 
5303*404b540aSrobert 	    if (join_bb
5304*404b540aSrobert 		&& REGNO_REG_SET_P (join_bb->il.rtl->global_live_at_start, j))
5305*404b540aSrobert 	      continue;
5306*404b540aSrobert 
5307*404b540aSrobert 	    SET_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, j);
5308*404b540aSrobert 	  }
5309*404b540aSrobert     }
5310*404b540aSrobert 
5311*404b540aSrobert   for (j = 0; j < frv_ifcvt.cur_scratch_regs; j++)
5312*404b540aSrobert     frv_ifcvt.scratch_regs[j] = NULL_RTX;
5313*404b540aSrobert 
5314*404b540aSrobert   frv_ifcvt.added_insns_list = NULL_RTX;
5315*404b540aSrobert   frv_ifcvt.cur_scratch_regs = 0;
5316*404b540aSrobert 
5317*404b540aSrobert   bb = (basic_block *) alloca ((2 + ce_info->num_multiple_test_blocks)
5318*404b540aSrobert 			       * sizeof (basic_block));
5319*404b540aSrobert 
5320*404b540aSrobert   if (join_bb)
5321*404b540aSrobert     {
5322*404b540aSrobert       unsigned int regno;
5323*404b540aSrobert 
5324*404b540aSrobert       /* Remove anything live at the beginning of the join block from being
5325*404b540aSrobert          available for allocation.  */
5326*404b540aSrobert       EXECUTE_IF_SET_IN_REG_SET (join_bb->il.rtl->global_live_at_start, 0, regno, rsi)
5327*404b540aSrobert 	{
5328*404b540aSrobert 	  if (regno < FIRST_PSEUDO_REGISTER)
5329*404b540aSrobert 	    CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
5330*404b540aSrobert 	}
5331*404b540aSrobert     }
5332*404b540aSrobert 
5333*404b540aSrobert   /* Add in all of the blocks in multiple &&/|| blocks to be scanned.  */
5334*404b540aSrobert   num_bb = 0;
5335*404b540aSrobert   if (ce_info->num_multiple_test_blocks)
5336*404b540aSrobert     {
5337*404b540aSrobert       basic_block multiple_test_bb = ce_info->last_test_bb;
5338*404b540aSrobert 
5339*404b540aSrobert       while (multiple_test_bb != test_bb)
5340*404b540aSrobert 	{
5341*404b540aSrobert 	  bb[num_bb++] = multiple_test_bb;
5342*404b540aSrobert 	  multiple_test_bb = EDGE_PRED (multiple_test_bb, 0)->src;
5343*404b540aSrobert 	}
5344*404b540aSrobert     }
5345*404b540aSrobert 
5346*404b540aSrobert   /* Add in the THEN and ELSE blocks to be scanned.  */
5347*404b540aSrobert   bb[num_bb++] = then_bb;
5348*404b540aSrobert   if (else_bb)
5349*404b540aSrobert     bb[num_bb++] = else_bb;
5350*404b540aSrobert 
5351*404b540aSrobert   sub_cond_exec_reg = NULL_RTX;
5352*404b540aSrobert   frv_ifcvt.num_nested_cond_exec = 0;
5353*404b540aSrobert 
5354*404b540aSrobert   /* Scan all of the blocks for registers that must not be allocated.  */
5355*404b540aSrobert   for (j = 0; j < num_bb; j++)
5356*404b540aSrobert     {
5357*404b540aSrobert       rtx last_insn = BB_END (bb[j]);
5358*404b540aSrobert       rtx insn = BB_HEAD (bb[j]);
5359*404b540aSrobert       unsigned int regno;
5360*404b540aSrobert 
5361*404b540aSrobert       if (dump_file)
5362*404b540aSrobert 	fprintf (dump_file, "Scanning %s block %d, start %d, end %d\n",
5363*404b540aSrobert 		 (bb[j] == else_bb) ? "else" : ((bb[j] == then_bb) ? "then" : "test"),
5364*404b540aSrobert 		 (int) bb[j]->index,
5365*404b540aSrobert 		 (int) INSN_UID (BB_HEAD (bb[j])),
5366*404b540aSrobert 		 (int) INSN_UID (BB_END (bb[j])));
5367*404b540aSrobert 
5368*404b540aSrobert       /* Anything live at the beginning of the block is obviously unavailable
5369*404b540aSrobert          for allocation.  */
5370*404b540aSrobert       EXECUTE_IF_SET_IN_REG_SET (bb[j]->il.rtl->global_live_at_start, 0, regno, rsi)
5371*404b540aSrobert 	{
5372*404b540aSrobert 	  if (regno < FIRST_PSEUDO_REGISTER)
5373*404b540aSrobert 	    CLEAR_HARD_REG_BIT (tmp_reg->regs, regno);
5374*404b540aSrobert 	}
5375*404b540aSrobert 
5376*404b540aSrobert       /* Loop through the insns in the block.  */
5377*404b540aSrobert       for (;;)
5378*404b540aSrobert 	{
5379*404b540aSrobert 	  /* Mark any new registers that are created as being unavailable for
5380*404b540aSrobert              allocation.  Also see if the CC register used in nested IFs can be
5381*404b540aSrobert              reallocated.  */
5382*404b540aSrobert 	  if (INSN_P (insn))
5383*404b540aSrobert 	    {
5384*404b540aSrobert 	      rtx pattern;
5385*404b540aSrobert 	      rtx set;
5386*404b540aSrobert 	      int skip_nested_if = FALSE;
5387*404b540aSrobert 
5388*404b540aSrobert 	      for_each_rtx (&PATTERN (insn), frv_clear_registers_used,
5389*404b540aSrobert 			    (void *)&tmp_reg->regs);
5390*404b540aSrobert 
5391*404b540aSrobert 	      pattern = PATTERN (insn);
5392*404b540aSrobert 	      if (GET_CODE (pattern) == COND_EXEC)
5393*404b540aSrobert 		{
5394*404b540aSrobert 		  rtx reg = XEXP (COND_EXEC_TEST (pattern), 0);
5395*404b540aSrobert 
5396*404b540aSrobert 		  if (reg != sub_cond_exec_reg)
5397*404b540aSrobert 		    {
5398*404b540aSrobert 		      sub_cond_exec_reg = reg;
5399*404b540aSrobert 		      frv_ifcvt.num_nested_cond_exec++;
5400*404b540aSrobert 		    }
5401*404b540aSrobert 		}
5402*404b540aSrobert 
5403*404b540aSrobert 	      set = single_set_pattern (pattern);
5404*404b540aSrobert 	      if (set)
5405*404b540aSrobert 		{
5406*404b540aSrobert 		  rtx dest = SET_DEST (set);
5407*404b540aSrobert 		  rtx src = SET_SRC (set);
5408*404b540aSrobert 
5409*404b540aSrobert 		  if (GET_CODE (dest) == REG)
5410*404b540aSrobert 		    {
5411*404b540aSrobert 		      int regno = REGNO (dest);
5412*404b540aSrobert 		      enum rtx_code src_code = GET_CODE (src);
5413*404b540aSrobert 
5414*404b540aSrobert 		      if (CC_P (regno) && src_code == COMPARE)
5415*404b540aSrobert 			skip_nested_if = TRUE;
5416*404b540aSrobert 
5417*404b540aSrobert 		      else if (CR_P (regno)
5418*404b540aSrobert 			       && (src_code == IF_THEN_ELSE
5419*404b540aSrobert 				   || COMPARISON_P (src)))
5420*404b540aSrobert 			skip_nested_if = TRUE;
5421*404b540aSrobert 		    }
5422*404b540aSrobert 		}
5423*404b540aSrobert 
5424*404b540aSrobert 	      if (! skip_nested_if)
5425*404b540aSrobert 		for_each_rtx (&PATTERN (insn), frv_clear_registers_used,
5426*404b540aSrobert 			      (void *)&frv_ifcvt.nested_cc_ok_rewrite);
5427*404b540aSrobert 	    }
5428*404b540aSrobert 
5429*404b540aSrobert 	  if (insn == last_insn)
5430*404b540aSrobert 	    break;
5431*404b540aSrobert 
5432*404b540aSrobert 	  insn = NEXT_INSN (insn);
5433*404b540aSrobert 	}
5434*404b540aSrobert     }
5435*404b540aSrobert 
5436*404b540aSrobert   /* If this is a nested if, rewrite the CC registers that are available to
5437*404b540aSrobert      include the ones that can be rewritten, to increase the chance of being
5438*404b540aSrobert      able to allocate a paired CC/CR register combination.  */
5439*404b540aSrobert   if (ce_info->pass > 1)
5440*404b540aSrobert     {
5441*404b540aSrobert       for (j = CC_FIRST; j <= CC_LAST; j++)
5442*404b540aSrobert 	if (TEST_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, j))
5443*404b540aSrobert 	  SET_HARD_REG_BIT (tmp_reg->regs, j);
5444*404b540aSrobert 	else
5445*404b540aSrobert 	  CLEAR_HARD_REG_BIT (tmp_reg->regs, j);
5446*404b540aSrobert     }
5447*404b540aSrobert 
5448*404b540aSrobert   if (dump_file)
5449*404b540aSrobert     {
5450*404b540aSrobert       int num_gprs = 0;
5451*404b540aSrobert       fprintf (dump_file, "Available GPRs: ");
5452*404b540aSrobert 
5453*404b540aSrobert       for (j = GPR_FIRST; j <= GPR_LAST; j++)
5454*404b540aSrobert 	if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
5455*404b540aSrobert 	  {
5456*404b540aSrobert 	    fprintf (dump_file, " %d [%s]", j, reg_names[j]);
5457*404b540aSrobert 	    if (++num_gprs > GPR_TEMP_NUM+2)
5458*404b540aSrobert 	      break;
5459*404b540aSrobert 	  }
5460*404b540aSrobert 
5461*404b540aSrobert       fprintf (dump_file, "%s\nAvailable CRs:  ",
5462*404b540aSrobert 	       (num_gprs > GPR_TEMP_NUM+2) ? " ..." : "");
5463*404b540aSrobert 
5464*404b540aSrobert       for (j = CR_FIRST; j <= CR_LAST; j++)
5465*404b540aSrobert 	if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
5466*404b540aSrobert 	  fprintf (dump_file, " %d [%s]", j, reg_names[j]);
5467*404b540aSrobert 
5468*404b540aSrobert       fputs ("\n", dump_file);
5469*404b540aSrobert 
5470*404b540aSrobert       if (ce_info->pass > 1)
5471*404b540aSrobert 	{
5472*404b540aSrobert 	  fprintf (dump_file, "Modifiable CCs: ");
5473*404b540aSrobert 	  for (j = CC_FIRST; j <= CC_LAST; j++)
5474*404b540aSrobert 	    if (TEST_HARD_REG_BIT (tmp_reg->regs, j))
5475*404b540aSrobert 	      fprintf (dump_file, " %d [%s]", j, reg_names[j]);
5476*404b540aSrobert 
5477*404b540aSrobert 	  fprintf (dump_file, "\n%d nested COND_EXEC statements\n",
5478*404b540aSrobert 		   frv_ifcvt.num_nested_cond_exec);
5479*404b540aSrobert 	}
5480*404b540aSrobert     }
5481*404b540aSrobert 
5482*404b540aSrobert   /* Allocate the appropriate temporary condition code register.  Try to
5483*404b540aSrobert      allocate the ICR/FCR register that corresponds to the ICC/FCC register so
5484*404b540aSrobert      that conditional cmp's can be done.  */
5485*404b540aSrobert   if (mode == CCmode || mode == CC_UNSmode || mode == CC_NZmode)
5486*404b540aSrobert     {
5487*404b540aSrobert       cr_class = ICR_REGS;
5488*404b540aSrobert       cc_class = ICC_REGS;
5489*404b540aSrobert       cc_first = ICC_FIRST;
5490*404b540aSrobert       cc_last = ICC_LAST;
5491*404b540aSrobert     }
5492*404b540aSrobert   else if (mode == CC_FPmode)
5493*404b540aSrobert     {
5494*404b540aSrobert       cr_class = FCR_REGS;
5495*404b540aSrobert       cc_class = FCC_REGS;
5496*404b540aSrobert       cc_first = FCC_FIRST;
5497*404b540aSrobert       cc_last = FCC_LAST;
5498*404b540aSrobert     }
5499*404b540aSrobert   else
5500*404b540aSrobert     {
5501*404b540aSrobert       cc_first = cc_last = 0;
5502*404b540aSrobert       cr_class = cc_class = NO_REGS;
5503*404b540aSrobert     }
5504*404b540aSrobert 
5505*404b540aSrobert   cc = XEXP (true_expr, 0);
5506*404b540aSrobert   nested_cc = cr = NULL_RTX;
5507*404b540aSrobert   if (cc_class != NO_REGS)
5508*404b540aSrobert     {
5509*404b540aSrobert       /* For nested IFs and &&/||, see if we can find a CC and CR register pair
5510*404b540aSrobert          so we can execute a csubcc/caddcc/cfcmps instruction.  */
5511*404b540aSrobert       int cc_regno;
5512*404b540aSrobert 
5513*404b540aSrobert       for (cc_regno = cc_first; cc_regno <= cc_last; cc_regno++)
5514*404b540aSrobert 	{
5515*404b540aSrobert 	  int cr_regno = cc_regno - CC_FIRST + CR_FIRST;
5516*404b540aSrobert 
5517*404b540aSrobert 	  if (TEST_HARD_REG_BIT (frv_ifcvt.tmp_reg.regs, cc_regno)
5518*404b540aSrobert 	      && TEST_HARD_REG_BIT (frv_ifcvt.tmp_reg.regs, cr_regno))
5519*404b540aSrobert 	    {
5520*404b540aSrobert 	      frv_ifcvt.tmp_reg.next_reg[ (int)cr_class ] = cr_regno;
5521*404b540aSrobert 	      cr = frv_alloc_temp_reg (tmp_reg, cr_class, CC_CCRmode, TRUE,
5522*404b540aSrobert 				       TRUE);
5523*404b540aSrobert 
5524*404b540aSrobert 	      frv_ifcvt.tmp_reg.next_reg[ (int)cc_class ] = cc_regno;
5525*404b540aSrobert 	      nested_cc = frv_alloc_temp_reg (tmp_reg, cc_class, CCmode,
5526*404b540aSrobert 						  TRUE, TRUE);
5527*404b540aSrobert 	      break;
5528*404b540aSrobert 	    }
5529*404b540aSrobert 	}
5530*404b540aSrobert     }
5531*404b540aSrobert 
5532*404b540aSrobert   if (! cr)
5533*404b540aSrobert     {
5534*404b540aSrobert       if (dump_file)
5535*404b540aSrobert 	fprintf (dump_file, "Could not allocate a CR temporary register\n");
5536*404b540aSrobert 
5537*404b540aSrobert       goto fail;
5538*404b540aSrobert     }
5539*404b540aSrobert 
5540*404b540aSrobert   if (dump_file)
5541*404b540aSrobert     fprintf (dump_file,
5542*404b540aSrobert 	     "Will use %s for conditional execution, %s for nested comparisons\n",
5543*404b540aSrobert 	     reg_names[ REGNO (cr)],
5544*404b540aSrobert 	     (nested_cc) ? reg_names[ REGNO (nested_cc) ] : "<none>");
5545*404b540aSrobert 
5546*404b540aSrobert   /* Set the CCR bit.  Note for integer tests, we reverse the condition so that
5547*404b540aSrobert      in an IF-THEN-ELSE sequence, we are testing the TRUE case against the CCR
5548*404b540aSrobert      bit being true.  We don't do this for floating point, because of NaNs.  */
5549*404b540aSrobert   code = GET_CODE (true_expr);
5550*404b540aSrobert   if (GET_MODE (cc) != CC_FPmode)
5551*404b540aSrobert     {
5552*404b540aSrobert       code = reverse_condition (code);
5553*404b540aSrobert       code_true = EQ;
5554*404b540aSrobert       code_false = NE;
5555*404b540aSrobert     }
5556*404b540aSrobert   else
5557*404b540aSrobert     {
5558*404b540aSrobert       code_true = NE;
5559*404b540aSrobert       code_false = EQ;
5560*404b540aSrobert     }
5561*404b540aSrobert 
5562*404b540aSrobert   check_insn = gen_rtx_SET (VOIDmode, cr,
5563*404b540aSrobert 			    gen_rtx_fmt_ee (code, CC_CCRmode, cc, const0_rtx));
5564*404b540aSrobert 
5565*404b540aSrobert   /* Record the check insn to be inserted later.  */
5566*404b540aSrobert   frv_ifcvt_add_insn (check_insn, BB_END (test_bb), TRUE);
5567*404b540aSrobert 
5568*404b540aSrobert   /* Update the tests.  */
5569*404b540aSrobert   frv_ifcvt.cr_reg = cr;
5570*404b540aSrobert   frv_ifcvt.nested_cc_reg = nested_cc;
5571*404b540aSrobert   *p_true = gen_rtx_fmt_ee (code_true, CC_CCRmode, cr, const0_rtx);
5572*404b540aSrobert   *p_false = gen_rtx_fmt_ee (code_false, CC_CCRmode, cr, const0_rtx);
5573*404b540aSrobert   return;
5574*404b540aSrobert 
5575*404b540aSrobert   /* Fail, don't do this conditional execution.  */
5576*404b540aSrobert  fail:
5577*404b540aSrobert   *p_true = NULL_RTX;
5578*404b540aSrobert   *p_false = NULL_RTX;
5579*404b540aSrobert   if (dump_file)
5580*404b540aSrobert     fprintf (dump_file, "Disabling this conditional execution.\n");
5581*404b540aSrobert 
5582*404b540aSrobert   return;
5583*404b540aSrobert }
5584*404b540aSrobert 
5585*404b540aSrobert 
5586*404b540aSrobert /* A C expression to modify the code described by the conditional if
5587*404b540aSrobert    information CE_INFO, for the basic block BB, possibly updating the tests in
5588*404b540aSrobert    TRUE_EXPR, and FALSE_EXPR for converting the && and || parts of if-then or
5589*404b540aSrobert    if-then-else code to conditional instructions.  Set either TRUE_EXPR or
5590*404b540aSrobert    FALSE_EXPR to a null pointer if the tests cannot be converted.  */
5591*404b540aSrobert 
5592*404b540aSrobert /* p_true and p_false are given expressions of the form:
5593*404b540aSrobert 
5594*404b540aSrobert 	(and (eq:CC_CCR (reg:CC_CCR)
5595*404b540aSrobert 			(const_int 0))
5596*404b540aSrobert 	     (eq:CC (reg:CC)
5597*404b540aSrobert 		    (const_int 0))) */
5598*404b540aSrobert 
5599*404b540aSrobert void
frv_ifcvt_modify_multiple_tests(ce_if_block_t * ce_info,basic_block bb,rtx * p_true,rtx * p_false)5600*404b540aSrobert frv_ifcvt_modify_multiple_tests (ce_if_block_t *ce_info,
5601*404b540aSrobert                                  basic_block bb,
5602*404b540aSrobert                                  rtx *p_true,
5603*404b540aSrobert                                  rtx *p_false)
5604*404b540aSrobert {
5605*404b540aSrobert   rtx old_true = XEXP (*p_true, 0);
5606*404b540aSrobert   rtx old_false = XEXP (*p_false, 0);
5607*404b540aSrobert   rtx true_expr = XEXP (*p_true, 1);
5608*404b540aSrobert   rtx false_expr = XEXP (*p_false, 1);
5609*404b540aSrobert   rtx test_expr;
5610*404b540aSrobert   rtx old_test;
5611*404b540aSrobert   rtx cr = XEXP (old_true, 0);
5612*404b540aSrobert   rtx check_insn;
5613*404b540aSrobert   rtx new_cr = NULL_RTX;
5614*404b540aSrobert   rtx *p_new_cr = (rtx *)0;
5615*404b540aSrobert   rtx if_else;
5616*404b540aSrobert   rtx compare;
5617*404b540aSrobert   rtx cc;
5618*404b540aSrobert   enum reg_class cr_class;
5619*404b540aSrobert   enum machine_mode mode = GET_MODE (true_expr);
5620*404b540aSrobert   rtx (*logical_func)(rtx, rtx, rtx);
5621*404b540aSrobert 
5622*404b540aSrobert   if (TARGET_DEBUG_COND_EXEC)
5623*404b540aSrobert     {
5624*404b540aSrobert       fprintf (stderr,
5625*404b540aSrobert 	       "\n:::::::::: frv_ifcvt_modify_multiple_tests, before modification for %s\ntrue insn:\n",
5626*404b540aSrobert 	       ce_info->and_and_p ? "&&" : "||");
5627*404b540aSrobert 
5628*404b540aSrobert       debug_rtx (*p_true);
5629*404b540aSrobert 
5630*404b540aSrobert       fputs ("\nfalse insn:\n", stderr);
5631*404b540aSrobert       debug_rtx (*p_false);
5632*404b540aSrobert     }
5633*404b540aSrobert 
5634*404b540aSrobert   if (!TARGET_MULTI_CE)
5635*404b540aSrobert     goto fail;
5636*404b540aSrobert 
5637*404b540aSrobert   if (GET_CODE (cr) != REG)
5638*404b540aSrobert     goto fail;
5639*404b540aSrobert 
5640*404b540aSrobert   if (mode == CCmode || mode == CC_UNSmode || mode == CC_NZmode)
5641*404b540aSrobert     {
5642*404b540aSrobert       cr_class = ICR_REGS;
5643*404b540aSrobert       p_new_cr = &frv_ifcvt.extra_int_cr;
5644*404b540aSrobert     }
5645*404b540aSrobert   else if (mode == CC_FPmode)
5646*404b540aSrobert     {
5647*404b540aSrobert       cr_class = FCR_REGS;
5648*404b540aSrobert       p_new_cr = &frv_ifcvt.extra_fp_cr;
5649*404b540aSrobert     }
5650*404b540aSrobert   else
5651*404b540aSrobert     goto fail;
5652*404b540aSrobert 
5653*404b540aSrobert   /* Allocate a temp CR, reusing a previously allocated temp CR if we have 3 or
5654*404b540aSrobert      more &&/|| tests.  */
5655*404b540aSrobert   new_cr = *p_new_cr;
5656*404b540aSrobert   if (! new_cr)
5657*404b540aSrobert     {
5658*404b540aSrobert       new_cr = *p_new_cr = frv_alloc_temp_reg (&frv_ifcvt.tmp_reg, cr_class,
5659*404b540aSrobert 					       CC_CCRmode, TRUE, TRUE);
5660*404b540aSrobert       if (! new_cr)
5661*404b540aSrobert 	goto fail;
5662*404b540aSrobert     }
5663*404b540aSrobert 
5664*404b540aSrobert   if (ce_info->and_and_p)
5665*404b540aSrobert     {
5666*404b540aSrobert       old_test = old_false;
5667*404b540aSrobert       test_expr = true_expr;
5668*404b540aSrobert       logical_func = (GET_CODE (old_true) == EQ) ? gen_andcr : gen_andncr;
5669*404b540aSrobert       *p_true = gen_rtx_NE (CC_CCRmode, cr, const0_rtx);
5670*404b540aSrobert       *p_false = gen_rtx_EQ (CC_CCRmode, cr, const0_rtx);
5671*404b540aSrobert     }
5672*404b540aSrobert   else
5673*404b540aSrobert     {
5674*404b540aSrobert       old_test = old_false;
5675*404b540aSrobert       test_expr = false_expr;
5676*404b540aSrobert       logical_func = (GET_CODE (old_false) == EQ) ? gen_orcr : gen_orncr;
5677*404b540aSrobert       *p_true = gen_rtx_EQ (CC_CCRmode, cr, const0_rtx);
5678*404b540aSrobert       *p_false = gen_rtx_NE (CC_CCRmode, cr, const0_rtx);
5679*404b540aSrobert     }
5680*404b540aSrobert 
5681*404b540aSrobert   /* First add the andcr/andncr/orcr/orncr, which will be added after the
5682*404b540aSrobert      conditional check instruction, due to frv_ifcvt_add_insn being a LIFO
5683*404b540aSrobert      stack.  */
5684*404b540aSrobert   frv_ifcvt_add_insn ((*logical_func) (cr, cr, new_cr), BB_END (bb), TRUE);
5685*404b540aSrobert 
5686*404b540aSrobert   /* Now add the conditional check insn.  */
5687*404b540aSrobert   cc = XEXP (test_expr, 0);
5688*404b540aSrobert   compare = gen_rtx_fmt_ee (GET_CODE (test_expr), CC_CCRmode, cc, const0_rtx);
5689*404b540aSrobert   if_else = gen_rtx_IF_THEN_ELSE (CC_CCRmode, old_test, compare, const0_rtx);
5690*404b540aSrobert 
5691*404b540aSrobert   check_insn = gen_rtx_SET (VOIDmode, new_cr, if_else);
5692*404b540aSrobert 
5693*404b540aSrobert   /* Add the new check insn to the list of check insns that need to be
5694*404b540aSrobert      inserted.  */
5695*404b540aSrobert   frv_ifcvt_add_insn (check_insn, BB_END (bb), TRUE);
5696*404b540aSrobert 
5697*404b540aSrobert   if (TARGET_DEBUG_COND_EXEC)
5698*404b540aSrobert     {
5699*404b540aSrobert       fputs ("\n:::::::::: frv_ifcvt_modify_multiple_tests, after modification\ntrue insn:\n",
5700*404b540aSrobert 	     stderr);
5701*404b540aSrobert 
5702*404b540aSrobert       debug_rtx (*p_true);
5703*404b540aSrobert 
5704*404b540aSrobert       fputs ("\nfalse insn:\n", stderr);
5705*404b540aSrobert       debug_rtx (*p_false);
5706*404b540aSrobert     }
5707*404b540aSrobert 
5708*404b540aSrobert   return;
5709*404b540aSrobert 
5710*404b540aSrobert  fail:
5711*404b540aSrobert   *p_true = *p_false = NULL_RTX;
5712*404b540aSrobert 
5713*404b540aSrobert   /* If we allocated a CR register, release it.  */
5714*404b540aSrobert   if (new_cr)
5715*404b540aSrobert     {
5716*404b540aSrobert       CLEAR_HARD_REG_BIT (frv_ifcvt.tmp_reg.regs, REGNO (new_cr));
5717*404b540aSrobert       *p_new_cr = NULL_RTX;
5718*404b540aSrobert     }
5719*404b540aSrobert 
5720*404b540aSrobert   if (TARGET_DEBUG_COND_EXEC)
5721*404b540aSrobert     fputs ("\n:::::::::: frv_ifcvt_modify_multiple_tests, failed.\n", stderr);
5722*404b540aSrobert 
5723*404b540aSrobert   return;
5724*404b540aSrobert }
5725*404b540aSrobert 
5726*404b540aSrobert 
5727*404b540aSrobert /* Return a register which will be loaded with a value if an IF block is
5728*404b540aSrobert    converted to conditional execution.  This is used to rewrite instructions
5729*404b540aSrobert    that use constants to ones that just use registers.  */
5730*404b540aSrobert 
5731*404b540aSrobert static rtx
frv_ifcvt_load_value(rtx value,rtx insn ATTRIBUTE_UNUSED)5732*404b540aSrobert frv_ifcvt_load_value (rtx value, rtx insn ATTRIBUTE_UNUSED)
5733*404b540aSrobert {
5734*404b540aSrobert   int num_alloc = frv_ifcvt.cur_scratch_regs;
5735*404b540aSrobert   int i;
5736*404b540aSrobert   rtx reg;
5737*404b540aSrobert 
5738*404b540aSrobert   /* We know gr0 == 0, so replace any errant uses.  */
5739*404b540aSrobert   if (value == const0_rtx)
5740*404b540aSrobert     return gen_rtx_REG (SImode, GPR_FIRST);
5741*404b540aSrobert 
5742*404b540aSrobert   /* First search all registers currently loaded to see if we have an
5743*404b540aSrobert      applicable constant.  */
5744*404b540aSrobert   if (CONSTANT_P (value)
5745*404b540aSrobert       || (GET_CODE (value) == REG && REGNO (value) == LR_REGNO))
5746*404b540aSrobert     {
5747*404b540aSrobert       for (i = 0; i < num_alloc; i++)
5748*404b540aSrobert 	{
5749*404b540aSrobert 	  if (rtx_equal_p (SET_SRC (frv_ifcvt.scratch_regs[i]), value))
5750*404b540aSrobert 	    return SET_DEST (frv_ifcvt.scratch_regs[i]);
5751*404b540aSrobert 	}
5752*404b540aSrobert     }
5753*404b540aSrobert 
5754*404b540aSrobert   /* Have we exhausted the number of registers available?  */
5755*404b540aSrobert   if (num_alloc >= GPR_TEMP_NUM)
5756*404b540aSrobert     {
5757*404b540aSrobert       if (dump_file)
5758*404b540aSrobert 	fprintf (dump_file, "Too many temporary registers allocated\n");
5759*404b540aSrobert 
5760*404b540aSrobert       return NULL_RTX;
5761*404b540aSrobert     }
5762*404b540aSrobert 
5763*404b540aSrobert   /* Allocate the new register.  */
5764*404b540aSrobert   reg = frv_alloc_temp_reg (&frv_ifcvt.tmp_reg, GPR_REGS, SImode, TRUE, TRUE);
5765*404b540aSrobert   if (! reg)
5766*404b540aSrobert     {
5767*404b540aSrobert       if (dump_file)
5768*404b540aSrobert 	fputs ("Could not find a scratch register\n", dump_file);
5769*404b540aSrobert 
5770*404b540aSrobert       return NULL_RTX;
5771*404b540aSrobert     }
5772*404b540aSrobert 
5773*404b540aSrobert   frv_ifcvt.cur_scratch_regs++;
5774*404b540aSrobert   frv_ifcvt.scratch_regs[num_alloc] = gen_rtx_SET (VOIDmode, reg, value);
5775*404b540aSrobert 
5776*404b540aSrobert   if (dump_file)
5777*404b540aSrobert     {
5778*404b540aSrobert       if (GET_CODE (value) == CONST_INT)
5779*404b540aSrobert 	fprintf (dump_file, "Register %s will hold %ld\n",
5780*404b540aSrobert 		 reg_names[ REGNO (reg)], (long)INTVAL (value));
5781*404b540aSrobert 
5782*404b540aSrobert       else if (GET_CODE (value) == REG && REGNO (value) == LR_REGNO)
5783*404b540aSrobert 	fprintf (dump_file, "Register %s will hold LR\n",
5784*404b540aSrobert 		 reg_names[ REGNO (reg)]);
5785*404b540aSrobert 
5786*404b540aSrobert       else
5787*404b540aSrobert 	fprintf (dump_file, "Register %s will hold a saved value\n",
5788*404b540aSrobert 		 reg_names[ REGNO (reg)]);
5789*404b540aSrobert     }
5790*404b540aSrobert 
5791*404b540aSrobert   return reg;
5792*404b540aSrobert }
5793*404b540aSrobert 
5794*404b540aSrobert 
5795*404b540aSrobert /* Update a MEM used in conditional code that might contain an offset to put
5796*404b540aSrobert    the offset into a scratch register, so that the conditional load/store
5797*404b540aSrobert    operations can be used.  This function returns the original pointer if the
5798*404b540aSrobert    MEM is valid to use in conditional code, NULL if we can't load up the offset
5799*404b540aSrobert    into a temporary register, or the new MEM if we were successful.  */
5800*404b540aSrobert 
5801*404b540aSrobert static rtx
frv_ifcvt_rewrite_mem(rtx mem,enum machine_mode mode,rtx insn)5802*404b540aSrobert frv_ifcvt_rewrite_mem (rtx mem, enum machine_mode mode, rtx insn)
5803*404b540aSrobert {
5804*404b540aSrobert   rtx addr = XEXP (mem, 0);
5805*404b540aSrobert 
5806*404b540aSrobert   if (!frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE))
5807*404b540aSrobert     {
5808*404b540aSrobert       if (GET_CODE (addr) == PLUS)
5809*404b540aSrobert 	{
5810*404b540aSrobert 	  rtx addr_op0 = XEXP (addr, 0);
5811*404b540aSrobert 	  rtx addr_op1 = XEXP (addr, 1);
5812*404b540aSrobert 
5813*404b540aSrobert 	  if (GET_CODE (addr_op0) == REG && CONSTANT_P (addr_op1))
5814*404b540aSrobert 	    {
5815*404b540aSrobert 	      rtx reg = frv_ifcvt_load_value (addr_op1, insn);
5816*404b540aSrobert 	      if (!reg)
5817*404b540aSrobert 		return NULL_RTX;
5818*404b540aSrobert 
5819*404b540aSrobert 	      addr = gen_rtx_PLUS (Pmode, addr_op0, reg);
5820*404b540aSrobert 	    }
5821*404b540aSrobert 
5822*404b540aSrobert 	  else
5823*404b540aSrobert 	    return NULL_RTX;
5824*404b540aSrobert 	}
5825*404b540aSrobert 
5826*404b540aSrobert       else if (CONSTANT_P (addr))
5827*404b540aSrobert 	addr = frv_ifcvt_load_value (addr, insn);
5828*404b540aSrobert 
5829*404b540aSrobert       else
5830*404b540aSrobert 	return NULL_RTX;
5831*404b540aSrobert 
5832*404b540aSrobert       if (addr == NULL_RTX)
5833*404b540aSrobert 	return NULL_RTX;
5834*404b540aSrobert 
5835*404b540aSrobert       else if (XEXP (mem, 0) != addr)
5836*404b540aSrobert 	return change_address (mem, mode, addr);
5837*404b540aSrobert     }
5838*404b540aSrobert 
5839*404b540aSrobert   return mem;
5840*404b540aSrobert }
5841*404b540aSrobert 
5842*404b540aSrobert 
5843*404b540aSrobert /* Given a PATTERN, return a SET expression if this PATTERN has only a single
5844*404b540aSrobert    SET, possibly conditionally executed.  It may also have CLOBBERs, USEs.  */
5845*404b540aSrobert 
5846*404b540aSrobert static rtx
single_set_pattern(rtx pattern)5847*404b540aSrobert single_set_pattern (rtx pattern)
5848*404b540aSrobert {
5849*404b540aSrobert   rtx set;
5850*404b540aSrobert   int i;
5851*404b540aSrobert 
5852*404b540aSrobert   if (GET_CODE (pattern) == COND_EXEC)
5853*404b540aSrobert     pattern = COND_EXEC_CODE (pattern);
5854*404b540aSrobert 
5855*404b540aSrobert   if (GET_CODE (pattern) == SET)
5856*404b540aSrobert     return pattern;
5857*404b540aSrobert 
5858*404b540aSrobert   else if (GET_CODE (pattern) == PARALLEL)
5859*404b540aSrobert     {
5860*404b540aSrobert       for (i = 0, set = 0; i < XVECLEN (pattern, 0); i++)
5861*404b540aSrobert 	{
5862*404b540aSrobert 	  rtx sub = XVECEXP (pattern, 0, i);
5863*404b540aSrobert 
5864*404b540aSrobert 	  switch (GET_CODE (sub))
5865*404b540aSrobert 	    {
5866*404b540aSrobert 	    case USE:
5867*404b540aSrobert 	    case CLOBBER:
5868*404b540aSrobert 	      break;
5869*404b540aSrobert 
5870*404b540aSrobert 	    case SET:
5871*404b540aSrobert 	      if (set)
5872*404b540aSrobert 		return 0;
5873*404b540aSrobert 	      else
5874*404b540aSrobert 		set = sub;
5875*404b540aSrobert 	      break;
5876*404b540aSrobert 
5877*404b540aSrobert 	    default:
5878*404b540aSrobert 	      return 0;
5879*404b540aSrobert 	    }
5880*404b540aSrobert 	}
5881*404b540aSrobert       return set;
5882*404b540aSrobert     }
5883*404b540aSrobert 
5884*404b540aSrobert   return 0;
5885*404b540aSrobert }
5886*404b540aSrobert 
5887*404b540aSrobert 
5888*404b540aSrobert /* A C expression to modify the code described by the conditional if
5889*404b540aSrobert    information CE_INFO with the new PATTERN in INSN.  If PATTERN is a null
5890*404b540aSrobert    pointer after the IFCVT_MODIFY_INSN macro executes, it is assumed that that
5891*404b540aSrobert    insn cannot be converted to be executed conditionally.  */
5892*404b540aSrobert 
5893*404b540aSrobert rtx
frv_ifcvt_modify_insn(ce_if_block_t * ce_info,rtx pattern,rtx insn)5894*404b540aSrobert frv_ifcvt_modify_insn (ce_if_block_t *ce_info,
5895*404b540aSrobert                        rtx pattern,
5896*404b540aSrobert                        rtx insn)
5897*404b540aSrobert {
5898*404b540aSrobert   rtx orig_ce_pattern = pattern;
5899*404b540aSrobert   rtx set;
5900*404b540aSrobert   rtx op0;
5901*404b540aSrobert   rtx op1;
5902*404b540aSrobert   rtx test;
5903*404b540aSrobert 
5904*404b540aSrobert   gcc_assert (GET_CODE (pattern) == COND_EXEC);
5905*404b540aSrobert 
5906*404b540aSrobert   test = COND_EXEC_TEST (pattern);
5907*404b540aSrobert   if (GET_CODE (test) == AND)
5908*404b540aSrobert     {
5909*404b540aSrobert       rtx cr = frv_ifcvt.cr_reg;
5910*404b540aSrobert       rtx test_reg;
5911*404b540aSrobert 
5912*404b540aSrobert       op0 = XEXP (test, 0);
5913*404b540aSrobert       if (! rtx_equal_p (cr, XEXP (op0, 0)))
5914*404b540aSrobert 	goto fail;
5915*404b540aSrobert 
5916*404b540aSrobert       op1 = XEXP (test, 1);
5917*404b540aSrobert       test_reg = XEXP (op1, 0);
5918*404b540aSrobert       if (GET_CODE (test_reg) != REG)
5919*404b540aSrobert 	goto fail;
5920*404b540aSrobert 
5921*404b540aSrobert       /* Is this the first nested if block in this sequence?  If so, generate
5922*404b540aSrobert          an andcr or andncr.  */
5923*404b540aSrobert       if (! frv_ifcvt.last_nested_if_cr)
5924*404b540aSrobert 	{
5925*404b540aSrobert 	  rtx and_op;
5926*404b540aSrobert 
5927*404b540aSrobert 	  frv_ifcvt.last_nested_if_cr = test_reg;
5928*404b540aSrobert 	  if (GET_CODE (op0) == NE)
5929*404b540aSrobert 	    and_op = gen_andcr (test_reg, cr, test_reg);
5930*404b540aSrobert 	  else
5931*404b540aSrobert 	    and_op = gen_andncr (test_reg, cr, test_reg);
5932*404b540aSrobert 
5933*404b540aSrobert 	  frv_ifcvt_add_insn (and_op, insn, TRUE);
5934*404b540aSrobert 	}
5935*404b540aSrobert 
5936*404b540aSrobert       /* If this isn't the first statement in the nested if sequence, see if we
5937*404b540aSrobert          are dealing with the same register.  */
5938*404b540aSrobert       else if (! rtx_equal_p (test_reg, frv_ifcvt.last_nested_if_cr))
5939*404b540aSrobert 	goto fail;
5940*404b540aSrobert 
5941*404b540aSrobert       COND_EXEC_TEST (pattern) = test = op1;
5942*404b540aSrobert     }
5943*404b540aSrobert 
5944*404b540aSrobert   /* If this isn't a nested if, reset state variables.  */
5945*404b540aSrobert   else
5946*404b540aSrobert     {
5947*404b540aSrobert       frv_ifcvt.last_nested_if_cr = NULL_RTX;
5948*404b540aSrobert     }
5949*404b540aSrobert 
5950*404b540aSrobert   set = single_set_pattern (pattern);
5951*404b540aSrobert   if (set)
5952*404b540aSrobert     {
5953*404b540aSrobert       rtx dest = SET_DEST (set);
5954*404b540aSrobert       rtx src = SET_SRC (set);
5955*404b540aSrobert       enum machine_mode mode = GET_MODE (dest);
5956*404b540aSrobert 
5957*404b540aSrobert       /* Check for normal binary operators.  */
5958*404b540aSrobert       if (mode == SImode && ARITHMETIC_P (src))
5959*404b540aSrobert 	{
5960*404b540aSrobert 	  op0 = XEXP (src, 0);
5961*404b540aSrobert 	  op1 = XEXP (src, 1);
5962*404b540aSrobert 
5963*404b540aSrobert 	  if (integer_register_operand (op0, SImode) && CONSTANT_P (op1))
5964*404b540aSrobert 	    {
5965*404b540aSrobert 	      op1 = frv_ifcvt_load_value (op1, insn);
5966*404b540aSrobert 	      if (op1)
5967*404b540aSrobert 		COND_EXEC_CODE (pattern)
5968*404b540aSrobert 		  = gen_rtx_SET (VOIDmode, dest, gen_rtx_fmt_ee (GET_CODE (src),
5969*404b540aSrobert 								 GET_MODE (src),
5970*404b540aSrobert 								 op0, op1));
5971*404b540aSrobert 	      else
5972*404b540aSrobert 		goto fail;
5973*404b540aSrobert 	    }
5974*404b540aSrobert 	}
5975*404b540aSrobert 
5976*404b540aSrobert       /* For multiply by a constant, we need to handle the sign extending
5977*404b540aSrobert          correctly.  Add a USE of the value after the multiply to prevent flow
5978*404b540aSrobert          from cratering because only one register out of the two were used.  */
5979*404b540aSrobert       else if (mode == DImode && GET_CODE (src) == MULT)
5980*404b540aSrobert 	{
5981*404b540aSrobert 	  op0 = XEXP (src, 0);
5982*404b540aSrobert 	  op1 = XEXP (src, 1);
5983*404b540aSrobert 	  if (GET_CODE (op0) == SIGN_EXTEND && GET_CODE (op1) == CONST_INT)
5984*404b540aSrobert 	    {
5985*404b540aSrobert 	      op1 = frv_ifcvt_load_value (op1, insn);
5986*404b540aSrobert 	      if (op1)
5987*404b540aSrobert 		{
5988*404b540aSrobert 		  op1 = gen_rtx_SIGN_EXTEND (DImode, op1);
5989*404b540aSrobert 		  COND_EXEC_CODE (pattern)
5990*404b540aSrobert 		    = gen_rtx_SET (VOIDmode, dest,
5991*404b540aSrobert 				   gen_rtx_MULT (DImode, op0, op1));
5992*404b540aSrobert 		}
5993*404b540aSrobert 	      else
5994*404b540aSrobert 		goto fail;
5995*404b540aSrobert 	    }
5996*404b540aSrobert 
5997*404b540aSrobert 	  frv_ifcvt_add_insn (gen_rtx_USE (VOIDmode, dest), insn, FALSE);
5998*404b540aSrobert 	}
5999*404b540aSrobert 
6000*404b540aSrobert       /* If we are just loading a constant created for a nested conditional
6001*404b540aSrobert          execution statement, just load the constant without any conditional
6002*404b540aSrobert          execution, since we know that the constant will not interfere with any
6003*404b540aSrobert          other registers.  */
6004*404b540aSrobert       else if (frv_ifcvt.scratch_insns_bitmap
6005*404b540aSrobert 	       && bitmap_bit_p (frv_ifcvt.scratch_insns_bitmap,
6006*404b540aSrobert 				INSN_UID (insn))
6007*404b540aSrobert 	       && REG_P (SET_DEST (set))
6008*404b540aSrobert 	       /* We must not unconditionally set a scratch reg chosen
6009*404b540aSrobert 		  for a nested if-converted block if its incoming
6010*404b540aSrobert 		  value from the TEST block (or the result of the THEN
6011*404b540aSrobert 		  branch) could/should propagate to the JOIN block.
6012*404b540aSrobert 		  It suffices to test whether the register is live at
6013*404b540aSrobert 		  the JOIN point: if it's live there, we can infer
6014*404b540aSrobert 		  that we set it in the former JOIN block of the
6015*404b540aSrobert 		  nested if-converted block (otherwise it wouldn't
6016*404b540aSrobert 		  have been available as a scratch register), and it
6017*404b540aSrobert 		  is either propagated through or set in the other
6018*404b540aSrobert 		  conditional block.  It's probably not worth trying
6019*404b540aSrobert 		  to catch the latter case, and it could actually
6020*404b540aSrobert 		  limit scheduling of the combined block quite
6021*404b540aSrobert 		  severely.  */
6022*404b540aSrobert 	       && ce_info->join_bb
6023*404b540aSrobert 	       && ! (REGNO_REG_SET_P
6024*404b540aSrobert 		     (ce_info->join_bb->il.rtl->global_live_at_start,
6025*404b540aSrobert 		      REGNO (SET_DEST (set))))
6026*404b540aSrobert 	       /* Similarly, we must not unconditionally set a reg
6027*404b540aSrobert 		  used as scratch in the THEN branch if the same reg
6028*404b540aSrobert 		  is live in the ELSE branch.  */
6029*404b540aSrobert 	       && (! ce_info->else_bb
6030*404b540aSrobert 		   || BLOCK_FOR_INSN (insn) == ce_info->else_bb
6031*404b540aSrobert 		   || ! (REGNO_REG_SET_P
6032*404b540aSrobert 			 (ce_info->else_bb->il.rtl->global_live_at_start,
6033*404b540aSrobert 			  REGNO (SET_DEST (set))))))
6034*404b540aSrobert 	pattern = set;
6035*404b540aSrobert 
6036*404b540aSrobert       else if (mode == QImode || mode == HImode || mode == SImode
6037*404b540aSrobert 	       || mode == SFmode)
6038*404b540aSrobert 	{
6039*404b540aSrobert 	  int changed_p = FALSE;
6040*404b540aSrobert 
6041*404b540aSrobert 	  /* Check for just loading up a constant */
6042*404b540aSrobert 	  if (CONSTANT_P (src) && integer_register_operand (dest, mode))
6043*404b540aSrobert 	    {
6044*404b540aSrobert 	      src = frv_ifcvt_load_value (src, insn);
6045*404b540aSrobert 	      if (!src)
6046*404b540aSrobert 		goto fail;
6047*404b540aSrobert 
6048*404b540aSrobert 	      changed_p = TRUE;
6049*404b540aSrobert 	    }
6050*404b540aSrobert 
6051*404b540aSrobert 	  /* See if we need to fix up stores */
6052*404b540aSrobert 	  if (GET_CODE (dest) == MEM)
6053*404b540aSrobert 	    {
6054*404b540aSrobert 	      rtx new_mem = frv_ifcvt_rewrite_mem (dest, mode, insn);
6055*404b540aSrobert 
6056*404b540aSrobert 	      if (!new_mem)
6057*404b540aSrobert 		goto fail;
6058*404b540aSrobert 
6059*404b540aSrobert 	      else if (new_mem != dest)
6060*404b540aSrobert 		{
6061*404b540aSrobert 		  changed_p = TRUE;
6062*404b540aSrobert 		  dest = new_mem;
6063*404b540aSrobert 		}
6064*404b540aSrobert 	    }
6065*404b540aSrobert 
6066*404b540aSrobert 	  /* See if we need to fix up loads */
6067*404b540aSrobert 	  if (GET_CODE (src) == MEM)
6068*404b540aSrobert 	    {
6069*404b540aSrobert 	      rtx new_mem = frv_ifcvt_rewrite_mem (src, mode, insn);
6070*404b540aSrobert 
6071*404b540aSrobert 	      if (!new_mem)
6072*404b540aSrobert 		goto fail;
6073*404b540aSrobert 
6074*404b540aSrobert 	      else if (new_mem != src)
6075*404b540aSrobert 		{
6076*404b540aSrobert 		  changed_p = TRUE;
6077*404b540aSrobert 		  src = new_mem;
6078*404b540aSrobert 		}
6079*404b540aSrobert 	    }
6080*404b540aSrobert 
6081*404b540aSrobert 	  /* If either src or destination changed, redo SET.  */
6082*404b540aSrobert 	  if (changed_p)
6083*404b540aSrobert 	    COND_EXEC_CODE (pattern) = gen_rtx_SET (VOIDmode, dest, src);
6084*404b540aSrobert 	}
6085*404b540aSrobert 
6086*404b540aSrobert       /* Rewrite a nested set cccr in terms of IF_THEN_ELSE.  Also deal with
6087*404b540aSrobert          rewriting the CC register to be the same as the paired CC/CR register
6088*404b540aSrobert          for nested ifs.  */
6089*404b540aSrobert       else if (mode == CC_CCRmode && COMPARISON_P (src))
6090*404b540aSrobert 	{
6091*404b540aSrobert 	  int regno = REGNO (XEXP (src, 0));
6092*404b540aSrobert 	  rtx if_else;
6093*404b540aSrobert 
6094*404b540aSrobert 	  if (ce_info->pass > 1
6095*404b540aSrobert 	      && regno != (int)REGNO (frv_ifcvt.nested_cc_reg)
6096*404b540aSrobert 	      && TEST_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite, regno))
6097*404b540aSrobert 	    {
6098*404b540aSrobert 	      src = gen_rtx_fmt_ee (GET_CODE (src),
6099*404b540aSrobert 				    CC_CCRmode,
6100*404b540aSrobert 				    frv_ifcvt.nested_cc_reg,
6101*404b540aSrobert 				    XEXP (src, 1));
6102*404b540aSrobert 	    }
6103*404b540aSrobert 
6104*404b540aSrobert 	  if_else = gen_rtx_IF_THEN_ELSE (CC_CCRmode, test, src, const0_rtx);
6105*404b540aSrobert 	  pattern = gen_rtx_SET (VOIDmode, dest, if_else);
6106*404b540aSrobert 	}
6107*404b540aSrobert 
6108*404b540aSrobert       /* Remap a nested compare instruction to use the paired CC/CR reg.  */
6109*404b540aSrobert       else if (ce_info->pass > 1
6110*404b540aSrobert 	       && GET_CODE (dest) == REG
6111*404b540aSrobert 	       && CC_P (REGNO (dest))
6112*404b540aSrobert 	       && REGNO (dest) != REGNO (frv_ifcvt.nested_cc_reg)
6113*404b540aSrobert 	       && TEST_HARD_REG_BIT (frv_ifcvt.nested_cc_ok_rewrite,
6114*404b540aSrobert 				     REGNO (dest))
6115*404b540aSrobert 	       && GET_CODE (src) == COMPARE)
6116*404b540aSrobert 	{
6117*404b540aSrobert 	  PUT_MODE (frv_ifcvt.nested_cc_reg, GET_MODE (dest));
6118*404b540aSrobert 	  COND_EXEC_CODE (pattern)
6119*404b540aSrobert 	    = gen_rtx_SET (VOIDmode, frv_ifcvt.nested_cc_reg, copy_rtx (src));
6120*404b540aSrobert 	}
6121*404b540aSrobert     }
6122*404b540aSrobert 
6123*404b540aSrobert   if (TARGET_DEBUG_COND_EXEC)
6124*404b540aSrobert     {
6125*404b540aSrobert       rtx orig_pattern = PATTERN (insn);
6126*404b540aSrobert 
6127*404b540aSrobert       PATTERN (insn) = pattern;
6128*404b540aSrobert       fprintf (stderr,
6129*404b540aSrobert 	       "\n:::::::::: frv_ifcvt_modify_insn: pass = %d, insn after modification:\n",
6130*404b540aSrobert 	       ce_info->pass);
6131*404b540aSrobert 
6132*404b540aSrobert       debug_rtx (insn);
6133*404b540aSrobert       PATTERN (insn) = orig_pattern;
6134*404b540aSrobert     }
6135*404b540aSrobert 
6136*404b540aSrobert   return pattern;
6137*404b540aSrobert 
6138*404b540aSrobert  fail:
6139*404b540aSrobert   if (TARGET_DEBUG_COND_EXEC)
6140*404b540aSrobert     {
6141*404b540aSrobert       rtx orig_pattern = PATTERN (insn);
6142*404b540aSrobert 
6143*404b540aSrobert       PATTERN (insn) = orig_ce_pattern;
6144*404b540aSrobert       fprintf (stderr,
6145*404b540aSrobert 	       "\n:::::::::: frv_ifcvt_modify_insn: pass = %d, insn could not be modified:\n",
6146*404b540aSrobert 	       ce_info->pass);
6147*404b540aSrobert 
6148*404b540aSrobert       debug_rtx (insn);
6149*404b540aSrobert       PATTERN (insn) = orig_pattern;
6150*404b540aSrobert     }
6151*404b540aSrobert 
6152*404b540aSrobert   return NULL_RTX;
6153*404b540aSrobert }
6154*404b540aSrobert 
6155*404b540aSrobert 
6156*404b540aSrobert /* A C expression to perform any final machine dependent modifications in
6157*404b540aSrobert    converting code to conditional execution in the code described by the
6158*404b540aSrobert    conditional if information CE_INFO.  */
6159*404b540aSrobert 
6160*404b540aSrobert void
frv_ifcvt_modify_final(ce_if_block_t * ce_info ATTRIBUTE_UNUSED)6161*404b540aSrobert frv_ifcvt_modify_final (ce_if_block_t *ce_info ATTRIBUTE_UNUSED)
6162*404b540aSrobert {
6163*404b540aSrobert   rtx existing_insn;
6164*404b540aSrobert   rtx check_insn;
6165*404b540aSrobert   rtx p = frv_ifcvt.added_insns_list;
6166*404b540aSrobert   int i;
6167*404b540aSrobert 
6168*404b540aSrobert   /* Loop inserting the check insns.  The last check insn is the first test,
6169*404b540aSrobert      and is the appropriate place to insert constants.  */
6170*404b540aSrobert   gcc_assert (p);
6171*404b540aSrobert 
6172*404b540aSrobert   do
6173*404b540aSrobert     {
6174*404b540aSrobert       rtx check_and_insert_insns = XEXP (p, 0);
6175*404b540aSrobert       rtx old_p = p;
6176*404b540aSrobert 
6177*404b540aSrobert       check_insn = XEXP (check_and_insert_insns, 0);
6178*404b540aSrobert       existing_insn = XEXP (check_and_insert_insns, 1);
6179*404b540aSrobert       p = XEXP (p, 1);
6180*404b540aSrobert 
6181*404b540aSrobert       /* The jump bit is used to say that the new insn is to be inserted BEFORE
6182*404b540aSrobert          the existing insn, otherwise it is to be inserted AFTER.  */
6183*404b540aSrobert       if (check_and_insert_insns->jump)
6184*404b540aSrobert 	{
6185*404b540aSrobert 	  emit_insn_before (check_insn, existing_insn);
6186*404b540aSrobert 	  check_and_insert_insns->jump = 0;
6187*404b540aSrobert 	}
6188*404b540aSrobert       else
6189*404b540aSrobert 	emit_insn_after (check_insn, existing_insn);
6190*404b540aSrobert 
6191*404b540aSrobert       free_EXPR_LIST_node (check_and_insert_insns);
6192*404b540aSrobert       free_EXPR_LIST_node (old_p);
6193*404b540aSrobert     }
6194*404b540aSrobert   while (p != NULL_RTX);
6195*404b540aSrobert 
6196*404b540aSrobert   /* Load up any constants needed into temp gprs */
6197*404b540aSrobert   for (i = 0; i < frv_ifcvt.cur_scratch_regs; i++)
6198*404b540aSrobert     {
6199*404b540aSrobert       rtx insn = emit_insn_before (frv_ifcvt.scratch_regs[i], existing_insn);
6200*404b540aSrobert       if (! frv_ifcvt.scratch_insns_bitmap)
6201*404b540aSrobert 	frv_ifcvt.scratch_insns_bitmap = BITMAP_ALLOC (NULL);
6202*404b540aSrobert       bitmap_set_bit (frv_ifcvt.scratch_insns_bitmap, INSN_UID (insn));
6203*404b540aSrobert       frv_ifcvt.scratch_regs[i] = NULL_RTX;
6204*404b540aSrobert     }
6205*404b540aSrobert 
6206*404b540aSrobert   frv_ifcvt.added_insns_list = NULL_RTX;
6207*404b540aSrobert   frv_ifcvt.cur_scratch_regs = 0;
6208*404b540aSrobert }
6209*404b540aSrobert 
6210*404b540aSrobert 
6211*404b540aSrobert /* A C expression to cancel any machine dependent modifications in converting
6212*404b540aSrobert    code to conditional execution in the code described by the conditional if
6213*404b540aSrobert    information CE_INFO.  */
6214*404b540aSrobert 
6215*404b540aSrobert void
frv_ifcvt_modify_cancel(ce_if_block_t * ce_info ATTRIBUTE_UNUSED)6216*404b540aSrobert frv_ifcvt_modify_cancel (ce_if_block_t *ce_info ATTRIBUTE_UNUSED)
6217*404b540aSrobert {
6218*404b540aSrobert   int i;
6219*404b540aSrobert   rtx p = frv_ifcvt.added_insns_list;
6220*404b540aSrobert 
6221*404b540aSrobert   /* Loop freeing up the EXPR_LIST's allocated.  */
6222*404b540aSrobert   while (p != NULL_RTX)
6223*404b540aSrobert     {
6224*404b540aSrobert       rtx check_and_jump = XEXP (p, 0);
6225*404b540aSrobert       rtx old_p = p;
6226*404b540aSrobert 
6227*404b540aSrobert       p = XEXP (p, 1);
6228*404b540aSrobert       free_EXPR_LIST_node (check_and_jump);
6229*404b540aSrobert       free_EXPR_LIST_node (old_p);
6230*404b540aSrobert     }
6231*404b540aSrobert 
6232*404b540aSrobert   /* Release any temporary gprs allocated.  */
6233*404b540aSrobert   for (i = 0; i < frv_ifcvt.cur_scratch_regs; i++)
6234*404b540aSrobert     frv_ifcvt.scratch_regs[i] = NULL_RTX;
6235*404b540aSrobert 
6236*404b540aSrobert   frv_ifcvt.added_insns_list = NULL_RTX;
6237*404b540aSrobert   frv_ifcvt.cur_scratch_regs = 0;
6238*404b540aSrobert   return;
6239*404b540aSrobert }
6240*404b540aSrobert 
6241*404b540aSrobert /* A C expression for the size in bytes of the trampoline, as an integer.
6242*404b540aSrobert    The template is:
6243*404b540aSrobert 
6244*404b540aSrobert 	setlo #0, <jmp_reg>
6245*404b540aSrobert 	setlo #0, <static_chain>
6246*404b540aSrobert 	sethi #0, <jmp_reg>
6247*404b540aSrobert 	sethi #0, <static_chain>
6248*404b540aSrobert 	jmpl @(gr0,<jmp_reg>) */
6249*404b540aSrobert 
6250*404b540aSrobert int
frv_trampoline_size(void)6251*404b540aSrobert frv_trampoline_size (void)
6252*404b540aSrobert {
6253*404b540aSrobert   if (TARGET_FDPIC)
6254*404b540aSrobert     /* Allocate room for the function descriptor and the lddi
6255*404b540aSrobert        instruction.  */
6256*404b540aSrobert     return 8 + 6 * 4;
6257*404b540aSrobert   return 5 /* instructions */ * 4 /* instruction size.  */;
6258*404b540aSrobert }
6259*404b540aSrobert 
6260*404b540aSrobert 
6261*404b540aSrobert /* A C statement to initialize the variable parts of a trampoline.  ADDR is an
6262*404b540aSrobert    RTX for the address of the trampoline; FNADDR is an RTX for the address of
6263*404b540aSrobert    the nested function; STATIC_CHAIN is an RTX for the static chain value that
6264*404b540aSrobert    should be passed to the function when it is called.
6265*404b540aSrobert 
6266*404b540aSrobert    The template is:
6267*404b540aSrobert 
6268*404b540aSrobert 	setlo #0, <jmp_reg>
6269*404b540aSrobert 	setlo #0, <static_chain>
6270*404b540aSrobert 	sethi #0, <jmp_reg>
6271*404b540aSrobert 	sethi #0, <static_chain>
6272*404b540aSrobert 	jmpl @(gr0,<jmp_reg>) */
6273*404b540aSrobert 
6274*404b540aSrobert void
frv_initialize_trampoline(rtx addr,rtx fnaddr,rtx static_chain)6275*404b540aSrobert frv_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
6276*404b540aSrobert {
6277*404b540aSrobert   rtx sc_reg = force_reg (Pmode, static_chain);
6278*404b540aSrobert 
6279*404b540aSrobert   emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"),
6280*404b540aSrobert 		     FALSE, VOIDmode, 4,
6281*404b540aSrobert 		     addr, Pmode,
6282*404b540aSrobert 		     GEN_INT (frv_trampoline_size ()), SImode,
6283*404b540aSrobert 		     fnaddr, Pmode,
6284*404b540aSrobert 		     sc_reg, Pmode);
6285*404b540aSrobert }
6286*404b540aSrobert 
6287*404b540aSrobert 
6288*404b540aSrobert /* Many machines have some registers that cannot be copied directly to or from
6289*404b540aSrobert    memory or even from other types of registers.  An example is the `MQ'
6290*404b540aSrobert    register, which on most machines, can only be copied to or from general
6291*404b540aSrobert    registers, but not memory.  Some machines allow copying all registers to and
6292*404b540aSrobert    from memory, but require a scratch register for stores to some memory
6293*404b540aSrobert    locations (e.g., those with symbolic address on the RT, and those with
6294*404b540aSrobert    certain symbolic address on the SPARC when compiling PIC).  In some cases,
6295*404b540aSrobert    both an intermediate and a scratch register are required.
6296*404b540aSrobert 
6297*404b540aSrobert    You should define these macros to indicate to the reload phase that it may
6298*404b540aSrobert    need to allocate at least one register for a reload in addition to the
6299*404b540aSrobert    register to contain the data.  Specifically, if copying X to a register
6300*404b540aSrobert    CLASS in MODE requires an intermediate register, you should define
6301*404b540aSrobert    `SECONDARY_INPUT_RELOAD_CLASS' to return the largest register class all of
6302*404b540aSrobert    whose registers can be used as intermediate registers or scratch registers.
6303*404b540aSrobert 
6304*404b540aSrobert    If copying a register CLASS in MODE to X requires an intermediate or scratch
6305*404b540aSrobert    register, `SECONDARY_OUTPUT_RELOAD_CLASS' should be defined to return the
6306*404b540aSrobert    largest register class required.  If the requirements for input and output
6307*404b540aSrobert    reloads are the same, the macro `SECONDARY_RELOAD_CLASS' should be used
6308*404b540aSrobert    instead of defining both macros identically.
6309*404b540aSrobert 
6310*404b540aSrobert    The values returned by these macros are often `GENERAL_REGS'.  Return
6311*404b540aSrobert    `NO_REGS' if no spare register is needed; i.e., if X can be directly copied
6312*404b540aSrobert    to or from a register of CLASS in MODE without requiring a scratch register.
6313*404b540aSrobert    Do not define this macro if it would always return `NO_REGS'.
6314*404b540aSrobert 
6315*404b540aSrobert    If a scratch register is required (either with or without an intermediate
6316*404b540aSrobert    register), you should define patterns for `reload_inM' or `reload_outM', as
6317*404b540aSrobert    required..  These patterns, which will normally be implemented with a
6318*404b540aSrobert    `define_expand', should be similar to the `movM' patterns, except that
6319*404b540aSrobert    operand 2 is the scratch register.
6320*404b540aSrobert 
6321*404b540aSrobert    Define constraints for the reload register and scratch register that contain
6322*404b540aSrobert    a single register class.  If the original reload register (whose class is
6323*404b540aSrobert    CLASS) can meet the constraint given in the pattern, the value returned by
6324*404b540aSrobert    these macros is used for the class of the scratch register.  Otherwise, two
6325*404b540aSrobert    additional reload registers are required.  Their classes are obtained from
6326*404b540aSrobert    the constraints in the insn pattern.
6327*404b540aSrobert 
6328*404b540aSrobert    X might be a pseudo-register or a `subreg' of a pseudo-register, which could
6329*404b540aSrobert    either be in a hard register or in memory.  Use `true_regnum' to find out;
6330*404b540aSrobert    it will return -1 if the pseudo is in memory and the hard register number if
6331*404b540aSrobert    it is in a register.
6332*404b540aSrobert 
6333*404b540aSrobert    These macros should not be used in the case where a particular class of
6334*404b540aSrobert    registers can only be copied to memory and not to another class of
6335*404b540aSrobert    registers.  In that case, secondary reload registers are not needed and
6336*404b540aSrobert    would not be helpful.  Instead, a stack location must be used to perform the
6337*404b540aSrobert    copy and the `movM' pattern should use memory as an intermediate storage.
6338*404b540aSrobert    This case often occurs between floating-point and general registers.  */
6339*404b540aSrobert 
6340*404b540aSrobert enum reg_class
frv_secondary_reload_class(enum reg_class class,enum machine_mode mode ATTRIBUTE_UNUSED,rtx x,int in_p ATTRIBUTE_UNUSED)6341*404b540aSrobert frv_secondary_reload_class (enum reg_class class,
6342*404b540aSrobert                             enum machine_mode mode ATTRIBUTE_UNUSED,
6343*404b540aSrobert                             rtx x,
6344*404b540aSrobert                             int in_p ATTRIBUTE_UNUSED)
6345*404b540aSrobert {
6346*404b540aSrobert   enum reg_class ret;
6347*404b540aSrobert 
6348*404b540aSrobert   switch (class)
6349*404b540aSrobert     {
6350*404b540aSrobert     default:
6351*404b540aSrobert       ret = NO_REGS;
6352*404b540aSrobert       break;
6353*404b540aSrobert 
6354*404b540aSrobert       /* Accumulators/Accumulator guard registers need to go through floating
6355*404b540aSrobert          point registers.  */
6356*404b540aSrobert     case QUAD_REGS:
6357*404b540aSrobert     case EVEN_REGS:
6358*404b540aSrobert     case GPR_REGS:
6359*404b540aSrobert       ret = NO_REGS;
6360*404b540aSrobert       if (x && GET_CODE (x) == REG)
6361*404b540aSrobert 	{
6362*404b540aSrobert 	  int regno = REGNO (x);
6363*404b540aSrobert 
6364*404b540aSrobert 	  if (ACC_P (regno) || ACCG_P (regno))
6365*404b540aSrobert 	    ret = FPR_REGS;
6366*404b540aSrobert 	}
6367*404b540aSrobert       break;
6368*404b540aSrobert 
6369*404b540aSrobert       /* Nonzero constants should be loaded into an FPR through a GPR.  */
6370*404b540aSrobert     case QUAD_FPR_REGS:
6371*404b540aSrobert     case FEVEN_REGS:
6372*404b540aSrobert     case FPR_REGS:
6373*404b540aSrobert       if (x && CONSTANT_P (x) && !ZERO_P (x))
6374*404b540aSrobert 	ret = GPR_REGS;
6375*404b540aSrobert       else
6376*404b540aSrobert 	ret = NO_REGS;
6377*404b540aSrobert       break;
6378*404b540aSrobert 
6379*404b540aSrobert       /* All of these types need gpr registers.  */
6380*404b540aSrobert     case ICC_REGS:
6381*404b540aSrobert     case FCC_REGS:
6382*404b540aSrobert     case CC_REGS:
6383*404b540aSrobert     case ICR_REGS:
6384*404b540aSrobert     case FCR_REGS:
6385*404b540aSrobert     case CR_REGS:
6386*404b540aSrobert     case LCR_REG:
6387*404b540aSrobert     case LR_REG:
6388*404b540aSrobert       ret = GPR_REGS;
6389*404b540aSrobert       break;
6390*404b540aSrobert 
6391*404b540aSrobert       /* The accumulators need fpr registers */
6392*404b540aSrobert     case ACC_REGS:
6393*404b540aSrobert     case EVEN_ACC_REGS:
6394*404b540aSrobert     case QUAD_ACC_REGS:
6395*404b540aSrobert     case ACCG_REGS:
6396*404b540aSrobert       ret = FPR_REGS;
6397*404b540aSrobert       break;
6398*404b540aSrobert     }
6399*404b540aSrobert 
6400*404b540aSrobert   return ret;
6401*404b540aSrobert }
6402*404b540aSrobert 
6403*404b540aSrobert 
6404*404b540aSrobert /* A C expression whose value is nonzero if pseudos that have been assigned to
6405*404b540aSrobert    registers of class CLASS would likely be spilled because registers of CLASS
6406*404b540aSrobert    are needed for spill registers.
6407*404b540aSrobert 
6408*404b540aSrobert    The default value of this macro returns 1 if CLASS has exactly one register
6409*404b540aSrobert    and zero otherwise.  On most machines, this default should be used.  Only
6410*404b540aSrobert    define this macro to some other expression if pseudo allocated by
6411*404b540aSrobert    `local-alloc.c' end up in memory because their hard registers were needed
6412*404b540aSrobert    for spill registers.  If this macro returns nonzero for those classes, those
6413*404b540aSrobert    pseudos will only be allocated by `global.c', which knows how to reallocate
6414*404b540aSrobert    the pseudo to another register.  If there would not be another register
6415*404b540aSrobert    available for reallocation, you should not change the definition of this
6416*404b540aSrobert    macro since the only effect of such a definition would be to slow down
6417*404b540aSrobert    register allocation.  */
6418*404b540aSrobert 
6419*404b540aSrobert int
frv_class_likely_spilled_p(enum reg_class class)6420*404b540aSrobert frv_class_likely_spilled_p (enum reg_class class)
6421*404b540aSrobert {
6422*404b540aSrobert   switch (class)
6423*404b540aSrobert     {
6424*404b540aSrobert     default:
6425*404b540aSrobert       break;
6426*404b540aSrobert 
6427*404b540aSrobert     case GR8_REGS:
6428*404b540aSrobert     case GR9_REGS:
6429*404b540aSrobert     case GR89_REGS:
6430*404b540aSrobert     case FDPIC_FPTR_REGS:
6431*404b540aSrobert     case FDPIC_REGS:
6432*404b540aSrobert     case ICC_REGS:
6433*404b540aSrobert     case FCC_REGS:
6434*404b540aSrobert     case CC_REGS:
6435*404b540aSrobert     case ICR_REGS:
6436*404b540aSrobert     case FCR_REGS:
6437*404b540aSrobert     case CR_REGS:
6438*404b540aSrobert     case LCR_REG:
6439*404b540aSrobert     case LR_REG:
6440*404b540aSrobert     case SPR_REGS:
6441*404b540aSrobert     case QUAD_ACC_REGS:
6442*404b540aSrobert     case EVEN_ACC_REGS:
6443*404b540aSrobert     case ACC_REGS:
6444*404b540aSrobert     case ACCG_REGS:
6445*404b540aSrobert       return TRUE;
6446*404b540aSrobert     }
6447*404b540aSrobert 
6448*404b540aSrobert   return FALSE;
6449*404b540aSrobert }
6450*404b540aSrobert 
6451*404b540aSrobert 
6452*404b540aSrobert /* An expression for the alignment of a structure field FIELD if the
6453*404b540aSrobert    alignment computed in the usual way is COMPUTED.  GCC uses this
6454*404b540aSrobert    value instead of the value in `BIGGEST_ALIGNMENT' or
6455*404b540aSrobert    `BIGGEST_FIELD_ALIGNMENT', if defined, for structure fields only.  */
6456*404b540aSrobert 
6457*404b540aSrobert /* The definition type of the bit field data is either char, short, long or
6458*404b540aSrobert    long long. The maximum bit size is the number of bits of its own type.
6459*404b540aSrobert 
6460*404b540aSrobert    The bit field data is assigned to a storage unit that has an adequate size
6461*404b540aSrobert    for bit field data retention and is located at the smallest address.
6462*404b540aSrobert 
6463*404b540aSrobert    Consecutive bit field data are packed at consecutive bits having the same
6464*404b540aSrobert    storage unit, with regard to the type, beginning with the MSB and continuing
6465*404b540aSrobert    toward the LSB.
6466*404b540aSrobert 
6467*404b540aSrobert    If a field to be assigned lies over a bit field type boundary, its
6468*404b540aSrobert    assignment is completed by aligning it with a boundary suitable for the
6469*404b540aSrobert    type.
6470*404b540aSrobert 
6471*404b540aSrobert    When a bit field having a bit length of 0 is declared, it is forcibly
6472*404b540aSrobert    assigned to the next storage unit.
6473*404b540aSrobert 
6474*404b540aSrobert    e.g)
6475*404b540aSrobert 	struct {
6476*404b540aSrobert 		int	a:2;
6477*404b540aSrobert 		int	b:6;
6478*404b540aSrobert 		char	c:4;
6479*404b540aSrobert 		int	d:10;
6480*404b540aSrobert 		int	 :0;
6481*404b540aSrobert 		int	f:2;
6482*404b540aSrobert 	} x;
6483*404b540aSrobert 
6484*404b540aSrobert 		+0	  +1	    +2	      +3
6485*404b540aSrobert 	&x	00000000  00000000  00000000  00000000
6486*404b540aSrobert 		MLM----L
6487*404b540aSrobert 		a    b
6488*404b540aSrobert 	&x+4	00000000  00000000  00000000  00000000
6489*404b540aSrobert 		M--L
6490*404b540aSrobert 		c
6491*404b540aSrobert 	&x+8	00000000  00000000  00000000  00000000
6492*404b540aSrobert 		M----------L
6493*404b540aSrobert 		d
6494*404b540aSrobert 	&x+12	00000000  00000000  00000000  00000000
6495*404b540aSrobert 		ML
6496*404b540aSrobert 		f
6497*404b540aSrobert */
6498*404b540aSrobert 
6499*404b540aSrobert int
frv_adjust_field_align(tree field,int computed)6500*404b540aSrobert frv_adjust_field_align (tree field, int computed)
6501*404b540aSrobert {
6502*404b540aSrobert   /* Make sure that the bitfield is not wider than the type.  */
6503*404b540aSrobert   if (DECL_BIT_FIELD (field)
6504*404b540aSrobert       && !DECL_ARTIFICIAL (field))
6505*404b540aSrobert     {
6506*404b540aSrobert       tree parent = DECL_CONTEXT (field);
6507*404b540aSrobert       tree prev = NULL_TREE;
6508*404b540aSrobert       tree cur;
6509*404b540aSrobert 
6510*404b540aSrobert       for (cur = TYPE_FIELDS (parent); cur && cur != field; cur = TREE_CHAIN (cur))
6511*404b540aSrobert 	{
6512*404b540aSrobert 	  if (TREE_CODE (cur) != FIELD_DECL)
6513*404b540aSrobert 	    continue;
6514*404b540aSrobert 
6515*404b540aSrobert 	  prev = cur;
6516*404b540aSrobert 	}
6517*404b540aSrobert 
6518*404b540aSrobert       gcc_assert (cur);
6519*404b540aSrobert 
6520*404b540aSrobert       /* If this isn't a :0 field and if the previous element is a bitfield
6521*404b540aSrobert 	 also, see if the type is different, if so, we will need to align the
6522*404b540aSrobert 	 bit-field to the next boundary.  */
6523*404b540aSrobert       if (prev
6524*404b540aSrobert 	  && ! DECL_PACKED (field)
6525*404b540aSrobert 	  && ! integer_zerop (DECL_SIZE (field))
6526*404b540aSrobert 	  && DECL_BIT_FIELD_TYPE (field) != DECL_BIT_FIELD_TYPE (prev))
6527*404b540aSrobert 	{
6528*404b540aSrobert 	  int prev_align = TYPE_ALIGN (TREE_TYPE (prev));
6529*404b540aSrobert 	  int cur_align  = TYPE_ALIGN (TREE_TYPE (field));
6530*404b540aSrobert 	  computed = (prev_align > cur_align) ? prev_align : cur_align;
6531*404b540aSrobert 	}
6532*404b540aSrobert     }
6533*404b540aSrobert 
6534*404b540aSrobert   return computed;
6535*404b540aSrobert }
6536*404b540aSrobert 
6537*404b540aSrobert 
6538*404b540aSrobert /* A C expression that is nonzero if it is permissible to store a value of mode
6539*404b540aSrobert    MODE in hard register number REGNO (or in several registers starting with
6540*404b540aSrobert    that one).  For a machine where all registers are equivalent, a suitable
6541*404b540aSrobert    definition is
6542*404b540aSrobert 
6543*404b540aSrobert         #define HARD_REGNO_MODE_OK(REGNO, MODE) 1
6544*404b540aSrobert 
6545*404b540aSrobert    It is not necessary for this macro to check for the numbers of fixed
6546*404b540aSrobert    registers, because the allocation mechanism considers them to be always
6547*404b540aSrobert    occupied.
6548*404b540aSrobert 
6549*404b540aSrobert    On some machines, double-precision values must be kept in even/odd register
6550*404b540aSrobert    pairs.  The way to implement that is to define this macro to reject odd
6551*404b540aSrobert    register numbers for such modes.
6552*404b540aSrobert 
6553*404b540aSrobert    The minimum requirement for a mode to be OK in a register is that the
6554*404b540aSrobert    `movMODE' instruction pattern support moves between the register and any
6555*404b540aSrobert    other hard register for which the mode is OK; and that moving a value into
6556*404b540aSrobert    the register and back out not alter it.
6557*404b540aSrobert 
6558*404b540aSrobert    Since the same instruction used to move `SImode' will work for all narrower
6559*404b540aSrobert    integer modes, it is not necessary on any machine for `HARD_REGNO_MODE_OK'
6560*404b540aSrobert    to distinguish between these modes, provided you define patterns `movhi',
6561*404b540aSrobert    etc., to take advantage of this.  This is useful because of the interaction
6562*404b540aSrobert    between `HARD_REGNO_MODE_OK' and `MODES_TIEABLE_P'; it is very desirable for
6563*404b540aSrobert    all integer modes to be tieable.
6564*404b540aSrobert 
6565*404b540aSrobert    Many machines have special registers for floating point arithmetic.  Often
6566*404b540aSrobert    people assume that floating point machine modes are allowed only in floating
6567*404b540aSrobert    point registers.  This is not true.  Any registers that can hold integers
6568*404b540aSrobert    can safely *hold* a floating point machine mode, whether or not floating
6569*404b540aSrobert    arithmetic can be done on it in those registers.  Integer move instructions
6570*404b540aSrobert    can be used to move the values.
6571*404b540aSrobert 
6572*404b540aSrobert    On some machines, though, the converse is true: fixed-point machine modes
6573*404b540aSrobert    may not go in floating registers.  This is true if the floating registers
6574*404b540aSrobert    normalize any value stored in them, because storing a non-floating value
6575*404b540aSrobert    there would garble it.  In this case, `HARD_REGNO_MODE_OK' should reject
6576*404b540aSrobert    fixed-point machine modes in floating registers.  But if the floating
6577*404b540aSrobert    registers do not automatically normalize, if you can store any bit pattern
6578*404b540aSrobert    in one and retrieve it unchanged without a trap, then any machine mode may
6579*404b540aSrobert    go in a floating register, so you can define this macro to say so.
6580*404b540aSrobert 
6581*404b540aSrobert    The primary significance of special floating registers is rather that they
6582*404b540aSrobert    are the registers acceptable in floating point arithmetic instructions.
6583*404b540aSrobert    However, this is of no concern to `HARD_REGNO_MODE_OK'.  You handle it by
6584*404b540aSrobert    writing the proper constraints for those instructions.
6585*404b540aSrobert 
6586*404b540aSrobert    On some machines, the floating registers are especially slow to access, so
6587*404b540aSrobert    that it is better to store a value in a stack frame than in such a register
6588*404b540aSrobert    if floating point arithmetic is not being done.  As long as the floating
6589*404b540aSrobert    registers are not in class `GENERAL_REGS', they will not be used unless some
6590*404b540aSrobert    pattern's constraint asks for one.  */
6591*404b540aSrobert 
6592*404b540aSrobert int
frv_hard_regno_mode_ok(int regno,enum machine_mode mode)6593*404b540aSrobert frv_hard_regno_mode_ok (int regno, enum machine_mode mode)
6594*404b540aSrobert {
6595*404b540aSrobert   int base;
6596*404b540aSrobert   int mask;
6597*404b540aSrobert 
6598*404b540aSrobert   switch (mode)
6599*404b540aSrobert     {
6600*404b540aSrobert     case CCmode:
6601*404b540aSrobert     case CC_UNSmode:
6602*404b540aSrobert     case CC_NZmode:
6603*404b540aSrobert       return ICC_P (regno) || GPR_P (regno);
6604*404b540aSrobert 
6605*404b540aSrobert     case CC_CCRmode:
6606*404b540aSrobert       return CR_P (regno) || GPR_P (regno);
6607*404b540aSrobert 
6608*404b540aSrobert     case CC_FPmode:
6609*404b540aSrobert       return FCC_P (regno) || GPR_P (regno);
6610*404b540aSrobert 
6611*404b540aSrobert     default:
6612*404b540aSrobert       break;
6613*404b540aSrobert     }
6614*404b540aSrobert 
6615*404b540aSrobert   /* Set BASE to the first register in REGNO's class.  Set MASK to the
6616*404b540aSrobert      bits that must be clear in (REGNO - BASE) for the register to be
6617*404b540aSrobert      well-aligned.  */
6618*404b540aSrobert   if (INTEGRAL_MODE_P (mode) || FLOAT_MODE_P (mode) || VECTOR_MODE_P (mode))
6619*404b540aSrobert     {
6620*404b540aSrobert       if (ACCG_P (regno))
6621*404b540aSrobert 	{
6622*404b540aSrobert 	  /* ACCGs store one byte.  Two-byte quantities must start in
6623*404b540aSrobert 	     even-numbered registers, four-byte ones in registers whose
6624*404b540aSrobert 	     numbers are divisible by four, and so on.  */
6625*404b540aSrobert 	  base = ACCG_FIRST;
6626*404b540aSrobert 	  mask = GET_MODE_SIZE (mode) - 1;
6627*404b540aSrobert 	}
6628*404b540aSrobert       else
6629*404b540aSrobert 	{
6630*404b540aSrobert 	   /* The other registers store one word.  */
6631*404b540aSrobert 	  if (GPR_P (regno) || regno == AP_FIRST)
6632*404b540aSrobert 	    base = GPR_FIRST;
6633*404b540aSrobert 
6634*404b540aSrobert 	  else if (FPR_P (regno))
6635*404b540aSrobert 	    base = FPR_FIRST;
6636*404b540aSrobert 
6637*404b540aSrobert 	  else if (ACC_P (regno))
6638*404b540aSrobert 	    base = ACC_FIRST;
6639*404b540aSrobert 
6640*404b540aSrobert 	  else if (SPR_P (regno))
6641*404b540aSrobert 	    return mode == SImode;
6642*404b540aSrobert 
6643*404b540aSrobert 	  /* Fill in the table.  */
6644*404b540aSrobert 	  else
6645*404b540aSrobert 	    return 0;
6646*404b540aSrobert 
6647*404b540aSrobert 	  /* Anything smaller than an SI is OK in any word-sized register.  */
6648*404b540aSrobert 	  if (GET_MODE_SIZE (mode) < 4)
6649*404b540aSrobert 	    return 1;
6650*404b540aSrobert 
6651*404b540aSrobert 	  mask = (GET_MODE_SIZE (mode) / 4) - 1;
6652*404b540aSrobert 	}
6653*404b540aSrobert       return (((regno - base) & mask) == 0);
6654*404b540aSrobert     }
6655*404b540aSrobert 
6656*404b540aSrobert   return 0;
6657*404b540aSrobert }
6658*404b540aSrobert 
6659*404b540aSrobert 
6660*404b540aSrobert /* A C expression for the number of consecutive hard registers, starting at
6661*404b540aSrobert    register number REGNO, required to hold a value of mode MODE.
6662*404b540aSrobert 
6663*404b540aSrobert    On a machine where all registers are exactly one word, a suitable definition
6664*404b540aSrobert    of this macro is
6665*404b540aSrobert 
6666*404b540aSrobert         #define HARD_REGNO_NREGS(REGNO, MODE)            \
6667*404b540aSrobert            ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1)  \
6668*404b540aSrobert             / UNITS_PER_WORD))  */
6669*404b540aSrobert 
6670*404b540aSrobert /* On the FRV, make the CC_FP mode take 3 words in the integer registers, so
6671*404b540aSrobert    that we can build the appropriate instructions to properly reload the
6672*404b540aSrobert    values.  Also, make the byte-sized accumulator guards use one guard
6673*404b540aSrobert    for each byte.  */
6674*404b540aSrobert 
6675*404b540aSrobert int
frv_hard_regno_nregs(int regno,enum machine_mode mode)6676*404b540aSrobert frv_hard_regno_nregs (int regno, enum machine_mode mode)
6677*404b540aSrobert {
6678*404b540aSrobert   if (ACCG_P (regno))
6679*404b540aSrobert     return GET_MODE_SIZE (mode);
6680*404b540aSrobert   else
6681*404b540aSrobert     return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
6682*404b540aSrobert }
6683*404b540aSrobert 
6684*404b540aSrobert 
6685*404b540aSrobert /* A C expression for the maximum number of consecutive registers of
6686*404b540aSrobert    class CLASS needed to hold a value of mode MODE.
6687*404b540aSrobert 
6688*404b540aSrobert    This is closely related to the macro `HARD_REGNO_NREGS'.  In fact, the value
6689*404b540aSrobert    of the macro `CLASS_MAX_NREGS (CLASS, MODE)' should be the maximum value of
6690*404b540aSrobert    `HARD_REGNO_NREGS (REGNO, MODE)' for all REGNO values in the class CLASS.
6691*404b540aSrobert 
6692*404b540aSrobert    This macro helps control the handling of multiple-word values in
6693*404b540aSrobert    the reload pass.
6694*404b540aSrobert 
6695*404b540aSrobert    This declaration is required.  */
6696*404b540aSrobert 
6697*404b540aSrobert int
frv_class_max_nregs(enum reg_class class,enum machine_mode mode)6698*404b540aSrobert frv_class_max_nregs (enum reg_class class, enum machine_mode mode)
6699*404b540aSrobert {
6700*404b540aSrobert   if (class == ACCG_REGS)
6701*404b540aSrobert     /* An N-byte value requires N accumulator guards.  */
6702*404b540aSrobert     return GET_MODE_SIZE (mode);
6703*404b540aSrobert   else
6704*404b540aSrobert     return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
6705*404b540aSrobert }
6706*404b540aSrobert 
6707*404b540aSrobert 
6708*404b540aSrobert /* A C expression that is nonzero if X is a legitimate constant for an
6709*404b540aSrobert    immediate operand on the target machine.  You can assume that X satisfies
6710*404b540aSrobert    `CONSTANT_P', so you need not check this.  In fact, `1' is a suitable
6711*404b540aSrobert    definition for this macro on machines where anything `CONSTANT_P' is valid.  */
6712*404b540aSrobert 
6713*404b540aSrobert int
frv_legitimate_constant_p(rtx x)6714*404b540aSrobert frv_legitimate_constant_p (rtx x)
6715*404b540aSrobert {
6716*404b540aSrobert   enum machine_mode mode = GET_MODE (x);
6717*404b540aSrobert 
6718*404b540aSrobert   /* frv_cannot_force_const_mem always returns true for FDPIC.  This
6719*404b540aSrobert      means that the move expanders will be expected to deal with most
6720*404b540aSrobert      kinds of constant, regardless of what we return here.
6721*404b540aSrobert 
6722*404b540aSrobert      However, among its other duties, LEGITIMATE_CONSTANT_P decides whether
6723*404b540aSrobert      a constant can be entered into reg_equiv_constant[].  If we return true,
6724*404b540aSrobert      reload can create new instances of the constant whenever it likes.
6725*404b540aSrobert 
6726*404b540aSrobert      The idea is therefore to accept as many constants as possible (to give
6727*404b540aSrobert      reload more freedom) while rejecting constants that can only be created
6728*404b540aSrobert      at certain times.  In particular, anything with a symbolic component will
6729*404b540aSrobert      require use of the pseudo FDPIC register, which is only available before
6730*404b540aSrobert      reload.  */
6731*404b540aSrobert   if (TARGET_FDPIC)
6732*404b540aSrobert     return LEGITIMATE_PIC_OPERAND_P (x);
6733*404b540aSrobert 
6734*404b540aSrobert   /* All of the integer constants are ok.  */
6735*404b540aSrobert   if (GET_CODE (x) != CONST_DOUBLE)
6736*404b540aSrobert     return TRUE;
6737*404b540aSrobert 
6738*404b540aSrobert   /* double integer constants are ok.  */
6739*404b540aSrobert   if (mode == VOIDmode || mode == DImode)
6740*404b540aSrobert     return TRUE;
6741*404b540aSrobert 
6742*404b540aSrobert   /* 0 is always ok.  */
6743*404b540aSrobert   if (x == CONST0_RTX (mode))
6744*404b540aSrobert     return TRUE;
6745*404b540aSrobert 
6746*404b540aSrobert   /* If floating point is just emulated, allow any constant, since it will be
6747*404b540aSrobert      constructed in the GPRs.  */
6748*404b540aSrobert   if (!TARGET_HAS_FPRS)
6749*404b540aSrobert     return TRUE;
6750*404b540aSrobert 
6751*404b540aSrobert   if (mode == DFmode && !TARGET_DOUBLE)
6752*404b540aSrobert     return TRUE;
6753*404b540aSrobert 
6754*404b540aSrobert   /* Otherwise store the constant away and do a load.  */
6755*404b540aSrobert   return FALSE;
6756*404b540aSrobert }
6757*404b540aSrobert 
6758*404b540aSrobert /* Implement SELECT_CC_MODE.  Choose CC_FP for floating-point comparisons,
6759*404b540aSrobert    CC_NZ for comparisons against zero in which a single Z or N flag test
6760*404b540aSrobert    is enough, CC_UNS for other unsigned comparisons, and CC for other
6761*404b540aSrobert    signed comparisons.  */
6762*404b540aSrobert 
6763*404b540aSrobert enum machine_mode
frv_select_cc_mode(enum rtx_code code,rtx x,rtx y)6764*404b540aSrobert frv_select_cc_mode (enum rtx_code code, rtx x, rtx y)
6765*404b540aSrobert {
6766*404b540aSrobert   if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
6767*404b540aSrobert     return CC_FPmode;
6768*404b540aSrobert 
6769*404b540aSrobert   switch (code)
6770*404b540aSrobert     {
6771*404b540aSrobert     case EQ:
6772*404b540aSrobert     case NE:
6773*404b540aSrobert     case LT:
6774*404b540aSrobert     case GE:
6775*404b540aSrobert       return y == const0_rtx ? CC_NZmode : CCmode;
6776*404b540aSrobert 
6777*404b540aSrobert     case GTU:
6778*404b540aSrobert     case GEU:
6779*404b540aSrobert     case LTU:
6780*404b540aSrobert     case LEU:
6781*404b540aSrobert       return y == const0_rtx ? CC_NZmode : CC_UNSmode;
6782*404b540aSrobert 
6783*404b540aSrobert     default:
6784*404b540aSrobert       return CCmode;
6785*404b540aSrobert     }
6786*404b540aSrobert }
6787*404b540aSrobert 
6788*404b540aSrobert /* A C expression for the cost of moving data from a register in class FROM to
6789*404b540aSrobert    one in class TO.  The classes are expressed using the enumeration values
6790*404b540aSrobert    such as `GENERAL_REGS'.  A value of 4 is the default; other values are
6791*404b540aSrobert    interpreted relative to that.
6792*404b540aSrobert 
6793*404b540aSrobert    It is not required that the cost always equal 2 when FROM is the same as TO;
6794*404b540aSrobert    on some machines it is expensive to move between registers if they are not
6795*404b540aSrobert    general registers.
6796*404b540aSrobert 
6797*404b540aSrobert    If reload sees an insn consisting of a single `set' between two hard
6798*404b540aSrobert    registers, and if `REGISTER_MOVE_COST' applied to their classes returns a
6799*404b540aSrobert    value of 2, reload does not check to ensure that the constraints of the insn
6800*404b540aSrobert    are met.  Setting a cost of other than 2 will allow reload to verify that
6801*404b540aSrobert    the constraints are met.  You should do this if the `movM' pattern's
6802*404b540aSrobert    constraints do not allow such copying.  */
6803*404b540aSrobert 
6804*404b540aSrobert #define HIGH_COST 40
6805*404b540aSrobert #define MEDIUM_COST 3
6806*404b540aSrobert #define LOW_COST 1
6807*404b540aSrobert 
6808*404b540aSrobert int
frv_register_move_cost(enum reg_class from,enum reg_class to)6809*404b540aSrobert frv_register_move_cost (enum reg_class from, enum reg_class to)
6810*404b540aSrobert {
6811*404b540aSrobert   switch (from)
6812*404b540aSrobert     {
6813*404b540aSrobert     default:
6814*404b540aSrobert       break;
6815*404b540aSrobert 
6816*404b540aSrobert     case QUAD_REGS:
6817*404b540aSrobert     case EVEN_REGS:
6818*404b540aSrobert     case GPR_REGS:
6819*404b540aSrobert       switch (to)
6820*404b540aSrobert 	{
6821*404b540aSrobert 	default:
6822*404b540aSrobert 	  break;
6823*404b540aSrobert 
6824*404b540aSrobert 	case QUAD_REGS:
6825*404b540aSrobert 	case EVEN_REGS:
6826*404b540aSrobert 	case GPR_REGS:
6827*404b540aSrobert 	  return LOW_COST;
6828*404b540aSrobert 
6829*404b540aSrobert 	case FEVEN_REGS:
6830*404b540aSrobert 	case FPR_REGS:
6831*404b540aSrobert 	  return LOW_COST;
6832*404b540aSrobert 
6833*404b540aSrobert 	case LCR_REG:
6834*404b540aSrobert 	case LR_REG:
6835*404b540aSrobert 	case SPR_REGS:
6836*404b540aSrobert 	  return LOW_COST;
6837*404b540aSrobert 	}
6838*404b540aSrobert 
6839*404b540aSrobert     case FEVEN_REGS:
6840*404b540aSrobert     case FPR_REGS:
6841*404b540aSrobert       switch (to)
6842*404b540aSrobert 	{
6843*404b540aSrobert 	default:
6844*404b540aSrobert 	  break;
6845*404b540aSrobert 
6846*404b540aSrobert 	case QUAD_REGS:
6847*404b540aSrobert 	case EVEN_REGS:
6848*404b540aSrobert 	case GPR_REGS:
6849*404b540aSrobert 	case ACC_REGS:
6850*404b540aSrobert 	case EVEN_ACC_REGS:
6851*404b540aSrobert 	case QUAD_ACC_REGS:
6852*404b540aSrobert 	case ACCG_REGS:
6853*404b540aSrobert 	  return MEDIUM_COST;
6854*404b540aSrobert 
6855*404b540aSrobert 	case FEVEN_REGS:
6856*404b540aSrobert 	case FPR_REGS:
6857*404b540aSrobert 	  return LOW_COST;
6858*404b540aSrobert 	}
6859*404b540aSrobert 
6860*404b540aSrobert     case LCR_REG:
6861*404b540aSrobert     case LR_REG:
6862*404b540aSrobert     case SPR_REGS:
6863*404b540aSrobert       switch (to)
6864*404b540aSrobert 	{
6865*404b540aSrobert 	default:
6866*404b540aSrobert 	  break;
6867*404b540aSrobert 
6868*404b540aSrobert 	case QUAD_REGS:
6869*404b540aSrobert 	case EVEN_REGS:
6870*404b540aSrobert 	case GPR_REGS:
6871*404b540aSrobert 	  return MEDIUM_COST;
6872*404b540aSrobert 	}
6873*404b540aSrobert 
6874*404b540aSrobert     case ACC_REGS:
6875*404b540aSrobert     case EVEN_ACC_REGS:
6876*404b540aSrobert     case QUAD_ACC_REGS:
6877*404b540aSrobert     case ACCG_REGS:
6878*404b540aSrobert       switch (to)
6879*404b540aSrobert 	{
6880*404b540aSrobert 	default:
6881*404b540aSrobert 	  break;
6882*404b540aSrobert 
6883*404b540aSrobert 	case FEVEN_REGS:
6884*404b540aSrobert 	case FPR_REGS:
6885*404b540aSrobert 	  return MEDIUM_COST;
6886*404b540aSrobert 
6887*404b540aSrobert 	}
6888*404b540aSrobert     }
6889*404b540aSrobert 
6890*404b540aSrobert   return HIGH_COST;
6891*404b540aSrobert }
6892*404b540aSrobert 
6893*404b540aSrobert /* Implementation of TARGET_ASM_INTEGER.  In the FRV case we need to
6894*404b540aSrobert    use ".picptr" to generate safe relocations for PIC code.  We also
6895*404b540aSrobert    need a fixup entry for aligned (non-debugging) code.  */
6896*404b540aSrobert 
6897*404b540aSrobert static bool
frv_assemble_integer(rtx value,unsigned int size,int aligned_p)6898*404b540aSrobert frv_assemble_integer (rtx value, unsigned int size, int aligned_p)
6899*404b540aSrobert {
6900*404b540aSrobert   if ((flag_pic || TARGET_FDPIC) && size == UNITS_PER_WORD)
6901*404b540aSrobert     {
6902*404b540aSrobert       if (GET_CODE (value) == CONST
6903*404b540aSrobert 	  || GET_CODE (value) == SYMBOL_REF
6904*404b540aSrobert 	  || GET_CODE (value) == LABEL_REF)
6905*404b540aSrobert 	{
6906*404b540aSrobert 	  if (TARGET_FDPIC && GET_CODE (value) == SYMBOL_REF
6907*404b540aSrobert 	      && SYMBOL_REF_FUNCTION_P (value))
6908*404b540aSrobert 	    {
6909*404b540aSrobert 	      fputs ("\t.picptr\tfuncdesc(", asm_out_file);
6910*404b540aSrobert 	      output_addr_const (asm_out_file, value);
6911*404b540aSrobert 	      fputs (")\n", asm_out_file);
6912*404b540aSrobert 	      return true;
6913*404b540aSrobert 	    }
6914*404b540aSrobert 	  else if (TARGET_FDPIC && GET_CODE (value) == CONST
6915*404b540aSrobert 		   && frv_function_symbol_referenced_p (value))
6916*404b540aSrobert 	    return false;
6917*404b540aSrobert 	  if (aligned_p && !TARGET_FDPIC)
6918*404b540aSrobert 	    {
6919*404b540aSrobert 	      static int label_num = 0;
6920*404b540aSrobert 	      char buf[256];
6921*404b540aSrobert 	      const char *p;
6922*404b540aSrobert 
6923*404b540aSrobert 	      ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", label_num++);
6924*404b540aSrobert 	      p = (* targetm.strip_name_encoding) (buf);
6925*404b540aSrobert 
6926*404b540aSrobert 	      fprintf (asm_out_file, "%s:\n", p);
6927*404b540aSrobert 	      fprintf (asm_out_file, "%s\n", FIXUP_SECTION_ASM_OP);
6928*404b540aSrobert 	      fprintf (asm_out_file, "\t.picptr\t%s\n", p);
6929*404b540aSrobert 	      fprintf (asm_out_file, "\t.previous\n");
6930*404b540aSrobert 	    }
6931*404b540aSrobert 	  assemble_integer_with_op ("\t.picptr\t", value);
6932*404b540aSrobert 	  return true;
6933*404b540aSrobert 	}
6934*404b540aSrobert       if (!aligned_p)
6935*404b540aSrobert 	{
6936*404b540aSrobert 	  /* We've set the unaligned SI op to NULL, so we always have to
6937*404b540aSrobert 	     handle the unaligned case here.  */
6938*404b540aSrobert 	  assemble_integer_with_op ("\t.4byte\t", value);
6939*404b540aSrobert 	  return true;
6940*404b540aSrobert 	}
6941*404b540aSrobert     }
6942*404b540aSrobert   return default_assemble_integer (value, size, aligned_p);
6943*404b540aSrobert }
6944*404b540aSrobert 
6945*404b540aSrobert /* Function to set up the backend function structure.  */
6946*404b540aSrobert 
6947*404b540aSrobert static struct machine_function *
frv_init_machine_status(void)6948*404b540aSrobert frv_init_machine_status (void)
6949*404b540aSrobert {
6950*404b540aSrobert   return ggc_alloc_cleared (sizeof (struct machine_function));
6951*404b540aSrobert }
6952*404b540aSrobert 
6953*404b540aSrobert /* Implement TARGET_SCHED_ISSUE_RATE.  */
6954*404b540aSrobert 
6955*404b540aSrobert int
frv_issue_rate(void)6956*404b540aSrobert frv_issue_rate (void)
6957*404b540aSrobert {
6958*404b540aSrobert   if (!TARGET_PACK)
6959*404b540aSrobert     return 1;
6960*404b540aSrobert 
6961*404b540aSrobert   switch (frv_cpu_type)
6962*404b540aSrobert     {
6963*404b540aSrobert     default:
6964*404b540aSrobert     case FRV_CPU_FR300:
6965*404b540aSrobert     case FRV_CPU_SIMPLE:
6966*404b540aSrobert       return 1;
6967*404b540aSrobert 
6968*404b540aSrobert     case FRV_CPU_FR400:
6969*404b540aSrobert     case FRV_CPU_FR405:
6970*404b540aSrobert     case FRV_CPU_FR450:
6971*404b540aSrobert       return 2;
6972*404b540aSrobert 
6973*404b540aSrobert     case FRV_CPU_GENERIC:
6974*404b540aSrobert     case FRV_CPU_FR500:
6975*404b540aSrobert     case FRV_CPU_TOMCAT:
6976*404b540aSrobert       return 4;
6977*404b540aSrobert 
6978*404b540aSrobert     case FRV_CPU_FR550:
6979*404b540aSrobert       return 8;
6980*404b540aSrobert     }
6981*404b540aSrobert }
6982*404b540aSrobert 
6983*404b540aSrobert /* A for_each_rtx callback.  If X refers to an accumulator, return
6984*404b540aSrobert    ACC_GROUP_ODD if the bit 2 of the register number is set and
6985*404b540aSrobert    ACC_GROUP_EVEN if it is clear.  Return 0 (ACC_GROUP_NONE)
6986*404b540aSrobert    otherwise.  */
6987*404b540aSrobert 
6988*404b540aSrobert static int
frv_acc_group_1(rtx * x,void * data ATTRIBUTE_UNUSED)6989*404b540aSrobert frv_acc_group_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
6990*404b540aSrobert {
6991*404b540aSrobert   if (REG_P (*x))
6992*404b540aSrobert     {
6993*404b540aSrobert       if (ACC_P (REGNO (*x)))
6994*404b540aSrobert 	return (REGNO (*x) - ACC_FIRST) & 4 ? ACC_GROUP_ODD : ACC_GROUP_EVEN;
6995*404b540aSrobert       if (ACCG_P (REGNO (*x)))
6996*404b540aSrobert 	return (REGNO (*x) - ACCG_FIRST) & 4 ? ACC_GROUP_ODD : ACC_GROUP_EVEN;
6997*404b540aSrobert     }
6998*404b540aSrobert   return 0;
6999*404b540aSrobert }
7000*404b540aSrobert 
7001*404b540aSrobert /* Return the value of INSN's acc_group attribute.  */
7002*404b540aSrobert 
7003*404b540aSrobert int
frv_acc_group(rtx insn)7004*404b540aSrobert frv_acc_group (rtx insn)
7005*404b540aSrobert {
7006*404b540aSrobert   /* This distinction only applies to the FR550 packing constraints.  */
7007*404b540aSrobert   if (frv_cpu_type != FRV_CPU_FR550)
7008*404b540aSrobert     return ACC_GROUP_NONE;
7009*404b540aSrobert   return for_each_rtx (&PATTERN (insn), frv_acc_group_1, 0);
7010*404b540aSrobert }
7011*404b540aSrobert 
7012*404b540aSrobert /* Return the index of the DFA unit in FRV_UNIT_NAMES[] that instruction
7013*404b540aSrobert    INSN will try to claim first.  Since this value depends only on the
7014*404b540aSrobert    type attribute, we can cache the results in FRV_TYPE_TO_UNIT[].  */
7015*404b540aSrobert 
7016*404b540aSrobert static unsigned int
frv_insn_unit(rtx insn)7017*404b540aSrobert frv_insn_unit (rtx insn)
7018*404b540aSrobert {
7019*404b540aSrobert   enum attr_type type;
7020*404b540aSrobert 
7021*404b540aSrobert   type = get_attr_type (insn);
7022*404b540aSrobert   if (frv_type_to_unit[type] == ARRAY_SIZE (frv_unit_codes))
7023*404b540aSrobert     {
7024*404b540aSrobert       /* We haven't seen this type of instruction before.  */
7025*404b540aSrobert       state_t state;
7026*404b540aSrobert       unsigned int unit;
7027*404b540aSrobert 
7028*404b540aSrobert       /* Issue the instruction on its own to see which unit it prefers.  */
7029*404b540aSrobert       state = alloca (state_size ());
7030*404b540aSrobert       state_reset (state);
7031*404b540aSrobert       state_transition (state, insn);
7032*404b540aSrobert 
7033*404b540aSrobert       /* Find out which unit was taken.  */
7034*404b540aSrobert       for (unit = 0; unit < ARRAY_SIZE (frv_unit_codes); unit++)
7035*404b540aSrobert 	if (cpu_unit_reservation_p (state, frv_unit_codes[unit]))
7036*404b540aSrobert 	  break;
7037*404b540aSrobert 
7038*404b540aSrobert       gcc_assert (unit != ARRAY_SIZE (frv_unit_codes));
7039*404b540aSrobert 
7040*404b540aSrobert       frv_type_to_unit[type] = unit;
7041*404b540aSrobert     }
7042*404b540aSrobert   return frv_type_to_unit[type];
7043*404b540aSrobert }
7044*404b540aSrobert 
7045*404b540aSrobert /* Return true if INSN issues to a branch unit.  */
7046*404b540aSrobert 
7047*404b540aSrobert static bool
frv_issues_to_branch_unit_p(rtx insn)7048*404b540aSrobert frv_issues_to_branch_unit_p (rtx insn)
7049*404b540aSrobert {
7050*404b540aSrobert   return frv_unit_groups[frv_insn_unit (insn)] == GROUP_B;
7051*404b540aSrobert }
7052*404b540aSrobert 
7053*404b540aSrobert /* The current state of the packing pass, implemented by frv_pack_insns.  */
7054*404b540aSrobert static struct {
7055*404b540aSrobert   /* The state of the pipeline DFA.  */
7056*404b540aSrobert   state_t dfa_state;
7057*404b540aSrobert 
7058*404b540aSrobert   /* Which hardware registers are set within the current packet,
7059*404b540aSrobert      and the conditions under which they are set.  */
7060*404b540aSrobert   regstate_t regstate[FIRST_PSEUDO_REGISTER];
7061*404b540aSrobert 
7062*404b540aSrobert   /* The memory locations that have been modified so far in this
7063*404b540aSrobert      packet.  MEM is the memref and COND is the regstate_t condition
7064*404b540aSrobert      under which it is set.  */
7065*404b540aSrobert   struct {
7066*404b540aSrobert     rtx mem;
7067*404b540aSrobert     regstate_t cond;
7068*404b540aSrobert   } mems[2];
7069*404b540aSrobert 
7070*404b540aSrobert   /* The number of valid entries in MEMS.  The value is larger than
7071*404b540aSrobert      ARRAY_SIZE (mems) if there were too many mems to record.  */
7072*404b540aSrobert   unsigned int num_mems;
7073*404b540aSrobert 
7074*404b540aSrobert   /* The maximum number of instructions that can be packed together.  */
7075*404b540aSrobert   unsigned int issue_rate;
7076*404b540aSrobert 
7077*404b540aSrobert   /* The instructions in the packet, partitioned into groups.  */
7078*404b540aSrobert   struct frv_packet_group {
7079*404b540aSrobert     /* How many instructions in the packet belong to this group.  */
7080*404b540aSrobert     unsigned int num_insns;
7081*404b540aSrobert 
7082*404b540aSrobert     /* A list of the instructions that belong to this group, in the order
7083*404b540aSrobert        they appear in the rtl stream.  */
7084*404b540aSrobert     rtx insns[ARRAY_SIZE (frv_unit_codes)];
7085*404b540aSrobert 
7086*404b540aSrobert     /* The contents of INSNS after they have been sorted into the correct
7087*404b540aSrobert        assembly-language order.  Element X issues to unit X.  The list may
7088*404b540aSrobert        contain extra nops.  */
7089*404b540aSrobert     rtx sorted[ARRAY_SIZE (frv_unit_codes)];
7090*404b540aSrobert 
7091*404b540aSrobert     /* The member of frv_nops[] to use in sorted[].  */
7092*404b540aSrobert     rtx nop;
7093*404b540aSrobert   } groups[NUM_GROUPS];
7094*404b540aSrobert 
7095*404b540aSrobert   /* The instructions that make up the current packet.  */
7096*404b540aSrobert   rtx insns[ARRAY_SIZE (frv_unit_codes)];
7097*404b540aSrobert   unsigned int num_insns;
7098*404b540aSrobert } frv_packet;
7099*404b540aSrobert 
7100*404b540aSrobert /* Return the regstate_t flags for the given COND_EXEC condition.
7101*404b540aSrobert    Abort if the condition isn't in the right form.  */
7102*404b540aSrobert 
7103*404b540aSrobert static int
frv_cond_flags(rtx cond)7104*404b540aSrobert frv_cond_flags (rtx cond)
7105*404b540aSrobert {
7106*404b540aSrobert   gcc_assert ((GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
7107*404b540aSrobert 	      && GET_CODE (XEXP (cond, 0)) == REG
7108*404b540aSrobert 	      && CR_P (REGNO (XEXP (cond, 0)))
7109*404b540aSrobert 	      && XEXP (cond, 1) == const0_rtx);
7110*404b540aSrobert   return ((REGNO (XEXP (cond, 0)) - CR_FIRST)
7111*404b540aSrobert 	  | (GET_CODE (cond) == NE
7112*404b540aSrobert 	     ? REGSTATE_IF_TRUE
7113*404b540aSrobert 	     : REGSTATE_IF_FALSE));
7114*404b540aSrobert }
7115*404b540aSrobert 
7116*404b540aSrobert 
7117*404b540aSrobert /* Return true if something accessed under condition COND2 can
7118*404b540aSrobert    conflict with something written under condition COND1.  */
7119*404b540aSrobert 
7120*404b540aSrobert static bool
frv_regstate_conflict_p(regstate_t cond1,regstate_t cond2)7121*404b540aSrobert frv_regstate_conflict_p (regstate_t cond1, regstate_t cond2)
7122*404b540aSrobert {
7123*404b540aSrobert   /* If either reference was unconditional, we have a conflict.  */
7124*404b540aSrobert   if ((cond1 & REGSTATE_IF_EITHER) == 0
7125*404b540aSrobert       || (cond2 & REGSTATE_IF_EITHER) == 0)
7126*404b540aSrobert     return true;
7127*404b540aSrobert 
7128*404b540aSrobert   /* The references might conflict if they were controlled by
7129*404b540aSrobert      different CRs.  */
7130*404b540aSrobert   if ((cond1 & REGSTATE_CC_MASK) != (cond2 & REGSTATE_CC_MASK))
7131*404b540aSrobert     return true;
7132*404b540aSrobert 
7133*404b540aSrobert   /* They definitely conflict if they are controlled by the
7134*404b540aSrobert      same condition.  */
7135*404b540aSrobert   if ((cond1 & cond2 & REGSTATE_IF_EITHER) != 0)
7136*404b540aSrobert     return true;
7137*404b540aSrobert 
7138*404b540aSrobert   return false;
7139*404b540aSrobert }
7140*404b540aSrobert 
7141*404b540aSrobert 
7142*404b540aSrobert /* A for_each_rtx callback.  Return 1 if *X depends on an instruction in
7143*404b540aSrobert    the current packet.  DATA points to a regstate_t that describes the
7144*404b540aSrobert    condition under which *X might be set or used.  */
7145*404b540aSrobert 
7146*404b540aSrobert static int
frv_registers_conflict_p_1(rtx * x,void * data)7147*404b540aSrobert frv_registers_conflict_p_1 (rtx *x, void *data)
7148*404b540aSrobert {
7149*404b540aSrobert   unsigned int regno, i;
7150*404b540aSrobert   regstate_t cond;
7151*404b540aSrobert 
7152*404b540aSrobert   cond = *(regstate_t *) data;
7153*404b540aSrobert 
7154*404b540aSrobert   if (GET_CODE (*x) == REG)
7155*404b540aSrobert     FOR_EACH_REGNO (regno, *x)
7156*404b540aSrobert       if ((frv_packet.regstate[regno] & REGSTATE_MODIFIED) != 0)
7157*404b540aSrobert 	if (frv_regstate_conflict_p (frv_packet.regstate[regno], cond))
7158*404b540aSrobert 	  return 1;
7159*404b540aSrobert 
7160*404b540aSrobert   if (GET_CODE (*x) == MEM)
7161*404b540aSrobert     {
7162*404b540aSrobert       /* If we ran out of memory slots, assume a conflict.  */
7163*404b540aSrobert       if (frv_packet.num_mems > ARRAY_SIZE (frv_packet.mems))
7164*404b540aSrobert 	return 1;
7165*404b540aSrobert 
7166*404b540aSrobert       /* Check for output or true dependencies with earlier MEMs.  */
7167*404b540aSrobert       for (i = 0; i < frv_packet.num_mems; i++)
7168*404b540aSrobert 	if (frv_regstate_conflict_p (frv_packet.mems[i].cond, cond))
7169*404b540aSrobert 	  {
7170*404b540aSrobert 	    if (true_dependence (frv_packet.mems[i].mem, VOIDmode,
7171*404b540aSrobert 				 *x, rtx_varies_p))
7172*404b540aSrobert 	      return 1;
7173*404b540aSrobert 
7174*404b540aSrobert 	    if (output_dependence (frv_packet.mems[i].mem, *x))
7175*404b540aSrobert 	      return 1;
7176*404b540aSrobert 	  }
7177*404b540aSrobert     }
7178*404b540aSrobert 
7179*404b540aSrobert   /* The return values of calls aren't significant: they describe
7180*404b540aSrobert      the effect of the call as a whole, not of the insn itself.  */
7181*404b540aSrobert   if (GET_CODE (*x) == SET && GET_CODE (SET_SRC (*x)) == CALL)
7182*404b540aSrobert     {
7183*404b540aSrobert       if (for_each_rtx (&SET_SRC (*x), frv_registers_conflict_p_1, data))
7184*404b540aSrobert 	return 1;
7185*404b540aSrobert       return -1;
7186*404b540aSrobert     }
7187*404b540aSrobert 
7188*404b540aSrobert   /* Check subexpressions.  */
7189*404b540aSrobert   return 0;
7190*404b540aSrobert }
7191*404b540aSrobert 
7192*404b540aSrobert 
7193*404b540aSrobert /* Return true if something in X might depend on an instruction
7194*404b540aSrobert    in the current packet.  */
7195*404b540aSrobert 
7196*404b540aSrobert static bool
frv_registers_conflict_p(rtx x)7197*404b540aSrobert frv_registers_conflict_p (rtx x)
7198*404b540aSrobert {
7199*404b540aSrobert   regstate_t flags;
7200*404b540aSrobert 
7201*404b540aSrobert   flags = 0;
7202*404b540aSrobert   if (GET_CODE (x) == COND_EXEC)
7203*404b540aSrobert     {
7204*404b540aSrobert       if (for_each_rtx (&XEXP (x, 0), frv_registers_conflict_p_1, &flags))
7205*404b540aSrobert 	return true;
7206*404b540aSrobert 
7207*404b540aSrobert       flags |= frv_cond_flags (XEXP (x, 0));
7208*404b540aSrobert       x = XEXP (x, 1);
7209*404b540aSrobert     }
7210*404b540aSrobert   return for_each_rtx (&x, frv_registers_conflict_p_1, &flags);
7211*404b540aSrobert }
7212*404b540aSrobert 
7213*404b540aSrobert 
7214*404b540aSrobert /* A note_stores callback.  DATA points to the regstate_t condition
7215*404b540aSrobert    under which X is modified.  Update FRV_PACKET accordingly.  */
7216*404b540aSrobert 
7217*404b540aSrobert static void
frv_registers_update_1(rtx x,rtx pat ATTRIBUTE_UNUSED,void * data)7218*404b540aSrobert frv_registers_update_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
7219*404b540aSrobert {
7220*404b540aSrobert   unsigned int regno;
7221*404b540aSrobert 
7222*404b540aSrobert   if (GET_CODE (x) == REG)
7223*404b540aSrobert     FOR_EACH_REGNO (regno, x)
7224*404b540aSrobert       frv_packet.regstate[regno] |= *(regstate_t *) data;
7225*404b540aSrobert 
7226*404b540aSrobert   if (GET_CODE (x) == MEM)
7227*404b540aSrobert     {
7228*404b540aSrobert       if (frv_packet.num_mems < ARRAY_SIZE (frv_packet.mems))
7229*404b540aSrobert 	{
7230*404b540aSrobert 	  frv_packet.mems[frv_packet.num_mems].mem = x;
7231*404b540aSrobert 	  frv_packet.mems[frv_packet.num_mems].cond = *(regstate_t *) data;
7232*404b540aSrobert 	}
7233*404b540aSrobert       frv_packet.num_mems++;
7234*404b540aSrobert     }
7235*404b540aSrobert }
7236*404b540aSrobert 
7237*404b540aSrobert 
7238*404b540aSrobert /* Update the register state information for an instruction whose
7239*404b540aSrobert    body is X.  */
7240*404b540aSrobert 
7241*404b540aSrobert static void
frv_registers_update(rtx x)7242*404b540aSrobert frv_registers_update (rtx x)
7243*404b540aSrobert {
7244*404b540aSrobert   regstate_t flags;
7245*404b540aSrobert 
7246*404b540aSrobert   flags = REGSTATE_MODIFIED;
7247*404b540aSrobert   if (GET_CODE (x) == COND_EXEC)
7248*404b540aSrobert     {
7249*404b540aSrobert       flags |= frv_cond_flags (XEXP (x, 0));
7250*404b540aSrobert       x = XEXP (x, 1);
7251*404b540aSrobert     }
7252*404b540aSrobert   note_stores (x, frv_registers_update_1, &flags);
7253*404b540aSrobert }
7254*404b540aSrobert 
7255*404b540aSrobert 
7256*404b540aSrobert /* Initialize frv_packet for the start of a new packet.  */
7257*404b540aSrobert 
7258*404b540aSrobert static void
frv_start_packet(void)7259*404b540aSrobert frv_start_packet (void)
7260*404b540aSrobert {
7261*404b540aSrobert   enum frv_insn_group group;
7262*404b540aSrobert 
7263*404b540aSrobert   memset (frv_packet.regstate, 0, sizeof (frv_packet.regstate));
7264*404b540aSrobert   frv_packet.num_mems = 0;
7265*404b540aSrobert   frv_packet.num_insns = 0;
7266*404b540aSrobert   for (group = 0; group < NUM_GROUPS; group++)
7267*404b540aSrobert     frv_packet.groups[group].num_insns = 0;
7268*404b540aSrobert }
7269*404b540aSrobert 
7270*404b540aSrobert 
7271*404b540aSrobert /* Likewise for the start of a new basic block.  */
7272*404b540aSrobert 
7273*404b540aSrobert static void
frv_start_packet_block(void)7274*404b540aSrobert frv_start_packet_block (void)
7275*404b540aSrobert {
7276*404b540aSrobert   state_reset (frv_packet.dfa_state);
7277*404b540aSrobert   frv_start_packet ();
7278*404b540aSrobert }
7279*404b540aSrobert 
7280*404b540aSrobert 
7281*404b540aSrobert /* Finish the current packet, if any, and start a new one.  Call
7282*404b540aSrobert    HANDLE_PACKET with FRV_PACKET describing the completed packet.  */
7283*404b540aSrobert 
7284*404b540aSrobert static void
frv_finish_packet(void (* handle_packet)(void))7285*404b540aSrobert frv_finish_packet (void (*handle_packet) (void))
7286*404b540aSrobert {
7287*404b540aSrobert   if (frv_packet.num_insns > 0)
7288*404b540aSrobert     {
7289*404b540aSrobert       handle_packet ();
7290*404b540aSrobert       state_transition (frv_packet.dfa_state, 0);
7291*404b540aSrobert       frv_start_packet ();
7292*404b540aSrobert     }
7293*404b540aSrobert }
7294*404b540aSrobert 
7295*404b540aSrobert 
7296*404b540aSrobert /* Return true if INSN can be added to the current packet.  Update
7297*404b540aSrobert    the DFA state on success.  */
7298*404b540aSrobert 
7299*404b540aSrobert static bool
frv_pack_insn_p(rtx insn)7300*404b540aSrobert frv_pack_insn_p (rtx insn)
7301*404b540aSrobert {
7302*404b540aSrobert   /* See if the packet is already as long as it can be.  */
7303*404b540aSrobert   if (frv_packet.num_insns == frv_packet.issue_rate)
7304*404b540aSrobert     return false;
7305*404b540aSrobert 
7306*404b540aSrobert   /* If the scheduler thought that an instruction should start a packet,
7307*404b540aSrobert      it's usually a good idea to believe it.  It knows much more about
7308*404b540aSrobert      the latencies than we do.
7309*404b540aSrobert 
7310*404b540aSrobert      There are some exceptions though:
7311*404b540aSrobert 
7312*404b540aSrobert        - Conditional instructions are scheduled on the assumption that
7313*404b540aSrobert 	 they will be executed.  This is usually a good thing, since it
7314*404b540aSrobert 	 tends to avoid unnecessary stalls in the conditional code.
7315*404b540aSrobert 	 But we want to pack conditional instructions as tightly as
7316*404b540aSrobert 	 possible, in order to optimize the case where they aren't
7317*404b540aSrobert 	 executed.
7318*404b540aSrobert 
7319*404b540aSrobert        - The scheduler will always put branches on their own, even
7320*404b540aSrobert 	 if there's no real dependency.
7321*404b540aSrobert 
7322*404b540aSrobert        - There's no point putting a call in its own packet unless
7323*404b540aSrobert 	 we have to.  */
7324*404b540aSrobert   if (frv_packet.num_insns > 0
7325*404b540aSrobert       && GET_CODE (insn) == INSN
7326*404b540aSrobert       && GET_MODE (insn) == TImode
7327*404b540aSrobert       && GET_CODE (PATTERN (insn)) != COND_EXEC)
7328*404b540aSrobert     return false;
7329*404b540aSrobert 
7330*404b540aSrobert   /* Check for register conflicts.  Don't do this for setlo since any
7331*404b540aSrobert      conflict will be with the partnering sethi, with which it can
7332*404b540aSrobert      be packed.  */
7333*404b540aSrobert   if (get_attr_type (insn) != TYPE_SETLO)
7334*404b540aSrobert     if (frv_registers_conflict_p (PATTERN (insn)))
7335*404b540aSrobert       return false;
7336*404b540aSrobert 
7337*404b540aSrobert   return state_transition (frv_packet.dfa_state, insn) < 0;
7338*404b540aSrobert }
7339*404b540aSrobert 
7340*404b540aSrobert 
7341*404b540aSrobert /* Add instruction INSN to the current packet.  */
7342*404b540aSrobert 
7343*404b540aSrobert static void
frv_add_insn_to_packet(rtx insn)7344*404b540aSrobert frv_add_insn_to_packet (rtx insn)
7345*404b540aSrobert {
7346*404b540aSrobert   struct frv_packet_group *packet_group;
7347*404b540aSrobert 
7348*404b540aSrobert   packet_group = &frv_packet.groups[frv_unit_groups[frv_insn_unit (insn)]];
7349*404b540aSrobert   packet_group->insns[packet_group->num_insns++] = insn;
7350*404b540aSrobert   frv_packet.insns[frv_packet.num_insns++] = insn;
7351*404b540aSrobert 
7352*404b540aSrobert   frv_registers_update (PATTERN (insn));
7353*404b540aSrobert }
7354*404b540aSrobert 
7355*404b540aSrobert 
7356*404b540aSrobert /* Insert INSN (a member of frv_nops[]) into the current packet.  If the
7357*404b540aSrobert    packet ends in a branch or call, insert the nop before it, otherwise
7358*404b540aSrobert    add to the end.  */
7359*404b540aSrobert 
7360*404b540aSrobert static void
frv_insert_nop_in_packet(rtx insn)7361*404b540aSrobert frv_insert_nop_in_packet (rtx insn)
7362*404b540aSrobert {
7363*404b540aSrobert   struct frv_packet_group *packet_group;
7364*404b540aSrobert   rtx last;
7365*404b540aSrobert 
7366*404b540aSrobert   packet_group = &frv_packet.groups[frv_unit_groups[frv_insn_unit (insn)]];
7367*404b540aSrobert   last = frv_packet.insns[frv_packet.num_insns - 1];
7368*404b540aSrobert   if (GET_CODE (last) != INSN)
7369*404b540aSrobert     {
7370*404b540aSrobert       insn = emit_insn_before (PATTERN (insn), last);
7371*404b540aSrobert       frv_packet.insns[frv_packet.num_insns - 1] = insn;
7372*404b540aSrobert       frv_packet.insns[frv_packet.num_insns++] = last;
7373*404b540aSrobert     }
7374*404b540aSrobert   else
7375*404b540aSrobert     {
7376*404b540aSrobert       insn = emit_insn_after (PATTERN (insn), last);
7377*404b540aSrobert       frv_packet.insns[frv_packet.num_insns++] = insn;
7378*404b540aSrobert     }
7379*404b540aSrobert   packet_group->insns[packet_group->num_insns++] = insn;
7380*404b540aSrobert }
7381*404b540aSrobert 
7382*404b540aSrobert 
7383*404b540aSrobert /* If packing is enabled, divide the instructions into packets and
7384*404b540aSrobert    return true.  Call HANDLE_PACKET for each complete packet.  */
7385*404b540aSrobert 
7386*404b540aSrobert static bool
frv_for_each_packet(void (* handle_packet)(void))7387*404b540aSrobert frv_for_each_packet (void (*handle_packet) (void))
7388*404b540aSrobert {
7389*404b540aSrobert   rtx insn, next_insn;
7390*404b540aSrobert 
7391*404b540aSrobert   frv_packet.issue_rate = frv_issue_rate ();
7392*404b540aSrobert 
7393*404b540aSrobert   /* Early exit if we don't want to pack insns.  */
7394*404b540aSrobert   if (!optimize
7395*404b540aSrobert       || !flag_schedule_insns_after_reload
7396*404b540aSrobert       || !TARGET_VLIW_BRANCH
7397*404b540aSrobert       || frv_packet.issue_rate == 1)
7398*404b540aSrobert     return false;
7399*404b540aSrobert 
7400*404b540aSrobert   /* Set up the initial packing state.  */
7401*404b540aSrobert   dfa_start ();
7402*404b540aSrobert   frv_packet.dfa_state = alloca (state_size ());
7403*404b540aSrobert 
7404*404b540aSrobert   frv_start_packet_block ();
7405*404b540aSrobert   for (insn = get_insns (); insn != 0; insn = next_insn)
7406*404b540aSrobert     {
7407*404b540aSrobert       enum rtx_code code;
7408*404b540aSrobert       bool eh_insn_p;
7409*404b540aSrobert 
7410*404b540aSrobert       code = GET_CODE (insn);
7411*404b540aSrobert       next_insn = NEXT_INSN (insn);
7412*404b540aSrobert 
7413*404b540aSrobert       if (code == CODE_LABEL)
7414*404b540aSrobert 	{
7415*404b540aSrobert 	  frv_finish_packet (handle_packet);
7416*404b540aSrobert 	  frv_start_packet_block ();
7417*404b540aSrobert 	}
7418*404b540aSrobert 
7419*404b540aSrobert       if (INSN_P (insn))
7420*404b540aSrobert 	switch (GET_CODE (PATTERN (insn)))
7421*404b540aSrobert 	  {
7422*404b540aSrobert 	  case USE:
7423*404b540aSrobert 	  case CLOBBER:
7424*404b540aSrobert 	  case ADDR_VEC:
7425*404b540aSrobert 	  case ADDR_DIFF_VEC:
7426*404b540aSrobert 	    break;
7427*404b540aSrobert 
7428*404b540aSrobert 	  default:
7429*404b540aSrobert 	    /* Calls mustn't be packed on a TOMCAT.  */
7430*404b540aSrobert 	    if (GET_CODE (insn) == CALL_INSN && frv_cpu_type == FRV_CPU_TOMCAT)
7431*404b540aSrobert 	      frv_finish_packet (handle_packet);
7432*404b540aSrobert 
7433*404b540aSrobert 	    /* Since the last instruction in a packet determines the EH
7434*404b540aSrobert 	       region, any exception-throwing instruction must come at
7435*404b540aSrobert 	       the end of reordered packet.  Insns that issue to a
7436*404b540aSrobert 	       branch unit are bound to come last; for others it's
7437*404b540aSrobert 	       too hard to predict.  */
7438*404b540aSrobert 	    eh_insn_p = (find_reg_note (insn, REG_EH_REGION, NULL) != NULL);
7439*404b540aSrobert 	    if (eh_insn_p && !frv_issues_to_branch_unit_p (insn))
7440*404b540aSrobert 	      frv_finish_packet (handle_packet);
7441*404b540aSrobert 
7442*404b540aSrobert 	    /* Finish the current packet if we can't add INSN to it.
7443*404b540aSrobert 	       Simulate cycles until INSN is ready to issue.  */
7444*404b540aSrobert 	    if (!frv_pack_insn_p (insn))
7445*404b540aSrobert 	      {
7446*404b540aSrobert 		frv_finish_packet (handle_packet);
7447*404b540aSrobert 		while (!frv_pack_insn_p (insn))
7448*404b540aSrobert 		  state_transition (frv_packet.dfa_state, 0);
7449*404b540aSrobert 	      }
7450*404b540aSrobert 
7451*404b540aSrobert 	    /* Add the instruction to the packet.  */
7452*404b540aSrobert 	    frv_add_insn_to_packet (insn);
7453*404b540aSrobert 
7454*404b540aSrobert 	    /* Calls and jumps end a packet, as do insns that throw
7455*404b540aSrobert 	       an exception.  */
7456*404b540aSrobert 	    if (code == CALL_INSN || code == JUMP_INSN || eh_insn_p)
7457*404b540aSrobert 	      frv_finish_packet (handle_packet);
7458*404b540aSrobert 	    break;
7459*404b540aSrobert 	  }
7460*404b540aSrobert     }
7461*404b540aSrobert   frv_finish_packet (handle_packet);
7462*404b540aSrobert   dfa_finish ();
7463*404b540aSrobert   return true;
7464*404b540aSrobert }
7465*404b540aSrobert 
7466*404b540aSrobert /* Subroutine of frv_sort_insn_group.  We are trying to sort
7467*404b540aSrobert    frv_packet.groups[GROUP].sorted[0...NUM_INSNS-1] into assembly
7468*404b540aSrobert    language order.  We have already picked a new position for
7469*404b540aSrobert    frv_packet.groups[GROUP].sorted[X] if bit X of ISSUED is set.
7470*404b540aSrobert    These instructions will occupy elements [0, LOWER_SLOT) and
7471*404b540aSrobert    [UPPER_SLOT, NUM_INSNS) of the final (sorted) array.  STATE is
7472*404b540aSrobert    the DFA state after issuing these instructions.
7473*404b540aSrobert 
7474*404b540aSrobert    Try filling elements [LOWER_SLOT, UPPER_SLOT) with every permutation
7475*404b540aSrobert    of the unused instructions.  Return true if one such permutation gives
7476*404b540aSrobert    a valid ordering, leaving the successful permutation in sorted[].
7477*404b540aSrobert    Do not modify sorted[] until a valid permutation is found.  */
7478*404b540aSrobert 
7479*404b540aSrobert static bool
frv_sort_insn_group_1(enum frv_insn_group group,unsigned int lower_slot,unsigned int upper_slot,unsigned int issued,unsigned int num_insns,state_t state)7480*404b540aSrobert frv_sort_insn_group_1 (enum frv_insn_group group,
7481*404b540aSrobert 		       unsigned int lower_slot, unsigned int upper_slot,
7482*404b540aSrobert 		       unsigned int issued, unsigned int num_insns,
7483*404b540aSrobert 		       state_t state)
7484*404b540aSrobert {
7485*404b540aSrobert   struct frv_packet_group *packet_group;
7486*404b540aSrobert   unsigned int i;
7487*404b540aSrobert   state_t test_state;
7488*404b540aSrobert   size_t dfa_size;
7489*404b540aSrobert   rtx insn;
7490*404b540aSrobert 
7491*404b540aSrobert   /* Early success if we've filled all the slots.  */
7492*404b540aSrobert   if (lower_slot == upper_slot)
7493*404b540aSrobert     return true;
7494*404b540aSrobert 
7495*404b540aSrobert   packet_group = &frv_packet.groups[group];
7496*404b540aSrobert   dfa_size = state_size ();
7497*404b540aSrobert   test_state = alloca (dfa_size);
7498*404b540aSrobert 
7499*404b540aSrobert   /* Try issuing each unused instruction.  */
7500*404b540aSrobert   for (i = num_insns - 1; i + 1 != 0; i--)
7501*404b540aSrobert     if (~issued & (1 << i))
7502*404b540aSrobert       {
7503*404b540aSrobert 	insn = packet_group->sorted[i];
7504*404b540aSrobert 	memcpy (test_state, state, dfa_size);
7505*404b540aSrobert 	if (state_transition (test_state, insn) < 0
7506*404b540aSrobert 	    && cpu_unit_reservation_p (test_state,
7507*404b540aSrobert 				       NTH_UNIT (group, upper_slot - 1))
7508*404b540aSrobert 	    && frv_sort_insn_group_1 (group, lower_slot, upper_slot - 1,
7509*404b540aSrobert 				      issued | (1 << i), num_insns,
7510*404b540aSrobert 				      test_state))
7511*404b540aSrobert 	  {
7512*404b540aSrobert 	    packet_group->sorted[upper_slot - 1] = insn;
7513*404b540aSrobert 	    return true;
7514*404b540aSrobert 	  }
7515*404b540aSrobert       }
7516*404b540aSrobert 
7517*404b540aSrobert   return false;
7518*404b540aSrobert }
7519*404b540aSrobert 
7520*404b540aSrobert /* Compare two instructions by their frv_insn_unit.  */
7521*404b540aSrobert 
7522*404b540aSrobert static int
frv_compare_insns(const void * first,const void * second)7523*404b540aSrobert frv_compare_insns (const void *first, const void *second)
7524*404b540aSrobert {
7525*404b540aSrobert   const rtx *insn1 = first, *insn2 = second;
7526*404b540aSrobert   return frv_insn_unit (*insn1) - frv_insn_unit (*insn2);
7527*404b540aSrobert }
7528*404b540aSrobert 
7529*404b540aSrobert /* Copy frv_packet.groups[GROUP].insns[] to frv_packet.groups[GROUP].sorted[]
7530*404b540aSrobert    and sort it into assembly language order.  See frv.md for a description of
7531*404b540aSrobert    the algorithm.  */
7532*404b540aSrobert 
7533*404b540aSrobert static void
frv_sort_insn_group(enum frv_insn_group group)7534*404b540aSrobert frv_sort_insn_group (enum frv_insn_group group)
7535*404b540aSrobert {
7536*404b540aSrobert   struct frv_packet_group *packet_group;
7537*404b540aSrobert   unsigned int first, i, nop, max_unit, num_slots;
7538*404b540aSrobert   state_t state, test_state;
7539*404b540aSrobert   size_t dfa_size;
7540*404b540aSrobert 
7541*404b540aSrobert   packet_group = &frv_packet.groups[group];
7542*404b540aSrobert 
7543*404b540aSrobert   /* Assume no nop is needed.  */
7544*404b540aSrobert   packet_group->nop = 0;
7545*404b540aSrobert 
7546*404b540aSrobert   if (packet_group->num_insns == 0)
7547*404b540aSrobert     return;
7548*404b540aSrobert 
7549*404b540aSrobert   /* Copy insns[] to sorted[].  */
7550*404b540aSrobert   memcpy (packet_group->sorted, packet_group->insns,
7551*404b540aSrobert 	  sizeof (rtx) * packet_group->num_insns);
7552*404b540aSrobert 
7553*404b540aSrobert   /* Sort sorted[] by the unit that each insn tries to take first.  */
7554*404b540aSrobert   if (packet_group->num_insns > 1)
7555*404b540aSrobert     qsort (packet_group->sorted, packet_group->num_insns,
7556*404b540aSrobert 	   sizeof (rtx), frv_compare_insns);
7557*404b540aSrobert 
7558*404b540aSrobert   /* That's always enough for branch and control insns.  */
7559*404b540aSrobert   if (group == GROUP_B || group == GROUP_C)
7560*404b540aSrobert     return;
7561*404b540aSrobert 
7562*404b540aSrobert   dfa_size = state_size ();
7563*404b540aSrobert   state = alloca (dfa_size);
7564*404b540aSrobert   test_state = alloca (dfa_size);
7565*404b540aSrobert 
7566*404b540aSrobert   /* Find the highest FIRST such that sorted[0...FIRST-1] can issue
7567*404b540aSrobert      consecutively and such that the DFA takes unit X when sorted[X]
7568*404b540aSrobert      is added.  Set STATE to the new DFA state.  */
7569*404b540aSrobert   state_reset (test_state);
7570*404b540aSrobert   for (first = 0; first < packet_group->num_insns; first++)
7571*404b540aSrobert     {
7572*404b540aSrobert       memcpy (state, test_state, dfa_size);
7573*404b540aSrobert       if (state_transition (test_state, packet_group->sorted[first]) >= 0
7574*404b540aSrobert 	  || !cpu_unit_reservation_p (test_state, NTH_UNIT (group, first)))
7575*404b540aSrobert 	break;
7576*404b540aSrobert     }
7577*404b540aSrobert 
7578*404b540aSrobert   /* If all the instructions issued in ascending order, we're done.  */
7579*404b540aSrobert   if (first == packet_group->num_insns)
7580*404b540aSrobert     return;
7581*404b540aSrobert 
7582*404b540aSrobert   /* Add nops to the end of sorted[] and try each permutation until
7583*404b540aSrobert      we find one that works.  */
7584*404b540aSrobert   for (nop = 0; nop < frv_num_nops; nop++)
7585*404b540aSrobert     {
7586*404b540aSrobert       max_unit = frv_insn_unit (frv_nops[nop]);
7587*404b540aSrobert       if (frv_unit_groups[max_unit] == group)
7588*404b540aSrobert 	{
7589*404b540aSrobert 	  packet_group->nop = frv_nops[nop];
7590*404b540aSrobert 	  num_slots = UNIT_NUMBER (max_unit) + 1;
7591*404b540aSrobert 	  for (i = packet_group->num_insns; i < num_slots; i++)
7592*404b540aSrobert 	    packet_group->sorted[i] = frv_nops[nop];
7593*404b540aSrobert 	  if (frv_sort_insn_group_1 (group, first, num_slots,
7594*404b540aSrobert 				     (1 << first) - 1, num_slots, state))
7595*404b540aSrobert 	    return;
7596*404b540aSrobert 	}
7597*404b540aSrobert     }
7598*404b540aSrobert   gcc_unreachable ();
7599*404b540aSrobert }
7600*404b540aSrobert 
7601*404b540aSrobert /* Sort the current packet into assembly-language order.  Set packing
7602*404b540aSrobert    flags as appropriate.  */
7603*404b540aSrobert 
7604*404b540aSrobert static void
frv_reorder_packet(void)7605*404b540aSrobert frv_reorder_packet (void)
7606*404b540aSrobert {
7607*404b540aSrobert   unsigned int cursor[NUM_GROUPS];
7608*404b540aSrobert   rtx insns[ARRAY_SIZE (frv_unit_groups)];
7609*404b540aSrobert   unsigned int unit, to, from;
7610*404b540aSrobert   enum frv_insn_group group;
7611*404b540aSrobert   struct frv_packet_group *packet_group;
7612*404b540aSrobert 
7613*404b540aSrobert   /* First sort each group individually.  */
7614*404b540aSrobert   for (group = 0; group < NUM_GROUPS; group++)
7615*404b540aSrobert     {
7616*404b540aSrobert       cursor[group] = 0;
7617*404b540aSrobert       frv_sort_insn_group (group);
7618*404b540aSrobert     }
7619*404b540aSrobert 
7620*404b540aSrobert   /* Go through the unit template and try add an instruction from
7621*404b540aSrobert      that unit's group.  */
7622*404b540aSrobert   to = 0;
7623*404b540aSrobert   for (unit = 0; unit < ARRAY_SIZE (frv_unit_groups); unit++)
7624*404b540aSrobert     {
7625*404b540aSrobert       group = frv_unit_groups[unit];
7626*404b540aSrobert       packet_group = &frv_packet.groups[group];
7627*404b540aSrobert       if (cursor[group] < packet_group->num_insns)
7628*404b540aSrobert 	{
7629*404b540aSrobert 	  /* frv_reorg should have added nops for us.  */
7630*404b540aSrobert 	  gcc_assert (packet_group->sorted[cursor[group]]
7631*404b540aSrobert 		      != packet_group->nop);
7632*404b540aSrobert 	  insns[to++] = packet_group->sorted[cursor[group]++];
7633*404b540aSrobert 	}
7634*404b540aSrobert     }
7635*404b540aSrobert 
7636*404b540aSrobert   gcc_assert (to == frv_packet.num_insns);
7637*404b540aSrobert 
7638*404b540aSrobert   /* Clear the last instruction's packing flag, thus marking the end of
7639*404b540aSrobert      a packet.  Reorder the other instructions relative to it.  */
7640*404b540aSrobert   CLEAR_PACKING_FLAG (insns[to - 1]);
7641*404b540aSrobert   for (from = 0; from < to - 1; from++)
7642*404b540aSrobert     {
7643*404b540aSrobert       remove_insn (insns[from]);
7644*404b540aSrobert       add_insn_before (insns[from], insns[to - 1]);
7645*404b540aSrobert       SET_PACKING_FLAG (insns[from]);
7646*404b540aSrobert     }
7647*404b540aSrobert }
7648*404b540aSrobert 
7649*404b540aSrobert 
7650*404b540aSrobert /* Divide instructions into packets.  Reorder the contents of each
7651*404b540aSrobert    packet so that they are in the correct assembly-language order.
7652*404b540aSrobert 
7653*404b540aSrobert    Since this pass can change the raw meaning of the rtl stream, it must
7654*404b540aSrobert    only be called at the last minute, just before the instructions are
7655*404b540aSrobert    written out.  */
7656*404b540aSrobert 
7657*404b540aSrobert static void
frv_pack_insns(void)7658*404b540aSrobert frv_pack_insns (void)
7659*404b540aSrobert {
7660*404b540aSrobert   if (frv_for_each_packet (frv_reorder_packet))
7661*404b540aSrobert     frv_insn_packing_flag = 0;
7662*404b540aSrobert   else
7663*404b540aSrobert     frv_insn_packing_flag = -1;
7664*404b540aSrobert }
7665*404b540aSrobert 
7666*404b540aSrobert /* See whether we need to add nops to group GROUP in order to
7667*404b540aSrobert    make a valid packet.  */
7668*404b540aSrobert 
7669*404b540aSrobert static void
frv_fill_unused_units(enum frv_insn_group group)7670*404b540aSrobert frv_fill_unused_units (enum frv_insn_group group)
7671*404b540aSrobert {
7672*404b540aSrobert   unsigned int non_nops, nops, i;
7673*404b540aSrobert   struct frv_packet_group *packet_group;
7674*404b540aSrobert 
7675*404b540aSrobert   packet_group = &frv_packet.groups[group];
7676*404b540aSrobert 
7677*404b540aSrobert   /* Sort the instructions into assembly-language order.
7678*404b540aSrobert      Use nops to fill slots that are otherwise unused.  */
7679*404b540aSrobert   frv_sort_insn_group (group);
7680*404b540aSrobert 
7681*404b540aSrobert   /* See how many nops are needed before the final useful instruction.  */
7682*404b540aSrobert   i = nops = 0;
7683*404b540aSrobert   for (non_nops = 0; non_nops < packet_group->num_insns; non_nops++)
7684*404b540aSrobert     while (packet_group->sorted[i++] == packet_group->nop)
7685*404b540aSrobert       nops++;
7686*404b540aSrobert 
7687*404b540aSrobert   /* Insert that many nops into the instruction stream.  */
7688*404b540aSrobert   while (nops-- > 0)
7689*404b540aSrobert     frv_insert_nop_in_packet (packet_group->nop);
7690*404b540aSrobert }
7691*404b540aSrobert 
7692*404b540aSrobert /* Return true if accesses IO1 and IO2 refer to the same doubleword.  */
7693*404b540aSrobert 
7694*404b540aSrobert static bool
frv_same_doubleword_p(const struct frv_io * io1,const struct frv_io * io2)7695*404b540aSrobert frv_same_doubleword_p (const struct frv_io *io1, const struct frv_io *io2)
7696*404b540aSrobert {
7697*404b540aSrobert   if (io1->const_address != 0 && io2->const_address != 0)
7698*404b540aSrobert     return io1->const_address == io2->const_address;
7699*404b540aSrobert 
7700*404b540aSrobert   if (io1->var_address != 0 && io2->var_address != 0)
7701*404b540aSrobert     return rtx_equal_p (io1->var_address, io2->var_address);
7702*404b540aSrobert 
7703*404b540aSrobert   return false;
7704*404b540aSrobert }
7705*404b540aSrobert 
7706*404b540aSrobert /* Return true if operations IO1 and IO2 are guaranteed to complete
7707*404b540aSrobert    in order.  */
7708*404b540aSrobert 
7709*404b540aSrobert static bool
frv_io_fixed_order_p(const struct frv_io * io1,const struct frv_io * io2)7710*404b540aSrobert frv_io_fixed_order_p (const struct frv_io *io1, const struct frv_io *io2)
7711*404b540aSrobert {
7712*404b540aSrobert   /* The order of writes is always preserved.  */
7713*404b540aSrobert   if (io1->type == FRV_IO_WRITE && io2->type == FRV_IO_WRITE)
7714*404b540aSrobert     return true;
7715*404b540aSrobert 
7716*404b540aSrobert   /* The order of reads isn't preserved.  */
7717*404b540aSrobert   if (io1->type != FRV_IO_WRITE && io2->type != FRV_IO_WRITE)
7718*404b540aSrobert     return false;
7719*404b540aSrobert 
7720*404b540aSrobert   /* One operation is a write and the other is (or could be) a read.
7721*404b540aSrobert      The order is only guaranteed if the accesses are to the same
7722*404b540aSrobert      doubleword.  */
7723*404b540aSrobert   return frv_same_doubleword_p (io1, io2);
7724*404b540aSrobert }
7725*404b540aSrobert 
7726*404b540aSrobert /* Generalize I/O operation X so that it covers both X and Y. */
7727*404b540aSrobert 
7728*404b540aSrobert static void
frv_io_union(struct frv_io * x,const struct frv_io * y)7729*404b540aSrobert frv_io_union (struct frv_io *x, const struct frv_io *y)
7730*404b540aSrobert {
7731*404b540aSrobert   if (x->type != y->type)
7732*404b540aSrobert     x->type = FRV_IO_UNKNOWN;
7733*404b540aSrobert   if (!frv_same_doubleword_p (x, y))
7734*404b540aSrobert     {
7735*404b540aSrobert       x->const_address = 0;
7736*404b540aSrobert       x->var_address = 0;
7737*404b540aSrobert     }
7738*404b540aSrobert }
7739*404b540aSrobert 
7740*404b540aSrobert /* Fill IO with information about the load or store associated with
7741*404b540aSrobert    membar instruction INSN.  */
7742*404b540aSrobert 
7743*404b540aSrobert static void
frv_extract_membar(struct frv_io * io,rtx insn)7744*404b540aSrobert frv_extract_membar (struct frv_io *io, rtx insn)
7745*404b540aSrobert {
7746*404b540aSrobert   extract_insn (insn);
7747*404b540aSrobert   io->type = INTVAL (recog_data.operand[2]);
7748*404b540aSrobert   io->const_address = INTVAL (recog_data.operand[1]);
7749*404b540aSrobert   io->var_address = XEXP (recog_data.operand[0], 0);
7750*404b540aSrobert }
7751*404b540aSrobert 
7752*404b540aSrobert /* A note_stores callback for which DATA points to an rtx.  Nullify *DATA
7753*404b540aSrobert    if X is a register and *DATA depends on X.  */
7754*404b540aSrobert 
7755*404b540aSrobert static void
frv_io_check_address(rtx x,rtx pat ATTRIBUTE_UNUSED,void * data)7756*404b540aSrobert frv_io_check_address (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
7757*404b540aSrobert {
7758*404b540aSrobert   rtx *other = data;
7759*404b540aSrobert 
7760*404b540aSrobert   if (REG_P (x) && *other != 0 && reg_overlap_mentioned_p (x, *other))
7761*404b540aSrobert     *other = 0;
7762*404b540aSrobert }
7763*404b540aSrobert 
7764*404b540aSrobert /* A note_stores callback for which DATA points to a HARD_REG_SET.
7765*404b540aSrobert    Remove every modified register from the set.  */
7766*404b540aSrobert 
7767*404b540aSrobert static void
frv_io_handle_set(rtx x,rtx pat ATTRIBUTE_UNUSED,void * data)7768*404b540aSrobert frv_io_handle_set (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
7769*404b540aSrobert {
7770*404b540aSrobert   HARD_REG_SET *set = data;
7771*404b540aSrobert   unsigned int regno;
7772*404b540aSrobert 
7773*404b540aSrobert   if (REG_P (x))
7774*404b540aSrobert     FOR_EACH_REGNO (regno, x)
7775*404b540aSrobert       CLEAR_HARD_REG_BIT (*set, regno);
7776*404b540aSrobert }
7777*404b540aSrobert 
7778*404b540aSrobert /* A for_each_rtx callback for which DATA points to a HARD_REG_SET.
7779*404b540aSrobert    Add every register in *X to the set.  */
7780*404b540aSrobert 
7781*404b540aSrobert static int
frv_io_handle_use_1(rtx * x,void * data)7782*404b540aSrobert frv_io_handle_use_1 (rtx *x, void *data)
7783*404b540aSrobert {
7784*404b540aSrobert   HARD_REG_SET *set = data;
7785*404b540aSrobert   unsigned int regno;
7786*404b540aSrobert 
7787*404b540aSrobert   if (REG_P (*x))
7788*404b540aSrobert     FOR_EACH_REGNO (regno, *x)
7789*404b540aSrobert       SET_HARD_REG_BIT (*set, regno);
7790*404b540aSrobert 
7791*404b540aSrobert   return 0;
7792*404b540aSrobert }
7793*404b540aSrobert 
7794*404b540aSrobert /* A note_stores callback that applies frv_io_handle_use_1 to an
7795*404b540aSrobert    entire rhs value.  */
7796*404b540aSrobert 
7797*404b540aSrobert static void
frv_io_handle_use(rtx * x,void * data)7798*404b540aSrobert frv_io_handle_use (rtx *x, void *data)
7799*404b540aSrobert {
7800*404b540aSrobert   for_each_rtx (x, frv_io_handle_use_1, data);
7801*404b540aSrobert }
7802*404b540aSrobert 
7803*404b540aSrobert /* Go through block BB looking for membars to remove.  There are two
7804*404b540aSrobert    cases where intra-block analysis is enough:
7805*404b540aSrobert 
7806*404b540aSrobert    - a membar is redundant if it occurs between two consecutive I/O
7807*404b540aSrobert    operations and if those operations are guaranteed to complete
7808*404b540aSrobert    in order.
7809*404b540aSrobert 
7810*404b540aSrobert    - a membar for a __builtin_read is redundant if the result is
7811*404b540aSrobert    used before the next I/O operation is issued.
7812*404b540aSrobert 
7813*404b540aSrobert    If the last membar in the block could not be removed, and there
7814*404b540aSrobert    are guaranteed to be no I/O operations between that membar and
7815*404b540aSrobert    the end of the block, store the membar in *LAST_MEMBAR, otherwise
7816*404b540aSrobert    store null.
7817*404b540aSrobert 
7818*404b540aSrobert    Describe the block's first I/O operation in *NEXT_IO.  Describe
7819*404b540aSrobert    an unknown operation if the block doesn't do any I/O.  */
7820*404b540aSrobert 
7821*404b540aSrobert static void
frv_optimize_membar_local(basic_block bb,struct frv_io * next_io,rtx * last_membar)7822*404b540aSrobert frv_optimize_membar_local (basic_block bb, struct frv_io *next_io,
7823*404b540aSrobert 			   rtx *last_membar)
7824*404b540aSrobert {
7825*404b540aSrobert   HARD_REG_SET used_regs;
7826*404b540aSrobert   rtx next_membar, set, insn;
7827*404b540aSrobert   bool next_is_end_p;
7828*404b540aSrobert 
7829*404b540aSrobert   /* NEXT_IO is the next I/O operation to be performed after the current
7830*404b540aSrobert      instruction.  It starts off as being an unknown operation.  */
7831*404b540aSrobert   memset (next_io, 0, sizeof (*next_io));
7832*404b540aSrobert 
7833*404b540aSrobert   /* NEXT_IS_END_P is true if NEXT_IO describes the end of the block.  */
7834*404b540aSrobert   next_is_end_p = true;
7835*404b540aSrobert 
7836*404b540aSrobert   /* If the current instruction is a __builtin_read or __builtin_write,
7837*404b540aSrobert      NEXT_MEMBAR is the membar instruction associated with it.  NEXT_MEMBAR
7838*404b540aSrobert      is null if the membar has already been deleted.
7839*404b540aSrobert 
7840*404b540aSrobert      Note that the initialization here should only be needed to
7841*404b540aSrobert      suppress warnings.  */
7842*404b540aSrobert   next_membar = 0;
7843*404b540aSrobert 
7844*404b540aSrobert   /* USED_REGS is the set of registers that are used before the
7845*404b540aSrobert      next I/O instruction.  */
7846*404b540aSrobert   CLEAR_HARD_REG_SET (used_regs);
7847*404b540aSrobert 
7848*404b540aSrobert   for (insn = BB_END (bb); insn != BB_HEAD (bb); insn = PREV_INSN (insn))
7849*404b540aSrobert     if (GET_CODE (insn) == CALL_INSN)
7850*404b540aSrobert       {
7851*404b540aSrobert 	/* We can't predict what a call will do to volatile memory.  */
7852*404b540aSrobert 	memset (next_io, 0, sizeof (struct frv_io));
7853*404b540aSrobert 	next_is_end_p = false;
7854*404b540aSrobert 	CLEAR_HARD_REG_SET (used_regs);
7855*404b540aSrobert       }
7856*404b540aSrobert     else if (INSN_P (insn))
7857*404b540aSrobert       switch (recog_memoized (insn))
7858*404b540aSrobert 	{
7859*404b540aSrobert 	case CODE_FOR_optional_membar_qi:
7860*404b540aSrobert 	case CODE_FOR_optional_membar_hi:
7861*404b540aSrobert 	case CODE_FOR_optional_membar_si:
7862*404b540aSrobert 	case CODE_FOR_optional_membar_di:
7863*404b540aSrobert 	  next_membar = insn;
7864*404b540aSrobert 	  if (next_is_end_p)
7865*404b540aSrobert 	    {
7866*404b540aSrobert 	      /* Local information isn't enough to decide whether this
7867*404b540aSrobert 		 membar is needed.  Stash it away for later.  */
7868*404b540aSrobert 	      *last_membar = insn;
7869*404b540aSrobert 	      frv_extract_membar (next_io, insn);
7870*404b540aSrobert 	      next_is_end_p = false;
7871*404b540aSrobert 	    }
7872*404b540aSrobert 	  else
7873*404b540aSrobert 	    {
7874*404b540aSrobert 	      /* Check whether the I/O operation before INSN could be
7875*404b540aSrobert 		 reordered with one described by NEXT_IO.  If it can't,
7876*404b540aSrobert 		 INSN will not be needed.  */
7877*404b540aSrobert 	      struct frv_io prev_io;
7878*404b540aSrobert 
7879*404b540aSrobert 	      frv_extract_membar (&prev_io, insn);
7880*404b540aSrobert 	      if (frv_io_fixed_order_p (&prev_io, next_io))
7881*404b540aSrobert 		{
7882*404b540aSrobert 		  if (dump_file)
7883*404b540aSrobert 		    fprintf (dump_file,
7884*404b540aSrobert 			     ";; [Local] Removing membar %d since order"
7885*404b540aSrobert 			     " of accesses is guaranteed\n",
7886*404b540aSrobert 			     INSN_UID (next_membar));
7887*404b540aSrobert 
7888*404b540aSrobert 		  insn = NEXT_INSN (insn);
7889*404b540aSrobert 		  delete_insn (next_membar);
7890*404b540aSrobert 		  next_membar = 0;
7891*404b540aSrobert 		}
7892*404b540aSrobert 	      *next_io = prev_io;
7893*404b540aSrobert 	    }
7894*404b540aSrobert 	  break;
7895*404b540aSrobert 
7896*404b540aSrobert 	default:
7897*404b540aSrobert 	  /* Invalidate NEXT_IO's address if it depends on something that
7898*404b540aSrobert 	     is clobbered by INSN.  */
7899*404b540aSrobert 	  if (next_io->var_address)
7900*404b540aSrobert 	    note_stores (PATTERN (insn), frv_io_check_address,
7901*404b540aSrobert 			 &next_io->var_address);
7902*404b540aSrobert 
7903*404b540aSrobert 	  /* If the next membar is associated with a __builtin_read,
7904*404b540aSrobert 	     see if INSN reads from that address.  If it does, and if
7905*404b540aSrobert 	     the destination register is used before the next I/O access,
7906*404b540aSrobert 	     there is no need for the membar.  */
7907*404b540aSrobert 	  set = PATTERN (insn);
7908*404b540aSrobert 	  if (next_io->type == FRV_IO_READ
7909*404b540aSrobert 	      && next_io->var_address != 0
7910*404b540aSrobert 	      && next_membar != 0
7911*404b540aSrobert 	      && GET_CODE (set) == SET
7912*404b540aSrobert 	      && GET_CODE (SET_DEST (set)) == REG
7913*404b540aSrobert 	      && TEST_HARD_REG_BIT (used_regs, REGNO (SET_DEST (set))))
7914*404b540aSrobert 	    {
7915*404b540aSrobert 	      rtx src;
7916*404b540aSrobert 
7917*404b540aSrobert 	      src = SET_SRC (set);
7918*404b540aSrobert 	      if (GET_CODE (src) == ZERO_EXTEND)
7919*404b540aSrobert 		src = XEXP (src, 0);
7920*404b540aSrobert 
7921*404b540aSrobert 	      if (GET_CODE (src) == MEM
7922*404b540aSrobert 		  && rtx_equal_p (XEXP (src, 0), next_io->var_address))
7923*404b540aSrobert 		{
7924*404b540aSrobert 		  if (dump_file)
7925*404b540aSrobert 		    fprintf (dump_file,
7926*404b540aSrobert 			     ";; [Local] Removing membar %d since the target"
7927*404b540aSrobert 			     " of %d is used before the I/O operation\n",
7928*404b540aSrobert 			     INSN_UID (next_membar), INSN_UID (insn));
7929*404b540aSrobert 
7930*404b540aSrobert 		  if (next_membar == *last_membar)
7931*404b540aSrobert 		    *last_membar = 0;
7932*404b540aSrobert 
7933*404b540aSrobert 		  delete_insn (next_membar);
7934*404b540aSrobert 		  next_membar = 0;
7935*404b540aSrobert 		}
7936*404b540aSrobert 	    }
7937*404b540aSrobert 
7938*404b540aSrobert 	  /* If INSN has volatile references, forget about any registers
7939*404b540aSrobert 	     that are used after it.  Otherwise forget about uses that
7940*404b540aSrobert 	     are (or might be) defined by INSN.  */
7941*404b540aSrobert 	  if (volatile_refs_p (PATTERN (insn)))
7942*404b540aSrobert 	    CLEAR_HARD_REG_SET (used_regs);
7943*404b540aSrobert 	  else
7944*404b540aSrobert 	    note_stores (PATTERN (insn), frv_io_handle_set, &used_regs);
7945*404b540aSrobert 
7946*404b540aSrobert 	  note_uses (&PATTERN (insn), frv_io_handle_use, &used_regs);
7947*404b540aSrobert 	  break;
7948*404b540aSrobert 	}
7949*404b540aSrobert }
7950*404b540aSrobert 
7951*404b540aSrobert /* See if MEMBAR, the last membar instruction in BB, can be removed.
7952*404b540aSrobert    FIRST_IO[X] describes the first operation performed by basic block X.  */
7953*404b540aSrobert 
7954*404b540aSrobert static void
frv_optimize_membar_global(basic_block bb,struct frv_io * first_io,rtx membar)7955*404b540aSrobert frv_optimize_membar_global (basic_block bb, struct frv_io *first_io,
7956*404b540aSrobert 			    rtx membar)
7957*404b540aSrobert {
7958*404b540aSrobert   struct frv_io this_io, next_io;
7959*404b540aSrobert   edge succ;
7960*404b540aSrobert   edge_iterator ei;
7961*404b540aSrobert 
7962*404b540aSrobert   /* We need to keep the membar if there is an edge to the exit block.  */
7963*404b540aSrobert   FOR_EACH_EDGE (succ, ei, bb->succs)
7964*404b540aSrobert   /* for (succ = bb->succ; succ != 0; succ = succ->succ_next) */
7965*404b540aSrobert     if (succ->dest == EXIT_BLOCK_PTR)
7966*404b540aSrobert       return;
7967*404b540aSrobert 
7968*404b540aSrobert   /* Work out the union of all successor blocks.  */
7969*404b540aSrobert   ei = ei_start (bb->succs);
7970*404b540aSrobert   ei_cond (ei, &succ);
7971*404b540aSrobert   /* next_io = first_io[bb->succ->dest->index]; */
7972*404b540aSrobert   next_io = first_io[succ->dest->index];
7973*404b540aSrobert   ei = ei_start (bb->succs);
7974*404b540aSrobert   if (ei_cond (ei, &succ))
7975*404b540aSrobert     {
7976*404b540aSrobert       for (ei_next (&ei); ei_cond (ei, &succ); ei_next (&ei))
7977*404b540aSrobert 	/*for (succ = bb->succ->succ_next; succ != 0; succ = succ->succ_next)*/
7978*404b540aSrobert 	frv_io_union (&next_io, &first_io[succ->dest->index]);
7979*404b540aSrobert     }
7980*404b540aSrobert   else
7981*404b540aSrobert     gcc_unreachable ();
7982*404b540aSrobert 
7983*404b540aSrobert   frv_extract_membar (&this_io, membar);
7984*404b540aSrobert   if (frv_io_fixed_order_p (&this_io, &next_io))
7985*404b540aSrobert     {
7986*404b540aSrobert       if (dump_file)
7987*404b540aSrobert 	fprintf (dump_file,
7988*404b540aSrobert 		 ";; [Global] Removing membar %d since order of accesses"
7989*404b540aSrobert 		 " is guaranteed\n", INSN_UID (membar));
7990*404b540aSrobert 
7991*404b540aSrobert       delete_insn (membar);
7992*404b540aSrobert     }
7993*404b540aSrobert }
7994*404b540aSrobert 
7995*404b540aSrobert /* Remove redundant membars from the current function.  */
7996*404b540aSrobert 
7997*404b540aSrobert static void
frv_optimize_membar(void)7998*404b540aSrobert frv_optimize_membar (void)
7999*404b540aSrobert {
8000*404b540aSrobert   basic_block bb;
8001*404b540aSrobert   struct frv_io *first_io;
8002*404b540aSrobert   rtx *last_membar;
8003*404b540aSrobert 
8004*404b540aSrobert   compute_bb_for_insn ();
8005*404b540aSrobert   first_io = xcalloc (last_basic_block, sizeof (struct frv_io));
8006*404b540aSrobert   last_membar = xcalloc (last_basic_block, sizeof (rtx));
8007*404b540aSrobert 
8008*404b540aSrobert   FOR_EACH_BB (bb)
8009*404b540aSrobert     frv_optimize_membar_local (bb, &first_io[bb->index],
8010*404b540aSrobert 			       &last_membar[bb->index]);
8011*404b540aSrobert 
8012*404b540aSrobert   FOR_EACH_BB (bb)
8013*404b540aSrobert     if (last_membar[bb->index] != 0)
8014*404b540aSrobert       frv_optimize_membar_global (bb, first_io, last_membar[bb->index]);
8015*404b540aSrobert 
8016*404b540aSrobert   free (first_io);
8017*404b540aSrobert   free (last_membar);
8018*404b540aSrobert }
8019*404b540aSrobert 
8020*404b540aSrobert /* Used by frv_reorg to keep track of the current packet's address.  */
8021*404b540aSrobert static unsigned int frv_packet_address;
8022*404b540aSrobert 
8023*404b540aSrobert /* If the current packet falls through to a label, try to pad the packet
8024*404b540aSrobert    with nops in order to fit the label's alignment requirements.  */
8025*404b540aSrobert 
8026*404b540aSrobert static void
frv_align_label(void)8027*404b540aSrobert frv_align_label (void)
8028*404b540aSrobert {
8029*404b540aSrobert   unsigned int alignment, target, nop;
8030*404b540aSrobert   rtx x, last, barrier, label;
8031*404b540aSrobert 
8032*404b540aSrobert   /* Walk forward to the start of the next packet.  Set ALIGNMENT to the
8033*404b540aSrobert      maximum alignment of that packet, LABEL to the last label between
8034*404b540aSrobert      the packets, and BARRIER to the last barrier.  */
8035*404b540aSrobert   last = frv_packet.insns[frv_packet.num_insns - 1];
8036*404b540aSrobert   label = barrier = 0;
8037*404b540aSrobert   alignment = 4;
8038*404b540aSrobert   for (x = NEXT_INSN (last); x != 0 && !INSN_P (x); x = NEXT_INSN (x))
8039*404b540aSrobert     {
8040*404b540aSrobert       if (LABEL_P (x))
8041*404b540aSrobert 	{
8042*404b540aSrobert 	  unsigned int subalign = 1 << label_to_alignment (x);
8043*404b540aSrobert 	  alignment = MAX (alignment, subalign);
8044*404b540aSrobert 	  label = x;
8045*404b540aSrobert 	}
8046*404b540aSrobert       if (BARRIER_P (x))
8047*404b540aSrobert 	barrier = x;
8048*404b540aSrobert     }
8049*404b540aSrobert 
8050*404b540aSrobert   /* If -malign-labels, and the packet falls through to an unaligned
8051*404b540aSrobert      label, try introducing a nop to align that label to 8 bytes.  */
8052*404b540aSrobert   if (TARGET_ALIGN_LABELS
8053*404b540aSrobert       && label != 0
8054*404b540aSrobert       && barrier == 0
8055*404b540aSrobert       && frv_packet.num_insns < frv_packet.issue_rate)
8056*404b540aSrobert     alignment = MAX (alignment, 8);
8057*404b540aSrobert 
8058*404b540aSrobert   /* Advance the address to the end of the current packet.  */
8059*404b540aSrobert   frv_packet_address += frv_packet.num_insns * 4;
8060*404b540aSrobert 
8061*404b540aSrobert   /* Work out the target address, after alignment.  */
8062*404b540aSrobert   target = (frv_packet_address + alignment - 1) & -alignment;
8063*404b540aSrobert 
8064*404b540aSrobert   /* If the packet falls through to the label, try to find an efficient
8065*404b540aSrobert      padding sequence.  */
8066*404b540aSrobert   if (barrier == 0)
8067*404b540aSrobert     {
8068*404b540aSrobert       /* First try adding nops to the current packet.  */
8069*404b540aSrobert       for (nop = 0; nop < frv_num_nops; nop++)
8070*404b540aSrobert 	while (frv_packet_address < target && frv_pack_insn_p (frv_nops[nop]))
8071*404b540aSrobert 	  {
8072*404b540aSrobert 	    frv_insert_nop_in_packet (frv_nops[nop]);
8073*404b540aSrobert 	    frv_packet_address += 4;
8074*404b540aSrobert 	  }
8075*404b540aSrobert 
8076*404b540aSrobert       /* If we still haven't reached the target, add some new packets that
8077*404b540aSrobert 	 contain only nops.  If there are two types of nop, insert an
8078*404b540aSrobert 	 alternating sequence of frv_nops[0] and frv_nops[1], which will
8079*404b540aSrobert 	 lead to packets like:
8080*404b540aSrobert 
8081*404b540aSrobert 		nop.p
8082*404b540aSrobert 		mnop.p/fnop.p
8083*404b540aSrobert 		nop.p
8084*404b540aSrobert 		mnop/fnop
8085*404b540aSrobert 
8086*404b540aSrobert 	 etc.  Just emit frv_nops[0] if that's the only nop we have.  */
8087*404b540aSrobert       last = frv_packet.insns[frv_packet.num_insns - 1];
8088*404b540aSrobert       nop = 0;
8089*404b540aSrobert       while (frv_packet_address < target)
8090*404b540aSrobert 	{
8091*404b540aSrobert 	  last = emit_insn_after (PATTERN (frv_nops[nop]), last);
8092*404b540aSrobert 	  frv_packet_address += 4;
8093*404b540aSrobert 	  if (frv_num_nops > 1)
8094*404b540aSrobert 	    nop ^= 1;
8095*404b540aSrobert 	}
8096*404b540aSrobert     }
8097*404b540aSrobert 
8098*404b540aSrobert   frv_packet_address = target;
8099*404b540aSrobert }
8100*404b540aSrobert 
8101*404b540aSrobert /* Subroutine of frv_reorg, called after each packet has been constructed
8102*404b540aSrobert    in frv_packet.  */
8103*404b540aSrobert 
8104*404b540aSrobert static void
frv_reorg_packet(void)8105*404b540aSrobert frv_reorg_packet (void)
8106*404b540aSrobert {
8107*404b540aSrobert   frv_fill_unused_units (GROUP_I);
8108*404b540aSrobert   frv_fill_unused_units (GROUP_FM);
8109*404b540aSrobert   frv_align_label ();
8110*404b540aSrobert }
8111*404b540aSrobert 
8112*404b540aSrobert /* Add an instruction with pattern NOP to frv_nops[].  */
8113*404b540aSrobert 
8114*404b540aSrobert static void
frv_register_nop(rtx nop)8115*404b540aSrobert frv_register_nop (rtx nop)
8116*404b540aSrobert {
8117*404b540aSrobert   nop = make_insn_raw (nop);
8118*404b540aSrobert   NEXT_INSN (nop) = 0;
8119*404b540aSrobert   PREV_INSN (nop) = 0;
8120*404b540aSrobert   frv_nops[frv_num_nops++] = nop;
8121*404b540aSrobert }
8122*404b540aSrobert 
8123*404b540aSrobert /* Implement TARGET_MACHINE_DEPENDENT_REORG.  Divide the instructions
8124*404b540aSrobert    into packets and check whether we need to insert nops in order to
8125*404b540aSrobert    fulfill the processor's issue requirements.  Also, if the user has
8126*404b540aSrobert    requested a certain alignment for a label, try to meet that alignment
8127*404b540aSrobert    by inserting nops in the previous packet.  */
8128*404b540aSrobert 
8129*404b540aSrobert static void
frv_reorg(void)8130*404b540aSrobert frv_reorg (void)
8131*404b540aSrobert {
8132*404b540aSrobert   if (optimize > 0 && TARGET_OPTIMIZE_MEMBAR && cfun->machine->has_membar_p)
8133*404b540aSrobert     frv_optimize_membar ();
8134*404b540aSrobert 
8135*404b540aSrobert   frv_num_nops = 0;
8136*404b540aSrobert   frv_register_nop (gen_nop ());
8137*404b540aSrobert   if (TARGET_MEDIA)
8138*404b540aSrobert     frv_register_nop (gen_mnop ());
8139*404b540aSrobert   if (TARGET_HARD_FLOAT)
8140*404b540aSrobert     frv_register_nop (gen_fnop ());
8141*404b540aSrobert 
8142*404b540aSrobert   /* Estimate the length of each branch.  Although this may change after
8143*404b540aSrobert      we've inserted nops, it will only do so in big functions.  */
8144*404b540aSrobert   shorten_branches (get_insns ());
8145*404b540aSrobert 
8146*404b540aSrobert   frv_packet_address = 0;
8147*404b540aSrobert   frv_for_each_packet (frv_reorg_packet);
8148*404b540aSrobert }
8149*404b540aSrobert 
8150*404b540aSrobert #define def_builtin(name, type, code) \
8151*404b540aSrobert   lang_hooks.builtin_function ((name), (type), (code), BUILT_IN_MD, NULL, NULL)
8152*404b540aSrobert 
8153*404b540aSrobert struct builtin_description
8154*404b540aSrobert {
8155*404b540aSrobert   enum insn_code icode;
8156*404b540aSrobert   const char *name;
8157*404b540aSrobert   enum frv_builtins code;
8158*404b540aSrobert   enum rtx_code comparison;
8159*404b540aSrobert   unsigned int flag;
8160*404b540aSrobert };
8161*404b540aSrobert 
8162*404b540aSrobert /* Media intrinsics that take a single, constant argument.  */
8163*404b540aSrobert 
8164*404b540aSrobert static struct builtin_description bdesc_set[] =
8165*404b540aSrobert {
8166*404b540aSrobert   { CODE_FOR_mhdsets, "__MHDSETS", FRV_BUILTIN_MHDSETS, 0, 0 }
8167*404b540aSrobert };
8168*404b540aSrobert 
8169*404b540aSrobert /* Media intrinsics that take just one argument.  */
8170*404b540aSrobert 
8171*404b540aSrobert static struct builtin_description bdesc_1arg[] =
8172*404b540aSrobert {
8173*404b540aSrobert   { CODE_FOR_mnot, "__MNOT", FRV_BUILTIN_MNOT, 0, 0 },
8174*404b540aSrobert   { CODE_FOR_munpackh, "__MUNPACKH", FRV_BUILTIN_MUNPACKH, 0, 0 },
8175*404b540aSrobert   { CODE_FOR_mbtoh, "__MBTOH", FRV_BUILTIN_MBTOH, 0, 0 },
8176*404b540aSrobert   { CODE_FOR_mhtob, "__MHTOB", FRV_BUILTIN_MHTOB, 0, 0 },
8177*404b540aSrobert   { CODE_FOR_mabshs, "__MABSHS", FRV_BUILTIN_MABSHS, 0, 0 },
8178*404b540aSrobert   { CODE_FOR_scutss, "__SCUTSS", FRV_BUILTIN_SCUTSS, 0, 0 }
8179*404b540aSrobert };
8180*404b540aSrobert 
8181*404b540aSrobert /* Media intrinsics that take two arguments.  */
8182*404b540aSrobert 
8183*404b540aSrobert static struct builtin_description bdesc_2arg[] =
8184*404b540aSrobert {
8185*404b540aSrobert   { CODE_FOR_mand, "__MAND", FRV_BUILTIN_MAND, 0, 0 },
8186*404b540aSrobert   { CODE_FOR_mor, "__MOR", FRV_BUILTIN_MOR, 0, 0 },
8187*404b540aSrobert   { CODE_FOR_mxor, "__MXOR", FRV_BUILTIN_MXOR, 0, 0 },
8188*404b540aSrobert   { CODE_FOR_maveh, "__MAVEH", FRV_BUILTIN_MAVEH, 0, 0 },
8189*404b540aSrobert   { CODE_FOR_msaths, "__MSATHS", FRV_BUILTIN_MSATHS, 0, 0 },
8190*404b540aSrobert   { CODE_FOR_msathu, "__MSATHU", FRV_BUILTIN_MSATHU, 0, 0 },
8191*404b540aSrobert   { CODE_FOR_maddhss, "__MADDHSS", FRV_BUILTIN_MADDHSS, 0, 0 },
8192*404b540aSrobert   { CODE_FOR_maddhus, "__MADDHUS", FRV_BUILTIN_MADDHUS, 0, 0 },
8193*404b540aSrobert   { CODE_FOR_msubhss, "__MSUBHSS", FRV_BUILTIN_MSUBHSS, 0, 0 },
8194*404b540aSrobert   { CODE_FOR_msubhus, "__MSUBHUS", FRV_BUILTIN_MSUBHUS, 0, 0 },
8195*404b540aSrobert   { CODE_FOR_mqaddhss, "__MQADDHSS", FRV_BUILTIN_MQADDHSS, 0, 0 },
8196*404b540aSrobert   { CODE_FOR_mqaddhus, "__MQADDHUS", FRV_BUILTIN_MQADDHUS, 0, 0 },
8197*404b540aSrobert   { CODE_FOR_mqsubhss, "__MQSUBHSS", FRV_BUILTIN_MQSUBHSS, 0, 0 },
8198*404b540aSrobert   { CODE_FOR_mqsubhus, "__MQSUBHUS", FRV_BUILTIN_MQSUBHUS, 0, 0 },
8199*404b540aSrobert   { CODE_FOR_mpackh, "__MPACKH", FRV_BUILTIN_MPACKH, 0, 0 },
8200*404b540aSrobert   { CODE_FOR_mcop1, "__Mcop1", FRV_BUILTIN_MCOP1, 0, 0 },
8201*404b540aSrobert   { CODE_FOR_mcop2, "__Mcop2", FRV_BUILTIN_MCOP2, 0, 0 },
8202*404b540aSrobert   { CODE_FOR_mwcut, "__MWCUT", FRV_BUILTIN_MWCUT, 0, 0 },
8203*404b540aSrobert   { CODE_FOR_mqsaths, "__MQSATHS", FRV_BUILTIN_MQSATHS, 0, 0 },
8204*404b540aSrobert   { CODE_FOR_mqlclrhs, "__MQLCLRHS", FRV_BUILTIN_MQLCLRHS, 0, 0 },
8205*404b540aSrobert   { CODE_FOR_mqlmths, "__MQLMTHS", FRV_BUILTIN_MQLMTHS, 0, 0 },
8206*404b540aSrobert   { CODE_FOR_smul, "__SMUL", FRV_BUILTIN_SMUL, 0, 0 },
8207*404b540aSrobert   { CODE_FOR_umul, "__UMUL", FRV_BUILTIN_UMUL, 0, 0 },
8208*404b540aSrobert   { CODE_FOR_addss, "__ADDSS", FRV_BUILTIN_ADDSS, 0, 0 },
8209*404b540aSrobert   { CODE_FOR_subss, "__SUBSS", FRV_BUILTIN_SUBSS, 0, 0 },
8210*404b540aSrobert   { CODE_FOR_slass, "__SLASS", FRV_BUILTIN_SLASS, 0, 0 },
8211*404b540aSrobert   { CODE_FOR_scan, "__SCAN", FRV_BUILTIN_SCAN, 0, 0 }
8212*404b540aSrobert };
8213*404b540aSrobert 
8214*404b540aSrobert /* Integer intrinsics that take two arguments and have no return value.  */
8215*404b540aSrobert 
8216*404b540aSrobert static struct builtin_description bdesc_int_void2arg[] =
8217*404b540aSrobert {
8218*404b540aSrobert   { CODE_FOR_smass, "__SMASS", FRV_BUILTIN_SMASS, 0, 0 },
8219*404b540aSrobert   { CODE_FOR_smsss, "__SMSSS", FRV_BUILTIN_SMSSS, 0, 0 },
8220*404b540aSrobert   { CODE_FOR_smu, "__SMU", FRV_BUILTIN_SMU, 0, 0 }
8221*404b540aSrobert };
8222*404b540aSrobert 
8223*404b540aSrobert static struct builtin_description bdesc_prefetches[] =
8224*404b540aSrobert {
8225*404b540aSrobert   { CODE_FOR_frv_prefetch0, "__data_prefetch0", FRV_BUILTIN_PREFETCH0, 0, 0 },
8226*404b540aSrobert   { CODE_FOR_frv_prefetch, "__data_prefetch", FRV_BUILTIN_PREFETCH, 0, 0 }
8227*404b540aSrobert };
8228*404b540aSrobert 
8229*404b540aSrobert /* Media intrinsics that take two arguments, the first being an ACC number.  */
8230*404b540aSrobert 
8231*404b540aSrobert static struct builtin_description bdesc_cut[] =
8232*404b540aSrobert {
8233*404b540aSrobert   { CODE_FOR_mcut, "__MCUT", FRV_BUILTIN_MCUT, 0, 0 },
8234*404b540aSrobert   { CODE_FOR_mcutss, "__MCUTSS", FRV_BUILTIN_MCUTSS, 0, 0 },
8235*404b540aSrobert   { CODE_FOR_mdcutssi, "__MDCUTSSI", FRV_BUILTIN_MDCUTSSI, 0, 0 }
8236*404b540aSrobert };
8237*404b540aSrobert 
8238*404b540aSrobert /* Two-argument media intrinsics with an immediate second argument.  */
8239*404b540aSrobert 
8240*404b540aSrobert static struct builtin_description bdesc_2argimm[] =
8241*404b540aSrobert {
8242*404b540aSrobert   { CODE_FOR_mrotli, "__MROTLI", FRV_BUILTIN_MROTLI, 0, 0 },
8243*404b540aSrobert   { CODE_FOR_mrotri, "__MROTRI", FRV_BUILTIN_MROTRI, 0, 0 },
8244*404b540aSrobert   { CODE_FOR_msllhi, "__MSLLHI", FRV_BUILTIN_MSLLHI, 0, 0 },
8245*404b540aSrobert   { CODE_FOR_msrlhi, "__MSRLHI", FRV_BUILTIN_MSRLHI, 0, 0 },
8246*404b540aSrobert   { CODE_FOR_msrahi, "__MSRAHI", FRV_BUILTIN_MSRAHI, 0, 0 },
8247*404b540aSrobert   { CODE_FOR_mexpdhw, "__MEXPDHW", FRV_BUILTIN_MEXPDHW, 0, 0 },
8248*404b540aSrobert   { CODE_FOR_mexpdhd, "__MEXPDHD", FRV_BUILTIN_MEXPDHD, 0, 0 },
8249*404b540aSrobert   { CODE_FOR_mdrotli, "__MDROTLI", FRV_BUILTIN_MDROTLI, 0, 0 },
8250*404b540aSrobert   { CODE_FOR_mcplhi, "__MCPLHI", FRV_BUILTIN_MCPLHI, 0, 0 },
8251*404b540aSrobert   { CODE_FOR_mcpli, "__MCPLI", FRV_BUILTIN_MCPLI, 0, 0 },
8252*404b540aSrobert   { CODE_FOR_mhsetlos, "__MHSETLOS", FRV_BUILTIN_MHSETLOS, 0, 0 },
8253*404b540aSrobert   { CODE_FOR_mhsetloh, "__MHSETLOH", FRV_BUILTIN_MHSETLOH, 0, 0 },
8254*404b540aSrobert   { CODE_FOR_mhsethis, "__MHSETHIS", FRV_BUILTIN_MHSETHIS, 0, 0 },
8255*404b540aSrobert   { CODE_FOR_mhsethih, "__MHSETHIH", FRV_BUILTIN_MHSETHIH, 0, 0 },
8256*404b540aSrobert   { CODE_FOR_mhdseth, "__MHDSETH", FRV_BUILTIN_MHDSETH, 0, 0 },
8257*404b540aSrobert   { CODE_FOR_mqsllhi, "__MQSLLHI", FRV_BUILTIN_MQSLLHI, 0, 0 },
8258*404b540aSrobert   { CODE_FOR_mqsrahi, "__MQSRAHI", FRV_BUILTIN_MQSRAHI, 0, 0 }
8259*404b540aSrobert };
8260*404b540aSrobert 
8261*404b540aSrobert /* Media intrinsics that take two arguments and return void, the first argument
8262*404b540aSrobert    being a pointer to 4 words in memory.  */
8263*404b540aSrobert 
8264*404b540aSrobert static struct builtin_description bdesc_void2arg[] =
8265*404b540aSrobert {
8266*404b540aSrobert   { CODE_FOR_mdunpackh, "__MDUNPACKH", FRV_BUILTIN_MDUNPACKH, 0, 0 },
8267*404b540aSrobert   { CODE_FOR_mbtohe, "__MBTOHE", FRV_BUILTIN_MBTOHE, 0, 0 },
8268*404b540aSrobert };
8269*404b540aSrobert 
8270*404b540aSrobert /* Media intrinsics that take three arguments, the first being a const_int that
8271*404b540aSrobert    denotes an accumulator, and that return void.  */
8272*404b540aSrobert 
8273*404b540aSrobert static struct builtin_description bdesc_void3arg[] =
8274*404b540aSrobert {
8275*404b540aSrobert   { CODE_FOR_mcpxrs, "__MCPXRS", FRV_BUILTIN_MCPXRS, 0, 0 },
8276*404b540aSrobert   { CODE_FOR_mcpxru, "__MCPXRU", FRV_BUILTIN_MCPXRU, 0, 0 },
8277*404b540aSrobert   { CODE_FOR_mcpxis, "__MCPXIS", FRV_BUILTIN_MCPXIS, 0, 0 },
8278*404b540aSrobert   { CODE_FOR_mcpxiu, "__MCPXIU", FRV_BUILTIN_MCPXIU, 0, 0 },
8279*404b540aSrobert   { CODE_FOR_mmulhs, "__MMULHS", FRV_BUILTIN_MMULHS, 0, 0 },
8280*404b540aSrobert   { CODE_FOR_mmulhu, "__MMULHU", FRV_BUILTIN_MMULHU, 0, 0 },
8281*404b540aSrobert   { CODE_FOR_mmulxhs, "__MMULXHS", FRV_BUILTIN_MMULXHS, 0, 0 },
8282*404b540aSrobert   { CODE_FOR_mmulxhu, "__MMULXHU", FRV_BUILTIN_MMULXHU, 0, 0 },
8283*404b540aSrobert   { CODE_FOR_mmachs, "__MMACHS", FRV_BUILTIN_MMACHS, 0, 0 },
8284*404b540aSrobert   { CODE_FOR_mmachu, "__MMACHU", FRV_BUILTIN_MMACHU, 0, 0 },
8285*404b540aSrobert   { CODE_FOR_mmrdhs, "__MMRDHS", FRV_BUILTIN_MMRDHS, 0, 0 },
8286*404b540aSrobert   { CODE_FOR_mmrdhu, "__MMRDHU", FRV_BUILTIN_MMRDHU, 0, 0 },
8287*404b540aSrobert   { CODE_FOR_mqcpxrs, "__MQCPXRS", FRV_BUILTIN_MQCPXRS, 0, 0 },
8288*404b540aSrobert   { CODE_FOR_mqcpxru, "__MQCPXRU", FRV_BUILTIN_MQCPXRU, 0, 0 },
8289*404b540aSrobert   { CODE_FOR_mqcpxis, "__MQCPXIS", FRV_BUILTIN_MQCPXIS, 0, 0 },
8290*404b540aSrobert   { CODE_FOR_mqcpxiu, "__MQCPXIU", FRV_BUILTIN_MQCPXIU, 0, 0 },
8291*404b540aSrobert   { CODE_FOR_mqmulhs, "__MQMULHS", FRV_BUILTIN_MQMULHS, 0, 0 },
8292*404b540aSrobert   { CODE_FOR_mqmulhu, "__MQMULHU", FRV_BUILTIN_MQMULHU, 0, 0 },
8293*404b540aSrobert   { CODE_FOR_mqmulxhs, "__MQMULXHS", FRV_BUILTIN_MQMULXHS, 0, 0 },
8294*404b540aSrobert   { CODE_FOR_mqmulxhu, "__MQMULXHU", FRV_BUILTIN_MQMULXHU, 0, 0 },
8295*404b540aSrobert   { CODE_FOR_mqmachs, "__MQMACHS", FRV_BUILTIN_MQMACHS, 0, 0 },
8296*404b540aSrobert   { CODE_FOR_mqmachu, "__MQMACHU", FRV_BUILTIN_MQMACHU, 0, 0 },
8297*404b540aSrobert   { CODE_FOR_mqxmachs, "__MQXMACHS", FRV_BUILTIN_MQXMACHS, 0, 0 },
8298*404b540aSrobert   { CODE_FOR_mqxmacxhs, "__MQXMACXHS", FRV_BUILTIN_MQXMACXHS, 0, 0 },
8299*404b540aSrobert   { CODE_FOR_mqmacxhs, "__MQMACXHS", FRV_BUILTIN_MQMACXHS, 0, 0 }
8300*404b540aSrobert };
8301*404b540aSrobert 
8302*404b540aSrobert /* Media intrinsics that take two accumulator numbers as argument and
8303*404b540aSrobert    return void.  */
8304*404b540aSrobert 
8305*404b540aSrobert static struct builtin_description bdesc_voidacc[] =
8306*404b540aSrobert {
8307*404b540aSrobert   { CODE_FOR_maddaccs, "__MADDACCS", FRV_BUILTIN_MADDACCS, 0, 0 },
8308*404b540aSrobert   { CODE_FOR_msubaccs, "__MSUBACCS", FRV_BUILTIN_MSUBACCS, 0, 0 },
8309*404b540aSrobert   { CODE_FOR_masaccs, "__MASACCS", FRV_BUILTIN_MASACCS, 0, 0 },
8310*404b540aSrobert   { CODE_FOR_mdaddaccs, "__MDADDACCS", FRV_BUILTIN_MDADDACCS, 0, 0 },
8311*404b540aSrobert   { CODE_FOR_mdsubaccs, "__MDSUBACCS", FRV_BUILTIN_MDSUBACCS, 0, 0 },
8312*404b540aSrobert   { CODE_FOR_mdasaccs, "__MDASACCS", FRV_BUILTIN_MDASACCS, 0, 0 }
8313*404b540aSrobert };
8314*404b540aSrobert 
8315*404b540aSrobert /* Intrinsics that load a value and then issue a MEMBAR.  The load is
8316*404b540aSrobert    a normal move and the ICODE is for the membar.  */
8317*404b540aSrobert 
8318*404b540aSrobert static struct builtin_description bdesc_loads[] =
8319*404b540aSrobert {
8320*404b540aSrobert   { CODE_FOR_optional_membar_qi, "__builtin_read8",
8321*404b540aSrobert     FRV_BUILTIN_READ8, 0, 0 },
8322*404b540aSrobert   { CODE_FOR_optional_membar_hi, "__builtin_read16",
8323*404b540aSrobert     FRV_BUILTIN_READ16, 0, 0 },
8324*404b540aSrobert   { CODE_FOR_optional_membar_si, "__builtin_read32",
8325*404b540aSrobert     FRV_BUILTIN_READ32, 0, 0 },
8326*404b540aSrobert   { CODE_FOR_optional_membar_di, "__builtin_read64",
8327*404b540aSrobert     FRV_BUILTIN_READ64, 0, 0 }
8328*404b540aSrobert };
8329*404b540aSrobert 
8330*404b540aSrobert /* Likewise stores.  */
8331*404b540aSrobert 
8332*404b540aSrobert static struct builtin_description bdesc_stores[] =
8333*404b540aSrobert {
8334*404b540aSrobert   { CODE_FOR_optional_membar_qi, "__builtin_write8",
8335*404b540aSrobert     FRV_BUILTIN_WRITE8, 0, 0 },
8336*404b540aSrobert   { CODE_FOR_optional_membar_hi, "__builtin_write16",
8337*404b540aSrobert     FRV_BUILTIN_WRITE16, 0, 0 },
8338*404b540aSrobert   { CODE_FOR_optional_membar_si, "__builtin_write32",
8339*404b540aSrobert     FRV_BUILTIN_WRITE32, 0, 0 },
8340*404b540aSrobert   { CODE_FOR_optional_membar_di, "__builtin_write64",
8341*404b540aSrobert     FRV_BUILTIN_WRITE64, 0, 0 },
8342*404b540aSrobert };
8343*404b540aSrobert 
8344*404b540aSrobert /* Initialize media builtins.  */
8345*404b540aSrobert 
8346*404b540aSrobert static void
frv_init_builtins(void)8347*404b540aSrobert frv_init_builtins (void)
8348*404b540aSrobert {
8349*404b540aSrobert   tree endlink = void_list_node;
8350*404b540aSrobert   tree accumulator = integer_type_node;
8351*404b540aSrobert   tree integer = integer_type_node;
8352*404b540aSrobert   tree voidt = void_type_node;
8353*404b540aSrobert   tree uhalf = short_unsigned_type_node;
8354*404b540aSrobert   tree sword1 = long_integer_type_node;
8355*404b540aSrobert   tree uword1 = long_unsigned_type_node;
8356*404b540aSrobert   tree sword2 = long_long_integer_type_node;
8357*404b540aSrobert   tree uword2 = long_long_unsigned_type_node;
8358*404b540aSrobert   tree uword4 = build_pointer_type (uword1);
8359*404b540aSrobert   tree vptr   = build_pointer_type (build_type_variant (void_type_node, 0, 1));
8360*404b540aSrobert   tree ubyte  = unsigned_char_type_node;
8361*404b540aSrobert   tree iacc   = integer_type_node;
8362*404b540aSrobert 
8363*404b540aSrobert #define UNARY(RET, T1) \
8364*404b540aSrobert   build_function_type (RET, tree_cons (NULL_TREE, T1, endlink))
8365*404b540aSrobert 
8366*404b540aSrobert #define BINARY(RET, T1, T2) \
8367*404b540aSrobert   build_function_type (RET, tree_cons (NULL_TREE, T1, \
8368*404b540aSrobert 			    tree_cons (NULL_TREE, T2, endlink)))
8369*404b540aSrobert 
8370*404b540aSrobert #define TRINARY(RET, T1, T2, T3) \
8371*404b540aSrobert   build_function_type (RET, tree_cons (NULL_TREE, T1, \
8372*404b540aSrobert 			    tree_cons (NULL_TREE, T2, \
8373*404b540aSrobert 			    tree_cons (NULL_TREE, T3, endlink))))
8374*404b540aSrobert 
8375*404b540aSrobert #define QUAD(RET, T1, T2, T3, T4) \
8376*404b540aSrobert   build_function_type (RET, tree_cons (NULL_TREE, T1, \
8377*404b540aSrobert 			    tree_cons (NULL_TREE, T2, \
8378*404b540aSrobert 			    tree_cons (NULL_TREE, T3, \
8379*404b540aSrobert 			    tree_cons (NULL_TREE, T4, endlink)))))
8380*404b540aSrobert 
8381*404b540aSrobert   tree void_ftype_void = build_function_type (voidt, endlink);
8382*404b540aSrobert 
8383*404b540aSrobert   tree void_ftype_acc = UNARY (voidt, accumulator);
8384*404b540aSrobert   tree void_ftype_uw4_uw1 = BINARY (voidt, uword4, uword1);
8385*404b540aSrobert   tree void_ftype_uw4_uw2 = BINARY (voidt, uword4, uword2);
8386*404b540aSrobert   tree void_ftype_acc_uw1 = BINARY (voidt, accumulator, uword1);
8387*404b540aSrobert   tree void_ftype_acc_acc = BINARY (voidt, accumulator, accumulator);
8388*404b540aSrobert   tree void_ftype_acc_uw1_uw1 = TRINARY (voidt, accumulator, uword1, uword1);
8389*404b540aSrobert   tree void_ftype_acc_sw1_sw1 = TRINARY (voidt, accumulator, sword1, sword1);
8390*404b540aSrobert   tree void_ftype_acc_uw2_uw2 = TRINARY (voidt, accumulator, uword2, uword2);
8391*404b540aSrobert   tree void_ftype_acc_sw2_sw2 = TRINARY (voidt, accumulator, sword2, sword2);
8392*404b540aSrobert 
8393*404b540aSrobert   tree uw1_ftype_uw1 = UNARY (uword1, uword1);
8394*404b540aSrobert   tree uw1_ftype_sw1 = UNARY (uword1, sword1);
8395*404b540aSrobert   tree uw1_ftype_uw2 = UNARY (uword1, uword2);
8396*404b540aSrobert   tree uw1_ftype_acc = UNARY (uword1, accumulator);
8397*404b540aSrobert   tree uw1_ftype_uh_uh = BINARY (uword1, uhalf, uhalf);
8398*404b540aSrobert   tree uw1_ftype_uw1_uw1 = BINARY (uword1, uword1, uword1);
8399*404b540aSrobert   tree uw1_ftype_uw1_int = BINARY (uword1, uword1, integer);
8400*404b540aSrobert   tree uw1_ftype_acc_uw1 = BINARY (uword1, accumulator, uword1);
8401*404b540aSrobert   tree uw1_ftype_acc_sw1 = BINARY (uword1, accumulator, sword1);
8402*404b540aSrobert   tree uw1_ftype_uw2_uw1 = BINARY (uword1, uword2, uword1);
8403*404b540aSrobert   tree uw1_ftype_uw2_int = BINARY (uword1, uword2, integer);
8404*404b540aSrobert 
8405*404b540aSrobert   tree sw1_ftype_int = UNARY (sword1, integer);
8406*404b540aSrobert   tree sw1_ftype_sw1_sw1 = BINARY (sword1, sword1, sword1);
8407*404b540aSrobert   tree sw1_ftype_sw1_int = BINARY (sword1, sword1, integer);
8408*404b540aSrobert 
8409*404b540aSrobert   tree uw2_ftype_uw1 = UNARY (uword2, uword1);
8410*404b540aSrobert   tree uw2_ftype_uw1_int = BINARY (uword2, uword1, integer);
8411*404b540aSrobert   tree uw2_ftype_uw2_uw2 = BINARY (uword2, uword2, uword2);
8412*404b540aSrobert   tree uw2_ftype_uw2_int = BINARY (uword2, uword2, integer);
8413*404b540aSrobert   tree uw2_ftype_acc_int = BINARY (uword2, accumulator, integer);
8414*404b540aSrobert   tree uw2_ftype_uh_uh_uh_uh = QUAD (uword2, uhalf, uhalf, uhalf, uhalf);
8415*404b540aSrobert 
8416*404b540aSrobert   tree sw2_ftype_sw2_sw2 = BINARY (sword2, sword2, sword2);
8417*404b540aSrobert   tree sw2_ftype_sw2_int   = BINARY (sword2, sword2, integer);
8418*404b540aSrobert   tree uw2_ftype_uw1_uw1   = BINARY (uword2, uword1, uword1);
8419*404b540aSrobert   tree sw2_ftype_sw1_sw1   = BINARY (sword2, sword1, sword1);
8420*404b540aSrobert   tree void_ftype_sw1_sw1  = BINARY (voidt, sword1, sword1);
8421*404b540aSrobert   tree void_ftype_iacc_sw2 = BINARY (voidt, iacc, sword2);
8422*404b540aSrobert   tree void_ftype_iacc_sw1 = BINARY (voidt, iacc, sword1);
8423*404b540aSrobert   tree sw1_ftype_sw1       = UNARY (sword1, sword1);
8424*404b540aSrobert   tree sw2_ftype_iacc      = UNARY (sword2, iacc);
8425*404b540aSrobert   tree sw1_ftype_iacc      = UNARY (sword1, iacc);
8426*404b540aSrobert   tree void_ftype_ptr      = UNARY (voidt, const_ptr_type_node);
8427*404b540aSrobert   tree uw1_ftype_vptr      = UNARY (uword1, vptr);
8428*404b540aSrobert   tree uw2_ftype_vptr      = UNARY (uword2, vptr);
8429*404b540aSrobert   tree void_ftype_vptr_ub  = BINARY (voidt, vptr, ubyte);
8430*404b540aSrobert   tree void_ftype_vptr_uh  = BINARY (voidt, vptr, uhalf);
8431*404b540aSrobert   tree void_ftype_vptr_uw1 = BINARY (voidt, vptr, uword1);
8432*404b540aSrobert   tree void_ftype_vptr_uw2 = BINARY (voidt, vptr, uword2);
8433*404b540aSrobert 
8434*404b540aSrobert   def_builtin ("__MAND", uw1_ftype_uw1_uw1, FRV_BUILTIN_MAND);
8435*404b540aSrobert   def_builtin ("__MOR", uw1_ftype_uw1_uw1, FRV_BUILTIN_MOR);
8436*404b540aSrobert   def_builtin ("__MXOR", uw1_ftype_uw1_uw1, FRV_BUILTIN_MXOR);
8437*404b540aSrobert   def_builtin ("__MNOT", uw1_ftype_uw1, FRV_BUILTIN_MNOT);
8438*404b540aSrobert   def_builtin ("__MROTLI", uw1_ftype_uw1_int, FRV_BUILTIN_MROTLI);
8439*404b540aSrobert   def_builtin ("__MROTRI", uw1_ftype_uw1_int, FRV_BUILTIN_MROTRI);
8440*404b540aSrobert   def_builtin ("__MWCUT", uw1_ftype_uw2_uw1, FRV_BUILTIN_MWCUT);
8441*404b540aSrobert   def_builtin ("__MAVEH", uw1_ftype_uw1_uw1, FRV_BUILTIN_MAVEH);
8442*404b540aSrobert   def_builtin ("__MSLLHI", uw1_ftype_uw1_int, FRV_BUILTIN_MSLLHI);
8443*404b540aSrobert   def_builtin ("__MSRLHI", uw1_ftype_uw1_int, FRV_BUILTIN_MSRLHI);
8444*404b540aSrobert   def_builtin ("__MSRAHI", sw1_ftype_sw1_int, FRV_BUILTIN_MSRAHI);
8445*404b540aSrobert   def_builtin ("__MSATHS", sw1_ftype_sw1_sw1, FRV_BUILTIN_MSATHS);
8446*404b540aSrobert   def_builtin ("__MSATHU", uw1_ftype_uw1_uw1, FRV_BUILTIN_MSATHU);
8447*404b540aSrobert   def_builtin ("__MADDHSS", sw1_ftype_sw1_sw1, FRV_BUILTIN_MADDHSS);
8448*404b540aSrobert   def_builtin ("__MADDHUS", uw1_ftype_uw1_uw1, FRV_BUILTIN_MADDHUS);
8449*404b540aSrobert   def_builtin ("__MSUBHSS", sw1_ftype_sw1_sw1, FRV_BUILTIN_MSUBHSS);
8450*404b540aSrobert   def_builtin ("__MSUBHUS", uw1_ftype_uw1_uw1, FRV_BUILTIN_MSUBHUS);
8451*404b540aSrobert   def_builtin ("__MMULHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMULHS);
8452*404b540aSrobert   def_builtin ("__MMULHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMULHU);
8453*404b540aSrobert   def_builtin ("__MMULXHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMULXHS);
8454*404b540aSrobert   def_builtin ("__MMULXHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMULXHU);
8455*404b540aSrobert   def_builtin ("__MMACHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMACHS);
8456*404b540aSrobert   def_builtin ("__MMACHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMACHU);
8457*404b540aSrobert   def_builtin ("__MMRDHS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MMRDHS);
8458*404b540aSrobert   def_builtin ("__MMRDHU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MMRDHU);
8459*404b540aSrobert   def_builtin ("__MQADDHSS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQADDHSS);
8460*404b540aSrobert   def_builtin ("__MQADDHUS", uw2_ftype_uw2_uw2, FRV_BUILTIN_MQADDHUS);
8461*404b540aSrobert   def_builtin ("__MQSUBHSS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQSUBHSS);
8462*404b540aSrobert   def_builtin ("__MQSUBHUS", uw2_ftype_uw2_uw2, FRV_BUILTIN_MQSUBHUS);
8463*404b540aSrobert   def_builtin ("__MQMULHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMULHS);
8464*404b540aSrobert   def_builtin ("__MQMULHU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQMULHU);
8465*404b540aSrobert   def_builtin ("__MQMULXHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMULXHS);
8466*404b540aSrobert   def_builtin ("__MQMULXHU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQMULXHU);
8467*404b540aSrobert   def_builtin ("__MQMACHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMACHS);
8468*404b540aSrobert   def_builtin ("__MQMACHU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQMACHU);
8469*404b540aSrobert   def_builtin ("__MCPXRS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MCPXRS);
8470*404b540aSrobert   def_builtin ("__MCPXRU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MCPXRU);
8471*404b540aSrobert   def_builtin ("__MCPXIS", void_ftype_acc_sw1_sw1, FRV_BUILTIN_MCPXIS);
8472*404b540aSrobert   def_builtin ("__MCPXIU", void_ftype_acc_uw1_uw1, FRV_BUILTIN_MCPXIU);
8473*404b540aSrobert   def_builtin ("__MQCPXRS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQCPXRS);
8474*404b540aSrobert   def_builtin ("__MQCPXRU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQCPXRU);
8475*404b540aSrobert   def_builtin ("__MQCPXIS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQCPXIS);
8476*404b540aSrobert   def_builtin ("__MQCPXIU", void_ftype_acc_uw2_uw2, FRV_BUILTIN_MQCPXIU);
8477*404b540aSrobert   def_builtin ("__MCUT", uw1_ftype_acc_uw1, FRV_BUILTIN_MCUT);
8478*404b540aSrobert   def_builtin ("__MCUTSS", uw1_ftype_acc_sw1, FRV_BUILTIN_MCUTSS);
8479*404b540aSrobert   def_builtin ("__MEXPDHW", uw1_ftype_uw1_int, FRV_BUILTIN_MEXPDHW);
8480*404b540aSrobert   def_builtin ("__MEXPDHD", uw2_ftype_uw1_int, FRV_BUILTIN_MEXPDHD);
8481*404b540aSrobert   def_builtin ("__MPACKH", uw1_ftype_uh_uh, FRV_BUILTIN_MPACKH);
8482*404b540aSrobert   def_builtin ("__MUNPACKH", uw2_ftype_uw1, FRV_BUILTIN_MUNPACKH);
8483*404b540aSrobert   def_builtin ("__MDPACKH", uw2_ftype_uh_uh_uh_uh, FRV_BUILTIN_MDPACKH);
8484*404b540aSrobert   def_builtin ("__MDUNPACKH", void_ftype_uw4_uw2, FRV_BUILTIN_MDUNPACKH);
8485*404b540aSrobert   def_builtin ("__MBTOH", uw2_ftype_uw1, FRV_BUILTIN_MBTOH);
8486*404b540aSrobert   def_builtin ("__MHTOB", uw1_ftype_uw2, FRV_BUILTIN_MHTOB);
8487*404b540aSrobert   def_builtin ("__MBTOHE", void_ftype_uw4_uw1, FRV_BUILTIN_MBTOHE);
8488*404b540aSrobert   def_builtin ("__MCLRACC", void_ftype_acc, FRV_BUILTIN_MCLRACC);
8489*404b540aSrobert   def_builtin ("__MCLRACCA", void_ftype_void, FRV_BUILTIN_MCLRACCA);
8490*404b540aSrobert   def_builtin ("__MRDACC", uw1_ftype_acc, FRV_BUILTIN_MRDACC);
8491*404b540aSrobert   def_builtin ("__MRDACCG", uw1_ftype_acc, FRV_BUILTIN_MRDACCG);
8492*404b540aSrobert   def_builtin ("__MWTACC", void_ftype_acc_uw1, FRV_BUILTIN_MWTACC);
8493*404b540aSrobert   def_builtin ("__MWTACCG", void_ftype_acc_uw1, FRV_BUILTIN_MWTACCG);
8494*404b540aSrobert   def_builtin ("__Mcop1", uw1_ftype_uw1_uw1, FRV_BUILTIN_MCOP1);
8495*404b540aSrobert   def_builtin ("__Mcop2", uw1_ftype_uw1_uw1, FRV_BUILTIN_MCOP2);
8496*404b540aSrobert   def_builtin ("__MTRAP", void_ftype_void, FRV_BUILTIN_MTRAP);
8497*404b540aSrobert   def_builtin ("__MQXMACHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQXMACHS);
8498*404b540aSrobert   def_builtin ("__MQXMACXHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQXMACXHS);
8499*404b540aSrobert   def_builtin ("__MQMACXHS", void_ftype_acc_sw2_sw2, FRV_BUILTIN_MQMACXHS);
8500*404b540aSrobert   def_builtin ("__MADDACCS", void_ftype_acc_acc, FRV_BUILTIN_MADDACCS);
8501*404b540aSrobert   def_builtin ("__MSUBACCS", void_ftype_acc_acc, FRV_BUILTIN_MSUBACCS);
8502*404b540aSrobert   def_builtin ("__MASACCS", void_ftype_acc_acc, FRV_BUILTIN_MASACCS);
8503*404b540aSrobert   def_builtin ("__MDADDACCS", void_ftype_acc_acc, FRV_BUILTIN_MDADDACCS);
8504*404b540aSrobert   def_builtin ("__MDSUBACCS", void_ftype_acc_acc, FRV_BUILTIN_MDSUBACCS);
8505*404b540aSrobert   def_builtin ("__MDASACCS", void_ftype_acc_acc, FRV_BUILTIN_MDASACCS);
8506*404b540aSrobert   def_builtin ("__MABSHS", uw1_ftype_sw1, FRV_BUILTIN_MABSHS);
8507*404b540aSrobert   def_builtin ("__MDROTLI", uw2_ftype_uw2_int, FRV_BUILTIN_MDROTLI);
8508*404b540aSrobert   def_builtin ("__MCPLHI", uw1_ftype_uw2_int, FRV_BUILTIN_MCPLHI);
8509*404b540aSrobert   def_builtin ("__MCPLI", uw1_ftype_uw2_int, FRV_BUILTIN_MCPLI);
8510*404b540aSrobert   def_builtin ("__MDCUTSSI", uw2_ftype_acc_int, FRV_BUILTIN_MDCUTSSI);
8511*404b540aSrobert   def_builtin ("__MQSATHS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQSATHS);
8512*404b540aSrobert   def_builtin ("__MHSETLOS", sw1_ftype_sw1_int, FRV_BUILTIN_MHSETLOS);
8513*404b540aSrobert   def_builtin ("__MHSETHIS", sw1_ftype_sw1_int, FRV_BUILTIN_MHSETHIS);
8514*404b540aSrobert   def_builtin ("__MHDSETS", sw1_ftype_int, FRV_BUILTIN_MHDSETS);
8515*404b540aSrobert   def_builtin ("__MHSETLOH", uw1_ftype_uw1_int, FRV_BUILTIN_MHSETLOH);
8516*404b540aSrobert   def_builtin ("__MHSETHIH", uw1_ftype_uw1_int, FRV_BUILTIN_MHSETHIH);
8517*404b540aSrobert   def_builtin ("__MHDSETH", uw1_ftype_uw1_int, FRV_BUILTIN_MHDSETH);
8518*404b540aSrobert   def_builtin ("__MQLCLRHS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQLCLRHS);
8519*404b540aSrobert   def_builtin ("__MQLMTHS", sw2_ftype_sw2_sw2, FRV_BUILTIN_MQLMTHS);
8520*404b540aSrobert   def_builtin ("__MQSLLHI", uw2_ftype_uw2_int, FRV_BUILTIN_MQSLLHI);
8521*404b540aSrobert   def_builtin ("__MQSRAHI", sw2_ftype_sw2_int, FRV_BUILTIN_MQSRAHI);
8522*404b540aSrobert   def_builtin ("__SMUL", sw2_ftype_sw1_sw1, FRV_BUILTIN_SMUL);
8523*404b540aSrobert   def_builtin ("__UMUL", uw2_ftype_uw1_uw1, FRV_BUILTIN_UMUL);
8524*404b540aSrobert   def_builtin ("__SMASS", void_ftype_sw1_sw1, FRV_BUILTIN_SMASS);
8525*404b540aSrobert   def_builtin ("__SMSSS", void_ftype_sw1_sw1, FRV_BUILTIN_SMSSS);
8526*404b540aSrobert   def_builtin ("__SMU", void_ftype_sw1_sw1, FRV_BUILTIN_SMU);
8527*404b540aSrobert   def_builtin ("__ADDSS", sw1_ftype_sw1_sw1, FRV_BUILTIN_ADDSS);
8528*404b540aSrobert   def_builtin ("__SUBSS", sw1_ftype_sw1_sw1, FRV_BUILTIN_SUBSS);
8529*404b540aSrobert   def_builtin ("__SLASS", sw1_ftype_sw1_sw1, FRV_BUILTIN_SLASS);
8530*404b540aSrobert   def_builtin ("__SCAN", sw1_ftype_sw1_sw1, FRV_BUILTIN_SCAN);
8531*404b540aSrobert   def_builtin ("__SCUTSS", sw1_ftype_sw1, FRV_BUILTIN_SCUTSS);
8532*404b540aSrobert   def_builtin ("__IACCreadll", sw2_ftype_iacc, FRV_BUILTIN_IACCreadll);
8533*404b540aSrobert   def_builtin ("__IACCreadl", sw1_ftype_iacc, FRV_BUILTIN_IACCreadl);
8534*404b540aSrobert   def_builtin ("__IACCsetll", void_ftype_iacc_sw2, FRV_BUILTIN_IACCsetll);
8535*404b540aSrobert   def_builtin ("__IACCsetl", void_ftype_iacc_sw1, FRV_BUILTIN_IACCsetl);
8536*404b540aSrobert   def_builtin ("__data_prefetch0", void_ftype_ptr, FRV_BUILTIN_PREFETCH0);
8537*404b540aSrobert   def_builtin ("__data_prefetch", void_ftype_ptr, FRV_BUILTIN_PREFETCH);
8538*404b540aSrobert   def_builtin ("__builtin_read8", uw1_ftype_vptr, FRV_BUILTIN_READ8);
8539*404b540aSrobert   def_builtin ("__builtin_read16", uw1_ftype_vptr, FRV_BUILTIN_READ16);
8540*404b540aSrobert   def_builtin ("__builtin_read32", uw1_ftype_vptr, FRV_BUILTIN_READ32);
8541*404b540aSrobert   def_builtin ("__builtin_read64", uw2_ftype_vptr, FRV_BUILTIN_READ64);
8542*404b540aSrobert 
8543*404b540aSrobert   def_builtin ("__builtin_write8", void_ftype_vptr_ub, FRV_BUILTIN_WRITE8);
8544*404b540aSrobert   def_builtin ("__builtin_write16", void_ftype_vptr_uh, FRV_BUILTIN_WRITE16);
8545*404b540aSrobert   def_builtin ("__builtin_write32", void_ftype_vptr_uw1, FRV_BUILTIN_WRITE32);
8546*404b540aSrobert   def_builtin ("__builtin_write64", void_ftype_vptr_uw2, FRV_BUILTIN_WRITE64);
8547*404b540aSrobert 
8548*404b540aSrobert #undef UNARY
8549*404b540aSrobert #undef BINARY
8550*404b540aSrobert #undef TRINARY
8551*404b540aSrobert #undef QUAD
8552*404b540aSrobert }
8553*404b540aSrobert 
8554*404b540aSrobert /* Set the names for various arithmetic operations according to the
8555*404b540aSrobert    FRV ABI.  */
8556*404b540aSrobert static void
frv_init_libfuncs(void)8557*404b540aSrobert frv_init_libfuncs (void)
8558*404b540aSrobert {
8559*404b540aSrobert   set_optab_libfunc (smod_optab,     SImode, "__modi");
8560*404b540aSrobert   set_optab_libfunc (umod_optab,     SImode, "__umodi");
8561*404b540aSrobert 
8562*404b540aSrobert   set_optab_libfunc (add_optab,      DImode, "__addll");
8563*404b540aSrobert   set_optab_libfunc (sub_optab,      DImode, "__subll");
8564*404b540aSrobert   set_optab_libfunc (smul_optab,     DImode, "__mulll");
8565*404b540aSrobert   set_optab_libfunc (sdiv_optab,     DImode, "__divll");
8566*404b540aSrobert   set_optab_libfunc (smod_optab,     DImode, "__modll");
8567*404b540aSrobert   set_optab_libfunc (umod_optab,     DImode, "__umodll");
8568*404b540aSrobert   set_optab_libfunc (and_optab,      DImode, "__andll");
8569*404b540aSrobert   set_optab_libfunc (ior_optab,      DImode, "__orll");
8570*404b540aSrobert   set_optab_libfunc (xor_optab,      DImode, "__xorll");
8571*404b540aSrobert   set_optab_libfunc (one_cmpl_optab, DImode, "__notll");
8572*404b540aSrobert 
8573*404b540aSrobert   set_optab_libfunc (add_optab,      SFmode, "__addf");
8574*404b540aSrobert   set_optab_libfunc (sub_optab,      SFmode, "__subf");
8575*404b540aSrobert   set_optab_libfunc (smul_optab,     SFmode, "__mulf");
8576*404b540aSrobert   set_optab_libfunc (sdiv_optab,     SFmode, "__divf");
8577*404b540aSrobert 
8578*404b540aSrobert   set_optab_libfunc (add_optab,      DFmode, "__addd");
8579*404b540aSrobert   set_optab_libfunc (sub_optab,      DFmode, "__subd");
8580*404b540aSrobert   set_optab_libfunc (smul_optab,     DFmode, "__muld");
8581*404b540aSrobert   set_optab_libfunc (sdiv_optab,     DFmode, "__divd");
8582*404b540aSrobert 
8583*404b540aSrobert   set_conv_libfunc (sext_optab,   DFmode, SFmode, "__ftod");
8584*404b540aSrobert   set_conv_libfunc (trunc_optab,  SFmode, DFmode, "__dtof");
8585*404b540aSrobert 
8586*404b540aSrobert   set_conv_libfunc (sfix_optab,   SImode, SFmode, "__ftoi");
8587*404b540aSrobert   set_conv_libfunc (sfix_optab,   DImode, SFmode, "__ftoll");
8588*404b540aSrobert   set_conv_libfunc (sfix_optab,   SImode, DFmode, "__dtoi");
8589*404b540aSrobert   set_conv_libfunc (sfix_optab,   DImode, DFmode, "__dtoll");
8590*404b540aSrobert 
8591*404b540aSrobert   set_conv_libfunc (ufix_optab,   SImode, SFmode, "__ftoui");
8592*404b540aSrobert   set_conv_libfunc (ufix_optab,   DImode, SFmode, "__ftoull");
8593*404b540aSrobert   set_conv_libfunc (ufix_optab,   SImode, DFmode, "__dtoui");
8594*404b540aSrobert   set_conv_libfunc (ufix_optab,   DImode, DFmode, "__dtoull");
8595*404b540aSrobert 
8596*404b540aSrobert   set_conv_libfunc (sfloat_optab, SFmode, SImode, "__itof");
8597*404b540aSrobert   set_conv_libfunc (sfloat_optab, SFmode, DImode, "__lltof");
8598*404b540aSrobert   set_conv_libfunc (sfloat_optab, DFmode, SImode, "__itod");
8599*404b540aSrobert   set_conv_libfunc (sfloat_optab, DFmode, DImode, "__lltod");
8600*404b540aSrobert }
8601*404b540aSrobert 
8602*404b540aSrobert /* Convert an integer constant to an accumulator register.  ICODE is the
8603*404b540aSrobert    code of the target instruction, OPNUM is the number of the
8604*404b540aSrobert    accumulator operand and OPVAL is the constant integer.  Try both
8605*404b540aSrobert    ACC and ACCG registers; only report an error if neither fit the
8606*404b540aSrobert    instruction.  */
8607*404b540aSrobert 
8608*404b540aSrobert static rtx
frv_int_to_acc(enum insn_code icode,int opnum,rtx opval)8609*404b540aSrobert frv_int_to_acc (enum insn_code icode, int opnum, rtx opval)
8610*404b540aSrobert {
8611*404b540aSrobert   rtx reg;
8612*404b540aSrobert   int i;
8613*404b540aSrobert 
8614*404b540aSrobert   /* ACCs and ACCGs are implicit global registers if media intrinsics
8615*404b540aSrobert      are being used.  We set up this lazily to avoid creating lots of
8616*404b540aSrobert      unnecessary call_insn rtl in non-media code.  */
8617*404b540aSrobert   for (i = 0; i <= ACC_MASK; i++)
8618*404b540aSrobert     if ((i & ACC_MASK) == i)
8619*404b540aSrobert       global_regs[i + ACC_FIRST] = global_regs[i + ACCG_FIRST] = 1;
8620*404b540aSrobert 
8621*404b540aSrobert   if (GET_CODE (opval) != CONST_INT)
8622*404b540aSrobert     {
8623*404b540aSrobert       error ("accumulator is not a constant integer");
8624*404b540aSrobert       return NULL_RTX;
8625*404b540aSrobert     }
8626*404b540aSrobert   if ((INTVAL (opval) & ~ACC_MASK) != 0)
8627*404b540aSrobert     {
8628*404b540aSrobert       error ("accumulator number is out of bounds");
8629*404b540aSrobert       return NULL_RTX;
8630*404b540aSrobert     }
8631*404b540aSrobert 
8632*404b540aSrobert   reg = gen_rtx_REG (insn_data[icode].operand[opnum].mode,
8633*404b540aSrobert 		     ACC_FIRST + INTVAL (opval));
8634*404b540aSrobert   if (! (*insn_data[icode].operand[opnum].predicate) (reg, VOIDmode))
8635*404b540aSrobert     REGNO (reg) = ACCG_FIRST + INTVAL (opval);
8636*404b540aSrobert 
8637*404b540aSrobert   if (! (*insn_data[icode].operand[opnum].predicate) (reg, VOIDmode))
8638*404b540aSrobert     {
8639*404b540aSrobert       error ("inappropriate accumulator for %qs", insn_data[icode].name);
8640*404b540aSrobert       return NULL_RTX;
8641*404b540aSrobert     }
8642*404b540aSrobert   return reg;
8643*404b540aSrobert }
8644*404b540aSrobert 
8645*404b540aSrobert /* If an ACC rtx has mode MODE, return the mode that the matching ACCG
8646*404b540aSrobert    should have.  */
8647*404b540aSrobert 
8648*404b540aSrobert static enum machine_mode
frv_matching_accg_mode(enum machine_mode mode)8649*404b540aSrobert frv_matching_accg_mode (enum machine_mode mode)
8650*404b540aSrobert {
8651*404b540aSrobert   switch (mode)
8652*404b540aSrobert     {
8653*404b540aSrobert     case V4SImode:
8654*404b540aSrobert       return V4QImode;
8655*404b540aSrobert 
8656*404b540aSrobert     case DImode:
8657*404b540aSrobert       return HImode;
8658*404b540aSrobert 
8659*404b540aSrobert     case SImode:
8660*404b540aSrobert       return QImode;
8661*404b540aSrobert 
8662*404b540aSrobert     default:
8663*404b540aSrobert       gcc_unreachable ();
8664*404b540aSrobert     }
8665*404b540aSrobert }
8666*404b540aSrobert 
8667*404b540aSrobert /* Given that a __builtin_read or __builtin_write function is accessing
8668*404b540aSrobert    address ADDRESS, return the value that should be used as operand 1
8669*404b540aSrobert    of the membar.  */
8670*404b540aSrobert 
8671*404b540aSrobert static rtx
frv_io_address_cookie(rtx address)8672*404b540aSrobert frv_io_address_cookie (rtx address)
8673*404b540aSrobert {
8674*404b540aSrobert   return (GET_CODE (address) == CONST_INT
8675*404b540aSrobert 	  ? GEN_INT (INTVAL (address) / 8 * 8)
8676*404b540aSrobert 	  : const0_rtx);
8677*404b540aSrobert }
8678*404b540aSrobert 
8679*404b540aSrobert /* Return the accumulator guard that should be paired with accumulator
8680*404b540aSrobert    register ACC.  The mode of the returned register is in the same
8681*404b540aSrobert    class as ACC, but is four times smaller.  */
8682*404b540aSrobert 
8683*404b540aSrobert rtx
frv_matching_accg_for_acc(rtx acc)8684*404b540aSrobert frv_matching_accg_for_acc (rtx acc)
8685*404b540aSrobert {
8686*404b540aSrobert   return gen_rtx_REG (frv_matching_accg_mode (GET_MODE (acc)),
8687*404b540aSrobert 		      REGNO (acc) - ACC_FIRST + ACCG_FIRST);
8688*404b540aSrobert }
8689*404b540aSrobert 
8690*404b540aSrobert /* Read a value from the head of the tree list pointed to by ARGLISTPTR.
8691*404b540aSrobert    Return the value as an rtx and replace *ARGLISTPTR with the tail of the
8692*404b540aSrobert    list.  */
8693*404b540aSrobert 
8694*404b540aSrobert static rtx
frv_read_argument(tree * arglistptr)8695*404b540aSrobert frv_read_argument (tree *arglistptr)
8696*404b540aSrobert {
8697*404b540aSrobert   tree next = TREE_VALUE (*arglistptr);
8698*404b540aSrobert   *arglistptr = TREE_CHAIN (*arglistptr);
8699*404b540aSrobert   return expand_expr (next, NULL_RTX, VOIDmode, 0);
8700*404b540aSrobert }
8701*404b540aSrobert 
8702*404b540aSrobert /* Like frv_read_argument, but interpret the argument as the number
8703*404b540aSrobert    of an IACC register and return a (reg:MODE ...) rtx for it.  */
8704*404b540aSrobert 
8705*404b540aSrobert static rtx
frv_read_iacc_argument(enum machine_mode mode,tree * arglistptr)8706*404b540aSrobert frv_read_iacc_argument (enum machine_mode mode, tree *arglistptr)
8707*404b540aSrobert {
8708*404b540aSrobert   int i, regno;
8709*404b540aSrobert   rtx op;
8710*404b540aSrobert 
8711*404b540aSrobert   op = frv_read_argument (arglistptr);
8712*404b540aSrobert   if (GET_CODE (op) != CONST_INT
8713*404b540aSrobert       || INTVAL (op) < 0
8714*404b540aSrobert       || INTVAL (op) > IACC_LAST - IACC_FIRST
8715*404b540aSrobert       || ((INTVAL (op) * 4) & (GET_MODE_SIZE (mode) - 1)) != 0)
8716*404b540aSrobert     {
8717*404b540aSrobert       error ("invalid IACC argument");
8718*404b540aSrobert       op = const0_rtx;
8719*404b540aSrobert     }
8720*404b540aSrobert 
8721*404b540aSrobert   /* IACCs are implicit global registers.  We set up this lazily to
8722*404b540aSrobert      avoid creating lots of unnecessary call_insn rtl when IACCs aren't
8723*404b540aSrobert      being used.  */
8724*404b540aSrobert   regno = INTVAL (op) + IACC_FIRST;
8725*404b540aSrobert   for (i = 0; i < HARD_REGNO_NREGS (regno, mode); i++)
8726*404b540aSrobert     global_regs[regno + i] = 1;
8727*404b540aSrobert 
8728*404b540aSrobert   return gen_rtx_REG (mode, regno);
8729*404b540aSrobert }
8730*404b540aSrobert 
8731*404b540aSrobert /* Return true if OPVAL can be used for operand OPNUM of instruction ICODE.
8732*404b540aSrobert    The instruction should require a constant operand of some sort.  The
8733*404b540aSrobert    function prints an error if OPVAL is not valid.  */
8734*404b540aSrobert 
8735*404b540aSrobert static int
frv_check_constant_argument(enum insn_code icode,int opnum,rtx opval)8736*404b540aSrobert frv_check_constant_argument (enum insn_code icode, int opnum, rtx opval)
8737*404b540aSrobert {
8738*404b540aSrobert   if (GET_CODE (opval) != CONST_INT)
8739*404b540aSrobert     {
8740*404b540aSrobert       error ("%qs expects a constant argument", insn_data[icode].name);
8741*404b540aSrobert       return FALSE;
8742*404b540aSrobert     }
8743*404b540aSrobert   if (! (*insn_data[icode].operand[opnum].predicate) (opval, VOIDmode))
8744*404b540aSrobert     {
8745*404b540aSrobert       error ("constant argument out of range for %qs", insn_data[icode].name);
8746*404b540aSrobert       return FALSE;
8747*404b540aSrobert     }
8748*404b540aSrobert   return TRUE;
8749*404b540aSrobert }
8750*404b540aSrobert 
8751*404b540aSrobert /* Return a legitimate rtx for instruction ICODE's return value.  Use TARGET
8752*404b540aSrobert    if it's not null, has the right mode, and satisfies operand 0's
8753*404b540aSrobert    predicate.  */
8754*404b540aSrobert 
8755*404b540aSrobert static rtx
frv_legitimize_target(enum insn_code icode,rtx target)8756*404b540aSrobert frv_legitimize_target (enum insn_code icode, rtx target)
8757*404b540aSrobert {
8758*404b540aSrobert   enum machine_mode mode = insn_data[icode].operand[0].mode;
8759*404b540aSrobert 
8760*404b540aSrobert   if (! target
8761*404b540aSrobert       || GET_MODE (target) != mode
8762*404b540aSrobert       || ! (*insn_data[icode].operand[0].predicate) (target, mode))
8763*404b540aSrobert     return gen_reg_rtx (mode);
8764*404b540aSrobert   else
8765*404b540aSrobert     return target;
8766*404b540aSrobert }
8767*404b540aSrobert 
8768*404b540aSrobert /* Given that ARG is being passed as operand OPNUM to instruction ICODE,
8769*404b540aSrobert    check whether ARG satisfies the operand's constraints.  If it doesn't,
8770*404b540aSrobert    copy ARG to a temporary register and return that.  Otherwise return ARG
8771*404b540aSrobert    itself.  */
8772*404b540aSrobert 
8773*404b540aSrobert static rtx
frv_legitimize_argument(enum insn_code icode,int opnum,rtx arg)8774*404b540aSrobert frv_legitimize_argument (enum insn_code icode, int opnum, rtx arg)
8775*404b540aSrobert {
8776*404b540aSrobert   enum machine_mode mode = insn_data[icode].operand[opnum].mode;
8777*404b540aSrobert 
8778*404b540aSrobert   if ((*insn_data[icode].operand[opnum].predicate) (arg, mode))
8779*404b540aSrobert     return arg;
8780*404b540aSrobert   else
8781*404b540aSrobert     return copy_to_mode_reg (mode, arg);
8782*404b540aSrobert }
8783*404b540aSrobert 
8784*404b540aSrobert /* Return a volatile memory reference of mode MODE whose address is ARG.  */
8785*404b540aSrobert 
8786*404b540aSrobert static rtx
frv_volatile_memref(enum machine_mode mode,rtx arg)8787*404b540aSrobert frv_volatile_memref (enum machine_mode mode, rtx arg)
8788*404b540aSrobert {
8789*404b540aSrobert   rtx mem;
8790*404b540aSrobert 
8791*404b540aSrobert   mem = gen_rtx_MEM (mode, memory_address (mode, arg));
8792*404b540aSrobert   MEM_VOLATILE_P (mem) = 1;
8793*404b540aSrobert   return mem;
8794*404b540aSrobert }
8795*404b540aSrobert 
8796*404b540aSrobert /* Expand builtins that take a single, constant argument.  At the moment,
8797*404b540aSrobert    only MHDSETS falls into this category.  */
8798*404b540aSrobert 
8799*404b540aSrobert static rtx
frv_expand_set_builtin(enum insn_code icode,tree arglist,rtx target)8800*404b540aSrobert frv_expand_set_builtin (enum insn_code icode, tree arglist, rtx target)
8801*404b540aSrobert {
8802*404b540aSrobert   rtx pat;
8803*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
8804*404b540aSrobert 
8805*404b540aSrobert   if (! frv_check_constant_argument (icode, 1, op0))
8806*404b540aSrobert     return NULL_RTX;
8807*404b540aSrobert 
8808*404b540aSrobert   target = frv_legitimize_target (icode, target);
8809*404b540aSrobert   pat = GEN_FCN (icode) (target, op0);
8810*404b540aSrobert   if (! pat)
8811*404b540aSrobert     return NULL_RTX;
8812*404b540aSrobert 
8813*404b540aSrobert   emit_insn (pat);
8814*404b540aSrobert   return target;
8815*404b540aSrobert }
8816*404b540aSrobert 
8817*404b540aSrobert /* Expand builtins that take one operand.  */
8818*404b540aSrobert 
8819*404b540aSrobert static rtx
frv_expand_unop_builtin(enum insn_code icode,tree arglist,rtx target)8820*404b540aSrobert frv_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
8821*404b540aSrobert {
8822*404b540aSrobert   rtx pat;
8823*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
8824*404b540aSrobert 
8825*404b540aSrobert   target = frv_legitimize_target (icode, target);
8826*404b540aSrobert   op0 = frv_legitimize_argument (icode, 1, op0);
8827*404b540aSrobert   pat = GEN_FCN (icode) (target, op0);
8828*404b540aSrobert   if (! pat)
8829*404b540aSrobert     return NULL_RTX;
8830*404b540aSrobert 
8831*404b540aSrobert   emit_insn (pat);
8832*404b540aSrobert   return target;
8833*404b540aSrobert }
8834*404b540aSrobert 
8835*404b540aSrobert /* Expand builtins that take two operands.  */
8836*404b540aSrobert 
8837*404b540aSrobert static rtx
frv_expand_binop_builtin(enum insn_code icode,tree arglist,rtx target)8838*404b540aSrobert frv_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
8839*404b540aSrobert {
8840*404b540aSrobert   rtx pat;
8841*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
8842*404b540aSrobert   rtx op1 = frv_read_argument (&arglist);
8843*404b540aSrobert 
8844*404b540aSrobert   target = frv_legitimize_target (icode, target);
8845*404b540aSrobert   op0 = frv_legitimize_argument (icode, 1, op0);
8846*404b540aSrobert   op1 = frv_legitimize_argument (icode, 2, op1);
8847*404b540aSrobert   pat = GEN_FCN (icode) (target, op0, op1);
8848*404b540aSrobert   if (! pat)
8849*404b540aSrobert     return NULL_RTX;
8850*404b540aSrobert 
8851*404b540aSrobert   emit_insn (pat);
8852*404b540aSrobert   return target;
8853*404b540aSrobert }
8854*404b540aSrobert 
8855*404b540aSrobert /* Expand cut-style builtins, which take two operands and an implicit ACCG
8856*404b540aSrobert    one.  */
8857*404b540aSrobert 
8858*404b540aSrobert static rtx
frv_expand_cut_builtin(enum insn_code icode,tree arglist,rtx target)8859*404b540aSrobert frv_expand_cut_builtin (enum insn_code icode, tree arglist, rtx target)
8860*404b540aSrobert {
8861*404b540aSrobert   rtx pat;
8862*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
8863*404b540aSrobert   rtx op1 = frv_read_argument (&arglist);
8864*404b540aSrobert   rtx op2;
8865*404b540aSrobert 
8866*404b540aSrobert   target = frv_legitimize_target (icode, target);
8867*404b540aSrobert   op0 = frv_int_to_acc (icode, 1, op0);
8868*404b540aSrobert   if (! op0)
8869*404b540aSrobert     return NULL_RTX;
8870*404b540aSrobert 
8871*404b540aSrobert   if (icode == CODE_FOR_mdcutssi || GET_CODE (op1) == CONST_INT)
8872*404b540aSrobert     {
8873*404b540aSrobert       if (! frv_check_constant_argument (icode, 2, op1))
8874*404b540aSrobert     	return NULL_RTX;
8875*404b540aSrobert     }
8876*404b540aSrobert   else
8877*404b540aSrobert     op1 = frv_legitimize_argument (icode, 2, op1);
8878*404b540aSrobert 
8879*404b540aSrobert   op2 = frv_matching_accg_for_acc (op0);
8880*404b540aSrobert   pat = GEN_FCN (icode) (target, op0, op1, op2);
8881*404b540aSrobert   if (! pat)
8882*404b540aSrobert     return NULL_RTX;
8883*404b540aSrobert 
8884*404b540aSrobert   emit_insn (pat);
8885*404b540aSrobert   return target;
8886*404b540aSrobert }
8887*404b540aSrobert 
8888*404b540aSrobert /* Expand builtins that take two operands and the second is immediate.  */
8889*404b540aSrobert 
8890*404b540aSrobert static rtx
frv_expand_binopimm_builtin(enum insn_code icode,tree arglist,rtx target)8891*404b540aSrobert frv_expand_binopimm_builtin (enum insn_code icode, tree arglist, rtx target)
8892*404b540aSrobert {
8893*404b540aSrobert   rtx pat;
8894*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
8895*404b540aSrobert   rtx op1 = frv_read_argument (&arglist);
8896*404b540aSrobert 
8897*404b540aSrobert   if (! frv_check_constant_argument (icode, 2, op1))
8898*404b540aSrobert     return NULL_RTX;
8899*404b540aSrobert 
8900*404b540aSrobert   target = frv_legitimize_target (icode, target);
8901*404b540aSrobert   op0 = frv_legitimize_argument (icode, 1, op0);
8902*404b540aSrobert   pat = GEN_FCN (icode) (target, op0, op1);
8903*404b540aSrobert   if (! pat)
8904*404b540aSrobert     return NULL_RTX;
8905*404b540aSrobert 
8906*404b540aSrobert   emit_insn (pat);
8907*404b540aSrobert   return target;
8908*404b540aSrobert }
8909*404b540aSrobert 
8910*404b540aSrobert /* Expand builtins that take two operands, the first operand being a pointer to
8911*404b540aSrobert    ints and return void.  */
8912*404b540aSrobert 
8913*404b540aSrobert static rtx
frv_expand_voidbinop_builtin(enum insn_code icode,tree arglist)8914*404b540aSrobert frv_expand_voidbinop_builtin (enum insn_code icode, tree arglist)
8915*404b540aSrobert {
8916*404b540aSrobert   rtx pat;
8917*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
8918*404b540aSrobert   rtx op1 = frv_read_argument (&arglist);
8919*404b540aSrobert   enum machine_mode mode0 = insn_data[icode].operand[0].mode;
8920*404b540aSrobert   rtx addr;
8921*404b540aSrobert 
8922*404b540aSrobert   if (GET_CODE (op0) != MEM)
8923*404b540aSrobert     {
8924*404b540aSrobert       rtx reg = op0;
8925*404b540aSrobert 
8926*404b540aSrobert       if (! offsettable_address_p (0, mode0, op0))
8927*404b540aSrobert 	{
8928*404b540aSrobert 	  reg = gen_reg_rtx (Pmode);
8929*404b540aSrobert 	  emit_insn (gen_rtx_SET (VOIDmode, reg, op0));
8930*404b540aSrobert 	}
8931*404b540aSrobert 
8932*404b540aSrobert       op0 = gen_rtx_MEM (SImode, reg);
8933*404b540aSrobert     }
8934*404b540aSrobert 
8935*404b540aSrobert   addr = XEXP (op0, 0);
8936*404b540aSrobert   if (! offsettable_address_p (0, mode0, addr))
8937*404b540aSrobert     addr = copy_to_mode_reg (Pmode, op0);
8938*404b540aSrobert 
8939*404b540aSrobert   op0 = change_address (op0, V4SImode, addr);
8940*404b540aSrobert   op1 = frv_legitimize_argument (icode, 1, op1);
8941*404b540aSrobert   pat = GEN_FCN (icode) (op0, op1);
8942*404b540aSrobert   if (! pat)
8943*404b540aSrobert     return 0;
8944*404b540aSrobert 
8945*404b540aSrobert   emit_insn (pat);
8946*404b540aSrobert   return 0;
8947*404b540aSrobert }
8948*404b540aSrobert 
8949*404b540aSrobert /* Expand builtins that take two long operands and return void.  */
8950*404b540aSrobert 
8951*404b540aSrobert static rtx
frv_expand_int_void2arg(enum insn_code icode,tree arglist)8952*404b540aSrobert frv_expand_int_void2arg (enum insn_code icode, tree arglist)
8953*404b540aSrobert {
8954*404b540aSrobert   rtx pat;
8955*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
8956*404b540aSrobert   rtx op1 = frv_read_argument (&arglist);
8957*404b540aSrobert 
8958*404b540aSrobert   op0 = frv_legitimize_argument (icode, 1, op0);
8959*404b540aSrobert   op1 = frv_legitimize_argument (icode, 1, op1);
8960*404b540aSrobert   pat = GEN_FCN (icode) (op0, op1);
8961*404b540aSrobert   if (! pat)
8962*404b540aSrobert     return NULL_RTX;
8963*404b540aSrobert 
8964*404b540aSrobert   emit_insn (pat);
8965*404b540aSrobert   return NULL_RTX;
8966*404b540aSrobert }
8967*404b540aSrobert 
8968*404b540aSrobert /* Expand prefetch builtins.  These take a single address as argument.  */
8969*404b540aSrobert 
8970*404b540aSrobert static rtx
frv_expand_prefetches(enum insn_code icode,tree arglist)8971*404b540aSrobert frv_expand_prefetches (enum insn_code icode, tree arglist)
8972*404b540aSrobert {
8973*404b540aSrobert   rtx pat;
8974*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
8975*404b540aSrobert 
8976*404b540aSrobert   pat = GEN_FCN (icode) (force_reg (Pmode, op0));
8977*404b540aSrobert   if (! pat)
8978*404b540aSrobert     return 0;
8979*404b540aSrobert 
8980*404b540aSrobert   emit_insn (pat);
8981*404b540aSrobert   return 0;
8982*404b540aSrobert }
8983*404b540aSrobert 
8984*404b540aSrobert /* Expand builtins that take three operands and return void.  The first
8985*404b540aSrobert    argument must be a constant that describes a pair or quad accumulators.  A
8986*404b540aSrobert    fourth argument is created that is the accumulator guard register that
8987*404b540aSrobert    corresponds to the accumulator.  */
8988*404b540aSrobert 
8989*404b540aSrobert static rtx
frv_expand_voidtriop_builtin(enum insn_code icode,tree arglist)8990*404b540aSrobert frv_expand_voidtriop_builtin (enum insn_code icode, tree arglist)
8991*404b540aSrobert {
8992*404b540aSrobert   rtx pat;
8993*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
8994*404b540aSrobert   rtx op1 = frv_read_argument (&arglist);
8995*404b540aSrobert   rtx op2 = frv_read_argument (&arglist);
8996*404b540aSrobert   rtx op3;
8997*404b540aSrobert 
8998*404b540aSrobert   op0 = frv_int_to_acc (icode, 0, op0);
8999*404b540aSrobert   if (! op0)
9000*404b540aSrobert     return NULL_RTX;
9001*404b540aSrobert 
9002*404b540aSrobert   op1 = frv_legitimize_argument (icode, 1, op1);
9003*404b540aSrobert   op2 = frv_legitimize_argument (icode, 2, op2);
9004*404b540aSrobert   op3 = frv_matching_accg_for_acc (op0);
9005*404b540aSrobert   pat = GEN_FCN (icode) (op0, op1, op2, op3);
9006*404b540aSrobert   if (! pat)
9007*404b540aSrobert     return NULL_RTX;
9008*404b540aSrobert 
9009*404b540aSrobert   emit_insn (pat);
9010*404b540aSrobert   return NULL_RTX;
9011*404b540aSrobert }
9012*404b540aSrobert 
9013*404b540aSrobert /* Expand builtins that perform accumulator-to-accumulator operations.
9014*404b540aSrobert    These builtins take two accumulator numbers as argument and return
9015*404b540aSrobert    void.  */
9016*404b540aSrobert 
9017*404b540aSrobert static rtx
frv_expand_voidaccop_builtin(enum insn_code icode,tree arglist)9018*404b540aSrobert frv_expand_voidaccop_builtin (enum insn_code icode, tree arglist)
9019*404b540aSrobert {
9020*404b540aSrobert   rtx pat;
9021*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
9022*404b540aSrobert   rtx op1 = frv_read_argument (&arglist);
9023*404b540aSrobert   rtx op2;
9024*404b540aSrobert   rtx op3;
9025*404b540aSrobert 
9026*404b540aSrobert   op0 = frv_int_to_acc (icode, 0, op0);
9027*404b540aSrobert   if (! op0)
9028*404b540aSrobert     return NULL_RTX;
9029*404b540aSrobert 
9030*404b540aSrobert   op1 = frv_int_to_acc (icode, 1, op1);
9031*404b540aSrobert   if (! op1)
9032*404b540aSrobert     return NULL_RTX;
9033*404b540aSrobert 
9034*404b540aSrobert   op2 = frv_matching_accg_for_acc (op0);
9035*404b540aSrobert   op3 = frv_matching_accg_for_acc (op1);
9036*404b540aSrobert   pat = GEN_FCN (icode) (op0, op1, op2, op3);
9037*404b540aSrobert   if (! pat)
9038*404b540aSrobert     return NULL_RTX;
9039*404b540aSrobert 
9040*404b540aSrobert   emit_insn (pat);
9041*404b540aSrobert   return NULL_RTX;
9042*404b540aSrobert }
9043*404b540aSrobert 
9044*404b540aSrobert /* Expand a __builtin_read* function.  ICODE is the instruction code for the
9045*404b540aSrobert    membar and TARGET_MODE is the mode that the loaded value should have.  */
9046*404b540aSrobert 
9047*404b540aSrobert static rtx
frv_expand_load_builtin(enum insn_code icode,enum machine_mode target_mode,tree arglist,rtx target)9048*404b540aSrobert frv_expand_load_builtin (enum insn_code icode, enum machine_mode target_mode,
9049*404b540aSrobert                          tree arglist, rtx target)
9050*404b540aSrobert {
9051*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
9052*404b540aSrobert   rtx cookie = frv_io_address_cookie (op0);
9053*404b540aSrobert 
9054*404b540aSrobert   if (target == 0 || !REG_P (target))
9055*404b540aSrobert     target = gen_reg_rtx (target_mode);
9056*404b540aSrobert   op0 = frv_volatile_memref (insn_data[icode].operand[0].mode, op0);
9057*404b540aSrobert   convert_move (target, op0, 1);
9058*404b540aSrobert   emit_insn (GEN_FCN (icode) (copy_rtx (op0), cookie, GEN_INT (FRV_IO_READ)));
9059*404b540aSrobert   cfun->machine->has_membar_p = 1;
9060*404b540aSrobert   return target;
9061*404b540aSrobert }
9062*404b540aSrobert 
9063*404b540aSrobert /* Likewise __builtin_write* functions.  */
9064*404b540aSrobert 
9065*404b540aSrobert static rtx
frv_expand_store_builtin(enum insn_code icode,tree arglist)9066*404b540aSrobert frv_expand_store_builtin (enum insn_code icode, tree arglist)
9067*404b540aSrobert {
9068*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
9069*404b540aSrobert   rtx op1 = frv_read_argument (&arglist);
9070*404b540aSrobert   rtx cookie = frv_io_address_cookie (op0);
9071*404b540aSrobert 
9072*404b540aSrobert   op0 = frv_volatile_memref (insn_data[icode].operand[0].mode, op0);
9073*404b540aSrobert   convert_move (op0, force_reg (insn_data[icode].operand[0].mode, op1), 1);
9074*404b540aSrobert   emit_insn (GEN_FCN (icode) (copy_rtx (op0), cookie, GEN_INT (FRV_IO_WRITE)));
9075*404b540aSrobert   cfun->machine->has_membar_p = 1;
9076*404b540aSrobert   return NULL_RTX;
9077*404b540aSrobert }
9078*404b540aSrobert 
9079*404b540aSrobert /* Expand the MDPACKH builtin.  It takes four unsigned short arguments and
9080*404b540aSrobert    each argument forms one word of the two double-word input registers.
9081*404b540aSrobert    ARGLIST is a TREE_LIST of the arguments and TARGET, if nonnull,
9082*404b540aSrobert    suggests a good place to put the return value.  */
9083*404b540aSrobert 
9084*404b540aSrobert static rtx
frv_expand_mdpackh_builtin(tree arglist,rtx target)9085*404b540aSrobert frv_expand_mdpackh_builtin (tree arglist, rtx target)
9086*404b540aSrobert {
9087*404b540aSrobert   enum insn_code icode = CODE_FOR_mdpackh;
9088*404b540aSrobert   rtx pat, op0, op1;
9089*404b540aSrobert   rtx arg1 = frv_read_argument (&arglist);
9090*404b540aSrobert   rtx arg2 = frv_read_argument (&arglist);
9091*404b540aSrobert   rtx arg3 = frv_read_argument (&arglist);
9092*404b540aSrobert   rtx arg4 = frv_read_argument (&arglist);
9093*404b540aSrobert 
9094*404b540aSrobert   target = frv_legitimize_target (icode, target);
9095*404b540aSrobert   op0 = gen_reg_rtx (DImode);
9096*404b540aSrobert   op1 = gen_reg_rtx (DImode);
9097*404b540aSrobert 
9098*404b540aSrobert   /* The high half of each word is not explicitly initialized, so indicate
9099*404b540aSrobert      that the input operands are not live before this point.  */
9100*404b540aSrobert   emit_insn (gen_rtx_CLOBBER (DImode, op0));
9101*404b540aSrobert   emit_insn (gen_rtx_CLOBBER (DImode, op1));
9102*404b540aSrobert 
9103*404b540aSrobert   /* Move each argument into the low half of its associated input word.  */
9104*404b540aSrobert   emit_move_insn (simplify_gen_subreg (HImode, op0, DImode, 2), arg1);
9105*404b540aSrobert   emit_move_insn (simplify_gen_subreg (HImode, op0, DImode, 6), arg2);
9106*404b540aSrobert   emit_move_insn (simplify_gen_subreg (HImode, op1, DImode, 2), arg3);
9107*404b540aSrobert   emit_move_insn (simplify_gen_subreg (HImode, op1, DImode, 6), arg4);
9108*404b540aSrobert 
9109*404b540aSrobert   pat = GEN_FCN (icode) (target, op0, op1);
9110*404b540aSrobert   if (! pat)
9111*404b540aSrobert     return NULL_RTX;
9112*404b540aSrobert 
9113*404b540aSrobert   emit_insn (pat);
9114*404b540aSrobert   return target;
9115*404b540aSrobert }
9116*404b540aSrobert 
9117*404b540aSrobert /* Expand the MCLRACC builtin.  This builtin takes a single accumulator
9118*404b540aSrobert    number as argument.  */
9119*404b540aSrobert 
9120*404b540aSrobert static rtx
frv_expand_mclracc_builtin(tree arglist)9121*404b540aSrobert frv_expand_mclracc_builtin (tree arglist)
9122*404b540aSrobert {
9123*404b540aSrobert   enum insn_code icode = CODE_FOR_mclracc;
9124*404b540aSrobert   rtx pat;
9125*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
9126*404b540aSrobert 
9127*404b540aSrobert   op0 = frv_int_to_acc (icode, 0, op0);
9128*404b540aSrobert   if (! op0)
9129*404b540aSrobert     return NULL_RTX;
9130*404b540aSrobert 
9131*404b540aSrobert   pat = GEN_FCN (icode) (op0);
9132*404b540aSrobert   if (pat)
9133*404b540aSrobert     emit_insn (pat);
9134*404b540aSrobert 
9135*404b540aSrobert   return NULL_RTX;
9136*404b540aSrobert }
9137*404b540aSrobert 
9138*404b540aSrobert /* Expand builtins that take no arguments.  */
9139*404b540aSrobert 
9140*404b540aSrobert static rtx
frv_expand_noargs_builtin(enum insn_code icode)9141*404b540aSrobert frv_expand_noargs_builtin (enum insn_code icode)
9142*404b540aSrobert {
9143*404b540aSrobert   rtx pat = GEN_FCN (icode) (const0_rtx);
9144*404b540aSrobert   if (pat)
9145*404b540aSrobert     emit_insn (pat);
9146*404b540aSrobert 
9147*404b540aSrobert   return NULL_RTX;
9148*404b540aSrobert }
9149*404b540aSrobert 
9150*404b540aSrobert /* Expand MRDACC and MRDACCG.  These builtins take a single accumulator
9151*404b540aSrobert    number or accumulator guard number as argument and return an SI integer.  */
9152*404b540aSrobert 
9153*404b540aSrobert static rtx
frv_expand_mrdacc_builtin(enum insn_code icode,tree arglist)9154*404b540aSrobert frv_expand_mrdacc_builtin (enum insn_code icode, tree arglist)
9155*404b540aSrobert {
9156*404b540aSrobert   rtx pat;
9157*404b540aSrobert   rtx target = gen_reg_rtx (SImode);
9158*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
9159*404b540aSrobert 
9160*404b540aSrobert   op0 = frv_int_to_acc (icode, 1, op0);
9161*404b540aSrobert   if (! op0)
9162*404b540aSrobert     return NULL_RTX;
9163*404b540aSrobert 
9164*404b540aSrobert   pat = GEN_FCN (icode) (target, op0);
9165*404b540aSrobert   if (! pat)
9166*404b540aSrobert     return NULL_RTX;
9167*404b540aSrobert 
9168*404b540aSrobert   emit_insn (pat);
9169*404b540aSrobert   return target;
9170*404b540aSrobert }
9171*404b540aSrobert 
9172*404b540aSrobert /* Expand MWTACC and MWTACCG.  These builtins take an accumulator or
9173*404b540aSrobert    accumulator guard as their first argument and an SImode value as their
9174*404b540aSrobert    second.  */
9175*404b540aSrobert 
9176*404b540aSrobert static rtx
frv_expand_mwtacc_builtin(enum insn_code icode,tree arglist)9177*404b540aSrobert frv_expand_mwtacc_builtin (enum insn_code icode, tree arglist)
9178*404b540aSrobert {
9179*404b540aSrobert   rtx pat;
9180*404b540aSrobert   rtx op0 = frv_read_argument (&arglist);
9181*404b540aSrobert   rtx op1 = frv_read_argument (&arglist);
9182*404b540aSrobert 
9183*404b540aSrobert   op0 = frv_int_to_acc (icode, 0, op0);
9184*404b540aSrobert   if (! op0)
9185*404b540aSrobert     return NULL_RTX;
9186*404b540aSrobert 
9187*404b540aSrobert   op1 = frv_legitimize_argument (icode, 1, op1);
9188*404b540aSrobert   pat = GEN_FCN (icode) (op0, op1);
9189*404b540aSrobert   if (pat)
9190*404b540aSrobert     emit_insn (pat);
9191*404b540aSrobert 
9192*404b540aSrobert   return NULL_RTX;
9193*404b540aSrobert }
9194*404b540aSrobert 
9195*404b540aSrobert /* Emit a move from SRC to DEST in SImode chunks.  This can be used
9196*404b540aSrobert    to move DImode values into and out of IACC0.  */
9197*404b540aSrobert 
9198*404b540aSrobert static void
frv_split_iacc_move(rtx dest,rtx src)9199*404b540aSrobert frv_split_iacc_move (rtx dest, rtx src)
9200*404b540aSrobert {
9201*404b540aSrobert   enum machine_mode inner;
9202*404b540aSrobert   int i;
9203*404b540aSrobert 
9204*404b540aSrobert   inner = GET_MODE (dest);
9205*404b540aSrobert   for (i = 0; i < GET_MODE_SIZE (inner); i += GET_MODE_SIZE (SImode))
9206*404b540aSrobert     emit_move_insn (simplify_gen_subreg (SImode, dest, inner, i),
9207*404b540aSrobert 		    simplify_gen_subreg (SImode, src, inner, i));
9208*404b540aSrobert }
9209*404b540aSrobert 
9210*404b540aSrobert /* Expand builtins.  */
9211*404b540aSrobert 
9212*404b540aSrobert static rtx
frv_expand_builtin(tree exp,rtx target,rtx subtarget ATTRIBUTE_UNUSED,enum machine_mode mode ATTRIBUTE_UNUSED,int ignore ATTRIBUTE_UNUSED)9213*404b540aSrobert frv_expand_builtin (tree exp,
9214*404b540aSrobert                     rtx target,
9215*404b540aSrobert                     rtx subtarget ATTRIBUTE_UNUSED,
9216*404b540aSrobert                     enum machine_mode mode ATTRIBUTE_UNUSED,
9217*404b540aSrobert                     int ignore ATTRIBUTE_UNUSED)
9218*404b540aSrobert {
9219*404b540aSrobert   tree arglist = TREE_OPERAND (exp, 1);
9220*404b540aSrobert   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
9221*404b540aSrobert   unsigned fcode = (unsigned)DECL_FUNCTION_CODE (fndecl);
9222*404b540aSrobert   unsigned i;
9223*404b540aSrobert   struct builtin_description *d;
9224*404b540aSrobert 
9225*404b540aSrobert   if (fcode < FRV_BUILTIN_FIRST_NONMEDIA && !TARGET_MEDIA)
9226*404b540aSrobert     {
9227*404b540aSrobert       error ("media functions are not available unless -mmedia is used");
9228*404b540aSrobert       return NULL_RTX;
9229*404b540aSrobert     }
9230*404b540aSrobert 
9231*404b540aSrobert   switch (fcode)
9232*404b540aSrobert     {
9233*404b540aSrobert     case FRV_BUILTIN_MCOP1:
9234*404b540aSrobert     case FRV_BUILTIN_MCOP2:
9235*404b540aSrobert     case FRV_BUILTIN_MDUNPACKH:
9236*404b540aSrobert     case FRV_BUILTIN_MBTOHE:
9237*404b540aSrobert       if (! TARGET_MEDIA_REV1)
9238*404b540aSrobert 	{
9239*404b540aSrobert 	  error ("this media function is only available on the fr500");
9240*404b540aSrobert 	  return NULL_RTX;
9241*404b540aSrobert 	}
9242*404b540aSrobert       break;
9243*404b540aSrobert 
9244*404b540aSrobert     case FRV_BUILTIN_MQXMACHS:
9245*404b540aSrobert     case FRV_BUILTIN_MQXMACXHS:
9246*404b540aSrobert     case FRV_BUILTIN_MQMACXHS:
9247*404b540aSrobert     case FRV_BUILTIN_MADDACCS:
9248*404b540aSrobert     case FRV_BUILTIN_MSUBACCS:
9249*404b540aSrobert     case FRV_BUILTIN_MASACCS:
9250*404b540aSrobert     case FRV_BUILTIN_MDADDACCS:
9251*404b540aSrobert     case FRV_BUILTIN_MDSUBACCS:
9252*404b540aSrobert     case FRV_BUILTIN_MDASACCS:
9253*404b540aSrobert     case FRV_BUILTIN_MABSHS:
9254*404b540aSrobert     case FRV_BUILTIN_MDROTLI:
9255*404b540aSrobert     case FRV_BUILTIN_MCPLHI:
9256*404b540aSrobert     case FRV_BUILTIN_MCPLI:
9257*404b540aSrobert     case FRV_BUILTIN_MDCUTSSI:
9258*404b540aSrobert     case FRV_BUILTIN_MQSATHS:
9259*404b540aSrobert     case FRV_BUILTIN_MHSETLOS:
9260*404b540aSrobert     case FRV_BUILTIN_MHSETLOH:
9261*404b540aSrobert     case FRV_BUILTIN_MHSETHIS:
9262*404b540aSrobert     case FRV_BUILTIN_MHSETHIH:
9263*404b540aSrobert     case FRV_BUILTIN_MHDSETS:
9264*404b540aSrobert     case FRV_BUILTIN_MHDSETH:
9265*404b540aSrobert       if (! TARGET_MEDIA_REV2)
9266*404b540aSrobert 	{
9267*404b540aSrobert 	  error ("this media function is only available on the fr400"
9268*404b540aSrobert 		 " and fr550");
9269*404b540aSrobert 	  return NULL_RTX;
9270*404b540aSrobert 	}
9271*404b540aSrobert       break;
9272*404b540aSrobert 
9273*404b540aSrobert     case FRV_BUILTIN_SMASS:
9274*404b540aSrobert     case FRV_BUILTIN_SMSSS:
9275*404b540aSrobert     case FRV_BUILTIN_SMU:
9276*404b540aSrobert     case FRV_BUILTIN_ADDSS:
9277*404b540aSrobert     case FRV_BUILTIN_SUBSS:
9278*404b540aSrobert     case FRV_BUILTIN_SLASS:
9279*404b540aSrobert     case FRV_BUILTIN_SCUTSS:
9280*404b540aSrobert     case FRV_BUILTIN_IACCreadll:
9281*404b540aSrobert     case FRV_BUILTIN_IACCreadl:
9282*404b540aSrobert     case FRV_BUILTIN_IACCsetll:
9283*404b540aSrobert     case FRV_BUILTIN_IACCsetl:
9284*404b540aSrobert       if (!TARGET_FR405_BUILTINS)
9285*404b540aSrobert 	{
9286*404b540aSrobert 	  error ("this builtin function is only available"
9287*404b540aSrobert 		 " on the fr405 and fr450");
9288*404b540aSrobert 	  return NULL_RTX;
9289*404b540aSrobert 	}
9290*404b540aSrobert       break;
9291*404b540aSrobert 
9292*404b540aSrobert     case FRV_BUILTIN_PREFETCH:
9293*404b540aSrobert       if (!TARGET_FR500_FR550_BUILTINS)
9294*404b540aSrobert 	{
9295*404b540aSrobert 	  error ("this builtin function is only available on the fr500"
9296*404b540aSrobert 		 " and fr550");
9297*404b540aSrobert 	  return NULL_RTX;
9298*404b540aSrobert 	}
9299*404b540aSrobert       break;
9300*404b540aSrobert 
9301*404b540aSrobert     case FRV_BUILTIN_MQLCLRHS:
9302*404b540aSrobert     case FRV_BUILTIN_MQLMTHS:
9303*404b540aSrobert     case FRV_BUILTIN_MQSLLHI:
9304*404b540aSrobert     case FRV_BUILTIN_MQSRAHI:
9305*404b540aSrobert       if (!TARGET_MEDIA_FR450)
9306*404b540aSrobert 	{
9307*404b540aSrobert 	  error ("this builtin function is only available on the fr450");
9308*404b540aSrobert 	  return NULL_RTX;
9309*404b540aSrobert 	}
9310*404b540aSrobert       break;
9311*404b540aSrobert 
9312*404b540aSrobert     default:
9313*404b540aSrobert       break;
9314*404b540aSrobert     }
9315*404b540aSrobert 
9316*404b540aSrobert   /* Expand unique builtins.  */
9317*404b540aSrobert 
9318*404b540aSrobert   switch (fcode)
9319*404b540aSrobert     {
9320*404b540aSrobert     case FRV_BUILTIN_MTRAP:
9321*404b540aSrobert       return frv_expand_noargs_builtin (CODE_FOR_mtrap);
9322*404b540aSrobert 
9323*404b540aSrobert     case FRV_BUILTIN_MCLRACC:
9324*404b540aSrobert       return frv_expand_mclracc_builtin (arglist);
9325*404b540aSrobert 
9326*404b540aSrobert     case FRV_BUILTIN_MCLRACCA:
9327*404b540aSrobert       if (TARGET_ACC_8)
9328*404b540aSrobert 	return frv_expand_noargs_builtin (CODE_FOR_mclracca8);
9329*404b540aSrobert       else
9330*404b540aSrobert 	return frv_expand_noargs_builtin (CODE_FOR_mclracca4);
9331*404b540aSrobert 
9332*404b540aSrobert     case FRV_BUILTIN_MRDACC:
9333*404b540aSrobert       return frv_expand_mrdacc_builtin (CODE_FOR_mrdacc, arglist);
9334*404b540aSrobert 
9335*404b540aSrobert     case FRV_BUILTIN_MRDACCG:
9336*404b540aSrobert       return frv_expand_mrdacc_builtin (CODE_FOR_mrdaccg, arglist);
9337*404b540aSrobert 
9338*404b540aSrobert     case FRV_BUILTIN_MWTACC:
9339*404b540aSrobert       return frv_expand_mwtacc_builtin (CODE_FOR_mwtacc, arglist);
9340*404b540aSrobert 
9341*404b540aSrobert     case FRV_BUILTIN_MWTACCG:
9342*404b540aSrobert       return frv_expand_mwtacc_builtin (CODE_FOR_mwtaccg, arglist);
9343*404b540aSrobert 
9344*404b540aSrobert     case FRV_BUILTIN_MDPACKH:
9345*404b540aSrobert       return frv_expand_mdpackh_builtin (arglist, target);
9346*404b540aSrobert 
9347*404b540aSrobert     case FRV_BUILTIN_IACCreadll:
9348*404b540aSrobert       {
9349*404b540aSrobert 	rtx src = frv_read_iacc_argument (DImode, &arglist);
9350*404b540aSrobert 	if (target == 0 || !REG_P (target))
9351*404b540aSrobert 	  target = gen_reg_rtx (DImode);
9352*404b540aSrobert 	frv_split_iacc_move (target, src);
9353*404b540aSrobert 	return target;
9354*404b540aSrobert       }
9355*404b540aSrobert 
9356*404b540aSrobert     case FRV_BUILTIN_IACCreadl:
9357*404b540aSrobert       return frv_read_iacc_argument (SImode, &arglist);
9358*404b540aSrobert 
9359*404b540aSrobert     case FRV_BUILTIN_IACCsetll:
9360*404b540aSrobert       {
9361*404b540aSrobert 	rtx dest = frv_read_iacc_argument (DImode, &arglist);
9362*404b540aSrobert 	rtx src = frv_read_argument (&arglist);
9363*404b540aSrobert 	frv_split_iacc_move (dest, force_reg (DImode, src));
9364*404b540aSrobert 	return 0;
9365*404b540aSrobert       }
9366*404b540aSrobert 
9367*404b540aSrobert     case FRV_BUILTIN_IACCsetl:
9368*404b540aSrobert       {
9369*404b540aSrobert 	rtx dest = frv_read_iacc_argument (SImode, &arglist);
9370*404b540aSrobert 	rtx src = frv_read_argument (&arglist);
9371*404b540aSrobert 	emit_move_insn (dest, force_reg (SImode, src));
9372*404b540aSrobert 	return 0;
9373*404b540aSrobert       }
9374*404b540aSrobert 
9375*404b540aSrobert     default:
9376*404b540aSrobert       break;
9377*404b540aSrobert     }
9378*404b540aSrobert 
9379*404b540aSrobert   /* Expand groups of builtins.  */
9380*404b540aSrobert 
9381*404b540aSrobert   for (i = 0, d = bdesc_set; i < ARRAY_SIZE (bdesc_set); i++, d++)
9382*404b540aSrobert     if (d->code == fcode)
9383*404b540aSrobert       return frv_expand_set_builtin (d->icode, arglist, target);
9384*404b540aSrobert 
9385*404b540aSrobert   for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
9386*404b540aSrobert     if (d->code == fcode)
9387*404b540aSrobert       return frv_expand_unop_builtin (d->icode, arglist, target);
9388*404b540aSrobert 
9389*404b540aSrobert   for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
9390*404b540aSrobert     if (d->code == fcode)
9391*404b540aSrobert       return frv_expand_binop_builtin (d->icode, arglist, target);
9392*404b540aSrobert 
9393*404b540aSrobert   for (i = 0, d = bdesc_cut; i < ARRAY_SIZE (bdesc_cut); i++, d++)
9394*404b540aSrobert     if (d->code == fcode)
9395*404b540aSrobert       return frv_expand_cut_builtin (d->icode, arglist, target);
9396*404b540aSrobert 
9397*404b540aSrobert   for (i = 0, d = bdesc_2argimm; i < ARRAY_SIZE (bdesc_2argimm); i++, d++)
9398*404b540aSrobert     if (d->code == fcode)
9399*404b540aSrobert       return frv_expand_binopimm_builtin (d->icode, arglist, target);
9400*404b540aSrobert 
9401*404b540aSrobert   for (i = 0, d = bdesc_void2arg; i < ARRAY_SIZE (bdesc_void2arg); i++, d++)
9402*404b540aSrobert     if (d->code == fcode)
9403*404b540aSrobert       return frv_expand_voidbinop_builtin (d->icode, arglist);
9404*404b540aSrobert 
9405*404b540aSrobert   for (i = 0, d = bdesc_void3arg; i < ARRAY_SIZE (bdesc_void3arg); i++, d++)
9406*404b540aSrobert     if (d->code == fcode)
9407*404b540aSrobert       return frv_expand_voidtriop_builtin (d->icode, arglist);
9408*404b540aSrobert 
9409*404b540aSrobert   for (i = 0, d = bdesc_voidacc; i < ARRAY_SIZE (bdesc_voidacc); i++, d++)
9410*404b540aSrobert     if (d->code == fcode)
9411*404b540aSrobert       return frv_expand_voidaccop_builtin (d->icode, arglist);
9412*404b540aSrobert 
9413*404b540aSrobert   for (i = 0, d = bdesc_int_void2arg;
9414*404b540aSrobert        i < ARRAY_SIZE (bdesc_int_void2arg); i++, d++)
9415*404b540aSrobert     if (d->code == fcode)
9416*404b540aSrobert       return frv_expand_int_void2arg (d->icode, arglist);
9417*404b540aSrobert 
9418*404b540aSrobert   for (i = 0, d = bdesc_prefetches;
9419*404b540aSrobert        i < ARRAY_SIZE (bdesc_prefetches); i++, d++)
9420*404b540aSrobert     if (d->code == fcode)
9421*404b540aSrobert       return frv_expand_prefetches (d->icode, arglist);
9422*404b540aSrobert 
9423*404b540aSrobert   for (i = 0, d = bdesc_loads; i < ARRAY_SIZE (bdesc_loads); i++, d++)
9424*404b540aSrobert     if (d->code == fcode)
9425*404b540aSrobert       return frv_expand_load_builtin (d->icode, TYPE_MODE (TREE_TYPE (exp)),
9426*404b540aSrobert 				      arglist, target);
9427*404b540aSrobert 
9428*404b540aSrobert   for (i = 0, d = bdesc_stores; i < ARRAY_SIZE (bdesc_stores); i++, d++)
9429*404b540aSrobert     if (d->code == fcode)
9430*404b540aSrobert       return frv_expand_store_builtin (d->icode, arglist);
9431*404b540aSrobert 
9432*404b540aSrobert   return 0;
9433*404b540aSrobert }
9434*404b540aSrobert 
9435*404b540aSrobert static bool
frv_in_small_data_p(tree decl)9436*404b540aSrobert frv_in_small_data_p (tree decl)
9437*404b540aSrobert {
9438*404b540aSrobert   HOST_WIDE_INT size;
9439*404b540aSrobert   tree section_name;
9440*404b540aSrobert 
9441*404b540aSrobert   /* Don't apply the -G flag to internal compiler structures.  We
9442*404b540aSrobert      should leave such structures in the main data section, partly
9443*404b540aSrobert      for efficiency and partly because the size of some of them
9444*404b540aSrobert      (such as C++ typeinfos) is not known until later.  */
9445*404b540aSrobert   if (TREE_CODE (decl) != VAR_DECL || DECL_ARTIFICIAL (decl))
9446*404b540aSrobert     return false;
9447*404b540aSrobert 
9448*404b540aSrobert   /* If we already know which section the decl should be in, see if
9449*404b540aSrobert      it's a small data section.  */
9450*404b540aSrobert   section_name = DECL_SECTION_NAME (decl);
9451*404b540aSrobert   if (section_name)
9452*404b540aSrobert     {
9453*404b540aSrobert       gcc_assert (TREE_CODE (section_name) == STRING_CST);
9454*404b540aSrobert       if (frv_string_begins_with (section_name, ".sdata"))
9455*404b540aSrobert 	return true;
9456*404b540aSrobert       if (frv_string_begins_with (section_name, ".sbss"))
9457*404b540aSrobert 	return true;
9458*404b540aSrobert       return false;
9459*404b540aSrobert     }
9460*404b540aSrobert 
9461*404b540aSrobert   size = int_size_in_bytes (TREE_TYPE (decl));
9462*404b540aSrobert   if (size > 0 && (unsigned HOST_WIDE_INT) size <= g_switch_value)
9463*404b540aSrobert     return true;
9464*404b540aSrobert 
9465*404b540aSrobert   return false;
9466*404b540aSrobert }
9467*404b540aSrobert 
9468*404b540aSrobert static bool
frv_rtx_costs(rtx x,int code ATTRIBUTE_UNUSED,int outer_code ATTRIBUTE_UNUSED,int * total)9469*404b540aSrobert frv_rtx_costs (rtx x,
9470*404b540aSrobert                int code ATTRIBUTE_UNUSED,
9471*404b540aSrobert                int outer_code ATTRIBUTE_UNUSED,
9472*404b540aSrobert                int *total)
9473*404b540aSrobert {
9474*404b540aSrobert   if (outer_code == MEM)
9475*404b540aSrobert     {
9476*404b540aSrobert       /* Don't differentiate between memory addresses.  All the ones
9477*404b540aSrobert 	 we accept have equal cost.  */
9478*404b540aSrobert       *total = COSTS_N_INSNS (0);
9479*404b540aSrobert       return true;
9480*404b540aSrobert     }
9481*404b540aSrobert 
9482*404b540aSrobert   switch (code)
9483*404b540aSrobert     {
9484*404b540aSrobert     case CONST_INT:
9485*404b540aSrobert       /* Make 12 bit integers really cheap.  */
9486*404b540aSrobert       if (IN_RANGE_P (INTVAL (x), -2048, 2047))
9487*404b540aSrobert 	{
9488*404b540aSrobert 	  *total = 0;
9489*404b540aSrobert 	  return true;
9490*404b540aSrobert 	}
9491*404b540aSrobert       /* Fall through.  */
9492*404b540aSrobert 
9493*404b540aSrobert     case CONST:
9494*404b540aSrobert     case LABEL_REF:
9495*404b540aSrobert     case SYMBOL_REF:
9496*404b540aSrobert     case CONST_DOUBLE:
9497*404b540aSrobert       *total = COSTS_N_INSNS (2);
9498*404b540aSrobert       return true;
9499*404b540aSrobert 
9500*404b540aSrobert     case PLUS:
9501*404b540aSrobert     case MINUS:
9502*404b540aSrobert     case AND:
9503*404b540aSrobert     case IOR:
9504*404b540aSrobert     case XOR:
9505*404b540aSrobert     case ASHIFT:
9506*404b540aSrobert     case ASHIFTRT:
9507*404b540aSrobert     case LSHIFTRT:
9508*404b540aSrobert     case NOT:
9509*404b540aSrobert     case NEG:
9510*404b540aSrobert     case COMPARE:
9511*404b540aSrobert       if (GET_MODE (x) == SImode)
9512*404b540aSrobert 	*total = COSTS_N_INSNS (1);
9513*404b540aSrobert       else if (GET_MODE (x) == DImode)
9514*404b540aSrobert         *total = COSTS_N_INSNS (2);
9515*404b540aSrobert       else
9516*404b540aSrobert         *total = COSTS_N_INSNS (3);
9517*404b540aSrobert       return true;
9518*404b540aSrobert 
9519*404b540aSrobert     case MULT:
9520*404b540aSrobert       if (GET_MODE (x) == SImode)
9521*404b540aSrobert         *total = COSTS_N_INSNS (2);
9522*404b540aSrobert       else
9523*404b540aSrobert         *total = COSTS_N_INSNS (6);	/* guess */
9524*404b540aSrobert       return true;
9525*404b540aSrobert 
9526*404b540aSrobert     case DIV:
9527*404b540aSrobert     case UDIV:
9528*404b540aSrobert     case MOD:
9529*404b540aSrobert     case UMOD:
9530*404b540aSrobert       *total = COSTS_N_INSNS (18);
9531*404b540aSrobert       return true;
9532*404b540aSrobert 
9533*404b540aSrobert     case MEM:
9534*404b540aSrobert       *total = COSTS_N_INSNS (3);
9535*404b540aSrobert       return true;
9536*404b540aSrobert 
9537*404b540aSrobert     default:
9538*404b540aSrobert       return false;
9539*404b540aSrobert     }
9540*404b540aSrobert }
9541*404b540aSrobert 
9542*404b540aSrobert static void
frv_asm_out_constructor(rtx symbol,int priority ATTRIBUTE_UNUSED)9543*404b540aSrobert frv_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
9544*404b540aSrobert {
9545*404b540aSrobert   switch_to_section (ctors_section);
9546*404b540aSrobert   assemble_align (POINTER_SIZE);
9547*404b540aSrobert   if (TARGET_FDPIC)
9548*404b540aSrobert     {
9549*404b540aSrobert       int ok = frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
9550*404b540aSrobert 
9551*404b540aSrobert       gcc_assert (ok);
9552*404b540aSrobert       return;
9553*404b540aSrobert     }
9554*404b540aSrobert   assemble_integer_with_op ("\t.picptr\t", symbol);
9555*404b540aSrobert }
9556*404b540aSrobert 
9557*404b540aSrobert static void
frv_asm_out_destructor(rtx symbol,int priority ATTRIBUTE_UNUSED)9558*404b540aSrobert frv_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
9559*404b540aSrobert {
9560*404b540aSrobert   switch_to_section (dtors_section);
9561*404b540aSrobert   assemble_align (POINTER_SIZE);
9562*404b540aSrobert   if (TARGET_FDPIC)
9563*404b540aSrobert     {
9564*404b540aSrobert       int ok = frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1);
9565*404b540aSrobert 
9566*404b540aSrobert       gcc_assert (ok);
9567*404b540aSrobert       return;
9568*404b540aSrobert     }
9569*404b540aSrobert   assemble_integer_with_op ("\t.picptr\t", symbol);
9570*404b540aSrobert }
9571*404b540aSrobert 
9572*404b540aSrobert /* Worker function for TARGET_STRUCT_VALUE_RTX.  */
9573*404b540aSrobert 
9574*404b540aSrobert static rtx
frv_struct_value_rtx(tree fntype ATTRIBUTE_UNUSED,int incoming ATTRIBUTE_UNUSED)9575*404b540aSrobert frv_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
9576*404b540aSrobert 		      int incoming ATTRIBUTE_UNUSED)
9577*404b540aSrobert {
9578*404b540aSrobert   return gen_rtx_REG (Pmode, FRV_STRUCT_VALUE_REGNUM);
9579*404b540aSrobert }
9580*404b540aSrobert 
9581*404b540aSrobert #define TLS_BIAS (2048 - 16)
9582*404b540aSrobert 
9583*404b540aSrobert /* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
9584*404b540aSrobert    We need to emit DTP-relative relocations.  */
9585*404b540aSrobert 
9586*404b540aSrobert static void
frv_output_dwarf_dtprel(FILE * file,int size,rtx x)9587*404b540aSrobert frv_output_dwarf_dtprel (FILE *file, int size, rtx x)
9588*404b540aSrobert {
9589*404b540aSrobert   gcc_assert (size == 4);
9590*404b540aSrobert   fputs ("\t.picptr\ttlsmoff(", file);
9591*404b540aSrobert   /* We want the unbiased TLS offset, so add the bias to the
9592*404b540aSrobert      expression, such that the implicit biasing cancels out.  */
9593*404b540aSrobert   output_addr_const (file, plus_constant (x, TLS_BIAS));
9594*404b540aSrobert   fputs (")", file);
9595*404b540aSrobert }
9596*404b540aSrobert 
9597*404b540aSrobert #include "gt-frv.h"
9598