annotate gcc/config/epiphany/epiphany.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Subroutines used for code generation on the EPIPHANY cpu.
kono
parents:
diff changeset
2 Copyright (C) 1994-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
3 Contributed by Embecosm on behalf of Adapteva, Inc.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify
kono
parents:
diff changeset
8 it under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
9 the Free Software Foundation; either version 3, or (at your option)
kono
parents:
diff changeset
10 any later version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful,
kono
parents:
diff changeset
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kono
parents:
diff changeset
15 GNU General Public License for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21 #include "config.h"
kono
parents:
diff changeset
22 #include "system.h"
kono
parents:
diff changeset
23 #include "coretypes.h"
kono
parents:
diff changeset
24 #include "backend.h"
kono
parents:
diff changeset
25 #include "target.h"
kono
parents:
diff changeset
26 #include "rtl.h"
kono
parents:
diff changeset
27 #include "tree.h"
kono
parents:
diff changeset
28 #include "df.h"
kono
parents:
diff changeset
29 #include "memmodel.h"
kono
parents:
diff changeset
30 #include "tm_p.h"
kono
parents:
diff changeset
31 #include "stringpool.h"
kono
parents:
diff changeset
32 #include "attribs.h"
kono
parents:
diff changeset
33 #include "optabs.h"
kono
parents:
diff changeset
34 #include "emit-rtl.h"
kono
parents:
diff changeset
35 #include "recog.h"
kono
parents:
diff changeset
36 #include "diagnostic-core.h"
kono
parents:
diff changeset
37 #include "alias.h"
kono
parents:
diff changeset
38 #include "stor-layout.h"
kono
parents:
diff changeset
39 #include "varasm.h"
kono
parents:
diff changeset
40 #include "calls.h"
kono
parents:
diff changeset
41 #include "output.h"
kono
parents:
diff changeset
42 #include "insn-attr.h"
kono
parents:
diff changeset
43 #include "explow.h"
kono
parents:
diff changeset
44 #include "expr.h"
kono
parents:
diff changeset
45 #include "tm-constrs.h"
kono
parents:
diff changeset
46 #include "tree-pass.h" /* for current_pass */
kono
parents:
diff changeset
47 #include "context.h"
kono
parents:
diff changeset
48 #include "pass_manager.h"
kono
parents:
diff changeset
49 #include "builtins.h"
kono
parents:
diff changeset
50
kono
parents:
diff changeset
51 /* Which cpu we're compiling for. */
kono
parents:
diff changeset
52 int epiphany_cpu_type;
kono
parents:
diff changeset
53
kono
parents:
diff changeset
54 /* Name of mangle string to add to symbols to separate code compiled for each
kono
parents:
diff changeset
55 cpu (or NULL). */
kono
parents:
diff changeset
56 const char *epiphany_mangle_cpu;
kono
parents:
diff changeset
57
kono
parents:
diff changeset
58 /* Array of valid operand punctuation characters. */
kono
parents:
diff changeset
59 char epiphany_punct_chars[256];
kono
parents:
diff changeset
60
kono
parents:
diff changeset
61 /* The rounding mode that we generally use for floating point. */
kono
parents:
diff changeset
62 int epiphany_normal_fp_rounding;
kono
parents:
diff changeset
63
kono
parents:
diff changeset
64 /* The pass instance, for use in epiphany_optimize_mode_switching. */
kono
parents:
diff changeset
65 static opt_pass *pass_mode_switch_use;
kono
parents:
diff changeset
66
kono
parents:
diff changeset
67 static void epiphany_init_reg_tables (void);
kono
parents:
diff changeset
68 static int get_epiphany_condition_code (rtx);
kono
parents:
diff changeset
69 static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
kono
parents:
diff changeset
70 static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int,
kono
parents:
diff changeset
71 bool *);
kono
parents:
diff changeset
72 static bool epiphany_pass_by_reference (cumulative_args_t, machine_mode,
kono
parents:
diff changeset
73 const_tree, bool);
kono
parents:
diff changeset
74 static rtx_insn *frame_insn (rtx);
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 /* defines for the initialization of the GCC target structure. */
kono
parents:
diff changeset
77 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table
kono
parents:
diff changeset
78
kono
parents:
diff changeset
79 #define TARGET_PRINT_OPERAND epiphany_print_operand
kono
parents:
diff changeset
80 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address
kono
parents:
diff changeset
81
kono
parents:
diff changeset
82 #define TARGET_RTX_COSTS epiphany_rtx_costs
kono
parents:
diff changeset
83 #define TARGET_ADDRESS_COST epiphany_address_cost
kono
parents:
diff changeset
84 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode
kono
parents:
diff changeset
87 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
kono
parents:
diff changeset
88
kono
parents:
diff changeset
89 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory
kono
parents:
diff changeset
90 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference
kono
parents:
diff changeset
91 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
kono
parents:
diff changeset
92 #define TARGET_FUNCTION_VALUE epiphany_function_value
kono
parents:
diff changeset
93 #define TARGET_LIBCALL_VALUE epiphany_libcall_value
kono
parents:
diff changeset
94 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs
kono
parents:
diff changeset
97
kono
parents:
diff changeset
98 /* Using the simplistic varags handling forces us to do partial reg/stack
kono
parents:
diff changeset
99 argument passing for types with larger size (> 4 bytes) than alignment. */
kono
parents:
diff changeset
100 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes
kono
parents:
diff changeset
101
kono
parents:
diff changeset
102 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate
kono
parents:
diff changeset
105 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost
kono
parents:
diff changeset
106
kono
parents:
diff changeset
107 #define TARGET_LRA_P hook_bool_void_false
kono
parents:
diff changeset
108
kono
parents:
diff changeset
109 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload
kono
parents:
diff changeset
112
kono
parents:
diff changeset
113 #define TARGET_OPTION_OVERRIDE epiphany_override_options
kono
parents:
diff changeset
114
kono
parents:
diff changeset
115 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 #define TARGET_FUNCTION_ARG epiphany_function_arg
kono
parents:
diff changeset
118
kono
parents:
diff changeset
119 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance
kono
parents:
diff changeset
120
kono
parents:
diff changeset
121 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary
kono
parents:
diff changeset
122
kono
parents:
diff changeset
123 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init
kono
parents:
diff changeset
124
kono
parents:
diff changeset
125 /* Nonzero if the constant rtx value is a legitimate general operand.
kono
parents:
diff changeset
126 We can handle any 32- or 64-bit constant. */
kono
parents:
diff changeset
127 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \
kono
parents:
diff changeset
130 epiphany_min_divisions_for_recip_mul
kono
parents:
diff changeset
131
kono
parents:
diff changeset
132 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode
kono
parents:
diff changeset
133
kono
parents:
diff changeset
134 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
kono
parents:
diff changeset
137 epiphany_vector_alignment_reachable
kono
parents:
diff changeset
138
kono
parents:
diff changeset
139 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
kono
parents:
diff changeset
140 epiphany_support_vector_misalignment
kono
parents:
diff changeset
141
kono
parents:
diff changeset
142 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
kono
parents:
diff changeset
143 hook_bool_const_tree_hwi_hwi_const_tree_true
kono
parents:
diff changeset
144 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk
kono
parents:
diff changeset
145
kono
parents:
diff changeset
146 /* ??? we can use larger offsets for wider-mode sized accesses, but there
kono
parents:
diff changeset
147 is no concept of anchors being dependent on the modes that they are used
kono
parents:
diff changeset
148 for, so we can only use an offset range that would suit all modes. */
kono
parents:
diff changeset
149 #define TARGET_MAX_ANCHOR_OFFSET (optimize_size ? 31 : 2047)
kono
parents:
diff changeset
150 /* We further restrict the minimum to be a multiple of eight. */
kono
parents:
diff changeset
151 #define TARGET_MIN_ANCHOR_OFFSET (optimize_size ? 0 : -2040)
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 /* Mode switching hooks. */
kono
parents:
diff changeset
154
kono
parents:
diff changeset
155 #define TARGET_MODE_EMIT emit_set_fp_mode
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 #define TARGET_MODE_NEEDED epiphany_mode_needed
kono
parents:
diff changeset
158
kono
parents:
diff changeset
159 #define TARGET_MODE_PRIORITY epiphany_mode_priority
kono
parents:
diff changeset
160
kono
parents:
diff changeset
161 #define TARGET_MODE_ENTRY epiphany_mode_entry
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 #define TARGET_MODE_EXIT epiphany_mode_exit
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 #define TARGET_MODE_AFTER epiphany_mode_after
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167 #include "target-def.h"
kono
parents:
diff changeset
168
kono
parents:
diff changeset
169 #undef TARGET_ASM_ALIGNED_HI_OP
kono
parents:
diff changeset
170 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
kono
parents:
diff changeset
171 #undef TARGET_ASM_ALIGNED_SI_OP
kono
parents:
diff changeset
172 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
kono
parents:
diff changeset
173
kono
parents:
diff changeset
174 #undef TARGET_HARD_REGNO_MODE_OK
kono
parents:
diff changeset
175 #define TARGET_HARD_REGNO_MODE_OK epiphany_hard_regno_mode_ok
kono
parents:
diff changeset
176
kono
parents:
diff changeset
177 #undef TARGET_CONSTANT_ALIGNMENT
kono
parents:
diff changeset
178 #define TARGET_CONSTANT_ALIGNMENT epiphany_constant_alignment
kono
parents:
diff changeset
179
kono
parents:
diff changeset
180 #undef TARGET_STARTING_FRAME_OFFSET
kono
parents:
diff changeset
181 #define TARGET_STARTING_FRAME_OFFSET epiphany_starting_frame_offset
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 bool
kono
parents:
diff changeset
184 epiphany_is_interrupt_p (tree decl)
kono
parents:
diff changeset
185 {
kono
parents:
diff changeset
186 tree attrs;
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188 attrs = DECL_ATTRIBUTES (decl);
kono
parents:
diff changeset
189 if (lookup_attribute ("interrupt", attrs))
kono
parents:
diff changeset
190 return true;
kono
parents:
diff changeset
191 else
kono
parents:
diff changeset
192 return false;
kono
parents:
diff changeset
193 }
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 /* Called from epiphany_override_options.
kono
parents:
diff changeset
196 We use this to initialize various things. */
kono
parents:
diff changeset
197
kono
parents:
diff changeset
198 static void
kono
parents:
diff changeset
199 epiphany_init (void)
kono
parents:
diff changeset
200 {
kono
parents:
diff changeset
201 /* N.B. this pass must not run before the first optimize_mode_switching
kono
parents:
diff changeset
202 pass because of the side offect of epiphany_mode_needed on
kono
parents:
diff changeset
203 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before
kono
parents:
diff changeset
204 pass_resolve_sw_modes. */
kono
parents:
diff changeset
205 pass_mode_switch_use = make_pass_mode_switch_use (g);
kono
parents:
diff changeset
206 struct register_pass_info insert_use_info
kono
parents:
diff changeset
207 = { pass_mode_switch_use, "mode_sw",
kono
parents:
diff changeset
208 1, PASS_POS_INSERT_AFTER
kono
parents:
diff changeset
209 };
kono
parents:
diff changeset
210 opt_pass *mode_sw2
kono
parents:
diff changeset
211 = g->get_passes()->get_pass_mode_switching ()->clone ();
kono
parents:
diff changeset
212 struct register_pass_info mode_sw2_info
kono
parents:
diff changeset
213 = { mode_sw2, "mode_sw",
kono
parents:
diff changeset
214 1, PASS_POS_INSERT_AFTER
kono
parents:
diff changeset
215 };
kono
parents:
diff changeset
216 opt_pass *mode_sw3 = make_pass_resolve_sw_modes (g);
kono
parents:
diff changeset
217 struct register_pass_info mode_sw3_info
kono
parents:
diff changeset
218 = { mode_sw3, "mode_sw",
kono
parents:
diff changeset
219 1, PASS_POS_INSERT_AFTER
kono
parents:
diff changeset
220 };
kono
parents:
diff changeset
221 opt_pass *mode_sw4
kono
parents:
diff changeset
222 = g->get_passes()->get_pass_split_all_insns ()->clone ();
kono
parents:
diff changeset
223 struct register_pass_info mode_sw4_info
kono
parents:
diff changeset
224 = { mode_sw4, "mode_sw",
kono
parents:
diff changeset
225 1, PASS_POS_INSERT_AFTER
kono
parents:
diff changeset
226 };
kono
parents:
diff changeset
227 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
kono
parents:
diff changeset
228 #define N_ENTITIES ARRAY_SIZE (num_modes)
kono
parents:
diff changeset
229
kono
parents:
diff changeset
230 epiphany_init_reg_tables ();
kono
parents:
diff changeset
231
kono
parents:
diff changeset
232 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */
kono
parents:
diff changeset
233 memset (epiphany_punct_chars, 0, sizeof (epiphany_punct_chars));
kono
parents:
diff changeset
234 epiphany_punct_chars['-'] = 1;
kono
parents:
diff changeset
235
kono
parents:
diff changeset
236 epiphany_normal_fp_rounding
kono
parents:
diff changeset
237 = (epiphany_normal_fp_mode == FP_MODE_ROUND_TRUNC
kono
parents:
diff changeset
238 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
kono
parents:
diff changeset
239 register_pass (&mode_sw4_info);
kono
parents:
diff changeset
240 register_pass (&mode_sw2_info);
kono
parents:
diff changeset
241 register_pass (&mode_sw3_info);
kono
parents:
diff changeset
242 register_pass (&insert_use_info);
kono
parents:
diff changeset
243 register_pass (&mode_sw2_info);
kono
parents:
diff changeset
244 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */
kono
parents:
diff changeset
245 gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM);
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 #if 1 /* As long as peep2_rescan is not implemented,
kono
parents:
diff changeset
248 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,)
kono
parents:
diff changeset
249 we need a second peephole2 pass to get reasonable code. */
kono
parents:
diff changeset
250 {
kono
parents:
diff changeset
251 opt_pass *extra_peephole2
kono
parents:
diff changeset
252 = g->get_passes ()->get_pass_peephole2 ()->clone ();
kono
parents:
diff changeset
253 struct register_pass_info peep2_2_info
kono
parents:
diff changeset
254 = { extra_peephole2, "peephole2",
kono
parents:
diff changeset
255 1, PASS_POS_INSERT_AFTER
kono
parents:
diff changeset
256 };
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 register_pass (&peep2_2_info);
kono
parents:
diff changeset
259 }
kono
parents:
diff changeset
260 #endif
kono
parents:
diff changeset
261 }
kono
parents:
diff changeset
262
kono
parents:
diff changeset
263 /* The condition codes of the EPIPHANY, and the inverse function. */
kono
parents:
diff changeset
264 static const char *const epiphany_condition_codes[] =
kono
parents:
diff changeset
265 { /* 0 1 2 3 4 5 6 7 8 9 */
kono
parents:
diff changeset
266 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu",
kono
parents:
diff changeset
267 /* 10 11 12 13 */
kono
parents:
diff changeset
268 "beq","bne","blt", "blte",
kono
parents:
diff changeset
269 };
kono
parents:
diff changeset
270
kono
parents:
diff changeset
271 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
kono
parents:
diff changeset
272
kono
parents:
diff changeset
273 /* Returns the index of the EPIPHANY condition code string in
kono
parents:
diff changeset
274 `epiphany_condition_codes'. COMPARISON should be an rtx like
kono
parents:
diff changeset
275 `(eq (...) (...))'. */
kono
parents:
diff changeset
276
kono
parents:
diff changeset
277 static int
kono
parents:
diff changeset
278 get_epiphany_condition_code (rtx comparison)
kono
parents:
diff changeset
279 {
kono
parents:
diff changeset
280 switch (GET_MODE (XEXP (comparison, 0)))
kono
parents:
diff changeset
281 {
kono
parents:
diff changeset
282 case E_CCmode:
kono
parents:
diff changeset
283 switch (GET_CODE (comparison))
kono
parents:
diff changeset
284 {
kono
parents:
diff changeset
285 case EQ : return 0;
kono
parents:
diff changeset
286 case NE : return 1;
kono
parents:
diff changeset
287 case LTU : return 2;
kono
parents:
diff changeset
288 case GEU : return 3;
kono
parents:
diff changeset
289 case GT : return 4;
kono
parents:
diff changeset
290 case LE : return 5;
kono
parents:
diff changeset
291 case GE : return 6;
kono
parents:
diff changeset
292 case LT : return 7;
kono
parents:
diff changeset
293 case GTU : return 8;
kono
parents:
diff changeset
294 case LEU : return 9;
kono
parents:
diff changeset
295
kono
parents:
diff changeset
296 default : gcc_unreachable ();
kono
parents:
diff changeset
297 }
kono
parents:
diff changeset
298 case E_CC_N_NEmode:
kono
parents:
diff changeset
299 switch (GET_CODE (comparison))
kono
parents:
diff changeset
300 {
kono
parents:
diff changeset
301 case EQ: return 6;
kono
parents:
diff changeset
302 case NE: return 7;
kono
parents:
diff changeset
303 default: gcc_unreachable ();
kono
parents:
diff changeset
304 }
kono
parents:
diff changeset
305 case E_CC_C_LTUmode:
kono
parents:
diff changeset
306 switch (GET_CODE (comparison))
kono
parents:
diff changeset
307 {
kono
parents:
diff changeset
308 case GEU: return 2;
kono
parents:
diff changeset
309 case LTU: return 3;
kono
parents:
diff changeset
310 default: gcc_unreachable ();
kono
parents:
diff changeset
311 }
kono
parents:
diff changeset
312 case E_CC_C_GTUmode:
kono
parents:
diff changeset
313 switch (GET_CODE (comparison))
kono
parents:
diff changeset
314 {
kono
parents:
diff changeset
315 case LEU: return 3;
kono
parents:
diff changeset
316 case GTU: return 2;
kono
parents:
diff changeset
317 default: gcc_unreachable ();
kono
parents:
diff changeset
318 }
kono
parents:
diff changeset
319 case E_CC_FPmode:
kono
parents:
diff changeset
320 switch (GET_CODE (comparison))
kono
parents:
diff changeset
321 {
kono
parents:
diff changeset
322 case EQ: return 10;
kono
parents:
diff changeset
323 case NE: return 11;
kono
parents:
diff changeset
324 case LT: return 12;
kono
parents:
diff changeset
325 case LE: return 13;
kono
parents:
diff changeset
326 default: gcc_unreachable ();
kono
parents:
diff changeset
327 }
kono
parents:
diff changeset
328 case E_CC_FP_EQmode:
kono
parents:
diff changeset
329 switch (GET_CODE (comparison))
kono
parents:
diff changeset
330 {
kono
parents:
diff changeset
331 case EQ: return 0;
kono
parents:
diff changeset
332 case NE: return 1;
kono
parents:
diff changeset
333 default: gcc_unreachable ();
kono
parents:
diff changeset
334 }
kono
parents:
diff changeset
335 case E_CC_FP_GTEmode:
kono
parents:
diff changeset
336 switch (GET_CODE (comparison))
kono
parents:
diff changeset
337 {
kono
parents:
diff changeset
338 case EQ: return 0;
kono
parents:
diff changeset
339 case NE: return 1;
kono
parents:
diff changeset
340 case GT : return 4;
kono
parents:
diff changeset
341 case GE : return 6;
kono
parents:
diff changeset
342 case UNLE : return 5;
kono
parents:
diff changeset
343 case UNLT : return 7;
kono
parents:
diff changeset
344 default: gcc_unreachable ();
kono
parents:
diff changeset
345 }
kono
parents:
diff changeset
346 case E_CC_FP_ORDmode:
kono
parents:
diff changeset
347 switch (GET_CODE (comparison))
kono
parents:
diff changeset
348 {
kono
parents:
diff changeset
349 case ORDERED: return 9;
kono
parents:
diff changeset
350 case UNORDERED: return 8;
kono
parents:
diff changeset
351 default: gcc_unreachable ();
kono
parents:
diff changeset
352 }
kono
parents:
diff changeset
353 case E_CC_FP_UNEQmode:
kono
parents:
diff changeset
354 switch (GET_CODE (comparison))
kono
parents:
diff changeset
355 {
kono
parents:
diff changeset
356 case UNEQ: return 9;
kono
parents:
diff changeset
357 case LTGT: return 8;
kono
parents:
diff changeset
358 default: gcc_unreachable ();
kono
parents:
diff changeset
359 }
kono
parents:
diff changeset
360 default: gcc_unreachable ();
kono
parents:
diff changeset
361 }
kono
parents:
diff changeset
362 /*NOTREACHED*/
kono
parents:
diff changeset
363 return (42);
kono
parents:
diff changeset
364 }
kono
parents:
diff changeset
365
kono
parents:
diff changeset
366
kono
parents:
diff changeset
367 /* Implement TARGET_HARD_REGNO_MODE_OK. */
kono
parents:
diff changeset
368
kono
parents:
diff changeset
369 static bool
kono
parents:
diff changeset
370 epiphany_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
kono
parents:
diff changeset
371 {
kono
parents:
diff changeset
372 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
kono
parents:
diff changeset
373 return (regno & 1) == 0 && GPR_P (regno);
kono
parents:
diff changeset
374 else
kono
parents:
diff changeset
375 return true;
kono
parents:
diff changeset
376 }
kono
parents:
diff changeset
377
kono
parents:
diff changeset
378 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
kono
parents:
diff changeset
379 return the mode to be used for the comparison. */
kono
parents:
diff changeset
380
kono
parents:
diff changeset
381 machine_mode
kono
parents:
diff changeset
382 epiphany_select_cc_mode (enum rtx_code op,
kono
parents:
diff changeset
383 rtx x ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
384 rtx y ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
385 {
kono
parents:
diff changeset
386 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
kono
parents:
diff changeset
387 {
kono
parents:
diff changeset
388 if (TARGET_SOFT_CMPSF
kono
parents:
diff changeset
389 || op == ORDERED || op == UNORDERED)
kono
parents:
diff changeset
390 {
kono
parents:
diff changeset
391 if (op == EQ || op == NE)
kono
parents:
diff changeset
392 return CC_FP_EQmode;
kono
parents:
diff changeset
393 if (op == ORDERED || op == UNORDERED)
kono
parents:
diff changeset
394 return CC_FP_ORDmode;
kono
parents:
diff changeset
395 if (op == UNEQ || op == LTGT)
kono
parents:
diff changeset
396 return CC_FP_UNEQmode;
kono
parents:
diff changeset
397 return CC_FP_GTEmode;
kono
parents:
diff changeset
398 }
kono
parents:
diff changeset
399 return CC_FPmode;
kono
parents:
diff changeset
400 }
kono
parents:
diff changeset
401 /* recognize combiner pattern ashlsi_btst:
kono
parents:
diff changeset
402 (parallel [
kono
parents:
diff changeset
403 (set (reg:N_NE 65 cc1)
kono
parents:
diff changeset
404 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ])
kono
parents:
diff changeset
405 (const_int 1 [0x1])
kono
parents:
diff changeset
406 (const_int 0 [0x0]))
kono
parents:
diff changeset
407 (const_int 0 [0x0])))
kono
parents:
diff changeset
408 (clobber (scratch:SI)) */
kono
parents:
diff changeset
409 else if ((op == EQ || op == NE)
kono
parents:
diff changeset
410 && GET_CODE (x) == ZERO_EXTRACT
kono
parents:
diff changeset
411 && XEXP (x, 1) == const1_rtx
kono
parents:
diff changeset
412 && CONST_INT_P (XEXP (x, 2)))
kono
parents:
diff changeset
413 return CC_N_NEmode;
kono
parents:
diff changeset
414 else if ((op == GEU || op == LTU) && GET_CODE (x) == PLUS)
kono
parents:
diff changeset
415 return CC_C_LTUmode;
kono
parents:
diff changeset
416 else if ((op == LEU || op == GTU) && GET_CODE (x) == MINUS)
kono
parents:
diff changeset
417 return CC_C_GTUmode;
kono
parents:
diff changeset
418 else
kono
parents:
diff changeset
419 return CCmode;
kono
parents:
diff changeset
420 }
kono
parents:
diff changeset
421
kono
parents:
diff changeset
422 enum reg_class epiphany_regno_reg_class[FIRST_PSEUDO_REGISTER];
kono
parents:
diff changeset
423
kono
parents:
diff changeset
424 static void
kono
parents:
diff changeset
425 epiphany_init_reg_tables (void)
kono
parents:
diff changeset
426 {
kono
parents:
diff changeset
427 int i;
kono
parents:
diff changeset
428
kono
parents:
diff changeset
429 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
kono
parents:
diff changeset
430 {
kono
parents:
diff changeset
431 if (i == GPR_LR)
kono
parents:
diff changeset
432 epiphany_regno_reg_class[i] = LR_REGS;
kono
parents:
diff changeset
433 else if (i <= 7 && TARGET_PREFER_SHORT_INSN_REGS)
kono
parents:
diff changeset
434 epiphany_regno_reg_class[i] = SHORT_INSN_REGS;
kono
parents:
diff changeset
435 else if (call_used_regs[i]
kono
parents:
diff changeset
436 && TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i))
kono
parents:
diff changeset
437 epiphany_regno_reg_class[i] = SIBCALL_REGS;
kono
parents:
diff changeset
438 else if (i >= CORE_CONTROL_FIRST && i <= CORE_CONTROL_LAST)
kono
parents:
diff changeset
439 epiphany_regno_reg_class[i] = CORE_CONTROL_REGS;
kono
parents:
diff changeset
440 else if (i < (GPR_LAST+1)
kono
parents:
diff changeset
441 || i == ARG_POINTER_REGNUM || i == FRAME_POINTER_REGNUM)
kono
parents:
diff changeset
442 epiphany_regno_reg_class[i] = GENERAL_REGS;
kono
parents:
diff changeset
443 else if (i == CC_REGNUM)
kono
parents:
diff changeset
444 epiphany_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */;
kono
parents:
diff changeset
445 else
kono
parents:
diff changeset
446 epiphany_regno_reg_class[i] = NO_REGS;
kono
parents:
diff changeset
447 }
kono
parents:
diff changeset
448 }
kono
parents:
diff changeset
449
kono
parents:
diff changeset
450 /* EPIPHANY specific attribute support.
kono
parents:
diff changeset
451
kono
parents:
diff changeset
452 The EPIPHANY has these attributes:
kono
parents:
diff changeset
453 interrupt - for interrupt functions.
kono
parents:
diff changeset
454 short_call - the function is assumed to be reachable with the b / bl
kono
parents:
diff changeset
455 instructions.
kono
parents:
diff changeset
456 long_call - the function address is loaded into a register before use.
kono
parents:
diff changeset
457 disinterrupt - functions which mask interrupts throughout.
kono
parents:
diff changeset
458 They unmask them while calling an interruptible
kono
parents:
diff changeset
459 function, though. */
kono
parents:
diff changeset
460
kono
parents:
diff changeset
461 static const struct attribute_spec epiphany_attribute_table[] =
kono
parents:
diff changeset
462 {
kono
parents:
diff changeset
463 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
kono
parents:
diff changeset
464 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true },
kono
parents:
diff changeset
465 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
kono
parents:
diff changeset
466 { "long_call", 0, 0, false, true, true, NULL, false },
kono
parents:
diff changeset
467 { "short_call", 0, 0, false, true, true, NULL, false },
kono
parents:
diff changeset
468 { "disinterrupt", 0, 0, false, true, true, NULL, true },
kono
parents:
diff changeset
469 { NULL, 0, 0, false, false, false, NULL, false }
kono
parents:
diff changeset
470 };
kono
parents:
diff changeset
471
kono
parents:
diff changeset
472 /* Handle an "interrupt" attribute; arguments as in
kono
parents:
diff changeset
473 struct attribute_spec.handler. */
kono
parents:
diff changeset
474 static tree
kono
parents:
diff changeset
475 epiphany_handle_interrupt_attribute (tree *node, tree name, tree args,
kono
parents:
diff changeset
476 int flags ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
477 bool *no_add_attrs)
kono
parents:
diff changeset
478 {
kono
parents:
diff changeset
479 tree value;
kono
parents:
diff changeset
480
kono
parents:
diff changeset
481 if (!args)
kono
parents:
diff changeset
482 {
kono
parents:
diff changeset
483 gcc_assert (DECL_P (*node));
kono
parents:
diff changeset
484 tree t = TREE_TYPE (*node);
kono
parents:
diff changeset
485 if (TREE_CODE (t) != FUNCTION_TYPE)
kono
parents:
diff changeset
486 warning (OPT_Wattributes, "%qE attribute only applies to functions",
kono
parents:
diff changeset
487 name);
kono
parents:
diff changeset
488 /* Argument handling and the stack layout for interrupt handlers
kono
parents:
diff changeset
489 don't mix. It makes no sense in the first place, so emit an
kono
parents:
diff changeset
490 error for this. */
kono
parents:
diff changeset
491 else if (TYPE_ARG_TYPES (t)
kono
parents:
diff changeset
492 && TREE_VALUE (TYPE_ARG_TYPES (t)) != void_type_node)
kono
parents:
diff changeset
493 error_at (DECL_SOURCE_LOCATION (*node),
kono
parents:
diff changeset
494 "interrupt handlers cannot have arguments");
kono
parents:
diff changeset
495 return NULL_TREE;
kono
parents:
diff changeset
496 }
kono
parents:
diff changeset
497
kono
parents:
diff changeset
498 value = TREE_VALUE (args);
kono
parents:
diff changeset
499
kono
parents:
diff changeset
500 if (TREE_CODE (value) != STRING_CST)
kono
parents:
diff changeset
501 {
kono
parents:
diff changeset
502 warning (OPT_Wattributes,
kono
parents:
diff changeset
503 "argument of %qE attribute is not a string constant", name);
kono
parents:
diff changeset
504 *no_add_attrs = true;
kono
parents:
diff changeset
505 }
kono
parents:
diff changeset
506 else if (strcmp (TREE_STRING_POINTER (value), "reset")
kono
parents:
diff changeset
507 && strcmp (TREE_STRING_POINTER (value), "software_exception")
kono
parents:
diff changeset
508 && strcmp (TREE_STRING_POINTER (value), "page_miss")
kono
parents:
diff changeset
509 && strcmp (TREE_STRING_POINTER (value), "timer0")
kono
parents:
diff changeset
510 && strcmp (TREE_STRING_POINTER (value), "timer1")
kono
parents:
diff changeset
511 && strcmp (TREE_STRING_POINTER (value), "message")
kono
parents:
diff changeset
512 && strcmp (TREE_STRING_POINTER (value), "dma0")
kono
parents:
diff changeset
513 && strcmp (TREE_STRING_POINTER (value), "dma1")
kono
parents:
diff changeset
514 && strcmp (TREE_STRING_POINTER (value), "wand")
kono
parents:
diff changeset
515 && strcmp (TREE_STRING_POINTER (value), "swi"))
kono
parents:
diff changeset
516 {
kono
parents:
diff changeset
517 warning (OPT_Wattributes,
kono
parents:
diff changeset
518 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
kono
parents:
diff changeset
519 name);
kono
parents:
diff changeset
520 *no_add_attrs = true;
kono
parents:
diff changeset
521 return NULL_TREE;
kono
parents:
diff changeset
522 }
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args),
kono
parents:
diff changeset
525 flags, no_add_attrs);
kono
parents:
diff changeset
526 }
kono
parents:
diff changeset
527
kono
parents:
diff changeset
528 /* Handle a "forwarder_section" attribute; arguments as in
kono
parents:
diff changeset
529 struct attribute_spec.handler. */
kono
parents:
diff changeset
530 static tree
kono
parents:
diff changeset
531 epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
532 tree name, tree args,
kono
parents:
diff changeset
533 int flags ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
534 bool *no_add_attrs)
kono
parents:
diff changeset
535 {
kono
parents:
diff changeset
536 tree value;
kono
parents:
diff changeset
537
kono
parents:
diff changeset
538 value = TREE_VALUE (args);
kono
parents:
diff changeset
539
kono
parents:
diff changeset
540 if (TREE_CODE (value) != STRING_CST)
kono
parents:
diff changeset
541 {
kono
parents:
diff changeset
542 warning (OPT_Wattributes,
kono
parents:
diff changeset
543 "argument of %qE attribute is not a string constant", name);
kono
parents:
diff changeset
544 *no_add_attrs = true;
kono
parents:
diff changeset
545 }
kono
parents:
diff changeset
546 return NULL_TREE;
kono
parents:
diff changeset
547 }
kono
parents:
diff changeset
548
kono
parents:
diff changeset
549
kono
parents:
diff changeset
550 /* Misc. utilities. */
kono
parents:
diff changeset
551
kono
parents:
diff changeset
552 /* Generate a SYMBOL_REF for the special function NAME. When the address
kono
parents:
diff changeset
553 can't be placed directly into a call instruction, and if possible, copy
kono
parents:
diff changeset
554 it to a register so that cse / code hoisting is possible. */
kono
parents:
diff changeset
555 rtx
kono
parents:
diff changeset
556 sfunc_symbol (const char *name)
kono
parents:
diff changeset
557 {
kono
parents:
diff changeset
558 rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
kono
parents:
diff changeset
559
kono
parents:
diff changeset
560 /* These sfuncs should be hidden, and every dso should get a copy. */
kono
parents:
diff changeset
561 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL;
kono
parents:
diff changeset
562 if (TARGET_SHORT_CALLS)
kono
parents:
diff changeset
563 ; /* Nothing to be done. */
kono
parents:
diff changeset
564 else if (can_create_pseudo_p ())
kono
parents:
diff changeset
565 sym = copy_to_mode_reg (Pmode, sym);
kono
parents:
diff changeset
566 else /* We rely on reload to fix this up. */
kono
parents:
diff changeset
567 gcc_assert (!reload_in_progress || reload_completed);
kono
parents:
diff changeset
568 return sym;
kono
parents:
diff changeset
569 }
kono
parents:
diff changeset
570
kono
parents:
diff changeset
571 /* X and Y are two things to compare using CODE in IN_MODE.
kono
parents:
diff changeset
572 Emit the compare insn, construct the proper cc reg in the proper
kono
parents:
diff changeset
573 mode, and return the rtx for the cc reg comparison in CMODE. */
kono
parents:
diff changeset
574
kono
parents:
diff changeset
575 rtx
kono
parents:
diff changeset
576 gen_compare_reg (machine_mode cmode, enum rtx_code code,
kono
parents:
diff changeset
577 machine_mode in_mode, rtx x, rtx y)
kono
parents:
diff changeset
578 {
kono
parents:
diff changeset
579 machine_mode mode = SELECT_CC_MODE (code, x, y);
kono
parents:
diff changeset
580 rtx cc_reg, pat, clob0, clob1, clob2;
kono
parents:
diff changeset
581
kono
parents:
diff changeset
582 if (in_mode == VOIDmode)
kono
parents:
diff changeset
583 in_mode = GET_MODE (x);
kono
parents:
diff changeset
584 if (in_mode == VOIDmode)
kono
parents:
diff changeset
585 in_mode = GET_MODE (y);
kono
parents:
diff changeset
586
kono
parents:
diff changeset
587 if (mode == CC_FPmode)
kono
parents:
diff changeset
588 {
kono
parents:
diff changeset
589 /* The epiphany has only EQ / NE / LT / LE conditions for
kono
parents:
diff changeset
590 hardware floating point. */
kono
parents:
diff changeset
591 if (code == GT || code == GE || code == UNLE || code == UNLT)
kono
parents:
diff changeset
592 {
kono
parents:
diff changeset
593 rtx tmp = x; x = y; y = tmp;
kono
parents:
diff changeset
594 code = swap_condition (code);
kono
parents:
diff changeset
595 }
kono
parents:
diff changeset
596 cc_reg = gen_rtx_REG (mode, CCFP_REGNUM);
kono
parents:
diff changeset
597 y = force_reg (in_mode, y);
kono
parents:
diff changeset
598 }
kono
parents:
diff changeset
599 else
kono
parents:
diff changeset
600 {
kono
parents:
diff changeset
601 if (mode == CC_FP_GTEmode
kono
parents:
diff changeset
602 && (code == LE || code == LT || code == UNGT || code == UNGE))
kono
parents:
diff changeset
603 {
kono
parents:
diff changeset
604 if (flag_finite_math_only
kono
parents:
diff changeset
605 && ((REG_P (x) && REGNO (x) == GPR_0)
kono
parents:
diff changeset
606 || (REG_P (y) && REGNO (y) == GPR_1)))
kono
parents:
diff changeset
607 switch (code)
kono
parents:
diff changeset
608 {
kono
parents:
diff changeset
609 case LE: code = UNLE; break;
kono
parents:
diff changeset
610 case LT: code = UNLT; break;
kono
parents:
diff changeset
611 case UNGT: code = GT; break;
kono
parents:
diff changeset
612 case UNGE: code = GE; break;
kono
parents:
diff changeset
613 default: gcc_unreachable ();
kono
parents:
diff changeset
614 }
kono
parents:
diff changeset
615 else
kono
parents:
diff changeset
616 {
kono
parents:
diff changeset
617 rtx tmp = x; x = y; y = tmp;
kono
parents:
diff changeset
618 code = swap_condition (code);
kono
parents:
diff changeset
619 }
kono
parents:
diff changeset
620 }
kono
parents:
diff changeset
621 cc_reg = gen_rtx_REG (mode, CC_REGNUM);
kono
parents:
diff changeset
622 }
kono
parents:
diff changeset
623 if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode
kono
parents:
diff changeset
624 || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
kono
parents:
diff changeset
625 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */
kono
parents:
diff changeset
626 && (!REG_P (x) || REGNO (x) != GPR_0
kono
parents:
diff changeset
627 || !REG_P (y) || REGNO (y) != GPR_1))
kono
parents:
diff changeset
628 {
kono
parents:
diff changeset
629 rtx reg;
kono
parents:
diff changeset
630
kono
parents:
diff changeset
631 #if 0
kono
parents:
diff changeset
632 /* ??? We should really do the r0/r1 clobber only during rtl expansion,
kono
parents:
diff changeset
633 but just like the flag clobber of movsicc, we have to allow
kono
parents:
diff changeset
634 this for ifcvt to work, on the assumption that we'll only want
kono
parents:
diff changeset
635 to do this if these registers have been used before by the
kono
parents:
diff changeset
636 pre-ifcvt code. */
kono
parents:
diff changeset
637 gcc_assert (currently_expanding_to_rtl);
kono
parents:
diff changeset
638 #endif
kono
parents:
diff changeset
639 reg = gen_rtx_REG (in_mode, GPR_0);
kono
parents:
diff changeset
640 if (reg_overlap_mentioned_p (reg, y))
kono
parents:
diff changeset
641 return 0;
kono
parents:
diff changeset
642 emit_move_insn (reg, x);
kono
parents:
diff changeset
643 x = reg;
kono
parents:
diff changeset
644 reg = gen_rtx_REG (in_mode, GPR_1);
kono
parents:
diff changeset
645 emit_move_insn (reg, y);
kono
parents:
diff changeset
646 y = reg;
kono
parents:
diff changeset
647 }
kono
parents:
diff changeset
648 else
kono
parents:
diff changeset
649 x = force_reg (in_mode, x);
kono
parents:
diff changeset
650
kono
parents:
diff changeset
651 pat = gen_rtx_SET (cc_reg, gen_rtx_COMPARE (mode, x, y));
kono
parents:
diff changeset
652 if (mode == CC_FP_EQmode || mode == CC_FP_GTEmode)
kono
parents:
diff changeset
653 {
kono
parents:
diff changeset
654 const char *name = mode == CC_FP_EQmode ? "__eqsf2" : "__gtesf2";
kono
parents:
diff changeset
655 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
kono
parents:
diff changeset
656
kono
parents:
diff changeset
657 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
kono
parents:
diff changeset
658 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
kono
parents:
diff changeset
659 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (4, pat, use, clob0, clob1));
kono
parents:
diff changeset
660 }
kono
parents:
diff changeset
661 else if (mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
kono
parents:
diff changeset
662 {
kono
parents:
diff changeset
663 const char *name = mode == CC_FP_ORDmode ? "__ordsf2" : "__uneqsf2";
kono
parents:
diff changeset
664 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
kono
parents:
diff changeset
665
kono
parents:
diff changeset
666 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
kono
parents:
diff changeset
667 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_16));
kono
parents:
diff changeset
668 clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
kono
parents:
diff changeset
669 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (5, pat, use,
kono
parents:
diff changeset
670 clob0, clob1, clob2));
kono
parents:
diff changeset
671 }
kono
parents:
diff changeset
672 else
kono
parents:
diff changeset
673 {
kono
parents:
diff changeset
674 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (in_mode));
kono
parents:
diff changeset
675 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob0));
kono
parents:
diff changeset
676 }
kono
parents:
diff changeset
677 emit_insn (pat);
kono
parents:
diff changeset
678 return gen_rtx_fmt_ee (code, cmode, cc_reg, const0_rtx);
kono
parents:
diff changeset
679 }
kono
parents:
diff changeset
680
kono
parents:
diff changeset
681 /* The ROUND_ADVANCE* macros are local to this file. */
kono
parents:
diff changeset
682 /* Round SIZE up to a word boundary. */
kono
parents:
diff changeset
683 #define ROUND_ADVANCE(SIZE) \
kono
parents:
diff changeset
684 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
kono
parents:
diff changeset
685
kono
parents:
diff changeset
686 /* Round arg MODE/TYPE up to the next word boundary. */
kono
parents:
diff changeset
687 #define ROUND_ADVANCE_ARG(MODE, TYPE) \
kono
parents:
diff changeset
688 ((MODE) == BLKmode \
kono
parents:
diff changeset
689 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
kono
parents:
diff changeset
690 : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))
kono
parents:
diff changeset
691
kono
parents:
diff changeset
692 /* Round CUM up to the necessary point for argument MODE/TYPE. */
kono
parents:
diff changeset
693 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \
kono
parents:
diff changeset
694 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \
kono
parents:
diff changeset
695 ? (((CUM) + 1) & ~1) \
kono
parents:
diff changeset
696 : (CUM))
kono
parents:
diff changeset
697
kono
parents:
diff changeset
698 static unsigned int
kono
parents:
diff changeset
699 epiphany_function_arg_boundary (machine_mode mode, const_tree type)
kono
parents:
diff changeset
700 {
kono
parents:
diff changeset
701 if ((type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode)) <= PARM_BOUNDARY)
kono
parents:
diff changeset
702 return PARM_BOUNDARY;
kono
parents:
diff changeset
703 return 2 * PARM_BOUNDARY;
kono
parents:
diff changeset
704 }
kono
parents:
diff changeset
705
kono
parents:
diff changeset
706 /* Do any needed setup for a variadic function. For the EPIPHANY, we
kono
parents:
diff changeset
707 actually emit the code in epiphany_expand_prologue.
kono
parents:
diff changeset
708
kono
parents:
diff changeset
709 CUM has not been updated for the last named argument which has type TYPE
kono
parents:
diff changeset
710 and mode MODE, and we rely on this fact. */
kono
parents:
diff changeset
711
kono
parents:
diff changeset
712
kono
parents:
diff changeset
713 static void
kono
parents:
diff changeset
714 epiphany_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
kono
parents:
diff changeset
715 tree type, int *pretend_size, int no_rtl)
kono
parents:
diff changeset
716 {
kono
parents:
diff changeset
717 int first_anon_arg;
kono
parents:
diff changeset
718 CUMULATIVE_ARGS next_cum;
kono
parents:
diff changeset
719 machine_function_t *mf = MACHINE_FUNCTION (cfun);
kono
parents:
diff changeset
720
kono
parents:
diff changeset
721 /* All BLKmode values are passed by reference. */
kono
parents:
diff changeset
722 gcc_assert (mode != BLKmode);
kono
parents:
diff changeset
723
kono
parents:
diff changeset
724 next_cum = *get_cumulative_args (cum);
kono
parents:
diff changeset
725 next_cum
kono
parents:
diff changeset
726 = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
kono
parents:
diff changeset
727 first_anon_arg = next_cum;
kono
parents:
diff changeset
728
kono
parents:
diff changeset
729 if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl)
kono
parents:
diff changeset
730 {
kono
parents:
diff changeset
731 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */
kono
parents:
diff changeset
732 int first_reg_offset = first_anon_arg;
kono
parents:
diff changeset
733
kono
parents:
diff changeset
734 *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset)
kono
parents:
diff changeset
735 * UNITS_PER_WORD);
kono
parents:
diff changeset
736 }
kono
parents:
diff changeset
737 mf->args_parsed = 1;
kono
parents:
diff changeset
738 mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0);
kono
parents:
diff changeset
739 }
kono
parents:
diff changeset
740
kono
parents:
diff changeset
741 static int
kono
parents:
diff changeset
742 epiphany_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
kono
parents:
diff changeset
743 tree type, bool named ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
744 {
kono
parents:
diff changeset
745 int words = 0, rounded_cum;
kono
parents:
diff changeset
746
kono
parents:
diff changeset
747 gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true));
kono
parents:
diff changeset
748
kono
parents:
diff changeset
749 rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type);
kono
parents:
diff changeset
750 if (rounded_cum < MAX_EPIPHANY_PARM_REGS)
kono
parents:
diff changeset
751 {
kono
parents:
diff changeset
752 words = MAX_EPIPHANY_PARM_REGS - rounded_cum;
kono
parents:
diff changeset
753 if (words >= ROUND_ADVANCE_ARG (mode, type))
kono
parents:
diff changeset
754 words = 0;
kono
parents:
diff changeset
755 }
kono
parents:
diff changeset
756 return words * UNITS_PER_WORD;
kono
parents:
diff changeset
757 }
kono
parents:
diff changeset
758
kono
parents:
diff changeset
759 /* Cost functions. */
kono
parents:
diff changeset
760
kono
parents:
diff changeset
761 /* Compute a (partial) cost for rtx X. Return true if the complete
kono
parents:
diff changeset
762 cost has been computed, and false if subexpressions should be
kono
parents:
diff changeset
763 scanned. In either case, *TOTAL contains the cost result. */
kono
parents:
diff changeset
764
kono
parents:
diff changeset
765 static bool
kono
parents:
diff changeset
766 epiphany_rtx_costs (rtx x, machine_mode mode, int outer_code,
kono
parents:
diff changeset
767 int opno ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
768 int *total, bool speed ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
769 {
kono
parents:
diff changeset
770 int code = GET_CODE (x);
kono
parents:
diff changeset
771
kono
parents:
diff changeset
772 switch (code)
kono
parents:
diff changeset
773 {
kono
parents:
diff changeset
774 /* Small integers in the right context are as cheap as registers. */
kono
parents:
diff changeset
775 case CONST_INT:
kono
parents:
diff changeset
776 if ((outer_code == PLUS || outer_code == MINUS)
kono
parents:
diff changeset
777 && SIMM11 (INTVAL (x)))
kono
parents:
diff changeset
778 {
kono
parents:
diff changeset
779 *total = 0;
kono
parents:
diff changeset
780 return true;
kono
parents:
diff changeset
781 }
kono
parents:
diff changeset
782 if (IMM16 (INTVAL (x)))
kono
parents:
diff changeset
783 {
kono
parents:
diff changeset
784 *total = outer_code == SET ? 0 : COSTS_N_INSNS (1);
kono
parents:
diff changeset
785 return true;
kono
parents:
diff changeset
786 }
kono
parents:
diff changeset
787 /* FALLTHRU */
kono
parents:
diff changeset
788
kono
parents:
diff changeset
789 case CONST:
kono
parents:
diff changeset
790 case LABEL_REF:
kono
parents:
diff changeset
791 case SYMBOL_REF:
kono
parents:
diff changeset
792 *total = COSTS_N_INSNS ((epiphany_small16 (x) ? 0 : 1)
kono
parents:
diff changeset
793 + (outer_code == SET ? 0 : 1));
kono
parents:
diff changeset
794 return true;
kono
parents:
diff changeset
795
kono
parents:
diff changeset
796 case CONST_DOUBLE:
kono
parents:
diff changeset
797 {
kono
parents:
diff changeset
798 rtx high, low;
kono
parents:
diff changeset
799 split_double (x, &high, &low);
kono
parents:
diff changeset
800 *total = COSTS_N_INSNS (!IMM16 (INTVAL (high))
kono
parents:
diff changeset
801 + !IMM16 (INTVAL (low)));
kono
parents:
diff changeset
802 return true;
kono
parents:
diff changeset
803 }
kono
parents:
diff changeset
804
kono
parents:
diff changeset
805 case ASHIFT:
kono
parents:
diff changeset
806 case ASHIFTRT:
kono
parents:
diff changeset
807 case LSHIFTRT:
kono
parents:
diff changeset
808 *total = COSTS_N_INSNS (1);
kono
parents:
diff changeset
809 return true;
kono
parents:
diff changeset
810
kono
parents:
diff changeset
811 case COMPARE:
kono
parents:
diff changeset
812 switch (mode)
kono
parents:
diff changeset
813 {
kono
parents:
diff changeset
814 /* There are a number of single-insn combiner patterns that use
kono
parents:
diff changeset
815 the flag side effects of arithmetic. */
kono
parents:
diff changeset
816 case E_CC_N_NEmode:
kono
parents:
diff changeset
817 case E_CC_C_LTUmode:
kono
parents:
diff changeset
818 case E_CC_C_GTUmode:
kono
parents:
diff changeset
819 return true;
kono
parents:
diff changeset
820 default:
kono
parents:
diff changeset
821 return false;
kono
parents:
diff changeset
822 }
kono
parents:
diff changeset
823
kono
parents:
diff changeset
824
kono
parents:
diff changeset
825 case SET:
kono
parents:
diff changeset
826 {
kono
parents:
diff changeset
827 rtx src = SET_SRC (x);
kono
parents:
diff changeset
828 if (BINARY_P (src))
kono
parents:
diff changeset
829 *total = 0;
kono
parents:
diff changeset
830 return false;
kono
parents:
diff changeset
831 }
kono
parents:
diff changeset
832
kono
parents:
diff changeset
833 default:
kono
parents:
diff changeset
834 return false;
kono
parents:
diff changeset
835 }
kono
parents:
diff changeset
836 }
kono
parents:
diff changeset
837
kono
parents:
diff changeset
838
kono
parents:
diff changeset
839 /* Provide the costs of an addressing mode that contains ADDR.
kono
parents:
diff changeset
840 If ADDR is not a valid address, its cost is irrelevant. */
kono
parents:
diff changeset
841
kono
parents:
diff changeset
842 static int
kono
parents:
diff changeset
843 epiphany_address_cost (rtx addr, machine_mode mode,
kono
parents:
diff changeset
844 addr_space_t as ATTRIBUTE_UNUSED, bool speed)
kono
parents:
diff changeset
845 {
kono
parents:
diff changeset
846 rtx reg;
kono
parents:
diff changeset
847 rtx off = const0_rtx;
kono
parents:
diff changeset
848 int i;
kono
parents:
diff changeset
849
kono
parents:
diff changeset
850 if (speed)
kono
parents:
diff changeset
851 return 0;
kono
parents:
diff changeset
852 /* Return 0 for addresses valid in short insns, 1 for addresses only valid
kono
parents:
diff changeset
853 in long insns. */
kono
parents:
diff changeset
854 switch (GET_CODE (addr))
kono
parents:
diff changeset
855 {
kono
parents:
diff changeset
856 case PLUS :
kono
parents:
diff changeset
857 reg = XEXP (addr, 0);
kono
parents:
diff changeset
858 off = XEXP (addr, 1);
kono
parents:
diff changeset
859 break;
kono
parents:
diff changeset
860 case POST_MODIFY:
kono
parents:
diff changeset
861 reg = XEXP (addr, 0);
kono
parents:
diff changeset
862 off = XEXP (addr, 1);
kono
parents:
diff changeset
863 gcc_assert (GET_CODE (off) == PLUS && rtx_equal_p (reg, XEXP (off, 0)));
kono
parents:
diff changeset
864 off = XEXP (off, 1);
kono
parents:
diff changeset
865 if (satisfies_constraint_Rgs (reg) && satisfies_constraint_Rgs (off))
kono
parents:
diff changeset
866 return 0;
kono
parents:
diff changeset
867 return 1;
kono
parents:
diff changeset
868 case REG:
kono
parents:
diff changeset
869 default:
kono
parents:
diff changeset
870 reg = addr;
kono
parents:
diff changeset
871 break;
kono
parents:
diff changeset
872 }
kono
parents:
diff changeset
873 if (!satisfies_constraint_Rgs (reg))
kono
parents:
diff changeset
874 return 1;
kono
parents:
diff changeset
875 /* The offset range available for short instructions depends on the mode
kono
parents:
diff changeset
876 of the memory access. */
kono
parents:
diff changeset
877 /* First, make sure we have a valid integer. */
kono
parents:
diff changeset
878 if (!satisfies_constraint_L (off))
kono
parents:
diff changeset
879 return 1;
kono
parents:
diff changeset
880 i = INTVAL (off);
kono
parents:
diff changeset
881 switch (GET_MODE_SIZE (mode))
kono
parents:
diff changeset
882 {
kono
parents:
diff changeset
883 default:
kono
parents:
diff changeset
884 case 4:
kono
parents:
diff changeset
885 if (i & 1)
kono
parents:
diff changeset
886 return 1;
kono
parents:
diff changeset
887 i >>= 1;
kono
parents:
diff changeset
888 /* Fall through. */
kono
parents:
diff changeset
889 case 2:
kono
parents:
diff changeset
890 if (i & 1)
kono
parents:
diff changeset
891 return 1;
kono
parents:
diff changeset
892 i >>= 1;
kono
parents:
diff changeset
893 /* Fall through. */
kono
parents:
diff changeset
894 case 1:
kono
parents:
diff changeset
895 return i < -7 || i > 7;
kono
parents:
diff changeset
896 }
kono
parents:
diff changeset
897 }
kono
parents:
diff changeset
898
kono
parents:
diff changeset
899 /* Compute the cost of moving data between registers and memory.
kono
parents:
diff changeset
900 For integer, load latency is twice as long as register-register moves,
kono
parents:
diff changeset
901 but issue pich is the same. For floating point, load latency is three
kono
parents:
diff changeset
902 times as much as a reg-reg move. */
kono
parents:
diff changeset
903 static int
kono
parents:
diff changeset
904 epiphany_memory_move_cost (machine_mode mode,
kono
parents:
diff changeset
905 reg_class_t rclass ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
906 bool in ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
907 {
kono
parents:
diff changeset
908 return GET_MODE_CLASS (mode) == MODE_INT ? 3 : 4;
kono
parents:
diff changeset
909 }
kono
parents:
diff changeset
910
kono
parents:
diff changeset
911 /* Function prologue/epilogue handlers. */
kono
parents:
diff changeset
912
kono
parents:
diff changeset
913 /* EPIPHANY stack frames look like:
kono
parents:
diff changeset
914
kono
parents:
diff changeset
915 Before call After call
kono
parents:
diff changeset
916 +-----------------------+ +-----------------------+
kono
parents:
diff changeset
917 | | | |
kono
parents:
diff changeset
918 high | local variables, | | local variables, |
kono
parents:
diff changeset
919 mem | reg save area, etc. | | reg save area, etc. |
kono
parents:
diff changeset
920 | | | |
kono
parents:
diff changeset
921 +-----------------------+ +-----------------------+
kono
parents:
diff changeset
922 | | | |
kono
parents:
diff changeset
923 | arguments on stack. | | arguments on stack. |
kono
parents:
diff changeset
924 | | | |
kono
parents:
diff changeset
925 SP+8->+-----------------------+FP+8m->+-----------------------+
kono
parents:
diff changeset
926 | 2 word save area for | | reg parm save area, |
kono
parents:
diff changeset
927 | leaf funcs / flags | | only created for |
kono
parents:
diff changeset
928 SP+0->+-----------------------+ | variable argument |
kono
parents:
diff changeset
929 | functions |
kono
parents:
diff changeset
930 FP+8n->+-----------------------+
kono
parents:
diff changeset
931 | |
kono
parents:
diff changeset
932 | register save area |
kono
parents:
diff changeset
933 | |
kono
parents:
diff changeset
934 +-----------------------+
kono
parents:
diff changeset
935 | |
kono
parents:
diff changeset
936 | local variables |
kono
parents:
diff changeset
937 | |
kono
parents:
diff changeset
938 FP+0->+-----------------------+
kono
parents:
diff changeset
939 | |
kono
parents:
diff changeset
940 | alloca allocations |
kono
parents:
diff changeset
941 | |
kono
parents:
diff changeset
942 +-----------------------+
kono
parents:
diff changeset
943 | |
kono
parents:
diff changeset
944 | arguments on stack |
kono
parents:
diff changeset
945 | |
kono
parents:
diff changeset
946 SP+8->+-----------------------+
kono
parents:
diff changeset
947 low | 2 word save area for |
kono
parents:
diff changeset
948 memory | leaf funcs / flags |
kono
parents:
diff changeset
949 SP+0->+-----------------------+
kono
parents:
diff changeset
950
kono
parents:
diff changeset
951 Notes:
kono
parents:
diff changeset
952 1) The "reg parm save area" does not exist for non variable argument fns.
kono
parents:
diff changeset
953 The "reg parm save area" could be eliminated if we created our
kono
parents:
diff changeset
954 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well
kono
parents:
diff changeset
955 (so it's not done). */
kono
parents:
diff changeset
956
kono
parents:
diff changeset
957 /* Structure to be filled in by epiphany_compute_frame_size with register
kono
parents:
diff changeset
958 save masks, and offsets for the current function. */
kono
parents:
diff changeset
959 struct epiphany_frame_info
kono
parents:
diff changeset
960 {
kono
parents:
diff changeset
961 unsigned int total_size; /* # bytes that the entire frame takes up. */
kono
parents:
diff changeset
962 unsigned int pretend_size; /* # bytes we push and pretend caller did. */
kono
parents:
diff changeset
963 unsigned int args_size; /* # bytes that outgoing arguments take up. */
kono
parents:
diff changeset
964 unsigned int reg_size; /* # bytes needed to store regs. */
kono
parents:
diff changeset
965 unsigned int var_size; /* # bytes that variables take up. */
kono
parents:
diff changeset
966 HARD_REG_SET gmask; /* Set of saved gp registers. */
kono
parents:
diff changeset
967 int initialized; /* Nonzero if frame size already calculated. */
kono
parents:
diff changeset
968 int stld_sz; /* Current load/store data size for offset
kono
parents:
diff changeset
969 adjustment. */
kono
parents:
diff changeset
970 int need_fp; /* value to override "frame_pointer_needed */
kono
parents:
diff changeset
971 /* FIRST_SLOT is the slot that is saved first, at the very start of
kono
parents:
diff changeset
972 the frame, with a POST_MODIFY to allocate the frame, if the size fits,
kono
parents:
diff changeset
973 or at least the parm and register save areas, otherwise.
kono
parents:
diff changeset
974 In the case of a large frame, LAST_SLOT is the slot that is saved last,
kono
parents:
diff changeset
975 with a POST_MODIFY to allocate the rest of the frame. */
kono
parents:
diff changeset
976 int first_slot, last_slot, first_slot_offset, last_slot_offset;
kono
parents:
diff changeset
977 int first_slot_size;
kono
parents:
diff changeset
978 int small_threshold;
kono
parents:
diff changeset
979 };
kono
parents:
diff changeset
980
kono
parents:
diff changeset
981 /* Current frame information calculated by epiphany_compute_frame_size. */
kono
parents:
diff changeset
982 static struct epiphany_frame_info current_frame_info;
kono
parents:
diff changeset
983
kono
parents:
diff changeset
984 /* Zero structure to initialize current_frame_info. */
kono
parents:
diff changeset
985 static struct epiphany_frame_info zero_frame_info;
kono
parents:
diff changeset
986
kono
parents:
diff changeset
987 /* The usual; we set up our machine_function data. */
kono
parents:
diff changeset
988 static struct machine_function *
kono
parents:
diff changeset
989 epiphany_init_machine_status (void)
kono
parents:
diff changeset
990 {
kono
parents:
diff changeset
991 struct machine_function *machine;
kono
parents:
diff changeset
992
kono
parents:
diff changeset
993 /* Reset state info for each function. */
kono
parents:
diff changeset
994 current_frame_info = zero_frame_info;
kono
parents:
diff changeset
995
kono
parents:
diff changeset
996 machine = ggc_cleared_alloc<machine_function_t> ();
kono
parents:
diff changeset
997
kono
parents:
diff changeset
998 return machine;
kono
parents:
diff changeset
999 }
kono
parents:
diff changeset
1000
kono
parents:
diff changeset
1001 /* Implements INIT_EXPANDERS. We just set up to call the above
kono
parents:
diff changeset
1002 * function. */
kono
parents:
diff changeset
1003 void
kono
parents:
diff changeset
1004 epiphany_init_expanders (void)
kono
parents:
diff changeset
1005 {
kono
parents:
diff changeset
1006 init_machine_status = epiphany_init_machine_status;
kono
parents:
diff changeset
1007 }
kono
parents:
diff changeset
1008
kono
parents:
diff changeset
1009 /* Type of function DECL.
kono
parents:
diff changeset
1010
kono
parents:
diff changeset
1011 The result is cached. To reset the cache at the end of a function,
kono
parents:
diff changeset
1012 call with DECL = NULL_TREE. */
kono
parents:
diff changeset
1013
kono
parents:
diff changeset
1014 static enum epiphany_function_type
kono
parents:
diff changeset
1015 epiphany_compute_function_type (tree decl)
kono
parents:
diff changeset
1016 {
kono
parents:
diff changeset
1017 tree a;
kono
parents:
diff changeset
1018 /* Cached value. */
kono
parents:
diff changeset
1019 static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN;
kono
parents:
diff changeset
1020 /* Last function we were called for. */
kono
parents:
diff changeset
1021 static tree last_fn = NULL_TREE;
kono
parents:
diff changeset
1022
kono
parents:
diff changeset
1023 /* Resetting the cached value? */
kono
parents:
diff changeset
1024 if (decl == NULL_TREE)
kono
parents:
diff changeset
1025 {
kono
parents:
diff changeset
1026 fn_type = EPIPHANY_FUNCTION_UNKNOWN;
kono
parents:
diff changeset
1027 last_fn = NULL_TREE;
kono
parents:
diff changeset
1028 return fn_type;
kono
parents:
diff changeset
1029 }
kono
parents:
diff changeset
1030
kono
parents:
diff changeset
1031 if (decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN)
kono
parents:
diff changeset
1032 return fn_type;
kono
parents:
diff changeset
1033
kono
parents:
diff changeset
1034 /* Assume we have a normal function (not an interrupt handler). */
kono
parents:
diff changeset
1035 fn_type = EPIPHANY_FUNCTION_NORMAL;
kono
parents:
diff changeset
1036
kono
parents:
diff changeset
1037 /* Now see if this is an interrupt handler. */
kono
parents:
diff changeset
1038 for (a = DECL_ATTRIBUTES (decl);
kono
parents:
diff changeset
1039 a;
kono
parents:
diff changeset
1040 a = TREE_CHAIN (a))
kono
parents:
diff changeset
1041 {
kono
parents:
diff changeset
1042 tree name = TREE_PURPOSE (a);
kono
parents:
diff changeset
1043
kono
parents:
diff changeset
1044 if (name == get_identifier ("interrupt"))
kono
parents:
diff changeset
1045 fn_type = EPIPHANY_FUNCTION_INTERRUPT;
kono
parents:
diff changeset
1046 }
kono
parents:
diff changeset
1047
kono
parents:
diff changeset
1048 last_fn = decl;
kono
parents:
diff changeset
1049 return fn_type;
kono
parents:
diff changeset
1050 }
kono
parents:
diff changeset
1051
kono
parents:
diff changeset
1052 #define RETURN_ADDR_REGNUM GPR_LR
kono
parents:
diff changeset
1053 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
kono
parents:
diff changeset
1054 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
kono
parents:
diff changeset
1055
kono
parents:
diff changeset
1056 /* Tell prologue and epilogue if register REGNO should be saved / restored.
kono
parents:
diff changeset
1057 The return address and frame pointer are treated separately.
kono
parents:
diff changeset
1058 Don't consider them here. */
kono
parents:
diff changeset
1059 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
kono
parents:
diff changeset
1060 ((df_regs_ever_live_p (regno) \
kono
parents:
diff changeset
1061 || (interrupt_p && !crtl->is_leaf \
kono
parents:
diff changeset
1062 && call_used_regs[regno] && !fixed_regs[regno])) \
kono
parents:
diff changeset
1063 && (!call_used_regs[regno] || regno == GPR_LR \
kono
parents:
diff changeset
1064 || (interrupt_p && regno != GPR_SP)))
kono
parents:
diff changeset
1065
kono
parents:
diff changeset
1066 #define MUST_SAVE_RETURN_ADDR 0
kono
parents:
diff changeset
1067
kono
parents:
diff changeset
1068 /* Return the bytes needed to compute the frame pointer from the current
kono
parents:
diff changeset
1069 stack pointer.
kono
parents:
diff changeset
1070
kono
parents:
diff changeset
1071 SIZE is the size needed for local variables. */
kono
parents:
diff changeset
1072
kono
parents:
diff changeset
1073 static unsigned int
kono
parents:
diff changeset
1074 epiphany_compute_frame_size (int size /* # of var. bytes allocated. */)
kono
parents:
diff changeset
1075 {
kono
parents:
diff changeset
1076 int regno;
kono
parents:
diff changeset
1077 unsigned int total_size, var_size, args_size, pretend_size, reg_size;
kono
parents:
diff changeset
1078 HARD_REG_SET gmask;
kono
parents:
diff changeset
1079 enum epiphany_function_type fn_type;
kono
parents:
diff changeset
1080 int interrupt_p;
kono
parents:
diff changeset
1081 int first_slot, last_slot, first_slot_offset, last_slot_offset;
kono
parents:
diff changeset
1082 int first_slot_size;
kono
parents:
diff changeset
1083 int small_slots = 0;
kono
parents:
diff changeset
1084
kono
parents:
diff changeset
1085 var_size = size;
kono
parents:
diff changeset
1086 args_size = crtl->outgoing_args_size;
kono
parents:
diff changeset
1087 pretend_size = crtl->args.pretend_args_size;
kono
parents:
diff changeset
1088 total_size = args_size + var_size;
kono
parents:
diff changeset
1089 reg_size = 0;
kono
parents:
diff changeset
1090 CLEAR_HARD_REG_SET (gmask);
kono
parents:
diff changeset
1091 first_slot = -1;
kono
parents:
diff changeset
1092 first_slot_offset = 0;
kono
parents:
diff changeset
1093 last_slot = -1;
kono
parents:
diff changeset
1094 last_slot_offset = 0;
kono
parents:
diff changeset
1095 first_slot_size = UNITS_PER_WORD;
kono
parents:
diff changeset
1096
kono
parents:
diff changeset
1097 /* See if this is an interrupt handler. Call used registers must be saved
kono
parents:
diff changeset
1098 for them too. */
kono
parents:
diff changeset
1099 fn_type = epiphany_compute_function_type (current_function_decl);
kono
parents:
diff changeset
1100 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
kono
parents:
diff changeset
1101
kono
parents:
diff changeset
1102 /* Calculate space needed for registers. */
kono
parents:
diff changeset
1103
kono
parents:
diff changeset
1104 for (regno = MAX_EPIPHANY_PARM_REGS - 1; pretend_size > reg_size; regno--)
kono
parents:
diff changeset
1105 {
kono
parents:
diff changeset
1106 reg_size += UNITS_PER_WORD;
kono
parents:
diff changeset
1107 SET_HARD_REG_BIT (gmask, regno);
kono
parents:
diff changeset
1108 if (epiphany_stack_offset - reg_size == 0)
kono
parents:
diff changeset
1109 first_slot = regno;
kono
parents:
diff changeset
1110 }
kono
parents:
diff changeset
1111
kono
parents:
diff changeset
1112 if (interrupt_p)
kono
parents:
diff changeset
1113 reg_size += 2 * UNITS_PER_WORD;
kono
parents:
diff changeset
1114 else
kono
parents:
diff changeset
1115 small_slots = epiphany_stack_offset / UNITS_PER_WORD;
kono
parents:
diff changeset
1116
kono
parents:
diff changeset
1117 if (frame_pointer_needed)
kono
parents:
diff changeset
1118 {
kono
parents:
diff changeset
1119 current_frame_info.need_fp = 1;
kono
parents:
diff changeset
1120 if (!interrupt_p && first_slot < 0)
kono
parents:
diff changeset
1121 first_slot = GPR_FP;
kono
parents:
diff changeset
1122 }
kono
parents:
diff changeset
1123 else
kono
parents:
diff changeset
1124 current_frame_info.need_fp = 0;
kono
parents:
diff changeset
1125 for (regno = 0; regno <= GPR_LAST; regno++)
kono
parents:
diff changeset
1126 {
kono
parents:
diff changeset
1127 if (MUST_SAVE_REGISTER (regno, interrupt_p))
kono
parents:
diff changeset
1128 {
kono
parents:
diff changeset
1129 gcc_assert (!TEST_HARD_REG_BIT (gmask, regno));
kono
parents:
diff changeset
1130 reg_size += UNITS_PER_WORD;
kono
parents:
diff changeset
1131 SET_HARD_REG_BIT (gmask, regno);
kono
parents:
diff changeset
1132 /* FIXME: when optimizing for speed, take schedling into account
kono
parents:
diff changeset
1133 when selecting these registers. */
kono
parents:
diff changeset
1134 if (regno == first_slot)
kono
parents:
diff changeset
1135 gcc_assert (regno == GPR_FP && frame_pointer_needed);
kono
parents:
diff changeset
1136 else if (!interrupt_p && first_slot < 0)
kono
parents:
diff changeset
1137 first_slot = regno;
kono
parents:
diff changeset
1138 else if (last_slot < 0
kono
parents:
diff changeset
1139 && (first_slot ^ regno) != 1
kono
parents:
diff changeset
1140 && (!interrupt_p || regno > GPR_1))
kono
parents:
diff changeset
1141 last_slot = regno;
kono
parents:
diff changeset
1142 }
kono
parents:
diff changeset
1143 }
kono
parents:
diff changeset
1144 if (TEST_HARD_REG_BIT (gmask, GPR_LR))
kono
parents:
diff changeset
1145 MACHINE_FUNCTION (cfun)->lr_clobbered = 1;
kono
parents:
diff changeset
1146 /* ??? Could sometimes do better than that. */
kono
parents:
diff changeset
1147 current_frame_info.small_threshold
kono
parents:
diff changeset
1148 = (optimize >= 3 || interrupt_p ? 0
kono
parents:
diff changeset
1149 : pretend_size ? small_slots
kono
parents:
diff changeset
1150 : 4 + small_slots - (first_slot == GPR_FP));
kono
parents:
diff changeset
1151
kono
parents:
diff changeset
1152 /* If there might be variables with 64-bit alignment requirement, align the
kono
parents:
diff changeset
1153 start of the variables. */
kono
parents:
diff changeset
1154 if (var_size >= 2 * UNITS_PER_WORD
kono
parents:
diff changeset
1155 /* We don't want to split a double reg save/restore across two unpaired
kono
parents:
diff changeset
1156 stack slots when optimizing. This rounding could be avoided with
kono
parents:
diff changeset
1157 more complex reordering of the register saves, but that would seem
kono
parents:
diff changeset
1158 to be a lot of code complexity for little gain. */
kono
parents:
diff changeset
1159 || (reg_size > 8 && optimize))
kono
parents:
diff changeset
1160 reg_size = EPIPHANY_STACK_ALIGN (reg_size);
kono
parents:
diff changeset
1161 if (((total_size + reg_size
kono
parents:
diff changeset
1162 /* Reserve space for UNKNOWN_REGNUM. */
kono
parents:
diff changeset
1163 + EPIPHANY_STACK_ALIGN (4))
kono
parents:
diff changeset
1164 <= (unsigned) epiphany_stack_offset)
kono
parents:
diff changeset
1165 && !interrupt_p
kono
parents:
diff changeset
1166 && crtl->is_leaf && !frame_pointer_needed)
kono
parents:
diff changeset
1167 {
kono
parents:
diff changeset
1168 first_slot = -1;
kono
parents:
diff changeset
1169 last_slot = -1;
kono
parents:
diff changeset
1170 goto alloc_done;
kono
parents:
diff changeset
1171 }
kono
parents:
diff changeset
1172 else if (reg_size
kono
parents:
diff changeset
1173 && !interrupt_p
kono
parents:
diff changeset
1174 && reg_size < (unsigned HOST_WIDE_INT) epiphany_stack_offset)
kono
parents:
diff changeset
1175 reg_size = epiphany_stack_offset;
kono
parents:
diff changeset
1176 if (interrupt_p)
kono
parents:
diff changeset
1177 {
kono
parents:
diff changeset
1178 if (total_size + reg_size < 0x3fc)
kono
parents:
diff changeset
1179 {
kono
parents:
diff changeset
1180 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
kono
parents:
diff changeset
1181 first_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
kono
parents:
diff changeset
1182 last_slot = -1;
kono
parents:
diff changeset
1183 }
kono
parents:
diff changeset
1184 else
kono
parents:
diff changeset
1185 {
kono
parents:
diff changeset
1186 first_slot_offset = EPIPHANY_STACK_ALIGN (reg_size);
kono
parents:
diff changeset
1187 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
kono
parents:
diff changeset
1188 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
kono
parents:
diff changeset
1189 if (last_slot >= 0)
kono
parents:
diff changeset
1190 CLEAR_HARD_REG_BIT (gmask, last_slot);
kono
parents:
diff changeset
1191 }
kono
parents:
diff changeset
1192 }
kono
parents:
diff changeset
1193 else if (total_size + reg_size < 0x1ffc && first_slot >= 0)
kono
parents:
diff changeset
1194 {
kono
parents:
diff changeset
1195 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
kono
parents:
diff changeset
1196 last_slot = -1;
kono
parents:
diff changeset
1197 }
kono
parents:
diff changeset
1198 else
kono
parents:
diff changeset
1199 {
kono
parents:
diff changeset
1200 if (total_size + reg_size <= (unsigned) epiphany_stack_offset)
kono
parents:
diff changeset
1201 {
kono
parents:
diff changeset
1202 gcc_assert (first_slot < 0);
kono
parents:
diff changeset
1203 gcc_assert (reg_size == 0 || (int) reg_size == epiphany_stack_offset);
kono
parents:
diff changeset
1204 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
kono
parents:
diff changeset
1205 }
kono
parents:
diff changeset
1206 else
kono
parents:
diff changeset
1207 {
kono
parents:
diff changeset
1208 first_slot_offset
kono
parents:
diff changeset
1209 = (reg_size
kono
parents:
diff changeset
1210 ? EPIPHANY_STACK_ALIGN (reg_size - epiphany_stack_offset) : 0);
kono
parents:
diff changeset
1211 if (!first_slot_offset)
kono
parents:
diff changeset
1212 {
kono
parents:
diff changeset
1213 if (first_slot != GPR_FP || !current_frame_info.need_fp)
kono
parents:
diff changeset
1214 last_slot = first_slot;
kono
parents:
diff changeset
1215 first_slot = -1;
kono
parents:
diff changeset
1216 }
kono
parents:
diff changeset
1217 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
kono
parents:
diff changeset
1218 if (reg_size)
kono
parents:
diff changeset
1219 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
kono
parents:
diff changeset
1220 }
kono
parents:
diff changeset
1221 if (last_slot >= 0)
kono
parents:
diff changeset
1222 CLEAR_HARD_REG_BIT (gmask, last_slot);
kono
parents:
diff changeset
1223 }
kono
parents:
diff changeset
1224 alloc_done:
kono
parents:
diff changeset
1225 if (first_slot >= 0)
kono
parents:
diff changeset
1226 {
kono
parents:
diff changeset
1227 CLEAR_HARD_REG_BIT (gmask, first_slot);
kono
parents:
diff changeset
1228 if (TEST_HARD_REG_BIT (gmask, first_slot ^ 1)
kono
parents:
diff changeset
1229 && epiphany_stack_offset - pretend_size >= 2 * UNITS_PER_WORD)
kono
parents:
diff changeset
1230 {
kono
parents:
diff changeset
1231 CLEAR_HARD_REG_BIT (gmask, first_slot ^ 1);
kono
parents:
diff changeset
1232 first_slot_size = 2 * UNITS_PER_WORD;
kono
parents:
diff changeset
1233 first_slot &= ~1;
kono
parents:
diff changeset
1234 }
kono
parents:
diff changeset
1235 }
kono
parents:
diff changeset
1236 total_size = first_slot_offset + last_slot_offset;
kono
parents:
diff changeset
1237
kono
parents:
diff changeset
1238 /* Save computed information. */
kono
parents:
diff changeset
1239 current_frame_info.total_size = total_size;
kono
parents:
diff changeset
1240 current_frame_info.pretend_size = pretend_size;
kono
parents:
diff changeset
1241 current_frame_info.var_size = var_size;
kono
parents:
diff changeset
1242 current_frame_info.args_size = args_size;
kono
parents:
diff changeset
1243 current_frame_info.reg_size = reg_size;
kono
parents:
diff changeset
1244 COPY_HARD_REG_SET (current_frame_info.gmask, gmask);
kono
parents:
diff changeset
1245 current_frame_info.first_slot = first_slot;
kono
parents:
diff changeset
1246 current_frame_info.last_slot = last_slot;
kono
parents:
diff changeset
1247 current_frame_info.first_slot_offset = first_slot_offset;
kono
parents:
diff changeset
1248 current_frame_info.first_slot_size = first_slot_size;
kono
parents:
diff changeset
1249 current_frame_info.last_slot_offset = last_slot_offset;
kono
parents:
diff changeset
1250
kono
parents:
diff changeset
1251 current_frame_info.initialized = reload_completed;
kono
parents:
diff changeset
1252
kono
parents:
diff changeset
1253 /* Ok, we're done. */
kono
parents:
diff changeset
1254 return total_size;
kono
parents:
diff changeset
1255 }
kono
parents:
diff changeset
1256
kono
parents:
diff changeset
1257 /* Print operand X (an rtx) in assembler syntax to file FILE.
kono
parents:
diff changeset
1258 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
kono
parents:
diff changeset
1259 For `%' followed by punctuation, CODE is the punctuation and X is null. */
kono
parents:
diff changeset
1260
kono
parents:
diff changeset
1261 static void
kono
parents:
diff changeset
1262 epiphany_print_operand (FILE *file, rtx x, int code)
kono
parents:
diff changeset
1263 {
kono
parents:
diff changeset
1264 switch (code)
kono
parents:
diff changeset
1265 {
kono
parents:
diff changeset
1266 case 'd':
kono
parents:
diff changeset
1267 fputs (epiphany_condition_codes[get_epiphany_condition_code (x)], file);
kono
parents:
diff changeset
1268 return;
kono
parents:
diff changeset
1269 case 'D':
kono
parents:
diff changeset
1270 fputs (epiphany_condition_codes[EPIPHANY_INVERSE_CONDITION_CODE
kono
parents:
diff changeset
1271 (get_epiphany_condition_code (x))],
kono
parents:
diff changeset
1272 file);
kono
parents:
diff changeset
1273 return;
kono
parents:
diff changeset
1274
kono
parents:
diff changeset
1275 case 'X':
kono
parents:
diff changeset
1276 current_frame_info.stld_sz = 8;
kono
parents:
diff changeset
1277 break;
kono
parents:
diff changeset
1278
kono
parents:
diff changeset
1279 case 'C' :
kono
parents:
diff changeset
1280 current_frame_info.stld_sz = 4;
kono
parents:
diff changeset
1281 break;
kono
parents:
diff changeset
1282
kono
parents:
diff changeset
1283 case 'c' :
kono
parents:
diff changeset
1284 current_frame_info.stld_sz = 2;
kono
parents:
diff changeset
1285 break;
kono
parents:
diff changeset
1286
kono
parents:
diff changeset
1287 case 'f':
kono
parents:
diff changeset
1288 fputs (REG_P (x) ? "jalr " : "bl ", file);
kono
parents:
diff changeset
1289 break;
kono
parents:
diff changeset
1290
kono
parents:
diff changeset
1291 case '-':
kono
parents:
diff changeset
1292 fprintf (file, "r%d", epiphany_m1reg);
kono
parents:
diff changeset
1293 return;
kono
parents:
diff changeset
1294
kono
parents:
diff changeset
1295 case 0 :
kono
parents:
diff changeset
1296 /* Do nothing special. */
kono
parents:
diff changeset
1297 break;
kono
parents:
diff changeset
1298 default :
kono
parents:
diff changeset
1299 /* Unknown flag. */
kono
parents:
diff changeset
1300 output_operand_lossage ("invalid operand output code");
kono
parents:
diff changeset
1301 }
kono
parents:
diff changeset
1302
kono
parents:
diff changeset
1303 switch (GET_CODE (x))
kono
parents:
diff changeset
1304 {
kono
parents:
diff changeset
1305 rtx addr;
kono
parents:
diff changeset
1306 rtx offset;
kono
parents:
diff changeset
1307
kono
parents:
diff changeset
1308 case REG :
kono
parents:
diff changeset
1309 fputs (reg_names[REGNO (x)], file);
kono
parents:
diff changeset
1310 break;
kono
parents:
diff changeset
1311 case MEM :
kono
parents:
diff changeset
1312 if (code == 0)
kono
parents:
diff changeset
1313 current_frame_info.stld_sz = 1;
kono
parents:
diff changeset
1314 fputc ('[', file);
kono
parents:
diff changeset
1315 addr = XEXP (x, 0);
kono
parents:
diff changeset
1316 switch (GET_CODE (addr))
kono
parents:
diff changeset
1317 {
kono
parents:
diff changeset
1318 case POST_INC:
kono
parents:
diff changeset
1319 offset = GEN_INT (GET_MODE_SIZE (GET_MODE (x)));
kono
parents:
diff changeset
1320 addr = XEXP (addr, 0);
kono
parents:
diff changeset
1321 break;
kono
parents:
diff changeset
1322 case POST_DEC:
kono
parents:
diff changeset
1323 offset = GEN_INT (-GET_MODE_SIZE (GET_MODE (x)));
kono
parents:
diff changeset
1324 addr = XEXP (addr, 0);
kono
parents:
diff changeset
1325 break;
kono
parents:
diff changeset
1326 case POST_MODIFY:
kono
parents:
diff changeset
1327 offset = XEXP (XEXP (addr, 1), 1);
kono
parents:
diff changeset
1328 addr = XEXP (addr, 0);
kono
parents:
diff changeset
1329 break;
kono
parents:
diff changeset
1330 default:
kono
parents:
diff changeset
1331 offset = 0;
kono
parents:
diff changeset
1332 break;
kono
parents:
diff changeset
1333 }
kono
parents:
diff changeset
1334 output_address (GET_MODE (x), addr);
kono
parents:
diff changeset
1335 fputc (']', file);
kono
parents:
diff changeset
1336 if (offset)
kono
parents:
diff changeset
1337 {
kono
parents:
diff changeset
1338 fputc (',', file);
kono
parents:
diff changeset
1339 if (CONST_INT_P (offset)) switch (GET_MODE_SIZE (GET_MODE (x)))
kono
parents:
diff changeset
1340 {
kono
parents:
diff changeset
1341 default:
kono
parents:
diff changeset
1342 gcc_unreachable ();
kono
parents:
diff changeset
1343 case 8:
kono
parents:
diff changeset
1344 offset = GEN_INT (INTVAL (offset) >> 3);
kono
parents:
diff changeset
1345 break;
kono
parents:
diff changeset
1346 case 4:
kono
parents:
diff changeset
1347 offset = GEN_INT (INTVAL (offset) >> 2);
kono
parents:
diff changeset
1348 break;
kono
parents:
diff changeset
1349 case 2:
kono
parents:
diff changeset
1350 offset = GEN_INT (INTVAL (offset) >> 1);
kono
parents:
diff changeset
1351 break;
kono
parents:
diff changeset
1352 case 1:
kono
parents:
diff changeset
1353 break;
kono
parents:
diff changeset
1354 }
kono
parents:
diff changeset
1355 output_address (GET_MODE (x), offset);
kono
parents:
diff changeset
1356 }
kono
parents:
diff changeset
1357 break;
kono
parents:
diff changeset
1358 case CONST_DOUBLE :
kono
parents:
diff changeset
1359 /* We handle SFmode constants here as output_addr_const doesn't. */
kono
parents:
diff changeset
1360 if (GET_MODE (x) == SFmode)
kono
parents:
diff changeset
1361 {
kono
parents:
diff changeset
1362 long l;
kono
parents:
diff changeset
1363
kono
parents:
diff changeset
1364 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), l);
kono
parents:
diff changeset
1365 fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l);
kono
parents:
diff changeset
1366 break;
kono
parents:
diff changeset
1367 }
kono
parents:
diff changeset
1368 /* FALLTHRU */
kono
parents:
diff changeset
1369 /* Let output_addr_const deal with it. */
kono
parents:
diff changeset
1370 case CONST_INT:
kono
parents:
diff changeset
1371 fprintf(file,"%s",IMMEDIATE_PREFIX);
kono
parents:
diff changeset
1372 if (code == 'C' || code == 'X')
kono
parents:
diff changeset
1373 {
kono
parents:
diff changeset
1374 fprintf (file, "%ld",
kono
parents:
diff changeset
1375 (long) (INTVAL (x) / current_frame_info.stld_sz));
kono
parents:
diff changeset
1376 break;
kono
parents:
diff changeset
1377 }
kono
parents:
diff changeset
1378 /* Fall through */
kono
parents:
diff changeset
1379 default :
kono
parents:
diff changeset
1380 output_addr_const (file, x);
kono
parents:
diff changeset
1381 break;
kono
parents:
diff changeset
1382 }
kono
parents:
diff changeset
1383 }
kono
parents:
diff changeset
1384
kono
parents:
diff changeset
1385 /* Print a memory address as an operand to reference that memory location. */
kono
parents:
diff changeset
1386
kono
parents:
diff changeset
1387 static void
kono
parents:
diff changeset
1388 epiphany_print_operand_address (FILE *file, machine_mode /*mode*/, rtx addr)
kono
parents:
diff changeset
1389 {
kono
parents:
diff changeset
1390 register rtx base, index = 0;
kono
parents:
diff changeset
1391 int offset = 0;
kono
parents:
diff changeset
1392
kono
parents:
diff changeset
1393 switch (GET_CODE (addr))
kono
parents:
diff changeset
1394 {
kono
parents:
diff changeset
1395 case REG :
kono
parents:
diff changeset
1396 fputs (reg_names[REGNO (addr)], file);
kono
parents:
diff changeset
1397 break;
kono
parents:
diff changeset
1398 case SYMBOL_REF :
kono
parents:
diff changeset
1399 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr))
kono
parents:
diff changeset
1400 {
kono
parents:
diff changeset
1401 output_addr_const (file, addr);
kono
parents:
diff changeset
1402 }
kono
parents:
diff changeset
1403 else
kono
parents:
diff changeset
1404 {
kono
parents:
diff changeset
1405 output_addr_const (file, addr);
kono
parents:
diff changeset
1406 }
kono
parents:
diff changeset
1407 break;
kono
parents:
diff changeset
1408 case PLUS :
kono
parents:
diff changeset
1409 if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
kono
parents:
diff changeset
1410 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
kono
parents:
diff changeset
1411 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
kono
parents:
diff changeset
1412 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
kono
parents:
diff changeset
1413 else
kono
parents:
diff changeset
1414 base = XEXP (addr, 0), index = XEXP (addr, 1);
kono
parents:
diff changeset
1415 gcc_assert (GET_CODE (base) == REG);
kono
parents:
diff changeset
1416 fputs (reg_names[REGNO (base)], file);
kono
parents:
diff changeset
1417 if (index == 0)
kono
parents:
diff changeset
1418 {
kono
parents:
diff changeset
1419 /*
kono
parents:
diff changeset
1420 ** ++rk quirky method to scale offset for ld/str.......
kono
parents:
diff changeset
1421 */
kono
parents:
diff changeset
1422 fprintf (file, ",%s%d", IMMEDIATE_PREFIX,
kono
parents:
diff changeset
1423 offset/current_frame_info.stld_sz);
kono
parents:
diff changeset
1424 }
kono
parents:
diff changeset
1425 else
kono
parents:
diff changeset
1426 {
kono
parents:
diff changeset
1427 switch (GET_CODE (index))
kono
parents:
diff changeset
1428 {
kono
parents:
diff changeset
1429 case REG:
kono
parents:
diff changeset
1430 fprintf (file, ",%s", reg_names[REGNO (index)]);
kono
parents:
diff changeset
1431 break;
kono
parents:
diff changeset
1432 case SYMBOL_REF:
kono
parents:
diff changeset
1433 fputc (',', file), output_addr_const (file, index);
kono
parents:
diff changeset
1434 break;
kono
parents:
diff changeset
1435 default:
kono
parents:
diff changeset
1436 gcc_unreachable ();
kono
parents:
diff changeset
1437 }
kono
parents:
diff changeset
1438 }
kono
parents:
diff changeset
1439 break;
kono
parents:
diff changeset
1440 case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY:
kono
parents:
diff changeset
1441 /* We shouldn't get here as we've lost the mode of the memory object
kono
parents:
diff changeset
1442 (which says how much to inc/dec by.
kono
parents:
diff changeset
1443 FIXME: We have the mode now, address printing can be moved into this
kono
parents:
diff changeset
1444 function. */
kono
parents:
diff changeset
1445 gcc_unreachable ();
kono
parents:
diff changeset
1446 break;
kono
parents:
diff changeset
1447 default:
kono
parents:
diff changeset
1448 output_addr_const (file, addr);
kono
parents:
diff changeset
1449 break;
kono
parents:
diff changeset
1450 }
kono
parents:
diff changeset
1451 }
kono
parents:
diff changeset
1452
kono
parents:
diff changeset
1453 void
kono
parents:
diff changeset
1454 epiphany_final_prescan_insn (rtx_insn *insn ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
1455 rtx *opvec ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
1456 int noperands ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1457 {
kono
parents:
diff changeset
1458 int i = epiphany_n_nops;
kono
parents:
diff changeset
1459 rtx pat ATTRIBUTE_UNUSED;
kono
parents:
diff changeset
1460
kono
parents:
diff changeset
1461 while (i--)
kono
parents:
diff changeset
1462 fputs ("\tnop\n", asm_out_file);
kono
parents:
diff changeset
1463 }
kono
parents:
diff changeset
1464
kono
parents:
diff changeset
1465
kono
parents:
diff changeset
1466 /* Worker function for TARGET_RETURN_IN_MEMORY. */
kono
parents:
diff changeset
1467
kono
parents:
diff changeset
1468 static bool
kono
parents:
diff changeset
1469 epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1470 {
kono
parents:
diff changeset
1471 HOST_WIDE_INT size = int_size_in_bytes (type);
kono
parents:
diff changeset
1472
kono
parents:
diff changeset
1473 if (AGGREGATE_TYPE_P (type)
kono
parents:
diff changeset
1474 && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
kono
parents:
diff changeset
1475 return true;
kono
parents:
diff changeset
1476 return (size == -1 || size > 8);
kono
parents:
diff changeset
1477 }
kono
parents:
diff changeset
1478
kono
parents:
diff changeset
1479 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
kono
parents:
diff changeset
1480 passed by reference. */
kono
parents:
diff changeset
1481
kono
parents:
diff changeset
1482 static bool
kono
parents:
diff changeset
1483 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
1484 machine_mode mode, const_tree type,
kono
parents:
diff changeset
1485 bool named ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1486 {
kono
parents:
diff changeset
1487 if (type)
kono
parents:
diff changeset
1488 {
kono
parents:
diff changeset
1489 if (AGGREGATE_TYPE_P (type)
kono
parents:
diff changeset
1490 && (mode == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
kono
parents:
diff changeset
1491 return true;
kono
parents:
diff changeset
1492 }
kono
parents:
diff changeset
1493 return false;
kono
parents:
diff changeset
1494 }
kono
parents:
diff changeset
1495
kono
parents:
diff changeset
1496
kono
parents:
diff changeset
1497 static rtx
kono
parents:
diff changeset
1498 epiphany_function_value (const_tree ret_type,
kono
parents:
diff changeset
1499 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
1500 bool outgoing ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1501 {
kono
parents:
diff changeset
1502 machine_mode mode;
kono
parents:
diff changeset
1503
kono
parents:
diff changeset
1504 mode = TYPE_MODE (ret_type);
kono
parents:
diff changeset
1505 /* We must change the mode like PROMOTE_MODE does.
kono
parents:
diff changeset
1506 ??? PROMOTE_MODE is ignored for non-scalar types.
kono
parents:
diff changeset
1507 The set of types tested here has to be kept in sync
kono
parents:
diff changeset
1508 with the one in explow.c:promote_mode. */
kono
parents:
diff changeset
1509 if (GET_MODE_CLASS (mode) == MODE_INT
kono
parents:
diff changeset
1510 && GET_MODE_SIZE (mode) < 4
kono
parents:
diff changeset
1511 && (TREE_CODE (ret_type) == INTEGER_TYPE
kono
parents:
diff changeset
1512 || TREE_CODE (ret_type) == ENUMERAL_TYPE
kono
parents:
diff changeset
1513 || TREE_CODE (ret_type) == BOOLEAN_TYPE
kono
parents:
diff changeset
1514 || TREE_CODE (ret_type) == OFFSET_TYPE))
kono
parents:
diff changeset
1515 mode = SImode;
kono
parents:
diff changeset
1516 return gen_rtx_REG (mode, 0);
kono
parents:
diff changeset
1517 }
kono
parents:
diff changeset
1518
kono
parents:
diff changeset
1519 static rtx
kono
parents:
diff changeset
1520 epiphany_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1521 {
kono
parents:
diff changeset
1522 return gen_rtx_REG (mode, 0);
kono
parents:
diff changeset
1523 }
kono
parents:
diff changeset
1524
kono
parents:
diff changeset
1525 static bool
kono
parents:
diff changeset
1526 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1527 {
kono
parents:
diff changeset
1528 return regno == 0;
kono
parents:
diff changeset
1529 }
kono
parents:
diff changeset
1530
kono
parents:
diff changeset
1531 /* Fix up invalid option settings. */
kono
parents:
diff changeset
1532 static void
kono
parents:
diff changeset
1533 epiphany_override_options (void)
kono
parents:
diff changeset
1534 {
kono
parents:
diff changeset
1535 if (epiphany_stack_offset < 4)
kono
parents:
diff changeset
1536 error ("stack_offset must be at least 4");
kono
parents:
diff changeset
1537 if (epiphany_stack_offset & 3)
kono
parents:
diff changeset
1538 error ("stack_offset must be a multiple of 4");
kono
parents:
diff changeset
1539 epiphany_stack_offset = (epiphany_stack_offset + 3) & -4;
kono
parents:
diff changeset
1540 if (!TARGET_SOFT_CMPSF)
kono
parents:
diff changeset
1541 flag_finite_math_only = 1;
kono
parents:
diff changeset
1542
kono
parents:
diff changeset
1543 /* This needs to be done at start up. It's convenient to do it here. */
kono
parents:
diff changeset
1544 epiphany_init ();
kono
parents:
diff changeset
1545 }
kono
parents:
diff changeset
1546
kono
parents:
diff changeset
1547 /* For a DImode load / store SET, make a SImode set for a
kono
parents:
diff changeset
1548 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart
kono
parents:
diff changeset
1549 subreg. */
kono
parents:
diff changeset
1550 static rtx
kono
parents:
diff changeset
1551 frame_subreg_note (rtx set, int offset)
kono
parents:
diff changeset
1552 {
kono
parents:
diff changeset
1553 rtx src = simplify_gen_subreg (SImode, SET_SRC (set), DImode, offset);
kono
parents:
diff changeset
1554 rtx dst = simplify_gen_subreg (SImode, SET_DEST (set), DImode, offset);
kono
parents:
diff changeset
1555
kono
parents:
diff changeset
1556 set = gen_rtx_SET (dst ,src);
kono
parents:
diff changeset
1557 RTX_FRAME_RELATED_P (set) = 1;
kono
parents:
diff changeset
1558 return set;
kono
parents:
diff changeset
1559 }
kono
parents:
diff changeset
1560
kono
parents:
diff changeset
1561 static rtx_insn *
kono
parents:
diff changeset
1562 frame_insn (rtx x)
kono
parents:
diff changeset
1563 {
kono
parents:
diff changeset
1564 int i;
kono
parents:
diff changeset
1565 rtx note = NULL_RTX;
kono
parents:
diff changeset
1566 rtx_insn *insn;
kono
parents:
diff changeset
1567
kono
parents:
diff changeset
1568 if (GET_CODE (x) == PARALLEL)
kono
parents:
diff changeset
1569 {
kono
parents:
diff changeset
1570 rtx part = XVECEXP (x, 0, 0);
kono
parents:
diff changeset
1571
kono
parents:
diff changeset
1572 if (GET_MODE (SET_DEST (part)) == DImode)
kono
parents:
diff changeset
1573 {
kono
parents:
diff changeset
1574 note = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (x, 0) + 1));
kono
parents:
diff changeset
1575 XVECEXP (note, 0, 0) = frame_subreg_note (part, 0);
kono
parents:
diff changeset
1576 XVECEXP (note, 0, 1) = frame_subreg_note (part, UNITS_PER_WORD);
kono
parents:
diff changeset
1577 for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
kono
parents:
diff changeset
1578 {
kono
parents:
diff changeset
1579 part = copy_rtx (XVECEXP (x, 0, i));
kono
parents:
diff changeset
1580
kono
parents:
diff changeset
1581 if (GET_CODE (part) == SET)
kono
parents:
diff changeset
1582 RTX_FRAME_RELATED_P (part) = 1;
kono
parents:
diff changeset
1583 XVECEXP (note, 0, i + 1) = part;
kono
parents:
diff changeset
1584 }
kono
parents:
diff changeset
1585 }
kono
parents:
diff changeset
1586 else
kono
parents:
diff changeset
1587 {
kono
parents:
diff changeset
1588 for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
kono
parents:
diff changeset
1589 {
kono
parents:
diff changeset
1590 part = XVECEXP (x, 0, i);
kono
parents:
diff changeset
1591
kono
parents:
diff changeset
1592 if (GET_CODE (part) == SET)
kono
parents:
diff changeset
1593 RTX_FRAME_RELATED_P (part) = 1;
kono
parents:
diff changeset
1594 }
kono
parents:
diff changeset
1595 }
kono
parents:
diff changeset
1596 }
kono
parents:
diff changeset
1597 else if (GET_CODE (x) == SET && GET_MODE (SET_DEST (x)) == DImode)
kono
parents:
diff changeset
1598 note = gen_rtx_PARALLEL (VOIDmode,
kono
parents:
diff changeset
1599 gen_rtvec (2, frame_subreg_note (x, 0),
kono
parents:
diff changeset
1600 frame_subreg_note (x, UNITS_PER_WORD)));
kono
parents:
diff changeset
1601 insn = emit_insn (x);
kono
parents:
diff changeset
1602 RTX_FRAME_RELATED_P (insn) = 1;
kono
parents:
diff changeset
1603 if (note)
kono
parents:
diff changeset
1604 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
kono
parents:
diff changeset
1605 return insn;
kono
parents:
diff changeset
1606 }
kono
parents:
diff changeset
1607
kono
parents:
diff changeset
1608 static rtx_insn *
kono
parents:
diff changeset
1609 frame_move_insn (rtx to, rtx from)
kono
parents:
diff changeset
1610 {
kono
parents:
diff changeset
1611 return frame_insn (gen_rtx_SET (to, from));
kono
parents:
diff changeset
1612 }
kono
parents:
diff changeset
1613
kono
parents:
diff changeset
1614 /* Generate a MEM referring to a varargs argument slot. */
kono
parents:
diff changeset
1615
kono
parents:
diff changeset
1616 static rtx
kono
parents:
diff changeset
1617 gen_varargs_mem (machine_mode mode, rtx addr)
kono
parents:
diff changeset
1618 {
kono
parents:
diff changeset
1619 rtx mem = gen_rtx_MEM (mode, addr);
kono
parents:
diff changeset
1620 MEM_NOTRAP_P (mem) = 1;
kono
parents:
diff changeset
1621 set_mem_alias_set (mem, get_varargs_alias_set ());
kono
parents:
diff changeset
1622 return mem;
kono
parents:
diff changeset
1623 }
kono
parents:
diff changeset
1624
kono
parents:
diff changeset
1625 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) .
kono
parents:
diff changeset
1626 If EPILOGUE_P is 0, save; if it is one, restore.
kono
parents:
diff changeset
1627 ADDR is the stack slot to save the first register to; subsequent
kono
parents:
diff changeset
1628 registers are written to lower addresses.
kono
parents:
diff changeset
1629 However, the order of register pairs can be reversed in order to
kono
parents:
diff changeset
1630 use double-word load-store instructions. Likewise, an unpaired single
kono
parents:
diff changeset
1631 word save slot can be skipped while double saves are carried out, and
kono
parents:
diff changeset
1632 reused when a single register is to be saved. */
kono
parents:
diff changeset
1633
kono
parents:
diff changeset
1634 static void
kono
parents:
diff changeset
1635 epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p)
kono
parents:
diff changeset
1636 {
kono
parents:
diff changeset
1637 int i;
kono
parents:
diff changeset
1638 int stack_offset
kono
parents:
diff changeset
1639 = current_frame_info.first_slot >= 0 ? epiphany_stack_offset : 0;
kono
parents:
diff changeset
1640 rtx skipped_mem = NULL_RTX;
kono
parents:
diff changeset
1641 int last_saved = limit - 1;
kono
parents:
diff changeset
1642
kono
parents:
diff changeset
1643 if (!optimize)
kono
parents:
diff changeset
1644 while (last_saved >= 0
kono
parents:
diff changeset
1645 && !TEST_HARD_REG_BIT (current_frame_info.gmask, last_saved))
kono
parents:
diff changeset
1646 last_saved--;
kono
parents:
diff changeset
1647 for (i = 0; i < limit; i++)
kono
parents:
diff changeset
1648 {
kono
parents:
diff changeset
1649 machine_mode mode = word_mode;
kono
parents:
diff changeset
1650 rtx mem, reg;
kono
parents:
diff changeset
1651 int n = i;
kono
parents:
diff changeset
1652 rtx (*gen_mem) (machine_mode, rtx) = gen_frame_mem;
kono
parents:
diff changeset
1653
kono
parents:
diff changeset
1654 /* Make sure we push the arguments in the right order. */
kono
parents:
diff changeset
1655 if (n < MAX_EPIPHANY_PARM_REGS && crtl->args.pretend_args_size)
kono
parents:
diff changeset
1656 {
kono
parents:
diff changeset
1657 n = MAX_EPIPHANY_PARM_REGS - 1 - n;
kono
parents:
diff changeset
1658 gen_mem = gen_varargs_mem;
kono
parents:
diff changeset
1659 }
kono
parents:
diff changeset
1660 if (stack_offset == current_frame_info.first_slot_size
kono
parents:
diff changeset
1661 && current_frame_info.first_slot >= 0)
kono
parents:
diff changeset
1662 {
kono
parents:
diff changeset
1663 if (current_frame_info.first_slot_size > UNITS_PER_WORD)
kono
parents:
diff changeset
1664 {
kono
parents:
diff changeset
1665 mode = DImode;
kono
parents:
diff changeset
1666 addr = plus_constant (Pmode, addr,
kono
parents:
diff changeset
1667 - (HOST_WIDE_INT) UNITS_PER_WORD);
kono
parents:
diff changeset
1668 }
kono
parents:
diff changeset
1669 if (i-- < min || !epilogue_p)
kono
parents:
diff changeset
1670 goto next_slot;
kono
parents:
diff changeset
1671 n = current_frame_info.first_slot;
kono
parents:
diff changeset
1672 gen_mem = gen_frame_mem;
kono
parents:
diff changeset
1673 }
kono
parents:
diff changeset
1674 else if (n == UNKNOWN_REGNUM
kono
parents:
diff changeset
1675 && stack_offset > current_frame_info.first_slot_size)
kono
parents:
diff changeset
1676 {
kono
parents:
diff changeset
1677 i--;
kono
parents:
diff changeset
1678 goto next_slot;
kono
parents:
diff changeset
1679 }
kono
parents:
diff changeset
1680 else if (!TEST_HARD_REG_BIT (current_frame_info.gmask, n))
kono
parents:
diff changeset
1681 continue;
kono
parents:
diff changeset
1682 else if (i < min)
kono
parents:
diff changeset
1683 goto next_slot;
kono
parents:
diff changeset
1684
kono
parents:
diff changeset
1685 /* Check for a register pair to save. */
kono
parents:
diff changeset
1686 if (n == i
kono
parents:
diff changeset
1687 && (n >= MAX_EPIPHANY_PARM_REGS || crtl->args.pretend_args_size == 0)
kono
parents:
diff changeset
1688 && (n & 1) == 0 && n+1 < limit
kono
parents:
diff changeset
1689 && TEST_HARD_REG_BIT (current_frame_info.gmask, n+1))
kono
parents:
diff changeset
1690 {
kono
parents:
diff changeset
1691 /* If it fits in the current stack slot pair, place it there. */
kono
parents:
diff changeset
1692 if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 0
kono
parents:
diff changeset
1693 && stack_offset != 2 * UNITS_PER_WORD
kono
parents:
diff changeset
1694 && (current_frame_info.last_slot < 0
kono
parents:
diff changeset
1695 || INTVAL (XEXP (addr, 1)) != UNITS_PER_WORD)
kono
parents:
diff changeset
1696 && (n+1 != last_saved || !skipped_mem))
kono
parents:
diff changeset
1697 {
kono
parents:
diff changeset
1698 mode = DImode;
kono
parents:
diff changeset
1699 i++;
kono
parents:
diff changeset
1700 addr = plus_constant (Pmode, addr,
kono
parents:
diff changeset
1701 - (HOST_WIDE_INT) UNITS_PER_WORD);
kono
parents:
diff changeset
1702 }
kono
parents:
diff changeset
1703 /* If it fits in the following stack slot pair, that's fine, too. */
kono
parents:
diff changeset
1704 else if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 4
kono
parents:
diff changeset
1705 && stack_offset != 2 * UNITS_PER_WORD
kono
parents:
diff changeset
1706 && stack_offset != 3 * UNITS_PER_WORD
kono
parents:
diff changeset
1707 && (current_frame_info.last_slot < 0
kono
parents:
diff changeset
1708 || INTVAL (XEXP (addr, 1)) != 2 * UNITS_PER_WORD)
kono
parents:
diff changeset
1709 && n + 1 != last_saved)
kono
parents:
diff changeset
1710 {
kono
parents:
diff changeset
1711 gcc_assert (!skipped_mem);
kono
parents:
diff changeset
1712 stack_offset -= GET_MODE_SIZE (mode);
kono
parents:
diff changeset
1713 skipped_mem = gen_mem (mode, addr);
kono
parents:
diff changeset
1714 mode = DImode;
kono
parents:
diff changeset
1715 i++;
kono
parents:
diff changeset
1716 addr = plus_constant (Pmode, addr,
kono
parents:
diff changeset
1717 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
kono
parents:
diff changeset
1718 }
kono
parents:
diff changeset
1719 }
kono
parents:
diff changeset
1720 reg = gen_rtx_REG (mode, n);
kono
parents:
diff changeset
1721 if (mode != DImode && skipped_mem)
kono
parents:
diff changeset
1722 mem = skipped_mem;
kono
parents:
diff changeset
1723 else
kono
parents:
diff changeset
1724 mem = gen_mem (mode, addr);
kono
parents:
diff changeset
1725
kono
parents:
diff changeset
1726 /* If we are loading / storing LR, note the offset that
kono
parents:
diff changeset
1727 gen_reload_insi_ra requires. Since GPR_LR is even,
kono
parents:
diff changeset
1728 we only need to test n, even if mode is DImode. */
kono
parents:
diff changeset
1729 gcc_assert ((GPR_LR & 1) == 0);
kono
parents:
diff changeset
1730 if (n == GPR_LR)
kono
parents:
diff changeset
1731 {
kono
parents:
diff changeset
1732 long lr_slot_offset = 0;
kono
parents:
diff changeset
1733 rtx m_addr = XEXP (mem, 0);
kono
parents:
diff changeset
1734
kono
parents:
diff changeset
1735 if (GET_CODE (m_addr) == PLUS)
kono
parents:
diff changeset
1736 lr_slot_offset = INTVAL (XEXP (m_addr, 1));
kono
parents:
diff changeset
1737 if (frame_pointer_needed)
kono
parents:
diff changeset
1738 lr_slot_offset += (current_frame_info.first_slot_offset
kono
parents:
diff changeset
1739 - current_frame_info.total_size);
kono
parents:
diff changeset
1740 if (MACHINE_FUNCTION (cfun)->lr_slot_known)
kono
parents:
diff changeset
1741 gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_offset
kono
parents:
diff changeset
1742 == lr_slot_offset);
kono
parents:
diff changeset
1743 MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset;
kono
parents:
diff changeset
1744 MACHINE_FUNCTION (cfun)->lr_slot_known = 1;
kono
parents:
diff changeset
1745 }
kono
parents:
diff changeset
1746
kono
parents:
diff changeset
1747 if (!epilogue_p)
kono
parents:
diff changeset
1748 frame_move_insn (mem, reg);
kono
parents:
diff changeset
1749 else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size)
kono
parents:
diff changeset
1750 emit_move_insn (reg, mem);
kono
parents:
diff changeset
1751 if (mem == skipped_mem)
kono
parents:
diff changeset
1752 {
kono
parents:
diff changeset
1753 skipped_mem = NULL_RTX;
kono
parents:
diff changeset
1754 continue;
kono
parents:
diff changeset
1755 }
kono
parents:
diff changeset
1756 next_slot:
kono
parents:
diff changeset
1757 addr = plus_constant (Pmode, addr, -(HOST_WIDE_INT) UNITS_PER_WORD);
kono
parents:
diff changeset
1758 stack_offset -= GET_MODE_SIZE (mode);
kono
parents:
diff changeset
1759 }
kono
parents:
diff changeset
1760 }
kono
parents:
diff changeset
1761
kono
parents:
diff changeset
1762 void
kono
parents:
diff changeset
1763 epiphany_expand_prologue (void)
kono
parents:
diff changeset
1764 {
kono
parents:
diff changeset
1765 int interrupt_p;
kono
parents:
diff changeset
1766 enum epiphany_function_type fn_type;
kono
parents:
diff changeset
1767 rtx addr, mem, off, reg;
kono
parents:
diff changeset
1768
kono
parents:
diff changeset
1769 if (!current_frame_info.initialized)
kono
parents:
diff changeset
1770 epiphany_compute_frame_size (get_frame_size ());
kono
parents:
diff changeset
1771
kono
parents:
diff changeset
1772 /* It is debatable if we should adjust this by epiphany_stack_offset. */
kono
parents:
diff changeset
1773 if (flag_stack_usage_info)
kono
parents:
diff changeset
1774 current_function_static_stack_size = current_frame_info.total_size;
kono
parents:
diff changeset
1775
kono
parents:
diff changeset
1776 fn_type = epiphany_compute_function_type (current_function_decl);
kono
parents:
diff changeset
1777 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
kono
parents:
diff changeset
1778
kono
parents:
diff changeset
1779 if (interrupt_p)
kono
parents:
diff changeset
1780 {
kono
parents:
diff changeset
1781 addr = plus_constant (Pmode, stack_pointer_rtx,
kono
parents:
diff changeset
1782 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
kono
parents:
diff changeset
1783 if (!lookup_attribute ("forwarder_section",
kono
parents:
diff changeset
1784 DECL_ATTRIBUTES (current_function_decl))
kono
parents:
diff changeset
1785 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl),
kono
parents:
diff changeset
1786 0)))
kono
parents:
diff changeset
1787 frame_move_insn (gen_frame_mem (DImode, addr),
kono
parents:
diff changeset
1788 gen_rtx_REG (DImode, GPR_0));
kono
parents:
diff changeset
1789 frame_move_insn (gen_rtx_REG (SImode, GPR_0),
kono
parents:
diff changeset
1790 gen_rtx_REG (word_mode, STATUS_REGNUM));
kono
parents:
diff changeset
1791 frame_move_insn (gen_rtx_REG (SImode, GPR_1),
kono
parents:
diff changeset
1792 gen_rtx_REG (word_mode, IRET_REGNUM));
kono
parents:
diff changeset
1793 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
kono
parents:
diff changeset
1794 off = GEN_INT (-current_frame_info.first_slot_offset);
kono
parents:
diff changeset
1795 frame_insn (gen_stack_adjust_add (off, mem));
kono
parents:
diff changeset
1796 if (!epiphany_uninterruptible_p (current_function_decl))
kono
parents:
diff changeset
1797 emit_insn (gen_gie ());
kono
parents:
diff changeset
1798 addr = plus_constant (Pmode, stack_pointer_rtx,
kono
parents:
diff changeset
1799 current_frame_info.first_slot_offset
kono
parents:
diff changeset
1800 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD);
kono
parents:
diff changeset
1801 }
kono
parents:
diff changeset
1802 else
kono
parents:
diff changeset
1803 {
kono
parents:
diff changeset
1804 addr = plus_constant (Pmode, stack_pointer_rtx,
kono
parents:
diff changeset
1805 epiphany_stack_offset
kono
parents:
diff changeset
1806 - (HOST_WIDE_INT) UNITS_PER_WORD);
kono
parents:
diff changeset
1807 epiphany_emit_save_restore (0, current_frame_info.small_threshold,
kono
parents:
diff changeset
1808 addr, 0);
kono
parents:
diff changeset
1809 /* Allocate register save area; for small to medium size frames,
kono
parents:
diff changeset
1810 allocate the entire frame; this is joint with one register save. */
kono
parents:
diff changeset
1811 if (current_frame_info.first_slot >= 0)
kono
parents:
diff changeset
1812 {
kono
parents:
diff changeset
1813 machine_mode mode
kono
parents:
diff changeset
1814 = (current_frame_info.first_slot_size == UNITS_PER_WORD
kono
parents:
diff changeset
1815 ? word_mode : DImode);
kono
parents:
diff changeset
1816
kono
parents:
diff changeset
1817 off = GEN_INT (-current_frame_info.first_slot_offset);
kono
parents:
diff changeset
1818 mem = gen_frame_mem (BLKmode,
kono
parents:
diff changeset
1819 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
kono
parents:
diff changeset
1820 frame_insn (gen_stack_adjust_str
kono
parents:
diff changeset
1821 (gen_frame_mem (mode, stack_pointer_rtx),
kono
parents:
diff changeset
1822 gen_rtx_REG (mode, current_frame_info.first_slot),
kono
parents:
diff changeset
1823 off, mem));
kono
parents:
diff changeset
1824 addr = plus_constant (Pmode, addr,
kono
parents:
diff changeset
1825 current_frame_info.first_slot_offset);
kono
parents:
diff changeset
1826 }
kono
parents:
diff changeset
1827 }
kono
parents:
diff changeset
1828 epiphany_emit_save_restore (current_frame_info.small_threshold,
kono
parents:
diff changeset
1829 FIRST_PSEUDO_REGISTER, addr, 0);
kono
parents:
diff changeset
1830 if (current_frame_info.need_fp)
kono
parents:
diff changeset
1831 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
kono
parents:
diff changeset
1832 /* For large frames, allocate bulk of frame. This is usually joint with one
kono
parents:
diff changeset
1833 register save. */
kono
parents:
diff changeset
1834 if (current_frame_info.last_slot >= 0)
kono
parents:
diff changeset
1835 {
kono
parents:
diff changeset
1836 rtx ip, mem2, note;
kono
parents:
diff changeset
1837 rtx_insn *insn;
kono
parents:
diff changeset
1838
kono
parents:
diff changeset
1839 gcc_assert (current_frame_info.last_slot != GPR_FP
kono
parents:
diff changeset
1840 || (!current_frame_info.need_fp
kono
parents:
diff changeset
1841 && current_frame_info.first_slot < 0));
kono
parents:
diff changeset
1842 off = GEN_INT (-current_frame_info.last_slot_offset);
kono
parents:
diff changeset
1843 mem = gen_frame_mem (BLKmode,
kono
parents:
diff changeset
1844 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
kono
parents:
diff changeset
1845 ip = gen_rtx_REG (Pmode, GPR_IP);
kono
parents:
diff changeset
1846 frame_move_insn (ip, off);
kono
parents:
diff changeset
1847 reg = gen_rtx_REG (word_mode, current_frame_info.last_slot),
kono
parents:
diff changeset
1848 mem2 = gen_frame_mem (word_mode, stack_pointer_rtx),
kono
parents:
diff changeset
1849 insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem));
kono
parents:
diff changeset
1850 /* Instruction scheduling can separate the instruction setting IP from
kono
parents:
diff changeset
1851 INSN so that dwarf2out_frame_debug_expr becomes confused what the
kono
parents:
diff changeset
1852 temporary register is. Example: _gcov.o */
kono
parents:
diff changeset
1853 note = gen_rtx_SET (stack_pointer_rtx,
kono
parents:
diff changeset
1854 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
kono
parents:
diff changeset
1855 note = gen_rtx_PARALLEL (VOIDmode,
kono
parents:
diff changeset
1856 gen_rtvec (2, gen_rtx_SET (mem2, reg), note));
kono
parents:
diff changeset
1857 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
kono
parents:
diff changeset
1858 }
kono
parents:
diff changeset
1859 /* If there is only one or no register to save, yet we have a large frame,
kono
parents:
diff changeset
1860 use an add. */
kono
parents:
diff changeset
1861 else if (current_frame_info.last_slot_offset)
kono
parents:
diff changeset
1862 {
kono
parents:
diff changeset
1863 mem = gen_frame_mem (BLKmode,
kono
parents:
diff changeset
1864 plus_constant (Pmode, stack_pointer_rtx,
kono
parents:
diff changeset
1865 current_frame_info.last_slot_offset));
kono
parents:
diff changeset
1866 off = GEN_INT (-current_frame_info.last_slot_offset);
kono
parents:
diff changeset
1867 if (!SIMM11 (INTVAL (off)))
kono
parents:
diff changeset
1868 {
kono
parents:
diff changeset
1869 reg = gen_rtx_REG (Pmode, GPR_IP);
kono
parents:
diff changeset
1870 frame_move_insn (reg, off);
kono
parents:
diff changeset
1871 off = reg;
kono
parents:
diff changeset
1872 }
kono
parents:
diff changeset
1873 frame_insn (gen_stack_adjust_add (off, mem));
kono
parents:
diff changeset
1874 }
kono
parents:
diff changeset
1875 }
kono
parents:
diff changeset
1876
kono
parents:
diff changeset
1877 void
kono
parents:
diff changeset
1878 epiphany_expand_epilogue (int sibcall_p)
kono
parents:
diff changeset
1879 {
kono
parents:
diff changeset
1880 int interrupt_p;
kono
parents:
diff changeset
1881 enum epiphany_function_type fn_type;
kono
parents:
diff changeset
1882 rtx mem, addr, reg, off;
kono
parents:
diff changeset
1883 HOST_WIDE_INT restore_offset;
kono
parents:
diff changeset
1884
kono
parents:
diff changeset
1885 fn_type = epiphany_compute_function_type( current_function_decl);
kono
parents:
diff changeset
1886 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
kono
parents:
diff changeset
1887
kono
parents:
diff changeset
1888 /* For variable frames, deallocate bulk of frame. */
kono
parents:
diff changeset
1889 if (current_frame_info.need_fp)
kono
parents:
diff changeset
1890 {
kono
parents:
diff changeset
1891 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
kono
parents:
diff changeset
1892 emit_insn (gen_stack_adjust_mov (mem));
kono
parents:
diff changeset
1893 }
kono
parents:
diff changeset
1894 /* Else for large static frames, deallocate bulk of frame. */
kono
parents:
diff changeset
1895 else if (current_frame_info.last_slot_offset)
kono
parents:
diff changeset
1896 {
kono
parents:
diff changeset
1897 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
kono
parents:
diff changeset
1898 reg = gen_rtx_REG (Pmode, GPR_IP);
kono
parents:
diff changeset
1899 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset));
kono
parents:
diff changeset
1900 emit_insn (gen_stack_adjust_add (reg, mem));
kono
parents:
diff changeset
1901 }
kono
parents:
diff changeset
1902 restore_offset = (interrupt_p
kono
parents:
diff changeset
1903 ? - 3 * UNITS_PER_WORD
kono
parents:
diff changeset
1904 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
kono
parents:
diff changeset
1905 addr = plus_constant (Pmode, stack_pointer_rtx,
kono
parents:
diff changeset
1906 (current_frame_info.first_slot_offset
kono
parents:
diff changeset
1907 + restore_offset));
kono
parents:
diff changeset
1908 epiphany_emit_save_restore (current_frame_info.small_threshold,
kono
parents:
diff changeset
1909 FIRST_PSEUDO_REGISTER, addr, 1);
kono
parents:
diff changeset
1910
kono
parents:
diff changeset
1911 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl))
kono
parents:
diff changeset
1912 emit_insn (gen_gid ());
kono
parents:
diff changeset
1913
kono
parents:
diff changeset
1914 off = GEN_INT (current_frame_info.first_slot_offset);
kono
parents:
diff changeset
1915 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
kono
parents:
diff changeset
1916 /* For large / variable size frames, deallocating the register save area is
kono
parents:
diff changeset
1917 joint with one register restore; for medium size frames, we use a
kono
parents:
diff changeset
1918 dummy post-increment load to dealloacte the whole frame. */
kono
parents:
diff changeset
1919 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0)
kono
parents:
diff changeset
1920 {
kono
parents:
diff changeset
1921 emit_insn (gen_stack_adjust_ldr
kono
parents:
diff changeset
1922 (gen_rtx_REG (word_mode,
kono
parents:
diff changeset
1923 (current_frame_info.last_slot >= 0
kono
parents:
diff changeset
1924 ? current_frame_info.last_slot : GPR_IP)),
kono
parents:
diff changeset
1925 gen_frame_mem (word_mode, stack_pointer_rtx),
kono
parents:
diff changeset
1926 off,
kono
parents:
diff changeset
1927 mem));
kono
parents:
diff changeset
1928 }
kono
parents:
diff changeset
1929 /* While for small frames, we deallocate the entire frame with one add. */
kono
parents:
diff changeset
1930 else if (INTVAL (off))
kono
parents:
diff changeset
1931 {
kono
parents:
diff changeset
1932 emit_insn (gen_stack_adjust_add (off, mem));
kono
parents:
diff changeset
1933 }
kono
parents:
diff changeset
1934 if (interrupt_p)
kono
parents:
diff changeset
1935 {
kono
parents:
diff changeset
1936 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM),
kono
parents:
diff changeset
1937 gen_rtx_REG (SImode, GPR_0));
kono
parents:
diff changeset
1938 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM),
kono
parents:
diff changeset
1939 gen_rtx_REG (SImode, GPR_1));
kono
parents:
diff changeset
1940 addr = plus_constant (Pmode, stack_pointer_rtx,
kono
parents:
diff changeset
1941 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
kono
parents:
diff changeset
1942 emit_move_insn (gen_rtx_REG (DImode, GPR_0),
kono
parents:
diff changeset
1943 gen_frame_mem (DImode, addr));
kono
parents:
diff changeset
1944 }
kono
parents:
diff changeset
1945 addr = plus_constant (Pmode, stack_pointer_rtx,
kono
parents:
diff changeset
1946 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
kono
parents:
diff changeset
1947 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1);
kono
parents:
diff changeset
1948 if (!sibcall_p)
kono
parents:
diff changeset
1949 {
kono
parents:
diff changeset
1950 if (interrupt_p)
kono
parents:
diff changeset
1951 emit_jump_insn (gen_return_internal_interrupt());
kono
parents:
diff changeset
1952 else
kono
parents:
diff changeset
1953 emit_jump_insn (gen_return_i ());
kono
parents:
diff changeset
1954 }
kono
parents:
diff changeset
1955 }
kono
parents:
diff changeset
1956
kono
parents:
diff changeset
1957 int
kono
parents:
diff changeset
1958 epiphany_initial_elimination_offset (int from, int to)
kono
parents:
diff changeset
1959 {
kono
parents:
diff changeset
1960 epiphany_compute_frame_size (get_frame_size ());
kono
parents:
diff changeset
1961 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
kono
parents:
diff changeset
1962 return current_frame_info.total_size - current_frame_info.reg_size;
kono
parents:
diff changeset
1963 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
kono
parents:
diff changeset
1964 return current_frame_info.first_slot_offset - current_frame_info.reg_size;
kono
parents:
diff changeset
1965 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
kono
parents:
diff changeset
1966 return (current_frame_info.total_size
kono
parents:
diff changeset
1967 - ((current_frame_info.pretend_size + 4) & -8));
kono
parents:
diff changeset
1968 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
kono
parents:
diff changeset
1969 return (current_frame_info.first_slot_offset
kono
parents:
diff changeset
1970 - ((current_frame_info.pretend_size + 4) & -8));
kono
parents:
diff changeset
1971 gcc_unreachable ();
kono
parents:
diff changeset
1972 }
kono
parents:
diff changeset
1973
kono
parents:
diff changeset
1974 bool
kono
parents:
diff changeset
1975 epiphany_regno_rename_ok (unsigned, unsigned dst)
kono
parents:
diff changeset
1976 {
kono
parents:
diff changeset
1977 enum epiphany_function_type fn_type;
kono
parents:
diff changeset
1978
kono
parents:
diff changeset
1979 fn_type = epiphany_compute_function_type (current_function_decl);
kono
parents:
diff changeset
1980 if (!EPIPHANY_INTERRUPT_P (fn_type))
kono
parents:
diff changeset
1981 return true;
kono
parents:
diff changeset
1982 if (df_regs_ever_live_p (dst))
kono
parents:
diff changeset
1983 return true;
kono
parents:
diff changeset
1984 return false;
kono
parents:
diff changeset
1985 }
kono
parents:
diff changeset
1986
kono
parents:
diff changeset
1987 static int
kono
parents:
diff changeset
1988 epiphany_issue_rate (void)
kono
parents:
diff changeset
1989 {
kono
parents:
diff changeset
1990 return 2;
kono
parents:
diff changeset
1991 }
kono
parents:
diff changeset
1992
kono
parents:
diff changeset
1993 /* Function to update the integer COST
kono
parents:
diff changeset
1994 based on the relationship between INSN that is dependent on
kono
parents:
diff changeset
1995 DEP_INSN through the dependence LINK. The default is to make no
kono
parents:
diff changeset
1996 adjustment to COST. This can be used for example to specify to
kono
parents:
diff changeset
1997 the scheduler that an output- or anti-dependence does not incur
kono
parents:
diff changeset
1998 the same cost as a data-dependence. The return value should be
kono
parents:
diff changeset
1999 the new value for COST. */
kono
parents:
diff changeset
2000 static int
kono
parents:
diff changeset
2001 epiphany_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn,
kono
parents:
diff changeset
2002 int cost, unsigned int)
kono
parents:
diff changeset
2003 {
kono
parents:
diff changeset
2004 if (dep_type == 0)
kono
parents:
diff changeset
2005 {
kono
parents:
diff changeset
2006 rtx dep_set;
kono
parents:
diff changeset
2007
kono
parents:
diff changeset
2008 if (recog_memoized (insn) < 0
kono
parents:
diff changeset
2009 || recog_memoized (dep_insn) < 0)
kono
parents:
diff changeset
2010 return cost;
kono
parents:
diff changeset
2011
kono
parents:
diff changeset
2012 dep_set = single_set (dep_insn);
kono
parents:
diff changeset
2013
kono
parents:
diff changeset
2014 /* The latency that we specify in the scheduling description refers
kono
parents:
diff changeset
2015 to the actual output, not to an auto-increment register; for that,
kono
parents:
diff changeset
2016 the latency is one. */
kono
parents:
diff changeset
2017 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1)
kono
parents:
diff changeset
2018 {
kono
parents:
diff changeset
2019 rtx set = single_set (insn);
kono
parents:
diff changeset
2020
kono
parents:
diff changeset
2021 if (set
kono
parents:
diff changeset
2022 && !reg_overlap_mentioned_p (SET_DEST (dep_set), SET_SRC (set))
kono
parents:
diff changeset
2023 && (!MEM_P (SET_DEST (set))
kono
parents:
diff changeset
2024 || !reg_overlap_mentioned_p (SET_DEST (dep_set),
kono
parents:
diff changeset
2025 XEXP (SET_DEST (set), 0))))
kono
parents:
diff changeset
2026 cost = 1;
kono
parents:
diff changeset
2027 }
kono
parents:
diff changeset
2028 }
kono
parents:
diff changeset
2029 return cost;
kono
parents:
diff changeset
2030 }
kono
parents:
diff changeset
2031
kono
parents:
diff changeset
2032 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
kono
parents:
diff changeset
2033
kono
parents:
diff changeset
2034 #define RTX_OK_FOR_BASE_P(X) \
kono
parents:
diff changeset
2035 (REG_P (X) && REG_OK_FOR_BASE_P (X))
kono
parents:
diff changeset
2036
kono
parents:
diff changeset
2037 #define RTX_OK_FOR_INDEX_P(MODE, X) \
kono
parents:
diff changeset
2038 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
kono
parents:
diff changeset
2039 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
kono
parents:
diff changeset
2040 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
kono
parents:
diff changeset
2041
kono
parents:
diff changeset
2042 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
kono
parents:
diff changeset
2043 (GET_CODE (X) == PLUS \
kono
parents:
diff changeset
2044 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
kono
parents:
diff changeset
2045 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
kono
parents:
diff changeset
2046 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
kono
parents:
diff changeset
2047
kono
parents:
diff changeset
2048 static bool
kono
parents:
diff changeset
2049 epiphany_legitimate_address_p (machine_mode mode, rtx x, bool strict)
kono
parents:
diff changeset
2050 {
kono
parents:
diff changeset
2051 #define REG_OK_FOR_BASE_P(X) \
kono
parents:
diff changeset
2052 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
kono
parents:
diff changeset
2053 if (RTX_OK_FOR_BASE_P (x))
kono
parents:
diff changeset
2054 return true;
kono
parents:
diff changeset
2055 if (RTX_FRAME_OFFSET_P (x))
kono
parents:
diff changeset
2056 return true;
kono
parents:
diff changeset
2057 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x))
kono
parents:
diff changeset
2058 return true;
kono
parents:
diff changeset
2059 /* If this is a misaligned stack access, don't force it to reg+index. */
kono
parents:
diff changeset
2060 if (GET_MODE_SIZE (mode) == 8
kono
parents:
diff changeset
2061 && GET_CODE (x) == PLUS && XEXP (x, 0) == stack_pointer_rtx
kono
parents:
diff changeset
2062 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */
kono
parents:
diff changeset
2063 && !(INTVAL (XEXP (x, 1)) & 3)
kono
parents:
diff changeset
2064 && INTVAL (XEXP (x, 1)) >= -2047 * 4
kono
parents:
diff changeset
2065 && INTVAL (XEXP (x, 1)) <= 2046 * 4)
kono
parents:
diff changeset
2066 return true;
kono
parents:
diff changeset
2067 if (TARGET_POST_INC
kono
parents:
diff changeset
2068 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC)
kono
parents:
diff changeset
2069 && RTX_OK_FOR_BASE_P (XEXP ((x), 0)))
kono
parents:
diff changeset
2070 return true;
kono
parents:
diff changeset
2071 if ((TARGET_POST_MODIFY || reload_completed)
kono
parents:
diff changeset
2072 && GET_CODE (x) == POST_MODIFY
kono
parents:
diff changeset
2073 && GET_CODE (XEXP ((x), 1)) == PLUS
kono
parents:
diff changeset
2074 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0))
kono
parents:
diff changeset
2075 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1)))
kono
parents:
diff changeset
2076 return true;
kono
parents:
diff changeset
2077 if (mode == BLKmode)
kono
parents:
diff changeset
2078 return epiphany_legitimate_address_p (SImode, x, strict);
kono
parents:
diff changeset
2079 return false;
kono
parents:
diff changeset
2080 }
kono
parents:
diff changeset
2081
kono
parents:
diff changeset
2082 static reg_class_t
kono
parents:
diff changeset
2083 epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass,
kono
parents:
diff changeset
2084 machine_mode mode ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2085 secondary_reload_info *sri)
kono
parents:
diff changeset
2086 {
kono
parents:
diff changeset
2087 /* This could give more reload inheritance, but we are missing some
kono
parents:
diff changeset
2088 reload infrastructure. */
kono
parents:
diff changeset
2089 if (0)
kono
parents:
diff changeset
2090 if (in_p && GET_CODE (x) == UNSPEC
kono
parents:
diff changeset
2091 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x))
kono
parents:
diff changeset
2092 {
kono
parents:
diff changeset
2093 gcc_assert (rclass == GENERAL_REGS);
kono
parents:
diff changeset
2094 sri->icode = CODE_FOR_reload_insi_ra;
kono
parents:
diff changeset
2095 return NO_REGS;
kono
parents:
diff changeset
2096 }
kono
parents:
diff changeset
2097 return NO_REGS;
kono
parents:
diff changeset
2098 }
kono
parents:
diff changeset
2099
kono
parents:
diff changeset
2100 bool
kono
parents:
diff changeset
2101 epiphany_is_long_call_p (rtx x)
kono
parents:
diff changeset
2102 {
kono
parents:
diff changeset
2103 tree decl = SYMBOL_REF_DECL (x);
kono
parents:
diff changeset
2104 bool ret_val = !TARGET_SHORT_CALLS;
kono
parents:
diff changeset
2105 tree attrs;
kono
parents:
diff changeset
2106
kono
parents:
diff changeset
2107 /* ??? Is it safe to default to ret_val if decl is NULL? We should
kono
parents:
diff changeset
2108 probably encode information via encode_section_info, and also
kono
parents:
diff changeset
2109 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
kono
parents:
diff changeset
2110 into account. */
kono
parents:
diff changeset
2111 if (decl)
kono
parents:
diff changeset
2112 {
kono
parents:
diff changeset
2113 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
kono
parents:
diff changeset
2114 if (lookup_attribute ("long_call", attrs))
kono
parents:
diff changeset
2115 ret_val = true;
kono
parents:
diff changeset
2116 else if (lookup_attribute ("short_call", attrs))
kono
parents:
diff changeset
2117 ret_val = false;
kono
parents:
diff changeset
2118 }
kono
parents:
diff changeset
2119 return ret_val;
kono
parents:
diff changeset
2120 }
kono
parents:
diff changeset
2121
kono
parents:
diff changeset
2122 bool
kono
parents:
diff changeset
2123 epiphany_small16 (rtx x)
kono
parents:
diff changeset
2124 {
kono
parents:
diff changeset
2125 rtx base = x;
kono
parents:
diff changeset
2126 rtx offs ATTRIBUTE_UNUSED = const0_rtx;
kono
parents:
diff changeset
2127
kono
parents:
diff changeset
2128 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
kono
parents:
diff changeset
2129 {
kono
parents:
diff changeset
2130 base = XEXP (XEXP (x, 0), 0);
kono
parents:
diff changeset
2131 offs = XEXP (XEXP (x, 0), 1);
kono
parents:
diff changeset
2132 }
kono
parents:
diff changeset
2133 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base)
kono
parents:
diff changeset
2134 && epiphany_is_long_call_p (base))
kono
parents:
diff changeset
2135 return false;
kono
parents:
diff changeset
2136 return TARGET_SMALL16 != 0;
kono
parents:
diff changeset
2137 }
kono
parents:
diff changeset
2138
kono
parents:
diff changeset
2139 /* Return nonzero if it is ok to make a tail-call to DECL. */
kono
parents:
diff changeset
2140 static bool
kono
parents:
diff changeset
2141 epiphany_function_ok_for_sibcall (tree decl, tree exp)
kono
parents:
diff changeset
2142 {
kono
parents:
diff changeset
2143 bool cfun_interrupt_p, call_interrupt_p;
kono
parents:
diff changeset
2144
kono
parents:
diff changeset
2145 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
kono
parents:
diff changeset
2146 (current_function_decl));
kono
parents:
diff changeset
2147 if (decl)
kono
parents:
diff changeset
2148 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl));
kono
parents:
diff changeset
2149 else
kono
parents:
diff changeset
2150 {
kono
parents:
diff changeset
2151 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp));
kono
parents:
diff changeset
2152
kono
parents:
diff changeset
2153 gcc_assert (POINTER_TYPE_P (fn_type));
kono
parents:
diff changeset
2154 fn_type = TREE_TYPE (fn_type);
kono
parents:
diff changeset
2155 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE
kono
parents:
diff changeset
2156 || TREE_CODE (fn_type) == METHOD_TYPE);
kono
parents:
diff changeset
2157 call_interrupt_p
kono
parents:
diff changeset
2158 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL;
kono
parents:
diff changeset
2159 }
kono
parents:
diff changeset
2160
kono
parents:
diff changeset
2161 /* Don't tailcall from or to an ISR routine - although we could in
kono
parents:
diff changeset
2162 principle tailcall from one ISR routine to another, we'd need to
kono
parents:
diff changeset
2163 handle this in sibcall_epilogue to make it work. */
kono
parents:
diff changeset
2164 if (cfun_interrupt_p || call_interrupt_p)
kono
parents:
diff changeset
2165 return false;
kono
parents:
diff changeset
2166
kono
parents:
diff changeset
2167 /* Everything else is ok. */
kono
parents:
diff changeset
2168 return true;
kono
parents:
diff changeset
2169 }
kono
parents:
diff changeset
2170
kono
parents:
diff changeset
2171 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call
kono
parents:
diff changeset
2172 expander.
kono
parents:
diff changeset
2173 Return true iff the type of T has the uninterruptible attribute.
kono
parents:
diff changeset
2174 If T is NULL, return false. */
kono
parents:
diff changeset
2175 bool
kono
parents:
diff changeset
2176 epiphany_uninterruptible_p (tree t)
kono
parents:
diff changeset
2177 {
kono
parents:
diff changeset
2178 tree attrs;
kono
parents:
diff changeset
2179
kono
parents:
diff changeset
2180 if (t)
kono
parents:
diff changeset
2181 {
kono
parents:
diff changeset
2182 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t));
kono
parents:
diff changeset
2183 if (lookup_attribute ("disinterrupt", attrs))
kono
parents:
diff changeset
2184 return true;
kono
parents:
diff changeset
2185 }
kono
parents:
diff changeset
2186 return false;
kono
parents:
diff changeset
2187 }
kono
parents:
diff changeset
2188
kono
parents:
diff changeset
2189 bool
kono
parents:
diff changeset
2190 epiphany_call_uninterruptible_p (rtx mem)
kono
parents:
diff changeset
2191 {
kono
parents:
diff changeset
2192 rtx addr = XEXP (mem, 0);
kono
parents:
diff changeset
2193 tree t = NULL_TREE;
kono
parents:
diff changeset
2194
kono
parents:
diff changeset
2195 if (GET_CODE (addr) == SYMBOL_REF)
kono
parents:
diff changeset
2196 t = SYMBOL_REF_DECL (addr);
kono
parents:
diff changeset
2197 if (!t)
kono
parents:
diff changeset
2198 t = MEM_EXPR (mem);
kono
parents:
diff changeset
2199 return epiphany_uninterruptible_p (t);
kono
parents:
diff changeset
2200 }
kono
parents:
diff changeset
2201
kono
parents:
diff changeset
2202 static machine_mode
kono
parents:
diff changeset
2203 epiphany_promote_function_mode (const_tree type, machine_mode mode,
kono
parents:
diff changeset
2204 int *punsignedp ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2205 const_tree funtype ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2206 int for_return ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
2207 {
kono
parents:
diff changeset
2208 int dummy;
kono
parents:
diff changeset
2209
kono
parents:
diff changeset
2210 return promote_mode (type, mode, &dummy);
kono
parents:
diff changeset
2211 }
kono
parents:
diff changeset
2212
kono
parents:
diff changeset
2213 static void
kono
parents:
diff changeset
2214 epiphany_conditional_register_usage (void)
kono
parents:
diff changeset
2215 {
kono
parents:
diff changeset
2216 int i;
kono
parents:
diff changeset
2217
kono
parents:
diff changeset
2218 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
kono
parents:
diff changeset
2219 {
kono
parents:
diff changeset
2220 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
kono
parents:
diff changeset
2221 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
kono
parents:
diff changeset
2222 }
kono
parents:
diff changeset
2223 if (TARGET_HALF_REG_FILE)
kono
parents:
diff changeset
2224 {
kono
parents:
diff changeset
2225 for (i = 32; i <= 63; i++)
kono
parents:
diff changeset
2226 {
kono
parents:
diff changeset
2227 fixed_regs[i] = 1;
kono
parents:
diff changeset
2228 call_used_regs[i] = 1;
kono
parents:
diff changeset
2229 }
kono
parents:
diff changeset
2230 }
kono
parents:
diff changeset
2231 if (epiphany_m1reg >= 0)
kono
parents:
diff changeset
2232 {
kono
parents:
diff changeset
2233 fixed_regs[epiphany_m1reg] = 1;
kono
parents:
diff changeset
2234 call_used_regs[epiphany_m1reg] = 1;
kono
parents:
diff changeset
2235 }
kono
parents:
diff changeset
2236 if (!TARGET_PREFER_SHORT_INSN_REGS)
kono
parents:
diff changeset
2237 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]);
kono
parents:
diff changeset
2238 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS],
kono
parents:
diff changeset
2239 reg_class_contents[GENERAL_REGS]);
kono
parents:
diff changeset
2240 /* It would be simpler and quicker if we could just use
kono
parents:
diff changeset
2241 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
kono
parents:
diff changeset
2242 it is set up later by our caller. */
kono
parents:
diff changeset
2243 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
kono
parents:
diff changeset
2244 if (!call_used_regs[i])
kono
parents:
diff changeset
2245 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i);
kono
parents:
diff changeset
2246 }
kono
parents:
diff changeset
2247
kono
parents:
diff changeset
2248 /* Determine where to put an argument to a function.
kono
parents:
diff changeset
2249 Value is zero to push the argument on the stack,
kono
parents:
diff changeset
2250 or a hard register in which to store the argument.
kono
parents:
diff changeset
2251
kono
parents:
diff changeset
2252 MODE is the argument's machine mode.
kono
parents:
diff changeset
2253 TYPE is the data type of the argument (as a tree).
kono
parents:
diff changeset
2254 This is null for libcalls where that information may
kono
parents:
diff changeset
2255 not be available.
kono
parents:
diff changeset
2256 CUM is a variable of type CUMULATIVE_ARGS which gives info about
kono
parents:
diff changeset
2257 the preceding args and about the function being called.
kono
parents:
diff changeset
2258 NAMED is nonzero if this argument is a named parameter
kono
parents:
diff changeset
2259 (otherwise it is an extra parameter matching an ellipsis). */
kono
parents:
diff changeset
2260 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
kono
parents:
diff changeset
2261 registers and the rest are pushed. */
kono
parents:
diff changeset
2262 static rtx
kono
parents:
diff changeset
2263 epiphany_function_arg (cumulative_args_t cum_v, machine_mode mode,
kono
parents:
diff changeset
2264 const_tree type, bool named ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
2265 {
kono
parents:
diff changeset
2266 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
kono
parents:
diff changeset
2267
kono
parents:
diff changeset
2268 if (PASS_IN_REG_P (cum, mode, type))
kono
parents:
diff changeset
2269 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type));
kono
parents:
diff changeset
2270 return 0;
kono
parents:
diff changeset
2271 }
kono
parents:
diff changeset
2272
kono
parents:
diff changeset
2273 /* Update the data in CUM to advance over an argument
kono
parents:
diff changeset
2274 of mode MODE and data type TYPE.
kono
parents:
diff changeset
2275 (TYPE is null for libcalls where that information may not be available.) */
kono
parents:
diff changeset
2276 static void
kono
parents:
diff changeset
2277 epiphany_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
kono
parents:
diff changeset
2278 const_tree type, bool named ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
2279 {
kono
parents:
diff changeset
2280 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
kono
parents:
diff changeset
2281
kono
parents:
diff changeset
2282 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
kono
parents:
diff changeset
2283 }
kono
parents:
diff changeset
2284
kono
parents:
diff changeset
2285 /* Nested function support.
kono
parents:
diff changeset
2286 An epiphany trampoline looks like this:
kono
parents:
diff changeset
2287 mov r16,%low(fnaddr)
kono
parents:
diff changeset
2288 movt r16,%high(fnaddr)
kono
parents:
diff changeset
2289 mov ip,%low(cxt)
kono
parents:
diff changeset
2290 movt ip,%high(cxt)
kono
parents:
diff changeset
2291 jr r16 */
kono
parents:
diff changeset
2292
kono
parents:
diff changeset
2293 #define EPIPHANY_LOW_RTX(X) \
kono
parents:
diff changeset
2294 (gen_rtx_IOR (SImode, \
kono
parents:
diff changeset
2295 gen_rtx_ASHIFT (SImode, \
kono
parents:
diff changeset
2296 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
kono
parents:
diff changeset
2297 gen_rtx_ASHIFT (SImode, \
kono
parents:
diff changeset
2298 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
kono
parents:
diff changeset
2299 #define EPIPHANY_HIGH_RTX(X) \
kono
parents:
diff changeset
2300 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
kono
parents:
diff changeset
2301
kono
parents:
diff changeset
2302 /* Emit RTL insns to initialize the variable parts of a trampoline.
kono
parents:
diff changeset
2303 FNADDR is an RTX for the address of the function's pure code.
kono
parents:
diff changeset
2304 CXT is an RTX for the static chain value for the function. */
kono
parents:
diff changeset
2305 static void
kono
parents:
diff changeset
2306 epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
kono
parents:
diff changeset
2307 {
kono
parents:
diff changeset
2308 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
kono
parents:
diff changeset
2309 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0));
kono
parents:
diff changeset
2310
kono
parents:
diff changeset
2311 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)),
kono
parents:
diff changeset
2312 gen_rtx_IOR (SImode, GEN_INT (0x4002000b),
kono
parents:
diff changeset
2313 EPIPHANY_LOW_RTX (fnaddr)));
kono
parents:
diff changeset
2314 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)),
kono
parents:
diff changeset
2315 gen_rtx_IOR (SImode, GEN_INT (0x5002000b),
kono
parents:
diff changeset
2316 EPIPHANY_HIGH_RTX (fnaddr)));
kono
parents:
diff changeset
2317 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)),
kono
parents:
diff changeset
2318 gen_rtx_IOR (SImode, GEN_INT (0x2002800b),
kono
parents:
diff changeset
2319 EPIPHANY_LOW_RTX (cxt)));
kono
parents:
diff changeset
2320 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)),
kono
parents:
diff changeset
2321 gen_rtx_IOR (SImode, GEN_INT (0x3002800b),
kono
parents:
diff changeset
2322 EPIPHANY_HIGH_RTX (cxt)));
kono
parents:
diff changeset
2323 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)),
kono
parents:
diff changeset
2324 GEN_INT (0x0802014f));
kono
parents:
diff changeset
2325 }
kono
parents:
diff changeset
2326
kono
parents:
diff changeset
2327 bool
kono
parents:
diff changeset
2328 epiphany_optimize_mode_switching (int entity)
kono
parents:
diff changeset
2329 {
kono
parents:
diff changeset
2330 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity))
kono
parents:
diff changeset
2331 return false;
kono
parents:
diff changeset
2332 switch (entity)
kono
parents:
diff changeset
2333 {
kono
parents:
diff changeset
2334 case EPIPHANY_MSW_ENTITY_AND:
kono
parents:
diff changeset
2335 case EPIPHANY_MSW_ENTITY_OR:
kono
parents:
diff changeset
2336 case EPIPHANY_MSW_ENTITY_CONFIG:
kono
parents:
diff changeset
2337 return true;
kono
parents:
diff changeset
2338 case EPIPHANY_MSW_ENTITY_NEAREST:
kono
parents:
diff changeset
2339 case EPIPHANY_MSW_ENTITY_TRUNC:
kono
parents:
diff changeset
2340 return optimize > 0;
kono
parents:
diff changeset
2341 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
kono
parents:
diff changeset
2342 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0;
kono
parents:
diff changeset
2343 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
kono
parents:
diff changeset
2344 return (MACHINE_FUNCTION (cfun)->sw_entities_processed
kono
parents:
diff changeset
2345 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0;
kono
parents:
diff changeset
2346 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
kono
parents:
diff changeset
2347 return optimize == 0 || current_pass == pass_mode_switch_use;
kono
parents:
diff changeset
2348 }
kono
parents:
diff changeset
2349 gcc_unreachable ();
kono
parents:
diff changeset
2350 }
kono
parents:
diff changeset
2351
kono
parents:
diff changeset
2352 static int
kono
parents:
diff changeset
2353 epiphany_mode_priority (int entity, int priority)
kono
parents:
diff changeset
2354 {
kono
parents:
diff changeset
2355 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR
kono
parents:
diff changeset
2356 || entity== EPIPHANY_MSW_ENTITY_CONFIG)
kono
parents:
diff changeset
2357 return priority;
kono
parents:
diff changeset
2358 if (priority > 3)
kono
parents:
diff changeset
2359 switch (priority)
kono
parents:
diff changeset
2360 {
kono
parents:
diff changeset
2361 case 4: return FP_MODE_ROUND_UNKNOWN;
kono
parents:
diff changeset
2362 case 5: return FP_MODE_NONE;
kono
parents:
diff changeset
2363 default: gcc_unreachable ();
kono
parents:
diff changeset
2364 }
kono
parents:
diff changeset
2365 switch ((enum attr_fp_mode) epiphany_normal_fp_mode)
kono
parents:
diff changeset
2366 {
kono
parents:
diff changeset
2367 case FP_MODE_INT:
kono
parents:
diff changeset
2368 switch (priority)
kono
parents:
diff changeset
2369 {
kono
parents:
diff changeset
2370 case 0: return FP_MODE_INT;
kono
parents:
diff changeset
2371 case 1: return epiphany_normal_fp_rounding;
kono
parents:
diff changeset
2372 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST
kono
parents:
diff changeset
2373 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
kono
parents:
diff changeset
2374 case 3: return FP_MODE_CALLER;
kono
parents:
diff changeset
2375 }
kono
parents:
diff changeset
2376 case FP_MODE_ROUND_NEAREST:
kono
parents:
diff changeset
2377 case FP_MODE_CALLER:
kono
parents:
diff changeset
2378 switch (priority)
kono
parents:
diff changeset
2379 {
kono
parents:
diff changeset
2380 case 0: return FP_MODE_ROUND_NEAREST;
kono
parents:
diff changeset
2381 case 1: return FP_MODE_ROUND_TRUNC;
kono
parents:
diff changeset
2382 case 2: return FP_MODE_INT;
kono
parents:
diff changeset
2383 case 3: return FP_MODE_CALLER;
kono
parents:
diff changeset
2384 }
kono
parents:
diff changeset
2385 case FP_MODE_ROUND_TRUNC:
kono
parents:
diff changeset
2386 switch (priority)
kono
parents:
diff changeset
2387 {
kono
parents:
diff changeset
2388 case 0: return FP_MODE_ROUND_TRUNC;
kono
parents:
diff changeset
2389 case 1: return FP_MODE_ROUND_NEAREST;
kono
parents:
diff changeset
2390 case 2: return FP_MODE_INT;
kono
parents:
diff changeset
2391 case 3: return FP_MODE_CALLER;
kono
parents:
diff changeset
2392 }
kono
parents:
diff changeset
2393 case FP_MODE_ROUND_UNKNOWN:
kono
parents:
diff changeset
2394 case FP_MODE_NONE:
kono
parents:
diff changeset
2395 gcc_unreachable ();
kono
parents:
diff changeset
2396 }
kono
parents:
diff changeset
2397 gcc_unreachable ();
kono
parents:
diff changeset
2398 }
kono
parents:
diff changeset
2399
kono
parents:
diff changeset
2400 int
kono
parents:
diff changeset
2401 epiphany_mode_needed (int entity, rtx_insn *insn)
kono
parents:
diff changeset
2402 {
kono
parents:
diff changeset
2403 enum attr_fp_mode mode;
kono
parents:
diff changeset
2404
kono
parents:
diff changeset
2405 if (recog_memoized (insn) < 0)
kono
parents:
diff changeset
2406 {
kono
parents:
diff changeset
2407 if (entity == EPIPHANY_MSW_ENTITY_AND
kono
parents:
diff changeset
2408 || entity == EPIPHANY_MSW_ENTITY_OR
kono
parents:
diff changeset
2409 || entity == EPIPHANY_MSW_ENTITY_CONFIG)
kono
parents:
diff changeset
2410 return 2;
kono
parents:
diff changeset
2411 return FP_MODE_NONE;
kono
parents:
diff changeset
2412 }
kono
parents:
diff changeset
2413 mode = get_attr_fp_mode (insn);
kono
parents:
diff changeset
2414
kono
parents:
diff changeset
2415 switch (entity)
kono
parents:
diff changeset
2416 {
kono
parents:
diff changeset
2417 case EPIPHANY_MSW_ENTITY_AND:
kono
parents:
diff changeset
2418 return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2;
kono
parents:
diff changeset
2419 case EPIPHANY_MSW_ENTITY_OR:
kono
parents:
diff changeset
2420 return mode == FP_MODE_INT ? 1 : 2;
kono
parents:
diff changeset
2421 case EPIPHANY_MSW_ENTITY_CONFIG:
kono
parents:
diff changeset
2422 /* We must know/save config before we set it to something else.
kono
parents:
diff changeset
2423 Where we need the original value, we are fine with having it
kono
parents:
diff changeset
2424 just unchanged from the function start.
kono
parents:
diff changeset
2425 Because of the nature of the mode switching optimization,
kono
parents:
diff changeset
2426 a restore will be dominated by a clobber. */
kono
parents:
diff changeset
2427 if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER)
kono
parents:
diff changeset
2428 return 1;
kono
parents:
diff changeset
2429 /* A cpecial case are abnormal edges, which are deemed to clobber
kono
parents:
diff changeset
2430 the mode as well. We need to pin this effect on a actually
kono
parents:
diff changeset
2431 dominating insn, and one where the frame can be accessed, too, in
kono
parents:
diff changeset
2432 case the pseudo used to save CONFIG doesn't get a hard register. */
kono
parents:
diff changeset
2433 if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX))
kono
parents:
diff changeset
2434 return 1;
kono
parents:
diff changeset
2435 return 2;
kono
parents:
diff changeset
2436 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
kono
parents:
diff changeset
2437 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
kono
parents:
diff changeset
2438 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn);
kono
parents:
diff changeset
2439 /* Fall through. */
kono
parents:
diff changeset
2440 case EPIPHANY_MSW_ENTITY_NEAREST:
kono
parents:
diff changeset
2441 case EPIPHANY_MSW_ENTITY_TRUNC:
kono
parents:
diff changeset
2442 if (mode == FP_MODE_ROUND_UNKNOWN)
kono
parents:
diff changeset
2443 {
kono
parents:
diff changeset
2444 MACHINE_FUNCTION (cfun)->unknown_mode_uses++;
kono
parents:
diff changeset
2445 return FP_MODE_NONE;
kono
parents:
diff changeset
2446 }
kono
parents:
diff changeset
2447 return mode;
kono
parents:
diff changeset
2448 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
kono
parents:
diff changeset
2449 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC)
kono
parents:
diff changeset
2450 return FP_MODE_ROUND_UNKNOWN;
kono
parents:
diff changeset
2451 return mode;
kono
parents:
diff changeset
2452 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
kono
parents:
diff changeset
2453 if (mode == FP_MODE_ROUND_UNKNOWN)
kono
parents:
diff changeset
2454 return epiphany_normal_fp_rounding;
kono
parents:
diff changeset
2455 return mode;
kono
parents:
diff changeset
2456 default:
kono
parents:
diff changeset
2457 gcc_unreachable ();
kono
parents:
diff changeset
2458 }
kono
parents:
diff changeset
2459 }
kono
parents:
diff changeset
2460
kono
parents:
diff changeset
2461 static int
kono
parents:
diff changeset
2462 epiphany_mode_entry_exit (int entity, bool exit)
kono
parents:
diff changeset
2463 {
kono
parents:
diff changeset
2464 int normal_mode = epiphany_normal_fp_mode ;
kono
parents:
diff changeset
2465
kono
parents:
diff changeset
2466 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity);
kono
parents:
diff changeset
2467 if (epiphany_is_interrupt_p (current_function_decl))
kono
parents:
diff changeset
2468 normal_mode = FP_MODE_CALLER;
kono
parents:
diff changeset
2469 switch (entity)
kono
parents:
diff changeset
2470 {
kono
parents:
diff changeset
2471 case EPIPHANY_MSW_ENTITY_AND:
kono
parents:
diff changeset
2472 if (exit)
kono
parents:
diff changeset
2473 return normal_mode != FP_MODE_INT ? 1 : 2;
kono
parents:
diff changeset
2474 return 0;
kono
parents:
diff changeset
2475 case EPIPHANY_MSW_ENTITY_OR:
kono
parents:
diff changeset
2476 if (exit)
kono
parents:
diff changeset
2477 return normal_mode == FP_MODE_INT ? 1 : 2;
kono
parents:
diff changeset
2478 return 0;
kono
parents:
diff changeset
2479 case EPIPHANY_MSW_ENTITY_CONFIG:
kono
parents:
diff changeset
2480 if (exit)
kono
parents:
diff changeset
2481 return 2;
kono
parents:
diff changeset
2482 return normal_mode == FP_MODE_CALLER ? 0 : 1;
kono
parents:
diff changeset
2483 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
kono
parents:
diff changeset
2484 if (normal_mode == FP_MODE_ROUND_NEAREST
kono
parents:
diff changeset
2485 || normal_mode == FP_MODE_ROUND_TRUNC)
kono
parents:
diff changeset
2486 return FP_MODE_ROUND_UNKNOWN;
kono
parents:
diff changeset
2487 /* Fall through. */
kono
parents:
diff changeset
2488 case EPIPHANY_MSW_ENTITY_NEAREST:
kono
parents:
diff changeset
2489 case EPIPHANY_MSW_ENTITY_TRUNC:
kono
parents:
diff changeset
2490 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
kono
parents:
diff changeset
2491 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
kono
parents:
diff changeset
2492 return normal_mode;
kono
parents:
diff changeset
2493 default:
kono
parents:
diff changeset
2494 gcc_unreachable ();
kono
parents:
diff changeset
2495 }
kono
parents:
diff changeset
2496 }
kono
parents:
diff changeset
2497
kono
parents:
diff changeset
2498 int
kono
parents:
diff changeset
2499 epiphany_mode_after (int entity, int last_mode, rtx_insn *insn)
kono
parents:
diff changeset
2500 {
kono
parents:
diff changeset
2501 /* We have too few call-saved registers to hope to keep the masks across
kono
parents:
diff changeset
2502 calls. */
kono
parents:
diff changeset
2503 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
kono
parents:
diff changeset
2504 {
kono
parents:
diff changeset
2505 if (CALL_P (insn))
kono
parents:
diff changeset
2506 return 0;
kono
parents:
diff changeset
2507 return last_mode;
kono
parents:
diff changeset
2508 }
kono
parents:
diff changeset
2509 /* If there is an abnormal edge, we don't want the config register to
kono
parents:
diff changeset
2510 be 'saved' again at the destination.
kono
parents:
diff changeset
2511 The frame pointer adjustment is inside a PARALLEL because of the
kono
parents:
diff changeset
2512 flags clobber. */
kono
parents:
diff changeset
2513 if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn)
kono
parents:
diff changeset
2514 && GET_CODE (PATTERN (insn)) == PARALLEL
kono
parents:
diff changeset
2515 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
kono
parents:
diff changeset
2516 && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx)
kono
parents:
diff changeset
2517 {
kono
parents:
diff changeset
2518 gcc_assert (cfun->has_nonlocal_label);
kono
parents:
diff changeset
2519 return 1;
kono
parents:
diff changeset
2520 }
kono
parents:
diff changeset
2521 if (recog_memoized (insn) < 0)
kono
parents:
diff changeset
2522 return last_mode;
kono
parents:
diff changeset
2523 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN
kono
parents:
diff changeset
2524 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC)
kono
parents:
diff changeset
2525 {
kono
parents:
diff changeset
2526 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
kono
parents:
diff changeset
2527 return FP_MODE_ROUND_NEAREST;
kono
parents:
diff changeset
2528 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
kono
parents:
diff changeset
2529 return FP_MODE_ROUND_TRUNC;
kono
parents:
diff changeset
2530 }
kono
parents:
diff changeset
2531 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
kono
parents:
diff changeset
2532 {
kono
parents:
diff changeset
2533 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
kono
parents:
diff changeset
2534 int fp_mode;
kono
parents:
diff changeset
2535
kono
parents:
diff changeset
2536 if (REG_P (src))
kono
parents:
diff changeset
2537 return FP_MODE_CALLER;
kono
parents:
diff changeset
2538 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0));
kono
parents:
diff changeset
2539 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
kono
parents:
diff changeset
2540 && (fp_mode == FP_MODE_ROUND_NEAREST
kono
parents:
diff changeset
2541 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC))
kono
parents:
diff changeset
2542 return FP_MODE_ROUND_UNKNOWN;
kono
parents:
diff changeset
2543 return fp_mode;
kono
parents:
diff changeset
2544 }
kono
parents:
diff changeset
2545 return last_mode;
kono
parents:
diff changeset
2546 }
kono
parents:
diff changeset
2547
kono
parents:
diff changeset
2548 static int
kono
parents:
diff changeset
2549 epiphany_mode_entry (int entity)
kono
parents:
diff changeset
2550 {
kono
parents:
diff changeset
2551 return epiphany_mode_entry_exit (entity, false);
kono
parents:
diff changeset
2552 }
kono
parents:
diff changeset
2553
kono
parents:
diff changeset
2554 static int
kono
parents:
diff changeset
2555 epiphany_mode_exit (int entity)
kono
parents:
diff changeset
2556 {
kono
parents:
diff changeset
2557 return epiphany_mode_entry_exit (entity, true);
kono
parents:
diff changeset
2558 }
kono
parents:
diff changeset
2559
kono
parents:
diff changeset
2560 void
kono
parents:
diff changeset
2561 emit_set_fp_mode (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2562 HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
2563 {
kono
parents:
diff changeset
2564 rtx save_cc, cc_reg, mask, src, src2;
kono
parents:
diff changeset
2565 enum attr_fp_mode fp_mode;
kono
parents:
diff changeset
2566
kono
parents:
diff changeset
2567 if (!MACHINE_FUNCTION (cfun)->and_mask)
kono
parents:
diff changeset
2568 {
kono
parents:
diff changeset
2569 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode);
kono
parents:
diff changeset
2570 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode);
kono
parents:
diff changeset
2571 }
kono
parents:
diff changeset
2572 if (entity == EPIPHANY_MSW_ENTITY_AND)
kono
parents:
diff changeset
2573 {
kono
parents:
diff changeset
2574 gcc_assert (mode >= 0 && mode <= 2);
kono
parents:
diff changeset
2575 if (mode == 1)
kono
parents:
diff changeset
2576 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask,
kono
parents:
diff changeset
2577 gen_int_mode (0xfff1fffe, SImode));
kono
parents:
diff changeset
2578 return;
kono
parents:
diff changeset
2579 }
kono
parents:
diff changeset
2580 else if (entity == EPIPHANY_MSW_ENTITY_OR)
kono
parents:
diff changeset
2581 {
kono
parents:
diff changeset
2582 gcc_assert (mode >= 0 && mode <= 2);
kono
parents:
diff changeset
2583 if (mode == 1)
kono
parents:
diff changeset
2584 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000));
kono
parents:
diff changeset
2585 return;
kono
parents:
diff changeset
2586 }
kono
parents:
diff changeset
2587 else if (entity == EPIPHANY_MSW_ENTITY_CONFIG)
kono
parents:
diff changeset
2588 {
kono
parents:
diff changeset
2589 /* Mode switching optimization is done after emit_initial_value_sets,
kono
parents:
diff changeset
2590 so we have to take care of CONFIG_REGNUM here. */
kono
parents:
diff changeset
2591 gcc_assert (mode >= 0 && mode <= 2);
kono
parents:
diff changeset
2592 rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
kono
parents:
diff changeset
2593 if (mode == 1)
kono
parents:
diff changeset
2594 emit_insn (gen_save_config (save));
kono
parents:
diff changeset
2595 return;
kono
parents:
diff changeset
2596 }
kono
parents:
diff changeset
2597 fp_mode = (enum attr_fp_mode) mode;
kono
parents:
diff changeset
2598 src = NULL_RTX;
kono
parents:
diff changeset
2599
kono
parents:
diff changeset
2600 switch (fp_mode)
kono
parents:
diff changeset
2601 {
kono
parents:
diff changeset
2602 case FP_MODE_CALLER:
kono
parents:
diff changeset
2603 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later
kono
parents:
diff changeset
2604 so that the config save gets inserted before the first use. */
kono
parents:
diff changeset
2605 gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG);
kono
parents:
diff changeset
2606 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
kono
parents:
diff changeset
2607 mask = MACHINE_FUNCTION (cfun)->and_mask;
kono
parents:
diff changeset
2608 break;
kono
parents:
diff changeset
2609 case FP_MODE_ROUND_UNKNOWN:
kono
parents:
diff changeset
2610 MACHINE_FUNCTION (cfun)->unknown_mode_sets++;
kono
parents:
diff changeset
2611 mask = MACHINE_FUNCTION (cfun)->and_mask;
kono
parents:
diff changeset
2612 break;
kono
parents:
diff changeset
2613 case FP_MODE_ROUND_NEAREST:
kono
parents:
diff changeset
2614 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
kono
parents:
diff changeset
2615 return;
kono
parents:
diff changeset
2616 mask = MACHINE_FUNCTION (cfun)->and_mask;
kono
parents:
diff changeset
2617 break;
kono
parents:
diff changeset
2618 case FP_MODE_ROUND_TRUNC:
kono
parents:
diff changeset
2619 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
kono
parents:
diff changeset
2620 return;
kono
parents:
diff changeset
2621 mask = MACHINE_FUNCTION (cfun)->and_mask;
kono
parents:
diff changeset
2622 break;
kono
parents:
diff changeset
2623 case FP_MODE_INT:
kono
parents:
diff changeset
2624 mask = MACHINE_FUNCTION (cfun)->or_mask;
kono
parents:
diff changeset
2625 break;
kono
parents:
diff changeset
2626 case FP_MODE_NONE:
kono
parents:
diff changeset
2627 default:
kono
parents:
diff changeset
2628 gcc_unreachable ();
kono
parents:
diff changeset
2629 }
kono
parents:
diff changeset
2630 save_cc = gen_reg_rtx (CCmode);
kono
parents:
diff changeset
2631 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
kono
parents:
diff changeset
2632 emit_move_insn (save_cc, cc_reg);
kono
parents:
diff changeset
2633 mask = force_reg (SImode, mask);
kono
parents:
diff changeset
2634 if (!src)
kono
parents:
diff changeset
2635 {
kono
parents:
diff changeset
2636 rtvec v = gen_rtvec (1, GEN_INT (fp_mode));
kono
parents:
diff changeset
2637
kono
parents:
diff changeset
2638 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
kono
parents:
diff changeset
2639 }
kono
parents:
diff changeset
2640 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN
kono
parents:
diff changeset
2641 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
kono
parents:
diff changeset
2642 src2 = copy_rtx (src);
kono
parents:
diff changeset
2643 else
kono
parents:
diff changeset
2644 {
kono
parents:
diff changeset
2645 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN));
kono
parents:
diff changeset
2646
kono
parents:
diff changeset
2647 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
kono
parents:
diff changeset
2648 }
kono
parents:
diff changeset
2649 emit_insn (gen_set_fp_mode (src, src2, mask));
kono
parents:
diff changeset
2650 emit_move_insn (cc_reg, save_cc);
kono
parents:
diff changeset
2651 }
kono
parents:
diff changeset
2652
kono
parents:
diff changeset
2653 void
kono
parents:
diff changeset
2654 epiphany_expand_set_fp_mode (rtx *operands)
kono
parents:
diff changeset
2655 {
kono
parents:
diff changeset
2656 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM);
kono
parents:
diff changeset
2657 rtx src = operands[0];
kono
parents:
diff changeset
2658 rtx mask_reg = operands[2];
kono
parents:
diff changeset
2659 rtx scratch = operands[3];
kono
parents:
diff changeset
2660 enum attr_fp_mode fp_mode;
kono
parents:
diff changeset
2661
kono
parents:
diff changeset
2662
kono
parents:
diff changeset
2663 gcc_assert (rtx_equal_p (src, operands[1])
kono
parents:
diff changeset
2664 /* Sometimes reload gets silly and reloads the same pseudo
kono
parents:
diff changeset
2665 into different registers. */
kono
parents:
diff changeset
2666 || (REG_P (src) && REG_P (operands[1])));
kono
parents:
diff changeset
2667
kono
parents:
diff changeset
2668 if (!epiphany_uninterruptible_p (current_function_decl))
kono
parents:
diff changeset
2669 emit_insn (gen_gid ());
kono
parents:
diff changeset
2670 emit_move_insn (scratch, ctrl);
kono
parents:
diff changeset
2671
kono
parents:
diff changeset
2672 if (GET_CODE (src) == REG)
kono
parents:
diff changeset
2673 {
kono
parents:
diff changeset
2674 /* FP_MODE_CALLER */
kono
parents:
diff changeset
2675 emit_insn (gen_xorsi3 (scratch, scratch, src));
kono
parents:
diff changeset
2676 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
kono
parents:
diff changeset
2677 emit_insn (gen_xorsi3 (scratch, scratch, src));
kono
parents:
diff changeset
2678 }
kono
parents:
diff changeset
2679 else
kono
parents:
diff changeset
2680 {
kono
parents:
diff changeset
2681 gcc_assert (GET_CODE (src) == CONST);
kono
parents:
diff changeset
2682 src = XEXP (src, 0);
kono
parents:
diff changeset
2683 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0));
kono
parents:
diff changeset
2684 switch (fp_mode)
kono
parents:
diff changeset
2685 {
kono
parents:
diff changeset
2686 case FP_MODE_ROUND_NEAREST:
kono
parents:
diff changeset
2687 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
kono
parents:
diff changeset
2688 break;
kono
parents:
diff changeset
2689 case FP_MODE_ROUND_TRUNC:
kono
parents:
diff changeset
2690 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
kono
parents:
diff changeset
2691 emit_insn (gen_add2_insn (scratch, const1_rtx));
kono
parents:
diff changeset
2692 break;
kono
parents:
diff changeset
2693 case FP_MODE_INT:
kono
parents:
diff changeset
2694 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg));
kono
parents:
diff changeset
2695 break;
kono
parents:
diff changeset
2696 case FP_MODE_CALLER:
kono
parents:
diff changeset
2697 case FP_MODE_ROUND_UNKNOWN:
kono
parents:
diff changeset
2698 case FP_MODE_NONE:
kono
parents:
diff changeset
2699 gcc_unreachable ();
kono
parents:
diff changeset
2700 }
kono
parents:
diff changeset
2701 }
kono
parents:
diff changeset
2702 emit_move_insn (ctrl, scratch);
kono
parents:
diff changeset
2703 if (!epiphany_uninterruptible_p (current_function_decl))
kono
parents:
diff changeset
2704 emit_insn (gen_gie ());
kono
parents:
diff changeset
2705 }
kono
parents:
diff changeset
2706
kono
parents:
diff changeset
2707 void
kono
parents:
diff changeset
2708 epiphany_insert_mode_switch_use (rtx_insn *insn,
kono
parents:
diff changeset
2709 int entity ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2710 int mode ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
2711 {
kono
parents:
diff changeset
2712 rtx pat = PATTERN (insn);
kono
parents:
diff changeset
2713 rtvec v;
kono
parents:
diff changeset
2714 int len, i;
kono
parents:
diff changeset
2715 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM);
kono
parents:
diff changeset
2716 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM);
kono
parents:
diff changeset
2717
kono
parents:
diff changeset
2718 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
kono
parents:
diff changeset
2719 return;
kono
parents:
diff changeset
2720 switch ((enum attr_fp_mode) get_attr_fp_mode (insn))
kono
parents:
diff changeset
2721 {
kono
parents:
diff changeset
2722 case FP_MODE_ROUND_NEAREST:
kono
parents:
diff changeset
2723 near = gen_rtx_USE (VOIDmode, near);
kono
parents:
diff changeset
2724 trunc = gen_rtx_CLOBBER (VOIDmode, trunc);
kono
parents:
diff changeset
2725 break;
kono
parents:
diff changeset
2726 case FP_MODE_ROUND_TRUNC:
kono
parents:
diff changeset
2727 near = gen_rtx_CLOBBER (VOIDmode, near);
kono
parents:
diff changeset
2728 trunc = gen_rtx_USE (VOIDmode, trunc);
kono
parents:
diff changeset
2729 break;
kono
parents:
diff changeset
2730 case FP_MODE_ROUND_UNKNOWN:
kono
parents:
diff changeset
2731 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM));
kono
parents:
diff changeset
2732 trunc = copy_rtx (near);
kono
parents:
diff changeset
2733 /* Fall through. */
kono
parents:
diff changeset
2734 case FP_MODE_INT:
kono
parents:
diff changeset
2735 case FP_MODE_CALLER:
kono
parents:
diff changeset
2736 near = gen_rtx_USE (VOIDmode, near);
kono
parents:
diff changeset
2737 trunc = gen_rtx_USE (VOIDmode, trunc);
kono
parents:
diff changeset
2738 break;
kono
parents:
diff changeset
2739 case FP_MODE_NONE:
kono
parents:
diff changeset
2740 gcc_unreachable ();
kono
parents:
diff changeset
2741 }
kono
parents:
diff changeset
2742 gcc_assert (GET_CODE (pat) == PARALLEL);
kono
parents:
diff changeset
2743 len = XVECLEN (pat, 0);
kono
parents:
diff changeset
2744 v = rtvec_alloc (len + 2);
kono
parents:
diff changeset
2745 for (i = 0; i < len; i++)
kono
parents:
diff changeset
2746 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i);
kono
parents:
diff changeset
2747 RTVEC_ELT (v, len) = near;
kono
parents:
diff changeset
2748 RTVEC_ELT (v, len + 1) = trunc;
kono
parents:
diff changeset
2749 pat = gen_rtx_PARALLEL (VOIDmode, v);
kono
parents:
diff changeset
2750 PATTERN (insn) = pat;
kono
parents:
diff changeset
2751 MACHINE_FUNCTION (cfun)->control_use_inserted = true;
kono
parents:
diff changeset
2752 }
kono
parents:
diff changeset
2753
kono
parents:
diff changeset
2754 bool
kono
parents:
diff changeset
2755 epiphany_epilogue_uses (int regno)
kono
parents:
diff changeset
2756 {
kono
parents:
diff changeset
2757 if (regno == GPR_LR)
kono
parents:
diff changeset
2758 return true;
kono
parents:
diff changeset
2759 if (reload_completed && epiphany_is_interrupt_p (current_function_decl))
kono
parents:
diff changeset
2760 {
kono
parents:
diff changeset
2761 if (fixed_regs[regno]
kono
parents:
diff changeset
2762 && regno != STATUS_REGNUM && regno != IRET_REGNUM
kono
parents:
diff changeset
2763 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM)
kono
parents:
diff changeset
2764 return false;
kono
parents:
diff changeset
2765 return true;
kono
parents:
diff changeset
2766 }
kono
parents:
diff changeset
2767 if (regno == FP_NEAREST_REGNUM
kono
parents:
diff changeset
2768 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC)
kono
parents:
diff changeset
2769 return true;
kono
parents:
diff changeset
2770 if (regno == FP_TRUNCATE_REGNUM
kono
parents:
diff changeset
2771 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST)
kono
parents:
diff changeset
2772 return true;
kono
parents:
diff changeset
2773 return false;
kono
parents:
diff changeset
2774 }
kono
parents:
diff changeset
2775
kono
parents:
diff changeset
2776 static unsigned int
kono
parents:
diff changeset
2777 epiphany_min_divisions_for_recip_mul (machine_mode mode)
kono
parents:
diff changeset
2778 {
kono
parents:
diff changeset
2779 if (flag_reciprocal_math && mode == SFmode)
kono
parents:
diff changeset
2780 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
kono
parents:
diff changeset
2781 it already at the tree level and expose it to further optimizations. */
kono
parents:
diff changeset
2782 return 1;
kono
parents:
diff changeset
2783 return default_min_divisions_for_recip_mul (mode);
kono
parents:
diff changeset
2784 }
kono
parents:
diff changeset
2785
kono
parents:
diff changeset
2786 static machine_mode
kono
parents:
diff changeset
2787 epiphany_preferred_simd_mode (scalar_mode mode ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
2788 {
kono
parents:
diff changeset
2789 return TARGET_VECT_DOUBLE ? DImode : SImode;
kono
parents:
diff changeset
2790 }
kono
parents:
diff changeset
2791
kono
parents:
diff changeset
2792 static bool
kono
parents:
diff changeset
2793 epiphany_vector_mode_supported_p (machine_mode mode)
kono
parents:
diff changeset
2794 {
kono
parents:
diff changeset
2795 if (mode == V2SFmode)
kono
parents:
diff changeset
2796 return true;
kono
parents:
diff changeset
2797 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
kono
parents:
diff changeset
2798 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
kono
parents:
diff changeset
2799 return true;
kono
parents:
diff changeset
2800 return false;
kono
parents:
diff changeset
2801 }
kono
parents:
diff changeset
2802
kono
parents:
diff changeset
2803 static bool
kono
parents:
diff changeset
2804 epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
kono
parents:
diff changeset
2805 {
kono
parents:
diff changeset
2806 /* Vectors which aren't in packed structures will not be less aligned than
kono
parents:
diff changeset
2807 the natural alignment of their element type, so this is safe. */
kono
parents:
diff changeset
2808 if (TYPE_ALIGN_UNIT (type) == 4)
kono
parents:
diff changeset
2809 return !is_packed;
kono
parents:
diff changeset
2810
kono
parents:
diff changeset
2811 return default_builtin_vector_alignment_reachable (type, is_packed);
kono
parents:
diff changeset
2812 }
kono
parents:
diff changeset
2813
kono
parents:
diff changeset
2814 static bool
kono
parents:
diff changeset
2815 epiphany_support_vector_misalignment (machine_mode mode, const_tree type,
kono
parents:
diff changeset
2816 int misalignment, bool is_packed)
kono
parents:
diff changeset
2817 {
kono
parents:
diff changeset
2818 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
kono
parents:
diff changeset
2819 return true;
kono
parents:
diff changeset
2820 return default_builtin_support_vector_misalignment (mode, type, misalignment,
kono
parents:
diff changeset
2821 is_packed);
kono
parents:
diff changeset
2822 }
kono
parents:
diff changeset
2823
kono
parents:
diff changeset
2824 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
kono
parents:
diff changeset
2825 structs. Make structs double-word-aligned it they are a double word or
kono
parents:
diff changeset
2826 (potentially) larger; failing that, do the same for a size of 32 bits. */
kono
parents:
diff changeset
2827 unsigned
kono
parents:
diff changeset
2828 epiphany_special_round_type_align (tree type, unsigned computed,
kono
parents:
diff changeset
2829 unsigned specified)
kono
parents:
diff changeset
2830 {
kono
parents:
diff changeset
2831 unsigned align = MAX (computed, specified);
kono
parents:
diff changeset
2832 tree field;
kono
parents:
diff changeset
2833 HOST_WIDE_INT total, max;
kono
parents:
diff changeset
2834 unsigned try_align = FASTEST_ALIGNMENT;
kono
parents:
diff changeset
2835
kono
parents:
diff changeset
2836 if (maximum_field_alignment && try_align > maximum_field_alignment)
kono
parents:
diff changeset
2837 try_align = maximum_field_alignment;
kono
parents:
diff changeset
2838 if (align >= try_align)
kono
parents:
diff changeset
2839 return align;
kono
parents:
diff changeset
2840 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
kono
parents:
diff changeset
2841 {
kono
parents:
diff changeset
2842 tree offset, size;
kono
parents:
diff changeset
2843
kono
parents:
diff changeset
2844 if (TREE_CODE (field) != FIELD_DECL
kono
parents:
diff changeset
2845 || TREE_TYPE (field) == error_mark_node)
kono
parents:
diff changeset
2846 continue;
kono
parents:
diff changeset
2847 offset = bit_position (field);
kono
parents:
diff changeset
2848 size = DECL_SIZE (field);
kono
parents:
diff changeset
2849 if (!tree_fits_uhwi_p (offset) || !tree_fits_uhwi_p (size)
kono
parents:
diff changeset
2850 || tree_to_uhwi (offset) >= try_align
kono
parents:
diff changeset
2851 || tree_to_uhwi (size) >= try_align)
kono
parents:
diff changeset
2852 return try_align;
kono
parents:
diff changeset
2853 total = tree_to_uhwi (offset) + tree_to_uhwi (size);
kono
parents:
diff changeset
2854 if (total > max)
kono
parents:
diff changeset
2855 max = total;
kono
parents:
diff changeset
2856 }
kono
parents:
diff changeset
2857 if (max >= (HOST_WIDE_INT) try_align)
kono
parents:
diff changeset
2858 align = try_align;
kono
parents:
diff changeset
2859 else if (try_align > 32 && max >= 32)
kono
parents:
diff changeset
2860 align = max > 32 ? 64 : 32;
kono
parents:
diff changeset
2861 return align;
kono
parents:
diff changeset
2862 }
kono
parents:
diff changeset
2863
kono
parents:
diff changeset
2864 /* Upping the alignment of arrays in structs is not only a performance
kono
parents:
diff changeset
2865 enhancement, it also helps preserve assumptions about how
kono
parents:
diff changeset
2866 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
kono
parents:
diff changeset
2867 libgcov.c . */
kono
parents:
diff changeset
2868 unsigned
kono
parents:
diff changeset
2869 epiphany_adjust_field_align (tree type, unsigned computed)
kono
parents:
diff changeset
2870 {
kono
parents:
diff changeset
2871 if (computed == 32
kono
parents:
diff changeset
2872 && TREE_CODE (type) == ARRAY_TYPE)
kono
parents:
diff changeset
2873 {
kono
parents:
diff changeset
2874 tree elmsz = TYPE_SIZE (TREE_TYPE (type));
kono
parents:
diff changeset
2875
kono
parents:
diff changeset
2876 if (!tree_fits_uhwi_p (elmsz) || tree_to_uhwi (elmsz) >= 32)
kono
parents:
diff changeset
2877 return 64;
kono
parents:
diff changeset
2878 }
kono
parents:
diff changeset
2879 return computed;
kono
parents:
diff changeset
2880 }
kono
parents:
diff changeset
2881
kono
parents:
diff changeset
2882 /* Output code to add DELTA to the first argument, and then jump
kono
parents:
diff changeset
2883 to FUNCTION. Used for C++ multiple inheritance. */
kono
parents:
diff changeset
2884 static void
kono
parents:
diff changeset
2885 epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2886 HOST_WIDE_INT delta,
kono
parents:
diff changeset
2887 HOST_WIDE_INT vcall_offset,
kono
parents:
diff changeset
2888 tree function)
kono
parents:
diff changeset
2889 {
kono
parents:
diff changeset
2890 int this_regno
kono
parents:
diff changeset
2891 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0;
kono
parents:
diff changeset
2892 const char *this_name = reg_names[this_regno];
kono
parents:
diff changeset
2893 const char *fname;
kono
parents:
diff changeset
2894
kono
parents:
diff changeset
2895 /* We use IP and R16 as a scratch registers. */
kono
parents:
diff changeset
2896 gcc_assert (call_used_regs [GPR_IP]);
kono
parents:
diff changeset
2897 gcc_assert (call_used_regs [GPR_16]);
kono
parents:
diff changeset
2898
kono
parents:
diff changeset
2899 /* Add DELTA. When possible use a plain add, otherwise load it into
kono
parents:
diff changeset
2900 a register first. */
kono
parents:
diff changeset
2901 if (delta == 0)
kono
parents:
diff changeset
2902 ; /* Done. */
kono
parents:
diff changeset
2903 else if (SIMM11 (delta))
kono
parents:
diff changeset
2904 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta);
kono
parents:
diff changeset
2905 else if (delta < 0 && delta >= -0xffff)
kono
parents:
diff changeset
2906 {
kono
parents:
diff changeset
2907 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta);
kono
parents:
diff changeset
2908 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name);
kono
parents:
diff changeset
2909 }
kono
parents:
diff changeset
2910 else
kono
parents:
diff changeset
2911 {
kono
parents:
diff changeset
2912 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta);
kono
parents:
diff changeset
2913 if (delta & ~0xffff)
kono
parents:
diff changeset
2914 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta);
kono
parents:
diff changeset
2915 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name);
kono
parents:
diff changeset
2916 }
kono
parents:
diff changeset
2917
kono
parents:
diff changeset
2918 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
kono
parents:
diff changeset
2919 if (vcall_offset != 0)
kono
parents:
diff changeset
2920 {
kono
parents:
diff changeset
2921 /* ldr ip,[this] --> temp = *this
kono
parents:
diff changeset
2922 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
kono
parents:
diff changeset
2923 add this,this,ip --> this+ = *(*this + vcall_offset) */
kono
parents:
diff changeset
2924 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name);
kono
parents:
diff changeset
2925 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4
kono
parents:
diff changeset
2926 || (vcall_offset & 3) != 0)
kono
parents:
diff changeset
2927 {
kono
parents:
diff changeset
2928 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset);
kono
parents:
diff changeset
2929 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset);
kono
parents:
diff changeset
2930 asm_fprintf (file, "\tldr\tip, [ip,r16]\n");
kono
parents:
diff changeset
2931 }
kono
parents:
diff changeset
2932 else
kono
parents:
diff changeset
2933 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4);
kono
parents:
diff changeset
2934 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name);
kono
parents:
diff changeset
2935 }
kono
parents:
diff changeset
2936
kono
parents:
diff changeset
2937 fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
kono
parents:
diff changeset
2938 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0)))
kono
parents:
diff changeset
2939 {
kono
parents:
diff changeset
2940 fputs ("\tmov\tip,%low(", file);
kono
parents:
diff changeset
2941 assemble_name (file, fname);
kono
parents:
diff changeset
2942 fputs (")\n\tmovt\tip,%high(", file);
kono
parents:
diff changeset
2943 assemble_name (file, fname);
kono
parents:
diff changeset
2944 fputs (")\n\tjr ip\n", file);
kono
parents:
diff changeset
2945 }
kono
parents:
diff changeset
2946 else
kono
parents:
diff changeset
2947 {
kono
parents:
diff changeset
2948 fputs ("\tb\t", file);
kono
parents:
diff changeset
2949 assemble_name (file, fname);
kono
parents:
diff changeset
2950 fputc ('\n', file);
kono
parents:
diff changeset
2951 }
kono
parents:
diff changeset
2952 }
kono
parents:
diff changeset
2953
kono
parents:
diff changeset
2954 void
kono
parents:
diff changeset
2955 epiphany_start_function (FILE *file, const char *name, tree decl)
kono
parents:
diff changeset
2956 {
kono
parents:
diff changeset
2957 /* If the function doesn't fit into the on-chip memory, it will have a
kono
parents:
diff changeset
2958 section attribute - or lack of it - that denotes it goes somewhere else.
kono
parents:
diff changeset
2959 But the architecture spec says that an interrupt vector still has to
kono
parents:
diff changeset
2960 point to on-chip memory. So we must place a jump there to get to the
kono
parents:
diff changeset
2961 actual function implementation. The forwarder_section attribute
kono
parents:
diff changeset
2962 specifies the section where this jump goes.
kono
parents:
diff changeset
2963 This mechanism can also be useful to have a shortcall destination for
kono
parents:
diff changeset
2964 a function that is actually placed much farther away. */
kono
parents:
diff changeset
2965 tree attrs, int_attr, int_names, int_name, forwarder_attr;
kono
parents:
diff changeset
2966
kono
parents:
diff changeset
2967 attrs = DECL_ATTRIBUTES (decl);
kono
parents:
diff changeset
2968 int_attr = lookup_attribute ("interrupt", attrs);
kono
parents:
diff changeset
2969 if (int_attr)
kono
parents:
diff changeset
2970 for (int_names = TREE_VALUE (int_attr); int_names;
kono
parents:
diff changeset
2971 int_names = TREE_CHAIN (int_names))
kono
parents:
diff changeset
2972 {
kono
parents:
diff changeset
2973 char buf[99];
kono
parents:
diff changeset
2974
kono
parents:
diff changeset
2975 int_name = TREE_VALUE (int_names);
kono
parents:
diff changeset
2976 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
kono
parents:
diff changeset
2977 switch_to_section (get_section (buf, SECTION_CODE, decl));
kono
parents:
diff changeset
2978 fputs ("\tb\t", file);
kono
parents:
diff changeset
2979 assemble_name (file, name);
kono
parents:
diff changeset
2980 fputc ('\n', file);
kono
parents:
diff changeset
2981 }
kono
parents:
diff changeset
2982 forwarder_attr = lookup_attribute ("forwarder_section", attrs);
kono
parents:
diff changeset
2983 if (forwarder_attr)
kono
parents:
diff changeset
2984 {
kono
parents:
diff changeset
2985 const char *prefix = "__forwarder_dst_";
kono
parents:
diff changeset
2986 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
kono
parents:
diff changeset
2987
kono
parents:
diff changeset
2988 strcpy (dst_name, prefix);
kono
parents:
diff changeset
2989 strcat (dst_name, name);
kono
parents:
diff changeset
2990 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
kono
parents:
diff changeset
2991 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
kono
parents:
diff changeset
2992 SECTION_CODE, decl));
kono
parents:
diff changeset
2993 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
kono
parents:
diff changeset
2994 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
kono
parents:
diff changeset
2995 {
kono
parents:
diff changeset
2996 int tmp = GPR_0;
kono
parents:
diff changeset
2997
kono
parents:
diff changeset
2998 if (int_attr)
kono
parents:
diff changeset
2999 fputs ("\tstrd r0,[sp,-1]\n", file);
kono
parents:
diff changeset
3000 else
kono
parents:
diff changeset
3001 tmp = GPR_16;
kono
parents:
diff changeset
3002 gcc_assert (call_used_regs[tmp]);
kono
parents:
diff changeset
3003 fprintf (file, "\tmov r%d,%%low(", tmp);
kono
parents:
diff changeset
3004 assemble_name (file, dst_name);
kono
parents:
diff changeset
3005 fprintf (file, ")\n"
kono
parents:
diff changeset
3006 "\tmovt r%d,%%high(", tmp);
kono
parents:
diff changeset
3007 assemble_name (file, dst_name);
kono
parents:
diff changeset
3008 fprintf (file, ")\n"
kono
parents:
diff changeset
3009 "\tjr r%d\n", tmp);
kono
parents:
diff changeset
3010 }
kono
parents:
diff changeset
3011 else
kono
parents:
diff changeset
3012 {
kono
parents:
diff changeset
3013 fputs ("\tb\t", file);
kono
parents:
diff changeset
3014 assemble_name (file, dst_name);
kono
parents:
diff changeset
3015 fputc ('\n', file);
kono
parents:
diff changeset
3016 }
kono
parents:
diff changeset
3017 name = dst_name;
kono
parents:
diff changeset
3018 }
kono
parents:
diff changeset
3019 switch_to_section (function_section (decl));
kono
parents:
diff changeset
3020 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
kono
parents:
diff changeset
3021 }
kono
parents:
diff changeset
3022
kono
parents:
diff changeset
3023
kono
parents:
diff changeset
3024 /* Implement TARGET_CONSTANT_ALIGNMENT. */
kono
parents:
diff changeset
3025
kono
parents:
diff changeset
3026 static HOST_WIDE_INT
kono
parents:
diff changeset
3027 epiphany_constant_alignment (const_tree exp, HOST_WIDE_INT align)
kono
parents:
diff changeset
3028 {
kono
parents:
diff changeset
3029 if (TREE_CODE (exp) == STRING_CST)
kono
parents:
diff changeset
3030 return MAX (align, FASTEST_ALIGNMENT);
kono
parents:
diff changeset
3031 return align;
kono
parents:
diff changeset
3032 }
kono
parents:
diff changeset
3033
kono
parents:
diff changeset
3034 /* Implement TARGET_STARTING_FRAME_OFFSET. */
kono
parents:
diff changeset
3035
kono
parents:
diff changeset
3036 static HOST_WIDE_INT
kono
parents:
diff changeset
3037 epiphany_starting_frame_offset (void)
kono
parents:
diff changeset
3038 {
kono
parents:
diff changeset
3039 return epiphany_stack_offset;
kono
parents:
diff changeset
3040 }
kono
parents:
diff changeset
3041
kono
parents:
diff changeset
3042 struct gcc_target targetm = TARGET_INITIALIZER;