]>
Commit | Line | Data |
---|---|---|
2e076ddf | 1 | /* Subroutines used for code generation on the Mitsubishi M32R cpu. |
c5c76735 | 2 | Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. |
8c5ca3b9 DE |
3 | |
4 | This file is part of GNU CC. | |
5 | ||
6 | GNU CC is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GNU CC is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU CC; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
19 | Boston, MA 02111-1307, USA. */ | |
20 | ||
8c5ca3b9 | 21 | #include "config.h" |
5b8ae21f | 22 | #include "system.h" |
8c5ca3b9 DE |
23 | #include "tree.h" |
24 | #include "rtl.h" | |
25 | #include "regs.h" | |
26 | #include "hard-reg-set.h" | |
27 | #include "real.h" | |
28 | #include "insn-config.h" | |
29 | #include "conditions.h" | |
30 | #include "insn-flags.h" | |
31 | #include "output.h" | |
32 | #include "insn-attr.h" | |
33 | #include "flags.h" | |
34 | #include "expr.h" | |
bf6bb899 | 35 | #include "function.h" |
8c5ca3b9 DE |
36 | #include "recog.h" |
37 | ||
38 | /* Save the operands last given to a compare for use when we | |
39 | generate a scc or bcc insn. */ | |
40 | rtx m32r_compare_op0, m32r_compare_op1; | |
41 | ||
42 | /* Array of valid operand punctuation characters. */ | |
43 | char m32r_punct_chars[256]; | |
44 | ||
8c5ca3b9 DE |
45 | /* Selected code model. */ |
46 | char *m32r_model_string = M32R_MODEL_DEFAULT; | |
47 | enum m32r_model m32r_model; | |
48 | ||
49 | /* Selected SDA support. */ | |
50 | char *m32r_sdata_string = M32R_SDATA_DEFAULT; | |
51 | enum m32r_sdata m32r_sdata; | |
52 | ||
2b7972b0 MM |
53 | |
54 | /* Forward declaration. */ | |
55 | static void init_reg_tables PROTO((void)); | |
56 | ||
8c5ca3b9 DE |
57 | /* Called by OVERRIDE_OPTIONS to initialize various things. */ |
58 | ||
59 | void | |
60 | m32r_init () | |
61 | { | |
62 | init_reg_tables (); | |
63 | ||
64 | /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */ | |
65 | memset (m32r_punct_chars, 0, sizeof (m32r_punct_chars)); | |
66 | m32r_punct_chars['#'] = 1; | |
67 | m32r_punct_chars['@'] = 1; /* ??? no longer used */ | |
68 | ||
69 | /* Provide default value if not specified. */ | |
70 | if (!g_switch_set) | |
71 | g_switch_value = SDATA_DEFAULT_SIZE; | |
72 | ||
73 | if (strcmp (m32r_model_string, "small") == 0) | |
74 | m32r_model = M32R_MODEL_SMALL; | |
75 | else if (strcmp (m32r_model_string, "medium") == 0) | |
76 | m32r_model = M32R_MODEL_MEDIUM; | |
77 | else if (strcmp (m32r_model_string, "large") == 0) | |
78 | m32r_model = M32R_MODEL_LARGE; | |
79 | else | |
80 | error ("bad value (%s) for -mmodel switch", m32r_model_string); | |
81 | ||
82 | if (strcmp (m32r_sdata_string, "none") == 0) | |
83 | m32r_sdata = M32R_SDATA_NONE; | |
84 | else if (strcmp (m32r_sdata_string, "sdata") == 0) | |
85 | m32r_sdata = M32R_SDATA_SDATA; | |
86 | else if (strcmp (m32r_sdata_string, "use") == 0) | |
87 | m32r_sdata = M32R_SDATA_USE; | |
88 | else | |
89 | error ("bad value (%s) for -msdata switch", m32r_sdata_string); | |
2b7972b0 | 90 | |
8c5ca3b9 DE |
91 | } |
92 | ||
93 | /* Vectors to keep interesting information about registers where it can easily | |
94 | be got. We use to use the actual mode value as the bit number, but there | |
95 | is (or may be) more than 32 modes now. Instead we use two tables: one | |
96 | indexed by hard register number, and one indexed by mode. */ | |
97 | ||
98 | /* The purpose of m32r_mode_class is to shrink the range of modes so that | |
99 | they all fit (as bit numbers) in a 32 bit word (again). Each real mode is | |
100 | mapped into one m32r_mode_class mode. */ | |
101 | ||
2b7972b0 MM |
102 | enum m32r_mode_class |
103 | { | |
8c5ca3b9 DE |
104 | C_MODE, |
105 | S_MODE, D_MODE, T_MODE, O_MODE, | |
106 | SF_MODE, DF_MODE, TF_MODE, OF_MODE | |
107 | }; | |
108 | ||
109 | /* Modes for condition codes. */ | |
110 | #define C_MODES (1 << (int) C_MODE) | |
111 | ||
112 | /* Modes for single-word and smaller quantities. */ | |
113 | #define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE)) | |
114 | ||
115 | /* Modes for double-word and smaller quantities. */ | |
116 | #define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE)) | |
117 | ||
118 | /* Modes for quad-word and smaller quantities. */ | |
119 | #define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE)) | |
120 | ||
2b7972b0 | 121 | |
8c5ca3b9 DE |
122 | /* Value is 1 if register/mode pair is acceptable on arc. */ |
123 | ||
2b7972b0 MM |
124 | unsigned int m32r_hard_regno_mode_ok[FIRST_PSEUDO_REGISTER] = |
125 | { | |
8c5ca3b9 DE |
126 | T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, |
127 | T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, S_MODES, S_MODES, S_MODES, | |
128 | S_MODES, C_MODES | |
129 | }; | |
130 | ||
131 | unsigned int m32r_mode_class [NUM_MACHINE_MODES]; | |
132 | ||
133 | enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER]; | |
134 | ||
135 | static void | |
136 | init_reg_tables () | |
137 | { | |
138 | int i; | |
139 | ||
140 | for (i = 0; i < NUM_MACHINE_MODES; i++) | |
141 | { | |
142 | switch (GET_MODE_CLASS (i)) | |
143 | { | |
144 | case MODE_INT: | |
145 | case MODE_PARTIAL_INT: | |
146 | case MODE_COMPLEX_INT: | |
147 | if (GET_MODE_SIZE (i) <= 4) | |
148 | m32r_mode_class[i] = 1 << (int) S_MODE; | |
149 | else if (GET_MODE_SIZE (i) == 8) | |
150 | m32r_mode_class[i] = 1 << (int) D_MODE; | |
151 | else if (GET_MODE_SIZE (i) == 16) | |
152 | m32r_mode_class[i] = 1 << (int) T_MODE; | |
153 | else if (GET_MODE_SIZE (i) == 32) | |
154 | m32r_mode_class[i] = 1 << (int) O_MODE; | |
155 | else | |
156 | m32r_mode_class[i] = 0; | |
157 | break; | |
158 | case MODE_FLOAT: | |
159 | case MODE_COMPLEX_FLOAT: | |
160 | if (GET_MODE_SIZE (i) <= 4) | |
161 | m32r_mode_class[i] = 1 << (int) SF_MODE; | |
162 | else if (GET_MODE_SIZE (i) == 8) | |
163 | m32r_mode_class[i] = 1 << (int) DF_MODE; | |
164 | else if (GET_MODE_SIZE (i) == 16) | |
165 | m32r_mode_class[i] = 1 << (int) TF_MODE; | |
166 | else if (GET_MODE_SIZE (i) == 32) | |
167 | m32r_mode_class[i] = 1 << (int) OF_MODE; | |
168 | else | |
169 | m32r_mode_class[i] = 0; | |
170 | break; | |
171 | case MODE_CC: | |
172 | default: | |
173 | /* mode_class hasn't been initialized yet for EXTRA_CC_MODES, so | |
174 | we must explicitly check for them here. */ | |
175 | if (i == (int) CCmode) | |
176 | m32r_mode_class[i] = 1 << (int) C_MODE; | |
177 | else | |
178 | m32r_mode_class[i] = 0; | |
179 | break; | |
180 | } | |
181 | } | |
182 | ||
183 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
184 | { | |
185 | if (GPR_P (i)) | |
186 | m32r_regno_reg_class[i] = GENERAL_REGS; | |
187 | else if (i == ARG_POINTER_REGNUM) | |
188 | m32r_regno_reg_class[i] = GENERAL_REGS; | |
189 | else | |
190 | m32r_regno_reg_class[i] = NO_REGS; | |
191 | } | |
192 | } | |
193 | \f | |
194 | /* M32R specific attribute support. | |
195 | ||
196 | interrupt - for interrupt functions | |
197 | ||
198 | model - select code model used to access object | |
199 | ||
200 | small: addresses use 24 bits, use bl to make calls | |
201 | medium: addresses use 32 bits, use bl to make calls | |
202 | large: addresses use 32 bits, use seth/add3/jl to make calls | |
203 | ||
204 | Grep for MODEL in m32r.h for more info. | |
205 | */ | |
206 | ||
6aa489b4 NC |
207 | static tree interrupt_ident1; |
208 | static tree interrupt_ident2; | |
209 | static tree model_ident1; | |
210 | static tree model_ident2; | |
211 | static tree small_ident1; | |
212 | static tree small_ident2; | |
213 | static tree medium_ident1; | |
214 | static tree medium_ident2; | |
215 | static tree large_ident1; | |
216 | static tree large_ident2; | |
217 | ||
218 | static void | |
219 | init_idents PROTO ((void)) | |
220 | { | |
221 | if (interrupt_ident1 == 0) | |
222 | { | |
223 | interrupt_ident1 = get_identifier ("interrupt"); | |
224 | interrupt_ident2 = get_identifier ("__interrupt__"); | |
225 | model_ident1 = get_identifier ("model"); | |
226 | model_ident2 = get_identifier ("__model__"); | |
227 | small_ident1 = get_identifier ("small"); | |
228 | small_ident2 = get_identifier ("__small__"); | |
229 | medium_ident1 = get_identifier ("medium"); | |
230 | medium_ident2 = get_identifier ("__medium__"); | |
231 | large_ident1 = get_identifier ("large"); | |
232 | large_ident2 = get_identifier ("__large__"); | |
233 | } | |
234 | } | |
235 | ||
8c5ca3b9 DE |
236 | /* Return nonzero if IDENTIFIER is a valid decl attribute. */ |
237 | ||
238 | int | |
239 | m32r_valid_machine_decl_attribute (type, attributes, identifier, args) | |
240 | tree type; | |
241 | tree attributes; | |
242 | tree identifier; | |
243 | tree args; | |
244 | { | |
dd535142 | 245 | init_idents (); |
8c5ca3b9 | 246 | |
6aa489b4 NC |
247 | if ((identifier == interrupt_ident1 |
248 | || identifier == interrupt_ident2) | |
8c5ca3b9 DE |
249 | && list_length (args) == 0) |
250 | return 1; | |
251 | ||
6aa489b4 NC |
252 | if ((identifier == model_ident1 |
253 | || identifier == model_ident2) | |
8c5ca3b9 | 254 | && list_length (args) == 1 |
6aa489b4 NC |
255 | && (TREE_VALUE (args) == small_ident1 |
256 | || TREE_VALUE (args) == small_ident2 | |
257 | || TREE_VALUE (args) == medium_ident1 | |
258 | || TREE_VALUE (args) == medium_ident2 | |
259 | || TREE_VALUE (args) == large_ident1 | |
260 | || TREE_VALUE (args) == large_ident2)) | |
8c5ca3b9 DE |
261 | return 1; |
262 | ||
263 | return 0; | |
264 | } | |
265 | ||
266 | /* Return zero if TYPE1 and TYPE are incompatible, one if they are compatible, | |
267 | and two if they are nearly compatible (which causes a warning to be | |
268 | generated). */ | |
269 | ||
270 | int | |
271 | m32r_comp_type_attributes (type1, type2) | |
272 | tree type1, type2; | |
273 | { | |
274 | return 1; | |
275 | } | |
276 | ||
277 | /* Set the default attributes for TYPE. */ | |
278 | ||
279 | void | |
280 | m32r_set_default_type_attributes (type) | |
281 | tree type; | |
282 | { | |
283 | } | |
284 | \f | |
285 | /* A C statement or statements to switch to the appropriate | |
286 | section for output of DECL. DECL is either a `VAR_DECL' node | |
287 | or a constant of some sort. RELOC indicates whether forming | |
288 | the initial value of DECL requires link-time relocations. */ | |
289 | ||
290 | void | |
291 | m32r_select_section (decl, reloc) | |
292 | tree decl; | |
293 | int reloc; | |
294 | { | |
295 | if (TREE_CODE (decl) == STRING_CST) | |
296 | { | |
297 | if (! flag_writable_strings) | |
298 | const_section (); | |
299 | else | |
300 | data_section (); | |
301 | } | |
302 | else if (TREE_CODE (decl) == VAR_DECL) | |
303 | { | |
304 | if (SDATA_NAME_P (XSTR (XEXP (DECL_RTL (decl), 0), 0))) | |
305 | sdata_section (); | |
306 | else if ((flag_pic && reloc) | |
307 | || !TREE_READONLY (decl) | |
308 | || TREE_SIDE_EFFECTS (decl) | |
309 | || !DECL_INITIAL (decl) | |
310 | || (DECL_INITIAL (decl) != error_mark_node | |
311 | && !TREE_CONSTANT (DECL_INITIAL (decl)))) | |
312 | data_section (); | |
313 | else | |
314 | const_section (); | |
315 | } | |
316 | else | |
317 | const_section (); | |
318 | } | |
319 | ||
320 | /* Encode section information of DECL, which is either a VAR_DECL, | |
321 | FUNCTION_DECL, STRING_CST, CONSTRUCTOR, or ???. | |
322 | ||
323 | For the M32R we want to record: | |
324 | ||
325 | - whether the object lives in .sdata/.sbss. | |
326 | objects living in .sdata/.sbss are prefixed with SDATA_FLAG_CHAR | |
327 | ||
328 | - what code model should be used to access the object | |
329 | small: recorded with no flag - for space efficiency since they'll | |
330 | be the most common | |
331 | medium: prefixed with MEDIUM_FLAG_CHAR | |
332 | large: prefixed with LARGE_FLAG_CHAR | |
333 | */ | |
334 | ||
335 | void | |
336 | m32r_encode_section_info (decl) | |
337 | tree decl; | |
338 | { | |
339 | char prefix = 0; | |
340 | tree model = 0; | |
341 | ||
342 | switch (TREE_CODE (decl)) | |
343 | { | |
344 | case VAR_DECL : | |
345 | case FUNCTION_DECL : | |
346 | model = lookup_attribute ("model", DECL_MACHINE_ATTRIBUTES (decl)); | |
347 | break; | |
348 | case STRING_CST : | |
349 | case CONSTRUCTOR : | |
350 | /* ??? document all others that can appear here */ | |
351 | default : | |
352 | return; | |
353 | } | |
354 | ||
355 | /* Only mark the object as being small data area addressable if | |
356 | it hasn't been explicitly marked with a code model. | |
357 | ||
358 | The user can explicitly put an object in the small data area with the | |
359 | section attribute. If the object is in sdata/sbss and marked with a | |
360 | code model do both [put the object in .sdata and mark it as being | |
361 | addressed with a specific code model - don't mark it as being addressed | |
362 | with an SDA reloc though]. This is ok and might be useful at times. If | |
363 | the object doesn't fit the linker will give an error. */ | |
364 | ||
365 | if (! model) | |
366 | { | |
367 | if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd' | |
368 | && DECL_SECTION_NAME (decl) != NULL_TREE) | |
369 | { | |
370 | char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); | |
371 | if (! strcmp (name, ".sdata") || ! strcmp (name, ".sbss")) | |
372 | { | |
373 | #if 0 /* ??? There's no reason to disallow this, is there? */ | |
374 | if (TREE_READONLY (decl)) | |
375 | error_with_decl (decl, "const objects cannot go in .sdata/.sbss"); | |
376 | #endif | |
377 | prefix = SDATA_FLAG_CHAR; | |
378 | } | |
379 | } | |
380 | else | |
381 | { | |
382 | if (TREE_CODE (decl) == VAR_DECL | |
383 | && ! TREE_READONLY (decl) | |
384 | && ! TARGET_SDATA_NONE) | |
385 | { | |
386 | int size = int_size_in_bytes (TREE_TYPE (decl)); | |
387 | ||
388 | if (size > 0 && size <= g_switch_value) | |
389 | prefix = SDATA_FLAG_CHAR; | |
390 | } | |
391 | } | |
392 | } | |
393 | ||
394 | /* If data area not decided yet, check for a code model. */ | |
395 | if (prefix == 0) | |
396 | { | |
397 | if (model) | |
398 | { | |
6aa489b4 | 399 | tree id; |
dd535142 | 400 | |
6aa489b4 NC |
401 | init_idents (); |
402 | ||
403 | id = TREE_VALUE (TREE_VALUE (model)); | |
404 | ||
405 | if (id == small_ident1 || id == small_ident2) | |
8c5ca3b9 | 406 | ; /* don't mark the symbol specially */ |
6aa489b4 | 407 | else if (id == medium_ident1 || id == medium_ident2) |
8c5ca3b9 | 408 | prefix = MEDIUM_FLAG_CHAR; |
6aa489b4 | 409 | else if (id == large_ident1 || id == large_ident2) |
8c5ca3b9 DE |
410 | prefix = LARGE_FLAG_CHAR; |
411 | else | |
412 | abort (); /* shouldn't happen */ | |
413 | } | |
414 | else | |
415 | { | |
416 | if (TARGET_MODEL_SMALL) | |
417 | ; /* don't mark the symbol specially */ | |
418 | else if (TARGET_MODEL_MEDIUM) | |
419 | prefix = MEDIUM_FLAG_CHAR; | |
420 | else if (TARGET_MODEL_LARGE) | |
421 | prefix = LARGE_FLAG_CHAR; | |
422 | else | |
423 | abort (); /* shouldn't happen */ | |
424 | } | |
425 | } | |
426 | ||
427 | if (prefix != 0) | |
428 | { | |
429 | rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' | |
430 | ? TREE_CST_RTL (decl) : DECL_RTL (decl)); | |
431 | char *str = XSTR (XEXP (rtl, 0), 0); | |
432 | int len = strlen (str); | |
433 | char *newstr = savealloc (len + 2); | |
434 | strcpy (newstr + 1, str); | |
435 | *newstr = prefix; | |
436 | XSTR (XEXP (rtl, 0), 0) = newstr; | |
437 | } | |
438 | } | |
439 | ||
440 | /* Do anything needed before RTL is emitted for each function. */ | |
441 | ||
442 | void | |
443 | m32r_init_expanders () | |
444 | { | |
445 | /* ??? At one point there was code here. The function is left in | |
446 | to make it easy to experiment. */ | |
447 | } | |
448 | \f | |
449 | /* Acceptable arguments to the call insn. */ | |
450 | ||
451 | int | |
2b7972b0 | 452 | call_address_operand (op, int_mode) |
8c5ca3b9 | 453 | rtx op; |
2b7972b0 | 454 | int int_mode; |
8c5ca3b9 | 455 | { |
2b7972b0 | 456 | return symbolic_operand (op, int_mode); |
2e076ddf | 457 | |
2b7972b0 MM |
458 | /* Constants and values in registers are not OK, because |
459 | the m32r BL instruction can only support PC relative branching. */ | |
8c5ca3b9 DE |
460 | } |
461 | ||
462 | int | |
2b7972b0 | 463 | call_operand (op, int_mode) |
8c5ca3b9 | 464 | rtx op; |
2b7972b0 | 465 | int int_mode; |
8c5ca3b9 | 466 | { |
2b7972b0 MM |
467 | enum machine_mode mode = (enum machine_mode)int_mode; |
468 | ||
8c5ca3b9 DE |
469 | if (GET_CODE (op) != MEM) |
470 | return 0; | |
471 | op = XEXP (op, 0); | |
472 | return call_address_operand (op, mode); | |
473 | } | |
474 | ||
475 | /* Returns 1 if OP is a symbol reference. */ | |
476 | ||
477 | int | |
2b7972b0 | 478 | symbolic_operand (op, int_mode) |
8c5ca3b9 | 479 | rtx op; |
2b7972b0 | 480 | int int_mode; |
8c5ca3b9 DE |
481 | { |
482 | switch (GET_CODE (op)) | |
483 | { | |
484 | case SYMBOL_REF: | |
485 | case LABEL_REF: | |
486 | case CONST : | |
487 | return 1; | |
2b7972b0 | 488 | |
8c5ca3b9 DE |
489 | default: |
490 | return 0; | |
491 | } | |
492 | } | |
493 | ||
8c5ca3b9 DE |
494 | /* Return 1 if OP is a reference to an object in .sdata/.sbss. */ |
495 | ||
496 | int | |
2b7972b0 | 497 | small_data_operand (op, int_mode) |
8c5ca3b9 | 498 | rtx op; |
2b7972b0 | 499 | int int_mode; |
8c5ca3b9 DE |
500 | { |
501 | if (! TARGET_SDATA_USE) | |
502 | return 0; | |
503 | ||
504 | if (GET_CODE (op) == SYMBOL_REF) | |
505 | return SDATA_NAME_P (XSTR (op, 0)); | |
506 | ||
507 | if (GET_CODE (op) == CONST | |
508 | && GET_CODE (XEXP (op, 0)) == PLUS | |
509 | && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF | |
510 | && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT | |
511 | && INT16_P (INTVAL (XEXP (XEXP (op, 0), 1)))) | |
512 | return SDATA_NAME_P (XSTR (XEXP (XEXP (op, 0), 0), 0)); | |
513 | ||
514 | return 0; | |
515 | } | |
516 | ||
517 | /* Return 1 if OP is a symbol that can use 24 bit addressing. */ | |
518 | ||
519 | int | |
2b7972b0 | 520 | addr24_operand (op, int_mode) |
8c5ca3b9 | 521 | rtx op; |
2b7972b0 | 522 | int int_mode; |
8c5ca3b9 DE |
523 | { |
524 | if (GET_CODE (op) == LABEL_REF) | |
525 | return TARGET_ADDR24; | |
526 | ||
527 | if (GET_CODE (op) == SYMBOL_REF) | |
528 | return (SMALL_NAME_P (XSTR (op, 0)) | |
529 | || (TARGET_ADDR24 | |
630f5ae6 DE |
530 | && (CONSTANT_POOL_ADDRESS_P (op) |
531 | || LIT_NAME_P (XSTR (op, 0))))); | |
8c5ca3b9 DE |
532 | |
533 | if (GET_CODE (op) == CONST | |
534 | && GET_CODE (XEXP (op, 0)) == PLUS | |
535 | && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF | |
536 | && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT | |
537 | && UINT24_P (INTVAL (XEXP (XEXP (op, 0), 1)))) | |
538 | { | |
539 | rtx sym = XEXP (XEXP (op, 0), 0); | |
540 | return (SMALL_NAME_P (XSTR (sym, 0)) | |
541 | || (TARGET_ADDR24 | |
630f5ae6 DE |
542 | && (CONSTANT_POOL_ADDRESS_P (op) |
543 | || LIT_NAME_P (XSTR (op, 0))))); | |
8c5ca3b9 DE |
544 | } |
545 | ||
546 | return 0; | |
547 | } | |
548 | ||
549 | /* Return 1 if OP is a symbol that needs 32 bit addressing. */ | |
550 | ||
551 | int | |
2b7972b0 | 552 | addr32_operand (op, int_mode) |
8c5ca3b9 | 553 | rtx op; |
2b7972b0 | 554 | int int_mode; |
8c5ca3b9 DE |
555 | { |
556 | if (GET_CODE (op) == LABEL_REF) | |
557 | return TARGET_ADDR32; | |
558 | ||
559 | if (GET_CODE (op) == SYMBOL_REF) | |
2b7972b0 MM |
560 | return (! addr24_operand (op, int_mode) |
561 | && ! small_data_operand (op, int_mode)); | |
8c5ca3b9 DE |
562 | |
563 | if (GET_CODE (op) == CONST | |
564 | && GET_CODE (XEXP (op, 0)) == PLUS | |
565 | && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF | |
566 | && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) | |
567 | { | |
2b7972b0 MM |
568 | return (! addr24_operand (op, int_mode) |
569 | && ! small_data_operand (op, int_mode)); | |
8c5ca3b9 DE |
570 | } |
571 | ||
572 | return 0; | |
573 | } | |
574 | ||
575 | /* Return 1 if OP is a function that can be called with the `bl' insn. */ | |
576 | ||
577 | int | |
2b7972b0 | 578 | call26_operand (op, int_mode) |
8c5ca3b9 | 579 | rtx op; |
2b7972b0 | 580 | int int_mode; |
8c5ca3b9 DE |
581 | { |
582 | if (GET_CODE (op) == SYMBOL_REF) | |
583 | return ! LARGE_NAME_P (XSTR (op, 0)); | |
584 | ||
585 | return TARGET_CALL26; | |
586 | } | |
587 | ||
8c5ca3b9 DE |
588 | /* Returns 1 if OP is an acceptable operand for seth/add3. */ |
589 | ||
590 | int | |
2b7972b0 | 591 | seth_add3_operand (op, int_mode) |
8c5ca3b9 | 592 | rtx op; |
2b7972b0 | 593 | int int_mode; |
8c5ca3b9 DE |
594 | { |
595 | if (GET_CODE (op) == SYMBOL_REF | |
596 | || GET_CODE (op) == LABEL_REF) | |
597 | return 1; | |
598 | ||
599 | if (GET_CODE (op) == CONST | |
600 | && GET_CODE (XEXP (op, 0)) == PLUS | |
601 | && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF | |
602 | && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT | |
603 | && INT16_P (INTVAL (XEXP (XEXP (op, 0), 1)))) | |
604 | return 1; | |
605 | ||
606 | return 0; | |
607 | } | |
608 | ||
8c5ca3b9 DE |
609 | /* Return true if OP is a signed 16 bit immediate value |
610 | useful in comparisons. */ | |
611 | ||
612 | int | |
2b7972b0 | 613 | cmp_int16_operand (op, int_mode) |
8c5ca3b9 | 614 | rtx op; |
2b7972b0 | 615 | int int_mode; |
8c5ca3b9 DE |
616 | { |
617 | if (GET_CODE (op) != CONST_INT) | |
618 | return 0; | |
619 | return CMP_INT16_P (INTVAL (op)); | |
620 | } | |
621 | ||
622 | /* Return true if OP is an unsigned 16 bit immediate value. */ | |
623 | ||
2b7972b0 MM |
624 | int |
625 | uint16_operand (op, int_mode) | |
8c5ca3b9 | 626 | rtx op; |
2b7972b0 | 627 | int int_mode; |
8c5ca3b9 DE |
628 | { |
629 | if (GET_CODE (op) != CONST_INT) | |
630 | return 0; | |
631 | return UINT16_P (INTVAL (op)); | |
632 | } | |
633 | ||
8c5ca3b9 DE |
634 | /* Return true if OP is a register or signed 8 bit value. */ |
635 | ||
636 | int | |
2b7972b0 | 637 | reg_or_int16_operand (op, int_mode) |
8c5ca3b9 | 638 | rtx op; |
2b7972b0 | 639 | int int_mode; |
8c5ca3b9 | 640 | { |
2b7972b0 MM |
641 | enum machine_mode mode = (enum machine_mode)int_mode; |
642 | ||
8c5ca3b9 DE |
643 | if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG) |
644 | return register_operand (op, mode); | |
645 | if (GET_CODE (op) != CONST_INT) | |
646 | return 0; | |
647 | return INT16_P (INTVAL (op)); | |
648 | } | |
649 | ||
2e076ddf | 650 | /* Return true if OP is a register or an unsigned 16 bit value. */ |
8c5ca3b9 DE |
651 | |
652 | int | |
2b7972b0 | 653 | reg_or_uint16_operand (op, int_mode) |
8c5ca3b9 | 654 | rtx op; |
2b7972b0 | 655 | int int_mode; |
8c5ca3b9 | 656 | { |
2b7972b0 MM |
657 | enum machine_mode mode = (enum machine_mode)int_mode; |
658 | ||
8c5ca3b9 DE |
659 | if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG) |
660 | return register_operand (op, mode); | |
661 | if (GET_CODE (op) != CONST_INT) | |
662 | return 0; | |
663 | return UINT16_P (INTVAL (op)); | |
664 | } | |
665 | ||
666 | /* Return true if OP is a register or signed 16 bit value for compares. */ | |
667 | ||
668 | int | |
2b7972b0 | 669 | reg_or_cmp_int16_operand (op, int_mode) |
8c5ca3b9 | 670 | rtx op; |
2b7972b0 | 671 | int int_mode; |
8c5ca3b9 | 672 | { |
2b7972b0 MM |
673 | enum machine_mode mode = (enum machine_mode)int_mode; |
674 | ||
8c5ca3b9 DE |
675 | if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG) |
676 | return register_operand (op, mode); | |
677 | if (GET_CODE (op) != CONST_INT) | |
678 | return 0; | |
679 | return CMP_INT16_P (INTVAL (op)); | |
680 | } | |
681 | ||
4d6c607f DE |
682 | /* Return true if OP is a const_int requiring two instructions to load. */ |
683 | ||
684 | int | |
2b7972b0 | 685 | two_insn_const_operand (op, int_mode) |
4d6c607f | 686 | rtx op; |
2b7972b0 | 687 | int int_mode; |
4d6c607f DE |
688 | { |
689 | if (GET_CODE (op) != CONST_INT) | |
690 | return 0; | |
691 | if (INT16_P (INTVAL (op)) | |
692 | || UINT24_P (INTVAL (op)) | |
693 | || UPPER16_P (INTVAL (op))) | |
694 | return 0; | |
695 | return 1; | |
696 | } | |
697 | ||
8c5ca3b9 DE |
698 | /* Return true if OP is an acceptable argument for a single word |
699 | move source. */ | |
700 | ||
701 | int | |
2b7972b0 | 702 | move_src_operand (op, int_mode) |
8c5ca3b9 | 703 | rtx op; |
2b7972b0 | 704 | int int_mode; |
8c5ca3b9 | 705 | { |
2b7972b0 | 706 | enum machine_mode mode = (enum machine_mode)int_mode; |
8c5ca3b9 DE |
707 | switch (GET_CODE (op)) |
708 | { | |
709 | case SYMBOL_REF : | |
710 | case CONST : | |
2b7972b0 | 711 | return addr24_operand (op, int_mode); |
8c5ca3b9 | 712 | case CONST_INT : |
efbbf34f DE |
713 | /* ??? We allow more cse opportunities if we only allow constants |
714 | loadable with one insn, and split the rest into two. The instances | |
715 | where this would help should be rare and the current way is | |
716 | simpler. */ | |
8c5ca3b9 DE |
717 | return INT32_P (INTVAL (op)); |
718 | case LABEL_REF : | |
719 | return TARGET_ADDR24; | |
720 | case CONST_DOUBLE : | |
721 | if (mode == SFmode) | |
722 | return 1; | |
723 | else if (mode == SImode) | |
724 | { | |
725 | /* Large unsigned constants are represented as const_double's. */ | |
726 | unsigned HOST_WIDE_INT low, high; | |
727 | ||
728 | low = CONST_DOUBLE_LOW (op); | |
729 | high = CONST_DOUBLE_HIGH (op); | |
730 | return high == 0 && low <= 0xffffffff; | |
731 | } | |
732 | else | |
733 | return 0; | |
734 | case REG : | |
735 | return register_operand (op, mode); | |
736 | case SUBREG : | |
737 | /* (subreg (mem ...) ...) can occur here if the inner part was once a | |
738 | pseudo-reg and is now a stack slot. */ | |
739 | if (GET_CODE (SUBREG_REG (op)) == MEM) | |
740 | return address_operand (XEXP (SUBREG_REG (op), 0), mode); | |
741 | else | |
742 | return register_operand (op, mode); | |
743 | case MEM : | |
744 | return address_operand (XEXP (op, 0), mode); | |
745 | default : | |
746 | return 0; | |
747 | } | |
748 | } | |
749 | ||
750 | /* Return true if OP is an acceptable argument for a double word | |
751 | move source. */ | |
752 | ||
753 | int | |
2b7972b0 | 754 | move_double_src_operand (op, int_mode) |
8c5ca3b9 | 755 | rtx op; |
2b7972b0 | 756 | int int_mode; |
8c5ca3b9 | 757 | { |
2b7972b0 | 758 | enum machine_mode mode = (enum machine_mode)int_mode; |
8c5ca3b9 DE |
759 | switch (GET_CODE (op)) |
760 | { | |
761 | case CONST_INT : | |
762 | case CONST_DOUBLE : | |
5b8ae21f | 763 | return 1; |
8c5ca3b9 DE |
764 | case REG : |
765 | return register_operand (op, mode); | |
766 | case SUBREG : | |
767 | /* (subreg (mem ...) ...) can occur here if the inner part was once a | |
768 | pseudo-reg and is now a stack slot. */ | |
769 | if (GET_CODE (SUBREG_REG (op)) == MEM) | |
2b7972b0 | 770 | return move_double_src_operand (SUBREG_REG (op), int_mode); |
8c5ca3b9 DE |
771 | else |
772 | return register_operand (op, mode); | |
773 | case MEM : | |
774 | /* Disallow auto inc/dec for now. */ | |
775 | if (GET_CODE (XEXP (op, 0)) == PRE_DEC | |
776 | || GET_CODE (XEXP (op, 0)) == PRE_INC) | |
777 | return 0; | |
778 | return address_operand (XEXP (op, 0), mode); | |
779 | default : | |
780 | return 0; | |
781 | } | |
782 | } | |
783 | ||
784 | /* Return true if OP is an acceptable argument for a move destination. */ | |
785 | ||
786 | int | |
2b7972b0 | 787 | move_dest_operand (op, int_mode) |
8c5ca3b9 | 788 | rtx op; |
2b7972b0 | 789 | int int_mode; |
8c5ca3b9 | 790 | { |
2b7972b0 | 791 | enum machine_mode mode = (enum machine_mode)int_mode; |
8c5ca3b9 DE |
792 | switch (GET_CODE (op)) |
793 | { | |
794 | case REG : | |
795 | return register_operand (op, mode); | |
796 | case SUBREG : | |
797 | /* (subreg (mem ...) ...) can occur here if the inner part was once a | |
798 | pseudo-reg and is now a stack slot. */ | |
799 | if (GET_CODE (SUBREG_REG (op)) == MEM) | |
800 | return address_operand (XEXP (SUBREG_REG (op), 0), mode); | |
801 | else | |
802 | return register_operand (op, mode); | |
803 | case MEM : | |
804 | return address_operand (XEXP (op, 0), mode); | |
805 | default : | |
806 | return 0; | |
807 | } | |
808 | } | |
809 | ||
810 | /* Return 1 if OP is a DImode const we want to handle inline. | |
811 | This must match the code in the movdi pattern. | |
812 | It is used by the 'G' CONST_DOUBLE_OK_FOR_LETTER. */ | |
813 | ||
814 | int | |
815 | easy_di_const (op) | |
816 | rtx op; | |
817 | { | |
818 | rtx high_rtx, low_rtx; | |
819 | HOST_WIDE_INT high, low; | |
820 | ||
821 | split_double (op, &high_rtx, &low_rtx); | |
822 | high = INTVAL (high_rtx); | |
823 | low = INTVAL (low_rtx); | |
824 | /* Pick constants loadable with 2 16 bit `ldi' insns. */ | |
825 | if (high >= -128 && high <= 127 | |
826 | && low >= -128 && low <= 127) | |
827 | return 1; | |
828 | return 0; | |
829 | } | |
830 | ||
831 | /* Return 1 if OP is a DFmode const we want to handle inline. | |
832 | This must match the code in the movdf pattern. | |
833 | It is used by the 'H' CONST_DOUBLE_OK_FOR_LETTER. */ | |
834 | ||
835 | int | |
836 | easy_df_const (op) | |
837 | rtx op; | |
838 | { | |
839 | REAL_VALUE_TYPE r; | |
840 | long l[2]; | |
841 | ||
842 | REAL_VALUE_FROM_CONST_DOUBLE (r, op); | |
843 | REAL_VALUE_TO_TARGET_DOUBLE (r, l); | |
844 | if (l[0] == 0 && l[1] == 0) | |
845 | return 1; | |
846 | if ((l[0] & 0xffff) == 0 && l[1] == 0) | |
847 | return 1; | |
848 | return 0; | |
849 | } | |
850 | ||
851 | /* Return 1 if OP is an EQ or NE comparison operator. */ | |
852 | ||
853 | int | |
2b7972b0 | 854 | eqne_comparison_operator (op, int_mode) |
8c5ca3b9 | 855 | rtx op; |
2b7972b0 | 856 | int int_mode; |
8c5ca3b9 DE |
857 | { |
858 | enum rtx_code code = GET_CODE (op); | |
859 | ||
860 | if (GET_RTX_CLASS (code) != '<') | |
861 | return 0; | |
862 | return (code == EQ || code == NE); | |
863 | } | |
864 | ||
865 | /* Return 1 if OP is a signed comparison operator. */ | |
866 | ||
867 | int | |
2b7972b0 | 868 | signed_comparison_operator (op, int_mode) |
8c5ca3b9 | 869 | rtx op; |
2b7972b0 | 870 | int int_mode; |
8c5ca3b9 DE |
871 | { |
872 | enum rtx_code code = GET_CODE (op); | |
873 | ||
874 | if (GET_RTX_CLASS (code) != '<') | |
875 | return 0; | |
876 | return (code == EQ || code == NE | |
877 | || code == LT || code == LE || code == GT || code == GE); | |
878 | } | |
879 | ||
880 | /* Return 1 if OP is (mem (reg ...)). | |
881 | This is used in insn length calcs. */ | |
882 | ||
883 | int | |
2b7972b0 | 884 | memreg_operand (op, int_mode) |
8c5ca3b9 | 885 | rtx op; |
2b7972b0 | 886 | int int_mode; |
8c5ca3b9 DE |
887 | { |
888 | return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == REG; | |
889 | } | |
2b7972b0 MM |
890 | |
891 | /* Return non-zero if the operand is an insn that is a small insn. | |
892 | Allow const_int 0 as well, which is a placeholder for NOP slots. */ | |
893 | ||
894 | int | |
895 | small_insn_p (op, int_mode) | |
896 | rtx op; | |
897 | int int_mode; | |
898 | { | |
899 | if (GET_CODE (op) == CONST_INT && INTVAL (op) == 0) | |
900 | return 1; | |
901 | ||
902 | if (GET_RTX_CLASS (GET_CODE (op)) != 'i') | |
903 | return 0; | |
904 | ||
905 | return get_attr_length (op) == 2; | |
906 | } | |
907 | ||
908 | /* Return non-zero if the operand is an insn that is a large insn. */ | |
909 | ||
910 | int | |
911 | large_insn_p (op, int_mode) | |
912 | rtx op; | |
913 | int int_mode; | |
914 | { | |
915 | if (GET_RTX_CLASS (GET_CODE (op)) != 'i') | |
916 | return 0; | |
917 | ||
918 | return get_attr_length (op) != 2; | |
919 | } | |
920 | ||
8c5ca3b9 DE |
921 | \f |
922 | /* Comparisons. */ | |
923 | ||
924 | /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, | |
925 | return the mode to be used for the comparison. */ | |
926 | ||
2b7972b0 | 927 | int |
8c5ca3b9 | 928 | m32r_select_cc_mode (op, x, y) |
2b7972b0 | 929 | int op; |
8c5ca3b9 DE |
930 | rtx x, y; |
931 | { | |
51c10c4e | 932 | return (int)SImode; |
8c5ca3b9 DE |
933 | } |
934 | ||
935 | /* X and Y are two things to compare using CODE. Emit the compare insn and | |
2b7972b0 MM |
936 | return the rtx for compare [arg0 of the if_then_else]. |
937 | If need_compare is true then the comparison insn must be generated, rather | |
938 | than being susummed into the following branch instruction. */ | |
8c5ca3b9 DE |
939 | |
940 | rtx | |
c5c76735 JL |
941 | gen_compare (code, x, y, need_compare) |
942 | enum rtx_code code; | |
943 | rtx x, y; | |
944 | int need_compare; | |
8c5ca3b9 | 945 | { |
c5c76735 JL |
946 | enum machine_mode mode = SELECT_CC_MODE (code, x, y); |
947 | enum rtx_code compare_code, branch_code; | |
948 | rtx cc_reg = gen_rtx_REG (mode, CARRY_REGNUM); | |
949 | int swap_p = 0; | |
8c5ca3b9 DE |
950 | |
951 | switch (code) | |
952 | { | |
2e076ddf NC |
953 | case EQ: compare_code = EQ; branch_code = NE; break; |
954 | case NE: compare_code = EQ; branch_code = EQ; break; | |
955 | case LT: compare_code = LT; branch_code = NE; break; | |
956 | case LE: compare_code = LT; branch_code = EQ; must_swap = 1; break; | |
957 | case GT: compare_code = LT; branch_code = NE; must_swap = 1; break; | |
958 | case GE: compare_code = LT; branch_code = EQ; break; | |
8c5ca3b9 | 959 | case LTU: compare_code = LTU; branch_code = NE; break; |
2e076ddf NC |
960 | case LEU: compare_code = LTU; branch_code = EQ; must_swap = 1; break; |
961 | case GTU: compare_code = LTU; branch_code = NE; must_swap = 1; break; | |
8c5ca3b9 DE |
962 | case GEU: compare_code = LTU; branch_code = EQ; break; |
963 | } | |
964 | ||
2b7972b0 MM |
965 | if (need_compare) |
966 | { | |
967 | switch (compare_code) | |
968 | { | |
969 | case EQ: | |
970 | if (GET_CODE (y) == CONST_INT | |
971 | && CMP_INT16_P (INTVAL (y)) /* reg equal to small const. */ | |
972 | && y != const0_rtx) | |
973 | { | |
974 | rtx tmp = gen_reg_rtx (SImode); | |
975 | ||
976 | emit_insn (gen_cmp_ne_small_const_insn (tmp, x, y)); | |
977 | x = tmp; | |
978 | y = const0_rtx; | |
979 | } | |
980 | else if (CONSTANT_P (y)) /* reg equal to const. */ | |
981 | { | |
982 | rtx tmp = force_reg (GET_MODE (x), y); | |
983 | y = tmp; | |
984 | } | |
985 | ||
986 | if (register_operand (y, SImode) /* reg equal to reg. */ | |
987 | || y == const0_rtx) /* req equal to zero. */ | |
988 | { | |
989 | emit_insn (gen_cmp_eqsi_insn (x, y)); | |
990 | ||
991 | return gen_rtx (code, mode, cc_reg, const0_rtx); | |
992 | } | |
993 | break; | |
994 | ||
995 | case LT: | |
996 | if (register_operand (y, SImode) | |
997 | || (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y)))) | |
998 | { | |
999 | rtx tmp = gen_reg_rtx (SImode); /* reg compared to reg. */ | |
1000 | ||
1001 | switch (code) | |
1002 | { | |
1003 | case LT: | |
1004 | emit_insn (gen_cmp_ltsi_insn (x, y)); | |
1005 | code = EQ; | |
1006 | break; | |
1007 | case LE: | |
1008 | if (y == const0_rtx) | |
1009 | tmp = const1_rtx; | |
1010 | else | |
1011 | emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx)); | |
1012 | emit_insn (gen_cmp_ltsi_insn (x, tmp)); | |
1013 | code = EQ; | |
1014 | break; | |
1015 | case GT: | |
1016 | if (GET_CODE (y) == CONST_INT) | |
1017 | tmp = gen_rtx (PLUS, SImode, y, const1_rtx); | |
1018 | else | |
1019 | emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx)); | |
1020 | emit_insn (gen_cmp_ltsi_insn (x, tmp)); | |
1021 | code = NE; | |
1022 | break; | |
1023 | case GE: | |
1024 | emit_insn (gen_cmp_ltsi_insn (x, y)); | |
1025 | code = NE; | |
1026 | break; | |
1027 | default: | |
1028 | abort(); | |
1029 | } | |
1030 | ||
1031 | return gen_rtx (code, mode, cc_reg, const0_rtx); | |
1032 | } | |
1033 | break; | |
1034 | ||
1035 | case LTU: | |
1036 | if (register_operand (y, SImode) | |
1037 | || (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y)))) | |
1038 | { | |
1039 | rtx tmp = gen_reg_rtx (SImode); /* reg (unsigned) compared to reg. */ | |
1040 | ||
1041 | switch (code) | |
1042 | { | |
1043 | case LTU: | |
1044 | emit_insn (gen_cmp_ltusi_insn (x, y)); | |
1045 | code = EQ; | |
1046 | break; | |
1047 | case LEU: | |
1048 | if (y == const0_rtx) | |
1049 | tmp = const1_rtx; | |
1050 | else | |
1051 | emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx)); | |
1052 | emit_insn (gen_cmp_ltusi_insn (x, tmp)); | |
1053 | code = EQ; | |
1054 | break; | |
1055 | case GTU: | |
1056 | if (GET_CODE (y) == CONST_INT) | |
1057 | tmp = gen_rtx (PLUS, SImode, y, const1_rtx); | |
1058 | else | |
1059 | emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx)); | |
1060 | emit_insn (gen_cmp_ltusi_insn (x, tmp)); | |
1061 | code = NE; | |
1062 | break; | |
1063 | case GEU: | |
1064 | emit_insn (gen_cmp_ltusi_insn (x, y)); | |
1065 | code = NE; | |
1066 | break; | |
1067 | default: | |
1068 | abort(); | |
1069 | } | |
1070 | ||
1071 | return gen_rtx (code, mode, cc_reg, const0_rtx); | |
1072 | } | |
1073 | break; | |
1074 | ||
1075 | default: | |
1076 | abort(); | |
1077 | } | |
1078 | } | |
1079 | else | |
1080 | if (! TARGET_OLD_COMPARE) | |
8c5ca3b9 DE |
1081 | { |
1082 | /* reg/reg equal comparison */ | |
1083 | if (compare_code == EQ | |
1084 | && register_operand (y, SImode)) | |
1085 | return gen_rtx (code, mode, x, y); | |
2e076ddf | 1086 | |
8c5ca3b9 DE |
1087 | /* reg/zero signed comparison */ |
1088 | if ((compare_code == EQ || compare_code == LT) | |
1089 | && y == const0_rtx) | |
1090 | return gen_rtx (code, mode, x, y); | |
2e076ddf | 1091 | |
8c5ca3b9 DE |
1092 | /* reg/smallconst equal comparison */ |
1093 | if (compare_code == EQ | |
1094 | && GET_CODE (y) == CONST_INT | |
1095 | && CMP_INT16_P (INTVAL (y))) | |
1096 | { | |
1097 | rtx tmp = gen_reg_rtx (SImode); | |
1098 | emit_insn (gen_cmp_ne_small_const_insn (tmp, x, y)); | |
1099 | return gen_rtx (code, mode, tmp, const0_rtx); | |
1100 | } | |
2e076ddf | 1101 | |
8c5ca3b9 DE |
1102 | /* reg/const equal comparison */ |
1103 | if (compare_code == EQ | |
1104 | && CONSTANT_P (y)) | |
1105 | { | |
1106 | rtx tmp = force_reg (GET_MODE (x), y); | |
1107 | return gen_rtx (code, mode, x, tmp); | |
1108 | } | |
1109 | } | |
1110 | ||
2e076ddf | 1111 | if (CONSTANT_P (y)) |
8c5ca3b9 | 1112 | { |
2e076ddf | 1113 | if (must_swap) |
8c5ca3b9 | 1114 | y = force_reg (GET_MODE (x), y); |
2e076ddf NC |
1115 | else |
1116 | { | |
1117 | int ok_const = | |
1118 | (code == LTU || code == LEU || code == GTU || code == GEU) | |
1119 | ? uint16_operand (y, GET_MODE (y)) | |
1120 | : reg_or_cmp_int16_operand (y, GET_MODE (y)); | |
1121 | ||
1122 | if (! ok_const) | |
1123 | y = force_reg (GET_MODE (x), y); | |
1124 | } | |
8c5ca3b9 DE |
1125 | } |
1126 | ||
1127 | switch (compare_code) | |
1128 | { | |
1129 | case EQ : | |
2e076ddf | 1130 | emit_insn (gen_cmp_eqsi_insn (must_swap ? y : x, must_swap ? x : y)); |
8c5ca3b9 DE |
1131 | break; |
1132 | case LT : | |
2e076ddf | 1133 | emit_insn (gen_cmp_ltsi_insn (must_swap ? y : x, must_swap ? x : y)); |
8c5ca3b9 DE |
1134 | break; |
1135 | case LTU : | |
2e076ddf | 1136 | emit_insn (gen_cmp_ltusi_insn (must_swap ? y : x, must_swap ? x : y)); |
8c5ca3b9 DE |
1137 | break; |
1138 | } | |
1139 | ||
1140 | return gen_rtx (branch_code, VOIDmode, cc_reg, CONST0_RTX (mode)); | |
1141 | } | |
5b8ae21f MM |
1142 | \f |
1143 | /* Split a 2 word move (DI or DF) into component parts. */ | |
1144 | ||
1145 | rtx | |
1146 | gen_split_move_double (operands) | |
1147 | rtx operands[]; | |
1148 | { | |
1149 | enum machine_mode mode = GET_MODE (operands[0]); | |
1150 | rtx dest = operands[0]; | |
1151 | rtx src = operands[1]; | |
1152 | rtx val; | |
1153 | ||
ca3bf2b5 JW |
1154 | /* We might have (SUBREG (MEM)) here, so just get rid of the |
1155 | subregs to make this code simpler. It is safe to call | |
1156 | alter_subreg any time after reload. */ | |
1157 | if (GET_CODE (dest) == SUBREG) | |
1158 | dest = alter_subreg (dest); | |
1159 | if (GET_CODE (src) == SUBREG) | |
1160 | src = alter_subreg (src); | |
1161 | ||
5b8ae21f | 1162 | start_sequence (); |
ca3bf2b5 | 1163 | if (GET_CODE (dest) == REG) |
5b8ae21f | 1164 | { |
ca3bf2b5 JW |
1165 | int dregno = REGNO (dest); |
1166 | ||
5b8ae21f | 1167 | /* reg = reg */ |
ca3bf2b5 | 1168 | if (GET_CODE (src) == REG) |
5b8ae21f | 1169 | { |
ca3bf2b5 JW |
1170 | int sregno = REGNO (src); |
1171 | ||
1172 | int reverse = (dregno == sregno + 1); | |
1173 | ||
5b8ae21f MM |
1174 | /* We normally copy the low-numbered register first. However, if |
1175 | the first register operand 0 is the same as the second register of | |
1176 | operand 1, we must copy in the opposite order. */ | |
5b8ae21f MM |
1177 | emit_insn (gen_rtx_SET (VOIDmode, |
1178 | operand_subword (dest, reverse, TRUE, mode), | |
1179 | operand_subword (src, reverse, TRUE, mode))); | |
1180 | ||
1181 | emit_insn (gen_rtx_SET (VOIDmode, | |
1182 | operand_subword (dest, !reverse, TRUE, mode), | |
1183 | operand_subword (src, !reverse, TRUE, mode))); | |
1184 | } | |
1185 | ||
1186 | /* reg = constant */ | |
1187 | else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE) | |
1188 | { | |
1189 | rtx words[2]; | |
1190 | split_double (src, &words[0], &words[1]); | |
1191 | emit_insn (gen_rtx_SET (VOIDmode, | |
1192 | operand_subword (dest, 0, TRUE, mode), | |
1193 | words[0])); | |
1194 | ||
1195 | emit_insn (gen_rtx_SET (VOIDmode, | |
1196 | operand_subword (dest, 1, TRUE, mode), | |
1197 | words[1])); | |
1198 | } | |
1199 | ||
1200 | /* reg = mem */ | |
1201 | else if (GET_CODE (src) == MEM) | |
1202 | { | |
1203 | /* If the high-address word is used in the address, we must load it | |
1204 | last. Otherwise, load it first. */ | |
1205 | rtx addr = XEXP (src, 0); | |
ca3bf2b5 | 1206 | int reverse = (refers_to_regno_p (dregno, dregno+1, addr, 0) != 0); |
5b8ae21f MM |
1207 | |
1208 | /* We used to optimize loads from single registers as | |
1209 | ||
1210 | ld r1,r3+; ld r2,r3 | |
1211 | ||
1212 | if r3 were not used subsequently. However, the REG_NOTES aren't | |
1213 | propigated correctly by the reload phase, and it can cause bad | |
1214 | code to be generated. We could still try: | |
1215 | ||
1216 | ld r1,r3+; ld r2,r3; addi r3,-4 | |
1217 | ||
1218 | which saves 2 bytes and doesn't force longword alignment. */ | |
1219 | emit_insn (gen_rtx_SET (VOIDmode, | |
1220 | operand_subword (dest, reverse, TRUE, mode), | |
1221 | change_address (src, SImode, | |
1222 | plus_constant (addr, | |
1223 | reverse * UNITS_PER_WORD)))); | |
1224 | ||
1225 | emit_insn (gen_rtx_SET (VOIDmode, | |
1226 | operand_subword (dest, !reverse, TRUE, mode), | |
1227 | change_address (src, SImode, | |
1228 | plus_constant (addr, | |
1229 | (!reverse) * UNITS_PER_WORD)))); | |
1230 | } | |
1231 | ||
1232 | else | |
1233 | abort (); | |
1234 | } | |
1235 | ||
1236 | /* mem = reg */ | |
1237 | /* We used to optimize loads from single registers as | |
1238 | ||
1239 | st r1,r3; st r2,+r3 | |
1240 | ||
1241 | if r3 were not used subsequently. However, the REG_NOTES aren't | |
1242 | propigated correctly by the reload phase, and it can cause bad | |
1243 | code to be generated. We could still try: | |
1244 | ||
1245 | st r1,r3; st r2,+r3; addi r3,-4 | |
1246 | ||
1247 | which saves 2 bytes and doesn't force longword alignment. */ | |
ca3bf2b5 | 1248 | else if (GET_CODE (dest) == MEM && GET_CODE (src) == REG) |
5b8ae21f MM |
1249 | { |
1250 | rtx addr = XEXP (dest, 0); | |
1251 | ||
1252 | emit_insn (gen_rtx_SET (VOIDmode, | |
1253 | change_address (dest, SImode, addr), | |
1254 | operand_subword (src, 0, TRUE, mode))); | |
1255 | ||
1256 | emit_insn (gen_rtx_SET (VOIDmode, | |
1257 | change_address (dest, SImode, | |
1258 | plus_constant (addr, UNITS_PER_WORD)), | |
1259 | operand_subword (src, 1, TRUE, mode))); | |
1260 | } | |
1261 | ||
1262 | else | |
1263 | abort (); | |
1264 | ||
1265 | val = gen_sequence (); | |
1266 | end_sequence (); | |
1267 | return val; | |
1268 | } | |
1269 | ||
8c5ca3b9 DE |
1270 | \f |
1271 | /* Implements the FUNCTION_ARG_PARTIAL_NREGS macro. */ | |
1272 | ||
1273 | int | |
2b7972b0 | 1274 | function_arg_partial_nregs (cum, int_mode, type, named) |
8c5ca3b9 | 1275 | CUMULATIVE_ARGS *cum; |
2b7972b0 | 1276 | int int_mode; |
8c5ca3b9 DE |
1277 | tree type; |
1278 | int named; | |
1279 | { | |
2b7972b0 | 1280 | enum machine_mode mode = (enum machine_mode)int_mode; |
8c5ca3b9 DE |
1281 | int ret; |
1282 | int size = (((mode == BLKmode && type) | |
1283 | ? int_size_in_bytes (type) | |
1284 | : GET_MODE_SIZE (mode)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; | |
1285 | ||
1286 | if (*cum >= M32R_MAX_PARM_REGS) | |
1287 | ret = 0; | |
1288 | else if (*cum + size > M32R_MAX_PARM_REGS) | |
1289 | ret = (*cum + size) - M32R_MAX_PARM_REGS; | |
1290 | else | |
1291 | ret = 0; | |
1292 | ||
1293 | return ret; | |
1294 | } | |
1295 | ||
1296 | /* Do any needed setup for a variadic function. For the M32R, we must | |
1297 | create a register parameter block, and then copy any anonymous arguments | |
1298 | in registers to memory. | |
1299 | ||
1300 | CUM has not been updated for the last named argument which has type TYPE | |
1301 | and mode MODE, and we rely on this fact. */ | |
1302 | ||
1303 | void | |
2b7972b0 | 1304 | m32r_setup_incoming_varargs (cum, int_mode, type, pretend_size, no_rtl) |
8c5ca3b9 | 1305 | CUMULATIVE_ARGS *cum; |
2b7972b0 | 1306 | int int_mode; |
8c5ca3b9 DE |
1307 | tree type; |
1308 | int *pretend_size; | |
1309 | int no_rtl; | |
1310 | { | |
2b7972b0 | 1311 | enum machine_mode mode = (enum machine_mode)int_mode; |
8c5ca3b9 DE |
1312 | int first_anon_arg; |
1313 | ||
1314 | if (no_rtl) | |
1315 | return; | |
1316 | ||
1317 | /* All BLKmode values are passed by reference. */ | |
1318 | if (mode == BLKmode) | |
1319 | abort (); | |
1320 | ||
1321 | /* We must treat `__builtin_va_alist' as an anonymous arg. */ | |
1322 | if (current_function_varargs) | |
1323 | first_anon_arg = *cum; | |
1324 | else | |
1325 | first_anon_arg = (ROUND_ADVANCE_CUM (*cum, mode, type) | |
1326 | + ROUND_ADVANCE_ARG (mode, type)); | |
1327 | ||
1328 | if (first_anon_arg < M32R_MAX_PARM_REGS) | |
1329 | { | |
1330 | /* Note that first_reg_offset < M32R_MAX_PARM_REGS. */ | |
1331 | int first_reg_offset = first_anon_arg; | |
1332 | /* Size in words to "pretend" allocate. */ | |
1333 | int size = M32R_MAX_PARM_REGS - first_reg_offset; | |
1334 | rtx regblock; | |
1335 | ||
c5c76735 JL |
1336 | regblock = gen_rtx_MEM (BLKmode, |
1337 | plus_constant (arg_pointer_rtx, | |
1338 | FIRST_PARM_OFFSET (0))); | |
40cae311 | 1339 | MEM_ALIAS_SET (regblock) = get_varargs_alias_set (); |
8c5ca3b9 DE |
1340 | move_block_from_reg (first_reg_offset, regblock, |
1341 | size, size * UNITS_PER_WORD); | |
1342 | ||
1343 | *pretend_size = (size * UNITS_PER_WORD); | |
1344 | } | |
1345 | } | |
40cae311 RH |
1346 | |
1347 | /* Implement `va_arg'. */ | |
1348 | ||
1349 | rtx | |
1350 | m32r_va_arg (valist, type) | |
1351 | tree valist, type; | |
1352 | { | |
1353 | HOST_WIDE_INT size, rsize; | |
1354 | tree t; | |
1355 | rtx addr_rtx; | |
1356 | ||
1357 | size = int_size_in_bytes (type); | |
1358 | rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD; | |
1359 | ||
1360 | if (size > 8) | |
1361 | { | |
1362 | tree type_ptr, type_ptr_ptr; | |
1363 | ||
1364 | /* Pass by reference. */ | |
1365 | ||
1366 | type_ptr = build_pointer_type (type); | |
1367 | type_ptr_ptr = build_pointer_type (type_ptr); | |
1368 | ||
1369 | t = build (POSTINCREMENT_EXPR, va_list_type_node, valist, | |
1370 | build_int_2 (UNITS_PER_WORD, 0)); | |
1371 | TREE_SIDE_EFFECTS (t) = 1; | |
1372 | t = build1 (NOP_EXPR, type_ptr_ptr, t); | |
1373 | TREE_SIDE_EFFECTS (t) = 1; | |
1374 | t = build1 (INDIRECT_REF, type_ptr, t); | |
1375 | ||
1376 | addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL); | |
1377 | } | |
1378 | else | |
1379 | { | |
1380 | /* Pass by value. */ | |
1381 | ||
1382 | if (size < UNITS_PER_WORD) | |
1383 | { | |
1384 | /* Care for bigendian correction on the aligned address. */ | |
1385 | t = build (PLUS_EXPR, ptr_type_node, valist, | |
1386 | build_int_2 (rsize - size, 0)); | |
1387 | addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL); | |
1388 | addr_rtx = copy_to_reg (addr_rtx); | |
1389 | ||
1390 | /* Increment AP. */ | |
1391 | t = build (PLUS_EXPR, va_list_type_node, valist, | |
1392 | build_int_2 (rsize, 0)); | |
1393 | t = build (MODIFY_EXPR, va_list_type_node, valist, t); | |
1394 | TREE_SIDE_EFFECTS (t) = 1; | |
1395 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
1396 | } | |
1397 | else | |
1398 | { | |
1399 | t = build (POSTINCREMENT_EXPR, va_list_type_node, valist, | |
1400 | build_int_2 (rsize, 0)); | |
1401 | TREE_SIDE_EFFECTS (t) = 1; | |
1402 | addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL); | |
1403 | } | |
1404 | } | |
1405 | ||
1406 | return addr_rtx; | |
1407 | } | |
8c5ca3b9 DE |
1408 | \f |
1409 | /* Cost functions. */ | |
1410 | ||
1411 | /* Provide the costs of an addressing mode that contains ADDR. | |
1412 | If ADDR is not a valid address, its cost is irrelevant. | |
1413 | ||
1414 | This function is trivial at the moment. This code doesn't live | |
1415 | in m32r.h so it's easy to experiment. */ | |
1416 | ||
1417 | int | |
1418 | m32r_address_cost (addr) | |
1419 | rtx addr; | |
1420 | { | |
1421 | return 1; | |
1422 | } | |
1423 | \f | |
1424 | /* Type of function DECL. | |
1425 | ||
1426 | The result is cached. To reset the cache at the end of a function, | |
1427 | call with DECL = NULL_TREE. */ | |
1428 | ||
1429 | enum m32r_function_type | |
1430 | m32r_compute_function_type (decl) | |
1431 | tree decl; | |
1432 | { | |
1433 | /* Cached value. */ | |
1434 | static enum m32r_function_type fn_type = M32R_FUNCTION_UNKNOWN; | |
1435 | /* Last function we were called for. */ | |
1436 | static tree last_fn = NULL_TREE; | |
1437 | ||
1438 | /* Resetting the cached value? */ | |
1439 | if (decl == NULL_TREE) | |
1440 | { | |
1441 | fn_type = M32R_FUNCTION_UNKNOWN; | |
1442 | last_fn = NULL_TREE; | |
1443 | return fn_type; | |
1444 | } | |
1445 | ||
1446 | if (decl == last_fn && fn_type != M32R_FUNCTION_UNKNOWN) | |
1447 | return fn_type; | |
1448 | ||
1449 | /* Compute function type. */ | |
1450 | fn_type = (lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (current_function_decl)) != NULL_TREE | |
1451 | ? M32R_FUNCTION_INTERRUPT | |
1452 | : M32R_FUNCTION_NORMAL); | |
1453 | ||
1454 | last_fn = decl; | |
1455 | return fn_type; | |
1456 | } | |
1457 | \f/* Function prologue/epilogue handlers. */ | |
1458 | ||
1459 | /* M32R stack frames look like: | |
1460 | ||
1461 | Before call After call | |
1462 | +-----------------------+ +-----------------------+ | |
1463 | | | | | | |
1464 | high | local variables, | | local variables, | | |
1465 | mem | reg save area, etc. | | reg save area, etc. | | |
1466 | | | | | | |
1467 | +-----------------------+ +-----------------------+ | |
1468 | | | | | | |
1469 | | arguments on stack. | | arguments on stack. | | |
1470 | | | | | | |
1471 | SP+0->+-----------------------+ +-----------------------+ | |
1472 | | reg parm save area, | | |
1473 | | only created for | | |
1474 | | variable argument | | |
1475 | | functions | | |
1476 | +-----------------------+ | |
1477 | | previous frame ptr | | |
1478 | +-----------------------+ | |
1479 | | | | |
1480 | | register save area | | |
1481 | | | | |
1482 | +-----------------------+ | |
1483 | | return address | | |
1484 | +-----------------------+ | |
1485 | | | | |
1486 | | local variables | | |
1487 | | | | |
1488 | +-----------------------+ | |
1489 | | | | |
1490 | | alloca allocations | | |
1491 | | | | |
1492 | +-----------------------+ | |
1493 | | | | |
1494 | low | arguments on stack | | |
1495 | memory | | | |
1496 | SP+0->+-----------------------+ | |
1497 | ||
1498 | Notes: | |
1499 | 1) The "reg parm save area" does not exist for non variable argument fns. | |
1500 | 2) The "reg parm save area" can be eliminated completely if we saved regs | |
1501 | containing anonymous args separately but that complicates things too | |
1502 | much (so it's not done). | |
1503 | 3) The return address is saved after the register save area so as to have as | |
1504 | many insns as possible between the restoration of `lr' and the `jmp lr'. | |
1505 | */ | |
1506 | ||
1507 | /* Structure to be filled in by m32r_compute_frame_size with register | |
1508 | save masks, and offsets for the current function. */ | |
1509 | struct m32r_frame_info | |
1510 | { | |
1511 | unsigned int total_size; /* # bytes that the entire frame takes up */ | |
1512 | unsigned int extra_size; /* # bytes of extra stuff */ | |
1513 | unsigned int pretend_size; /* # bytes we push and pretend caller did */ | |
1514 | unsigned int args_size; /* # bytes that outgoing arguments take up */ | |
1515 | unsigned int reg_size; /* # bytes needed to store regs */ | |
1516 | unsigned int var_size; /* # bytes that variables take up */ | |
1517 | unsigned int gmask; /* mask of saved gp registers */ | |
1518 | unsigned int save_fp; /* nonzero if fp must be saved */ | |
1519 | unsigned int save_lr; /* nonzero if lr (return addr) must be saved */ | |
1520 | int initialized; /* nonzero if frame size already calculated */ | |
1521 | }; | |
1522 | ||
1523 | /* Current frame information calculated by m32r_compute_frame_size. */ | |
1524 | static struct m32r_frame_info current_frame_info; | |
1525 | ||
1526 | /* Zero structure to initialize current_frame_info. */ | |
1527 | static struct m32r_frame_info zero_frame_info; | |
1528 | ||
1529 | #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM)) | |
1530 | #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM)) | |
1531 | ||
1532 | /* Tell prologue and epilogue if register REGNO should be saved / restored. | |
1533 | The return address and frame pointer are treated separately. | |
1534 | Don't consider them here. */ | |
1535 | #define MUST_SAVE_REGISTER(regno, interrupt_p) \ | |
1536 | ((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \ | |
1537 | && (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_p))) | |
1538 | ||
1539 | #define MUST_SAVE_FRAME_POINTER (regs_ever_live[FRAME_POINTER_REGNUM]) | |
5b8ae21f | 1540 | #define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM] || profile_flag) |
8c5ca3b9 | 1541 | |
2b7972b0 MM |
1542 | #define SHORT_INSN_SIZE 2 /* size of small instructions */ |
1543 | #define LONG_INSN_SIZE 4 /* size of long instructions */ | |
1544 | ||
8c5ca3b9 DE |
1545 | /* Return the bytes needed to compute the frame pointer from the current |
1546 | stack pointer. | |
1547 | ||
1548 | SIZE is the size needed for local variables. */ | |
1549 | ||
1550 | unsigned int | |
1551 | m32r_compute_frame_size (size) | |
1552 | int size; /* # of var. bytes allocated. */ | |
1553 | { | |
1554 | int regno; | |
1555 | unsigned int total_size, var_size, args_size, pretend_size, extra_size; | |
5b8ae21f | 1556 | unsigned int reg_size, frame_size; |
8c5ca3b9 DE |
1557 | unsigned int gmask; |
1558 | enum m32r_function_type fn_type; | |
1559 | int interrupt_p; | |
1560 | ||
1561 | var_size = M32R_STACK_ALIGN (size); | |
1562 | args_size = M32R_STACK_ALIGN (current_function_outgoing_args_size); | |
1563 | pretend_size = current_function_pretend_args_size; | |
1564 | extra_size = FIRST_PARM_OFFSET (0); | |
1565 | total_size = extra_size + pretend_size + args_size + var_size; | |
1566 | reg_size = 0; | |
1567 | gmask = 0; | |
1568 | ||
1569 | /* See if this is an interrupt handler. Call used registers must be saved | |
1570 | for them too. */ | |
1571 | fn_type = m32r_compute_function_type (current_function_decl); | |
1572 | interrupt_p = M32R_INTERRUPT_P (fn_type); | |
1573 | ||
1574 | /* Calculate space needed for registers. */ | |
1575 | ||
1576 | for (regno = 0; regno < M32R_MAX_INT_REGS; regno++) | |
1577 | { | |
1578 | if (MUST_SAVE_REGISTER (regno, interrupt_p)) | |
1579 | { | |
1580 | reg_size += UNITS_PER_WORD; | |
1581 | gmask |= 1 << regno; | |
1582 | } | |
1583 | } | |
1584 | ||
1585 | current_frame_info.save_fp = MUST_SAVE_FRAME_POINTER; | |
1586 | current_frame_info.save_lr = MUST_SAVE_RETURN_ADDR; | |
1587 | ||
1588 | reg_size += ((current_frame_info.save_fp + current_frame_info.save_lr) | |
1589 | * UNITS_PER_WORD); | |
1590 | total_size += reg_size; | |
1591 | ||
efbbf34f | 1592 | /* ??? Not sure this is necessary, and I don't think the epilogue |
8c5ca3b9 DE |
1593 | handler will do the right thing if this changes total_size. */ |
1594 | total_size = M32R_STACK_ALIGN (total_size); | |
1595 | ||
2b7972b0 MM |
1596 | frame_size = total_size - (pretend_size + reg_size); |
1597 | ||
8c5ca3b9 DE |
1598 | /* Save computed information. */ |
1599 | current_frame_info.total_size = total_size; | |
1600 | current_frame_info.extra_size = extra_size; | |
1601 | current_frame_info.pretend_size = pretend_size; | |
1602 | current_frame_info.var_size = var_size; | |
1603 | current_frame_info.args_size = args_size; | |
1604 | current_frame_info.reg_size = reg_size; | |
1605 | current_frame_info.gmask = gmask; | |
1606 | current_frame_info.initialized = reload_completed; | |
1607 | ||
1608 | /* Ok, we're done. */ | |
1609 | return total_size; | |
1610 | } | |
1611 | \f | |
2b7972b0 MM |
1612 | /* When the `length' insn attribute is used, this macro specifies the |
1613 | value to be assigned to the address of the first insn in a | |
1614 | function. If not specified, 0 is used. */ | |
1615 | ||
1616 | int | |
1617 | m32r_first_insn_address () | |
1618 | { | |
1619 | if (! current_frame_info.initialized) | |
1620 | m32r_compute_frame_size (get_frame_size ()); | |
1621 | ||
5b8ae21f | 1622 | return 0; |
2b7972b0 MM |
1623 | } |
1624 | \f | |
5b8ae21f | 1625 | /* Expand the m32r prologue as a series of insns. */ |
8c5ca3b9 DE |
1626 | |
1627 | void | |
5b8ae21f | 1628 | m32r_expand_prologue () |
8c5ca3b9 DE |
1629 | { |
1630 | int regno; | |
5b8ae21f | 1631 | int frame_size; |
8c5ca3b9 | 1632 | unsigned int gmask = current_frame_info.gmask; |
8c5ca3b9 | 1633 | |
5b8ae21f MM |
1634 | if (! current_frame_info.initialized) |
1635 | m32r_compute_frame_size (get_frame_size ()); | |
2b7972b0 | 1636 | |
5b8ae21f | 1637 | gmask = current_frame_info.gmask; |
8c5ca3b9 DE |
1638 | |
1639 | /* These cases shouldn't happen. Catch them now. */ | |
5b8ae21f | 1640 | if (current_frame_info.total_size == 0 && gmask) |
8c5ca3b9 DE |
1641 | abort (); |
1642 | ||
8c5ca3b9 DE |
1643 | /* Allocate space for register arguments if this is a variadic function. */ |
1644 | if (current_frame_info.pretend_size != 0) | |
737e7965 JW |
1645 | { |
1646 | /* Use a HOST_WIDE_INT temporary, since negating an unsigned int gives | |
1647 | the wrong result on a 64-bit host. */ | |
1648 | HOST_WIDE_INT pretend_size = current_frame_info.pretend_size; | |
1649 | emit_insn (gen_addsi3 (stack_pointer_rtx, | |
1650 | stack_pointer_rtx, | |
1651 | GEN_INT (-pretend_size))); | |
1652 | } | |
8c5ca3b9 DE |
1653 | |
1654 | /* Save any registers we need to and set up fp. */ | |
1655 | ||
1656 | if (current_frame_info.save_fp) | |
5b8ae21f | 1657 | emit_insn (gen_movsi_push (stack_pointer_rtx, frame_pointer_rtx)); |
8c5ca3b9 DE |
1658 | |
1659 | gmask &= ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK); | |
1660 | ||
1661 | /* Save any needed call-saved regs (and call-used if this is an | |
1662 | interrupt handler). */ | |
1663 | for (regno = 0; regno <= M32R_MAX_INT_REGS; ++regno) | |
1664 | { | |
1665 | if ((gmask & (1 << regno)) != 0) | |
5b8ae21f MM |
1666 | emit_insn (gen_movsi_push (stack_pointer_rtx, |
1667 | gen_rtx_REG (Pmode, regno))); | |
8c5ca3b9 DE |
1668 | } |
1669 | ||
1670 | if (current_frame_info.save_lr) | |
5b8ae21f MM |
1671 | emit_insn (gen_movsi_push (stack_pointer_rtx, |
1672 | gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM))); | |
8c5ca3b9 DE |
1673 | |
1674 | /* Allocate the stack frame. */ | |
5b8ae21f MM |
1675 | frame_size = (current_frame_info.total_size |
1676 | - (current_frame_info.pretend_size | |
1677 | + current_frame_info.reg_size)); | |
1678 | ||
8c5ca3b9 DE |
1679 | if (frame_size == 0) |
1680 | ; /* nothing to do */ | |
8c5ca3b9 | 1681 | else if (frame_size <= 32768) |
5b8ae21f MM |
1682 | emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, |
1683 | GEN_INT (-frame_size))); | |
8c5ca3b9 | 1684 | else |
5b8ae21f MM |
1685 | { |
1686 | rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM); | |
1687 | emit_insn (gen_movsi (tmp, GEN_INT (frame_size))); | |
1688 | emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp)); | |
1689 | } | |
8c5ca3b9 DE |
1690 | |
1691 | if (frame_pointer_needed) | |
5b8ae21f MM |
1692 | emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); |
1693 | ||
1694 | if (profile_flag || profile_block_flag) | |
1695 | emit_insn (gen_blockage ()); | |
1696 | } | |
1697 | ||
1698 | \f | |
1699 | /* Set up the stack and frame pointer (if desired) for the function. | |
1700 | Note, if this is changed, you need to mirror the changes in | |
1701 | m32r_compute_frame_size which calculates the prolog size. */ | |
1702 | ||
1703 | void | |
1704 | m32r_output_function_prologue (file, size) | |
1705 | FILE * file; | |
1706 | int size; | |
1707 | { | |
1708 | enum m32r_function_type fn_type = m32r_compute_function_type (current_function_decl); | |
1709 | ||
1710 | /* If this is an interrupt handler, mark it as such. */ | |
1711 | if (M32R_INTERRUPT_P (fn_type)) | |
1712 | { | |
1713 | fprintf (file, "\t%s interrupt handler\n", | |
1714 | ASM_COMMENT_START); | |
1715 | } | |
1716 | ||
1717 | if (! current_frame_info.initialized) | |
1718 | m32r_compute_frame_size (size); | |
8c5ca3b9 | 1719 | |
5b8ae21f MM |
1720 | /* This is only for the human reader. */ |
1721 | fprintf (file, | |
1722 | "\t%s PROLOGUE, vars= %d, regs= %d, args= %d, extra= %d\n", | |
1723 | ASM_COMMENT_START, | |
1724 | current_frame_info.var_size, | |
1725 | current_frame_info.reg_size / 4, | |
1726 | current_frame_info.args_size, | |
1727 | current_frame_info.extra_size); | |
8c5ca3b9 DE |
1728 | } |
1729 | \f | |
1730 | /* Do any necessary cleanup after a function to restore stack, frame, | |
1731 | and regs. */ | |
1732 | ||
1733 | void | |
1734 | m32r_output_function_epilogue (file, size) | |
2e076ddf NC |
1735 | FILE * file; |
1736 | int size; | |
8c5ca3b9 DE |
1737 | { |
1738 | int regno; | |
1739 | int noepilogue = FALSE; | |
1740 | int total_size; | |
1741 | enum m32r_function_type fn_type = m32r_compute_function_type (current_function_decl); | |
1742 | ||
1743 | /* This is only for the human reader. */ | |
1744 | fprintf (file, "\t%s EPILOGUE\n", ASM_COMMENT_START); | |
1745 | ||
1746 | if (!current_frame_info.initialized) | |
1747 | abort (); | |
1748 | total_size = current_frame_info.total_size; | |
1749 | ||
1750 | if (total_size == 0) | |
1751 | { | |
1752 | rtx insn = get_last_insn (); | |
1753 | ||
1754 | /* If the last insn was a BARRIER, we don't have to write any code | |
1755 | because a jump (aka return) was put there. */ | |
1756 | if (GET_CODE (insn) == NOTE) | |
1757 | insn = prev_nonnote_insn (insn); | |
1758 | if (insn && GET_CODE (insn) == BARRIER) | |
1759 | noepilogue = TRUE; | |
1760 | } | |
1761 | ||
1762 | if (!noepilogue) | |
1763 | { | |
1764 | unsigned int pretend_size = current_frame_info.pretend_size; | |
1765 | unsigned int frame_size = total_size - pretend_size; | |
1766 | unsigned int var_size = current_frame_info.var_size; | |
1767 | unsigned int args_size = current_frame_info.args_size; | |
1768 | unsigned int gmask = current_frame_info.gmask; | |
1769 | int can_trust_sp_p = !current_function_calls_alloca; | |
2e076ddf NC |
1770 | char * sp_str = reg_names[STACK_POINTER_REGNUM]; |
1771 | char * fp_str = reg_names[FRAME_POINTER_REGNUM]; | |
8c5ca3b9 DE |
1772 | |
1773 | /* The first thing to do is point the sp at the bottom of the register | |
1774 | save area. */ | |
1775 | if (can_trust_sp_p) | |
1776 | { | |
1777 | unsigned int reg_offset = var_size + args_size; | |
1778 | if (reg_offset == 0) | |
1779 | ; /* nothing to do */ | |
630f5ae6 DE |
1780 | else if (reg_offset < 128) |
1781 | fprintf (file, "\taddi %s,%s%d\n", | |
1782 | sp_str, IMMEDIATE_PREFIX, reg_offset); | |
8c5ca3b9 | 1783 | else if (reg_offset < 32768) |
630f5ae6 DE |
1784 | fprintf (file, "\tadd3 %s,%s,%s%d\n", |
1785 | sp_str, sp_str, IMMEDIATE_PREFIX, reg_offset); | |
8c5ca3b9 | 1786 | else |
630f5ae6 DE |
1787 | fprintf (file, "\tld24 %s,%s%d\n\tadd %s,%s\n", |
1788 | reg_names[PROLOGUE_TMP_REGNUM], | |
1789 | IMMEDIATE_PREFIX, reg_offset, | |
8c5ca3b9 DE |
1790 | sp_str, reg_names[PROLOGUE_TMP_REGNUM]); |
1791 | } | |
1792 | else if (frame_pointer_needed) | |
1793 | { | |
1794 | unsigned int reg_offset = var_size + args_size; | |
1795 | if (reg_offset == 0) | |
1796 | fprintf (file, "\tmv %s,%s\n", sp_str, fp_str); | |
1797 | else if (reg_offset < 32768) | |
630f5ae6 DE |
1798 | fprintf (file, "\tadd3 %s,%s,%s%d\n", |
1799 | sp_str, fp_str, IMMEDIATE_PREFIX, reg_offset); | |
8c5ca3b9 | 1800 | else |
630f5ae6 DE |
1801 | fprintf (file, "\tld24 %s,%s%d\n\tadd %s,%s\n", |
1802 | reg_names[PROLOGUE_TMP_REGNUM], | |
1803 | IMMEDIATE_PREFIX, reg_offset, | |
8c5ca3b9 DE |
1804 | sp_str, reg_names[PROLOGUE_TMP_REGNUM]); |
1805 | } | |
1806 | else | |
1807 | abort (); | |
1808 | ||
1809 | if (current_frame_info.save_lr) | |
1810 | fprintf (file, "\tpop %s\n", reg_names[RETURN_ADDR_REGNUM]); | |
1811 | ||
1812 | /* Restore any saved registers, in reverse order of course. */ | |
1813 | gmask &= ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK); | |
1814 | for (regno = M32R_MAX_INT_REGS - 1; regno >= 0; --regno) | |
1815 | { | |
1816 | if ((gmask & (1L << regno)) != 0) | |
1817 | fprintf (file, "\tpop %s\n", reg_names[regno]); | |
1818 | } | |
1819 | ||
1820 | if (current_frame_info.save_fp) | |
1821 | fprintf (file, "\tpop %s\n", fp_str); | |
1822 | ||
1823 | /* Remove varargs area if present. */ | |
8c5ca3b9 | 1824 | if (current_frame_info.pretend_size != 0) |
630f5ae6 DE |
1825 | fprintf (file, "\taddi %s,%s%d\n", |
1826 | sp_str, IMMEDIATE_PREFIX, current_frame_info.pretend_size); | |
8c5ca3b9 DE |
1827 | |
1828 | /* Emit the return instruction. */ | |
1829 | if (M32R_INTERRUPT_P (fn_type)) | |
1830 | fprintf (file, "\trte\n"); | |
1831 | else | |
1832 | fprintf (file, "\tjmp %s\n", reg_names[RETURN_ADDR_REGNUM]); | |
1833 | } | |
1834 | ||
1835 | #if 0 /* no longer needed */ | |
1836 | /* Ensure the function cleanly ends on a 32 bit boundary. */ | |
1837 | fprintf (file, "\t.fillinsn\n"); | |
1838 | #endif | |
1839 | ||
1840 | /* Reset state info for each function. */ | |
1841 | current_frame_info = zero_frame_info; | |
1842 | m32r_compute_function_type (NULL_TREE); | |
1843 | } | |
1844 | \f | |
1845 | /* PIC */ | |
1846 | ||
1847 | /* Emit special PIC prologues and epilogues. */ | |
1848 | ||
1849 | void | |
1850 | m32r_finalize_pic () | |
1851 | { | |
1852 | /* nothing to do */ | |
1853 | } | |
1854 | \f | |
1855 | /* Nested function support. */ | |
1856 | ||
1857 | /* Emit RTL insns to initialize the variable parts of a trampoline. | |
1858 | FNADDR is an RTX for the address of the function's pure code. | |
1859 | CXT is an RTX for the static chain value for the function. */ | |
1860 | ||
1861 | void | |
1862 | m32r_initialize_trampoline (tramp, fnaddr, cxt) | |
1863 | rtx tramp, fnaddr, cxt; | |
1864 | { | |
1865 | } | |
1866 | \f | |
1867 | /* Set the cpu type and print out other fancy things, | |
1868 | at the top of the file. */ | |
1869 | ||
1870 | void | |
1871 | m32r_asm_file_start (file) | |
2e076ddf | 1872 | FILE * file; |
8c5ca3b9 DE |
1873 | { |
1874 | if (flag_verbose_asm) | |
1875 | fprintf (file, "%s M32R/D special options: -G %d\n", | |
1876 | ASM_COMMENT_START, g_switch_value); | |
1877 | } | |
1878 | \f | |
1879 | /* Print operand X (an rtx) in assembler syntax to file FILE. | |
1880 | CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. | |
1881 | For `%' followed by punctuation, CODE is the punctuation and X is null. */ | |
1882 | ||
1883 | void | |
1884 | m32r_print_operand (file, x, code) | |
2e076ddf NC |
1885 | FILE * file; |
1886 | rtx x; | |
1887 | int code; | |
8c5ca3b9 | 1888 | { |
5b8ae21f MM |
1889 | rtx addr; |
1890 | ||
8c5ca3b9 DE |
1891 | switch (code) |
1892 | { | |
d2a73f8e NC |
1893 | /* The 's' and 'p' codes are used by output_block_move() to |
1894 | indicate post-increment 's'tores and 'p're-increment loads. */ | |
1895 | case 's': | |
1896 | if (GET_CODE (x) == REG) | |
1897 | fprintf (file, "@+%s", reg_names [REGNO (x)]); | |
1898 | else | |
1899 | output_operand_lossage ("invalid operand to %s code"); | |
1900 | return; | |
1901 | ||
1902 | case 'p': | |
1903 | if (GET_CODE (x) == REG) | |
1904 | fprintf (file, "@%s+", reg_names [REGNO (x)]); | |
1905 | else | |
1906 | output_operand_lossage ("invalid operand to %p code"); | |
1907 | return; | |
1908 | ||
8c5ca3b9 DE |
1909 | case 'R' : |
1910 | /* Write second word of DImode or DFmode reference, | |
1911 | register or memory. */ | |
1912 | if (GET_CODE (x) == REG) | |
1913 | fputs (reg_names[REGNO (x)+1], file); | |
1914 | else if (GET_CODE (x) == MEM) | |
1915 | { | |
1916 | fprintf (file, "@("); | |
1917 | /* Handle possible auto-increment. Since it is pre-increment and | |
1918 | we have already done it, we can just use an offset of four. */ | |
1919 | /* ??? This is taken from rs6000.c I think. I don't think it is | |
1920 | currently necessary, but keep it around. */ | |
1921 | if (GET_CODE (XEXP (x, 0)) == PRE_INC | |
1922 | || GET_CODE (XEXP (x, 0)) == PRE_DEC) | |
1923 | output_address (plus_constant (XEXP (XEXP (x, 0), 0), 4)); | |
1924 | else | |
1925 | output_address (plus_constant (XEXP (x, 0), 4)); | |
1926 | fputc (')', file); | |
1927 | } | |
1928 | else | |
1929 | output_operand_lossage ("invalid operand to %R code"); | |
1930 | return; | |
1931 | ||
1932 | case 'H' : /* High word */ | |
1933 | case 'L' : /* Low word */ | |
1934 | if (GET_CODE (x) == REG) | |
1935 | { | |
1936 | /* L = least significant word, H = most significant word */ | |
1937 | if ((WORDS_BIG_ENDIAN != 0) ^ (code == 'L')) | |
1938 | fputs (reg_names[REGNO (x)], file); | |
1939 | else | |
1940 | fputs (reg_names[REGNO (x)+1], file); | |
1941 | } | |
1942 | else if (GET_CODE (x) == CONST_INT | |
1943 | || GET_CODE (x) == CONST_DOUBLE) | |
1944 | { | |
1945 | rtx first, second; | |
1946 | ||
1947 | split_double (x, &first, &second); | |
d2a73f8e | 1948 | fprintf (file, "0x%08x", |
8c5ca3b9 DE |
1949 | code == 'L' ? INTVAL (first) : INTVAL (second)); |
1950 | } | |
1951 | else | |
1952 | output_operand_lossage ("invalid operand to %H/%L code"); | |
1953 | return; | |
1954 | ||
1955 | case 'A' : | |
1956 | { | |
1957 | REAL_VALUE_TYPE d; | |
1958 | char str[30]; | |
1959 | ||
1960 | if (GET_CODE (x) != CONST_DOUBLE | |
1961 | || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT) | |
1962 | abort (); | |
1963 | REAL_VALUE_FROM_CONST_DOUBLE (d, x); | |
1964 | REAL_VALUE_TO_DECIMAL (d, "%.20e", str); | |
1965 | fprintf (file, "%s", str); | |
1966 | return; | |
1967 | } | |
1968 | ||
1969 | case 'B' : /* Bottom half */ | |
1970 | case 'T' : /* Top half */ | |
1971 | /* Output the argument to a `seth' insn (sets the Top half-word). | |
1972 | For constants output arguments to a seth/or3 pair to set Top and | |
1973 | Bottom halves. For symbols output arguments to a seth/add3 pair to | |
1974 | set Top and Bottom halves. The difference exists because for | |
1975 | constants seth/or3 is more readable but for symbols we need to use | |
1976 | the same scheme as `ld' and `st' insns (16 bit addend is signed). */ | |
1977 | switch (GET_CODE (x)) | |
1978 | { | |
1979 | case CONST_INT : | |
1980 | case CONST_DOUBLE : | |
1981 | { | |
1982 | rtx first, second; | |
1983 | ||
1984 | split_double (x, &first, &second); | |
1985 | x = WORDS_BIG_ENDIAN ? second : first; | |
1986 | fprintf (file, | |
1987 | #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT | |
1988 | "0x%x", | |
1989 | #else | |
1990 | "0x%lx", | |
1991 | #endif | |
1992 | (code == 'B' | |
1993 | ? INTVAL (x) & 0xffff | |
1994 | : (INTVAL (x) >> 16) & 0xffff)); | |
1995 | } | |
1996 | return; | |
1997 | case CONST : | |
1998 | case SYMBOL_REF : | |
1999 | if (code == 'B' | |
2000 | && small_data_operand (x, VOIDmode)) | |
2001 | { | |
2002 | fputs ("sda(", file); | |
2003 | output_addr_const (file, x); | |
2004 | fputc (')', file); | |
2005 | return; | |
2006 | } | |
2007 | /* fall through */ | |
2008 | case LABEL_REF : | |
2009 | fputs (code == 'T' ? "shigh(" : "low(", file); | |
2010 | output_addr_const (file, x); | |
2011 | fputc (')', file); | |
2012 | return; | |
2013 | default : | |
2014 | output_operand_lossage ("invalid operand to %T/%B code"); | |
2015 | return; | |
2016 | } | |
2017 | break; | |
2018 | ||
2019 | case 'U' : | |
2e076ddf | 2020 | /* ??? wip */ |
8c5ca3b9 DE |
2021 | /* Output a load/store with update indicator if appropriate. */ |
2022 | if (GET_CODE (x) == MEM) | |
2023 | { | |
2024 | if (GET_CODE (XEXP (x, 0)) == PRE_INC | |
2025 | || GET_CODE (XEXP (x, 0)) == PRE_DEC) | |
2026 | fputs (".a", file); | |
2027 | } | |
2028 | else | |
2029 | output_operand_lossage ("invalid operand to %U code"); | |
2030 | return; | |
2031 | ||
2032 | case 'N' : | |
2033 | /* Print a constant value negated. */ | |
2034 | if (GET_CODE (x) == CONST_INT) | |
2035 | output_addr_const (file, GEN_INT (- INTVAL (x))); | |
2036 | else | |
2037 | output_operand_lossage ("invalid operand to %N code"); | |
2038 | return; | |
2039 | ||
4d6c607f DE |
2040 | case 'X' : |
2041 | /* Print a const_int in hex. Used in comments. */ | |
2042 | if (GET_CODE (x) == CONST_INT) | |
2043 | fprintf (file, | |
2044 | #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT | |
2045 | "0x%x", | |
2046 | #else | |
2047 | "0x%lx", | |
2048 | #endif | |
2049 | INTVAL (x)); | |
2050 | return; | |
2051 | ||
8c5ca3b9 DE |
2052 | case '#' : |
2053 | fputs (IMMEDIATE_PREFIX, file); | |
2054 | return; | |
2055 | ||
2056 | #if 0 /* ??? no longer used */ | |
2057 | case '@' : | |
2058 | fputs (reg_names[SDA_REGNUM], file); | |
2059 | return; | |
2060 | #endif | |
2061 | ||
2062 | case 0 : | |
2063 | /* Do nothing special. */ | |
2064 | break; | |
2065 | ||
2066 | default : | |
2067 | /* Unknown flag. */ | |
2068 | output_operand_lossage ("invalid operand output code"); | |
2069 | } | |
2070 | ||
2071 | switch (GET_CODE (x)) | |
2072 | { | |
2073 | case REG : | |
2074 | fputs (reg_names[REGNO (x)], file); | |
2075 | break; | |
2076 | ||
2077 | case MEM : | |
5b8ae21f MM |
2078 | addr = XEXP (x, 0); |
2079 | if (GET_CODE (addr) == PRE_INC) | |
2080 | { | |
2081 | if (GET_CODE (XEXP (addr, 0)) != REG) | |
2082 | abort (); | |
2083 | ||
2084 | fprintf (file, "@+%s", reg_names[REGNO (XEXP (addr, 0))]); | |
2085 | } | |
2086 | else if (GET_CODE (addr) == PRE_DEC) | |
2087 | { | |
2088 | if (GET_CODE (XEXP (addr, 0)) != REG) | |
2089 | abort (); | |
2090 | ||
2091 | fprintf (file, "@-%s", reg_names[REGNO (XEXP (addr, 0))]); | |
2092 | } | |
2093 | else if (GET_CODE (addr) == POST_INC) | |
2094 | { | |
2095 | if (GET_CODE (XEXP (addr, 0)) != REG) | |
2096 | abort (); | |
2097 | ||
2098 | fprintf (file, "@%s+", reg_names[REGNO (XEXP (addr, 0))]); | |
2099 | } | |
8c5ca3b9 | 2100 | else |
5b8ae21f MM |
2101 | { |
2102 | fputs ("@(", file); | |
2103 | output_address (XEXP (x, 0)); | |
2104 | fputc (')', file); | |
2105 | } | |
8c5ca3b9 DE |
2106 | break; |
2107 | ||
2108 | case CONST_DOUBLE : | |
2109 | /* We handle SFmode constants here as output_addr_const doesn't. */ | |
2110 | if (GET_MODE (x) == SFmode) | |
2111 | { | |
2112 | REAL_VALUE_TYPE d; | |
2113 | long l; | |
2114 | ||
2115 | REAL_VALUE_FROM_CONST_DOUBLE (d, x); | |
2116 | REAL_VALUE_TO_TARGET_SINGLE (d, l); | |
2117 | fprintf (file, "0x%08lx", l); | |
2118 | break; | |
2119 | } | |
2120 | ||
2121 | /* Fall through. Let output_addr_const deal with it. */ | |
2122 | ||
2123 | default : | |
2124 | output_addr_const (file, x); | |
2125 | break; | |
2126 | } | |
2127 | } | |
2128 | ||
2129 | /* Print a memory address as an operand to reference that memory location. */ | |
2130 | ||
2131 | void | |
2132 | m32r_print_operand_address (file, addr) | |
2e076ddf NC |
2133 | FILE * file; |
2134 | rtx addr; | |
8c5ca3b9 | 2135 | { |
2e076ddf NC |
2136 | register rtx base; |
2137 | register rtx index = 0; | |
2138 | int offset = 0; | |
8c5ca3b9 DE |
2139 | |
2140 | switch (GET_CODE (addr)) | |
2141 | { | |
2142 | case REG : | |
2143 | fputs (reg_names[REGNO (addr)], file); | |
2144 | break; | |
2145 | ||
2146 | case PLUS : | |
2147 | if (GET_CODE (XEXP (addr, 0)) == CONST_INT) | |
2148 | offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1); | |
2149 | else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) | |
2150 | offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0); | |
2151 | else | |
2152 | base = XEXP (addr, 0), index = XEXP (addr, 1); | |
2153 | if (GET_CODE (base) == REG) | |
2154 | { | |
2155 | /* Print the offset first (if present) to conform to the manual. */ | |
2156 | if (index == 0) | |
2157 | { | |
2158 | if (offset != 0) | |
2159 | fprintf (file, "%d,", offset); | |
2160 | fputs (reg_names[REGNO (base)], file); | |
2161 | } | |
2162 | /* The chip doesn't support this, but left in for generality. */ | |
2163 | else if (GET_CODE (index) == REG) | |
2164 | fprintf (file, "%s,%s", | |
2165 | reg_names[REGNO (base)], reg_names[REGNO (index)]); | |
2166 | /* Not sure this can happen, but leave in for now. */ | |
2167 | else if (GET_CODE (index) == SYMBOL_REF) | |
2168 | { | |
2169 | output_addr_const (file, index); | |
2170 | fputc (',', file); | |
2171 | fputs (reg_names[REGNO (base)], file); | |
2172 | } | |
2173 | else | |
2174 | abort (); | |
2175 | } | |
2176 | else if (GET_CODE (base) == LO_SUM) | |
2177 | { | |
2178 | if (index != 0 | |
2179 | || GET_CODE (XEXP (base, 0)) != REG) | |
2180 | abort (); | |
2181 | if (small_data_operand (XEXP (base, 1), VOIDmode)) | |
2182 | fputs ("sda(", file); | |
2183 | else | |
2184 | fputs ("low(", file); | |
2185 | output_addr_const (file, plus_constant (XEXP (base, 1), offset)); | |
2186 | fputs ("),", file); | |
2187 | fputs (reg_names[REGNO (XEXP (base, 0))], file); | |
2188 | } | |
2189 | else | |
2190 | abort (); | |
2191 | break; | |
2192 | ||
2193 | case LO_SUM : | |
2194 | if (GET_CODE (XEXP (addr, 0)) != REG) | |
2195 | abort (); | |
2196 | if (small_data_operand (XEXP (addr, 1), VOIDmode)) | |
2197 | fputs ("sda(", file); | |
2198 | else | |
2199 | fputs ("low(", file); | |
2200 | output_addr_const (file, XEXP (addr, 1)); | |
2201 | fputs ("),", file); | |
2202 | fputs (reg_names[REGNO (XEXP (addr, 0))], file); | |
2203 | break; | |
2204 | ||
5b8ae21f MM |
2205 | case PRE_INC : /* Assume SImode */ |
2206 | fprintf (file, "+%s", reg_names[REGNO (XEXP (addr, 0))]); | |
2207 | break; | |
2208 | ||
2209 | case PRE_DEC : /* Assume SImode */ | |
2210 | fprintf (file, "-%s", reg_names[REGNO (XEXP (addr, 0))]); | |
2211 | break; | |
2212 | ||
2213 | case POST_INC : /* Assume SImode */ | |
2214 | fprintf (file, "%s+", reg_names[REGNO (XEXP (addr, 0))]); | |
8c5ca3b9 DE |
2215 | break; |
2216 | ||
2217 | default : | |
2218 | output_addr_const (file, addr); | |
2219 | break; | |
2220 | } | |
2221 | } | |
2b7972b0 MM |
2222 | |
2223 | /* Return true if the operands are the constants 0 and 1. */ | |
2224 | int | |
2225 | zero_and_one (operand1, operand2) | |
2226 | rtx operand1; | |
2227 | rtx operand2; | |
2228 | { | |
2229 | return | |
2230 | GET_CODE (operand1) == CONST_INT | |
2231 | && GET_CODE (operand2) == CONST_INT | |
2232 | && ( ((INTVAL (operand1) == 0) && (INTVAL (operand2) == 1)) | |
2233 | ||((INTVAL (operand1) == 1) && (INTVAL (operand2) == 0))); | |
2234 | } | |
2235 | ||
2236 | /* Return non-zero if the operand is suitable for use in a conditional move sequence. */ | |
2237 | int | |
2238 | conditional_move_operand (operand, int_mode) | |
2239 | rtx operand; | |
2240 | int int_mode; | |
2241 | { | |
2242 | enum machine_mode mode = (enum machine_mode)int_mode; | |
2243 | ||
2244 | /* Only defined for simple integers so far... */ | |
2245 | if (mode != SImode && mode != HImode && mode != QImode) | |
2246 | return FALSE; | |
2247 | ||
2248 | /* At the moment we can hanndle moving registers and loading constants. */ | |
2249 | /* To be added: Addition/subtraction/bitops/multiplication of registers. */ | |
2250 | ||
2251 | switch (GET_CODE (operand)) | |
2252 | { | |
2253 | case REG: | |
2254 | return 1; | |
2255 | ||
2256 | case CONST_INT: | |
2257 | return INT8_P (INTVAL (operand)); | |
2258 | ||
2259 | default: | |
2260 | #if 0 | |
2261 | fprintf (stderr, "Test for cond move op of type: %s\n", | |
2262 | GET_RTX_NAME (GET_CODE (operand))); | |
2263 | #endif | |
2264 | return 0; | |
2265 | } | |
2266 | } | |
2267 | ||
2268 | /* Return true if the code is a test of the carry bit */ | |
2269 | int | |
2270 | carry_compare_operand (op, int_mode) | |
2271 | rtx op; | |
2272 | int int_mode; | |
2273 | { | |
2274 | rtx x; | |
2275 | ||
51c10c4e | 2276 | if (GET_MODE (op) != SImode && GET_MODE (op) != VOIDmode) |
2b7972b0 MM |
2277 | return FALSE; |
2278 | ||
2279 | if (GET_CODE (op) != NE && GET_CODE (op) != EQ) | |
2280 | return FALSE; | |
2281 | ||
2282 | x = XEXP (op, 0); | |
2283 | if (GET_CODE (x) != REG || REGNO (x) != CARRY_REGNUM) | |
2284 | return FALSE; | |
2285 | ||
2286 | x = XEXP (op, 1); | |
2287 | if (GET_CODE (x) != CONST_INT || INTVAL (x) != 0) | |
2288 | return FALSE; | |
2289 | ||
2290 | return TRUE; | |
2291 | } | |
2292 | ||
2293 | ||
2294 | /* Generate the correct assembler code to handle the conditional loading of a | |
2295 | value into a register. It is known that the operands satisfy the | |
2296 | conditional_move_operand() function above. The destination is operand[0]. | |
2297 | The condition is operand [1]. The 'true' value is operand [2] and the | |
2298 | 'false' value is operand [3]. */ | |
2299 | char * | |
2300 | emit_cond_move (operands, insn) | |
2301 | rtx * operands; | |
2302 | rtx insn; | |
2303 | { | |
2304 | static char buffer [100]; | |
51c10c4e NC |
2305 | char * dest = reg_names [REGNO (operands [0])]; |
2306 | ||
2b7972b0 MM |
2307 | buffer [0] = 0; |
2308 | ||
2309 | /* Destination must be a register. */ | |
2310 | if (GET_CODE (operands [0]) != REG) | |
2311 | abort(); | |
2312 | if (! conditional_move_operand (operands [2], SImode)) | |
2313 | abort(); | |
2314 | if (! conditional_move_operand (operands [3], SImode)) | |
2315 | abort(); | |
2316 | ||
2b7972b0 MM |
2317 | /* Check to see if the test is reversed. */ |
2318 | if (GET_CODE (operands [1]) == NE) | |
2319 | { | |
2320 | rtx tmp = operands [2]; | |
2321 | operands [2] = operands [3]; | |
2322 | operands [3] = tmp; | |
2323 | } | |
2324 | ||
51c10c4e NC |
2325 | sprintf (buffer, "mvfc %s, cbr", dest); |
2326 | ||
2327 | /* If the true value was '0' then we need to invert the results of the move. */ | |
2328 | if (INTVAL (operands [2]) == 0) | |
2329 | sprintf (buffer + strlen (buffer), "\n\txor3 %s, %s, #1", | |
2330 | dest, dest); | |
2331 | ||
2b7972b0 MM |
2332 | return buffer; |
2333 | } | |
2334 | ||
d2a73f8e NC |
2335 | |
2336 | \f | |
2337 | /* Use a library function to move some bytes. */ | |
2338 | static void | |
2339 | block_move_call (dest_reg, src_reg, bytes_rtx) | |
2340 | rtx dest_reg; | |
2341 | rtx src_reg; | |
2342 | rtx bytes_rtx; | |
2343 | { | |
2344 | /* We want to pass the size as Pmode, which will normally be SImode | |
2345 | but will be DImode if we are using 64 bit longs and pointers. */ | |
2346 | if (GET_MODE (bytes_rtx) != VOIDmode | |
2347 | && GET_MODE (bytes_rtx) != Pmode) | |
2348 | bytes_rtx = convert_to_mode (Pmode, bytes_rtx, 1); | |
2349 | ||
2350 | #ifdef TARGET_MEM_FUNCTIONS | |
2351 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, | |
2352 | VOIDmode, 3, dest_reg, Pmode, src_reg, Pmode, | |
2353 | convert_to_mode (TYPE_MODE (sizetype), bytes_rtx, | |
2354 | TREE_UNSIGNED (sizetype)), | |
2355 | TYPE_MODE (sizetype)); | |
2356 | #else | |
2357 | emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0, | |
2358 | VOIDmode, 3, src_reg, Pmode, dest_reg, Pmode, | |
2359 | convert_to_mode (TYPE_MODE (integer_type_node), bytes_rtx, | |
2360 | TREE_UNSIGNED (integer_type_node)), | |
2361 | TYPE_MODE (integer_type_node)); | |
2362 | #endif | |
2363 | } | |
2364 | ||
2365 | /* The maximum number of bytes to copy using pairs of load/store instructions. | |
2366 | If a block is larger than this then a loop will be generated to copy | |
2367 | MAX_MOVE_BYTES chunks at a time. The value of 32 is a semi-arbitary choice. | |
2368 | A customer uses Dhrystome as their benchmark, and Dhrystone has a 31 byte | |
2369 | string copy in it. */ | |
2370 | #define MAX_MOVE_BYTES 32 | |
2371 | ||
2372 | /* Expand string/block move operations. | |
2373 | ||
2374 | operands[0] is the pointer to the destination. | |
2375 | operands[1] is the pointer to the source. | |
2376 | operands[2] is the number of bytes to move. | |
2377 | operands[3] is the alignment. */ | |
2378 | ||
2379 | void | |
2380 | m32r_expand_block_move (operands) | |
2381 | rtx operands[]; | |
2382 | { | |
2383 | rtx orig_dst = operands[0]; | |
2384 | rtx orig_src = operands[1]; | |
2385 | rtx bytes_rtx = operands[2]; | |
2386 | rtx align_rtx = operands[3]; | |
2387 | int constp = GET_CODE (bytes_rtx) == CONST_INT; | |
2388 | HOST_WIDE_INT bytes = constp ? INTVAL (bytes_rtx) : 0; | |
2389 | int align = INTVAL (align_rtx); | |
2390 | int leftover; | |
2391 | rtx src_reg; | |
2392 | rtx dst_reg; | |
2393 | ||
2394 | if (constp && bytes <= 0) | |
2395 | return; | |
2396 | ||
2397 | /* Move the address into scratch registers. */ | |
2398 | dst_reg = copy_addr_to_reg (XEXP (orig_dst, 0)); | |
2399 | src_reg = copy_addr_to_reg (XEXP (orig_src, 0)); | |
2400 | ||
2401 | if (align > UNITS_PER_WORD) | |
2402 | align = UNITS_PER_WORD; | |
2403 | ||
2404 | /* If we prefer size over speed, always use a function call. | |
2405 | If we do not know the size, use a function call. | |
2406 | If the blocks are not word aligned, use a function call. */ | |
2407 | if (optimize_size || ! constp || align != UNITS_PER_WORD) | |
2408 | { | |
2409 | block_move_call (dst_reg, src_reg, bytes_rtx); | |
2410 | return; | |
2411 | } | |
2412 | ||
2413 | leftover = bytes % MAX_MOVE_BYTES; | |
2414 | bytes -= leftover; | |
2415 | ||
2416 | /* If necessary, generate a loop to handle the bulk of the copy. */ | |
2417 | if (bytes) | |
2418 | { | |
2419 | rtx label; | |
2420 | rtx final_src; | |
0ae9f65b DE |
2421 | rtx at_a_time = GEN_INT (MAX_MOVE_BYTES); |
2422 | rtx rounded_total = GEN_INT (bytes); | |
d2a73f8e NC |
2423 | |
2424 | /* If we are going to have to perform this loop more than | |
2425 | once, then generate a label and compute the address the | |
2426 | source register will contain upon completion of the final | |
2427 | itteration. */ | |
2428 | if (bytes > MAX_MOVE_BYTES) | |
2429 | { | |
2430 | final_src = gen_reg_rtx (Pmode); | |
2431 | ||
2432 | if (INT16_P(bytes)) | |
0ae9f65b | 2433 | emit_insn (gen_addsi3 (final_src, src_reg, rounded_total)); |
d2a73f8e NC |
2434 | else |
2435 | { | |
0ae9f65b | 2436 | emit_insn (gen_movsi (final_src, rounded_total)); |
d2a73f8e NC |
2437 | emit_insn (gen_addsi3 (final_src, final_src, src_reg)); |
2438 | } | |
2439 | ||
2440 | label = gen_label_rtx (); | |
2441 | emit_label (label); | |
2442 | } | |
2443 | ||
2444 | /* It is known that output_block_move() will update src_reg to point | |
2445 | to the word after the end of the source block, and dst_reg to point | |
2446 | to the last word of the destination block, provided that the block | |
2447 | is MAX_MOVE_BYTES long. */ | |
0ae9f65b | 2448 | emit_insn (gen_movstrsi_internal (dst_reg, src_reg, at_a_time)); |
d2a73f8e NC |
2449 | emit_insn (gen_addsi3 (dst_reg, dst_reg, GEN_INT (4))); |
2450 | ||
2451 | if (bytes > MAX_MOVE_BYTES) | |
2452 | { | |
2453 | emit_insn (gen_cmpsi (src_reg, final_src)); | |
2454 | emit_jump_insn (gen_bne (label)); | |
2455 | } | |
2456 | } | |
2457 | ||
2458 | if (leftover) | |
2459 | emit_insn (gen_movstrsi_internal (dst_reg, src_reg, GEN_INT (leftover))); | |
2460 | } | |
2461 | ||
2462 | \f | |
2463 | /* Emit load/stores for a small constant word aligned block_move. | |
2464 | ||
2465 | operands[0] is the memory address of the destination. | |
2466 | operands[1] is the memory address of the source. | |
2467 | operands[2] is the number of bytes to move. | |
2468 | operands[3] is a temp register. | |
2469 | operands[4] is a temp register. */ | |
2470 | ||
2471 | char * | |
2472 | m32r_output_block_move (insn, operands) | |
2473 | rtx insn; | |
2474 | rtx operands[]; | |
2475 | { | |
2476 | HOST_WIDE_INT bytes = INTVAL (operands[2]); | |
2477 | int first_time; | |
2478 | int got_extra = 0; | |
2479 | ||
2480 | if (bytes < 1 || bytes > MAX_MOVE_BYTES) | |
2481 | abort (); | |
2482 | ||
2483 | /* We do not have a post-increment store available, so the first set of | |
2484 | stores are done without any increment, then the remaining ones can use | |
2485 | the pre-increment addressing mode. | |
2486 | ||
2487 | Note: expand_block_move() also relies upon this behaviour when building | |
2488 | loops to copy large blocks. */ | |
2489 | first_time = 1; | |
2490 | ||
2491 | while (bytes > 0) | |
2492 | { | |
2493 | if (bytes >= 8) | |
2494 | { | |
2495 | if (first_time) | |
2496 | { | |
2497 | output_asm_insn ("ld\t%3, %p1", operands); | |
2498 | output_asm_insn ("ld\t%4, %p1", operands); | |
2499 | output_asm_insn ("st\t%3, @%0", operands); | |
2500 | output_asm_insn ("st\t%4, %s0", operands); | |
2501 | } | |
2502 | else | |
2503 | { | |
2504 | output_asm_insn ("ld\t%3, %p1", operands); | |
2505 | output_asm_insn ("ld\t%4, %p1", operands); | |
2506 | output_asm_insn ("st\t%3, %s0", operands); | |
2507 | output_asm_insn ("st\t%4, %s0", operands); | |
2508 | } | |
2509 | ||
2510 | bytes -= 8; | |
2511 | } | |
2512 | else if (bytes >= 4) | |
2513 | { | |
2514 | if (bytes > 4) | |
2515 | got_extra = 1; | |
2516 | ||
2517 | output_asm_insn ("ld\t%3, %p1", operands); | |
2518 | ||
2519 | if (got_extra) | |
2520 | output_asm_insn ("ld\t%4, %p1", operands); | |
2521 | ||
2522 | if (first_time) | |
2523 | output_asm_insn ("st\t%3, @%0", operands); | |
2524 | else | |
2525 | output_asm_insn ("st\t%3, %s0", operands); | |
2526 | ||
2527 | bytes -= 4; | |
2528 | } | |
2529 | else | |
2530 | { | |
2531 | /* Get the entire next word, even though we do not want all of it. | |
2532 | The saves us from doing several smaller loads, and we assume that | |
2533 | we cannot cause a page fault when at least part of the word is in | |
0ae9f65b DE |
2534 | valid memory [since we don't get called if things aren't properly |
2535 | aligned]. */ | |
2536 | int dst_offset = first_time ? 0 : 4; | |
2537 | int last_shift; | |
2538 | rtx my_operands[3]; | |
2539 | ||
2540 | /* If got_extra is true then we have already loaded | |
d2a73f8e NC |
2541 | the next word as part of loading and storing the previous word. */ |
2542 | if (! got_extra) | |
2543 | output_asm_insn ("ld\t%4, @%1", operands); | |
2544 | ||
2545 | if (bytes >= 2) | |
2546 | { | |
2547 | bytes -= 2; | |
2548 | ||
0ae9f65b DE |
2549 | output_asm_insn ("sra3\t%3, %4, #16", operands); |
2550 | my_operands[0] = operands[3]; | |
2551 | my_operands[1] = GEN_INT (dst_offset); | |
2552 | my_operands[2] = operands[0]; | |
2553 | output_asm_insn ("sth\t%0, @(%1,%2)", my_operands); | |
d2a73f8e NC |
2554 | |
2555 | /* If there is a byte left to store then increment the | |
2556 | destination address and shift the contents of the source | |
0ae9f65b | 2557 | register down by 8 bits. We could not do the address |
d2a73f8e NC |
2558 | increment in the store half word instruction, because it does |
2559 | not have an auto increment mode. */ | |
2560 | if (bytes > 0) /* assert (bytes == 1) */ | |
2561 | { | |
0ae9f65b DE |
2562 | dst_offset += 2; |
2563 | last_shift = 8; | |
d2a73f8e NC |
2564 | } |
2565 | } | |
0ae9f65b DE |
2566 | else |
2567 | last_shift = 24; | |
2568 | ||
2569 | if (bytes > 0) | |
2570 | { | |
2571 | my_operands[0] = operands[4]; | |
2572 | my_operands[1] = GEN_INT (last_shift); | |
2573 | output_asm_insn ("srai\t%0, #%1", my_operands); | |
2574 | my_operands[0] = operands[4]; | |
2575 | my_operands[1] = GEN_INT (dst_offset); | |
2576 | my_operands[2] = operands[0]; | |
2577 | output_asm_insn ("stb\t%0, @(%1,%2)", my_operands); | |
2578 | } | |
d2a73f8e NC |
2579 | |
2580 | bytes = 0; | |
2581 | } | |
2582 | ||
2583 | first_time = 0; | |
2584 | } | |
2585 | ||
2586 | return ""; | |
2587 | } | |
2588 | ||
2589 | /* Return true if op is an integer constant, less than or equal to | |
2590 | MAX_MOVE_BYTES. */ | |
2591 | int | |
2592 | m32r_block_immediate_operand (op, mode) | |
2593 | rtx op; | |
2594 | int mode; | |
2595 | { | |
2596 | if (GET_CODE (op) != CONST_INT | |
2597 | || INTVAL (op) > MAX_MOVE_BYTES | |
2598 | || INTVAL (op) <= 0) | |
2599 | return 0; | |
2600 | ||
2601 | return 1; | |
2602 | } |