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 = ®_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