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