Mercurial > hg > CbC > CbC_gcc
annotate gcc/config/arc/arc.c @ 63:b7f97abdc517 gcc-4.6-20100522
update gcc from gcc-4.5.0 to gcc-4.6
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 24 May 2010 12:47:05 +0900 |
parents | 77e2b8dfacca |
children | f6334be47118 |
rev | line source |
---|---|
0 | 1 /* Subroutines used for code generation on the Argonaut ARC cpu. |
2 Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
3 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
0 | 4 |
5 This file is part of GCC. | |
6 | |
7 GCC is free software; you can redistribute it and/or modify | |
8 it under the terms of the GNU General Public License as published by | |
9 the Free Software Foundation; either version 3, or (at your option) | |
10 any later version. | |
11 | |
12 GCC is distributed in the hope that it will be useful, | |
13 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 GNU General Public License for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with GCC; see the file COPYING3. If not see | |
19 <http://www.gnu.org/licenses/>. */ | |
20 | |
21 /* ??? This is an old port, and is undoubtedly suffering from bit rot. */ | |
22 | |
23 #include "config.h" | |
24 #include "system.h" | |
25 #include "coretypes.h" | |
26 #include "tm.h" | |
27 #include "tree.h" | |
28 #include "rtl.h" | |
29 #include "regs.h" | |
30 #include "hard-reg-set.h" | |
31 #include "insn-config.h" | |
32 #include "conditions.h" | |
33 #include "output.h" | |
34 #include "insn-attr.h" | |
35 #include "flags.h" | |
36 #include "function.h" | |
37 #include "expr.h" | |
38 #include "recog.h" | |
39 #include "toplev.h" | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
40 #include "df.h" |
0 | 41 #include "tm_p.h" |
42 #include "target.h" | |
43 #include "target-def.h" | |
44 | |
45 /* Which cpu we're compiling for. */ | |
46 int arc_cpu_type; | |
47 | |
48 /* Name of mangle string to add to symbols to separate code compiled for each | |
49 cpu (or NULL). */ | |
50 const char *arc_mangle_cpu; | |
51 | |
52 /* Name of text, data, and rodata sections used in varasm.c. */ | |
53 const char *arc_text_section; | |
54 const char *arc_data_section; | |
55 const char *arc_rodata_section; | |
56 | |
57 /* Array of valid operand punctuation characters. */ | |
58 char arc_punct_chars[256]; | |
59 | |
60 /* Variables used by arc_final_prescan_insn to implement conditional | |
61 execution. */ | |
62 static int arc_ccfsm_state; | |
63 static int arc_ccfsm_current_cc; | |
64 static rtx arc_ccfsm_target_insn; | |
65 static int arc_ccfsm_target_label; | |
66 | |
67 /* The maximum number of insns skipped which will be conditionalised if | |
68 possible. */ | |
69 #define MAX_INSNS_SKIPPED 3 | |
70 | |
71 /* A nop is needed between a 4 byte insn that sets the condition codes and | |
72 a branch that uses them (the same isn't true for an 8 byte insn that sets | |
73 the condition codes). Set by arc_final_prescan_insn. Used by | |
74 arc_print_operand. */ | |
75 static int last_insn_set_cc_p; | |
76 static int current_insn_set_cc_p; | |
77 static bool arc_handle_option (size_t, const char *, int); | |
78 static void record_cc_ref (rtx); | |
79 static void arc_init_reg_tables (void); | |
80 static int get_arc_condition_code (rtx); | |
81 static tree arc_handle_interrupt_attribute (tree *, tree, tree, int, bool *); | |
82 static bool arc_assemble_integer (rtx, unsigned int, int); | |
83 static void arc_output_function_prologue (FILE *, HOST_WIDE_INT); | |
84 static void arc_output_function_epilogue (FILE *, HOST_WIDE_INT); | |
85 static void arc_file_start (void); | |
86 static void arc_internal_label (FILE *, const char *, unsigned long); | |
87 static void arc_va_start (tree, rtx); | |
88 static void arc_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, | |
89 tree, int *, int); | |
90 static bool arc_rtx_costs (rtx, int, int, int *, bool); | |
91 static int arc_address_cost (rtx, bool); | |
92 static void arc_external_libcall (rtx); | |
93 static bool arc_return_in_memory (const_tree, const_tree); | |
94 static bool arc_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, | |
95 const_tree, bool); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
96 static void arc_trampoline_init (rtx, tree, rtx); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
97 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
98 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
99 /* ARC specific attributs. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
100 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
101 static const struct attribute_spec arc_attribute_table[] = |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
102 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
103 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
104 { "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute }, |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
105 { NULL, 0, 0, false, false, false, NULL } |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
106 }; |
0 | 107 |
108 /* Initialize the GCC target structure. */ | |
109 #undef TARGET_ASM_ALIGNED_HI_OP | |
110 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t" | |
111 #undef TARGET_ASM_ALIGNED_SI_OP | |
112 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" | |
113 #undef TARGET_ASM_INTEGER | |
114 #define TARGET_ASM_INTEGER arc_assemble_integer | |
115 | |
116 #undef TARGET_ASM_FUNCTION_PROLOGUE | |
117 #define TARGET_ASM_FUNCTION_PROLOGUE arc_output_function_prologue | |
118 #undef TARGET_ASM_FUNCTION_EPILOGUE | |
119 #define TARGET_ASM_FUNCTION_EPILOGUE arc_output_function_epilogue | |
120 #undef TARGET_ASM_FILE_START | |
121 #define TARGET_ASM_FILE_START arc_file_start | |
122 #undef TARGET_ATTRIBUTE_TABLE | |
123 #define TARGET_ATTRIBUTE_TABLE arc_attribute_table | |
124 #undef TARGET_ASM_INTERNAL_LABEL | |
125 #define TARGET_ASM_INTERNAL_LABEL arc_internal_label | |
126 #undef TARGET_ASM_EXTERNAL_LIBCALL | |
127 #define TARGET_ASM_EXTERNAL_LIBCALL arc_external_libcall | |
128 | |
129 #undef TARGET_HANDLE_OPTION | |
130 #define TARGET_HANDLE_OPTION arc_handle_option | |
131 | |
132 #undef TARGET_RTX_COSTS | |
133 #define TARGET_RTX_COSTS arc_rtx_costs | |
134 #undef TARGET_ADDRESS_COST | |
135 #define TARGET_ADDRESS_COST arc_address_cost | |
136 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
137 #undef TARGET_PROMOTE_FUNCTION_MODE |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
138 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote |
0 | 139 #undef TARGET_PROMOTE_PROTOTYPES |
140 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true | |
141 | |
142 #undef TARGET_RETURN_IN_MEMORY | |
143 #define TARGET_RETURN_IN_MEMORY arc_return_in_memory | |
144 #undef TARGET_PASS_BY_REFERENCE | |
145 #define TARGET_PASS_BY_REFERENCE arc_pass_by_reference | |
146 #undef TARGET_CALLEE_COPIES | |
147 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true | |
148 | |
149 #undef TARGET_SETUP_INCOMING_VARARGS | |
150 #define TARGET_SETUP_INCOMING_VARARGS arc_setup_incoming_varargs | |
151 | |
152 #undef TARGET_EXPAND_BUILTIN_VA_START | |
153 #define TARGET_EXPAND_BUILTIN_VA_START arc_va_start | |
154 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
155 #undef TARGET_TRAMPOLINE_INIT |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
156 #define TARGET_TRAMPOLINE_INIT arc_trampoline_init |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
157 |
0 | 158 struct gcc_target targetm = TARGET_INITIALIZER; |
159 | |
160 /* Implement TARGET_HANDLE_OPTION. */ | |
161 | |
162 static bool | |
163 arc_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED) | |
164 { | |
165 switch (code) | |
166 { | |
167 case OPT_mcpu_: | |
168 return strcmp (arg, "base") == 0 || ARC_EXTENSION_CPU (arg); | |
169 | |
170 default: | |
171 return true; | |
172 } | |
173 } | |
174 | |
175 /* Called by OVERRIDE_OPTIONS to initialize various things. */ | |
176 | |
177 void | |
178 arc_init (void) | |
179 { | |
180 char *tmp; | |
181 | |
182 /* Set the pseudo-ops for the various standard sections. */ | |
183 arc_text_section = tmp = XNEWVEC (char, strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1); | |
184 sprintf (tmp, ARC_SECTION_FORMAT, arc_text_string); | |
185 arc_data_section = tmp = XNEWVEC (char, strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1); | |
186 sprintf (tmp, ARC_SECTION_FORMAT, arc_data_string); | |
187 arc_rodata_section = tmp = XNEWVEC (char, strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1); | |
188 sprintf (tmp, ARC_SECTION_FORMAT, arc_rodata_string); | |
189 | |
190 arc_init_reg_tables (); | |
191 | |
192 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */ | |
193 memset (arc_punct_chars, 0, sizeof (arc_punct_chars)); | |
194 arc_punct_chars['#'] = 1; | |
195 arc_punct_chars['*'] = 1; | |
196 arc_punct_chars['?'] = 1; | |
197 arc_punct_chars['!'] = 1; | |
198 arc_punct_chars['~'] = 1; | |
199 } | |
200 | |
201 /* The condition codes of the ARC, and the inverse function. */ | |
202 static const char *const arc_condition_codes[] = | |
203 { | |
204 "al", 0, "eq", "ne", "p", "n", "c", "nc", "v", "nv", | |
205 "gt", "le", "ge", "lt", "hi", "ls", "pnz", 0 | |
206 }; | |
207 | |
208 #define ARC_INVERSE_CONDITION_CODE(X) ((X) ^ 1) | |
209 | |
210 /* Returns the index of the ARC condition code string in | |
211 `arc_condition_codes'. COMPARISON should be an rtx like | |
212 `(eq (...) (...))'. */ | |
213 | |
214 static int | |
215 get_arc_condition_code (rtx comparison) | |
216 { | |
217 switch (GET_CODE (comparison)) | |
218 { | |
219 case EQ : return 2; | |
220 case NE : return 3; | |
221 case GT : return 10; | |
222 case LE : return 11; | |
223 case GE : return 12; | |
224 case LT : return 13; | |
225 case GTU : return 14; | |
226 case LEU : return 15; | |
227 case LTU : return 6; | |
228 case GEU : return 7; | |
229 default : gcc_unreachable (); | |
230 } | |
231 /*NOTREACHED*/ | |
232 return (42); | |
233 } | |
234 | |
235 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, | |
236 return the mode to be used for the comparison. */ | |
237 | |
238 enum machine_mode | |
239 arc_select_cc_mode (enum rtx_code op, | |
240 rtx x ATTRIBUTE_UNUSED, | |
241 rtx y ATTRIBUTE_UNUSED) | |
242 { | |
243 switch (op) | |
244 { | |
245 case EQ : | |
246 case NE : | |
247 return CCZNmode; | |
248 default : | |
249 switch (GET_CODE (x)) | |
250 { | |
251 case AND : | |
252 case IOR : | |
253 case XOR : | |
254 case SIGN_EXTEND : | |
255 case ZERO_EXTEND : | |
256 return CCZNmode; | |
257 case ASHIFT : | |
258 case ASHIFTRT : | |
259 case LSHIFTRT : | |
260 return CCZNCmode; | |
261 default: | |
262 break; | |
263 } | |
264 } | |
265 return CCmode; | |
266 } | |
267 | |
268 /* Vectors to keep interesting information about registers where it can easily | |
269 be got. We use to use the actual mode value as the bit number, but there | |
270 is (or may be) more than 32 modes now. Instead we use two tables: one | |
271 indexed by hard register number, and one indexed by mode. */ | |
272 | |
273 /* The purpose of arc_mode_class is to shrink the range of modes so that | |
274 they all fit (as bit numbers) in a 32-bit word (again). Each real mode is | |
275 mapped into one arc_mode_class mode. */ | |
276 | |
277 enum arc_mode_class { | |
278 C_MODE, | |
279 S_MODE, D_MODE, T_MODE, O_MODE, | |
280 SF_MODE, DF_MODE, TF_MODE, OF_MODE | |
281 }; | |
282 | |
283 /* Modes for condition codes. */ | |
284 #define C_MODES (1 << (int) C_MODE) | |
285 | |
286 /* Modes for single-word and smaller quantities. */ | |
287 #define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE)) | |
288 | |
289 /* Modes for double-word and smaller quantities. */ | |
290 #define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE)) | |
291 | |
292 /* Modes for quad-word and smaller quantities. */ | |
293 #define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE)) | |
294 | |
295 /* Value is 1 if register/mode pair is acceptable on arc. */ | |
296 | |
297 const unsigned int arc_hard_regno_mode_ok[] = { | |
298 T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, | |
299 T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, | |
300 T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, D_MODES, | |
301 D_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, | |
302 | |
303 /* ??? Leave these as S_MODES for now. */ | |
304 S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, | |
305 S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, | |
306 S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, | |
307 S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, C_MODES | |
308 }; | |
309 | |
310 unsigned int arc_mode_class [NUM_MACHINE_MODES]; | |
311 | |
312 enum reg_class arc_regno_reg_class[FIRST_PSEUDO_REGISTER]; | |
313 | |
314 static void | |
315 arc_init_reg_tables (void) | |
316 { | |
317 int i; | |
318 | |
319 for (i = 0; i < NUM_MACHINE_MODES; i++) | |
320 { | |
321 switch (GET_MODE_CLASS (i)) | |
322 { | |
323 case MODE_INT: | |
324 case MODE_PARTIAL_INT: | |
325 case MODE_COMPLEX_INT: | |
326 if (GET_MODE_SIZE (i) <= 4) | |
327 arc_mode_class[i] = 1 << (int) S_MODE; | |
328 else if (GET_MODE_SIZE (i) == 8) | |
329 arc_mode_class[i] = 1 << (int) D_MODE; | |
330 else if (GET_MODE_SIZE (i) == 16) | |
331 arc_mode_class[i] = 1 << (int) T_MODE; | |
332 else if (GET_MODE_SIZE (i) == 32) | |
333 arc_mode_class[i] = 1 << (int) O_MODE; | |
334 else | |
335 arc_mode_class[i] = 0; | |
336 break; | |
337 case MODE_FLOAT: | |
338 case MODE_COMPLEX_FLOAT: | |
339 if (GET_MODE_SIZE (i) <= 4) | |
340 arc_mode_class[i] = 1 << (int) SF_MODE; | |
341 else if (GET_MODE_SIZE (i) == 8) | |
342 arc_mode_class[i] = 1 << (int) DF_MODE; | |
343 else if (GET_MODE_SIZE (i) == 16) | |
344 arc_mode_class[i] = 1 << (int) TF_MODE; | |
345 else if (GET_MODE_SIZE (i) == 32) | |
346 arc_mode_class[i] = 1 << (int) OF_MODE; | |
347 else | |
348 arc_mode_class[i] = 0; | |
349 break; | |
350 case MODE_CC: | |
351 arc_mode_class[i] = 1 << (int) C_MODE; | |
352 break; | |
353 default: | |
354 arc_mode_class[i] = 0; | |
355 break; | |
356 } | |
357 } | |
358 | |
359 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
360 { | |
361 if (i < 60) | |
362 arc_regno_reg_class[i] = GENERAL_REGS; | |
363 else if (i == 60) | |
364 arc_regno_reg_class[i] = LPCOUNT_REG; | |
365 else if (i == 61) | |
366 arc_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */; | |
367 else | |
368 arc_regno_reg_class[i] = NO_REGS; | |
369 } | |
370 } | |
371 | |
372 /* ARC specific attribute support. | |
373 | |
374 The ARC has these attributes: | |
375 interrupt - for interrupt functions | |
376 */ | |
377 | |
378 /* Handle an "interrupt" attribute; arguments as in | |
379 struct attribute_spec.handler. */ | |
380 static tree | |
381 arc_handle_interrupt_attribute (tree *node ATTRIBUTE_UNUSED, | |
382 tree name, | |
383 tree args, | |
384 int flags ATTRIBUTE_UNUSED, | |
385 bool *no_add_attrs) | |
386 { | |
387 tree value = TREE_VALUE (args); | |
388 | |
389 if (TREE_CODE (value) != STRING_CST) | |
390 { | |
391 warning (OPT_Wattributes, | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
392 "argument of %qE attribute is not a string constant", |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
393 name); |
0 | 394 *no_add_attrs = true; |
395 } | |
396 else if (strcmp (TREE_STRING_POINTER (value), "ilink1") | |
397 && strcmp (TREE_STRING_POINTER (value), "ilink2")) | |
398 { | |
399 warning (OPT_Wattributes, | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
400 "argument of %qE attribute is not \"ilink1\" or \"ilink2\"", |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
401 name); |
0 | 402 *no_add_attrs = true; |
403 } | |
404 | |
405 return NULL_TREE; | |
406 } | |
407 | |
408 | |
409 /* Acceptable arguments to the call insn. */ | |
410 | |
411 int | |
412 call_address_operand (rtx op, enum machine_mode mode) | |
413 { | |
414 return (symbolic_operand (op, mode) | |
415 || (GET_CODE (op) == CONST_INT && LEGITIMATE_CONSTANT_P (op)) | |
416 || (GET_CODE (op) == REG)); | |
417 } | |
418 | |
419 int | |
420 call_operand (rtx op, enum machine_mode mode) | |
421 { | |
422 if (GET_CODE (op) != MEM) | |
423 return 0; | |
424 op = XEXP (op, 0); | |
425 return call_address_operand (op, mode); | |
426 } | |
427 | |
428 /* Returns 1 if OP is a symbol reference. */ | |
429 | |
430 int | |
431 symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
432 { | |
433 switch (GET_CODE (op)) | |
434 { | |
435 case SYMBOL_REF: | |
436 case LABEL_REF: | |
437 case CONST : | |
438 return 1; | |
439 default: | |
440 return 0; | |
441 } | |
442 } | |
443 | |
444 /* Return truth value of statement that OP is a symbolic memory | |
445 operand of mode MODE. */ | |
446 | |
447 int | |
448 symbolic_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
449 { | |
450 if (GET_CODE (op) == SUBREG) | |
451 op = SUBREG_REG (op); | |
452 if (GET_CODE (op) != MEM) | |
453 return 0; | |
454 op = XEXP (op, 0); | |
455 return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST | |
456 || GET_CODE (op) == LABEL_REF); | |
457 } | |
458 | |
459 /* Return true if OP is a short immediate (shimm) value. */ | |
460 | |
461 int | |
462 short_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
463 { | |
464 if (GET_CODE (op) != CONST_INT) | |
465 return 0; | |
466 return SMALL_INT (INTVAL (op)); | |
467 } | |
468 | |
469 /* Return true if OP will require a long immediate (limm) value. | |
470 This is currently only used when calculating length attributes. */ | |
471 | |
472 int | |
473 long_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
474 { | |
475 switch (GET_CODE (op)) | |
476 { | |
477 case SYMBOL_REF : | |
478 case LABEL_REF : | |
479 case CONST : | |
480 return 1; | |
481 case CONST_INT : | |
482 return !SMALL_INT (INTVAL (op)); | |
483 case CONST_DOUBLE : | |
484 /* These can happen because large unsigned 32-bit constants are | |
485 represented this way (the multiplication patterns can cause these | |
486 to be generated). They also occur for SFmode values. */ | |
487 return 1; | |
488 default: | |
489 break; | |
490 } | |
491 return 0; | |
492 } | |
493 | |
494 /* Return true if OP is a MEM that when used as a load or store address will | |
495 require an 8 byte insn. | |
496 Load and store instructions don't allow the same possibilities but they're | |
497 similar enough that this one function will do. | |
498 This is currently only used when calculating length attributes. */ | |
499 | |
500 int | |
501 long_immediate_loadstore_operand (rtx op, | |
502 enum machine_mode mode ATTRIBUTE_UNUSED) | |
503 { | |
504 if (GET_CODE (op) != MEM) | |
505 return 0; | |
506 | |
507 op = XEXP (op, 0); | |
508 switch (GET_CODE (op)) | |
509 { | |
510 case SYMBOL_REF : | |
511 case LABEL_REF : | |
512 case CONST : | |
513 return 1; | |
514 case CONST_INT : | |
515 /* This must be handled as "st c,[limm]". Ditto for load. | |
516 Technically, the assembler could translate some possibilities to | |
517 "st c,[limm/2 + limm/2]" if limm/2 will fit in a shimm, but we don't | |
518 assume that it does. */ | |
519 return 1; | |
520 case CONST_DOUBLE : | |
521 /* These can happen because large unsigned 32-bit constants are | |
522 represented this way (the multiplication patterns can cause these | |
523 to be generated). They also occur for SFmode values. */ | |
524 return 1; | |
525 case REG : | |
526 return 0; | |
527 case PLUS : | |
528 if (GET_CODE (XEXP (op, 1)) == CONST_INT | |
529 && !SMALL_INT (INTVAL (XEXP (op, 1)))) | |
530 return 1; | |
531 return 0; | |
532 default: | |
533 break; | |
534 } | |
535 return 0; | |
536 } | |
537 | |
538 /* Return true if OP is an acceptable argument for a single word | |
539 move source. */ | |
540 | |
541 int | |
542 move_src_operand (rtx op, enum machine_mode mode) | |
543 { | |
544 switch (GET_CODE (op)) | |
545 { | |
546 case SYMBOL_REF : | |
547 case LABEL_REF : | |
548 case CONST : | |
549 return 1; | |
550 case CONST_INT : | |
551 return (LARGE_INT (INTVAL (op))); | |
552 case CONST_DOUBLE : | |
553 /* We can handle DImode integer constants in SImode if the value | |
554 (signed or unsigned) will fit in 32 bits. This is needed because | |
555 large unsigned 32-bit constants are represented as CONST_DOUBLEs. */ | |
556 if (mode == SImode) | |
557 return arc_double_limm_p (op); | |
558 /* We can handle 32-bit floating point constants. */ | |
559 if (mode == SFmode) | |
560 return GET_MODE (op) == SFmode; | |
561 return 0; | |
562 case REG : | |
563 return register_operand (op, mode); | |
564 case SUBREG : | |
565 /* (subreg (mem ...) ...) can occur here if the inner part was once a | |
566 pseudo-reg and is now a stack slot. */ | |
567 if (GET_CODE (SUBREG_REG (op)) == MEM) | |
568 return address_operand (XEXP (SUBREG_REG (op), 0), mode); | |
569 else | |
570 return register_operand (op, mode); | |
571 case MEM : | |
572 return address_operand (XEXP (op, 0), mode); | |
573 default : | |
574 return 0; | |
575 } | |
576 } | |
577 | |
578 /* Return true if OP is an acceptable argument for a double word | |
579 move source. */ | |
580 | |
581 int | |
582 move_double_src_operand (rtx op, enum machine_mode mode) | |
583 { | |
584 switch (GET_CODE (op)) | |
585 { | |
586 case REG : | |
587 return register_operand (op, mode); | |
588 case SUBREG : | |
589 /* (subreg (mem ...) ...) can occur here if the inner part was once a | |
590 pseudo-reg and is now a stack slot. */ | |
591 if (GET_CODE (SUBREG_REG (op)) == MEM) | |
592 return move_double_src_operand (SUBREG_REG (op), mode); | |
593 else | |
594 return register_operand (op, mode); | |
595 case MEM : | |
596 /* Disallow auto inc/dec for now. */ | |
597 if (GET_CODE (XEXP (op, 0)) == PRE_DEC | |
598 || GET_CODE (XEXP (op, 0)) == PRE_INC) | |
599 return 0; | |
600 return address_operand (XEXP (op, 0), mode); | |
601 case CONST_INT : | |
602 case CONST_DOUBLE : | |
603 return 1; | |
604 default : | |
605 return 0; | |
606 } | |
607 } | |
608 | |
609 /* Return true if OP is an acceptable argument for a move destination. */ | |
610 | |
611 int | |
612 move_dest_operand (rtx op, enum machine_mode mode) | |
613 { | |
614 switch (GET_CODE (op)) | |
615 { | |
616 case REG : | |
617 return register_operand (op, mode); | |
618 case SUBREG : | |
619 /* (subreg (mem ...) ...) can occur here if the inner part was once a | |
620 pseudo-reg and is now a stack slot. */ | |
621 if (GET_CODE (SUBREG_REG (op)) == MEM) | |
622 return address_operand (XEXP (SUBREG_REG (op), 0), mode); | |
623 else | |
624 return register_operand (op, mode); | |
625 case MEM : | |
626 return address_operand (XEXP (op, 0), mode); | |
627 default : | |
628 return 0; | |
629 } | |
630 } | |
631 | |
632 /* Return true if OP is valid load with update operand. */ | |
633 | |
634 int | |
635 load_update_operand (rtx op, enum machine_mode mode) | |
636 { | |
637 if (GET_CODE (op) != MEM | |
638 || GET_MODE (op) != mode) | |
639 return 0; | |
640 op = XEXP (op, 0); | |
641 if (GET_CODE (op) != PLUS | |
642 || GET_MODE (op) != Pmode | |
643 || !register_operand (XEXP (op, 0), Pmode) | |
644 || !nonmemory_operand (XEXP (op, 1), Pmode)) | |
645 return 0; | |
646 return 1; | |
647 } | |
648 | |
649 /* Return true if OP is valid store with update operand. */ | |
650 | |
651 int | |
652 store_update_operand (rtx op, enum machine_mode mode) | |
653 { | |
654 if (GET_CODE (op) != MEM | |
655 || GET_MODE (op) != mode) | |
656 return 0; | |
657 op = XEXP (op, 0); | |
658 if (GET_CODE (op) != PLUS | |
659 || GET_MODE (op) != Pmode | |
660 || !register_operand (XEXP (op, 0), Pmode) | |
661 || !(GET_CODE (XEXP (op, 1)) == CONST_INT | |
662 && SMALL_INT (INTVAL (XEXP (op, 1))))) | |
663 return 0; | |
664 return 1; | |
665 } | |
666 | |
667 /* Return true if OP is a non-volatile non-immediate operand. | |
668 Volatile memory refs require a special "cache-bypass" instruction | |
669 and only the standard movXX patterns are set up to handle them. */ | |
670 | |
671 int | |
672 nonvol_nonimm_operand (rtx op, enum machine_mode mode) | |
673 { | |
674 if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op)) | |
675 return 0; | |
676 return nonimmediate_operand (op, mode); | |
677 } | |
678 | |
679 /* Accept integer operands in the range -0x80000000..0x7fffffff. We have | |
680 to check the range carefully since this predicate is used in DImode | |
681 contexts. */ | |
682 | |
683 int | |
684 const_sint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
685 { | |
686 /* All allowed constants will fit a CONST_INT. */ | |
687 return (GET_CODE (op) == CONST_INT | |
688 && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff)); | |
689 } | |
690 | |
691 /* Accept integer operands in the range 0..0xffffffff. We have to check the | |
692 range carefully since this predicate is used in DImode contexts. Also, we | |
693 need some extra crud to make it work when hosted on 64-bit machines. */ | |
694 | |
695 int | |
696 const_uint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
697 { | |
698 #if HOST_BITS_PER_WIDE_INT > 32 | |
699 /* All allowed constants will fit a CONST_INT. */ | |
700 return (GET_CODE (op) == CONST_INT | |
701 && (INTVAL (op) >= 0 && INTVAL (op) <= 0xffffffffL)); | |
702 #else | |
703 return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0) | |
704 || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0)); | |
705 #endif | |
706 } | |
707 | |
708 /* Return 1 if OP is a comparison operator valid for the mode of CC. | |
709 This allows the use of MATCH_OPERATOR to recognize all the branch insns. | |
710 | |
711 Some insns only set a few bits in the condition code. So only allow those | |
712 comparisons that use the bits that are valid. */ | |
713 | |
714 int | |
715 proper_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
716 { | |
717 enum rtx_code code; | |
718 if (!COMPARISON_P (op)) | |
719 return 0; | |
720 | |
721 code = GET_CODE (op); | |
722 if (GET_MODE (XEXP (op, 0)) == CCZNmode) | |
723 return (code == EQ || code == NE); | |
724 if (GET_MODE (XEXP (op, 0)) == CCZNCmode) | |
725 return (code == EQ || code == NE | |
726 || code == LTU || code == GEU || code == GTU || code == LEU); | |
727 return 1; | |
728 } | |
729 | |
730 /* Misc. utilities. */ | |
731 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
732 /* X and Y are two things to compare using CODE. Return the rtx |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
733 for the cc reg in the proper mode. */ |
0 | 734 |
735 rtx | |
736 gen_compare_reg (enum rtx_code code, rtx x, rtx y) | |
737 { | |
738 enum machine_mode mode = SELECT_CC_MODE (code, x, y); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
739 return gen_rtx_REG (mode, 61); |
0 | 740 } |
741 | |
742 /* Return 1 if VALUE, a const_double, will fit in a limm (4 byte number). | |
743 We assume the value can be either signed or unsigned. */ | |
744 | |
745 int | |
746 arc_double_limm_p (rtx value) | |
747 { | |
748 HOST_WIDE_INT low, high; | |
749 | |
750 gcc_assert (GET_CODE (value) == CONST_DOUBLE); | |
751 | |
752 low = CONST_DOUBLE_LOW (value); | |
753 high = CONST_DOUBLE_HIGH (value); | |
754 | |
755 if (low & 0x80000000) | |
756 { | |
757 return (((unsigned HOST_WIDE_INT) low <= 0xffffffff && high == 0) | |
758 || (((low & - (unsigned HOST_WIDE_INT) 0x80000000) | |
759 == - (unsigned HOST_WIDE_INT) 0x80000000) | |
760 && high == -1)); | |
761 } | |
762 else | |
763 { | |
764 return (unsigned HOST_WIDE_INT) low <= 0x7fffffff && high == 0; | |
765 } | |
766 } | |
767 | |
768 /* Do any needed setup for a variadic function. For the ARC, we must | |
769 create a register parameter block, and then copy any anonymous arguments | |
770 in registers to memory. | |
771 | |
772 CUM has not been updated for the last named argument which has type TYPE | |
773 and mode MODE, and we rely on this fact. | |
774 | |
775 We do things a little weird here. We're supposed to only allocate space | |
776 for the anonymous arguments. However we need to keep the stack eight byte | |
777 aligned. So we round the space up if necessary, and leave it to va_start | |
778 to compensate. */ | |
779 | |
780 static void | |
781 arc_setup_incoming_varargs (CUMULATIVE_ARGS *cum, | |
782 enum machine_mode mode, | |
783 tree type ATTRIBUTE_UNUSED, | |
784 int *pretend_size, | |
785 int no_rtl) | |
786 { | |
787 int first_anon_arg; | |
788 | |
789 /* All BLKmode values are passed by reference. */ | |
790 gcc_assert (mode != BLKmode); | |
791 | |
792 first_anon_arg = *cum + ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) | |
793 / UNITS_PER_WORD); | |
794 | |
795 if (first_anon_arg < MAX_ARC_PARM_REGS && !no_rtl) | |
796 { | |
797 /* Note that first_reg_offset < MAX_ARC_PARM_REGS. */ | |
798 int first_reg_offset = first_anon_arg; | |
799 /* Size in words to "pretend" allocate. */ | |
800 int size = MAX_ARC_PARM_REGS - first_reg_offset; | |
801 /* Extra slop to keep stack eight byte aligned. */ | |
802 int align_slop = size & 1; | |
803 rtx regblock; | |
804 | |
805 regblock = gen_rtx_MEM (BLKmode, | |
806 plus_constant (arg_pointer_rtx, | |
807 FIRST_PARM_OFFSET (0) | |
808 + align_slop * UNITS_PER_WORD)); | |
809 set_mem_alias_set (regblock, get_varargs_alias_set ()); | |
810 set_mem_align (regblock, BITS_PER_WORD); | |
811 move_block_from_reg (first_reg_offset, regblock, | |
812 MAX_ARC_PARM_REGS - first_reg_offset); | |
813 | |
814 *pretend_size = ((MAX_ARC_PARM_REGS - first_reg_offset + align_slop) | |
815 * UNITS_PER_WORD); | |
816 } | |
817 } | |
818 | |
819 /* Cost functions. */ | |
820 | |
821 /* Compute a (partial) cost for rtx X. Return true if the complete | |
822 cost has been computed, and false if subexpressions should be | |
823 scanned. In either case, *TOTAL contains the cost result. */ | |
824 | |
825 static bool | |
826 arc_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total, | |
827 bool speed ATTRIBUTE_UNUSED) | |
828 { | |
829 switch (code) | |
830 { | |
831 /* Small integers are as cheap as registers. 4 byte values can | |
832 be fetched as immediate constants - let's give that the cost | |
833 of an extra insn. */ | |
834 case CONST_INT: | |
835 if (SMALL_INT (INTVAL (x))) | |
836 { | |
837 *total = 0; | |
838 return true; | |
839 } | |
840 /* FALLTHRU */ | |
841 | |
842 case CONST: | |
843 case LABEL_REF: | |
844 case SYMBOL_REF: | |
845 *total = COSTS_N_INSNS (1); | |
846 return true; | |
847 | |
848 case CONST_DOUBLE: | |
849 { | |
850 rtx high, low; | |
851 split_double (x, &high, &low); | |
852 *total = COSTS_N_INSNS (!SMALL_INT (INTVAL (high)) | |
853 + !SMALL_INT (INTVAL (low))); | |
854 return true; | |
855 } | |
856 | |
857 /* Encourage synth_mult to find a synthetic multiply when reasonable. | |
858 If we need more than 12 insns to do a multiply, then go out-of-line, | |
859 since the call overhead will be < 10% of the cost of the multiply. */ | |
860 case ASHIFT: | |
861 case ASHIFTRT: | |
862 case LSHIFTRT: | |
863 if (TARGET_SHIFTER) | |
864 *total = COSTS_N_INSNS (1); | |
865 else if (GET_CODE (XEXP (x, 1)) != CONST_INT) | |
866 *total = COSTS_N_INSNS (16); | |
867 else | |
868 *total = COSTS_N_INSNS (INTVAL (XEXP ((x), 1))); | |
869 return false; | |
870 | |
871 default: | |
872 return false; | |
873 } | |
874 } | |
875 | |
876 | |
877 /* Provide the costs of an addressing mode that contains ADDR. | |
878 If ADDR is not a valid address, its cost is irrelevant. */ | |
879 | |
880 static int | |
881 arc_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED) | |
882 { | |
883 switch (GET_CODE (addr)) | |
884 { | |
885 case REG : | |
886 return 1; | |
887 | |
888 case LABEL_REF : | |
889 case SYMBOL_REF : | |
890 case CONST : | |
891 return 2; | |
892 | |
893 case PLUS : | |
894 { | |
895 register rtx plus0 = XEXP (addr, 0); | |
896 register rtx plus1 = XEXP (addr, 1); | |
897 | |
898 if (GET_CODE (plus0) != REG) | |
899 break; | |
900 | |
901 switch (GET_CODE (plus1)) | |
902 { | |
903 case CONST_INT : | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
904 return SMALL_INT (INTVAL (plus1)) ? 1 : 2; |
0 | 905 case CONST : |
906 case SYMBOL_REF : | |
907 case LABEL_REF : | |
908 return 2; | |
909 default: | |
910 break; | |
911 } | |
912 break; | |
913 } | |
914 default: | |
915 break; | |
916 } | |
917 | |
918 return 4; | |
919 } | |
920 | |
921 /* Function prologue/epilogue handlers. */ | |
922 | |
923 /* ARC stack frames look like: | |
924 | |
925 Before call After call | |
926 +-----------------------+ +-----------------------+ | |
927 | | | | | |
928 high | local variables, | | local variables, | | |
929 mem | reg save area, etc. | | reg save area, etc. | | |
930 | | | | | |
931 +-----------------------+ +-----------------------+ | |
932 | | | | | |
933 | arguments on stack. | | arguments on stack. | | |
934 | | | | | |
935 SP+16->+-----------------------+FP+48->+-----------------------+ | |
936 | 4 word save area for | | reg parm save area, | | |
937 | return addr, prev %fp | | only created for | | |
938 SP+0->+-----------------------+ | variable argument | | |
939 | functions | | |
940 FP+16->+-----------------------+ | |
941 | 4 word save area for | | |
942 | return addr, prev %fp | | |
943 FP+0->+-----------------------+ | |
944 | | | |
945 | local variables | | |
946 | | | |
947 +-----------------------+ | |
948 | | | |
949 | register save area | | |
950 | | | |
951 +-----------------------+ | |
952 | | | |
953 | alloca allocations | | |
954 | | | |
955 +-----------------------+ | |
956 | | | |
957 | arguments on stack | | |
958 | | | |
959 SP+16->+-----------------------+ | |
960 low | 4 word save area for | | |
961 memory | return addr, prev %fp | | |
962 SP+0->+-----------------------+ | |
963 | |
964 Notes: | |
965 1) The "reg parm save area" does not exist for non variable argument fns. | |
966 The "reg parm save area" can be eliminated completely if we created our | |
967 own va-arc.h, but that has tradeoffs as well (so it's not done). */ | |
968 | |
969 /* Structure to be filled in by arc_compute_frame_size with register | |
970 save masks, and offsets for the current function. */ | |
971 struct arc_frame_info | |
972 { | |
973 unsigned int total_size; /* # bytes that the entire frame takes up. */ | |
974 unsigned int extra_size; /* # bytes of extra stuff. */ | |
975 unsigned int pretend_size; /* # bytes we push and pretend caller did. */ | |
976 unsigned int args_size; /* # bytes that outgoing arguments take up. */ | |
977 unsigned int reg_size; /* # bytes needed to store regs. */ | |
978 unsigned int var_size; /* # bytes that variables take up. */ | |
979 unsigned int reg_offset; /* Offset from new sp to store regs. */ | |
980 unsigned int gmask; /* Mask of saved gp registers. */ | |
981 int initialized; /* Nonzero if frame size already calculated. */ | |
982 }; | |
983 | |
984 /* Current frame information calculated by arc_compute_frame_size. */ | |
985 static struct arc_frame_info current_frame_info; | |
986 | |
987 /* Zero structure to initialize current_frame_info. */ | |
988 static struct arc_frame_info zero_frame_info; | |
989 | |
990 /* Type of function DECL. | |
991 | |
992 The result is cached. To reset the cache at the end of a function, | |
993 call with DECL = NULL_TREE. */ | |
994 | |
995 enum arc_function_type | |
996 arc_compute_function_type (tree decl) | |
997 { | |
998 tree a; | |
999 /* Cached value. */ | |
1000 static enum arc_function_type fn_type = ARC_FUNCTION_UNKNOWN; | |
1001 /* Last function we were called for. */ | |
1002 static tree last_fn = NULL_TREE; | |
1003 | |
1004 /* Resetting the cached value? */ | |
1005 if (decl == NULL_TREE) | |
1006 { | |
1007 fn_type = ARC_FUNCTION_UNKNOWN; | |
1008 last_fn = NULL_TREE; | |
1009 return fn_type; | |
1010 } | |
1011 | |
1012 if (decl == last_fn && fn_type != ARC_FUNCTION_UNKNOWN) | |
1013 return fn_type; | |
1014 | |
1015 /* Assume we have a normal function (not an interrupt handler). */ | |
1016 fn_type = ARC_FUNCTION_NORMAL; | |
1017 | |
1018 /* Now see if this is an interrupt handler. */ | |
1019 for (a = DECL_ATTRIBUTES (current_function_decl); | |
1020 a; | |
1021 a = TREE_CHAIN (a)) | |
1022 { | |
1023 tree name = TREE_PURPOSE (a), args = TREE_VALUE (a); | |
1024 | |
1025 if (name == get_identifier ("__interrupt__") | |
1026 && list_length (args) == 1 | |
1027 && TREE_CODE (TREE_VALUE (args)) == STRING_CST) | |
1028 { | |
1029 tree value = TREE_VALUE (args); | |
1030 | |
1031 if (!strcmp (TREE_STRING_POINTER (value), "ilink1")) | |
1032 fn_type = ARC_FUNCTION_ILINK1; | |
1033 else if (!strcmp (TREE_STRING_POINTER (value), "ilink2")) | |
1034 fn_type = ARC_FUNCTION_ILINK2; | |
1035 else | |
1036 gcc_unreachable (); | |
1037 break; | |
1038 } | |
1039 } | |
1040 | |
1041 last_fn = decl; | |
1042 return fn_type; | |
1043 } | |
1044 | |
1045 #define ILINK1_REGNUM 29 | |
1046 #define ILINK2_REGNUM 30 | |
1047 #define RETURN_ADDR_REGNUM 31 | |
1048 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM)) | |
1049 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM)) | |
1050 | |
1051 /* Tell prologue and epilogue if register REGNO should be saved / restored. | |
1052 The return address and frame pointer are treated separately. | |
1053 Don't consider them here. */ | |
1054 #define MUST_SAVE_REGISTER(regno, interrupt_p) \ | |
1055 ((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \ | |
1056 && (df_regs_ever_live_p (regno) && (!call_used_regs[regno] || interrupt_p))) | |
1057 | |
1058 #define MUST_SAVE_RETURN_ADDR (df_regs_ever_live_p (RETURN_ADDR_REGNUM)) | |
1059 | |
1060 /* Return the bytes needed to compute the frame pointer from the current | |
1061 stack pointer. | |
1062 | |
1063 SIZE is the size needed for local variables. */ | |
1064 | |
1065 unsigned int | |
1066 arc_compute_frame_size (int size /* # of var. bytes allocated. */) | |
1067 { | |
1068 int regno; | |
1069 unsigned int total_size, var_size, args_size, pretend_size, extra_size; | |
1070 unsigned int reg_size, reg_offset; | |
1071 unsigned int gmask; | |
1072 enum arc_function_type fn_type; | |
1073 int interrupt_p; | |
1074 | |
1075 var_size = size; | |
1076 args_size = crtl->outgoing_args_size; | |
1077 pretend_size = crtl->args.pretend_args_size; | |
1078 extra_size = FIRST_PARM_OFFSET (0); | |
1079 total_size = extra_size + pretend_size + args_size + var_size; | |
1080 reg_offset = FIRST_PARM_OFFSET(0) + crtl->outgoing_args_size; | |
1081 reg_size = 0; | |
1082 gmask = 0; | |
1083 | |
1084 /* See if this is an interrupt handler. Call used registers must be saved | |
1085 for them too. */ | |
1086 fn_type = arc_compute_function_type (current_function_decl); | |
1087 interrupt_p = ARC_INTERRUPT_P (fn_type); | |
1088 | |
1089 /* Calculate space needed for registers. | |
1090 ??? We ignore the extension registers for now. */ | |
1091 | |
1092 for (regno = 0; regno <= 31; regno++) | |
1093 { | |
1094 if (MUST_SAVE_REGISTER (regno, interrupt_p)) | |
1095 { | |
1096 reg_size += UNITS_PER_WORD; | |
1097 gmask |= 1 << regno; | |
1098 } | |
1099 } | |
1100 | |
1101 total_size += reg_size; | |
1102 | |
1103 /* If the only space to allocate is the fp/blink save area this is an | |
1104 empty frame. However, if we'll be making a function call we need to | |
1105 allocate a stack frame for our callee's fp/blink save area. */ | |
1106 if (total_size == extra_size | |
1107 && !MUST_SAVE_RETURN_ADDR) | |
1108 total_size = extra_size = 0; | |
1109 | |
1110 total_size = ARC_STACK_ALIGN (total_size); | |
1111 | |
1112 /* Save computed information. */ | |
1113 current_frame_info.total_size = total_size; | |
1114 current_frame_info.extra_size = extra_size; | |
1115 current_frame_info.pretend_size = pretend_size; | |
1116 current_frame_info.var_size = var_size; | |
1117 current_frame_info.args_size = args_size; | |
1118 current_frame_info.reg_size = reg_size; | |
1119 current_frame_info.reg_offset = reg_offset; | |
1120 current_frame_info.gmask = gmask; | |
1121 current_frame_info.initialized = reload_completed; | |
1122 | |
1123 /* Ok, we're done. */ | |
1124 return total_size; | |
1125 } | |
1126 | |
1127 /* Common code to save/restore registers. */ | |
1128 | |
1129 void | |
1130 arc_save_restore (FILE *file, | |
1131 const char *base_reg, | |
1132 unsigned int offset, | |
1133 unsigned int gmask, | |
1134 const char *op) | |
1135 { | |
1136 int regno; | |
1137 | |
1138 if (gmask == 0) | |
1139 return; | |
1140 | |
1141 for (regno = 0; regno <= 31; regno++) | |
1142 { | |
1143 if ((gmask & (1L << regno)) != 0) | |
1144 { | |
1145 fprintf (file, "\t%s %s,[%s,%d]\n", | |
1146 op, reg_names[regno], base_reg, offset); | |
1147 offset += UNITS_PER_WORD; | |
1148 } | |
1149 } | |
1150 } | |
1151 | |
1152 /* Target hook to assemble an integer object. The ARC version needs to | |
1153 emit a special directive for references to labels and function | |
1154 symbols. */ | |
1155 | |
1156 static bool | |
1157 arc_assemble_integer (rtx x, unsigned int size, int aligned_p) | |
1158 { | |
1159 if (size == UNITS_PER_WORD && aligned_p | |
1160 && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x)) | |
1161 || GET_CODE (x) == LABEL_REF)) | |
1162 { | |
1163 fputs ("\t.word\t%st(", asm_out_file); | |
1164 output_addr_const (asm_out_file, x); | |
1165 fputs (")\n", asm_out_file); | |
1166 return true; | |
1167 } | |
1168 return default_assemble_integer (x, size, aligned_p); | |
1169 } | |
1170 | |
1171 /* Set up the stack and frame pointer (if desired) for the function. */ | |
1172 | |
1173 static void | |
1174 arc_output_function_prologue (FILE *file, HOST_WIDE_INT size) | |
1175 { | |
1176 const char *sp_str = reg_names[STACK_POINTER_REGNUM]; | |
1177 const char *fp_str = reg_names[FRAME_POINTER_REGNUM]; | |
1178 unsigned int gmask = current_frame_info.gmask; | |
1179 enum arc_function_type fn_type = arc_compute_function_type (current_function_decl); | |
1180 | |
1181 /* If this is an interrupt handler, set up our stack frame. | |
1182 ??? Optimize later. */ | |
1183 if (ARC_INTERRUPT_P (fn_type)) | |
1184 { | |
1185 fprintf (file, "\t%s interrupt handler\n", | |
1186 ASM_COMMENT_START); | |
1187 fprintf (file, "\tsub %s,%s,16\n", sp_str, sp_str); | |
1188 } | |
1189 | |
1190 /* This is only for the human reader. */ | |
1191 fprintf (file, "\t%s BEGIN PROLOGUE %s vars= %d, regs= %d, args= %d, extra= %d\n", | |
1192 ASM_COMMENT_START, ASM_COMMENT_START, | |
1193 current_frame_info.var_size, | |
1194 current_frame_info.reg_size / 4, | |
1195 current_frame_info.args_size, | |
1196 current_frame_info.extra_size); | |
1197 | |
1198 size = ARC_STACK_ALIGN (size); | |
1199 size = (! current_frame_info.initialized | |
1200 ? arc_compute_frame_size (size) | |
1201 : current_frame_info.total_size); | |
1202 | |
1203 /* These cases shouldn't happen. Catch them now. */ | |
1204 gcc_assert (size || !gmask); | |
1205 | |
1206 /* Allocate space for register arguments if this is a variadic function. */ | |
1207 if (current_frame_info.pretend_size != 0) | |
1208 fprintf (file, "\tsub %s,%s,%d\n", | |
1209 sp_str, sp_str, current_frame_info.pretend_size); | |
1210 | |
1211 /* The home-grown ABI says link register is saved first. */ | |
1212 if (MUST_SAVE_RETURN_ADDR) | |
1213 fprintf (file, "\tst %s,[%s,%d]\n", | |
1214 reg_names[RETURN_ADDR_REGNUM], sp_str, UNITS_PER_WORD); | |
1215 | |
1216 /* Set up the previous frame pointer next (if we need to). */ | |
1217 if (frame_pointer_needed) | |
1218 { | |
1219 fprintf (file, "\tst %s,[%s]\n", fp_str, sp_str); | |
1220 fprintf (file, "\tmov %s,%s\n", fp_str, sp_str); | |
1221 } | |
1222 | |
1223 /* ??? We don't handle the case where the saved regs are more than 252 | |
1224 bytes away from sp. This can be handled by decrementing sp once, saving | |
1225 the regs, and then decrementing it again. The epilogue doesn't have this | |
1226 problem as the `ld' insn takes reg+limm values (though it would be more | |
1227 efficient to avoid reg+limm). */ | |
1228 | |
1229 /* Allocate the stack frame. */ | |
1230 if (size - current_frame_info.pretend_size > 0) | |
1231 fprintf (file, "\tsub %s,%s," HOST_WIDE_INT_PRINT_DEC "\n", | |
1232 sp_str, sp_str, size - current_frame_info.pretend_size); | |
1233 | |
1234 /* Save any needed call-saved regs (and call-used if this is an | |
1235 interrupt handler). */ | |
1236 arc_save_restore (file, sp_str, current_frame_info.reg_offset, | |
1237 /* The zeroing of these two bits is unnecessary, | |
1238 but leave this in for clarity. */ | |
1239 gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), | |
1240 "st"); | |
1241 | |
1242 fprintf (file, "\t%s END PROLOGUE\n", ASM_COMMENT_START); | |
1243 } | |
1244 | |
1245 /* Do any necessary cleanup after a function to restore stack, frame, | |
1246 and regs. */ | |
1247 | |
1248 static void | |
1249 arc_output_function_epilogue (FILE *file, HOST_WIDE_INT size) | |
1250 { | |
1251 rtx epilogue_delay = crtl->epilogue_delay_list; | |
1252 int noepilogue = FALSE; | |
1253 enum arc_function_type fn_type = arc_compute_function_type (current_function_decl); | |
1254 | |
1255 /* This is only for the human reader. */ | |
1256 fprintf (file, "\t%s EPILOGUE\n", ASM_COMMENT_START); | |
1257 | |
1258 size = ARC_STACK_ALIGN (size); | |
1259 size = (!current_frame_info.initialized | |
1260 ? arc_compute_frame_size (size) | |
1261 : current_frame_info.total_size); | |
1262 | |
1263 if (size == 0 && epilogue_delay == 0) | |
1264 { | |
1265 rtx insn = get_last_insn (); | |
1266 | |
1267 /* If the last insn was a BARRIER, we don't have to write any code | |
1268 because a jump (aka return) was put there. */ | |
1269 if (GET_CODE (insn) == NOTE) | |
1270 insn = prev_nonnote_insn (insn); | |
1271 if (insn && GET_CODE (insn) == BARRIER) | |
1272 noepilogue = TRUE; | |
1273 } | |
1274 | |
1275 if (!noepilogue) | |
1276 { | |
1277 unsigned int pretend_size = current_frame_info.pretend_size; | |
1278 unsigned int frame_size = size - pretend_size; | |
1279 int restored, fp_restored_p; | |
1280 int can_trust_sp_p = !cfun->calls_alloca; | |
1281 const char *sp_str = reg_names[STACK_POINTER_REGNUM]; | |
1282 const char *fp_str = reg_names[FRAME_POINTER_REGNUM]; | |
1283 | |
1284 /* ??? There are lots of optimizations that can be done here. | |
1285 EG: Use fp to restore regs if it's closer. | |
1286 Maybe in time we'll do them all. For now, always restore regs from | |
1287 sp, but don't restore sp if we don't have to. */ | |
1288 | |
1289 if (!can_trust_sp_p) | |
1290 { | |
1291 gcc_assert (frame_pointer_needed); | |
1292 fprintf (file,"\tsub %s,%s,%d\t\t%s sp not trusted here\n", | |
1293 sp_str, fp_str, frame_size, ASM_COMMENT_START); | |
1294 } | |
1295 | |
1296 /* Restore any saved registers. */ | |
1297 arc_save_restore (file, sp_str, current_frame_info.reg_offset, | |
1298 /* The zeroing of these two bits is unnecessary, | |
1299 but leave this in for clarity. */ | |
1300 current_frame_info.gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK), | |
1301 "ld"); | |
1302 | |
1303 if (MUST_SAVE_RETURN_ADDR) | |
1304 fprintf (file, "\tld %s,[%s,%d]\n", | |
1305 reg_names[RETURN_ADDR_REGNUM], | |
1306 frame_pointer_needed ? fp_str : sp_str, | |
1307 UNITS_PER_WORD + (frame_pointer_needed ? 0 : frame_size)); | |
1308 | |
1309 /* Keep track of how much of the stack pointer we've restored. | |
1310 It makes the following a lot more readable. */ | |
1311 restored = 0; | |
1312 fp_restored_p = 0; | |
1313 | |
1314 /* We try to emit the epilogue delay slot insn right after the load | |
1315 of the return address register so that it can execute with the | |
1316 stack intact. Secondly, loads are delayed. */ | |
1317 /* ??? If stack intactness is important, always emit now. */ | |
1318 if (MUST_SAVE_RETURN_ADDR && epilogue_delay != NULL_RTX) | |
1319 { | |
1320 final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL); | |
1321 epilogue_delay = NULL_RTX; | |
1322 } | |
1323 | |
1324 if (frame_pointer_needed) | |
1325 { | |
1326 /* Try to restore the frame pointer in the delay slot. We can't, | |
1327 however, if any of these is true. */ | |
1328 if (epilogue_delay != NULL_RTX | |
1329 || !SMALL_INT (frame_size) | |
1330 || pretend_size | |
1331 || ARC_INTERRUPT_P (fn_type)) | |
1332 { | |
1333 /* Note that we restore fp and sp here! */ | |
1334 fprintf (file, "\tld.a %s,[%s,%d]\n", fp_str, sp_str, frame_size); | |
1335 restored += frame_size; | |
1336 fp_restored_p = 1; | |
1337 } | |
1338 } | |
1339 else if (!SMALL_INT (size /* frame_size + pretend_size */) | |
1340 || ARC_INTERRUPT_P (fn_type)) | |
1341 { | |
1342 fprintf (file, "\tadd %s,%s,%d\n", sp_str, sp_str, frame_size); | |
1343 restored += frame_size; | |
1344 } | |
1345 | |
1346 /* These must be done before the return insn because the delay slot | |
1347 does the final stack restore. */ | |
1348 if (ARC_INTERRUPT_P (fn_type)) | |
1349 { | |
1350 if (epilogue_delay) | |
1351 { | |
1352 final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL); | |
1353 } | |
1354 } | |
1355 | |
1356 /* Emit the return instruction. */ | |
1357 { | |
1358 static const int regs[4] = { | |
1359 0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM | |
1360 }; | |
1361 | |
1362 /* Update the flags, if returning from an interrupt handler. */ | |
1363 if (ARC_INTERRUPT_P (fn_type)) | |
1364 fprintf (file, "\tj.d.f %s\n", reg_names[regs[fn_type]]); | |
1365 else | |
1366 fprintf (file, "\tj.d %s\n", reg_names[regs[fn_type]]); | |
1367 } | |
1368 | |
1369 /* If the only register saved is the return address, we need a | |
1370 nop, unless we have an instruction to put into it. Otherwise | |
1371 we don't since reloading multiple registers doesn't reference | |
1372 the register being loaded. */ | |
1373 | |
1374 if (ARC_INTERRUPT_P (fn_type)) | |
1375 fprintf (file, "\tadd %s,%s,16\n", sp_str, sp_str); | |
1376 else if (epilogue_delay != NULL_RTX) | |
1377 { | |
1378 gcc_assert (!frame_pointer_needed || fp_restored_p); | |
1379 gcc_assert (restored >= size); | |
1380 final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL); | |
1381 } | |
1382 else if (frame_pointer_needed && !fp_restored_p) | |
1383 { | |
1384 gcc_assert (SMALL_INT (frame_size)); | |
1385 /* Note that we restore fp and sp here! */ | |
1386 fprintf (file, "\tld.a %s,[%s,%d]\n", fp_str, sp_str, frame_size); | |
1387 } | |
1388 else if (restored < size) | |
1389 { | |
1390 gcc_assert (SMALL_INT (size - restored)); | |
1391 fprintf (file, "\tadd %s,%s," HOST_WIDE_INT_PRINT_DEC "\n", | |
1392 sp_str, sp_str, size - restored); | |
1393 } | |
1394 else | |
1395 fprintf (file, "\tnop\n"); | |
1396 } | |
1397 | |
1398 /* Reset state info for each function. */ | |
1399 current_frame_info = zero_frame_info; | |
1400 arc_compute_function_type (NULL_TREE); | |
1401 } | |
1402 | |
1403 /* Define the number of delay slots needed for the function epilogue. | |
1404 | |
1405 Interrupt handlers can't have any epilogue delay slots (it's always needed | |
1406 for something else, I think). For normal functions, we have to worry about | |
1407 using call-saved regs as they'll be restored before the delay slot insn. | |
1408 Functions with non-empty frames already have enough choices for the epilogue | |
1409 delay slot so for now we only consider functions with empty frames. */ | |
1410 | |
1411 int | |
1412 arc_delay_slots_for_epilogue (void) | |
1413 { | |
1414 if (arc_compute_function_type (current_function_decl) != ARC_FUNCTION_NORMAL) | |
1415 return 0; | |
1416 if (!current_frame_info.initialized) | |
1417 (void) arc_compute_frame_size (get_frame_size ()); | |
1418 if (current_frame_info.total_size == 0) | |
1419 return 1; | |
1420 return 0; | |
1421 } | |
1422 | |
1423 /* Return true if TRIAL is a valid insn for the epilogue delay slot. | |
1424 Any single length instruction which doesn't reference the stack or frame | |
1425 pointer or any call-saved register is OK. SLOT will always be 0. */ | |
1426 | |
1427 int | |
1428 arc_eligible_for_epilogue_delay (rtx trial, int slot) | |
1429 { | |
1430 gcc_assert (!slot); | |
1431 | |
1432 if (get_attr_length (trial) == 1 | |
1433 /* If registers where saved, presumably there's more than enough | |
1434 possibilities for the delay slot. The alternative is something | |
1435 more complicated (of course, if we expanded the epilogue as rtl | |
1436 this problem would go away). */ | |
1437 /* ??? Note that this will always be true since only functions with | |
1438 empty frames have epilogue delay slots. See | |
1439 arc_delay_slots_for_epilogue. */ | |
1440 && current_frame_info.gmask == 0 | |
1441 && ! reg_mentioned_p (stack_pointer_rtx, PATTERN (trial)) | |
1442 && ! reg_mentioned_p (frame_pointer_rtx, PATTERN (trial))) | |
1443 return 1; | |
1444 return 0; | |
1445 } | |
1446 | |
1447 /* Return true if OP is a shift operator. */ | |
1448 | |
1449 int | |
1450 shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
1451 { | |
1452 switch (GET_CODE (op)) | |
1453 { | |
1454 case ASHIFTRT: | |
1455 case LSHIFTRT: | |
1456 case ASHIFT: | |
1457 return 1; | |
1458 default: | |
1459 return 0; | |
1460 } | |
1461 } | |
1462 | |
1463 /* Output the assembler code for doing a shift. | |
1464 We go to a bit of trouble to generate efficient code as the ARC only has | |
1465 single bit shifts. This is taken from the h8300 port. We only have one | |
1466 mode of shifting and can't access individual bytes like the h8300 can, so | |
1467 this is greatly simplified (at the expense of not generating hyper- | |
1468 efficient code). | |
1469 | |
1470 This function is not used if the variable shift insns are present. */ | |
1471 | |
1472 /* ??? We assume the output operand is the same as operand 1. | |
1473 This can be optimized (deleted) in the case of 1 bit shifts. */ | |
1474 /* ??? We use the loop register here. We don't use it elsewhere (yet) and | |
1475 using it here will give us a chance to play with it. */ | |
1476 | |
1477 const char * | |
1478 output_shift (rtx *operands) | |
1479 { | |
1480 rtx shift = operands[3]; | |
1481 enum machine_mode mode = GET_MODE (shift); | |
1482 enum rtx_code code = GET_CODE (shift); | |
1483 const char *shift_one; | |
1484 | |
1485 gcc_assert (mode == SImode); | |
1486 | |
1487 switch (code) | |
1488 { | |
1489 case ASHIFT: shift_one = "asl %0,%0"; break; | |
1490 case ASHIFTRT: shift_one = "asr %0,%0"; break; | |
1491 case LSHIFTRT: shift_one = "lsr %0,%0"; break; | |
1492 default: gcc_unreachable (); | |
1493 } | |
1494 | |
1495 if (GET_CODE (operands[2]) != CONST_INT) | |
1496 { | |
1497 if (optimize) | |
1498 { | |
1499 output_asm_insn ("sub.f 0,%2,0", operands); | |
1500 output_asm_insn ("mov lp_count,%2", operands); | |
1501 output_asm_insn ("bz 2f", operands); | |
1502 } | |
1503 else | |
1504 output_asm_insn ("mov %4,%2", operands); | |
1505 goto shiftloop; | |
1506 } | |
1507 else | |
1508 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1509 int n; |
0 | 1510 |
1511 /* If the count is negative, make it 0. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1512 n = INTVAL (operands[2]); |
0 | 1513 if (n < 0) |
1514 n = 0; | |
1515 /* If the count is too big, truncate it. | |
1516 ANSI says shifts of GET_MODE_BITSIZE are undefined - we choose to | |
1517 do the intuitive thing. */ | |
1518 else if (n > GET_MODE_BITSIZE (mode)) | |
1519 n = GET_MODE_BITSIZE (mode); | |
1520 | |
1521 /* First see if we can do them inline. */ | |
1522 if (n <= 8) | |
1523 { | |
1524 while (--n >= 0) | |
1525 output_asm_insn (shift_one, operands); | |
1526 } | |
1527 /* See if we can use a rotate/and. */ | |
1528 else if (n == BITS_PER_WORD - 1) | |
1529 { | |
1530 switch (code) | |
1531 { | |
1532 case ASHIFT : | |
1533 output_asm_insn ("and %0,%0,1\n\tror %0,%0", operands); | |
1534 break; | |
1535 case ASHIFTRT : | |
1536 /* The ARC doesn't have a rol insn. Use something else. */ | |
1537 output_asm_insn ("asl.f 0,%0\n\tsbc %0,0,0", operands); | |
1538 break; | |
1539 case LSHIFTRT : | |
1540 /* The ARC doesn't have a rol insn. Use something else. */ | |
1541 output_asm_insn ("asl.f 0,%0\n\tadc %0,0,0", operands); | |
1542 break; | |
1543 default: | |
1544 break; | |
1545 } | |
1546 } | |
1547 /* Must loop. */ | |
1548 else | |
1549 { | |
1550 char buf[100]; | |
1551 | |
1552 if (optimize) | |
1553 output_asm_insn ("mov lp_count,%c2", operands); | |
1554 else | |
1555 output_asm_insn ("mov %4,%c2", operands); | |
1556 shiftloop: | |
1557 if (optimize) | |
1558 { | |
1559 if (flag_pic) | |
1560 sprintf (buf, "lr %%4,[status]\n\tadd %%4,%%4,6\t%s single insn loop start", | |
1561 ASM_COMMENT_START); | |
1562 else | |
1563 sprintf (buf, "mov %%4,%%%%st(1f)\t%s (single insn loop start) >> 2", | |
1564 ASM_COMMENT_START); | |
1565 output_asm_insn (buf, operands); | |
1566 output_asm_insn ("sr %4,[lp_start]", operands); | |
1567 output_asm_insn ("add %4,%4,1", operands); | |
1568 output_asm_insn ("sr %4,[lp_end]", operands); | |
1569 output_asm_insn ("nop\n\tnop", operands); | |
1570 if (flag_pic) | |
1571 fprintf (asm_out_file, "\t%s single insn loop\n", | |
1572 ASM_COMMENT_START); | |
1573 else | |
1574 fprintf (asm_out_file, "1:\t%s single insn loop\n", | |
1575 ASM_COMMENT_START); | |
1576 output_asm_insn (shift_one, operands); | |
1577 fprintf (asm_out_file, "2:\t%s end single insn loop\n", | |
1578 ASM_COMMENT_START); | |
1579 } | |
1580 else | |
1581 { | |
1582 fprintf (asm_out_file, "1:\t%s begin shift loop\n", | |
1583 ASM_COMMENT_START); | |
1584 output_asm_insn ("sub.f %4,%4,1", operands); | |
1585 output_asm_insn ("nop", operands); | |
1586 output_asm_insn ("bn.nd 2f", operands); | |
1587 output_asm_insn (shift_one, operands); | |
1588 output_asm_insn ("b.nd 1b", operands); | |
1589 fprintf (asm_out_file, "2:\t%s end shift loop\n", | |
1590 ASM_COMMENT_START); | |
1591 } | |
1592 } | |
1593 } | |
1594 | |
1595 return ""; | |
1596 } | |
1597 | |
1598 /* Nested function support. */ | |
1599 | |
1600 /* Emit RTL insns to initialize the variable parts of a trampoline. | |
1601 FNADDR is an RTX for the address of the function's pure code. | |
1602 CXT is an RTX for the static chain value for the function. */ | |
1603 | |
1604 void | |
1605 arc_initialize_trampoline (rtx tramp ATTRIBUTE_UNUSED, | |
1606 rtx fnaddr ATTRIBUTE_UNUSED, | |
1607 rtx cxt ATTRIBUTE_UNUSED) | |
1608 { | |
1609 } | |
1610 | |
1611 /* Set the cpu type and print out other fancy things, | |
1612 at the top of the file. */ | |
1613 | |
1614 static void | |
1615 arc_file_start (void) | |
1616 { | |
1617 default_file_start (); | |
1618 fprintf (asm_out_file, "\t.cpu %s\n", arc_cpu_string); | |
1619 } | |
1620 | |
1621 /* Print operand X (an rtx) in assembler syntax to file FILE. | |
1622 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. | |
1623 For `%' followed by punctuation, CODE is the punctuation and X is null. */ | |
1624 | |
1625 void | |
1626 arc_print_operand (FILE *file, rtx x, int code) | |
1627 { | |
1628 switch (code) | |
1629 { | |
1630 case '#' : | |
1631 /* Conditional branches. For now these are equivalent. */ | |
1632 case '*' : | |
1633 /* Unconditional branches. Output the appropriate delay slot suffix. */ | |
1634 if (!final_sequence || XVECLEN (final_sequence, 0) == 1) | |
1635 { | |
1636 /* There's nothing in the delay slot. */ | |
1637 fputs (".nd", file); | |
1638 } | |
1639 else | |
1640 { | |
1641 rtx jump = XVECEXP (final_sequence, 0, 0); | |
1642 rtx delay = XVECEXP (final_sequence, 0, 1); | |
1643 if (INSN_ANNULLED_BRANCH_P (jump)) | |
1644 fputs (INSN_FROM_TARGET_P (delay) ? ".jd" : ".nd", file); | |
1645 else | |
1646 fputs (".d", file); | |
1647 } | |
1648 return; | |
1649 case '?' : /* with leading "." */ | |
1650 case '!' : /* without leading "." */ | |
1651 /* This insn can be conditionally executed. See if the ccfsm machinery | |
1652 says it should be conditionalized. */ | |
1653 if (arc_ccfsm_state == 3 || arc_ccfsm_state == 4) | |
1654 { | |
1655 /* Is this insn in a delay slot? */ | |
1656 if (final_sequence && XVECLEN (final_sequence, 0) == 2) | |
1657 { | |
1658 rtx insn = XVECEXP (final_sequence, 0, 1); | |
1659 | |
1660 /* If the insn is annulled and is from the target path, we need | |
1661 to inverse the condition test. */ | |
1662 if (INSN_ANNULLED_BRANCH_P (insn)) | |
1663 { | |
1664 if (INSN_FROM_TARGET_P (insn)) | |
1665 fprintf (file, "%s%s", | |
1666 code == '?' ? "." : "", | |
1667 arc_condition_codes[ARC_INVERSE_CONDITION_CODE (arc_ccfsm_current_cc)]); | |
1668 else | |
1669 fprintf (file, "%s%s", | |
1670 code == '?' ? "." : "", | |
1671 arc_condition_codes[arc_ccfsm_current_cc]); | |
1672 } | |
1673 else | |
1674 { | |
1675 /* This insn is executed for either path, so don't | |
1676 conditionalize it at all. */ | |
1677 ; /* nothing to do */ | |
1678 } | |
1679 } | |
1680 else | |
1681 { | |
1682 /* This insn isn't in a delay slot. */ | |
1683 fprintf (file, "%s%s", | |
1684 code == '?' ? "." : "", | |
1685 arc_condition_codes[arc_ccfsm_current_cc]); | |
1686 } | |
1687 } | |
1688 return; | |
1689 case '~' : | |
1690 /* Output a nop if we're between a set of the condition codes, | |
1691 and a conditional branch. */ | |
1692 if (last_insn_set_cc_p) | |
1693 fputs ("nop\n\t", file); | |
1694 return; | |
1695 case 'd' : | |
1696 fputs (arc_condition_codes[get_arc_condition_code (x)], file); | |
1697 return; | |
1698 case 'D' : | |
1699 fputs (arc_condition_codes[ARC_INVERSE_CONDITION_CODE | |
1700 (get_arc_condition_code (x))], | |
1701 file); | |
1702 return; | |
1703 case 'R' : | |
1704 /* Write second word of DImode or DFmode reference, | |
1705 register or memory. */ | |
1706 if (GET_CODE (x) == REG) | |
1707 fputs (reg_names[REGNO (x)+1], file); | |
1708 else if (GET_CODE (x) == MEM) | |
1709 { | |
1710 fputc ('[', file); | |
1711 /* Handle possible auto-increment. Since it is pre-increment and | |
1712 we have already done it, we can just use an offset of four. */ | |
1713 /* ??? This is taken from rs6000.c I think. I don't think it is | |
1714 currently necessary, but keep it around. */ | |
1715 if (GET_CODE (XEXP (x, 0)) == PRE_INC | |
1716 || GET_CODE (XEXP (x, 0)) == PRE_DEC) | |
1717 output_address (plus_constant (XEXP (XEXP (x, 0), 0), 4)); | |
1718 else | |
1719 output_address (plus_constant (XEXP (x, 0), 4)); | |
1720 fputc (']', file); | |
1721 } | |
1722 else | |
1723 output_operand_lossage ("invalid operand to %%R code"); | |
1724 return; | |
1725 case 'S' : | |
1726 if ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x)) | |
1727 || GET_CODE (x) == LABEL_REF) | |
1728 { | |
1729 fprintf (file, "%%st("); | |
1730 output_addr_const (file, x); | |
1731 fprintf (file, ")"); | |
1732 return; | |
1733 } | |
1734 break; | |
1735 case 'H' : | |
1736 case 'L' : | |
1737 if (GET_CODE (x) == REG) | |
1738 { | |
1739 /* L = least significant word, H = most significant word */ | |
1740 if ((TARGET_BIG_ENDIAN != 0) ^ (code == 'L')) | |
1741 fputs (reg_names[REGNO (x)], file); | |
1742 else | |
1743 fputs (reg_names[REGNO (x)+1], file); | |
1744 } | |
1745 else if (GET_CODE (x) == CONST_INT | |
1746 || GET_CODE (x) == CONST_DOUBLE) | |
1747 { | |
1748 rtx first, second; | |
1749 | |
1750 split_double (x, &first, &second); | |
1751 fprintf (file, "0x%08lx", | |
1752 (long)(code == 'L' ? INTVAL (first) : INTVAL (second))); | |
1753 } | |
1754 else | |
1755 output_operand_lossage ("invalid operand to %%H/%%L code"); | |
1756 return; | |
1757 case 'A' : | |
1758 { | |
1759 char str[30]; | |
1760 | |
1761 gcc_assert (GET_CODE (x) == CONST_DOUBLE | |
1762 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT); | |
1763 | |
1764 real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x), sizeof (str), 0, 1); | |
1765 fprintf (file, "%s", str); | |
1766 return; | |
1767 } | |
1768 case 'U' : | |
1769 /* Output a load/store with update indicator if appropriate. */ | |
1770 if (GET_CODE (x) == MEM) | |
1771 { | |
1772 if (GET_CODE (XEXP (x, 0)) == PRE_INC | |
1773 || GET_CODE (XEXP (x, 0)) == PRE_DEC) | |
1774 fputs (".a", file); | |
1775 } | |
1776 else | |
1777 output_operand_lossage ("invalid operand to %%U code"); | |
1778 return; | |
1779 case 'V' : | |
1780 /* Output cache bypass indicator for a load/store insn. Volatile memory | |
1781 refs are defined to use the cache bypass mechanism. */ | |
1782 if (GET_CODE (x) == MEM) | |
1783 { | |
1784 if (MEM_VOLATILE_P (x)) | |
1785 fputs (".di", file); | |
1786 } | |
1787 else | |
1788 output_operand_lossage ("invalid operand to %%V code"); | |
1789 return; | |
1790 case 0 : | |
1791 /* Do nothing special. */ | |
1792 break; | |
1793 default : | |
1794 /* Unknown flag. */ | |
1795 output_operand_lossage ("invalid operand output code"); | |
1796 } | |
1797 | |
1798 switch (GET_CODE (x)) | |
1799 { | |
1800 case REG : | |
1801 fputs (reg_names[REGNO (x)], file); | |
1802 break; | |
1803 case MEM : | |
1804 fputc ('[', file); | |
1805 if (GET_CODE (XEXP (x, 0)) == PRE_INC) | |
1806 output_address (plus_constant (XEXP (XEXP (x, 0), 0), | |
1807 GET_MODE_SIZE (GET_MODE (x)))); | |
1808 else if (GET_CODE (XEXP (x, 0)) == PRE_DEC) | |
1809 output_address (plus_constant (XEXP (XEXP (x, 0), 0), | |
1810 - GET_MODE_SIZE (GET_MODE (x)))); | |
1811 else | |
1812 output_address (XEXP (x, 0)); | |
1813 fputc (']', file); | |
1814 break; | |
1815 case CONST_DOUBLE : | |
1816 /* We handle SFmode constants here as output_addr_const doesn't. */ | |
1817 if (GET_MODE (x) == SFmode) | |
1818 { | |
1819 REAL_VALUE_TYPE d; | |
1820 long l; | |
1821 | |
1822 REAL_VALUE_FROM_CONST_DOUBLE (d, x); | |
1823 REAL_VALUE_TO_TARGET_SINGLE (d, l); | |
1824 fprintf (file, "0x%08lx", l); | |
1825 break; | |
1826 } | |
1827 /* Fall through. Let output_addr_const deal with it. */ | |
1828 default : | |
1829 output_addr_const (file, x); | |
1830 break; | |
1831 } | |
1832 } | |
1833 | |
1834 /* Print a memory address as an operand to reference that memory location. */ | |
1835 | |
1836 void | |
1837 arc_print_operand_address (FILE *file, rtx addr) | |
1838 { | |
1839 register rtx base, index = 0; | |
1840 int offset = 0; | |
1841 | |
1842 switch (GET_CODE (addr)) | |
1843 { | |
1844 case REG : | |
1845 fputs (reg_names[REGNO (addr)], file); | |
1846 break; | |
1847 case SYMBOL_REF : | |
1848 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr)) | |
1849 { | |
1850 fprintf (file, "%%st("); | |
1851 output_addr_const (file, addr); | |
1852 fprintf (file, ")"); | |
1853 } | |
1854 else | |
1855 output_addr_const (file, addr); | |
1856 break; | |
1857 case PLUS : | |
1858 if (GET_CODE (XEXP (addr, 0)) == CONST_INT) | |
1859 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1); | |
1860 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) | |
1861 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0); | |
1862 else | |
1863 base = XEXP (addr, 0), index = XEXP (addr, 1); | |
1864 gcc_assert (GET_CODE (base) == REG); | |
1865 fputs (reg_names[REGNO (base)], file); | |
1866 if (index == 0) | |
1867 { | |
1868 if (offset != 0) | |
1869 fprintf (file, ",%d", offset); | |
1870 } | |
1871 else | |
1872 { | |
1873 switch (GET_CODE (index)) | |
1874 { | |
1875 case REG: | |
1876 fprintf (file, ",%s", reg_names[REGNO (index)]); | |
1877 break; | |
1878 case SYMBOL_REF: | |
1879 fputc (',', file), output_addr_const (file, index); | |
1880 break; | |
1881 default: | |
1882 gcc_unreachable (); | |
1883 } | |
1884 } | |
1885 break; | |
1886 case PRE_INC : | |
1887 case PRE_DEC : | |
1888 /* We shouldn't get here as we've lost the mode of the memory object | |
1889 (which says how much to inc/dec by. */ | |
1890 gcc_unreachable (); | |
1891 break; | |
1892 default : | |
1893 output_addr_const (file, addr); | |
1894 break; | |
1895 } | |
1896 } | |
1897 | |
1898 /* Update compare/branch separation marker. */ | |
1899 | |
1900 static void | |
1901 record_cc_ref (rtx insn) | |
1902 { | |
1903 last_insn_set_cc_p = current_insn_set_cc_p; | |
1904 | |
1905 switch (get_attr_cond (insn)) | |
1906 { | |
1907 case COND_SET : | |
1908 case COND_SET_ZN : | |
1909 case COND_SET_ZNC : | |
1910 if (get_attr_length (insn) == 1) | |
1911 current_insn_set_cc_p = 1; | |
1912 else | |
1913 current_insn_set_cc_p = 0; | |
1914 break; | |
1915 default : | |
1916 current_insn_set_cc_p = 0; | |
1917 break; | |
1918 } | |
1919 } | |
1920 | |
1921 /* Conditional execution support. | |
1922 | |
1923 This is based on the ARM port but for now is much simpler. | |
1924 | |
1925 A finite state machine takes care of noticing whether or not instructions | |
1926 can be conditionally executed, and thus decrease execution time and code | |
1927 size by deleting branch instructions. The fsm is controlled by | |
1928 final_prescan_insn, and controls the actions of PRINT_OPERAND. The patterns | |
1929 in the .md file for the branch insns also have a hand in this. */ | |
1930 | |
1931 /* The state of the fsm controlling condition codes are: | |
1932 0: normal, do nothing special | |
1933 1: don't output this insn | |
1934 2: don't output this insn | |
1935 3: make insns conditional | |
1936 4: make insns conditional | |
1937 | |
1938 State transitions (state->state by whom, under what condition): | |
1939 0 -> 1 final_prescan_insn, if insn is conditional branch | |
1940 0 -> 2 final_prescan_insn, if the `target' is an unconditional branch | |
1941 1 -> 3 branch patterns, after having not output the conditional branch | |
1942 2 -> 4 branch patterns, after having not output the conditional branch | |
1943 3 -> 0 (*targetm.asm_out.internal_label), if the `target' label is reached | |
1944 (the target label has CODE_LABEL_NUMBER equal to | |
1945 arc_ccfsm_target_label). | |
1946 4 -> 0 final_prescan_insn, if `target' unconditional branch is reached | |
1947 | |
1948 If the jump clobbers the conditions then we use states 2 and 4. | |
1949 | |
1950 A similar thing can be done with conditional return insns. | |
1951 | |
1952 We also handle separating branches from sets of the condition code. | |
1953 This is done here because knowledge of the ccfsm state is required, | |
1954 we may not be outputting the branch. */ | |
1955 | |
1956 void | |
1957 arc_final_prescan_insn (rtx insn, | |
1958 rtx *opvec ATTRIBUTE_UNUSED, | |
1959 int noperands ATTRIBUTE_UNUSED) | |
1960 { | |
1961 /* BODY will hold the body of INSN. */ | |
1962 register rtx body = PATTERN (insn); | |
1963 | |
1964 /* This will be 1 if trying to repeat the trick (i.e.: do the `else' part of | |
1965 an if/then/else), and things need to be reversed. */ | |
1966 int reverse = 0; | |
1967 | |
1968 /* If we start with a return insn, we only succeed if we find another one. */ | |
1969 int seeking_return = 0; | |
1970 | |
1971 /* START_INSN will hold the insn from where we start looking. This is the | |
1972 first insn after the following code_label if REVERSE is true. */ | |
1973 rtx start_insn = insn; | |
1974 | |
1975 /* Update compare/branch separation marker. */ | |
1976 record_cc_ref (insn); | |
1977 | |
1978 /* Allow -mdebug-ccfsm to turn this off so we can see how well it does. | |
1979 We can't do this in macro FINAL_PRESCAN_INSN because its called from | |
1980 final_scan_insn which has `optimize' as a local. */ | |
1981 if (optimize < 2 || TARGET_NO_COND_EXEC) | |
1982 return; | |
1983 | |
1984 /* If in state 4, check if the target branch is reached, in order to | |
1985 change back to state 0. */ | |
1986 if (arc_ccfsm_state == 4) | |
1987 { | |
1988 if (insn == arc_ccfsm_target_insn) | |
1989 { | |
1990 arc_ccfsm_target_insn = NULL; | |
1991 arc_ccfsm_state = 0; | |
1992 } | |
1993 return; | |
1994 } | |
1995 | |
1996 /* If in state 3, it is possible to repeat the trick, if this insn is an | |
1997 unconditional branch to a label, and immediately following this branch | |
1998 is the previous target label which is only used once, and the label this | |
1999 branch jumps to is not too far off. Or in other words "we've done the | |
2000 `then' part, see if we can do the `else' part." */ | |
2001 if (arc_ccfsm_state == 3) | |
2002 { | |
2003 if (simplejump_p (insn)) | |
2004 { | |
2005 start_insn = next_nonnote_insn (start_insn); | |
2006 if (GET_CODE (start_insn) == BARRIER) | |
2007 { | |
2008 /* ??? Isn't this always a barrier? */ | |
2009 start_insn = next_nonnote_insn (start_insn); | |
2010 } | |
2011 if (GET_CODE (start_insn) == CODE_LABEL | |
2012 && CODE_LABEL_NUMBER (start_insn) == arc_ccfsm_target_label | |
2013 && LABEL_NUSES (start_insn) == 1) | |
2014 reverse = TRUE; | |
2015 else | |
2016 return; | |
2017 } | |
2018 else if (GET_CODE (body) == RETURN) | |
2019 { | |
2020 start_insn = next_nonnote_insn (start_insn); | |
2021 if (GET_CODE (start_insn) == BARRIER) | |
2022 start_insn = next_nonnote_insn (start_insn); | |
2023 if (GET_CODE (start_insn) == CODE_LABEL | |
2024 && CODE_LABEL_NUMBER (start_insn) == arc_ccfsm_target_label | |
2025 && LABEL_NUSES (start_insn) == 1) | |
2026 { | |
2027 reverse = TRUE; | |
2028 seeking_return = 1; | |
2029 } | |
2030 else | |
2031 return; | |
2032 } | |
2033 else | |
2034 return; | |
2035 } | |
2036 | |
2037 if (GET_CODE (insn) != JUMP_INSN) | |
2038 return; | |
2039 | |
2040 /* This jump might be paralleled with a clobber of the condition codes, | |
2041 the jump should always come first. */ | |
2042 if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0) | |
2043 body = XVECEXP (body, 0, 0); | |
2044 | |
2045 if (reverse | |
2046 || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC | |
2047 && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE)) | |
2048 { | |
2049 int insns_skipped = 0, fail = FALSE, succeed = FALSE; | |
2050 /* Flag which part of the IF_THEN_ELSE is the LABEL_REF. */ | |
2051 int then_not_else = TRUE; | |
2052 /* Nonzero if next insn must be the target label. */ | |
2053 int next_must_be_target_label_p; | |
2054 rtx this_insn = start_insn, label = 0; | |
2055 | |
2056 /* Register the insn jumped to. */ | |
2057 if (reverse) | |
2058 { | |
2059 if (!seeking_return) | |
2060 label = XEXP (SET_SRC (body), 0); | |
2061 } | |
2062 else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF) | |
2063 label = XEXP (XEXP (SET_SRC (body), 1), 0); | |
2064 else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF) | |
2065 { | |
2066 label = XEXP (XEXP (SET_SRC (body), 2), 0); | |
2067 then_not_else = FALSE; | |
2068 } | |
2069 else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN) | |
2070 seeking_return = 1; | |
2071 else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN) | |
2072 { | |
2073 seeking_return = 1; | |
2074 then_not_else = FALSE; | |
2075 } | |
2076 else | |
2077 gcc_unreachable (); | |
2078 | |
2079 /* See how many insns this branch skips, and what kind of insns. If all | |
2080 insns are okay, and the label or unconditional branch to the same | |
2081 label is not too far away, succeed. */ | |
2082 for (insns_skipped = 0, next_must_be_target_label_p = FALSE; | |
2083 !fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED; | |
2084 insns_skipped++) | |
2085 { | |
2086 rtx scanbody; | |
2087 | |
2088 this_insn = next_nonnote_insn (this_insn); | |
2089 if (!this_insn) | |
2090 break; | |
2091 | |
2092 if (next_must_be_target_label_p) | |
2093 { | |
2094 if (GET_CODE (this_insn) == BARRIER) | |
2095 continue; | |
2096 if (GET_CODE (this_insn) == CODE_LABEL | |
2097 && this_insn == label) | |
2098 { | |
2099 arc_ccfsm_state = 1; | |
2100 succeed = TRUE; | |
2101 } | |
2102 else | |
2103 fail = TRUE; | |
2104 break; | |
2105 } | |
2106 | |
2107 scanbody = PATTERN (this_insn); | |
2108 | |
2109 switch (GET_CODE (this_insn)) | |
2110 { | |
2111 case CODE_LABEL: | |
2112 /* Succeed if it is the target label, otherwise fail since | |
2113 control falls in from somewhere else. */ | |
2114 if (this_insn == label) | |
2115 { | |
2116 arc_ccfsm_state = 1; | |
2117 succeed = TRUE; | |
2118 } | |
2119 else | |
2120 fail = TRUE; | |
2121 break; | |
2122 | |
2123 case BARRIER: | |
2124 /* Succeed if the following insn is the target label. | |
2125 Otherwise fail. | |
2126 If return insns are used then the last insn in a function | |
2127 will be a barrier. */ | |
2128 next_must_be_target_label_p = TRUE; | |
2129 break; | |
2130 | |
2131 case CALL_INSN: | |
2132 /* Can handle a call insn if there are no insns after it. | |
2133 IE: The next "insn" is the target label. We don't have to | |
2134 worry about delay slots as such insns are SEQUENCE's inside | |
2135 INSN's. ??? It is possible to handle such insns though. */ | |
2136 if (get_attr_cond (this_insn) == COND_CANUSE) | |
2137 next_must_be_target_label_p = TRUE; | |
2138 else | |
2139 fail = TRUE; | |
2140 break; | |
2141 | |
2142 case JUMP_INSN: | |
2143 /* If this is an unconditional branch to the same label, succeed. | |
2144 If it is to another label, do nothing. If it is conditional, | |
2145 fail. */ | |
2146 /* ??? Probably, the test for the SET and the PC are unnecessary. */ | |
2147 | |
2148 if (GET_CODE (scanbody) == SET | |
2149 && GET_CODE (SET_DEST (scanbody)) == PC) | |
2150 { | |
2151 if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF | |
2152 && XEXP (SET_SRC (scanbody), 0) == label && !reverse) | |
2153 { | |
2154 arc_ccfsm_state = 2; | |
2155 succeed = TRUE; | |
2156 } | |
2157 else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE) | |
2158 fail = TRUE; | |
2159 } | |
2160 else if (GET_CODE (scanbody) == RETURN | |
2161 && seeking_return) | |
2162 { | |
2163 arc_ccfsm_state = 2; | |
2164 succeed = TRUE; | |
2165 } | |
2166 else if (GET_CODE (scanbody) == PARALLEL) | |
2167 { | |
2168 if (get_attr_cond (this_insn) != COND_CANUSE) | |
2169 fail = TRUE; | |
2170 } | |
2171 break; | |
2172 | |
2173 case INSN: | |
2174 /* We can only do this with insns that can use the condition | |
2175 codes (and don't set them). */ | |
2176 if (GET_CODE (scanbody) == SET | |
2177 || GET_CODE (scanbody) == PARALLEL) | |
2178 { | |
2179 if (get_attr_cond (this_insn) != COND_CANUSE) | |
2180 fail = TRUE; | |
2181 } | |
2182 /* We can't handle other insns like sequences. */ | |
2183 else | |
2184 fail = TRUE; | |
2185 break; | |
2186 | |
2187 default: | |
2188 break; | |
2189 } | |
2190 } | |
2191 | |
2192 if (succeed) | |
2193 { | |
2194 if ((!seeking_return) && (arc_ccfsm_state == 1 || reverse)) | |
2195 arc_ccfsm_target_label = CODE_LABEL_NUMBER (label); | |
2196 else | |
2197 { | |
2198 gcc_assert (seeking_return || arc_ccfsm_state == 2); | |
2199 while (this_insn && GET_CODE (PATTERN (this_insn)) == USE) | |
2200 { | |
2201 this_insn = next_nonnote_insn (this_insn); | |
2202 gcc_assert (!this_insn | |
2203 || (GET_CODE (this_insn) != BARRIER | |
2204 && GET_CODE (this_insn) != CODE_LABEL)); | |
2205 } | |
2206 if (!this_insn) | |
2207 { | |
2208 /* Oh dear! we ran off the end, give up. */ | |
2209 extract_insn_cached (insn); | |
2210 arc_ccfsm_state = 0; | |
2211 arc_ccfsm_target_insn = NULL; | |
2212 return; | |
2213 } | |
2214 arc_ccfsm_target_insn = this_insn; | |
2215 } | |
2216 | |
2217 /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from | |
2218 what it was. */ | |
2219 if (!reverse) | |
2220 arc_ccfsm_current_cc = get_arc_condition_code (XEXP (SET_SRC (body), | |
2221 0)); | |
2222 | |
2223 if (reverse || then_not_else) | |
2224 arc_ccfsm_current_cc = ARC_INVERSE_CONDITION_CODE (arc_ccfsm_current_cc); | |
2225 } | |
2226 | |
2227 /* Restore recog_data. Getting the attributes of other insns can | |
2228 destroy this array, but final.c assumes that it remains intact | |
2229 across this call. */ | |
2230 extract_insn_cached (insn); | |
2231 } | |
2232 } | |
2233 | |
2234 /* Record that we are currently outputting label NUM with prefix PREFIX. | |
2235 It it's the label we're looking for, reset the ccfsm machinery. | |
2236 | |
2237 Called from (*targetm.asm_out.internal_label). */ | |
2238 | |
2239 void | |
2240 arc_ccfsm_at_label (const char *prefix, int num) | |
2241 { | |
2242 if (arc_ccfsm_state == 3 && arc_ccfsm_target_label == num | |
2243 && !strcmp (prefix, "L")) | |
2244 { | |
2245 arc_ccfsm_state = 0; | |
2246 arc_ccfsm_target_insn = NULL_RTX; | |
2247 } | |
2248 } | |
2249 | |
2250 /* See if the current insn, which is a conditional branch, is to be | |
2251 deleted. */ | |
2252 | |
2253 int | |
2254 arc_ccfsm_branch_deleted_p (void) | |
2255 { | |
2256 if (arc_ccfsm_state == 1 || arc_ccfsm_state == 2) | |
2257 return 1; | |
2258 return 0; | |
2259 } | |
2260 | |
2261 /* Record a branch isn't output because subsequent insns can be | |
2262 conditionalized. */ | |
2263 | |
2264 void | |
2265 arc_ccfsm_record_branch_deleted (void) | |
2266 { | |
2267 /* Indicate we're conditionalizing insns now. */ | |
2268 arc_ccfsm_state += 2; | |
2269 | |
2270 /* If the next insn is a subroutine call, we still need a nop between the | |
2271 cc setter and user. We need to undo the effect of calling record_cc_ref | |
2272 for the just deleted branch. */ | |
2273 current_insn_set_cc_p = last_insn_set_cc_p; | |
2274 } | |
2275 | |
2276 static void | |
2277 arc_va_start (tree valist, rtx nextarg) | |
2278 { | |
2279 /* See arc_setup_incoming_varargs for reasons for this oddity. */ | |
2280 if (crtl->args.info < 8 | |
2281 && (crtl->args.info & 1)) | |
2282 nextarg = plus_constant (nextarg, UNITS_PER_WORD); | |
2283 | |
2284 std_expand_builtin_va_start (valist, nextarg); | |
2285 } | |
2286 | |
2287 /* This is how to output a definition of an internal numbered label where | |
2288 PREFIX is the class of label and NUM is the number within the class. */ | |
2289 | |
2290 static void | |
2291 arc_internal_label (FILE *stream, const char *prefix, unsigned long labelno) | |
2292 { | |
2293 arc_ccfsm_at_label (prefix, labelno); | |
2294 default_internal_label (stream, prefix, labelno); | |
2295 } | |
2296 | |
2297 /* Worker function for TARGET_ASM_EXTERNAL_LIBCALL. */ | |
2298 | |
2299 static void | |
2300 arc_external_libcall (rtx fun ATTRIBUTE_UNUSED) | |
2301 { | |
2302 #if 0 | |
2303 /* On the ARC we want to have libgcc's for multiple cpus in one binary. | |
2304 We can't use `assemble_name' here as that will call ASM_OUTPUT_LABELREF | |
2305 and we'll get another suffix added on if -mmangle-cpu. */ | |
2306 if (TARGET_MANGLE_CPU_LIBGCC) | |
2307 { | |
2308 fprintf (FILE, "\t.rename\t_%s, _%s%s\n", | |
2309 XSTR (SYMREF, 0), XSTR (SYMREF, 0), | |
2310 arc_mangle_suffix); | |
2311 } | |
2312 #endif | |
2313 } | |
2314 | |
2315 /* Worker function for TARGET_RETURN_IN_MEMORY. */ | |
2316 | |
2317 static bool | |
2318 arc_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) | |
2319 { | |
2320 if (AGGREGATE_TYPE_P (type)) | |
2321 return true; | |
2322 else | |
2323 { | |
2324 HOST_WIDE_INT size = int_size_in_bytes (type); | |
2325 return (size == -1 || size > 8); | |
2326 } | |
2327 } | |
2328 | |
2329 /* For ARC, All aggregates and arguments greater than 8 bytes are | |
2330 passed by reference. */ | |
2331 | |
2332 static bool | |
2333 arc_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED, | |
2334 enum machine_mode mode, const_tree type, | |
2335 bool named ATTRIBUTE_UNUSED) | |
2336 { | |
2337 unsigned HOST_WIDE_INT size; | |
2338 | |
2339 if (type) | |
2340 { | |
2341 if (AGGREGATE_TYPE_P (type)) | |
2342 return true; | |
2343 size = int_size_in_bytes (type); | |
2344 } | |
2345 else | |
2346 size = GET_MODE_SIZE (mode); | |
2347 | |
2348 return size > 8; | |
2349 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2350 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2351 /* Trampolines. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2352 /* ??? This doesn't work yet because GCC will use as the address of a nested |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2353 function the address of the trampoline. We need to use that address |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2354 right shifted by 2. It looks like we'll need PSImode after all. :-( |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2355 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2356 ??? The above comment sounds like it's doable via |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2357 TARGET_TRAMPOLINE_ADJUST_ADDRESS; no PSImode needed. |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2358 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2359 On the ARC, the trampoline is quite simple as we have 32-bit immediate |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2360 constants. |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2361 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2362 mov r24,STATIC |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2363 j.nd FUNCTION |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2364 */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2365 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2366 static void |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2367 arc_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2368 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2369 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2370 rtx mem; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2371 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2372 mem = adjust_address (m_tramp, SImode, 0); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2373 emit_move_insn (mem, GEN_INT (0x631f7c00)); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2374 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2375 mem = adjust_address (m_tramp, SImode, 4); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2376 emit_move_insn (mem, chain_value); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2377 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2378 mem = adjust_address (m_tramp, SImode, 8); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2379 emit_move_insn (mem, GEN_INT (0x381f0000)); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2380 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2381 mem = adjust_address (m_tramp, SImode, 12); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2382 emit_move_insn (mem, fnaddr); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2383 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2384 emit_insn (gen_flush_icache (m_tramp)); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
2385 } |