]>
Commit | Line | Data |
---|---|---|
c65ebc55 | 1 | /* Definitions of target machine for GNU compiler. |
e65271be | 2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. |
c65ebc55 JW |
3 | Contributed by James E. Wilson <wilson@cygnus.com> and |
4 | David Mosberger <davidm@hpl.hp.com>. | |
5 | ||
6 | This file is part of GNU CC. | |
7 | ||
8 | GNU CC is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 2, or (at your option) | |
11 | any later version. | |
12 | ||
13 | GNU CC is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GNU CC; see the file COPYING. If not, write to | |
20 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
21 | Boston, MA 02111-1307, USA. */ | |
22 | ||
c65ebc55 | 23 | #include "config.h" |
ed9ccd8a | 24 | #include "system.h" |
c65ebc55 JW |
25 | #include "rtl.h" |
26 | #include "tree.h" | |
27 | #include "tm_p.h" | |
28 | #include "regs.h" | |
29 | #include "hard-reg-set.h" | |
30 | #include "real.h" | |
31 | #include "insn-config.h" | |
32 | #include "conditions.h" | |
33 | #include "insn-flags.h" | |
34 | #include "output.h" | |
35 | #include "insn-attr.h" | |
36 | #include "flags.h" | |
37 | #include "recog.h" | |
38 | #include "expr.h" | |
39 | #include "obstack.h" | |
40 | #include "except.h" | |
41 | #include "function.h" | |
42 | #include "ggc.h" | |
43 | #include "basic-block.h" | |
809d4ef1 | 44 | #include "toplev.h" |
c65ebc55 JW |
45 | |
46 | /* This is used for communication between ASM_OUTPUT_LABEL and | |
47 | ASM_OUTPUT_LABELREF. */ | |
48 | int ia64_asm_output_label = 0; | |
49 | ||
50 | /* Define the information needed to generate branch and scc insns. This is | |
51 | stored from the compare operation. */ | |
52 | struct rtx_def * ia64_compare_op0; | |
53 | struct rtx_def * ia64_compare_op1; | |
54 | ||
c65ebc55 | 55 | /* Register names for ia64_expand_prologue. */ |
3b572406 | 56 | static const char * const ia64_reg_numbers[96] = |
c65ebc55 JW |
57 | { "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39", |
58 | "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", | |
59 | "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55", | |
60 | "r56", "r57", "r58", "r59", "r60", "r61", "r62", "r63", | |
61 | "r64", "r65", "r66", "r67", "r68", "r69", "r70", "r71", | |
62 | "r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79", | |
63 | "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87", | |
64 | "r88", "r89", "r90", "r91", "r92", "r93", "r94", "r95", | |
65 | "r96", "r97", "r98", "r99", "r100","r101","r102","r103", | |
66 | "r104","r105","r106","r107","r108","r109","r110","r111", | |
67 | "r112","r113","r114","r115","r116","r117","r118","r119", | |
68 | "r120","r121","r122","r123","r124","r125","r126","r127"}; | |
69 | ||
70 | /* ??? These strings could be shared with REGISTER_NAMES. */ | |
3b572406 | 71 | static const char * const ia64_input_reg_names[8] = |
c65ebc55 JW |
72 | { "in0", "in1", "in2", "in3", "in4", "in5", "in6", "in7" }; |
73 | ||
74 | /* ??? These strings could be shared with REGISTER_NAMES. */ | |
3b572406 | 75 | static const char * const ia64_local_reg_names[80] = |
c65ebc55 JW |
76 | { "loc0", "loc1", "loc2", "loc3", "loc4", "loc5", "loc6", "loc7", |
77 | "loc8", "loc9", "loc10","loc11","loc12","loc13","loc14","loc15", | |
78 | "loc16","loc17","loc18","loc19","loc20","loc21","loc22","loc23", | |
79 | "loc24","loc25","loc26","loc27","loc28","loc29","loc30","loc31", | |
80 | "loc32","loc33","loc34","loc35","loc36","loc37","loc38","loc39", | |
81 | "loc40","loc41","loc42","loc43","loc44","loc45","loc46","loc47", | |
82 | "loc48","loc49","loc50","loc51","loc52","loc53","loc54","loc55", | |
83 | "loc56","loc57","loc58","loc59","loc60","loc61","loc62","loc63", | |
84 | "loc64","loc65","loc66","loc67","loc68","loc69","loc70","loc71", | |
85 | "loc72","loc73","loc74","loc75","loc76","loc77","loc78","loc79" }; | |
86 | ||
87 | /* ??? These strings could be shared with REGISTER_NAMES. */ | |
3b572406 | 88 | static const char * const ia64_output_reg_names[8] = |
c65ebc55 JW |
89 | { "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7" }; |
90 | ||
91 | /* String used with the -mfixed-range= option. */ | |
92 | const char *ia64_fixed_range_string; | |
93 | ||
94 | /* Variables which are this size or smaller are put in the sdata/sbss | |
95 | sections. */ | |
96 | ||
3b572406 RH |
97 | unsigned int ia64_section_threshold; |
98 | \f | |
97e242b0 RH |
99 | static int find_gr_spill PARAMS ((int)); |
100 | static int next_scratch_gr_reg PARAMS ((void)); | |
101 | static void mark_reg_gr_used_mask PARAMS ((rtx, void *)); | |
102 | static void ia64_compute_frame_size PARAMS ((HOST_WIDE_INT)); | |
103 | static void setup_spill_pointers PARAMS ((int, rtx, HOST_WIDE_INT)); | |
104 | static void finish_spill_pointers PARAMS ((void)); | |
105 | static rtx spill_restore_mem PARAMS ((rtx, HOST_WIDE_INT)); | |
870f9ec0 RH |
106 | static void do_spill PARAMS ((rtx (*)(rtx, rtx, rtx), rtx, HOST_WIDE_INT, rtx)); |
107 | static void do_restore PARAMS ((rtx (*)(rtx, rtx, rtx), rtx, HOST_WIDE_INT)); | |
0551c32d RH |
108 | static rtx gen_movdi_x PARAMS ((rtx, rtx, rtx)); |
109 | static rtx gen_fr_spill_x PARAMS ((rtx, rtx, rtx)); | |
110 | static rtx gen_fr_restore_x PARAMS ((rtx, rtx, rtx)); | |
97e242b0 | 111 | |
3b572406 RH |
112 | static enum machine_mode hfa_element_mode PARAMS ((tree, int)); |
113 | static void fix_range PARAMS ((const char *)); | |
114 | static void ia64_add_gc_roots PARAMS ((void)); | |
115 | static void ia64_init_machine_status PARAMS ((struct function *)); | |
116 | static void ia64_mark_machine_status PARAMS ((struct function *)); | |
117 | static void emit_insn_group_barriers PARAMS ((rtx)); | |
f2f90c63 | 118 | static void emit_predicate_relation_info PARAMS ((void)); |
3b572406 | 119 | static int process_set PARAMS ((FILE *, rtx)); |
0551c32d RH |
120 | |
121 | static rtx ia64_expand_fetch_and_op PARAMS ((optab, enum machine_mode, | |
122 | tree, rtx)); | |
123 | static rtx ia64_expand_op_and_fetch PARAMS ((optab, enum machine_mode, | |
124 | tree, rtx)); | |
125 | static rtx ia64_expand_compare_and_swap PARAMS ((enum machine_mode, int, | |
126 | tree, rtx)); | |
127 | static rtx ia64_expand_lock_test_and_set PARAMS ((enum machine_mode, | |
128 | tree, rtx)); | |
129 | static rtx ia64_expand_lock_release PARAMS ((enum machine_mode, tree, rtx)); | |
130 | ||
3b572406 | 131 | \f |
c65ebc55 JW |
132 | /* Return 1 if OP is a valid operand for the MEM of a CALL insn. */ |
133 | ||
134 | int | |
135 | call_operand (op, mode) | |
136 | rtx op; | |
137 | enum machine_mode mode; | |
138 | { | |
139 | if (mode != GET_MODE (op)) | |
140 | return 0; | |
141 | ||
142 | return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG | |
143 | || (GET_CODE (op) == SUBREG && GET_CODE (XEXP (op, 0)) == REG)); | |
144 | } | |
145 | ||
146 | /* Return 1 if OP refers to a symbol in the sdata section. */ | |
147 | ||
148 | int | |
149 | sdata_symbolic_operand (op, mode) | |
150 | rtx op; | |
fd7c34b0 | 151 | enum machine_mode mode ATTRIBUTE_UNUSED; |
c65ebc55 JW |
152 | { |
153 | switch (GET_CODE (op)) | |
154 | { | |
ac9cd70f RH |
155 | case CONST: |
156 | if (GET_CODE (XEXP (op, 0)) != PLUS | |
157 | || GET_CODE (XEXP (XEXP (op, 0), 0)) != SYMBOL_REF) | |
158 | break; | |
159 | op = XEXP (XEXP (op, 0), 0); | |
160 | /* FALLTHRU */ | |
161 | ||
c65ebc55 | 162 | case SYMBOL_REF: |
ac9cd70f RH |
163 | if (CONSTANT_POOL_ADDRESS_P (op)) |
164 | return GET_MODE_SIZE (get_pool_mode (op)) <= ia64_section_threshold; | |
165 | else | |
166 | return XSTR (op, 0)[0] == SDATA_NAME_FLAG_CHAR; | |
c65ebc55 | 167 | |
c65ebc55 JW |
168 | default: |
169 | break; | |
170 | } | |
171 | ||
172 | return 0; | |
173 | } | |
174 | ||
ec039e3c | 175 | /* Return 1 if OP refers to a symbol, and is appropriate for a GOT load. */ |
c65ebc55 JW |
176 | |
177 | int | |
ec039e3c | 178 | got_symbolic_operand (op, mode) |
c65ebc55 | 179 | rtx op; |
fd7c34b0 | 180 | enum machine_mode mode ATTRIBUTE_UNUSED; |
c65ebc55 JW |
181 | { |
182 | switch (GET_CODE (op)) | |
183 | { | |
184 | case CONST: | |
dee4095a RH |
185 | op = XEXP (op, 0); |
186 | if (GET_CODE (op) != PLUS) | |
187 | return 0; | |
188 | if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF) | |
189 | return 0; | |
190 | op = XEXP (op, 1); | |
191 | if (GET_CODE (op) != CONST_INT) | |
192 | return 0; | |
ec039e3c RH |
193 | |
194 | return 1; | |
195 | ||
196 | /* Ok if we're not using GOT entries at all. */ | |
197 | if (TARGET_NO_PIC || TARGET_AUTO_PIC) | |
198 | return 1; | |
199 | ||
200 | /* "Ok" while emitting rtl, since otherwise we won't be provided | |
201 | with the entire offset during emission, which makes it very | |
202 | hard to split the offset into high and low parts. */ | |
203 | if (rtx_equal_function_value_matters) | |
204 | return 1; | |
205 | ||
206 | /* Force the low 14 bits of the constant to zero so that we do not | |
dee4095a | 207 | use up so many GOT entries. */ |
ec039e3c RH |
208 | return (INTVAL (op) & 0x3fff) == 0; |
209 | ||
210 | case SYMBOL_REF: | |
211 | case LABEL_REF: | |
dee4095a RH |
212 | return 1; |
213 | ||
ec039e3c RH |
214 | default: |
215 | break; | |
216 | } | |
217 | return 0; | |
218 | } | |
219 | ||
220 | /* Return 1 if OP refers to a symbol. */ | |
221 | ||
222 | int | |
223 | symbolic_operand (op, mode) | |
224 | rtx op; | |
225 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
226 | { | |
227 | switch (GET_CODE (op)) | |
228 | { | |
229 | case CONST: | |
c65ebc55 JW |
230 | case SYMBOL_REF: |
231 | case LABEL_REF: | |
232 | return 1; | |
233 | ||
234 | default: | |
235 | break; | |
236 | } | |
237 | return 0; | |
238 | } | |
239 | ||
240 | /* Return 1 if OP refers to a function. */ | |
241 | ||
242 | int | |
243 | function_operand (op, mode) | |
244 | rtx op; | |
fd7c34b0 | 245 | enum machine_mode mode ATTRIBUTE_UNUSED; |
c65ebc55 JW |
246 | { |
247 | if (GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FLAG (op)) | |
248 | return 1; | |
249 | else | |
250 | return 0; | |
251 | } | |
252 | ||
253 | /* Return 1 if OP is setjmp or a similar function. */ | |
254 | ||
255 | /* ??? This is an unsatisfying solution. Should rethink. */ | |
256 | ||
257 | int | |
258 | setjmp_operand (op, mode) | |
259 | rtx op; | |
fd7c34b0 | 260 | enum machine_mode mode ATTRIBUTE_UNUSED; |
c65ebc55 | 261 | { |
809d4ef1 | 262 | const char *name; |
c65ebc55 JW |
263 | int retval = 0; |
264 | ||
265 | if (GET_CODE (op) != SYMBOL_REF) | |
266 | return 0; | |
267 | ||
268 | name = XSTR (op, 0); | |
269 | ||
270 | /* The following code is borrowed from special_function_p in calls.c. */ | |
271 | ||
272 | /* Disregard prefix _, __ or __x. */ | |
273 | if (name[0] == '_') | |
274 | { | |
275 | if (name[1] == '_' && name[2] == 'x') | |
276 | name += 3; | |
277 | else if (name[1] == '_') | |
278 | name += 2; | |
279 | else | |
280 | name += 1; | |
281 | } | |
282 | ||
283 | if (name[0] == 's') | |
284 | { | |
285 | retval | |
286 | = ((name[1] == 'e' | |
287 | && (! strcmp (name, "setjmp") | |
288 | || ! strcmp (name, "setjmp_syscall"))) | |
289 | || (name[1] == 'i' | |
290 | && ! strcmp (name, "sigsetjmp")) | |
291 | || (name[1] == 'a' | |
292 | && ! strcmp (name, "savectx"))); | |
293 | } | |
294 | else if ((name[0] == 'q' && name[1] == 's' | |
295 | && ! strcmp (name, "qsetjmp")) | |
296 | || (name[0] == 'v' && name[1] == 'f' | |
297 | && ! strcmp (name, "vfork"))) | |
298 | retval = 1; | |
299 | ||
300 | return retval; | |
301 | } | |
302 | ||
303 | /* Return 1 if OP is a general operand, but when pic exclude symbolic | |
304 | operands. */ | |
305 | ||
306 | /* ??? If we drop no-pic support, can delete SYMBOL_REF, CONST, and LABEL_REF | |
307 | from PREDICATE_CODES. */ | |
308 | ||
309 | int | |
310 | move_operand (op, mode) | |
311 | rtx op; | |
312 | enum machine_mode mode; | |
313 | { | |
ec039e3c | 314 | if (! TARGET_NO_PIC && symbolic_operand (op, mode)) |
c65ebc55 JW |
315 | return 0; |
316 | ||
317 | return general_operand (op, mode); | |
318 | } | |
319 | ||
0551c32d RH |
320 | /* Return 1 if OP is a register operand that is (or could be) a GR reg. */ |
321 | ||
322 | int | |
323 | gr_register_operand (op, mode) | |
324 | rtx op; | |
325 | enum machine_mode mode; | |
326 | { | |
327 | if (! register_operand (op, mode)) | |
328 | return 0; | |
329 | if (GET_CODE (op) == SUBREG) | |
330 | op = SUBREG_REG (op); | |
331 | if (GET_CODE (op) == REG) | |
332 | { | |
333 | unsigned int regno = REGNO (op); | |
334 | if (regno < FIRST_PSEUDO_REGISTER) | |
335 | return GENERAL_REGNO_P (regno); | |
336 | } | |
337 | return 1; | |
338 | } | |
339 | ||
340 | /* Return 1 if OP is a register operand that is (or could be) an FR reg. */ | |
341 | ||
342 | int | |
343 | fr_register_operand (op, mode) | |
344 | rtx op; | |
345 | enum machine_mode mode; | |
346 | { | |
347 | if (! register_operand (op, mode)) | |
348 | return 0; | |
349 | if (GET_CODE (op) == SUBREG) | |
350 | op = SUBREG_REG (op); | |
351 | if (GET_CODE (op) == REG) | |
352 | { | |
353 | unsigned int regno = REGNO (op); | |
354 | if (regno < FIRST_PSEUDO_REGISTER) | |
355 | return FR_REGNO_P (regno); | |
356 | } | |
357 | return 1; | |
358 | } | |
359 | ||
360 | /* Return 1 if OP is a register operand that is (or could be) a GR/FR reg. */ | |
361 | ||
362 | int | |
363 | grfr_register_operand (op, mode) | |
364 | rtx op; | |
365 | enum machine_mode mode; | |
366 | { | |
367 | if (! register_operand (op, mode)) | |
368 | return 0; | |
369 | if (GET_CODE (op) == SUBREG) | |
370 | op = SUBREG_REG (op); | |
371 | if (GET_CODE (op) == REG) | |
372 | { | |
373 | unsigned int regno = REGNO (op); | |
374 | if (regno < FIRST_PSEUDO_REGISTER) | |
375 | return GENERAL_REGNO_P (regno) || FR_REGNO_P (regno); | |
376 | } | |
377 | return 1; | |
378 | } | |
379 | ||
380 | /* Return 1 if OP is a nonimmediate operand that is (or could be) a GR reg. */ | |
381 | ||
382 | int | |
383 | gr_nonimmediate_operand (op, mode) | |
384 | rtx op; | |
385 | enum machine_mode mode; | |
386 | { | |
387 | if (! nonimmediate_operand (op, mode)) | |
388 | return 0; | |
389 | if (GET_CODE (op) == SUBREG) | |
390 | op = SUBREG_REG (op); | |
391 | if (GET_CODE (op) == REG) | |
392 | { | |
393 | unsigned int regno = REGNO (op); | |
394 | if (regno < FIRST_PSEUDO_REGISTER) | |
395 | return GENERAL_REGNO_P (regno); | |
396 | } | |
397 | return 1; | |
398 | } | |
399 | ||
655f2eb9 RH |
400 | /* Return 1 if OP is a nonimmediate operand that is (or could be) a FR reg. */ |
401 | ||
402 | int | |
403 | fr_nonimmediate_operand (op, mode) | |
404 | rtx op; | |
405 | enum machine_mode mode; | |
406 | { | |
407 | if (! nonimmediate_operand (op, mode)) | |
408 | return 0; | |
409 | if (GET_CODE (op) == SUBREG) | |
410 | op = SUBREG_REG (op); | |
411 | if (GET_CODE (op) == REG) | |
412 | { | |
413 | unsigned int regno = REGNO (op); | |
414 | if (regno < FIRST_PSEUDO_REGISTER) | |
415 | return FR_REGNO_P (regno); | |
416 | } | |
417 | return 1; | |
418 | } | |
419 | ||
0551c32d RH |
420 | /* Return 1 if OP is a nonimmediate operand that is a GR/FR reg. */ |
421 | ||
422 | int | |
423 | grfr_nonimmediate_operand (op, mode) | |
424 | rtx op; | |
425 | enum machine_mode mode; | |
426 | { | |
427 | if (! nonimmediate_operand (op, mode)) | |
428 | return 0; | |
429 | if (GET_CODE (op) == SUBREG) | |
430 | op = SUBREG_REG (op); | |
431 | if (GET_CODE (op) == REG) | |
432 | { | |
433 | unsigned int regno = REGNO (op); | |
434 | if (regno < FIRST_PSEUDO_REGISTER) | |
435 | return GENERAL_REGNO_P (regno) || FR_REGNO_P (regno); | |
436 | } | |
437 | return 1; | |
438 | } | |
439 | ||
440 | /* Return 1 if OP is a GR register operand, or zero. */ | |
c65ebc55 JW |
441 | |
442 | int | |
0551c32d | 443 | gr_reg_or_0_operand (op, mode) |
c65ebc55 JW |
444 | rtx op; |
445 | enum machine_mode mode; | |
446 | { | |
0551c32d | 447 | return (op == const0_rtx || gr_register_operand (op, mode)); |
c65ebc55 JW |
448 | } |
449 | ||
0551c32d | 450 | /* Return 1 if OP is a GR register operand, or a 5 bit immediate operand. */ |
041f25e6 RH |
451 | |
452 | int | |
0551c32d | 453 | gr_reg_or_5bit_operand (op, mode) |
041f25e6 RH |
454 | rtx op; |
455 | enum machine_mode mode; | |
456 | { | |
457 | return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 32) | |
458 | || GET_CODE (op) == CONSTANT_P_RTX | |
0551c32d | 459 | || gr_register_operand (op, mode)); |
041f25e6 RH |
460 | } |
461 | ||
0551c32d | 462 | /* Return 1 if OP is a GR register operand, or a 6 bit immediate operand. */ |
c65ebc55 JW |
463 | |
464 | int | |
0551c32d | 465 | gr_reg_or_6bit_operand (op, mode) |
c65ebc55 JW |
466 | rtx op; |
467 | enum machine_mode mode; | |
468 | { | |
469 | return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op))) | |
470 | || GET_CODE (op) == CONSTANT_P_RTX | |
0551c32d | 471 | || gr_register_operand (op, mode)); |
c65ebc55 JW |
472 | } |
473 | ||
0551c32d | 474 | /* Return 1 if OP is a GR register operand, or an 8 bit immediate operand. */ |
c65ebc55 JW |
475 | |
476 | int | |
0551c32d | 477 | gr_reg_or_8bit_operand (op, mode) |
c65ebc55 JW |
478 | rtx op; |
479 | enum machine_mode mode; | |
480 | { | |
481 | return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op))) | |
482 | || GET_CODE (op) == CONSTANT_P_RTX | |
0551c32d | 483 | || gr_register_operand (op, mode)); |
c65ebc55 JW |
484 | } |
485 | ||
0551c32d RH |
486 | /* Return 1 if OP is a GR/FR register operand, or an 8 bit immediate. */ |
487 | ||
488 | int | |
489 | grfr_reg_or_8bit_operand (op, mode) | |
490 | rtx op; | |
491 | enum machine_mode mode; | |
492 | { | |
493 | return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op))) | |
494 | || GET_CODE (op) == CONSTANT_P_RTX | |
495 | || grfr_register_operand (op, mode)); | |
496 | } | |
97e242b0 | 497 | |
c65ebc55 JW |
498 | /* Return 1 if OP is a register operand, or an 8 bit adjusted immediate |
499 | operand. */ | |
500 | ||
501 | int | |
0551c32d | 502 | gr_reg_or_8bit_adjusted_operand (op, mode) |
c65ebc55 JW |
503 | rtx op; |
504 | enum machine_mode mode; | |
505 | { | |
506 | return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_L (INTVAL (op))) | |
507 | || GET_CODE (op) == CONSTANT_P_RTX | |
0551c32d | 508 | || gr_register_operand (op, mode)); |
c65ebc55 JW |
509 | } |
510 | ||
511 | /* Return 1 if OP is a register operand, or is valid for both an 8 bit | |
512 | immediate and an 8 bit adjusted immediate operand. This is necessary | |
513 | because when we emit a compare, we don't know what the condition will be, | |
514 | so we need the union of the immediates accepted by GT and LT. */ | |
515 | ||
516 | int | |
0551c32d | 517 | gr_reg_or_8bit_and_adjusted_operand (op, mode) |
c65ebc55 JW |
518 | rtx op; |
519 | enum machine_mode mode; | |
520 | { | |
521 | return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op)) | |
522 | && CONST_OK_FOR_L (INTVAL (op))) | |
523 | || GET_CODE (op) == CONSTANT_P_RTX | |
0551c32d | 524 | || gr_register_operand (op, mode)); |
c65ebc55 JW |
525 | } |
526 | ||
527 | /* Return 1 if OP is a register operand, or a 14 bit immediate operand. */ | |
528 | ||
529 | int | |
0551c32d | 530 | gr_reg_or_14bit_operand (op, mode) |
c65ebc55 JW |
531 | rtx op; |
532 | enum machine_mode mode; | |
533 | { | |
534 | return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_I (INTVAL (op))) | |
535 | || GET_CODE (op) == CONSTANT_P_RTX | |
0551c32d | 536 | || gr_register_operand (op, mode)); |
c65ebc55 JW |
537 | } |
538 | ||
539 | /* Return 1 if OP is a register operand, or a 22 bit immediate operand. */ | |
540 | ||
541 | int | |
0551c32d | 542 | gr_reg_or_22bit_operand (op, mode) |
c65ebc55 JW |
543 | rtx op; |
544 | enum machine_mode mode; | |
545 | { | |
546 | return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_J (INTVAL (op))) | |
547 | || GET_CODE (op) == CONSTANT_P_RTX | |
0551c32d | 548 | || gr_register_operand (op, mode)); |
c65ebc55 JW |
549 | } |
550 | ||
551 | /* Return 1 if OP is a 6 bit immediate operand. */ | |
552 | ||
553 | int | |
554 | shift_count_operand (op, mode) | |
555 | rtx op; | |
fd7c34b0 | 556 | enum machine_mode mode ATTRIBUTE_UNUSED; |
c65ebc55 JW |
557 | { |
558 | return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op))) | |
559 | || GET_CODE (op) == CONSTANT_P_RTX); | |
560 | } | |
561 | ||
562 | /* Return 1 if OP is a 5 bit immediate operand. */ | |
563 | ||
564 | int | |
565 | shift_32bit_count_operand (op, mode) | |
566 | rtx op; | |
fd7c34b0 | 567 | enum machine_mode mode ATTRIBUTE_UNUSED; |
c65ebc55 JW |
568 | { |
569 | return ((GET_CODE (op) == CONST_INT | |
570 | && (INTVAL (op) >= 0 && INTVAL (op) < 32)) | |
571 | || GET_CODE (op) == CONSTANT_P_RTX); | |
572 | } | |
573 | ||
574 | /* Return 1 if OP is a 2, 4, 8, or 16 immediate operand. */ | |
575 | ||
576 | int | |
577 | shladd_operand (op, mode) | |
578 | rtx op; | |
fd7c34b0 | 579 | enum machine_mode mode ATTRIBUTE_UNUSED; |
c65ebc55 JW |
580 | { |
581 | return (GET_CODE (op) == CONST_INT | |
582 | && (INTVAL (op) == 2 || INTVAL (op) == 4 | |
583 | || INTVAL (op) == 8 || INTVAL (op) == 16)); | |
584 | } | |
585 | ||
586 | /* Return 1 if OP is a -16, -8, -4, -1, 1, 4, 8, or 16 immediate operand. */ | |
587 | ||
588 | int | |
589 | fetchadd_operand (op, mode) | |
590 | rtx op; | |
fd7c34b0 | 591 | enum machine_mode mode ATTRIBUTE_UNUSED; |
c65ebc55 JW |
592 | { |
593 | return (GET_CODE (op) == CONST_INT | |
594 | && (INTVAL (op) == -16 || INTVAL (op) == -8 || | |
595 | INTVAL (op) == -4 || INTVAL (op) == -1 || | |
596 | INTVAL (op) == 1 || INTVAL (op) == 4 || | |
597 | INTVAL (op) == 8 || INTVAL (op) == 16)); | |
598 | } | |
599 | ||
600 | /* Return 1 if OP is a floating-point constant zero, one, or a register. */ | |
601 | ||
602 | int | |
0551c32d | 603 | fr_reg_or_fp01_operand (op, mode) |
c65ebc55 JW |
604 | rtx op; |
605 | enum machine_mode mode; | |
606 | { | |
607 | return ((GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (op)) | |
0551c32d | 608 | || fr_register_operand (op, mode)); |
c65ebc55 JW |
609 | } |
610 | ||
4b983fdc RH |
611 | /* Like nonimmediate_operand, but don't allow MEMs that try to use a |
612 | POST_MODIFY with a REG as displacement. */ | |
613 | ||
614 | int | |
615 | destination_operand (op, mode) | |
616 | rtx op; | |
617 | enum machine_mode mode; | |
618 | { | |
619 | if (! nonimmediate_operand (op, mode)) | |
620 | return 0; | |
621 | if (GET_CODE (op) == MEM | |
622 | && GET_CODE (XEXP (op, 0)) == POST_MODIFY | |
623 | && GET_CODE (XEXP (XEXP (XEXP (op, 0), 1), 1)) == REG) | |
624 | return 0; | |
625 | return 1; | |
626 | } | |
627 | ||
0551c32d RH |
628 | /* Like memory_operand, but don't allow post-increments. */ |
629 | ||
630 | int | |
631 | not_postinc_memory_operand (op, mode) | |
632 | rtx op; | |
633 | enum machine_mode mode; | |
634 | { | |
635 | return (memory_operand (op, mode) | |
636 | && GET_RTX_CLASS (GET_CODE (XEXP (op, 0))) != 'a'); | |
637 | } | |
638 | ||
c65ebc55 JW |
639 | /* Return 1 if this is a comparison operator, which accepts an normal 8-bit |
640 | signed immediate operand. */ | |
641 | ||
642 | int | |
643 | normal_comparison_operator (op, mode) | |
644 | register rtx op; | |
645 | enum machine_mode mode; | |
646 | { | |
647 | enum rtx_code code = GET_CODE (op); | |
648 | return ((mode == VOIDmode || GET_MODE (op) == mode) | |
809d4ef1 | 649 | && (code == EQ || code == NE |
c65ebc55 JW |
650 | || code == GT || code == LE || code == GTU || code == LEU)); |
651 | } | |
652 | ||
653 | /* Return 1 if this is a comparison operator, which accepts an adjusted 8-bit | |
654 | signed immediate operand. */ | |
655 | ||
656 | int | |
657 | adjusted_comparison_operator (op, mode) | |
658 | register rtx op; | |
659 | enum machine_mode mode; | |
660 | { | |
661 | enum rtx_code code = GET_CODE (op); | |
662 | return ((mode == VOIDmode || GET_MODE (op) == mode) | |
663 | && (code == LT || code == GE || code == LTU || code == GEU)); | |
664 | } | |
665 | ||
f2f90c63 RH |
666 | /* Return 1 if this is a signed inequality operator. */ |
667 | ||
668 | int | |
669 | signed_inequality_operator (op, mode) | |
670 | register rtx op; | |
671 | enum machine_mode mode; | |
672 | { | |
673 | enum rtx_code code = GET_CODE (op); | |
674 | return ((mode == VOIDmode || GET_MODE (op) == mode) | |
675 | && (code == GE || code == GT | |
676 | || code == LE || code == LT)); | |
677 | } | |
678 | ||
e5bde68a RH |
679 | /* Return 1 if this operator is valid for predication. */ |
680 | ||
681 | int | |
682 | predicate_operator (op, mode) | |
683 | register rtx op; | |
684 | enum machine_mode mode; | |
685 | { | |
686 | enum rtx_code code = GET_CODE (op); | |
687 | return ((GET_MODE (op) == mode || mode == VOIDmode) | |
688 | && (code == EQ || code == NE)); | |
689 | } | |
5527bf14 RH |
690 | |
691 | /* Return 1 if this is the ar.lc register. */ | |
692 | ||
693 | int | |
694 | ar_lc_reg_operand (op, mode) | |
695 | register rtx op; | |
696 | enum machine_mode mode; | |
697 | { | |
698 | return (GET_MODE (op) == DImode | |
699 | && (mode == DImode || mode == VOIDmode) | |
700 | && GET_CODE (op) == REG | |
701 | && REGNO (op) == AR_LC_REGNUM); | |
702 | } | |
97e242b0 RH |
703 | |
704 | /* Return 1 if this is the ar.ccv register. */ | |
705 | ||
706 | int | |
707 | ar_ccv_reg_operand (op, mode) | |
708 | register rtx op; | |
709 | enum machine_mode mode; | |
710 | { | |
711 | return ((GET_MODE (op) == mode || mode == VOIDmode) | |
712 | && GET_CODE (op) == REG | |
713 | && REGNO (op) == AR_CCV_REGNUM); | |
714 | } | |
3f622353 RH |
715 | |
716 | /* Like general_operand, but don't allow (mem (addressof)). */ | |
717 | ||
718 | int | |
719 | general_tfmode_operand (op, mode) | |
720 | rtx op; | |
721 | enum machine_mode mode; | |
722 | { | |
723 | if (! general_operand (op, mode)) | |
724 | return 0; | |
725 | if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == ADDRESSOF) | |
726 | return 0; | |
727 | return 1; | |
728 | } | |
729 | ||
730 | /* Similarly. */ | |
731 | ||
732 | int | |
733 | destination_tfmode_operand (op, mode) | |
734 | rtx op; | |
735 | enum machine_mode mode; | |
736 | { | |
737 | if (! destination_operand (op, mode)) | |
738 | return 0; | |
739 | if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == ADDRESSOF) | |
740 | return 0; | |
741 | return 1; | |
742 | } | |
743 | ||
744 | /* Similarly. */ | |
745 | ||
746 | int | |
747 | tfreg_or_fp01_operand (op, mode) | |
748 | rtx op; | |
749 | enum machine_mode mode; | |
750 | { | |
751 | if (GET_CODE (op) == SUBREG) | |
752 | return 0; | |
0551c32d | 753 | return fr_reg_or_fp01_operand (op, mode); |
3f622353 | 754 | } |
9b7bf67d | 755 | \f |
557b9df5 RH |
756 | /* Return 1 if the operands of a move are ok. */ |
757 | ||
758 | int | |
759 | ia64_move_ok (dst, src) | |
760 | rtx dst, src; | |
761 | { | |
762 | /* If we're under init_recog_no_volatile, we'll not be able to use | |
763 | memory_operand. So check the code directly and don't worry about | |
764 | the validity of the underlying address, which should have been | |
765 | checked elsewhere anyway. */ | |
766 | if (GET_CODE (dst) != MEM) | |
767 | return 1; | |
768 | if (GET_CODE (src) == MEM) | |
769 | return 0; | |
770 | if (register_operand (src, VOIDmode)) | |
771 | return 1; | |
772 | ||
773 | /* Otherwise, this must be a constant, and that either 0 or 0.0 or 1.0. */ | |
774 | if (INTEGRAL_MODE_P (GET_MODE (dst))) | |
775 | return src == const0_rtx; | |
776 | else | |
777 | return GET_CODE (src) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (src); | |
778 | } | |
9b7bf67d | 779 | |
041f25e6 RH |
780 | /* Check if OP is a mask suitible for use with SHIFT in a dep.z instruction. |
781 | Return the length of the field, or <= 0 on failure. */ | |
782 | ||
783 | int | |
784 | ia64_depz_field_mask (rop, rshift) | |
785 | rtx rop, rshift; | |
786 | { | |
787 | unsigned HOST_WIDE_INT op = INTVAL (rop); | |
788 | unsigned HOST_WIDE_INT shift = INTVAL (rshift); | |
789 | ||
790 | /* Get rid of the zero bits we're shifting in. */ | |
791 | op >>= shift; | |
792 | ||
793 | /* We must now have a solid block of 1's at bit 0. */ | |
794 | return exact_log2 (op + 1); | |
795 | } | |
796 | ||
9b7bf67d RH |
797 | /* Expand a symbolic constant load. */ |
798 | /* ??? Should generalize this, so that we can also support 32 bit pointers. */ | |
799 | ||
800 | void | |
801 | ia64_expand_load_address (dest, src) | |
802 | rtx dest, src; | |
803 | { | |
804 | rtx temp; | |
805 | ||
806 | /* The destination could be a MEM during initial rtl generation, | |
807 | which isn't a valid destination for the PIC load address patterns. */ | |
808 | if (! register_operand (dest, DImode)) | |
809 | temp = gen_reg_rtx (DImode); | |
810 | else | |
811 | temp = dest; | |
812 | ||
813 | if (TARGET_AUTO_PIC) | |
814 | emit_insn (gen_load_gprel64 (temp, src)); | |
815 | else if (GET_CODE (src) == SYMBOL_REF && SYMBOL_REF_FLAG (src)) | |
816 | emit_insn (gen_load_fptr (temp, src)); | |
817 | else if (sdata_symbolic_operand (src, DImode)) | |
818 | emit_insn (gen_load_gprel (temp, src)); | |
819 | else if (GET_CODE (src) == CONST | |
820 | && GET_CODE (XEXP (src, 0)) == PLUS | |
821 | && GET_CODE (XEXP (XEXP (src, 0), 1)) == CONST_INT | |
822 | && (INTVAL (XEXP (XEXP (src, 0), 1)) & 0x1fff) != 0) | |
823 | { | |
824 | rtx subtarget = no_new_pseudos ? temp : gen_reg_rtx (DImode); | |
825 | rtx sym = XEXP (XEXP (src, 0), 0); | |
826 | HOST_WIDE_INT ofs, hi, lo; | |
827 | ||
828 | /* Split the offset into a sign extended 14-bit low part | |
829 | and a complementary high part. */ | |
830 | ofs = INTVAL (XEXP (XEXP (src, 0), 1)); | |
831 | lo = ((ofs & 0x3fff) ^ 0x2000) - 0x2000; | |
832 | hi = ofs - lo; | |
833 | ||
834 | emit_insn (gen_load_symptr (subtarget, plus_constant (sym, hi))); | |
835 | emit_insn (gen_adddi3 (temp, subtarget, GEN_INT (lo))); | |
836 | } | |
837 | else | |
838 | emit_insn (gen_load_symptr (temp, src)); | |
839 | ||
840 | if (temp != dest) | |
841 | emit_move_insn (dest, temp); | |
842 | } | |
97e242b0 RH |
843 | |
844 | rtx | |
845 | ia64_gp_save_reg (setjmp_p) | |
846 | int setjmp_p; | |
847 | { | |
848 | rtx save = cfun->machine->ia64_gp_save; | |
849 | ||
850 | if (save != NULL) | |
851 | { | |
852 | /* We can't save GP in a pseudo if we are calling setjmp, because | |
853 | pseudos won't be restored by longjmp. For now, we save it in r4. */ | |
854 | /* ??? It would be more efficient to save this directly into a stack | |
855 | slot. Unfortunately, the stack slot address gets cse'd across | |
856 | the setjmp call because the NOTE_INSN_SETJMP note is in the wrong | |
857 | place. */ | |
858 | ||
859 | /* ??? Get the barf bag, Virginia. We've got to replace this thing | |
860 | in place, since this rtx is used in exception handling receivers. | |
861 | Moreover, we must get this rtx out of regno_reg_rtx or reload | |
862 | will do the wrong thing. */ | |
863 | unsigned int old_regno = REGNO (save); | |
864 | if (setjmp_p && old_regno != GR_REG (4)) | |
865 | { | |
866 | REGNO (save) = GR_REG (4); | |
867 | regno_reg_rtx[old_regno] = gen_rtx_raw_REG (DImode, old_regno); | |
868 | } | |
869 | } | |
870 | else | |
871 | { | |
872 | if (setjmp_p) | |
873 | save = gen_rtx_REG (DImode, GR_REG (4)); | |
874 | else if (! optimize) | |
875 | save = gen_rtx_REG (DImode, LOC_REG (0)); | |
876 | else | |
877 | save = gen_reg_rtx (DImode); | |
878 | cfun->machine->ia64_gp_save = save; | |
879 | } | |
880 | ||
881 | return save; | |
882 | } | |
3f622353 RH |
883 | |
884 | /* Split a post-reload TImode reference into two DImode components. */ | |
885 | ||
886 | rtx | |
887 | ia64_split_timode (out, in, scratch) | |
888 | rtx out[2]; | |
889 | rtx in, scratch; | |
890 | { | |
891 | switch (GET_CODE (in)) | |
892 | { | |
893 | case REG: | |
894 | out[0] = gen_rtx_REG (DImode, REGNO (in)); | |
895 | out[1] = gen_rtx_REG (DImode, REGNO (in) + 1); | |
896 | return NULL_RTX; | |
897 | ||
898 | case MEM: | |
899 | { | |
3f622353 | 900 | rtx base = XEXP (in, 0); |
3f622353 RH |
901 | |
902 | switch (GET_CODE (base)) | |
903 | { | |
904 | case REG: | |
905 | out[0] = change_address (in, DImode, NULL_RTX); | |
906 | break; | |
907 | case POST_MODIFY: | |
908 | base = XEXP (base, 0); | |
909 | out[0] = change_address (in, DImode, NULL_RTX); | |
910 | break; | |
911 | ||
912 | /* Since we're changing the mode, we need to change to POST_MODIFY | |
913 | as well to preserve the size of the increment. Either that or | |
914 | do the update in two steps, but we've already got this scratch | |
915 | register handy so let's use it. */ | |
916 | case POST_INC: | |
917 | base = XEXP (base, 0); | |
918 | out[0] = change_address (in, DImode, | |
919 | gen_rtx_POST_MODIFY (Pmode, base,plus_constant (base, 16))); | |
920 | break; | |
921 | case POST_DEC: | |
922 | base = XEXP (base, 0); | |
923 | out[0] = change_address (in, DImode, | |
924 | gen_rtx_POST_MODIFY (Pmode, base,plus_constant (base, -16))); | |
925 | break; | |
926 | default: | |
927 | abort (); | |
928 | } | |
929 | ||
930 | if (scratch == NULL_RTX) | |
931 | abort (); | |
932 | out[1] = change_address (in, DImode, scratch); | |
933 | return gen_adddi3 (scratch, base, GEN_INT (8)); | |
934 | } | |
935 | ||
936 | case CONST_INT: | |
937 | case CONST_DOUBLE: | |
938 | split_double (in, &out[0], &out[1]); | |
939 | return NULL_RTX; | |
940 | ||
941 | default: | |
942 | abort (); | |
943 | } | |
944 | } | |
945 | ||
946 | /* ??? Fixing GR->FR TFmode moves during reload is hard. You need to go | |
947 | through memory plus an extra GR scratch register. Except that you can | |
948 | either get the first from SECONDARY_MEMORY_NEEDED or the second from | |
949 | SECONDARY_RELOAD_CLASS, but not both. | |
950 | ||
951 | We got into problems in the first place by allowing a construct like | |
952 | (subreg:TF (reg:TI)), which we got from a union containing a long double. | |
953 | This solution attempts to prevent this situation from ocurring. When | |
954 | we see something like the above, we spill the inner register to memory. */ | |
955 | ||
956 | rtx | |
957 | spill_tfmode_operand (in, force) | |
958 | rtx in; | |
959 | int force; | |
960 | { | |
961 | if (GET_CODE (in) == SUBREG | |
962 | && GET_MODE (SUBREG_REG (in)) == TImode | |
963 | && GET_CODE (SUBREG_REG (in)) == REG) | |
964 | { | |
965 | rtx mem = gen_mem_addressof (SUBREG_REG (in), NULL_TREE); | |
966 | return gen_rtx_MEM (TFmode, copy_to_reg (XEXP (mem, 0))); | |
967 | } | |
968 | else if (force && GET_CODE (in) == REG) | |
969 | { | |
970 | rtx mem = gen_mem_addressof (in, NULL_TREE); | |
971 | return gen_rtx_MEM (TFmode, copy_to_reg (XEXP (mem, 0))); | |
972 | } | |
973 | else if (GET_CODE (in) == MEM | |
974 | && GET_CODE (XEXP (in, 0)) == ADDRESSOF) | |
975 | { | |
976 | return change_address (in, TFmode, copy_to_reg (XEXP (in, 0))); | |
977 | } | |
978 | else | |
979 | return in; | |
980 | } | |
f2f90c63 RH |
981 | |
982 | /* Emit comparison instruction if necessary, returning the expression | |
983 | that holds the compare result in the proper mode. */ | |
984 | ||
985 | rtx | |
986 | ia64_expand_compare (code, mode) | |
987 | enum rtx_code code; | |
988 | enum machine_mode mode; | |
989 | { | |
990 | rtx op0 = ia64_compare_op0, op1 = ia64_compare_op1; | |
991 | rtx cmp; | |
992 | ||
993 | /* If we have a BImode input, then we already have a compare result, and | |
994 | do not need to emit another comparison. */ | |
995 | if (GET_MODE (op0) == BImode) | |
996 | { | |
997 | if ((code == NE || code == EQ) && op1 == const0_rtx) | |
998 | cmp = op0; | |
999 | else | |
1000 | abort (); | |
1001 | } | |
1002 | else | |
1003 | { | |
1004 | cmp = gen_reg_rtx (BImode); | |
1005 | emit_insn (gen_rtx_SET (VOIDmode, cmp, | |
1006 | gen_rtx_fmt_ee (code, BImode, op0, op1))); | |
1007 | code = NE; | |
1008 | } | |
1009 | ||
1010 | return gen_rtx_fmt_ee (code, mode, cmp, const0_rtx); | |
1011 | } | |
2ed4af6f RH |
1012 | |
1013 | /* Emit the appropriate sequence for a call. */ | |
1014 | ||
1015 | void | |
1016 | ia64_expand_call (retval, addr, nextarg, sibcall_p) | |
1017 | rtx retval; | |
1018 | rtx addr; | |
1019 | rtx nextarg; | |
1020 | int sibcall_p; | |
1021 | { | |
1022 | rtx insn, b0, gp_save, narg_rtx; | |
1023 | int narg; | |
1024 | ||
1025 | addr = XEXP (addr, 0); | |
1026 | b0 = gen_rtx_REG (DImode, R_BR (0)); | |
1027 | ||
1028 | if (! nextarg) | |
1029 | narg = 0; | |
1030 | else if (IN_REGNO_P (REGNO (nextarg))) | |
1031 | narg = REGNO (nextarg) - IN_REG (0); | |
1032 | else | |
1033 | narg = REGNO (nextarg) - OUT_REG (0); | |
1034 | narg_rtx = GEN_INT (narg); | |
1035 | ||
1036 | if (TARGET_NO_PIC || TARGET_AUTO_PIC) | |
1037 | { | |
1038 | if (sibcall_p) | |
1039 | insn = gen_sibcall_nopic (addr, narg_rtx, b0); | |
1040 | else if (! retval) | |
1041 | insn = gen_call_nopic (addr, narg_rtx, b0); | |
1042 | else | |
1043 | insn = gen_call_value_nopic (retval, addr, narg_rtx, b0); | |
1044 | emit_call_insn (insn); | |
1045 | return; | |
1046 | } | |
1047 | ||
1048 | if (sibcall_p) | |
1049 | gp_save = NULL_RTX; | |
1050 | else | |
1051 | gp_save = ia64_gp_save_reg (setjmp_operand (addr, VOIDmode)); | |
1052 | ||
1053 | /* If this is an indirect call, then we have the address of a descriptor. */ | |
1054 | if (! symbolic_operand (addr, VOIDmode)) | |
1055 | { | |
1056 | rtx dest; | |
1057 | ||
1058 | if (! sibcall_p) | |
1059 | emit_move_insn (gp_save, pic_offset_table_rtx); | |
1060 | ||
1061 | dest = force_reg (DImode, gen_rtx_MEM (DImode, addr)); | |
1062 | emit_move_insn (pic_offset_table_rtx, | |
1063 | gen_rtx_MEM (DImode, plus_constant (addr, 8))); | |
1064 | ||
1065 | if (sibcall_p) | |
1066 | insn = gen_sibcall_pic (dest, narg_rtx, b0); | |
1067 | else if (! retval) | |
1068 | insn = gen_call_pic (dest, narg_rtx, b0); | |
1069 | else | |
1070 | insn = gen_call_value_pic (retval, dest, narg_rtx, b0); | |
1071 | emit_call_insn (insn); | |
1072 | ||
1073 | if (! sibcall_p) | |
1074 | emit_move_insn (pic_offset_table_rtx, gp_save); | |
1075 | } | |
1076 | else if (TARGET_CONST_GP) | |
1077 | { | |
1078 | if (sibcall_p) | |
1079 | insn = gen_sibcall_nopic (addr, narg_rtx, b0); | |
1080 | else if (! retval) | |
1081 | insn = gen_call_nopic (addr, narg_rtx, b0); | |
1082 | else | |
1083 | insn = gen_call_value_nopic (retval, addr, narg_rtx, b0); | |
1084 | emit_call_insn (insn); | |
1085 | } | |
1086 | else | |
1087 | { | |
1088 | if (sibcall_p) | |
1089 | emit_call_insn (gen_sibcall_pic (addr, narg_rtx, b0)); | |
1090 | else | |
1091 | { | |
1092 | emit_move_insn (gp_save, pic_offset_table_rtx); | |
1093 | ||
1094 | if (! retval) | |
1095 | insn = gen_call_pic (addr, narg_rtx, b0); | |
1096 | else | |
1097 | insn = gen_call_value_pic (retval, addr, narg_rtx, b0); | |
1098 | emit_call_insn (insn); | |
1099 | ||
1100 | emit_move_insn (pic_offset_table_rtx, gp_save); | |
1101 | } | |
1102 | } | |
1103 | } | |
809d4ef1 | 1104 | \f |
3b572406 RH |
1105 | /* Begin the assembly file. */ |
1106 | ||
1107 | void | |
ca3920ad | 1108 | emit_safe_across_calls (f) |
3b572406 RH |
1109 | FILE *f; |
1110 | { | |
1111 | unsigned int rs, re; | |
1112 | int out_state; | |
1113 | ||
1114 | rs = 1; | |
1115 | out_state = 0; | |
1116 | while (1) | |
1117 | { | |
1118 | while (rs < 64 && call_used_regs[PR_REG (rs)]) | |
1119 | rs++; | |
1120 | if (rs >= 64) | |
1121 | break; | |
1122 | for (re = rs + 1; re < 64 && ! call_used_regs[PR_REG (re)]; re++) | |
1123 | continue; | |
1124 | if (out_state == 0) | |
1125 | { | |
1126 | fputs ("\t.pred.safe_across_calls ", f); | |
1127 | out_state = 1; | |
1128 | } | |
1129 | else | |
1130 | fputc (',', f); | |
1131 | if (re == rs + 1) | |
1132 | fprintf (f, "p%u", rs); | |
1133 | else | |
1134 | fprintf (f, "p%u-p%u", rs, re - 1); | |
1135 | rs = re + 1; | |
1136 | } | |
1137 | if (out_state) | |
1138 | fputc ('\n', f); | |
1139 | } | |
1140 | ||
97e242b0 | 1141 | |
c65ebc55 JW |
1142 | /* Structure to be filled in by ia64_compute_frame_size with register |
1143 | save masks and offsets for the current function. */ | |
1144 | ||
1145 | struct ia64_frame_info | |
1146 | { | |
97e242b0 RH |
1147 | HOST_WIDE_INT total_size; /* size of the stack frame, not including |
1148 | the caller's scratch area. */ | |
1149 | HOST_WIDE_INT spill_cfa_off; /* top of the reg spill area from the cfa. */ | |
1150 | HOST_WIDE_INT spill_size; /* size of the gr/br/fr spill area. */ | |
1151 | HOST_WIDE_INT extra_spill_size; /* size of spill area for others. */ | |
c65ebc55 | 1152 | HARD_REG_SET mask; /* mask of saved registers. */ |
97e242b0 RH |
1153 | unsigned int gr_used_mask; /* mask of registers in use as gr spill |
1154 | registers or long-term scratches. */ | |
1155 | int n_spilled; /* number of spilled registers. */ | |
1156 | int reg_fp; /* register for fp. */ | |
1157 | int reg_save_b0; /* save register for b0. */ | |
1158 | int reg_save_pr; /* save register for prs. */ | |
1159 | int reg_save_ar_pfs; /* save register for ar.pfs. */ | |
1160 | int reg_save_ar_unat; /* save register for ar.unat. */ | |
1161 | int reg_save_ar_lc; /* save register for ar.lc. */ | |
1162 | int n_input_regs; /* number of input registers used. */ | |
1163 | int n_local_regs; /* number of local registers used. */ | |
1164 | int n_output_regs; /* number of output registers used. */ | |
1165 | int n_rotate_regs; /* number of rotating registers used. */ | |
1166 | ||
1167 | char need_regstk; /* true if a .regstk directive needed. */ | |
1168 | char initialized; /* true if the data is finalized. */ | |
c65ebc55 JW |
1169 | }; |
1170 | ||
97e242b0 RH |
1171 | /* Current frame information calculated by ia64_compute_frame_size. */ |
1172 | static struct ia64_frame_info current_frame_info; | |
c65ebc55 | 1173 | |
97e242b0 RH |
1174 | /* Helper function for ia64_compute_frame_size: find an appropriate general |
1175 | register to spill some special register to. SPECIAL_SPILL_MASK contains | |
1176 | bits in GR0 to GR31 that have already been allocated by this routine. | |
1177 | TRY_LOCALS is true if we should attempt to locate a local regnum. */ | |
c65ebc55 | 1178 | |
97e242b0 RH |
1179 | static int |
1180 | find_gr_spill (try_locals) | |
1181 | int try_locals; | |
1182 | { | |
1183 | int regno; | |
1184 | ||
1185 | /* If this is a leaf function, first try an otherwise unused | |
1186 | call-clobbered register. */ | |
1187 | if (current_function_is_leaf) | |
1188 | { | |
1189 | for (regno = GR_REG (1); regno <= GR_REG (31); regno++) | |
1190 | if (! regs_ever_live[regno] | |
1191 | && call_used_regs[regno] | |
1192 | && ! fixed_regs[regno] | |
1193 | && ! global_regs[regno] | |
1194 | && ((current_frame_info.gr_used_mask >> regno) & 1) == 0) | |
1195 | { | |
1196 | current_frame_info.gr_used_mask |= 1 << regno; | |
1197 | return regno; | |
1198 | } | |
1199 | } | |
1200 | ||
1201 | if (try_locals) | |
1202 | { | |
1203 | regno = current_frame_info.n_local_regs; | |
1204 | if (regno < 80) | |
1205 | { | |
1206 | current_frame_info.n_local_regs = regno + 1; | |
1207 | return LOC_REG (0) + regno; | |
1208 | } | |
1209 | } | |
1210 | ||
1211 | /* Failed to find a general register to spill to. Must use stack. */ | |
1212 | return 0; | |
1213 | } | |
1214 | ||
1215 | /* In order to make for nice schedules, we try to allocate every temporary | |
1216 | to a different register. We must of course stay away from call-saved, | |
1217 | fixed, and global registers. We must also stay away from registers | |
1218 | allocated in current_frame_info.gr_used_mask, since those include regs | |
1219 | used all through the prologue. | |
1220 | ||
1221 | Any register allocated here must be used immediately. The idea is to | |
1222 | aid scheduling, not to solve data flow problems. */ | |
1223 | ||
1224 | static int last_scratch_gr_reg; | |
1225 | ||
1226 | static int | |
1227 | next_scratch_gr_reg () | |
1228 | { | |
1229 | int i, regno; | |
1230 | ||
1231 | for (i = 0; i < 32; ++i) | |
1232 | { | |
1233 | regno = (last_scratch_gr_reg + i + 1) & 31; | |
1234 | if (call_used_regs[regno] | |
1235 | && ! fixed_regs[regno] | |
1236 | && ! global_regs[regno] | |
1237 | && ((current_frame_info.gr_used_mask >> regno) & 1) == 0) | |
1238 | { | |
1239 | last_scratch_gr_reg = regno; | |
1240 | return regno; | |
1241 | } | |
1242 | } | |
1243 | ||
1244 | /* There must be _something_ available. */ | |
1245 | abort (); | |
1246 | } | |
1247 | ||
1248 | /* Helper function for ia64_compute_frame_size, called through | |
1249 | diddle_return_value. Mark REG in current_frame_info.gr_used_mask. */ | |
1250 | ||
1251 | static void | |
1252 | mark_reg_gr_used_mask (reg, data) | |
1253 | rtx reg; | |
1254 | void *data ATTRIBUTE_UNUSED; | |
c65ebc55 | 1255 | { |
97e242b0 RH |
1256 | unsigned int regno = REGNO (reg); |
1257 | if (regno < 32) | |
1258 | current_frame_info.gr_used_mask |= 1 << regno; | |
c65ebc55 JW |
1259 | } |
1260 | ||
1261 | /* Returns the number of bytes offset between the frame pointer and the stack | |
1262 | pointer for the current function. SIZE is the number of bytes of space | |
1263 | needed for local variables. */ | |
97e242b0 RH |
1264 | |
1265 | static void | |
c65ebc55 | 1266 | ia64_compute_frame_size (size) |
97e242b0 | 1267 | HOST_WIDE_INT size; |
c65ebc55 | 1268 | { |
97e242b0 RH |
1269 | HOST_WIDE_INT total_size; |
1270 | HOST_WIDE_INT spill_size = 0; | |
1271 | HOST_WIDE_INT extra_spill_size = 0; | |
1272 | HOST_WIDE_INT pretend_args_size; | |
c65ebc55 | 1273 | HARD_REG_SET mask; |
97e242b0 RH |
1274 | int n_spilled = 0; |
1275 | int spilled_gr_p = 0; | |
1276 | int spilled_fr_p = 0; | |
1277 | unsigned int regno; | |
1278 | int i; | |
c65ebc55 | 1279 | |
97e242b0 RH |
1280 | if (current_frame_info.initialized) |
1281 | return; | |
294dac80 | 1282 | |
97e242b0 | 1283 | memset (¤t_frame_info, 0, sizeof current_frame_info); |
c65ebc55 JW |
1284 | CLEAR_HARD_REG_SET (mask); |
1285 | ||
97e242b0 RH |
1286 | /* Don't allocate scratches to the return register. */ |
1287 | diddle_return_value (mark_reg_gr_used_mask, NULL); | |
1288 | ||
1289 | /* Don't allocate scratches to the EH scratch registers. */ | |
1290 | if (cfun->machine->ia64_eh_epilogue_sp) | |
1291 | mark_reg_gr_used_mask (cfun->machine->ia64_eh_epilogue_sp, NULL); | |
1292 | if (cfun->machine->ia64_eh_epilogue_bsp) | |
1293 | mark_reg_gr_used_mask (cfun->machine->ia64_eh_epilogue_bsp, NULL); | |
c65ebc55 | 1294 | |
97e242b0 RH |
1295 | /* Find the size of the register stack frame. We have only 80 local |
1296 | registers, because we reserve 8 for the inputs and 8 for the | |
1297 | outputs. */ | |
1298 | ||
1299 | /* Skip HARD_FRAME_POINTER_REGNUM (loc79) when frame_pointer_needed, | |
1300 | since we'll be adjusting that down later. */ | |
1301 | regno = LOC_REG (78) + ! frame_pointer_needed; | |
1302 | for (; regno >= LOC_REG (0); regno--) | |
1303 | if (regs_ever_live[regno]) | |
1304 | break; | |
1305 | current_frame_info.n_local_regs = regno - LOC_REG (0) + 1; | |
c65ebc55 | 1306 | |
26a110f5 | 1307 | if (cfun->machine->n_varargs > 0) |
97e242b0 RH |
1308 | current_frame_info.n_input_regs = 8; |
1309 | else | |
1310 | { | |
1311 | for (regno = IN_REG (7); regno >= IN_REG (0); regno--) | |
1312 | if (regs_ever_live[regno]) | |
1313 | break; | |
1314 | current_frame_info.n_input_regs = regno - IN_REG (0) + 1; | |
1315 | } | |
1316 | ||
1317 | for (regno = OUT_REG (7); regno >= OUT_REG (0); regno--) | |
1318 | if (regs_ever_live[regno]) | |
1319 | break; | |
1320 | i = regno - OUT_REG (0) + 1; | |
1321 | ||
1322 | /* When -p profiling, we need one output register for the mcount argument. | |
1323 | Likwise for -a profiling for the bb_init_func argument. For -ax | |
1324 | profiling, we need two output registers for the two bb_init_trace_func | |
1325 | arguments. */ | |
1326 | if (profile_flag || profile_block_flag == 1) | |
1327 | i = MAX (i, 1); | |
1328 | else if (profile_block_flag == 2) | |
1329 | i = MAX (i, 2); | |
1330 | current_frame_info.n_output_regs = i; | |
1331 | ||
1332 | /* ??? No rotating register support yet. */ | |
1333 | current_frame_info.n_rotate_regs = 0; | |
1334 | ||
1335 | /* Discover which registers need spilling, and how much room that | |
1336 | will take. Begin with floating point and general registers, | |
1337 | which will always wind up on the stack. */ | |
1338 | ||
1339 | for (regno = FR_REG (2); regno <= FR_REG (127); regno++) | |
c65ebc55 JW |
1340 | if (regs_ever_live[regno] && ! call_used_regs[regno]) |
1341 | { | |
1342 | SET_HARD_REG_BIT (mask, regno); | |
97e242b0 RH |
1343 | spill_size += 16; |
1344 | n_spilled += 1; | |
1345 | spilled_fr_p = 1; | |
c65ebc55 JW |
1346 | } |
1347 | ||
97e242b0 | 1348 | for (regno = GR_REG (1); regno <= GR_REG (31); regno++) |
c65ebc55 JW |
1349 | if (regs_ever_live[regno] && ! call_used_regs[regno]) |
1350 | { | |
1351 | SET_HARD_REG_BIT (mask, regno); | |
97e242b0 RH |
1352 | spill_size += 8; |
1353 | n_spilled += 1; | |
1354 | spilled_gr_p = 1; | |
c65ebc55 JW |
1355 | } |
1356 | ||
97e242b0 | 1357 | for (regno = BR_REG (1); regno <= BR_REG (7); regno++) |
c65ebc55 JW |
1358 | if (regs_ever_live[regno] && ! call_used_regs[regno]) |
1359 | { | |
1360 | SET_HARD_REG_BIT (mask, regno); | |
97e242b0 RH |
1361 | spill_size += 8; |
1362 | n_spilled += 1; | |
c65ebc55 JW |
1363 | } |
1364 | ||
97e242b0 RH |
1365 | /* Now come all special registers that might get saved in other |
1366 | general registers. */ | |
1367 | ||
1368 | if (frame_pointer_needed) | |
1369 | { | |
1370 | current_frame_info.reg_fp = find_gr_spill (1); | |
1371 | /* We should have gotten at least LOC79, since that's what | |
1372 | HARD_FRAME_POINTER_REGNUM is. */ | |
1373 | if (current_frame_info.reg_fp == 0) | |
1374 | abort (); | |
1375 | } | |
1376 | ||
1377 | if (! current_function_is_leaf) | |
c65ebc55 | 1378 | { |
97e242b0 RH |
1379 | /* Emit a save of BR0 if we call other functions. Do this even |
1380 | if this function doesn't return, as EH depends on this to be | |
1381 | able to unwind the stack. */ | |
1382 | SET_HARD_REG_BIT (mask, BR_REG (0)); | |
1383 | ||
1384 | current_frame_info.reg_save_b0 = find_gr_spill (1); | |
1385 | if (current_frame_info.reg_save_b0 == 0) | |
1386 | { | |
1387 | spill_size += 8; | |
1388 | n_spilled += 1; | |
1389 | } | |
1390 | ||
1391 | /* Similarly for ar.pfs. */ | |
1392 | SET_HARD_REG_BIT (mask, AR_PFS_REGNUM); | |
1393 | current_frame_info.reg_save_ar_pfs = find_gr_spill (1); | |
1394 | if (current_frame_info.reg_save_ar_pfs == 0) | |
1395 | { | |
1396 | extra_spill_size += 8; | |
1397 | n_spilled += 1; | |
1398 | } | |
c65ebc55 JW |
1399 | } |
1400 | else | |
97e242b0 RH |
1401 | { |
1402 | if (regs_ever_live[BR_REG (0)] && ! call_used_regs[BR_REG (0)]) | |
1403 | { | |
1404 | SET_HARD_REG_BIT (mask, BR_REG (0)); | |
1405 | spill_size += 8; | |
1406 | n_spilled += 1; | |
1407 | } | |
1408 | } | |
c65ebc55 | 1409 | |
97e242b0 RH |
1410 | /* Unwind descriptor hackery: things are most efficient if we allocate |
1411 | consecutive GR save registers for RP, PFS, FP in that order. However, | |
1412 | it is absolutely critical that FP get the only hard register that's | |
1413 | guaranteed to be free, so we allocated it first. If all three did | |
1414 | happen to be allocated hard regs, and are consecutive, rearrange them | |
1415 | into the preferred order now. */ | |
1416 | if (current_frame_info.reg_fp != 0 | |
1417 | && current_frame_info.reg_save_b0 == current_frame_info.reg_fp + 1 | |
1418 | && current_frame_info.reg_save_ar_pfs == current_frame_info.reg_fp + 2) | |
5527bf14 | 1419 | { |
97e242b0 RH |
1420 | current_frame_info.reg_save_b0 = current_frame_info.reg_fp; |
1421 | current_frame_info.reg_save_ar_pfs = current_frame_info.reg_fp + 1; | |
1422 | current_frame_info.reg_fp = current_frame_info.reg_fp + 2; | |
5527bf14 RH |
1423 | } |
1424 | ||
97e242b0 RH |
1425 | /* See if we need to store the predicate register block. */ |
1426 | for (regno = PR_REG (0); regno <= PR_REG (63); regno++) | |
1427 | if (regs_ever_live[regno] && ! call_used_regs[regno]) | |
1428 | break; | |
1429 | if (regno <= PR_REG (63)) | |
c65ebc55 | 1430 | { |
97e242b0 RH |
1431 | SET_HARD_REG_BIT (mask, PR_REG (0)); |
1432 | current_frame_info.reg_save_pr = find_gr_spill (1); | |
1433 | if (current_frame_info.reg_save_pr == 0) | |
1434 | { | |
1435 | extra_spill_size += 8; | |
1436 | n_spilled += 1; | |
1437 | } | |
1438 | ||
1439 | /* ??? Mark them all as used so that register renaming and such | |
1440 | are free to use them. */ | |
1441 | for (regno = PR_REG (0); regno <= PR_REG (63); regno++) | |
1442 | regs_ever_live[regno] = 1; | |
c65ebc55 JW |
1443 | } |
1444 | ||
97e242b0 RH |
1445 | /* If we're forced to use st8.spill, we're forced to save and restore |
1446 | ar.unat as well. */ | |
26a110f5 | 1447 | if (spilled_gr_p || cfun->machine->n_varargs) |
97e242b0 RH |
1448 | { |
1449 | SET_HARD_REG_BIT (mask, AR_UNAT_REGNUM); | |
1450 | current_frame_info.reg_save_ar_unat = find_gr_spill (spill_size == 0); | |
1451 | if (current_frame_info.reg_save_ar_unat == 0) | |
1452 | { | |
1453 | extra_spill_size += 8; | |
1454 | n_spilled += 1; | |
1455 | } | |
1456 | } | |
1457 | ||
1458 | if (regs_ever_live[AR_LC_REGNUM]) | |
1459 | { | |
1460 | SET_HARD_REG_BIT (mask, AR_LC_REGNUM); | |
1461 | current_frame_info.reg_save_ar_lc = find_gr_spill (spill_size == 0); | |
1462 | if (current_frame_info.reg_save_ar_lc == 0) | |
1463 | { | |
1464 | extra_spill_size += 8; | |
1465 | n_spilled += 1; | |
1466 | } | |
1467 | } | |
1468 | ||
1469 | /* If we have an odd number of words of pretend arguments written to | |
1470 | the stack, then the FR save area will be unaligned. We round the | |
1471 | size of this area up to keep things 16 byte aligned. */ | |
1472 | if (spilled_fr_p) | |
1473 | pretend_args_size = IA64_STACK_ALIGN (current_function_pretend_args_size); | |
1474 | else | |
1475 | pretend_args_size = current_function_pretend_args_size; | |
1476 | ||
1477 | total_size = (spill_size + extra_spill_size + size + pretend_args_size | |
1478 | + current_function_outgoing_args_size); | |
1479 | total_size = IA64_STACK_ALIGN (total_size); | |
1480 | ||
1481 | /* We always use the 16-byte scratch area provided by the caller, but | |
1482 | if we are a leaf function, there's no one to which we need to provide | |
1483 | a scratch area. */ | |
1484 | if (current_function_is_leaf) | |
1485 | total_size = MAX (0, total_size - 16); | |
1486 | ||
c65ebc55 | 1487 | current_frame_info.total_size = total_size; |
97e242b0 RH |
1488 | current_frame_info.spill_cfa_off = pretend_args_size - 16; |
1489 | current_frame_info.spill_size = spill_size; | |
1490 | current_frame_info.extra_spill_size = extra_spill_size; | |
c65ebc55 | 1491 | COPY_HARD_REG_SET (current_frame_info.mask, mask); |
97e242b0 | 1492 | current_frame_info.n_spilled = n_spilled; |
c65ebc55 | 1493 | current_frame_info.initialized = reload_completed; |
97e242b0 RH |
1494 | } |
1495 | ||
1496 | /* Compute the initial difference between the specified pair of registers. */ | |
1497 | ||
1498 | HOST_WIDE_INT | |
1499 | ia64_initial_elimination_offset (from, to) | |
1500 | int from, to; | |
1501 | { | |
1502 | HOST_WIDE_INT offset; | |
1503 | ||
1504 | ia64_compute_frame_size (get_frame_size ()); | |
1505 | switch (from) | |
1506 | { | |
1507 | case FRAME_POINTER_REGNUM: | |
1508 | if (to == HARD_FRAME_POINTER_REGNUM) | |
1509 | { | |
1510 | if (current_function_is_leaf) | |
1511 | offset = -current_frame_info.total_size; | |
1512 | else | |
1513 | offset = -(current_frame_info.total_size | |
1514 | - current_function_outgoing_args_size - 16); | |
1515 | } | |
1516 | else if (to == STACK_POINTER_REGNUM) | |
1517 | { | |
1518 | if (current_function_is_leaf) | |
1519 | offset = 0; | |
1520 | else | |
1521 | offset = 16 + current_function_outgoing_args_size; | |
1522 | } | |
1523 | else | |
1524 | abort (); | |
1525 | break; | |
c65ebc55 | 1526 | |
97e242b0 RH |
1527 | case ARG_POINTER_REGNUM: |
1528 | /* Arguments start above the 16 byte save area, unless stdarg | |
1529 | in which case we store through the 16 byte save area. */ | |
1530 | if (to == HARD_FRAME_POINTER_REGNUM) | |
1531 | offset = 16 - current_function_pretend_args_size; | |
1532 | else if (to == STACK_POINTER_REGNUM) | |
1533 | offset = (current_frame_info.total_size | |
1534 | + 16 - current_function_pretend_args_size); | |
1535 | else | |
1536 | abort (); | |
1537 | break; | |
1538 | ||
1539 | case RETURN_ADDRESS_POINTER_REGNUM: | |
1540 | offset = 0; | |
1541 | break; | |
1542 | ||
1543 | default: | |
1544 | abort (); | |
1545 | } | |
1546 | ||
1547 | return offset; | |
c65ebc55 JW |
1548 | } |
1549 | ||
97e242b0 RH |
1550 | /* If there are more than a trivial number of register spills, we use |
1551 | two interleaved iterators so that we can get two memory references | |
1552 | per insn group. | |
1553 | ||
1554 | In order to simplify things in the prologue and epilogue expanders, | |
1555 | we use helper functions to fix up the memory references after the | |
1556 | fact with the appropriate offsets to a POST_MODIFY memory mode. | |
1557 | The following data structure tracks the state of the two iterators | |
1558 | while insns are being emitted. */ | |
1559 | ||
1560 | struct spill_fill_data | |
c65ebc55 | 1561 | { |
97e242b0 RH |
1562 | rtx init_after; /* point at which to emit intializations */ |
1563 | rtx init_reg[2]; /* initial base register */ | |
1564 | rtx iter_reg[2]; /* the iterator registers */ | |
1565 | rtx *prev_addr[2]; /* address of last memory use */ | |
1566 | HOST_WIDE_INT prev_off[2]; /* last offset */ | |
1567 | int n_iter; /* number of iterators in use */ | |
1568 | int next_iter; /* next iterator to use */ | |
1569 | unsigned int save_gr_used_mask; | |
1570 | }; | |
1571 | ||
1572 | static struct spill_fill_data spill_fill_data; | |
c65ebc55 | 1573 | |
97e242b0 RH |
1574 | static void |
1575 | setup_spill_pointers (n_spills, init_reg, cfa_off) | |
1576 | int n_spills; | |
1577 | rtx init_reg; | |
1578 | HOST_WIDE_INT cfa_off; | |
1579 | { | |
1580 | int i; | |
1581 | ||
1582 | spill_fill_data.init_after = get_last_insn (); | |
1583 | spill_fill_data.init_reg[0] = init_reg; | |
1584 | spill_fill_data.init_reg[1] = init_reg; | |
1585 | spill_fill_data.prev_addr[0] = NULL; | |
1586 | spill_fill_data.prev_addr[1] = NULL; | |
1587 | spill_fill_data.prev_off[0] = cfa_off; | |
1588 | spill_fill_data.prev_off[1] = cfa_off; | |
1589 | spill_fill_data.next_iter = 0; | |
1590 | spill_fill_data.save_gr_used_mask = current_frame_info.gr_used_mask; | |
1591 | ||
1592 | spill_fill_data.n_iter = 1 + (n_spills > 2); | |
1593 | for (i = 0; i < spill_fill_data.n_iter; ++i) | |
c65ebc55 | 1594 | { |
97e242b0 RH |
1595 | int regno = next_scratch_gr_reg (); |
1596 | spill_fill_data.iter_reg[i] = gen_rtx_REG (DImode, regno); | |
1597 | current_frame_info.gr_used_mask |= 1 << regno; | |
1598 | } | |
1599 | } | |
1600 | ||
1601 | static void | |
1602 | finish_spill_pointers () | |
1603 | { | |
1604 | current_frame_info.gr_used_mask = spill_fill_data.save_gr_used_mask; | |
1605 | } | |
c65ebc55 | 1606 | |
97e242b0 RH |
1607 | static rtx |
1608 | spill_restore_mem (reg, cfa_off) | |
1609 | rtx reg; | |
1610 | HOST_WIDE_INT cfa_off; | |
1611 | { | |
1612 | int iter = spill_fill_data.next_iter; | |
1613 | HOST_WIDE_INT disp = spill_fill_data.prev_off[iter] - cfa_off; | |
1614 | rtx disp_rtx = GEN_INT (disp); | |
1615 | rtx mem; | |
1616 | ||
1617 | if (spill_fill_data.prev_addr[iter]) | |
1618 | { | |
1619 | if (CONST_OK_FOR_N (disp)) | |
1620 | *spill_fill_data.prev_addr[iter] | |
1621 | = gen_rtx_POST_MODIFY (DImode, spill_fill_data.iter_reg[iter], | |
1622 | gen_rtx_PLUS (DImode, | |
1623 | spill_fill_data.iter_reg[iter], | |
1624 | disp_rtx)); | |
c65ebc55 JW |
1625 | else |
1626 | { | |
97e242b0 RH |
1627 | /* ??? Could use register post_modify for loads. */ |
1628 | if (! CONST_OK_FOR_I (disp)) | |
1629 | { | |
1630 | rtx tmp = gen_rtx_REG (DImode, next_scratch_gr_reg ()); | |
1631 | emit_move_insn (tmp, disp_rtx); | |
1632 | disp_rtx = tmp; | |
1633 | } | |
1634 | emit_insn (gen_adddi3 (spill_fill_data.iter_reg[iter], | |
1635 | spill_fill_data.iter_reg[iter], disp_rtx)); | |
c65ebc55 | 1636 | } |
97e242b0 RH |
1637 | } |
1638 | /* Micro-optimization: if we've created a frame pointer, it's at | |
1639 | CFA 0, which may allow the real iterator to be initialized lower, | |
1640 | slightly increasing parallelism. Also, if there are few saves | |
1641 | it may eliminate the iterator entirely. */ | |
1642 | else if (disp == 0 | |
1643 | && spill_fill_data.init_reg[iter] == stack_pointer_rtx | |
1644 | && frame_pointer_needed) | |
1645 | { | |
1646 | mem = gen_rtx_MEM (GET_MODE (reg), hard_frame_pointer_rtx); | |
1647 | MEM_ALIAS_SET (mem) = get_varargs_alias_set (); | |
1648 | return mem; | |
1649 | } | |
1650 | else | |
1651 | { | |
1652 | rtx seq; | |
809d4ef1 | 1653 | |
97e242b0 RH |
1654 | if (disp == 0) |
1655 | seq = gen_movdi (spill_fill_data.iter_reg[iter], | |
1656 | spill_fill_data.init_reg[iter]); | |
1657 | else | |
c65ebc55 | 1658 | { |
97e242b0 RH |
1659 | start_sequence (); |
1660 | ||
1661 | if (! CONST_OK_FOR_I (disp)) | |
c65ebc55 | 1662 | { |
97e242b0 RH |
1663 | rtx tmp = gen_rtx_REG (DImode, next_scratch_gr_reg ()); |
1664 | emit_move_insn (tmp, disp_rtx); | |
1665 | disp_rtx = tmp; | |
c65ebc55 | 1666 | } |
97e242b0 RH |
1667 | |
1668 | emit_insn (gen_adddi3 (spill_fill_data.iter_reg[iter], | |
1669 | spill_fill_data.init_reg[iter], | |
1670 | disp_rtx)); | |
1671 | ||
1672 | seq = gen_sequence (); | |
1673 | end_sequence (); | |
c65ebc55 | 1674 | } |
809d4ef1 | 1675 | |
97e242b0 RH |
1676 | /* Careful for being the first insn in a sequence. */ |
1677 | if (spill_fill_data.init_after) | |
1678 | spill_fill_data.init_after | |
1679 | = emit_insn_after (seq, spill_fill_data.init_after); | |
1680 | else | |
bc08aefe RH |
1681 | { |
1682 | rtx first = get_insns (); | |
1683 | if (first) | |
1684 | spill_fill_data.init_after | |
1685 | = emit_insn_before (seq, first); | |
1686 | else | |
1687 | spill_fill_data.init_after = emit_insn (seq); | |
1688 | } | |
97e242b0 | 1689 | } |
c65ebc55 | 1690 | |
97e242b0 | 1691 | mem = gen_rtx_MEM (GET_MODE (reg), spill_fill_data.iter_reg[iter]); |
c65ebc55 | 1692 | |
97e242b0 RH |
1693 | /* ??? Not all of the spills are for varargs, but some of them are. |
1694 | The rest of the spills belong in an alias set of their own. But | |
1695 | it doesn't actually hurt to include them here. */ | |
1696 | MEM_ALIAS_SET (mem) = get_varargs_alias_set (); | |
809d4ef1 | 1697 | |
97e242b0 RH |
1698 | spill_fill_data.prev_addr[iter] = &XEXP (mem, 0); |
1699 | spill_fill_data.prev_off[iter] = cfa_off; | |
c65ebc55 | 1700 | |
97e242b0 RH |
1701 | if (++iter >= spill_fill_data.n_iter) |
1702 | iter = 0; | |
1703 | spill_fill_data.next_iter = iter; | |
c65ebc55 | 1704 | |
97e242b0 RH |
1705 | return mem; |
1706 | } | |
5527bf14 | 1707 | |
97e242b0 RH |
1708 | static void |
1709 | do_spill (move_fn, reg, cfa_off, frame_reg) | |
870f9ec0 | 1710 | rtx (*move_fn) PARAMS ((rtx, rtx, rtx)); |
97e242b0 RH |
1711 | rtx reg, frame_reg; |
1712 | HOST_WIDE_INT cfa_off; | |
1713 | { | |
1714 | rtx mem, insn; | |
5527bf14 | 1715 | |
97e242b0 | 1716 | mem = spill_restore_mem (reg, cfa_off); |
870f9ec0 | 1717 | insn = emit_insn ((*move_fn) (mem, reg, GEN_INT (cfa_off))); |
5527bf14 | 1718 | |
97e242b0 RH |
1719 | if (frame_reg) |
1720 | { | |
1721 | rtx base; | |
1722 | HOST_WIDE_INT off; | |
1723 | ||
1724 | RTX_FRAME_RELATED_P (insn) = 1; | |
1725 | ||
1726 | /* Don't even pretend that the unwind code can intuit its way | |
1727 | through a pair of interleaved post_modify iterators. Just | |
1728 | provide the correct answer. */ | |
1729 | ||
1730 | if (frame_pointer_needed) | |
1731 | { | |
1732 | base = hard_frame_pointer_rtx; | |
1733 | off = - cfa_off; | |
5527bf14 | 1734 | } |
97e242b0 RH |
1735 | else |
1736 | { | |
1737 | base = stack_pointer_rtx; | |
1738 | off = current_frame_info.total_size - cfa_off; | |
1739 | } | |
1740 | ||
1741 | REG_NOTES (insn) | |
1742 | = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, | |
1743 | gen_rtx_SET (VOIDmode, | |
1744 | gen_rtx_MEM (GET_MODE (reg), | |
1745 | plus_constant (base, off)), | |
1746 | frame_reg), | |
1747 | REG_NOTES (insn)); | |
c65ebc55 JW |
1748 | } |
1749 | } | |
1750 | ||
97e242b0 RH |
1751 | static void |
1752 | do_restore (move_fn, reg, cfa_off) | |
870f9ec0 | 1753 | rtx (*move_fn) PARAMS ((rtx, rtx, rtx)); |
97e242b0 RH |
1754 | rtx reg; |
1755 | HOST_WIDE_INT cfa_off; | |
1756 | { | |
870f9ec0 RH |
1757 | emit_insn ((*move_fn) (reg, spill_restore_mem (reg, cfa_off), |
1758 | GEN_INT (cfa_off))); | |
97e242b0 RH |
1759 | } |
1760 | ||
870f9ec0 RH |
1761 | /* Wrapper functions that discards the CONST_INT spill offset. These |
1762 | exist so that we can give gr_spill/gr_fill the offset they need and | |
1763 | use a consistant function interface. */ | |
1764 | ||
1765 | static rtx | |
1766 | gen_movdi_x (dest, src, offset) | |
1767 | rtx dest, src; | |
1768 | rtx offset ATTRIBUTE_UNUSED; | |
1769 | { | |
1770 | return gen_movdi (dest, src); | |
1771 | } | |
1772 | ||
1773 | static rtx | |
1774 | gen_fr_spill_x (dest, src, offset) | |
1775 | rtx dest, src; | |
1776 | rtx offset ATTRIBUTE_UNUSED; | |
1777 | { | |
1778 | return gen_fr_spill (dest, src); | |
1779 | } | |
1780 | ||
1781 | static rtx | |
1782 | gen_fr_restore_x (dest, src, offset) | |
1783 | rtx dest, src; | |
1784 | rtx offset ATTRIBUTE_UNUSED; | |
1785 | { | |
1786 | return gen_fr_restore (dest, src); | |
1787 | } | |
c65ebc55 JW |
1788 | |
1789 | /* Called after register allocation to add any instructions needed for the | |
1790 | prologue. Using a prologue insn is favored compared to putting all of the | |
1791 | instructions in the FUNCTION_PROLOGUE macro, since it allows the scheduler | |
1792 | to intermix instructions with the saves of the caller saved registers. In | |
1793 | some cases, it might be necessary to emit a barrier instruction as the last | |
1794 | insn to prevent such scheduling. | |
1795 | ||
1796 | Also any insns generated here should have RTX_FRAME_RELATED_P(insn) = 1 | |
97e242b0 RH |
1797 | so that the debug info generation code can handle them properly. |
1798 | ||
1799 | The register save area is layed out like so: | |
1800 | cfa+16 | |
1801 | [ varargs spill area ] | |
1802 | [ fr register spill area ] | |
1803 | [ br register spill area ] | |
1804 | [ ar register spill area ] | |
1805 | [ pr register spill area ] | |
1806 | [ gr register spill area ] */ | |
c65ebc55 JW |
1807 | |
1808 | /* ??? Get inefficient code when the frame size is larger than can fit in an | |
1809 | adds instruction. */ | |
1810 | ||
c65ebc55 JW |
1811 | void |
1812 | ia64_expand_prologue () | |
1813 | { | |
97e242b0 RH |
1814 | rtx insn, ar_pfs_save_reg, ar_unat_save_reg; |
1815 | int i, epilogue_p, regno, alt_regno, cfa_off, n_varargs; | |
1816 | rtx reg, alt_reg; | |
1817 | ||
1818 | ia64_compute_frame_size (get_frame_size ()); | |
1819 | last_scratch_gr_reg = 15; | |
1820 | ||
1821 | /* If there is no epilogue, then we don't need some prologue insns. | |
1822 | We need to avoid emitting the dead prologue insns, because flow | |
1823 | will complain about them. */ | |
c65ebc55 JW |
1824 | if (optimize) |
1825 | { | |
97e242b0 RH |
1826 | edge e; |
1827 | ||
c65ebc55 JW |
1828 | for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next) |
1829 | if ((e->flags & EDGE_FAKE) == 0 | |
1830 | && (e->flags & EDGE_FALLTHRU) != 0) | |
1831 | break; | |
1832 | epilogue_p = (e != NULL); | |
1833 | } | |
1834 | else | |
1835 | epilogue_p = 1; | |
1836 | ||
97e242b0 RH |
1837 | /* Set the local, input, and output register names. We need to do this |
1838 | for GNU libc, which creates crti.S/crtn.S by splitting initfini.c in | |
1839 | half. If we use in/loc/out register names, then we get assembler errors | |
1840 | in crtn.S because there is no alloc insn or regstk directive in there. */ | |
1841 | if (! TARGET_REG_NAMES) | |
1842 | { | |
1843 | int inputs = current_frame_info.n_input_regs; | |
1844 | int locals = current_frame_info.n_local_regs; | |
1845 | int outputs = current_frame_info.n_output_regs; | |
1846 | ||
1847 | for (i = 0; i < inputs; i++) | |
1848 | reg_names[IN_REG (i)] = ia64_reg_numbers[i]; | |
1849 | for (i = 0; i < locals; i++) | |
1850 | reg_names[LOC_REG (i)] = ia64_reg_numbers[inputs + i]; | |
1851 | for (i = 0; i < outputs; i++) | |
1852 | reg_names[OUT_REG (i)] = ia64_reg_numbers[inputs + locals + i]; | |
1853 | } | |
c65ebc55 | 1854 | |
97e242b0 RH |
1855 | /* Set the frame pointer register name. The regnum is logically loc79, |
1856 | but of course we'll not have allocated that many locals. Rather than | |
1857 | worrying about renumbering the existing rtxs, we adjust the name. */ | |
1858 | if (current_frame_info.reg_fp) | |
1859 | { | |
1860 | const char *tmp = reg_names[HARD_FRAME_POINTER_REGNUM]; | |
1861 | reg_names[HARD_FRAME_POINTER_REGNUM] | |
1862 | = reg_names[current_frame_info.reg_fp]; | |
1863 | reg_names[current_frame_info.reg_fp] = tmp; | |
1864 | } | |
c65ebc55 | 1865 | |
97e242b0 RH |
1866 | /* Fix up the return address placeholder. */ |
1867 | /* ??? We can fail if __builtin_return_address is used, and we didn't | |
1868 | allocate a register in which to save b0. I can't think of a way to | |
1869 | eliminate RETURN_ADDRESS_POINTER_REGNUM to a local register and | |
1870 | then be sure that I got the right one. Further, reload doesn't seem | |
1871 | to care if an eliminable register isn't used, and "eliminates" it | |
1872 | anyway. */ | |
1873 | if (regs_ever_live[RETURN_ADDRESS_POINTER_REGNUM] | |
1874 | && current_frame_info.reg_save_b0 != 0) | |
1875 | XINT (return_address_pointer_rtx, 0) = current_frame_info.reg_save_b0; | |
1876 | ||
1877 | /* We don't need an alloc instruction if we've used no outputs or locals. */ | |
1878 | if (current_frame_info.n_local_regs == 0 | |
2ed4af6f RH |
1879 | && current_frame_info.n_output_regs == 0 |
1880 | && current_frame_info.n_input_regs <= current_function_args_info.words) | |
97e242b0 RH |
1881 | { |
1882 | /* If there is no alloc, but there are input registers used, then we | |
1883 | need a .regstk directive. */ | |
1884 | current_frame_info.need_regstk = (TARGET_REG_NAMES != 0); | |
1885 | ar_pfs_save_reg = NULL_RTX; | |
1886 | } | |
1887 | else | |
1888 | { | |
1889 | current_frame_info.need_regstk = 0; | |
c65ebc55 | 1890 | |
97e242b0 RH |
1891 | if (current_frame_info.reg_save_ar_pfs) |
1892 | regno = current_frame_info.reg_save_ar_pfs; | |
1893 | else | |
1894 | regno = next_scratch_gr_reg (); | |
1895 | ar_pfs_save_reg = gen_rtx_REG (DImode, regno); | |
1896 | ||
1897 | insn = emit_insn (gen_alloc (ar_pfs_save_reg, | |
1898 | GEN_INT (current_frame_info.n_input_regs), | |
1899 | GEN_INT (current_frame_info.n_local_regs), | |
1900 | GEN_INT (current_frame_info.n_output_regs), | |
1901 | GEN_INT (current_frame_info.n_rotate_regs))); | |
1902 | RTX_FRAME_RELATED_P (insn) = (current_frame_info.reg_save_ar_pfs != 0); | |
1903 | } | |
c65ebc55 | 1904 | |
97e242b0 | 1905 | /* Set up frame pointer, stack pointer, and spill iterators. */ |
c65ebc55 | 1906 | |
26a110f5 | 1907 | n_varargs = cfun->machine->n_varargs; |
97e242b0 RH |
1908 | setup_spill_pointers (current_frame_info.n_spilled + n_varargs, |
1909 | stack_pointer_rtx, 0); | |
c65ebc55 | 1910 | |
97e242b0 RH |
1911 | if (frame_pointer_needed) |
1912 | { | |
1913 | insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); | |
1914 | RTX_FRAME_RELATED_P (insn) = 1; | |
1915 | } | |
c65ebc55 | 1916 | |
97e242b0 RH |
1917 | if (current_frame_info.total_size != 0) |
1918 | { | |
1919 | rtx frame_size_rtx = GEN_INT (- current_frame_info.total_size); | |
1920 | rtx offset; | |
c65ebc55 | 1921 | |
97e242b0 RH |
1922 | if (CONST_OK_FOR_I (- current_frame_info.total_size)) |
1923 | offset = frame_size_rtx; | |
1924 | else | |
1925 | { | |
1926 | regno = next_scratch_gr_reg (); | |
1927 | offset = gen_rtx_REG (DImode, regno); | |
1928 | emit_move_insn (offset, frame_size_rtx); | |
1929 | } | |
c65ebc55 | 1930 | |
97e242b0 RH |
1931 | insn = emit_insn (gen_adddi3 (stack_pointer_rtx, |
1932 | stack_pointer_rtx, offset)); | |
c65ebc55 | 1933 | |
97e242b0 RH |
1934 | if (! frame_pointer_needed) |
1935 | { | |
1936 | RTX_FRAME_RELATED_P (insn) = 1; | |
1937 | if (GET_CODE (offset) != CONST_INT) | |
1938 | { | |
1939 | REG_NOTES (insn) | |
1940 | = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, | |
1941 | gen_rtx_SET (VOIDmode, | |
1942 | stack_pointer_rtx, | |
1943 | gen_rtx_PLUS (DImode, | |
1944 | stack_pointer_rtx, | |
1945 | frame_size_rtx)), | |
1946 | REG_NOTES (insn)); | |
1947 | } | |
1948 | } | |
c65ebc55 | 1949 | |
97e242b0 RH |
1950 | /* ??? At this point we must generate a magic insn that appears to |
1951 | modify the stack pointer, the frame pointer, and all spill | |
1952 | iterators. This would allow the most scheduling freedom. For | |
1953 | now, just hard stop. */ | |
1954 | emit_insn (gen_blockage ()); | |
1955 | } | |
c65ebc55 | 1956 | |
97e242b0 RH |
1957 | /* Must copy out ar.unat before doing any integer spills. */ |
1958 | if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM)) | |
c65ebc55 | 1959 | { |
97e242b0 RH |
1960 | if (current_frame_info.reg_save_ar_unat) |
1961 | ar_unat_save_reg | |
1962 | = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_unat); | |
1963 | else | |
c65ebc55 | 1964 | { |
97e242b0 RH |
1965 | alt_regno = next_scratch_gr_reg (); |
1966 | ar_unat_save_reg = gen_rtx_REG (DImode, alt_regno); | |
1967 | current_frame_info.gr_used_mask |= 1 << alt_regno; | |
c65ebc55 | 1968 | } |
c65ebc55 | 1969 | |
97e242b0 RH |
1970 | reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM); |
1971 | insn = emit_move_insn (ar_unat_save_reg, reg); | |
1972 | RTX_FRAME_RELATED_P (insn) = (current_frame_info.reg_save_ar_unat != 0); | |
1973 | ||
1974 | /* Even if we're not going to generate an epilogue, we still | |
1975 | need to save the register so that EH works. */ | |
1976 | if (! epilogue_p && current_frame_info.reg_save_ar_unat) | |
1977 | emit_insn (gen_rtx_USE (VOIDmode, ar_unat_save_reg)); | |
c65ebc55 JW |
1978 | } |
1979 | else | |
97e242b0 RH |
1980 | ar_unat_save_reg = NULL_RTX; |
1981 | ||
1982 | /* Spill all varargs registers. Do this before spilling any GR registers, | |
1983 | since we want the UNAT bits for the GR registers to override the UNAT | |
1984 | bits from varargs, which we don't care about. */ | |
c65ebc55 | 1985 | |
97e242b0 RH |
1986 | cfa_off = -16; |
1987 | for (regno = GR_ARG_FIRST + 7; n_varargs > 0; --n_varargs, --regno) | |
c65ebc55 | 1988 | { |
97e242b0 | 1989 | reg = gen_rtx_REG (DImode, regno); |
870f9ec0 | 1990 | do_spill (gen_gr_spill, reg, cfa_off += 8, NULL_RTX); |
c65ebc55 | 1991 | } |
c65ebc55 | 1992 | |
97e242b0 RH |
1993 | /* Locate the bottom of the register save area. */ |
1994 | cfa_off = (current_frame_info.spill_cfa_off | |
1995 | + current_frame_info.spill_size | |
1996 | + current_frame_info.extra_spill_size); | |
c65ebc55 | 1997 | |
97e242b0 RH |
1998 | /* Save the predicate register block either in a register or in memory. */ |
1999 | if (TEST_HARD_REG_BIT (current_frame_info.mask, PR_REG (0))) | |
2000 | { | |
2001 | reg = gen_rtx_REG (DImode, PR_REG (0)); | |
2002 | if (current_frame_info.reg_save_pr != 0) | |
1ff5b671 | 2003 | { |
97e242b0 RH |
2004 | alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_pr); |
2005 | insn = emit_move_insn (alt_reg, reg); | |
1ff5b671 | 2006 | |
97e242b0 RH |
2007 | /* ??? Denote pr spill/fill by a DImode move that modifies all |
2008 | 64 hard registers. */ | |
1ff5b671 | 2009 | RTX_FRAME_RELATED_P (insn) = 1; |
97e242b0 RH |
2010 | REG_NOTES (insn) |
2011 | = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, | |
2012 | gen_rtx_SET (VOIDmode, alt_reg, reg), | |
2013 | REG_NOTES (insn)); | |
46327bc5 | 2014 | |
97e242b0 RH |
2015 | /* Even if we're not going to generate an epilogue, we still |
2016 | need to save the register so that EH works. */ | |
2017 | if (! epilogue_p) | |
2018 | emit_insn (gen_rtx_USE (VOIDmode, alt_reg)); | |
1ff5b671 JW |
2019 | } |
2020 | else | |
97e242b0 RH |
2021 | { |
2022 | alt_regno = next_scratch_gr_reg (); | |
2023 | alt_reg = gen_rtx_REG (DImode, alt_regno); | |
2024 | insn = emit_move_insn (alt_reg, reg); | |
870f9ec0 | 2025 | do_spill (gen_movdi_x, alt_reg, cfa_off, reg); |
97e242b0 RH |
2026 | cfa_off -= 8; |
2027 | } | |
c65ebc55 JW |
2028 | } |
2029 | ||
97e242b0 RH |
2030 | /* Handle AR regs in numerical order. All of them get special handling. */ |
2031 | if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM) | |
2032 | && current_frame_info.reg_save_ar_unat == 0) | |
c65ebc55 | 2033 | { |
97e242b0 | 2034 | reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM); |
870f9ec0 | 2035 | do_spill (gen_movdi_x, ar_unat_save_reg, cfa_off, reg); |
97e242b0 | 2036 | cfa_off -= 8; |
c65ebc55 | 2037 | } |
97e242b0 RH |
2038 | |
2039 | /* The alloc insn already copied ar.pfs into a general register. The | |
2040 | only thing we have to do now is copy that register to a stack slot | |
2041 | if we'd not allocated a local register for the job. */ | |
2042 | if (current_frame_info.reg_save_ar_pfs == 0 | |
2043 | && ! current_function_is_leaf) | |
c65ebc55 | 2044 | { |
97e242b0 | 2045 | reg = gen_rtx_REG (DImode, AR_PFS_REGNUM); |
870f9ec0 | 2046 | do_spill (gen_movdi_x, ar_pfs_save_reg, cfa_off, reg); |
97e242b0 RH |
2047 | cfa_off -= 8; |
2048 | } | |
2049 | ||
2050 | if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_LC_REGNUM)) | |
2051 | { | |
2052 | reg = gen_rtx_REG (DImode, AR_LC_REGNUM); | |
2053 | if (current_frame_info.reg_save_ar_lc != 0) | |
2054 | { | |
2055 | alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_lc); | |
2056 | insn = emit_move_insn (alt_reg, reg); | |
2057 | RTX_FRAME_RELATED_P (insn) = 1; | |
2058 | ||
2059 | /* Even if we're not going to generate an epilogue, we still | |
2060 | need to save the register so that EH works. */ | |
2061 | if (! epilogue_p) | |
2062 | emit_insn (gen_rtx_USE (VOIDmode, alt_reg)); | |
2063 | } | |
c65ebc55 JW |
2064 | else |
2065 | { | |
97e242b0 RH |
2066 | alt_regno = next_scratch_gr_reg (); |
2067 | alt_reg = gen_rtx_REG (DImode, alt_regno); | |
2068 | emit_move_insn (alt_reg, reg); | |
870f9ec0 | 2069 | do_spill (gen_movdi_x, alt_reg, cfa_off, reg); |
97e242b0 RH |
2070 | cfa_off -= 8; |
2071 | } | |
2072 | } | |
2073 | ||
2074 | /* We should now be at the base of the gr/br/fr spill area. */ | |
2075 | if (cfa_off != (current_frame_info.spill_cfa_off | |
2076 | + current_frame_info.spill_size)) | |
2077 | abort (); | |
2078 | ||
2079 | /* Spill all general registers. */ | |
2080 | for (regno = GR_REG (1); regno <= GR_REG (31); ++regno) | |
2081 | if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) | |
2082 | { | |
2083 | reg = gen_rtx_REG (DImode, regno); | |
2084 | do_spill (gen_gr_spill, reg, cfa_off, reg); | |
2085 | cfa_off -= 8; | |
2086 | } | |
2087 | ||
2088 | /* Handle BR0 specially -- it may be getting stored permanently in | |
2089 | some GR register. */ | |
2090 | if (TEST_HARD_REG_BIT (current_frame_info.mask, BR_REG (0))) | |
2091 | { | |
2092 | reg = gen_rtx_REG (DImode, BR_REG (0)); | |
2093 | if (current_frame_info.reg_save_b0 != 0) | |
2094 | { | |
2095 | alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_b0); | |
2096 | insn = emit_move_insn (alt_reg, reg); | |
c65ebc55 | 2097 | RTX_FRAME_RELATED_P (insn) = 1; |
97e242b0 RH |
2098 | |
2099 | /* Even if we're not going to generate an epilogue, we still | |
2100 | need to save the register so that EH works. */ | |
2101 | if (! epilogue_p) | |
2102 | emit_insn (gen_rtx_USE (VOIDmode, alt_reg)); | |
c65ebc55 | 2103 | } |
c65ebc55 | 2104 | else |
97e242b0 RH |
2105 | { |
2106 | alt_regno = next_scratch_gr_reg (); | |
2107 | alt_reg = gen_rtx_REG (DImode, alt_regno); | |
2108 | emit_move_insn (alt_reg, reg); | |
870f9ec0 | 2109 | do_spill (gen_movdi_x, alt_reg, cfa_off, reg); |
97e242b0 RH |
2110 | cfa_off -= 8; |
2111 | } | |
c65ebc55 JW |
2112 | } |
2113 | ||
97e242b0 RH |
2114 | /* Spill the rest of the BR registers. */ |
2115 | for (regno = BR_REG (1); regno <= BR_REG (7); ++regno) | |
2116 | if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) | |
2117 | { | |
2118 | alt_regno = next_scratch_gr_reg (); | |
2119 | alt_reg = gen_rtx_REG (DImode, alt_regno); | |
2120 | reg = gen_rtx_REG (DImode, regno); | |
2121 | emit_move_insn (alt_reg, reg); | |
870f9ec0 | 2122 | do_spill (gen_movdi_x, alt_reg, cfa_off, reg); |
97e242b0 RH |
2123 | cfa_off -= 8; |
2124 | } | |
2125 | ||
2126 | /* Align the frame and spill all FR registers. */ | |
2127 | for (regno = FR_REG (2); regno <= FR_REG (127); ++regno) | |
2128 | if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) | |
2129 | { | |
2130 | if (cfa_off & 15) | |
2131 | abort (); | |
3f622353 | 2132 | reg = gen_rtx_REG (TFmode, regno); |
870f9ec0 | 2133 | do_spill (gen_fr_spill_x, reg, cfa_off, reg); |
97e242b0 RH |
2134 | cfa_off -= 16; |
2135 | } | |
2136 | ||
2137 | if (cfa_off != current_frame_info.spill_cfa_off) | |
2138 | abort (); | |
2139 | ||
2140 | finish_spill_pointers (); | |
c65ebc55 JW |
2141 | } |
2142 | ||
2143 | /* Called after register allocation to add any instructions needed for the | |
2144 | epilogue. Using a epilogue insn is favored compared to putting all of the | |
2145 | instructions in the FUNCTION_PROLOGUE macro, since it allows the scheduler | |
2146 | to intermix instructions with the saves of the caller saved registers. In | |
2147 | some cases, it might be necessary to emit a barrier instruction as the last | |
2148 | insn to prevent such scheduling. */ | |
2149 | ||
2150 | void | |
2ed4af6f RH |
2151 | ia64_expand_epilogue (sibcall_p) |
2152 | int sibcall_p; | |
c65ebc55 | 2153 | { |
97e242b0 RH |
2154 | rtx insn, reg, alt_reg, ar_unat_save_reg; |
2155 | int regno, alt_regno, cfa_off; | |
2156 | ||
2157 | ia64_compute_frame_size (get_frame_size ()); | |
2158 | ||
2159 | /* If there is a frame pointer, then we use it instead of the stack | |
2160 | pointer, so that the stack pointer does not need to be valid when | |
2161 | the epilogue starts. See EXIT_IGNORE_STACK. */ | |
2162 | if (frame_pointer_needed) | |
2163 | setup_spill_pointers (current_frame_info.n_spilled, | |
2164 | hard_frame_pointer_rtx, 0); | |
2165 | else | |
2166 | setup_spill_pointers (current_frame_info.n_spilled, stack_pointer_rtx, | |
2167 | current_frame_info.total_size); | |
2168 | ||
2169 | if (current_frame_info.total_size != 0) | |
2170 | { | |
2171 | /* ??? At this point we must generate a magic insn that appears to | |
2172 | modify the spill iterators and the frame pointer. This would | |
2173 | allow the most scheduling freedom. For now, just hard stop. */ | |
2174 | emit_insn (gen_blockage ()); | |
2175 | } | |
2176 | ||
2177 | /* Locate the bottom of the register save area. */ | |
2178 | cfa_off = (current_frame_info.spill_cfa_off | |
2179 | + current_frame_info.spill_size | |
2180 | + current_frame_info.extra_spill_size); | |
2181 | ||
2182 | /* Restore the predicate registers. */ | |
2183 | if (TEST_HARD_REG_BIT (current_frame_info.mask, PR_REG (0))) | |
2184 | { | |
2185 | if (current_frame_info.reg_save_pr != 0) | |
2186 | alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_pr); | |
2187 | else | |
2188 | { | |
2189 | alt_regno = next_scratch_gr_reg (); | |
2190 | alt_reg = gen_rtx_REG (DImode, alt_regno); | |
870f9ec0 | 2191 | do_restore (gen_movdi_x, alt_reg, cfa_off); |
97e242b0 RH |
2192 | cfa_off -= 8; |
2193 | } | |
2194 | reg = gen_rtx_REG (DImode, PR_REG (0)); | |
2195 | emit_move_insn (reg, alt_reg); | |
2196 | } | |
2197 | ||
2198 | /* Restore the application registers. */ | |
2199 | ||
2200 | /* Load the saved unat from the stack, but do not restore it until | |
2201 | after the GRs have been restored. */ | |
2202 | if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM)) | |
2203 | { | |
2204 | if (current_frame_info.reg_save_ar_unat != 0) | |
2205 | ar_unat_save_reg | |
2206 | = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_unat); | |
2207 | else | |
2208 | { | |
2209 | alt_regno = next_scratch_gr_reg (); | |
2210 | ar_unat_save_reg = gen_rtx_REG (DImode, alt_regno); | |
2211 | current_frame_info.gr_used_mask |= 1 << alt_regno; | |
870f9ec0 | 2212 | do_restore (gen_movdi_x, ar_unat_save_reg, cfa_off); |
97e242b0 RH |
2213 | cfa_off -= 8; |
2214 | } | |
2215 | } | |
2216 | else | |
2217 | ar_unat_save_reg = NULL_RTX; | |
2218 | ||
2219 | if (current_frame_info.reg_save_ar_pfs != 0) | |
2220 | { | |
2221 | alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_pfs); | |
2222 | reg = gen_rtx_REG (DImode, AR_PFS_REGNUM); | |
2223 | emit_move_insn (reg, alt_reg); | |
2224 | } | |
2225 | else if (! current_function_is_leaf) | |
c65ebc55 | 2226 | { |
97e242b0 RH |
2227 | alt_regno = next_scratch_gr_reg (); |
2228 | alt_reg = gen_rtx_REG (DImode, alt_regno); | |
870f9ec0 | 2229 | do_restore (gen_movdi_x, alt_reg, cfa_off); |
97e242b0 RH |
2230 | cfa_off -= 8; |
2231 | reg = gen_rtx_REG (DImode, AR_PFS_REGNUM); | |
2232 | emit_move_insn (reg, alt_reg); | |
2233 | } | |
2234 | ||
2235 | if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_LC_REGNUM)) | |
2236 | { | |
2237 | if (current_frame_info.reg_save_ar_lc != 0) | |
2238 | alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_lc); | |
2239 | else | |
2240 | { | |
2241 | alt_regno = next_scratch_gr_reg (); | |
2242 | alt_reg = gen_rtx_REG (DImode, alt_regno); | |
870f9ec0 | 2243 | do_restore (gen_movdi_x, alt_reg, cfa_off); |
97e242b0 RH |
2244 | cfa_off -= 8; |
2245 | } | |
2246 | reg = gen_rtx_REG (DImode, AR_LC_REGNUM); | |
2247 | emit_move_insn (reg, alt_reg); | |
2248 | } | |
2249 | ||
2250 | /* We should now be at the base of the gr/br/fr spill area. */ | |
2251 | if (cfa_off != (current_frame_info.spill_cfa_off | |
2252 | + current_frame_info.spill_size)) | |
2253 | abort (); | |
2254 | ||
2255 | /* Restore all general registers. */ | |
2256 | for (regno = GR_REG (1); regno <= GR_REG (31); ++regno) | |
2257 | if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) | |
0c96007e | 2258 | { |
97e242b0 RH |
2259 | reg = gen_rtx_REG (DImode, regno); |
2260 | do_restore (gen_gr_restore, reg, cfa_off); | |
2261 | cfa_off -= 8; | |
0c96007e | 2262 | } |
97e242b0 RH |
2263 | |
2264 | /* Restore the branch registers. Handle B0 specially, as it may | |
2265 | have gotten stored in some GR register. */ | |
2266 | if (TEST_HARD_REG_BIT (current_frame_info.mask, BR_REG (0))) | |
2267 | { | |
2268 | if (current_frame_info.reg_save_b0 != 0) | |
2269 | alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_b0); | |
2270 | else | |
2271 | { | |
2272 | alt_regno = next_scratch_gr_reg (); | |
2273 | alt_reg = gen_rtx_REG (DImode, alt_regno); | |
870f9ec0 | 2274 | do_restore (gen_movdi_x, alt_reg, cfa_off); |
97e242b0 RH |
2275 | cfa_off -= 8; |
2276 | } | |
2277 | reg = gen_rtx_REG (DImode, BR_REG (0)); | |
2278 | emit_move_insn (reg, alt_reg); | |
2279 | } | |
2280 | ||
2281 | for (regno = BR_REG (1); regno <= BR_REG (7); ++regno) | |
2282 | if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) | |
0c96007e | 2283 | { |
97e242b0 RH |
2284 | alt_regno = next_scratch_gr_reg (); |
2285 | alt_reg = gen_rtx_REG (DImode, alt_regno); | |
870f9ec0 | 2286 | do_restore (gen_movdi_x, alt_reg, cfa_off); |
97e242b0 RH |
2287 | cfa_off -= 8; |
2288 | reg = gen_rtx_REG (DImode, regno); | |
2289 | emit_move_insn (reg, alt_reg); | |
2290 | } | |
c65ebc55 | 2291 | |
97e242b0 RH |
2292 | /* Restore floating point registers. */ |
2293 | for (regno = FR_REG (2); regno <= FR_REG (127); ++regno) | |
2294 | if (TEST_HARD_REG_BIT (current_frame_info.mask, regno)) | |
2295 | { | |
2296 | if (cfa_off & 15) | |
2297 | abort (); | |
3f622353 | 2298 | reg = gen_rtx_REG (TFmode, regno); |
870f9ec0 | 2299 | do_restore (gen_fr_restore_x, reg, cfa_off); |
97e242b0 | 2300 | cfa_off -= 16; |
0c96007e | 2301 | } |
97e242b0 RH |
2302 | |
2303 | /* Restore ar.unat for real. */ | |
2304 | if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM)) | |
2305 | { | |
2306 | reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM); | |
2307 | emit_move_insn (reg, ar_unat_save_reg); | |
c65ebc55 JW |
2308 | } |
2309 | ||
97e242b0 RH |
2310 | if (cfa_off != current_frame_info.spill_cfa_off) |
2311 | abort (); | |
2312 | ||
2313 | finish_spill_pointers (); | |
c65ebc55 | 2314 | |
97e242b0 RH |
2315 | if (current_frame_info.total_size || cfun->machine->ia64_eh_epilogue_sp) |
2316 | { | |
2317 | /* ??? At this point we must generate a magic insn that appears to | |
2318 | modify the spill iterators, the stack pointer, and the frame | |
2319 | pointer. This would allow the most scheduling freedom. For now, | |
2320 | just hard stop. */ | |
2321 | emit_insn (gen_blockage ()); | |
2322 | } | |
c65ebc55 | 2323 | |
97e242b0 RH |
2324 | if (cfun->machine->ia64_eh_epilogue_sp) |
2325 | emit_move_insn (stack_pointer_rtx, cfun->machine->ia64_eh_epilogue_sp); | |
2326 | else if (frame_pointer_needed) | |
2327 | { | |
2328 | insn = emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); | |
2329 | RTX_FRAME_RELATED_P (insn) = 1; | |
2330 | } | |
2331 | else if (current_frame_info.total_size) | |
0c96007e | 2332 | { |
97e242b0 RH |
2333 | rtx offset, frame_size_rtx; |
2334 | ||
2335 | frame_size_rtx = GEN_INT (current_frame_info.total_size); | |
2336 | if (CONST_OK_FOR_I (current_frame_info.total_size)) | |
2337 | offset = frame_size_rtx; | |
2338 | else | |
2339 | { | |
2340 | regno = next_scratch_gr_reg (); | |
2341 | offset = gen_rtx_REG (DImode, regno); | |
2342 | emit_move_insn (offset, frame_size_rtx); | |
2343 | } | |
2344 | ||
2345 | insn = emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, | |
2346 | offset)); | |
2347 | ||
2348 | RTX_FRAME_RELATED_P (insn) = 1; | |
2349 | if (GET_CODE (offset) != CONST_INT) | |
2350 | { | |
2351 | REG_NOTES (insn) | |
2352 | = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, | |
2353 | gen_rtx_SET (VOIDmode, | |
2354 | stack_pointer_rtx, | |
2355 | gen_rtx_PLUS (DImode, | |
2356 | stack_pointer_rtx, | |
2357 | frame_size_rtx)), | |
2358 | REG_NOTES (insn)); | |
2359 | } | |
0c96007e | 2360 | } |
97e242b0 RH |
2361 | |
2362 | if (cfun->machine->ia64_eh_epilogue_bsp) | |
2363 | emit_insn (gen_set_bsp (cfun->machine->ia64_eh_epilogue_bsp)); | |
2364 | ||
2ed4af6f RH |
2365 | if (! sibcall_p) |
2366 | emit_jump_insn (gen_return_internal (gen_rtx_REG (DImode, BR_REG (0)))); | |
c65ebc55 JW |
2367 | } |
2368 | ||
97e242b0 RH |
2369 | /* Return 1 if br.ret can do all the work required to return from a |
2370 | function. */ | |
2371 | ||
2372 | int | |
2373 | ia64_direct_return () | |
2374 | { | |
2375 | if (reload_completed && ! frame_pointer_needed) | |
2376 | { | |
2377 | ia64_compute_frame_size (get_frame_size ()); | |
2378 | ||
2379 | return (current_frame_info.total_size == 0 | |
2380 | && current_frame_info.n_spilled == 0 | |
2381 | && current_frame_info.reg_save_b0 == 0 | |
2382 | && current_frame_info.reg_save_pr == 0 | |
2383 | && current_frame_info.reg_save_ar_pfs == 0 | |
2384 | && current_frame_info.reg_save_ar_unat == 0 | |
2385 | && current_frame_info.reg_save_ar_lc == 0); | |
2386 | } | |
2387 | return 0; | |
2388 | } | |
2389 | ||
10c9f189 RH |
2390 | int |
2391 | ia64_hard_regno_rename_ok (from, to) | |
2392 | int from; | |
2393 | int to; | |
2394 | { | |
2395 | /* Don't clobber any of the registers we reserved for the prologue. */ | |
2396 | if (to == current_frame_info.reg_fp | |
2397 | || to == current_frame_info.reg_save_b0 | |
2398 | || to == current_frame_info.reg_save_pr | |
2399 | || to == current_frame_info.reg_save_ar_pfs | |
2400 | || to == current_frame_info.reg_save_ar_unat | |
2401 | || to == current_frame_info.reg_save_ar_lc) | |
2402 | return 0; | |
2403 | ||
2404 | /* Don't use output registers outside the register frame. */ | |
2405 | if (OUT_REGNO_P (to) && to >= OUT_REG (current_frame_info.n_output_regs)) | |
2406 | return 0; | |
2407 | ||
2408 | /* Retain even/oddness on predicate register pairs. */ | |
2409 | if (PR_REGNO_P (from) && PR_REGNO_P (to)) | |
2410 | return (from & 1) == (to & 1); | |
2411 | ||
2412 | return 1; | |
2413 | } | |
2414 | ||
c65ebc55 JW |
2415 | /* Emit the function prologue. */ |
2416 | ||
2417 | void | |
2418 | ia64_function_prologue (file, size) | |
2419 | FILE *file; | |
fd7c34b0 | 2420 | int size ATTRIBUTE_UNUSED; |
c65ebc55 | 2421 | { |
97e242b0 RH |
2422 | int mask, grsave, grsave_prev; |
2423 | ||
2424 | if (current_frame_info.need_regstk) | |
2425 | fprintf (file, "\t.regstk %d, %d, %d, %d\n", | |
2426 | current_frame_info.n_input_regs, | |
2427 | current_frame_info.n_local_regs, | |
2428 | current_frame_info.n_output_regs, | |
2429 | current_frame_info.n_rotate_regs); | |
c65ebc55 | 2430 | |
0c96007e AM |
2431 | if (!flag_unwind_tables && (!flag_exceptions || exceptions_via_longjmp)) |
2432 | return; | |
2433 | ||
97e242b0 | 2434 | /* Emit the .prologue directive. */ |
809d4ef1 | 2435 | |
97e242b0 RH |
2436 | mask = 0; |
2437 | grsave = grsave_prev = 0; | |
2438 | if (current_frame_info.reg_save_b0 != 0) | |
0c96007e | 2439 | { |
97e242b0 RH |
2440 | mask |= 8; |
2441 | grsave = grsave_prev = current_frame_info.reg_save_b0; | |
2442 | } | |
2443 | if (current_frame_info.reg_save_ar_pfs != 0 | |
2444 | && (grsave_prev == 0 | |
2445 | || current_frame_info.reg_save_ar_pfs == grsave_prev + 1)) | |
2446 | { | |
2447 | mask |= 4; | |
2448 | if (grsave_prev == 0) | |
2449 | grsave = current_frame_info.reg_save_ar_pfs; | |
2450 | grsave_prev = current_frame_info.reg_save_ar_pfs; | |
0c96007e | 2451 | } |
97e242b0 RH |
2452 | if (current_frame_info.reg_fp != 0 |
2453 | && (grsave_prev == 0 | |
2454 | || current_frame_info.reg_fp == grsave_prev + 1)) | |
2455 | { | |
2456 | mask |= 2; | |
2457 | if (grsave_prev == 0) | |
2458 | grsave = HARD_FRAME_POINTER_REGNUM; | |
2459 | grsave_prev = current_frame_info.reg_fp; | |
2460 | } | |
2461 | if (current_frame_info.reg_save_pr != 0 | |
2462 | && (grsave_prev == 0 | |
2463 | || current_frame_info.reg_save_pr == grsave_prev + 1)) | |
2464 | { | |
2465 | mask |= 1; | |
2466 | if (grsave_prev == 0) | |
2467 | grsave = current_frame_info.reg_save_pr; | |
2468 | } | |
2469 | ||
2470 | if (mask) | |
2471 | fprintf (file, "\t.prologue %d, %d\n", mask, | |
2472 | ia64_dbx_register_number (grsave)); | |
2473 | else | |
2474 | fputs ("\t.prologue\n", file); | |
2475 | ||
2476 | /* Emit a .spill directive, if necessary, to relocate the base of | |
2477 | the register spill area. */ | |
2478 | if (current_frame_info.spill_cfa_off != -16) | |
2479 | fprintf (file, "\t.spill %ld\n", | |
2480 | (long) (current_frame_info.spill_cfa_off | |
2481 | + current_frame_info.spill_size)); | |
c65ebc55 JW |
2482 | } |
2483 | ||
0186257f JW |
2484 | /* Emit the .body directive at the scheduled end of the prologue. */ |
2485 | ||
2486 | void | |
2487 | ia64_output_end_prologue (file) | |
2488 | FILE *file; | |
2489 | { | |
2490 | if (!flag_unwind_tables && (!flag_exceptions || exceptions_via_longjmp)) | |
2491 | return; | |
2492 | ||
2493 | fputs ("\t.body\n", file); | |
2494 | } | |
2495 | ||
c65ebc55 JW |
2496 | /* Emit the function epilogue. */ |
2497 | ||
2498 | void | |
2499 | ia64_function_epilogue (file, size) | |
fd7c34b0 RH |
2500 | FILE *file ATTRIBUTE_UNUSED; |
2501 | int size ATTRIBUTE_UNUSED; | |
c65ebc55 | 2502 | { |
8a959ea5 RH |
2503 | int i; |
2504 | ||
97e242b0 RH |
2505 | /* Reset from the function's potential modifications. */ |
2506 | XINT (return_address_pointer_rtx, 0) = RETURN_ADDRESS_POINTER_REGNUM; | |
c65ebc55 | 2507 | |
97e242b0 RH |
2508 | if (current_frame_info.reg_fp) |
2509 | { | |
2510 | const char *tmp = reg_names[HARD_FRAME_POINTER_REGNUM]; | |
2511 | reg_names[HARD_FRAME_POINTER_REGNUM] | |
2512 | = reg_names[current_frame_info.reg_fp]; | |
2513 | reg_names[current_frame_info.reg_fp] = tmp; | |
2514 | } | |
2515 | if (! TARGET_REG_NAMES) | |
2516 | { | |
97e242b0 RH |
2517 | for (i = 0; i < current_frame_info.n_input_regs; i++) |
2518 | reg_names[IN_REG (i)] = ia64_input_reg_names[i]; | |
2519 | for (i = 0; i < current_frame_info.n_local_regs; i++) | |
2520 | reg_names[LOC_REG (i)] = ia64_local_reg_names[i]; | |
2521 | for (i = 0; i < current_frame_info.n_output_regs; i++) | |
2522 | reg_names[OUT_REG (i)] = ia64_output_reg_names[i]; | |
2523 | } | |
8a959ea5 | 2524 | |
97e242b0 RH |
2525 | current_frame_info.initialized = 0; |
2526 | } | |
c65ebc55 JW |
2527 | |
2528 | int | |
97e242b0 RH |
2529 | ia64_dbx_register_number (regno) |
2530 | int regno; | |
c65ebc55 | 2531 | { |
97e242b0 RH |
2532 | /* In ia64_expand_prologue we quite literally renamed the frame pointer |
2533 | from its home at loc79 to something inside the register frame. We | |
2534 | must perform the same renumbering here for the debug info. */ | |
2535 | if (current_frame_info.reg_fp) | |
2536 | { | |
2537 | if (regno == HARD_FRAME_POINTER_REGNUM) | |
2538 | regno = current_frame_info.reg_fp; | |
2539 | else if (regno == current_frame_info.reg_fp) | |
2540 | regno = HARD_FRAME_POINTER_REGNUM; | |
2541 | } | |
2542 | ||
2543 | if (IN_REGNO_P (regno)) | |
2544 | return 32 + regno - IN_REG (0); | |
2545 | else if (LOC_REGNO_P (regno)) | |
2546 | return 32 + current_frame_info.n_input_regs + regno - LOC_REG (0); | |
2547 | else if (OUT_REGNO_P (regno)) | |
2548 | return (32 + current_frame_info.n_input_regs | |
2549 | + current_frame_info.n_local_regs + regno - OUT_REG (0)); | |
2550 | else | |
2551 | return regno; | |
c65ebc55 JW |
2552 | } |
2553 | ||
97e242b0 RH |
2554 | void |
2555 | ia64_initialize_trampoline (addr, fnaddr, static_chain) | |
2556 | rtx addr, fnaddr, static_chain; | |
2557 | { | |
2558 | rtx addr_reg, eight = GEN_INT (8); | |
2559 | ||
2560 | /* Load up our iterator. */ | |
2561 | addr_reg = gen_reg_rtx (Pmode); | |
2562 | emit_move_insn (addr_reg, addr); | |
2563 | ||
2564 | /* The first two words are the fake descriptor: | |
2565 | __ia64_trampoline, ADDR+16. */ | |
2566 | emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), | |
2567 | gen_rtx_SYMBOL_REF (Pmode, "__ia64_trampoline")); | |
2568 | emit_insn (gen_adddi3 (addr_reg, addr_reg, eight)); | |
2569 | ||
2570 | emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), | |
2571 | copy_to_reg (plus_constant (addr, 16))); | |
2572 | emit_insn (gen_adddi3 (addr_reg, addr_reg, eight)); | |
2573 | ||
2574 | /* The third word is the target descriptor. */ | |
2575 | emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), fnaddr); | |
2576 | emit_insn (gen_adddi3 (addr_reg, addr_reg, eight)); | |
2577 | ||
2578 | /* The fourth word is the static chain. */ | |
2579 | emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), static_chain); | |
2580 | } | |
c65ebc55 JW |
2581 | \f |
2582 | /* Do any needed setup for a variadic function. CUM has not been updated | |
97e242b0 RH |
2583 | for the last named argument which has type TYPE and mode MODE. |
2584 | ||
2585 | We generate the actual spill instructions during prologue generation. */ | |
2586 | ||
c65ebc55 JW |
2587 | void |
2588 | ia64_setup_incoming_varargs (cum, int_mode, type, pretend_size, second_time) | |
2589 | CUMULATIVE_ARGS cum; | |
26a110f5 RH |
2590 | int int_mode; |
2591 | tree type; | |
c65ebc55 | 2592 | int * pretend_size; |
97e242b0 | 2593 | int second_time ATTRIBUTE_UNUSED; |
c65ebc55 | 2594 | { |
26a110f5 RH |
2595 | /* If this is a stdarg function, then skip the current argument. */ |
2596 | if (! current_function_varargs) | |
2597 | ia64_function_arg_advance (&cum, int_mode, type, 1); | |
c65ebc55 JW |
2598 | |
2599 | if (cum.words < MAX_ARGUMENT_SLOTS) | |
26a110f5 RH |
2600 | { |
2601 | int n = MAX_ARGUMENT_SLOTS - cum.words; | |
2602 | *pretend_size = n * UNITS_PER_WORD; | |
2603 | cfun->machine->n_varargs = n; | |
2604 | } | |
c65ebc55 JW |
2605 | } |
2606 | ||
2607 | /* Check whether TYPE is a homogeneous floating point aggregate. If | |
2608 | it is, return the mode of the floating point type that appears | |
2609 | in all leafs. If it is not, return VOIDmode. | |
2610 | ||
2611 | An aggregate is a homogeneous floating point aggregate is if all | |
2612 | fields/elements in it have the same floating point type (e.g, | |
2613 | SFmode). 128-bit quad-precision floats are excluded. */ | |
2614 | ||
2615 | static enum machine_mode | |
2616 | hfa_element_mode (type, nested) | |
2617 | tree type; | |
2618 | int nested; | |
2619 | { | |
2620 | enum machine_mode element_mode = VOIDmode; | |
2621 | enum machine_mode mode; | |
2622 | enum tree_code code = TREE_CODE (type); | |
2623 | int know_element_mode = 0; | |
2624 | tree t; | |
2625 | ||
2626 | switch (code) | |
2627 | { | |
2628 | case VOID_TYPE: case INTEGER_TYPE: case ENUMERAL_TYPE: | |
2629 | case BOOLEAN_TYPE: case CHAR_TYPE: case POINTER_TYPE: | |
2630 | case OFFSET_TYPE: case REFERENCE_TYPE: case METHOD_TYPE: | |
2631 | case FILE_TYPE: case SET_TYPE: case LANG_TYPE: | |
2632 | case FUNCTION_TYPE: | |
2633 | return VOIDmode; | |
2634 | ||
2635 | /* Fortran complex types are supposed to be HFAs, so we need to handle | |
2636 | gcc's COMPLEX_TYPEs as HFAs. We need to exclude the integral complex | |
2637 | types though. */ | |
2638 | case COMPLEX_TYPE: | |
2639 | if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT) | |
2640 | return mode_for_size (GET_MODE_UNIT_SIZE (TYPE_MODE (type)) | |
2641 | * BITS_PER_UNIT, MODE_FLOAT, 0); | |
2642 | else | |
2643 | return VOIDmode; | |
2644 | ||
2645 | case REAL_TYPE: | |
2646 | /* We want to return VOIDmode for raw REAL_TYPEs, but the actual | |
2647 | mode if this is contained within an aggregate. */ | |
2648 | if (nested) | |
2649 | return TYPE_MODE (type); | |
2650 | else | |
2651 | return VOIDmode; | |
2652 | ||
2653 | case ARRAY_TYPE: | |
2654 | return TYPE_MODE (TREE_TYPE (type)); | |
2655 | ||
2656 | case RECORD_TYPE: | |
2657 | case UNION_TYPE: | |
2658 | case QUAL_UNION_TYPE: | |
2659 | for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t)) | |
2660 | { | |
2661 | if (TREE_CODE (t) != FIELD_DECL) | |
2662 | continue; | |
2663 | ||
2664 | mode = hfa_element_mode (TREE_TYPE (t), 1); | |
2665 | if (know_element_mode) | |
2666 | { | |
2667 | if (mode != element_mode) | |
2668 | return VOIDmode; | |
2669 | } | |
2670 | else if (GET_MODE_CLASS (mode) != MODE_FLOAT) | |
2671 | return VOIDmode; | |
2672 | else | |
2673 | { | |
2674 | know_element_mode = 1; | |
2675 | element_mode = mode; | |
2676 | } | |
2677 | } | |
2678 | return element_mode; | |
2679 | ||
2680 | default: | |
2681 | /* If we reach here, we probably have some front-end specific type | |
2682 | that the backend doesn't know about. This can happen via the | |
2683 | aggregate_value_p call in init_function_start. All we can do is | |
2684 | ignore unknown tree types. */ | |
2685 | return VOIDmode; | |
2686 | } | |
2687 | ||
2688 | return VOIDmode; | |
2689 | } | |
2690 | ||
2691 | /* Return rtx for register where argument is passed, or zero if it is passed | |
2692 | on the stack. */ | |
2693 | ||
2694 | /* ??? 128-bit quad-precision floats are always passed in general | |
2695 | registers. */ | |
2696 | ||
2697 | rtx | |
2698 | ia64_function_arg (cum, mode, type, named, incoming) | |
2699 | CUMULATIVE_ARGS *cum; | |
2700 | enum machine_mode mode; | |
2701 | tree type; | |
2702 | int named; | |
2703 | int incoming; | |
2704 | { | |
2705 | int basereg = (incoming ? GR_ARG_FIRST : AR_ARG_FIRST); | |
2706 | int words = (((mode == BLKmode ? int_size_in_bytes (type) | |
2707 | : GET_MODE_SIZE (mode)) + UNITS_PER_WORD - 1) | |
2708 | / UNITS_PER_WORD); | |
2709 | int offset = 0; | |
2710 | enum machine_mode hfa_mode = VOIDmode; | |
2711 | ||
f9f45ccb JW |
2712 | /* Integer and float arguments larger than 8 bytes start at the next even |
2713 | boundary. Aggregates larger than 8 bytes start at the next even boundary | |
7d17b34d JW |
2714 | if the aggregate has 16 byte alignment. Net effect is that types with |
2715 | alignment greater than 8 start at the next even boundary. */ | |
f9f45ccb JW |
2716 | /* ??? The ABI does not specify how to handle aggregates with alignment from |
2717 | 9 to 15 bytes, or greater than 16. We handle them all as if they had | |
2718 | 16 byte alignment. Such aggregates can occur only if gcc extensions are | |
2719 | used. */ | |
7d17b34d JW |
2720 | if ((type ? (TYPE_ALIGN (type) > 8 * BITS_PER_UNIT) |
2721 | : (words > 1)) | |
2722 | && (cum->words & 1)) | |
c65ebc55 JW |
2723 | offset = 1; |
2724 | ||
2725 | /* If all argument slots are used, then it must go on the stack. */ | |
2726 | if (cum->words + offset >= MAX_ARGUMENT_SLOTS) | |
2727 | return 0; | |
2728 | ||
2729 | /* Check for and handle homogeneous FP aggregates. */ | |
2730 | if (type) | |
2731 | hfa_mode = hfa_element_mode (type, 0); | |
2732 | ||
2733 | /* Unnamed prototyped hfas are passed as usual. Named prototyped hfas | |
2734 | and unprototyped hfas are passed specially. */ | |
2735 | if (hfa_mode != VOIDmode && (! cum->prototype || named)) | |
2736 | { | |
2737 | rtx loc[16]; | |
2738 | int i = 0; | |
2739 | int fp_regs = cum->fp_regs; | |
2740 | int int_regs = cum->words + offset; | |
2741 | int hfa_size = GET_MODE_SIZE (hfa_mode); | |
2742 | int byte_size; | |
2743 | int args_byte_size; | |
2744 | ||
2745 | /* If prototyped, pass it in FR regs then GR regs. | |
2746 | If not prototyped, pass it in both FR and GR regs. | |
2747 | ||
2748 | If this is an SFmode aggregate, then it is possible to run out of | |
2749 | FR regs while GR regs are still left. In that case, we pass the | |
2750 | remaining part in the GR regs. */ | |
2751 | ||
2752 | /* Fill the FP regs. We do this always. We stop if we reach the end | |
2753 | of the argument, the last FP register, or the last argument slot. */ | |
2754 | ||
2755 | byte_size = ((mode == BLKmode) | |
2756 | ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); | |
2757 | args_byte_size = int_regs * UNITS_PER_WORD; | |
2758 | offset = 0; | |
2759 | for (; (offset < byte_size && fp_regs < MAX_ARGUMENT_SLOTS | |
2760 | && args_byte_size < (MAX_ARGUMENT_SLOTS * UNITS_PER_WORD)); i++) | |
2761 | { | |
2762 | loc[i] = gen_rtx_EXPR_LIST (VOIDmode, | |
2763 | gen_rtx_REG (hfa_mode, (FR_ARG_FIRST | |
2764 | + fp_regs)), | |
2765 | GEN_INT (offset)); | |
c65ebc55 JW |
2766 | offset += hfa_size; |
2767 | args_byte_size += hfa_size; | |
2768 | fp_regs++; | |
2769 | } | |
2770 | ||
2771 | /* If no prototype, then the whole thing must go in GR regs. */ | |
2772 | if (! cum->prototype) | |
2773 | offset = 0; | |
2774 | /* If this is an SFmode aggregate, then we might have some left over | |
2775 | that needs to go in GR regs. */ | |
2776 | else if (byte_size != offset) | |
2777 | int_regs += offset / UNITS_PER_WORD; | |
2778 | ||
2779 | /* Fill in the GR regs. We must use DImode here, not the hfa mode. */ | |
2780 | ||
2781 | for (; offset < byte_size && int_regs < MAX_ARGUMENT_SLOTS; i++) | |
2782 | { | |
2783 | enum machine_mode gr_mode = DImode; | |
2784 | ||
2785 | /* If we have an odd 4 byte hunk because we ran out of FR regs, | |
2786 | then this goes in a GR reg left adjusted/little endian, right | |
2787 | adjusted/big endian. */ | |
2788 | /* ??? Currently this is handled wrong, because 4-byte hunks are | |
2789 | always right adjusted/little endian. */ | |
2790 | if (offset & 0x4) | |
2791 | gr_mode = SImode; | |
2792 | /* If we have an even 4 byte hunk because the aggregate is a | |
2793 | multiple of 4 bytes in size, then this goes in a GR reg right | |
2794 | adjusted/little endian. */ | |
2795 | else if (byte_size - offset == 4) | |
2796 | gr_mode = SImode; | |
2797 | ||
2798 | loc[i] = gen_rtx_EXPR_LIST (VOIDmode, | |
2799 | gen_rtx_REG (gr_mode, (basereg | |
2800 | + int_regs)), | |
2801 | GEN_INT (offset)); | |
2802 | offset += GET_MODE_SIZE (gr_mode); | |
2803 | int_regs++; | |
2804 | } | |
2805 | ||
2806 | /* If we ended up using just one location, just return that one loc. */ | |
2807 | if (i == 1) | |
2808 | return XEXP (loc[0], 0); | |
2809 | else | |
2810 | return gen_rtx_PARALLEL (mode, gen_rtvec_v (i, loc)); | |
2811 | } | |
2812 | ||
2813 | /* Integral and aggregates go in general registers. If we have run out of | |
2814 | FR registers, then FP values must also go in general registers. This can | |
2815 | happen when we have a SFmode HFA. */ | |
2816 | else if (! FLOAT_MODE_P (mode) || cum->fp_regs == MAX_ARGUMENT_SLOTS) | |
2817 | return gen_rtx_REG (mode, basereg + cum->words + offset); | |
2818 | ||
2819 | /* If there is a prototype, then FP values go in a FR register when | |
2820 | named, and in a GR registeer when unnamed. */ | |
2821 | else if (cum->prototype) | |
2822 | { | |
2823 | if (! named) | |
2824 | return gen_rtx_REG (mode, basereg + cum->words + offset); | |
2825 | else | |
2826 | return gen_rtx_REG (mode, FR_ARG_FIRST + cum->fp_regs); | |
2827 | } | |
2828 | /* If there is no prototype, then FP values go in both FR and GR | |
2829 | registers. */ | |
2830 | else | |
2831 | { | |
2832 | rtx fp_reg = gen_rtx_EXPR_LIST (VOIDmode, | |
2833 | gen_rtx_REG (mode, (FR_ARG_FIRST | |
2834 | + cum->fp_regs)), | |
2835 | const0_rtx); | |
2836 | rtx gr_reg = gen_rtx_EXPR_LIST (VOIDmode, | |
2837 | gen_rtx_REG (mode, | |
2838 | (basereg + cum->words | |
2839 | + offset)), | |
2840 | const0_rtx); | |
809d4ef1 | 2841 | |
c65ebc55 JW |
2842 | return gen_rtx_PARALLEL (mode, gen_rtvec (2, fp_reg, gr_reg)); |
2843 | } | |
2844 | } | |
2845 | ||
2846 | /* Return number of words, at the beginning of the argument, that must be | |
2847 | put in registers. 0 is the argument is entirely in registers or entirely | |
2848 | in memory. */ | |
2849 | ||
2850 | int | |
2851 | ia64_function_arg_partial_nregs (cum, mode, type, named) | |
2852 | CUMULATIVE_ARGS *cum; | |
2853 | enum machine_mode mode; | |
2854 | tree type; | |
fd7c34b0 | 2855 | int named ATTRIBUTE_UNUSED; |
c65ebc55 JW |
2856 | { |
2857 | int words = (((mode == BLKmode ? int_size_in_bytes (type) | |
2858 | : GET_MODE_SIZE (mode)) + UNITS_PER_WORD - 1) | |
2859 | / UNITS_PER_WORD); | |
2860 | int offset = 0; | |
2861 | ||
7d17b34d JW |
2862 | /* Arguments with alignment larger than 8 bytes start at the next even |
2863 | boundary. */ | |
2864 | if ((type ? (TYPE_ALIGN (type) > 8 * BITS_PER_UNIT) | |
2865 | : (words > 1)) | |
2866 | && (cum->words & 1)) | |
c65ebc55 JW |
2867 | offset = 1; |
2868 | ||
2869 | /* If all argument slots are used, then it must go on the stack. */ | |
2870 | if (cum->words + offset >= MAX_ARGUMENT_SLOTS) | |
2871 | return 0; | |
2872 | ||
2873 | /* It doesn't matter whether the argument goes in FR or GR regs. If | |
2874 | it fits within the 8 argument slots, then it goes entirely in | |
2875 | registers. If it extends past the last argument slot, then the rest | |
2876 | goes on the stack. */ | |
2877 | ||
2878 | if (words + cum->words + offset <= MAX_ARGUMENT_SLOTS) | |
2879 | return 0; | |
2880 | ||
2881 | return MAX_ARGUMENT_SLOTS - cum->words - offset; | |
2882 | } | |
2883 | ||
2884 | /* Update CUM to point after this argument. This is patterned after | |
2885 | ia64_function_arg. */ | |
2886 | ||
2887 | void | |
2888 | ia64_function_arg_advance (cum, mode, type, named) | |
2889 | CUMULATIVE_ARGS *cum; | |
2890 | enum machine_mode mode; | |
2891 | tree type; | |
2892 | int named; | |
2893 | { | |
2894 | int words = (((mode == BLKmode ? int_size_in_bytes (type) | |
2895 | : GET_MODE_SIZE (mode)) + UNITS_PER_WORD - 1) | |
2896 | / UNITS_PER_WORD); | |
2897 | int offset = 0; | |
2898 | enum machine_mode hfa_mode = VOIDmode; | |
2899 | ||
2900 | /* If all arg slots are already full, then there is nothing to do. */ | |
2901 | if (cum->words >= MAX_ARGUMENT_SLOTS) | |
2902 | return; | |
2903 | ||
7d17b34d JW |
2904 | /* Arguments with alignment larger than 8 bytes start at the next even |
2905 | boundary. */ | |
2906 | if ((type ? (TYPE_ALIGN (type) > 8 * BITS_PER_UNIT) | |
2907 | : (words > 1)) | |
2908 | && (cum->words & 1)) | |
c65ebc55 JW |
2909 | offset = 1; |
2910 | ||
2911 | cum->words += words + offset; | |
2912 | ||
2913 | /* Check for and handle homogeneous FP aggregates. */ | |
2914 | if (type) | |
2915 | hfa_mode = hfa_element_mode (type, 0); | |
2916 | ||
2917 | /* Unnamed prototyped hfas are passed as usual. Named prototyped hfas | |
2918 | and unprototyped hfas are passed specially. */ | |
2919 | if (hfa_mode != VOIDmode && (! cum->prototype || named)) | |
2920 | { | |
2921 | int fp_regs = cum->fp_regs; | |
2922 | /* This is the original value of cum->words + offset. */ | |
2923 | int int_regs = cum->words - words; | |
2924 | int hfa_size = GET_MODE_SIZE (hfa_mode); | |
2925 | int byte_size; | |
2926 | int args_byte_size; | |
2927 | ||
2928 | /* If prototyped, pass it in FR regs then GR regs. | |
2929 | If not prototyped, pass it in both FR and GR regs. | |
2930 | ||
2931 | If this is an SFmode aggregate, then it is possible to run out of | |
2932 | FR regs while GR regs are still left. In that case, we pass the | |
2933 | remaining part in the GR regs. */ | |
2934 | ||
2935 | /* Fill the FP regs. We do this always. We stop if we reach the end | |
2936 | of the argument, the last FP register, or the last argument slot. */ | |
2937 | ||
2938 | byte_size = ((mode == BLKmode) | |
2939 | ? int_size_in_bytes (type) : GET_MODE_SIZE (mode)); | |
2940 | args_byte_size = int_regs * UNITS_PER_WORD; | |
2941 | offset = 0; | |
2942 | for (; (offset < byte_size && fp_regs < MAX_ARGUMENT_SLOTS | |
2943 | && args_byte_size < (MAX_ARGUMENT_SLOTS * UNITS_PER_WORD));) | |
2944 | { | |
c65ebc55 JW |
2945 | offset += hfa_size; |
2946 | args_byte_size += hfa_size; | |
2947 | fp_regs++; | |
2948 | } | |
2949 | ||
2950 | cum->fp_regs = fp_regs; | |
2951 | } | |
2952 | ||
2953 | /* Integral and aggregates go in general registers. If we have run out of | |
2954 | FR registers, then FP values must also go in general registers. This can | |
2955 | happen when we have a SFmode HFA. */ | |
2956 | else if (! FLOAT_MODE_P (mode) || cum->fp_regs == MAX_ARGUMENT_SLOTS) | |
2957 | return; | |
2958 | ||
2959 | /* If there is a prototype, then FP values go in a FR register when | |
2960 | named, and in a GR registeer when unnamed. */ | |
2961 | else if (cum->prototype) | |
2962 | { | |
2963 | if (! named) | |
2964 | return; | |
2965 | else | |
2966 | /* ??? Complex types should not reach here. */ | |
2967 | cum->fp_regs += (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT ? 2 : 1); | |
2968 | } | |
2969 | /* If there is no prototype, then FP values go in both FR and GR | |
2970 | registers. */ | |
2971 | else | |
2972 | /* ??? Complex types should not reach here. */ | |
2973 | cum->fp_regs += (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT ? 2 : 1); | |
2974 | ||
2975 | return; | |
2976 | } | |
2977 | \f | |
2978 | /* Implement va_start. */ | |
2979 | ||
2980 | void | |
2981 | ia64_va_start (stdarg_p, valist, nextarg) | |
2982 | int stdarg_p; | |
2983 | tree valist; | |
2984 | rtx nextarg; | |
2985 | { | |
2986 | int arg_words; | |
2987 | int ofs; | |
2988 | ||
2989 | arg_words = current_function_args_info.words; | |
2990 | ||
2991 | if (stdarg_p) | |
2992 | ofs = 0; | |
2993 | else | |
2994 | ofs = (arg_words >= MAX_ARGUMENT_SLOTS ? -UNITS_PER_WORD : 0); | |
2995 | ||
2996 | nextarg = plus_constant (nextarg, ofs); | |
2997 | std_expand_builtin_va_start (1, valist, nextarg); | |
2998 | } | |
2999 | ||
3000 | /* Implement va_arg. */ | |
3001 | ||
3002 | rtx | |
3003 | ia64_va_arg (valist, type) | |
3004 | tree valist, type; | |
3005 | { | |
c65ebc55 JW |
3006 | tree t; |
3007 | ||
7d17b34d JW |
3008 | /* Arguments with alignment larger than 8 bytes start at the next even |
3009 | boundary. */ | |
3010 | if (TYPE_ALIGN (type) > 8 * BITS_PER_UNIT) | |
c65ebc55 JW |
3011 | { |
3012 | t = build (PLUS_EXPR, TREE_TYPE (valist), valist, | |
3013 | build_int_2 (2 * UNITS_PER_WORD - 1, 0)); | |
809d4ef1 | 3014 | t = build (BIT_AND_EXPR, TREE_TYPE (t), t, |
c65ebc55 JW |
3015 | build_int_2 (-2 * UNITS_PER_WORD, -1)); |
3016 | t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t); | |
3017 | TREE_SIDE_EFFECTS (t) = 1; | |
3018 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
3019 | } | |
3020 | ||
3021 | return std_expand_builtin_va_arg (valist, type); | |
3022 | } | |
3023 | \f | |
3024 | /* Return 1 if function return value returned in memory. Return 0 if it is | |
3025 | in a register. */ | |
3026 | ||
3027 | int | |
3028 | ia64_return_in_memory (valtype) | |
3029 | tree valtype; | |
3030 | { | |
3031 | enum machine_mode mode; | |
3032 | enum machine_mode hfa_mode; | |
3033 | int byte_size; | |
3034 | ||
3035 | mode = TYPE_MODE (valtype); | |
3036 | byte_size = ((mode == BLKmode) | |
3037 | ? int_size_in_bytes (valtype) : GET_MODE_SIZE (mode)); | |
3038 | ||
3039 | /* Hfa's with up to 8 elements are returned in the FP argument registers. */ | |
3040 | ||
3041 | hfa_mode = hfa_element_mode (valtype, 0); | |
3042 | if (hfa_mode != VOIDmode) | |
3043 | { | |
3044 | int hfa_size = GET_MODE_SIZE (hfa_mode); | |
3045 | ||
c65ebc55 JW |
3046 | if (byte_size / hfa_size > MAX_ARGUMENT_SLOTS) |
3047 | return 1; | |
3048 | else | |
3049 | return 0; | |
3050 | } | |
3051 | ||
3052 | else if (byte_size > UNITS_PER_WORD * MAX_INT_RETURN_SLOTS) | |
3053 | return 1; | |
3054 | else | |
3055 | return 0; | |
3056 | } | |
3057 | ||
3058 | /* Return rtx for register that holds the function return value. */ | |
3059 | ||
3060 | rtx | |
3061 | ia64_function_value (valtype, func) | |
3062 | tree valtype; | |
fd7c34b0 | 3063 | tree func ATTRIBUTE_UNUSED; |
c65ebc55 JW |
3064 | { |
3065 | enum machine_mode mode; | |
3066 | enum machine_mode hfa_mode; | |
3067 | ||
3068 | mode = TYPE_MODE (valtype); | |
3069 | hfa_mode = hfa_element_mode (valtype, 0); | |
3070 | ||
3071 | if (hfa_mode != VOIDmode) | |
3072 | { | |
3073 | rtx loc[8]; | |
3074 | int i; | |
3075 | int hfa_size; | |
3076 | int byte_size; | |
3077 | int offset; | |
3078 | ||
3079 | hfa_size = GET_MODE_SIZE (hfa_mode); | |
3080 | byte_size = ((mode == BLKmode) | |
3081 | ? int_size_in_bytes (valtype) : GET_MODE_SIZE (mode)); | |
3082 | offset = 0; | |
3083 | for (i = 0; offset < byte_size; i++) | |
3084 | { | |
3085 | loc[i] = gen_rtx_EXPR_LIST (VOIDmode, | |
3086 | gen_rtx_REG (hfa_mode, FR_ARG_FIRST + i), | |
3087 | GEN_INT (offset)); | |
c65ebc55 JW |
3088 | offset += hfa_size; |
3089 | } | |
3090 | ||
3091 | if (i == 1) | |
3092 | return XEXP (loc[0], 0); | |
3093 | else | |
3094 | return gen_rtx_PARALLEL (mode, gen_rtvec_v (i, loc)); | |
3095 | } | |
3096 | else if (FLOAT_TYPE_P (valtype)) | |
3097 | return gen_rtx_REG (mode, FR_ARG_FIRST); | |
3098 | else | |
3099 | return gen_rtx_REG (mode, GR_RET_FIRST); | |
3100 | } | |
3101 | ||
3102 | /* Print a memory address as an operand to reference that memory location. */ | |
3103 | ||
3104 | /* ??? Do we need this? It gets used only for 'a' operands. We could perhaps | |
3105 | also call this from ia64_print_operand for memory addresses. */ | |
3106 | ||
3107 | void | |
3108 | ia64_print_operand_address (stream, address) | |
fd7c34b0 RH |
3109 | FILE * stream ATTRIBUTE_UNUSED; |
3110 | rtx address ATTRIBUTE_UNUSED; | |
c65ebc55 JW |
3111 | { |
3112 | } | |
3113 | ||
3114 | /* Print an operand to a assembler instruction. | |
3115 | B Work arounds for hardware bugs. | |
3116 | C Swap and print a comparison operator. | |
3117 | D Print an FP comparison operator. | |
3118 | E Print 32 - constant, for SImode shifts as extract. | |
66db6b45 | 3119 | e Print 64 - constant, for DImode rotates. |
c65ebc55 JW |
3120 | F A floating point constant 0.0 emitted as f0, or 1.0 emitted as f1, or |
3121 | a floating point register emitted normally. | |
3122 | I Invert a predicate register by adding 1. | |
e5bde68a | 3123 | J Select the proper predicate register for a condition. |
6b6c1201 | 3124 | j Select the inverse predicate register for a condition. |
c65ebc55 JW |
3125 | O Append .acq for volatile load. |
3126 | P Postincrement of a MEM. | |
3127 | Q Append .rel for volatile store. | |
3128 | S Shift amount for shladd instruction. | |
3129 | T Print an 8-bit sign extended number (K) as a 32-bit unsigned number | |
3130 | for Intel assembler. | |
3131 | U Print an 8-bit sign extended number (K) as a 64-bit unsigned number | |
3132 | for Intel assembler. | |
3133 | r Print register name, or constant 0 as r0. HP compatibility for | |
3134 | Linux kernel. */ | |
3135 | void | |
3136 | ia64_print_operand (file, x, code) | |
3137 | FILE * file; | |
3138 | rtx x; | |
3139 | int code; | |
3140 | { | |
e57b9d65 RH |
3141 | const char *str; |
3142 | ||
c65ebc55 JW |
3143 | switch (code) |
3144 | { | |
c65ebc55 JW |
3145 | case 0: |
3146 | /* Handled below. */ | |
3147 | break; | |
809d4ef1 | 3148 | |
c65ebc55 JW |
3149 | case 'B': |
3150 | if (TARGET_A_STEP) | |
3151 | fputs (" ;; nop 0 ;; nop 0 ;;", file); | |
3152 | return; | |
3153 | ||
3154 | case 'C': | |
3155 | { | |
3156 | enum rtx_code c = swap_condition (GET_CODE (x)); | |
3157 | fputs (GET_RTX_NAME (c), file); | |
3158 | return; | |
3159 | } | |
3160 | ||
3161 | case 'D': | |
e57b9d65 RH |
3162 | switch (GET_CODE (x)) |
3163 | { | |
3164 | case NE: | |
3165 | str = "neq"; | |
3166 | break; | |
3167 | case UNORDERED: | |
3168 | str = "unord"; | |
3169 | break; | |
3170 | case ORDERED: | |
3171 | str = "ord"; | |
3172 | break; | |
3173 | default: | |
3174 | str = GET_RTX_NAME (GET_CODE (x)); | |
3175 | break; | |
3176 | } | |
3177 | fputs (str, file); | |
c65ebc55 JW |
3178 | return; |
3179 | ||
3180 | case 'E': | |
3181 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, 32 - INTVAL (x)); | |
3182 | return; | |
3183 | ||
66db6b45 RH |
3184 | case 'e': |
3185 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, 64 - INTVAL (x)); | |
3186 | return; | |
3187 | ||
c65ebc55 JW |
3188 | case 'F': |
3189 | if (x == CONST0_RTX (GET_MODE (x))) | |
e57b9d65 | 3190 | str = reg_names [FR_REG (0)]; |
c65ebc55 | 3191 | else if (x == CONST1_RTX (GET_MODE (x))) |
e57b9d65 | 3192 | str = reg_names [FR_REG (1)]; |
c65ebc55 | 3193 | else if (GET_CODE (x) == REG) |
e57b9d65 | 3194 | str = reg_names [REGNO (x)]; |
c65ebc55 JW |
3195 | else |
3196 | abort (); | |
e57b9d65 | 3197 | fputs (str, file); |
c65ebc55 JW |
3198 | return; |
3199 | ||
3200 | case 'I': | |
3201 | fputs (reg_names [REGNO (x) + 1], file); | |
3202 | return; | |
3203 | ||
e5bde68a | 3204 | case 'J': |
6b6c1201 RH |
3205 | case 'j': |
3206 | { | |
3207 | unsigned int regno = REGNO (XEXP (x, 0)); | |
3208 | if (GET_CODE (x) == EQ) | |
3209 | regno += 1; | |
3210 | if (code == 'j') | |
3211 | regno ^= 1; | |
3212 | fputs (reg_names [regno], file); | |
3213 | } | |
e5bde68a RH |
3214 | return; |
3215 | ||
c65ebc55 JW |
3216 | case 'O': |
3217 | if (MEM_VOLATILE_P (x)) | |
3218 | fputs(".acq", file); | |
3219 | return; | |
3220 | ||
3221 | case 'P': | |
3222 | { | |
4b983fdc | 3223 | HOST_WIDE_INT value; |
c65ebc55 | 3224 | |
4b983fdc RH |
3225 | switch (GET_CODE (XEXP (x, 0))) |
3226 | { | |
3227 | default: | |
3228 | return; | |
3229 | ||
3230 | case POST_MODIFY: | |
3231 | x = XEXP (XEXP (XEXP (x, 0), 1), 1); | |
3232 | if (GET_CODE (x) == CONST_INT) | |
08012cda | 3233 | value = INTVAL (x); |
4b983fdc RH |
3234 | else if (GET_CODE (x) == REG) |
3235 | { | |
08012cda | 3236 | fprintf (file, ", %s", reg_names[REGNO (x)]); |
4b983fdc RH |
3237 | return; |
3238 | } | |
3239 | else | |
3240 | abort (); | |
3241 | break; | |
c65ebc55 | 3242 | |
4b983fdc RH |
3243 | case POST_INC: |
3244 | value = GET_MODE_SIZE (GET_MODE (x)); | |
4b983fdc | 3245 | break; |
c65ebc55 | 3246 | |
4b983fdc | 3247 | case POST_DEC: |
08012cda | 3248 | value = - (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (x)); |
4b983fdc RH |
3249 | break; |
3250 | } | |
809d4ef1 | 3251 | |
4b983fdc RH |
3252 | putc (',', file); |
3253 | putc (' ', file); | |
3254 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, value); | |
c65ebc55 JW |
3255 | return; |
3256 | } | |
3257 | ||
3258 | case 'Q': | |
3259 | if (MEM_VOLATILE_P (x)) | |
3260 | fputs(".rel", file); | |
3261 | return; | |
3262 | ||
3263 | case 'S': | |
809d4ef1 | 3264 | fprintf (file, "%d", exact_log2 (INTVAL (x))); |
c65ebc55 JW |
3265 | return; |
3266 | ||
3267 | case 'T': | |
3268 | if (! TARGET_GNU_AS && GET_CODE (x) == CONST_INT) | |
3269 | { | |
809d4ef1 | 3270 | fprintf (file, "0x%x", (int) INTVAL (x) & 0xffffffff); |
c65ebc55 JW |
3271 | return; |
3272 | } | |
3273 | break; | |
3274 | ||
3275 | case 'U': | |
3276 | if (! TARGET_GNU_AS && GET_CODE (x) == CONST_INT) | |
3277 | { | |
3b572406 | 3278 | const char *prefix = "0x"; |
c65ebc55 JW |
3279 | if (INTVAL (x) & 0x80000000) |
3280 | { | |
3281 | fprintf (file, "0xffffffff"); | |
3282 | prefix = ""; | |
3283 | } | |
809d4ef1 | 3284 | fprintf (file, "%s%x", prefix, (int) INTVAL (x) & 0xffffffff); |
c65ebc55 JW |
3285 | return; |
3286 | } | |
3287 | break; | |
809d4ef1 | 3288 | |
c65ebc55 | 3289 | case 'r': |
18a3c539 JW |
3290 | /* If this operand is the constant zero, write it as register zero. |
3291 | Any register, zero, or CONST_INT value is OK here. */ | |
c65ebc55 JW |
3292 | if (GET_CODE (x) == REG) |
3293 | fputs (reg_names[REGNO (x)], file); | |
3294 | else if (x == CONST0_RTX (GET_MODE (x))) | |
3295 | fputs ("r0", file); | |
18a3c539 JW |
3296 | else if (GET_CODE (x) == CONST_INT) |
3297 | output_addr_const (file, x); | |
c65ebc55 JW |
3298 | else |
3299 | output_operand_lossage ("invalid %%r value"); | |
3300 | return; | |
3301 | ||
85548039 RH |
3302 | case '+': |
3303 | { | |
3304 | const char *which; | |
3305 | ||
3306 | /* For conditional branches, returns or calls, substitute | |
3307 | sptk, dptk, dpnt, or spnt for %s. */ | |
3308 | x = find_reg_note (current_output_insn, REG_BR_PROB, 0); | |
3309 | if (x) | |
3310 | { | |
3311 | int pred_val = INTVAL (XEXP (x, 0)); | |
3312 | ||
3313 | /* Guess top and bottom 10% statically predicted. */ | |
55d8cb78 | 3314 | if (pred_val < REG_BR_PROB_BASE / 50) |
85548039 RH |
3315 | which = ".spnt"; |
3316 | else if (pred_val < REG_BR_PROB_BASE / 2) | |
3317 | which = ".dpnt"; | |
55d8cb78 | 3318 | else if (pred_val < REG_BR_PROB_BASE / 100 * 98) |
85548039 RH |
3319 | which = ".dptk"; |
3320 | else | |
3321 | which = ".sptk"; | |
3322 | } | |
3323 | else if (GET_CODE (current_output_insn) == CALL_INSN) | |
3324 | which = ".sptk"; | |
3325 | else | |
3326 | which = ".dptk"; | |
3327 | ||
3328 | fputs (which, file); | |
3329 | return; | |
3330 | } | |
3331 | ||
6f8aa100 RH |
3332 | case ',': |
3333 | x = current_insn_predicate; | |
3334 | if (x) | |
3335 | { | |
3336 | unsigned int regno = REGNO (XEXP (x, 0)); | |
3337 | if (GET_CODE (x) == EQ) | |
3338 | regno += 1; | |
6f8aa100 RH |
3339 | fprintf (file, "(%s) ", reg_names [regno]); |
3340 | } | |
3341 | return; | |
3342 | ||
c65ebc55 JW |
3343 | default: |
3344 | output_operand_lossage ("ia64_print_operand: unknown code"); | |
3345 | return; | |
3346 | } | |
3347 | ||
3348 | switch (GET_CODE (x)) | |
3349 | { | |
3350 | /* This happens for the spill/restore instructions. */ | |
3351 | case POST_INC: | |
4b983fdc RH |
3352 | case POST_DEC: |
3353 | case POST_MODIFY: | |
c65ebc55 JW |
3354 | x = XEXP (x, 0); |
3355 | /* ... fall through ... */ | |
3356 | ||
3357 | case REG: | |
3358 | fputs (reg_names [REGNO (x)], file); | |
3359 | break; | |
3360 | ||
3361 | case MEM: | |
3362 | { | |
3363 | rtx addr = XEXP (x, 0); | |
4b983fdc | 3364 | if (GET_RTX_CLASS (GET_CODE (addr)) == 'a') |
c65ebc55 JW |
3365 | addr = XEXP (addr, 0); |
3366 | fprintf (file, "[%s]", reg_names [REGNO (addr)]); | |
3367 | break; | |
3368 | } | |
809d4ef1 | 3369 | |
c65ebc55 JW |
3370 | default: |
3371 | output_addr_const (file, x); | |
3372 | break; | |
3373 | } | |
3374 | ||
3375 | return; | |
3376 | } | |
c65ebc55 | 3377 | \f |
5527bf14 RH |
3378 | /* Calulate the cost of moving data from a register in class FROM to |
3379 | one in class TO. */ | |
3380 | ||
3381 | int | |
3382 | ia64_register_move_cost (from, to) | |
3383 | enum reg_class from, to; | |
3384 | { | |
3385 | int from_hard, to_hard; | |
3386 | int from_gr, to_gr; | |
3f622353 | 3387 | int from_fr, to_fr; |
f2f90c63 | 3388 | int from_pr, to_pr; |
5527bf14 RH |
3389 | |
3390 | from_hard = (from == BR_REGS || from == AR_M_REGS || from == AR_I_REGS); | |
3391 | to_hard = (to == BR_REGS || to == AR_M_REGS || to == AR_I_REGS); | |
3392 | from_gr = (from == GENERAL_REGS); | |
3393 | to_gr = (to == GENERAL_REGS); | |
3f622353 RH |
3394 | from_fr = (from == FR_REGS); |
3395 | to_fr = (to == FR_REGS); | |
f2f90c63 RH |
3396 | from_pr = (from == PR_REGS); |
3397 | to_pr = (to == PR_REGS); | |
5527bf14 RH |
3398 | |
3399 | if (from_hard && to_hard) | |
3400 | return 8; | |
3401 | else if ((from_hard && !to_gr) || (!from_gr && to_hard)) | |
3402 | return 6; | |
3403 | ||
f2f90c63 RH |
3404 | /* Moving between PR registers takes two insns. */ |
3405 | else if (from_pr && to_pr) | |
3406 | return 3; | |
3407 | /* Moving between PR and anything but GR is impossible. */ | |
3408 | else if ((from_pr && !to_gr) || (!from_gr && to_pr)) | |
3409 | return 6; | |
3410 | ||
3f622353 RH |
3411 | /* ??? Moving from FR<->GR must be more expensive than 2, so that we get |
3412 | secondary memory reloads for TFmode moves. Unfortunately, we don't | |
3413 | have the mode here, so we can't check that. */ | |
3414 | /* Moreover, we have to make this at least as high as MEMORY_MOVE_COST | |
3415 | to avoid spectacularly poor register class preferencing for TFmode. */ | |
3416 | else if (from_fr != to_fr) | |
3417 | return 5; | |
3418 | ||
5527bf14 RH |
3419 | return 2; |
3420 | } | |
c65ebc55 JW |
3421 | |
3422 | /* This function returns the register class required for a secondary | |
3423 | register when copying between one of the registers in CLASS, and X, | |
3424 | using MODE. A return value of NO_REGS means that no secondary register | |
3425 | is required. */ | |
3426 | ||
3427 | enum reg_class | |
3428 | ia64_secondary_reload_class (class, mode, x) | |
3429 | enum reg_class class; | |
fd7c34b0 | 3430 | enum machine_mode mode ATTRIBUTE_UNUSED; |
c65ebc55 JW |
3431 | rtx x; |
3432 | { | |
3433 | int regno = -1; | |
3434 | ||
3435 | if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG) | |
3436 | regno = true_regnum (x); | |
3437 | ||
97e242b0 RH |
3438 | switch (class) |
3439 | { | |
3440 | case BR_REGS: | |
3441 | /* ??? This is required because of a bad gcse/cse/global interaction. | |
3442 | We end up with two pseudos with overlapping lifetimes both of which | |
3443 | are equiv to the same constant, and both which need to be in BR_REGS. | |
3444 | This results in a BR_REGS to BR_REGS copy which doesn't exist. To | |
3445 | reproduce, return NO_REGS here, and compile divdi3 in libgcc2.c. | |
3446 | This seems to be a cse bug. cse_basic_block_end changes depending | |
3447 | on the path length, which means the qty_first_reg check in | |
3448 | make_regs_eqv can give different answers at different times. */ | |
3449 | /* ??? At some point I'll probably need a reload_indi pattern to handle | |
3450 | this. */ | |
3451 | if (BR_REGNO_P (regno)) | |
3452 | return GR_REGS; | |
3453 | ||
3454 | /* This is needed if a pseudo used as a call_operand gets spilled to a | |
3455 | stack slot. */ | |
3456 | if (GET_CODE (x) == MEM) | |
3457 | return GR_REGS; | |
3458 | break; | |
3459 | ||
3460 | case FR_REGS: | |
3461 | /* This can happen when a paradoxical subreg is an operand to the | |
3462 | muldi3 pattern. */ | |
3463 | /* ??? This shouldn't be necessary after instruction scheduling is | |
3464 | enabled, because paradoxical subregs are not accepted by | |
3465 | register_operand when INSN_SCHEDULING is defined. Or alternatively, | |
3466 | stop the paradoxical subreg stupidity in the *_operand functions | |
3467 | in recog.c. */ | |
3468 | if (GET_CODE (x) == MEM | |
3469 | && (GET_MODE (x) == SImode || GET_MODE (x) == HImode | |
3470 | || GET_MODE (x) == QImode)) | |
3471 | return GR_REGS; | |
3472 | ||
3473 | /* This can happen because of the ior/and/etc patterns that accept FP | |
3474 | registers as operands. If the third operand is a constant, then it | |
3475 | needs to be reloaded into a FP register. */ | |
3476 | if (GET_CODE (x) == CONST_INT) | |
3477 | return GR_REGS; | |
3478 | ||
3479 | /* This can happen because of register elimination in a muldi3 insn. | |
3480 | E.g. `26107 * (unsigned long)&u'. */ | |
3481 | if (GET_CODE (x) == PLUS) | |
3482 | return GR_REGS; | |
3483 | break; | |
3484 | ||
3485 | case PR_REGS: | |
f2f90c63 | 3486 | /* ??? This happens if we cse/gcse a BImode value across a call, |
97e242b0 RH |
3487 | and the function has a nonlocal goto. This is because global |
3488 | does not allocate call crossing pseudos to hard registers when | |
3489 | current_function_has_nonlocal_goto is true. This is relatively | |
3490 | common for C++ programs that use exceptions. To reproduce, | |
3491 | return NO_REGS and compile libstdc++. */ | |
3492 | if (GET_CODE (x) == MEM) | |
3493 | return GR_REGS; | |
f2f90c63 RH |
3494 | |
3495 | /* This can happen when we take a BImode subreg of a DImode value, | |
3496 | and that DImode value winds up in some non-GR register. */ | |
3497 | if (regno >= 0 && ! GENERAL_REGNO_P (regno) && ! PR_REGNO_P (regno)) | |
3498 | return GR_REGS; | |
97e242b0 RH |
3499 | break; |
3500 | ||
3f622353 RH |
3501 | case GR_REGS: |
3502 | /* Since we have no offsettable memory addresses, we need a temporary | |
3503 | to hold the address of the second word. */ | |
3504 | if (mode == TImode) | |
3505 | return GR_REGS; | |
3506 | break; | |
3507 | ||
97e242b0 RH |
3508 | default: |
3509 | break; | |
3510 | } | |
c65ebc55 JW |
3511 | |
3512 | return NO_REGS; | |
3513 | } | |
3514 | ||
3515 | \f | |
3516 | /* Emit text to declare externally defined variables and functions, because | |
3517 | the Intel assembler does not support undefined externals. */ | |
3518 | ||
3519 | void | |
3520 | ia64_asm_output_external (file, decl, name) | |
3521 | FILE *file; | |
3522 | tree decl; | |
809d4ef1 | 3523 | const char *name; |
c65ebc55 JW |
3524 | { |
3525 | int save_referenced; | |
3526 | ||
3527 | /* GNU as does not need anything here. */ | |
3528 | if (TARGET_GNU_AS) | |
3529 | return; | |
3530 | ||
3531 | /* ??? The Intel assembler creates a reference that needs to be satisfied by | |
3532 | the linker when we do this, so we need to be careful not to do this for | |
3533 | builtin functions which have no library equivalent. Unfortunately, we | |
3534 | can't tell here whether or not a function will actually be called by | |
3535 | expand_expr, so we pull in library functions even if we may not need | |
3536 | them later. */ | |
3537 | if (! strcmp (name, "__builtin_next_arg") | |
3538 | || ! strcmp (name, "alloca") | |
3539 | || ! strcmp (name, "__builtin_constant_p") | |
3540 | || ! strcmp (name, "__builtin_args_info")) | |
3541 | return; | |
3542 | ||
3543 | /* assemble_name will set TREE_SYMBOL_REFERENCED, so we must save and | |
3544 | restore it. */ | |
3545 | save_referenced = TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)); | |
3546 | if (TREE_CODE (decl) == FUNCTION_DECL) | |
3547 | { | |
f0ca81d2 | 3548 | fprintf (file, "%s", TYPE_ASM_OP); |
c65ebc55 JW |
3549 | assemble_name (file, name); |
3550 | putc (',', file); | |
3551 | fprintf (file, TYPE_OPERAND_FMT, "function"); | |
3552 | putc ('\n', file); | |
3553 | } | |
3554 | ASM_GLOBALIZE_LABEL (file, name); | |
3555 | TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) = save_referenced; | |
3556 | } | |
3557 | \f | |
3558 | /* Parse the -mfixed-range= option string. */ | |
3559 | ||
3560 | static void | |
3b572406 RH |
3561 | fix_range (const_str) |
3562 | const char *const_str; | |
c65ebc55 JW |
3563 | { |
3564 | int i, first, last; | |
3b572406 | 3565 | char *str, *dash, *comma; |
c65ebc55 JW |
3566 | |
3567 | /* str must be of the form REG1'-'REG2{,REG1'-'REG} where REG1 and | |
3568 | REG2 are either register names or register numbers. The effect | |
3569 | of this option is to mark the registers in the range from REG1 to | |
3570 | REG2 as ``fixed'' so they won't be used by the compiler. This is | |
3571 | used, e.g., to ensure that kernel mode code doesn't use f32-f127. */ | |
3572 | ||
3b572406 RH |
3573 | i = strlen (const_str); |
3574 | str = (char *) alloca (i + 1); | |
3575 | memcpy (str, const_str, i + 1); | |
3576 | ||
c65ebc55 JW |
3577 | while (1) |
3578 | { | |
3579 | dash = strchr (str, '-'); | |
3580 | if (!dash) | |
3581 | { | |
3582 | warning ("value of -mfixed-range must have form REG1-REG2"); | |
3583 | return; | |
3584 | } | |
3585 | *dash = '\0'; | |
3586 | ||
3587 | comma = strchr (dash + 1, ','); | |
3588 | if (comma) | |
3589 | *comma = '\0'; | |
3590 | ||
3591 | first = decode_reg_name (str); | |
3592 | if (first < 0) | |
3593 | { | |
3594 | warning ("unknown register name: %s", str); | |
3595 | return; | |
3596 | } | |
3597 | ||
3598 | last = decode_reg_name (dash + 1); | |
3599 | if (last < 0) | |
3600 | { | |
3601 | warning ("unknown register name: %s", dash + 1); | |
3602 | return; | |
3603 | } | |
3604 | ||
3605 | *dash = '-'; | |
3606 | ||
3607 | if (first > last) | |
3608 | { | |
3609 | warning ("%s-%s is an empty range", str, dash + 1); | |
3610 | return; | |
3611 | } | |
3612 | ||
3613 | for (i = first; i <= last; ++i) | |
3614 | fixed_regs[i] = call_used_regs[i] = 1; | |
3615 | ||
3616 | if (!comma) | |
3617 | break; | |
3618 | ||
3619 | *comma = ','; | |
3620 | str = comma + 1; | |
3621 | } | |
3622 | } | |
3623 | ||
3624 | /* Called to register all of our global variables with the garbage | |
3625 | collector. */ | |
3626 | ||
3627 | static void | |
3628 | ia64_add_gc_roots () | |
3629 | { | |
3630 | ggc_add_rtx_root (&ia64_compare_op0, 1); | |
3631 | ggc_add_rtx_root (&ia64_compare_op1, 1); | |
3632 | } | |
3633 | ||
0c96007e AM |
3634 | static void |
3635 | ia64_init_machine_status (p) | |
3636 | struct function *p; | |
3637 | { | |
3638 | p->machine = | |
3639 | (struct machine_function *) xcalloc (1, sizeof (struct machine_function)); | |
3640 | } | |
3641 | ||
3642 | static void | |
3643 | ia64_mark_machine_status (p) | |
3644 | struct function *p; | |
3645 | { | |
3646 | ggc_mark_rtx (p->machine->ia64_eh_epilogue_sp); | |
3647 | ggc_mark_rtx (p->machine->ia64_eh_epilogue_bsp); | |
97e242b0 | 3648 | ggc_mark_rtx (p->machine->ia64_gp_save); |
0c96007e AM |
3649 | } |
3650 | ||
3651 | ||
c65ebc55 JW |
3652 | /* Handle TARGET_OPTIONS switches. */ |
3653 | ||
3654 | void | |
3655 | ia64_override_options () | |
3656 | { | |
59da9a7d JW |
3657 | if (TARGET_AUTO_PIC) |
3658 | target_flags |= MASK_CONST_GP; | |
3659 | ||
655f2eb9 RH |
3660 | if (TARGET_INLINE_DIV_LAT && TARGET_INLINE_DIV_THR) |
3661 | { | |
3662 | warning ("cannot optimize division for both latency and throughput"); | |
3663 | target_flags &= ~MASK_INLINE_DIV_THR; | |
3664 | } | |
3665 | ||
c65ebc55 JW |
3666 | if (ia64_fixed_range_string) |
3667 | fix_range (ia64_fixed_range_string); | |
3668 | ||
3669 | ia64_section_threshold = g_switch_set ? g_switch_value : IA64_DEFAULT_GVALUE; | |
3670 | ||
0c96007e AM |
3671 | init_machine_status = ia64_init_machine_status; |
3672 | mark_machine_status = ia64_mark_machine_status; | |
3673 | ||
c65ebc55 JW |
3674 | ia64_add_gc_roots (); |
3675 | } | |
3676 | \f | |
3677 | /* The following collection of routines emit instruction group stop bits as | |
3678 | necessary to avoid dependencies. */ | |
3679 | ||
3680 | /* Need to track some additional registers as far as serialization is | |
3681 | concerned so we can properly handle br.call and br.ret. We could | |
3682 | make these registers visible to gcc, but since these registers are | |
3683 | never explicitly used in gcc generated code, it seems wasteful to | |
3684 | do so (plus it would make the call and return patterns needlessly | |
3685 | complex). */ | |
3686 | #define REG_GP (GR_REG (1)) | |
3687 | #define REG_RP (BR_REG (0)) | |
c65ebc55 | 3688 | #define REG_AR_CFM (FIRST_PSEUDO_REGISTER + 1) |
c65ebc55 JW |
3689 | /* This is used for volatile asms which may require a stop bit immediately |
3690 | before and after them. */ | |
5527bf14 | 3691 | #define REG_VOLATILE (FIRST_PSEUDO_REGISTER + 2) |
870f9ec0 RH |
3692 | #define AR_UNAT_BIT_0 (FIRST_PSEUDO_REGISTER + 3) |
3693 | #define NUM_REGS (AR_UNAT_BIT_0 + 64) | |
c65ebc55 | 3694 | |
f2f90c63 RH |
3695 | /* For each register, we keep track of how it has been written in the |
3696 | current instruction group. | |
3697 | ||
3698 | If a register is written unconditionally (no qualifying predicate), | |
3699 | WRITE_COUNT is set to 2 and FIRST_PRED is ignored. | |
3700 | ||
3701 | If a register is written if its qualifying predicate P is true, we | |
3702 | set WRITE_COUNT to 1 and FIRST_PRED to P. Later on, the same register | |
3703 | may be written again by the complement of P (P^1) and when this happens, | |
3704 | WRITE_COUNT gets set to 2. | |
3705 | ||
3706 | The result of this is that whenever an insn attempts to write a register | |
3707 | whose WRITE_COUNT is two, we need to issue a insn group barrier first. | |
3708 | ||
3709 | If a predicate register is written by a floating-point insn, we set | |
3710 | WRITTEN_BY_FP to true. | |
3711 | ||
3712 | If a predicate register is written by an AND.ORCM we set WRITTEN_BY_AND | |
3713 | to true; if it was written by an OR.ANDCM we set WRITTEN_BY_OR to true. */ | |
3714 | ||
c65ebc55 JW |
3715 | struct reg_write_state |
3716 | { | |
f2f90c63 RH |
3717 | unsigned int write_count : 2; |
3718 | unsigned int first_pred : 16; | |
3719 | unsigned int written_by_fp : 1; | |
3720 | unsigned int written_by_and : 1; | |
3721 | unsigned int written_by_or : 1; | |
c65ebc55 JW |
3722 | }; |
3723 | ||
3724 | /* Cumulative info for the current instruction group. */ | |
3725 | struct reg_write_state rws_sum[NUM_REGS]; | |
3726 | /* Info for the current instruction. This gets copied to rws_sum after a | |
3727 | stop bit is emitted. */ | |
3728 | struct reg_write_state rws_insn[NUM_REGS]; | |
3729 | ||
3730 | /* Misc flags needed to compute RAW/WAW dependencies while we are traversing | |
3731 | RTL for one instruction. */ | |
3732 | struct reg_flags | |
3733 | { | |
3734 | unsigned int is_write : 1; /* Is register being written? */ | |
3735 | unsigned int is_fp : 1; /* Is register used as part of an fp op? */ | |
3736 | unsigned int is_branch : 1; /* Is register used as part of a branch? */ | |
f2f90c63 RH |
3737 | unsigned int is_and : 1; /* Is register used as part of and.orcm? */ |
3738 | unsigned int is_or : 1; /* Is register used as part of or.andcm? */ | |
2ed4af6f | 3739 | unsigned int is_sibcall : 1; /* Is this a sibling or normal call? */ |
c65ebc55 JW |
3740 | }; |
3741 | ||
3b572406 RH |
3742 | static void rws_update PARAMS ((struct reg_write_state *, int, |
3743 | struct reg_flags, int)); | |
97e242b0 RH |
3744 | static int rws_access_regno PARAMS ((int, struct reg_flags, int)); |
3745 | static int rws_access_reg PARAMS ((rtx, struct reg_flags, int)); | |
3b572406 RH |
3746 | static int rtx_needs_barrier PARAMS ((rtx, struct reg_flags, int)); |
3747 | ||
c65ebc55 JW |
3748 | /* Update *RWS for REGNO, which is being written by the current instruction, |
3749 | with predicate PRED, and associated register flags in FLAGS. */ | |
3750 | ||
3751 | static void | |
3752 | rws_update (rws, regno, flags, pred) | |
3753 | struct reg_write_state *rws; | |
3754 | int regno; | |
3755 | struct reg_flags flags; | |
3756 | int pred; | |
3757 | { | |
3758 | rws[regno].write_count += pred ? 1 : 2; | |
3759 | rws[regno].written_by_fp |= flags.is_fp; | |
f2f90c63 RH |
3760 | /* ??? Not tracking and/or across differing predicates. */ |
3761 | rws[regno].written_by_and = flags.is_and; | |
3762 | rws[regno].written_by_or = flags.is_or; | |
c65ebc55 JW |
3763 | rws[regno].first_pred = pred; |
3764 | } | |
3765 | ||
3766 | /* Handle an access to register REGNO of type FLAGS using predicate register | |
3767 | PRED. Update rws_insn and rws_sum arrays. Return 1 if this access creates | |
3768 | a dependency with an earlier instruction in the same group. */ | |
3769 | ||
3770 | static int | |
97e242b0 | 3771 | rws_access_regno (regno, flags, pred) |
c65ebc55 JW |
3772 | int regno; |
3773 | struct reg_flags flags; | |
3774 | int pred; | |
3775 | { | |
3776 | int need_barrier = 0; | |
c65ebc55 JW |
3777 | |
3778 | if (regno >= NUM_REGS) | |
3779 | abort (); | |
3780 | ||
f2f90c63 RH |
3781 | if (! PR_REGNO_P (regno)) |
3782 | flags.is_and = flags.is_or = 0; | |
3783 | ||
c65ebc55 JW |
3784 | if (flags.is_write) |
3785 | { | |
12c2c7aa JW |
3786 | int write_count; |
3787 | ||
c65ebc55 JW |
3788 | /* One insn writes same reg multiple times? */ |
3789 | if (rws_insn[regno].write_count > 0) | |
3790 | abort (); | |
3791 | ||
3792 | /* Update info for current instruction. */ | |
3793 | rws_update (rws_insn, regno, flags, pred); | |
12c2c7aa | 3794 | write_count = rws_sum[regno].write_count; |
12c2c7aa JW |
3795 | |
3796 | switch (write_count) | |
c65ebc55 JW |
3797 | { |
3798 | case 0: | |
3799 | /* The register has not been written yet. */ | |
3800 | rws_update (rws_sum, regno, flags, pred); | |
c65ebc55 JW |
3801 | break; |
3802 | ||
3803 | case 1: | |
3804 | /* The register has been written via a predicate. If this is | |
3805 | not a complementary predicate, then we need a barrier. */ | |
3806 | /* ??? This assumes that P and P+1 are always complementary | |
3807 | predicates for P even. */ | |
f2f90c63 RH |
3808 | if (flags.is_and && rws_sum[regno].written_by_and) |
3809 | ; | |
3810 | else if (flags.is_or && rws_sum[regno].written_by_or) | |
3811 | ; | |
3812 | else if ((rws_sum[regno].first_pred ^ 1) != pred) | |
c65ebc55 JW |
3813 | need_barrier = 1; |
3814 | rws_update (rws_sum, regno, flags, pred); | |
c65ebc55 JW |
3815 | break; |
3816 | ||
3817 | case 2: | |
3818 | /* The register has been unconditionally written already. We | |
3819 | need a barrier. */ | |
f2f90c63 RH |
3820 | if (flags.is_and && rws_sum[regno].written_by_and) |
3821 | ; | |
3822 | else if (flags.is_or && rws_sum[regno].written_by_or) | |
3823 | ; | |
3824 | else | |
3825 | need_barrier = 1; | |
3826 | rws_sum[regno].written_by_and = flags.is_and; | |
3827 | rws_sum[regno].written_by_or = flags.is_or; | |
c65ebc55 JW |
3828 | break; |
3829 | ||
3830 | default: | |
3831 | abort (); | |
3832 | } | |
3833 | } | |
3834 | else | |
3835 | { | |
3836 | if (flags.is_branch) | |
3837 | { | |
3838 | /* Branches have several RAW exceptions that allow to avoid | |
3839 | barriers. */ | |
3840 | ||
5527bf14 | 3841 | if (REGNO_REG_CLASS (regno) == BR_REGS || regno == AR_PFS_REGNUM) |
c65ebc55 JW |
3842 | /* RAW dependencies on branch regs are permissible as long |
3843 | as the writer is a non-branch instruction. Since we | |
3844 | never generate code that uses a branch register written | |
3845 | by a branch instruction, handling this case is | |
3846 | easy. */ | |
5527bf14 | 3847 | return 0; |
c65ebc55 JW |
3848 | |
3849 | if (REGNO_REG_CLASS (regno) == PR_REGS | |
3850 | && ! rws_sum[regno].written_by_fp) | |
3851 | /* The predicates of a branch are available within the | |
3852 | same insn group as long as the predicate was written by | |
3853 | something other than a floating-point instruction. */ | |
3854 | return 0; | |
3855 | } | |
3856 | ||
f2f90c63 RH |
3857 | if (flags.is_and && rws_sum[regno].written_by_and) |
3858 | return 0; | |
3859 | if (flags.is_or && rws_sum[regno].written_by_or) | |
3860 | return 0; | |
3861 | ||
c65ebc55 JW |
3862 | switch (rws_sum[regno].write_count) |
3863 | { | |
3864 | case 0: | |
3865 | /* The register has not been written yet. */ | |
3866 | break; | |
3867 | ||
3868 | case 1: | |
3869 | /* The register has been written via a predicate. If this is | |
3870 | not a complementary predicate, then we need a barrier. */ | |
3871 | /* ??? This assumes that P and P+1 are always complementary | |
3872 | predicates for P even. */ | |
3873 | if ((rws_sum[regno].first_pred ^ 1) != pred) | |
3874 | need_barrier = 1; | |
3875 | break; | |
3876 | ||
3877 | case 2: | |
3878 | /* The register has been unconditionally written already. We | |
3879 | need a barrier. */ | |
3880 | need_barrier = 1; | |
3881 | break; | |
3882 | ||
3883 | default: | |
3884 | abort (); | |
3885 | } | |
3886 | } | |
3887 | ||
3888 | return need_barrier; | |
3889 | } | |
3890 | ||
97e242b0 RH |
3891 | static int |
3892 | rws_access_reg (reg, flags, pred) | |
3893 | rtx reg; | |
3894 | struct reg_flags flags; | |
3895 | int pred; | |
3896 | { | |
3897 | int regno = REGNO (reg); | |
3898 | int n = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)); | |
3899 | ||
3900 | if (n == 1) | |
3901 | return rws_access_regno (regno, flags, pred); | |
3902 | else | |
3903 | { | |
3904 | int need_barrier = 0; | |
3905 | while (--n >= 0) | |
3906 | need_barrier |= rws_access_regno (regno + n, flags, pred); | |
3907 | return need_barrier; | |
3908 | } | |
3909 | } | |
3910 | ||
c65ebc55 JW |
3911 | /* Handle an access to rtx X of type FLAGS using predicate register PRED. |
3912 | Return 1 is this access creates a dependency with an earlier instruction | |
3913 | in the same group. */ | |
3914 | ||
3915 | static int | |
3916 | rtx_needs_barrier (x, flags, pred) | |
3917 | rtx x; | |
3918 | struct reg_flags flags; | |
3919 | int pred; | |
3920 | { | |
3921 | int i, j; | |
3922 | int is_complemented = 0; | |
3923 | int need_barrier = 0; | |
3924 | const char *format_ptr; | |
3925 | struct reg_flags new_flags; | |
3926 | rtx src, dst; | |
3927 | rtx cond = 0; | |
3928 | ||
3929 | if (! x) | |
3930 | return 0; | |
3931 | ||
3932 | new_flags = flags; | |
3933 | ||
3934 | switch (GET_CODE (x)) | |
3935 | { | |
3936 | case SET: | |
3937 | src = SET_SRC (x); | |
3938 | switch (GET_CODE (src)) | |
3939 | { | |
3940 | case CALL: | |
3941 | /* We don't need to worry about the result registers that | |
3942 | get written by subroutine call. */ | |
3943 | need_barrier = rtx_needs_barrier (src, flags, pred); | |
3944 | return need_barrier; | |
3945 | ||
3946 | case IF_THEN_ELSE: | |
3947 | if (SET_DEST (x) == pc_rtx) | |
3948 | { | |
3949 | /* X is a conditional branch. */ | |
3950 | /* ??? This seems redundant, as the caller sets this bit for | |
3951 | all JUMP_INSNs. */ | |
3952 | new_flags.is_branch = 1; | |
3953 | need_barrier = rtx_needs_barrier (src, new_flags, pred); | |
3954 | return need_barrier; | |
3955 | } | |
3956 | else | |
3957 | { | |
3958 | /* X is a conditional move. */ | |
3959 | cond = XEXP (src, 0); | |
3960 | if (GET_CODE (cond) == EQ) | |
3961 | is_complemented = 1; | |
3962 | cond = XEXP (cond, 0); | |
3963 | if (GET_CODE (cond) != REG | |
3964 | && REGNO_REG_CLASS (REGNO (cond)) != PR_REGS) | |
3965 | abort (); | |
3966 | ||
3967 | if (XEXP (src, 1) == SET_DEST (x) | |
3968 | || XEXP (src, 2) == SET_DEST (x)) | |
3969 | { | |
3970 | /* X is a conditional move that conditionally writes the | |
3971 | destination. */ | |
3972 | ||
3973 | /* We need another complement in this case. */ | |
3974 | if (XEXP (src, 1) == SET_DEST (x)) | |
3975 | is_complemented = ! is_complemented; | |
3976 | ||
3977 | pred = REGNO (cond); | |
3978 | if (is_complemented) | |
3979 | ++pred; | |
3980 | } | |
3981 | ||
3982 | /* ??? If this is a conditional write to the dest, then this | |
3983 | instruction does not actually read one source. This probably | |
3984 | doesn't matter, because that source is also the dest. */ | |
3985 | /* ??? Multiple writes to predicate registers are allowed | |
3986 | if they are all AND type compares, or if they are all OR | |
3987 | type compares. We do not generate such instructions | |
3988 | currently. */ | |
3989 | } | |
3990 | /* ... fall through ... */ | |
3991 | ||
3992 | default: | |
3993 | if (GET_RTX_CLASS (GET_CODE (src)) == '<' | |
3994 | && GET_MODE_CLASS (GET_MODE (XEXP (src, 0))) == MODE_FLOAT) | |
3995 | /* Set new_flags.is_fp to 1 so that we know we're dealing | |
3996 | with a floating point comparison when processing the | |
3997 | destination of the SET. */ | |
3998 | new_flags.is_fp = 1; | |
f2f90c63 RH |
3999 | |
4000 | /* Discover if this is a parallel comparison. We only handle | |
4001 | and.orcm and or.andcm at present, since we must retain a | |
4002 | strict inverse on the predicate pair. */ | |
4003 | else if (GET_CODE (src) == AND) | |
4004 | new_flags.is_and = flags.is_and = 1; | |
4005 | else if (GET_CODE (src) == IOR) | |
4006 | new_flags.is_or = flags.is_or = 1; | |
4007 | ||
c65ebc55 JW |
4008 | break; |
4009 | } | |
4010 | need_barrier = rtx_needs_barrier (src, flags, pred); | |
97e242b0 | 4011 | |
c65ebc55 JW |
4012 | /* This instruction unconditionally uses a predicate register. */ |
4013 | if (cond) | |
97e242b0 | 4014 | need_barrier |= rws_access_reg (cond, flags, 0); |
c65ebc55 JW |
4015 | |
4016 | dst = SET_DEST (x); | |
4017 | if (GET_CODE (dst) == ZERO_EXTRACT) | |
4018 | { | |
4019 | need_barrier |= rtx_needs_barrier (XEXP (dst, 1), flags, pred); | |
4020 | need_barrier |= rtx_needs_barrier (XEXP (dst, 2), flags, pred); | |
4021 | dst = XEXP (dst, 0); | |
4022 | } | |
4023 | new_flags.is_write = 1; | |
4024 | need_barrier |= rtx_needs_barrier (dst, new_flags, pred); | |
4025 | break; | |
4026 | ||
4027 | case CALL: | |
4028 | new_flags.is_write = 0; | |
97e242b0 | 4029 | need_barrier |= rws_access_regno (AR_EC_REGNUM, new_flags, pred); |
c65ebc55 JW |
4030 | |
4031 | /* Avoid multiple register writes, in case this is a pattern with | |
4032 | multiple CALL rtx. This avoids an abort in rws_access_reg. */ | |
2ed4af6f | 4033 | if (! flags.is_sibcall && ! rws_insn[REG_AR_CFM].write_count) |
c65ebc55 JW |
4034 | { |
4035 | new_flags.is_write = 1; | |
97e242b0 RH |
4036 | need_barrier |= rws_access_regno (REG_RP, new_flags, pred); |
4037 | need_barrier |= rws_access_regno (AR_PFS_REGNUM, new_flags, pred); | |
4038 | need_barrier |= rws_access_regno (REG_AR_CFM, new_flags, pred); | |
c65ebc55 JW |
4039 | } |
4040 | break; | |
4041 | ||
e5bde68a RH |
4042 | case COND_EXEC: |
4043 | /* X is a predicated instruction. */ | |
4044 | ||
4045 | cond = COND_EXEC_TEST (x); | |
4046 | if (pred) | |
4047 | abort (); | |
4048 | need_barrier = rtx_needs_barrier (cond, flags, 0); | |
4049 | ||
4050 | if (GET_CODE (cond) == EQ) | |
4051 | is_complemented = 1; | |
4052 | cond = XEXP (cond, 0); | |
4053 | if (GET_CODE (cond) != REG | |
4054 | && REGNO_REG_CLASS (REGNO (cond)) != PR_REGS) | |
4055 | abort (); | |
4056 | pred = REGNO (cond); | |
4057 | if (is_complemented) | |
4058 | ++pred; | |
4059 | ||
4060 | need_barrier |= rtx_needs_barrier (COND_EXEC_CODE (x), flags, pred); | |
4061 | return need_barrier; | |
4062 | ||
c65ebc55 | 4063 | case CLOBBER: |
c65ebc55 | 4064 | case USE: |
c65ebc55 JW |
4065 | /* Clobber & use are for earlier compiler-phases only. */ |
4066 | break; | |
4067 | ||
4068 | case ASM_OPERANDS: | |
4069 | case ASM_INPUT: | |
4070 | /* We always emit stop bits for traditional asms. We emit stop bits | |
4071 | for volatile extended asms if TARGET_VOL_ASM_STOP is true. */ | |
4072 | if (GET_CODE (x) != ASM_OPERANDS | |
4073 | || (MEM_VOLATILE_P (x) && TARGET_VOL_ASM_STOP)) | |
4074 | { | |
4075 | /* Avoid writing the register multiple times if we have multiple | |
4076 | asm outputs. This avoids an abort in rws_access_reg. */ | |
4077 | if (! rws_insn[REG_VOLATILE].write_count) | |
4078 | { | |
4079 | new_flags.is_write = 1; | |
97e242b0 | 4080 | rws_access_regno (REG_VOLATILE, new_flags, pred); |
c65ebc55 JW |
4081 | } |
4082 | return 1; | |
4083 | } | |
4084 | ||
4085 | /* For all ASM_OPERANDS, we must traverse the vector of input operands. | |
4086 | We can not just fall through here since then we would be confused | |
4087 | by the ASM_INPUT rtx inside ASM_OPERANDS, which do not indicate | |
4088 | traditional asms unlike their normal usage. */ | |
4089 | ||
4090 | for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; --i) | |
4091 | if (rtx_needs_barrier (ASM_OPERANDS_INPUT (x, i), flags, pred)) | |
4092 | need_barrier = 1; | |
4093 | break; | |
4094 | ||
4095 | case PARALLEL: | |
4096 | for (i = XVECLEN (x, 0) - 1; i >= 0; --i) | |
4097 | if (rtx_needs_barrier (XVECEXP (x, 0, i), flags, pred)) | |
4098 | need_barrier = 1; | |
4099 | break; | |
4100 | ||
4101 | case SUBREG: | |
4102 | x = SUBREG_REG (x); | |
4103 | /* FALLTHRU */ | |
4104 | case REG: | |
870f9ec0 RH |
4105 | if (REGNO (x) == AR_UNAT_REGNUM) |
4106 | { | |
4107 | for (i = 0; i < 64; ++i) | |
4108 | need_barrier |= rws_access_regno (AR_UNAT_BIT_0 + i, flags, pred); | |
4109 | } | |
4110 | else | |
4111 | need_barrier = rws_access_reg (x, flags, pred); | |
c65ebc55 JW |
4112 | break; |
4113 | ||
4114 | case MEM: | |
4115 | /* Find the regs used in memory address computation. */ | |
4116 | new_flags.is_write = 0; | |
4117 | need_barrier = rtx_needs_barrier (XEXP (x, 0), new_flags, pred); | |
4118 | break; | |
4119 | ||
4120 | case CONST_INT: case CONST_DOUBLE: | |
4121 | case SYMBOL_REF: case LABEL_REF: case CONST: | |
4122 | break; | |
4123 | ||
4124 | /* Operators with side-effects. */ | |
4125 | case POST_INC: case POST_DEC: | |
4126 | if (GET_CODE (XEXP (x, 0)) != REG) | |
4127 | abort (); | |
4128 | ||
4129 | new_flags.is_write = 0; | |
97e242b0 | 4130 | need_barrier = rws_access_reg (XEXP (x, 0), new_flags, pred); |
c65ebc55 | 4131 | new_flags.is_write = 1; |
97e242b0 | 4132 | need_barrier |= rws_access_reg (XEXP (x, 0), new_flags, pred); |
4b983fdc RH |
4133 | break; |
4134 | ||
4135 | case POST_MODIFY: | |
4136 | if (GET_CODE (XEXP (x, 0)) != REG) | |
4137 | abort (); | |
4138 | ||
4139 | new_flags.is_write = 0; | |
97e242b0 | 4140 | need_barrier = rws_access_reg (XEXP (x, 0), new_flags, pred); |
4b983fdc RH |
4141 | need_barrier |= rtx_needs_barrier (XEXP (x, 1), new_flags, pred); |
4142 | new_flags.is_write = 1; | |
97e242b0 | 4143 | need_barrier |= rws_access_reg (XEXP (x, 0), new_flags, pred); |
c65ebc55 JW |
4144 | break; |
4145 | ||
4146 | /* Handle common unary and binary ops for efficiency. */ | |
4147 | case COMPARE: case PLUS: case MINUS: case MULT: case DIV: | |
4148 | case MOD: case UDIV: case UMOD: case AND: case IOR: | |
4149 | case XOR: case ASHIFT: case ROTATE: case ASHIFTRT: case LSHIFTRT: | |
4150 | case ROTATERT: case SMIN: case SMAX: case UMIN: case UMAX: | |
4151 | case NE: case EQ: case GE: case GT: case LE: | |
4152 | case LT: case GEU: case GTU: case LEU: case LTU: | |
4153 | need_barrier = rtx_needs_barrier (XEXP (x, 0), new_flags, pred); | |
4154 | need_barrier |= rtx_needs_barrier (XEXP (x, 1), new_flags, pred); | |
4155 | break; | |
4156 | ||
4157 | case NEG: case NOT: case SIGN_EXTEND: case ZERO_EXTEND: | |
4158 | case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: case FLOAT: | |
4159 | case FIX: case UNSIGNED_FLOAT: case UNSIGNED_FIX: case ABS: | |
4160 | case SQRT: case FFS: | |
4161 | need_barrier = rtx_needs_barrier (XEXP (x, 0), flags, pred); | |
4162 | break; | |
4163 | ||
4164 | case UNSPEC: | |
4165 | switch (XINT (x, 1)) | |
4166 | { | |
c65ebc55 JW |
4167 | case 1: /* st8.spill */ |
4168 | case 2: /* ld8.fill */ | |
870f9ec0 RH |
4169 | { |
4170 | HOST_WIDE_INT offset = INTVAL (XVECEXP (x, 0, 1)); | |
4171 | HOST_WIDE_INT bit = (offset >> 3) & 63; | |
4172 | ||
4173 | need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 0), flags, pred); | |
4174 | new_flags.is_write = (XINT (x, 1) == 1); | |
4175 | need_barrier |= rws_access_regno (AR_UNAT_BIT_0 + bit, | |
4176 | new_flags, pred); | |
4177 | break; | |
4178 | } | |
4179 | ||
c65ebc55 JW |
4180 | case 3: /* stf.spill */ |
4181 | case 4: /* ldf.spill */ | |
4182 | case 8: /* popcnt */ | |
4183 | need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 0), flags, pred); | |
4184 | break; | |
4185 | ||
f2f90c63 | 4186 | case 7: /* pred_rel_mutex */ |
2ed4af6f | 4187 | case 9: /* pic call */ |
c65ebc55 | 4188 | case 12: /* mf */ |
c65ebc55 | 4189 | case 19: /* fetchadd_acq */ |
0c96007e | 4190 | case 20: /* mov = ar.bsp */ |
ce152ef8 AM |
4191 | case 21: /* flushrs */ |
4192 | break; | |
0c96007e | 4193 | |
655f2eb9 RH |
4194 | case 5: /* recip_approx */ |
4195 | need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 0), flags, pred); | |
4196 | need_barrier |= rtx_needs_barrier (XVECEXP (x, 0, 1), flags, pred); | |
4197 | break; | |
4198 | ||
0551c32d RH |
4199 | case 13: /* cmpxchg_acq */ |
4200 | need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 1), flags, pred); | |
4201 | need_barrier |= rtx_needs_barrier (XVECEXP (x, 0, 2), flags, pred); | |
4202 | break; | |
4203 | ||
c65ebc55 JW |
4204 | default: |
4205 | abort (); | |
4206 | } | |
4207 | break; | |
4208 | ||
4209 | case UNSPEC_VOLATILE: | |
4210 | switch (XINT (x, 1)) | |
4211 | { | |
4212 | case 0: /* alloc */ | |
4213 | /* Alloc must always be the first instruction. Currently, we | |
4214 | only emit it at the function start, so we don't need to worry | |
4215 | about emitting a stop bit before it. */ | |
97e242b0 | 4216 | need_barrier = rws_access_regno (AR_PFS_REGNUM, flags, pred); |
c65ebc55 JW |
4217 | |
4218 | new_flags.is_write = 1; | |
97e242b0 | 4219 | need_barrier |= rws_access_regno (REG_AR_CFM, new_flags, pred); |
c65ebc55 JW |
4220 | return need_barrier; |
4221 | ||
4222 | case 1: /* blockage */ | |
4223 | case 2: /* insn group barrier */ | |
4224 | return 0; | |
4225 | ||
3b572406 RH |
4226 | case 5: /* set_bsp */ |
4227 | need_barrier = 1; | |
4228 | break; | |
4229 | ||
3b572406 | 4230 | case 7: /* pred.rel.mutex */ |
ca3920ad JW |
4231 | case 8: /* safe_across_calls all */ |
4232 | case 9: /* safe_across_calls normal */ | |
3b572406 | 4233 | return 0; |
0c96007e | 4234 | |
c65ebc55 JW |
4235 | default: |
4236 | abort (); | |
4237 | } | |
4238 | break; | |
4239 | ||
4240 | case RETURN: | |
4241 | new_flags.is_write = 0; | |
97e242b0 RH |
4242 | need_barrier = rws_access_regno (REG_RP, flags, pred); |
4243 | need_barrier |= rws_access_regno (AR_PFS_REGNUM, flags, pred); | |
c65ebc55 JW |
4244 | |
4245 | new_flags.is_write = 1; | |
97e242b0 RH |
4246 | need_barrier |= rws_access_regno (AR_EC_REGNUM, new_flags, pred); |
4247 | need_barrier |= rws_access_regno (REG_AR_CFM, new_flags, pred); | |
c65ebc55 JW |
4248 | break; |
4249 | ||
4250 | default: | |
4251 | format_ptr = GET_RTX_FORMAT (GET_CODE (x)); | |
4252 | for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) | |
4253 | switch (format_ptr[i]) | |
4254 | { | |
4255 | case '0': /* unused field */ | |
4256 | case 'i': /* integer */ | |
4257 | case 'n': /* note */ | |
4258 | case 'w': /* wide integer */ | |
4259 | case 's': /* pointer to string */ | |
4260 | case 'S': /* optional pointer to string */ | |
4261 | break; | |
4262 | ||
4263 | case 'e': | |
4264 | if (rtx_needs_barrier (XEXP (x, i), flags, pred)) | |
4265 | need_barrier = 1; | |
4266 | break; | |
4267 | ||
4268 | case 'E': | |
4269 | for (j = XVECLEN (x, i) - 1; j >= 0; --j) | |
4270 | if (rtx_needs_barrier (XVECEXP (x, i, j), flags, pred)) | |
4271 | need_barrier = 1; | |
4272 | break; | |
4273 | ||
4274 | default: | |
4275 | abort (); | |
4276 | } | |
2ed4af6f | 4277 | break; |
c65ebc55 JW |
4278 | } |
4279 | return need_barrier; | |
4280 | } | |
4281 | ||
099dde21 BS |
4282 | /* This structure is used to track some details about the previous insns |
4283 | groups so we can determine if it may be necessary to insert NOPs to | |
4284 | workaround hardware errata. */ | |
4285 | static struct group | |
4286 | { | |
4287 | HARD_REG_SET p_reg_set; | |
4288 | HARD_REG_SET gr_reg_conditionally_set; | |
4289 | } last_group[3]; | |
4290 | ||
4291 | /* Index into the last_group array. */ | |
4292 | static int group_idx; | |
4293 | ||
4294 | static void emit_group_barrier_after PARAMS ((rtx)); | |
4295 | static int errata_find_address_regs PARAMS ((rtx *, void *)); | |
4296 | static void errata_emit_nops PARAMS ((rtx)); | |
4297 | ||
4298 | /* Create a new group barrier, emit it after AFTER, and advance group_idx. */ | |
4299 | static void | |
4300 | emit_group_barrier_after (after) | |
4301 | rtx after; | |
4302 | { | |
4303 | emit_insn_after (gen_insn_group_barrier (), after); | |
4304 | group_idx = (group_idx + 1) % 3; | |
4305 | memset (last_group + group_idx, 0, sizeof last_group[group_idx]); | |
4306 | } | |
4307 | ||
4308 | /* Called through for_each_rtx; determines if a hard register that was | |
4309 | conditionally set in the previous group is used as an address register. | |
4310 | It ensures that for_each_rtx returns 1 in that case. */ | |
4311 | static int | |
4312 | errata_find_address_regs (xp, data) | |
4313 | rtx *xp; | |
4314 | void *data ATTRIBUTE_UNUSED; | |
4315 | { | |
4316 | rtx x = *xp; | |
4317 | if (GET_CODE (x) != MEM) | |
4318 | return 0; | |
4319 | x = XEXP (x, 0); | |
4320 | if (GET_CODE (x) == POST_MODIFY) | |
4321 | x = XEXP (x, 0); | |
4322 | if (GET_CODE (x) == REG) | |
4323 | { | |
4324 | struct group *prev_group = last_group + (group_idx + 2) % 3; | |
4325 | if (TEST_HARD_REG_BIT (prev_group->gr_reg_conditionally_set, | |
4326 | REGNO (x))) | |
4327 | return 1; | |
4328 | return -1; | |
4329 | } | |
4330 | return 0; | |
4331 | } | |
4332 | ||
4333 | /* Called for each insn; this function keeps track of the state in | |
4334 | last_group and emits additional NOPs if necessary to work around | |
4335 | an Itanium A/B step erratum. */ | |
4336 | static void | |
4337 | errata_emit_nops (insn) | |
4338 | rtx insn; | |
4339 | { | |
4340 | struct group *this_group = last_group + group_idx; | |
4341 | struct group *prev_group = last_group + (group_idx + 2) % 3; | |
4342 | rtx pat = PATTERN (insn); | |
4343 | rtx cond = GET_CODE (pat) == COND_EXEC ? COND_EXEC_TEST (pat) : 0; | |
4344 | rtx real_pat = cond ? COND_EXEC_CODE (pat) : pat; | |
4345 | enum attr_type type; | |
4346 | rtx set = real_pat; | |
4347 | ||
4348 | if (GET_CODE (real_pat) == USE | |
4349 | || GET_CODE (real_pat) == CLOBBER | |
4350 | || GET_CODE (real_pat) == ASM_INPUT | |
4351 | || GET_CODE (real_pat) == ADDR_VEC | |
4352 | || GET_CODE (real_pat) == ADDR_DIFF_VEC | |
4353 | || asm_noperands (insn) >= 0) | |
4354 | return; | |
4355 | ||
4356 | /* single_set doesn't work for COND_EXEC insns, so we have to duplicate | |
4357 | parts of it. */ | |
4358 | ||
4359 | if (GET_CODE (set) == PARALLEL) | |
4360 | { | |
4361 | int i; | |
4362 | set = XVECEXP (real_pat, 0, 0); | |
4363 | for (i = 1; i < XVECLEN (real_pat, 0); i++) | |
4364 | if (GET_CODE (XVECEXP (real_pat, 0, i)) != USE | |
4365 | && GET_CODE (XVECEXP (real_pat, 0, i)) != CLOBBER) | |
4366 | { | |
4367 | set = 0; | |
4368 | break; | |
4369 | } | |
4370 | } | |
4371 | ||
4372 | if (set && GET_CODE (set) != SET) | |
4373 | set = 0; | |
4374 | ||
4375 | type = get_attr_type (insn); | |
4376 | ||
4377 | if (type == TYPE_F | |
4378 | && set && REG_P (SET_DEST (set)) && PR_REGNO_P (REGNO (SET_DEST (set)))) | |
4379 | SET_HARD_REG_BIT (this_group->p_reg_set, REGNO (SET_DEST (set))); | |
4380 | ||
4381 | if ((type == TYPE_M || type == TYPE_A) && cond && set | |
4382 | && REG_P (SET_DEST (set)) | |
4383 | && GET_CODE (SET_SRC (set)) != PLUS | |
4384 | && GET_CODE (SET_SRC (set)) != MINUS | |
4385 | && (GET_CODE (SET_SRC (set)) != MEM | |
4386 | || GET_CODE (XEXP (SET_SRC (set), 0)) != POST_MODIFY) | |
4387 | && GENERAL_REGNO_P (REGNO (SET_DEST (set)))) | |
4388 | { | |
4389 | if (GET_RTX_CLASS (GET_CODE (cond)) != '<' | |
4390 | || ! REG_P (XEXP (cond, 0))) | |
4391 | abort (); | |
4392 | ||
4393 | if (TEST_HARD_REG_BIT (prev_group->p_reg_set, REGNO (XEXP (cond, 0)))) | |
4394 | SET_HARD_REG_BIT (this_group->gr_reg_conditionally_set, REGNO (SET_DEST (set))); | |
4395 | } | |
4396 | if (for_each_rtx (&real_pat, errata_find_address_regs, NULL)) | |
4397 | { | |
4398 | emit_insn_before (gen_insn_group_barrier (), insn); | |
4399 | emit_insn_before (gen_nop (), insn); | |
4400 | emit_insn_before (gen_insn_group_barrier (), insn); | |
4401 | } | |
4402 | } | |
4403 | ||
c65ebc55 JW |
4404 | /* INSNS is an chain of instructions. Scan the chain, and insert stop bits |
4405 | as necessary to eliminate dependendencies. */ | |
4406 | ||
4407 | static void | |
4408 | emit_insn_group_barriers (insns) | |
4409 | rtx insns; | |
4410 | { | |
c65ebc55 JW |
4411 | rtx insn, prev_insn; |
4412 | ||
4413 | memset (rws_sum, 0, sizeof (rws_sum)); | |
4414 | ||
099dde21 BS |
4415 | group_idx = 0; |
4416 | memset (last_group, 0, sizeof last_group); | |
4417 | ||
c65ebc55 JW |
4418 | prev_insn = 0; |
4419 | for (insn = insns; insn; insn = NEXT_INSN (insn)) | |
4420 | { | |
6b6c1201 RH |
4421 | int need_barrier = 0; |
4422 | struct reg_flags flags; | |
4423 | ||
099dde21 BS |
4424 | if ((TARGET_B_STEP || TARGET_A_STEP) && INSN_P (insn)) |
4425 | errata_emit_nops (insn); | |
4426 | ||
c65ebc55 JW |
4427 | memset (&flags, 0, sizeof (flags)); |
4428 | switch (GET_CODE (insn)) | |
4429 | { | |
4430 | case NOTE: | |
9c668921 RH |
4431 | /* For very small loops we can wind up with extra stop bits |
4432 | inside the loop because of not putting a stop after the | |
4433 | assignment to ar.lc before the loop label. */ | |
4434 | /* ??? Ideally we'd do this for any register used in the first | |
4435 | insn group that's been written recently. */ | |
4436 | if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) | |
4437 | { | |
4438 | need_barrier = rws_access_regno (AR_LC_REGNUM, flags, 0); | |
4439 | if (need_barrier) | |
4440 | { | |
099dde21 | 4441 | emit_group_barrier_after (insn); |
9c668921 RH |
4442 | memset (rws_sum, 0, sizeof(rws_sum)); |
4443 | prev_insn = NULL_RTX; | |
4444 | } | |
4445 | } | |
6b6c1201 RH |
4446 | break; |
4447 | ||
4448 | case CALL_INSN: | |
4449 | flags.is_branch = 1; | |
2ed4af6f | 4450 | flags.is_sibcall = SIBLING_CALL_P (insn); |
6b6c1201 RH |
4451 | memset (rws_insn, 0, sizeof (rws_insn)); |
4452 | need_barrier = rtx_needs_barrier (PATTERN (insn), flags, 0); | |
c65ebc55 | 4453 | |
6b6c1201 RH |
4454 | if (need_barrier) |
4455 | { | |
4456 | /* PREV_INSN null can happen if the very first insn is a | |
4457 | volatile asm. */ | |
4458 | if (prev_insn) | |
099dde21 | 4459 | emit_group_barrier_after (prev_insn); |
6b6c1201 RH |
4460 | memcpy (rws_sum, rws_insn, sizeof (rws_sum)); |
4461 | } | |
c65ebc55 | 4462 | |
6b6c1201 RH |
4463 | /* A call must end a group, otherwise the assembler might pack |
4464 | it in with a following branch and then the function return | |
4465 | goes to the wrong place. Do this unconditionally for | |
4466 | unconditional calls, simply because it (1) looks nicer and | |
4467 | (2) keeps the data structures more accurate for the insns | |
4468 | following the call. */ | |
c65ebc55 | 4469 | |
6b6c1201 RH |
4470 | need_barrier = 1; |
4471 | if (GET_CODE (PATTERN (insn)) == COND_EXEC) | |
4472 | { | |
4473 | rtx next_insn = insn; | |
4474 | do | |
4475 | next_insn = next_nonnote_insn (next_insn); | |
4476 | while (next_insn | |
4477 | && GET_CODE (next_insn) == INSN | |
4478 | && (GET_CODE (PATTERN (next_insn)) == USE | |
4479 | || GET_CODE (PATTERN (next_insn)) == CLOBBER)); | |
4480 | if (next_insn && GET_CODE (next_insn) != JUMP_INSN) | |
4481 | need_barrier = 0; | |
4482 | } | |
4483 | if (need_barrier) | |
4484 | { | |
099dde21 | 4485 | emit_group_barrier_after (insn); |
6b6c1201 RH |
4486 | memset (rws_sum, 0, sizeof (rws_sum)); |
4487 | prev_insn = NULL_RTX; | |
c65ebc55 | 4488 | } |
f2f90c63 RH |
4489 | else |
4490 | prev_insn = insn; | |
c65ebc55 | 4491 | break; |
6b6c1201 | 4492 | |
c65ebc55 | 4493 | case JUMP_INSN: |
c65ebc55 | 4494 | flags.is_branch = 1; |
6b6c1201 RH |
4495 | /* FALLTHRU */ |
4496 | ||
c65ebc55 JW |
4497 | case INSN: |
4498 | if (GET_CODE (PATTERN (insn)) == USE) | |
4499 | /* Don't care about USE "insns"---those are used to | |
4500 | indicate to the optimizer that it shouldn't get rid of | |
4501 | certain operations. */ | |
4502 | break; | |
4503 | else | |
4504 | { | |
e57b9d65 RH |
4505 | rtx pat = PATTERN (insn); |
4506 | ||
870f9ec0 | 4507 | /* Ug. Hack hacks hacked elsewhere. */ |
f2f90c63 | 4508 | switch (recog_memoized (insn)) |
870f9ec0 RH |
4509 | { |
4510 | /* We play dependency tricks with the epilogue in order | |
4511 | to get proper schedules. Undo this for dv analysis. */ | |
4512 | case CODE_FOR_epilogue_deallocate_stack: | |
4513 | pat = XVECEXP (pat, 0, 0); | |
4514 | break; | |
4515 | ||
4516 | /* The pattern we use for br.cloop confuses the code above. | |
4517 | The second element of the vector is representative. */ | |
4518 | case CODE_FOR_doloop_end_internal: | |
4519 | pat = XVECEXP (pat, 0, 1); | |
4520 | break; | |
4521 | ||
f2f90c63 RH |
4522 | /* Doesn't generate code. */ |
4523 | case CODE_FOR_pred_rel_mutex: | |
4524 | continue; | |
4525 | ||
870f9ec0 RH |
4526 | default: |
4527 | break; | |
4528 | } | |
5527bf14 | 4529 | |
c65ebc55 | 4530 | memset (rws_insn, 0, sizeof (rws_insn)); |
e57b9d65 | 4531 | need_barrier |= rtx_needs_barrier (pat, flags, 0); |
c65ebc55 JW |
4532 | |
4533 | /* Check to see if the previous instruction was a volatile | |
4534 | asm. */ | |
4535 | if (! need_barrier) | |
97e242b0 | 4536 | need_barrier = rws_access_regno (REG_VOLATILE, flags, 0); |
c65ebc55 JW |
4537 | |
4538 | if (need_barrier) | |
4539 | { | |
4540 | /* PREV_INSN null can happen if the very first insn is a | |
4541 | volatile asm. */ | |
4542 | if (prev_insn) | |
099dde21 | 4543 | emit_group_barrier_after (prev_insn); |
c65ebc55 JW |
4544 | memcpy (rws_sum, rws_insn, sizeof (rws_sum)); |
4545 | } | |
c65ebc55 JW |
4546 | prev_insn = insn; |
4547 | } | |
4548 | break; | |
4549 | ||
4550 | case BARRIER: | |
4551 | /* A barrier doesn't imply an instruction group boundary. */ | |
4552 | break; | |
4553 | ||
4554 | case CODE_LABEL: | |
4555 | /* Leave prev_insn alone so the barrier gets generated in front | |
4556 | of the label, if one is needed. */ | |
4557 | break; | |
4558 | ||
4559 | default: | |
4560 | abort (); | |
4561 | } | |
4562 | } | |
4563 | } | |
4564 | ||
3b572406 RH |
4565 | /* Emit pseudo-ops for the assembler to describe predicate relations. |
4566 | At present this assumes that we only consider predicate pairs to | |
4567 | be mutex, and that the assembler can deduce proper values from | |
4568 | straight-line code. */ | |
4569 | ||
4570 | static void | |
f2f90c63 | 4571 | emit_predicate_relation_info () |
3b572406 RH |
4572 | { |
4573 | int i; | |
4574 | ||
3b572406 RH |
4575 | for (i = n_basic_blocks - 1; i >= 0; --i) |
4576 | { | |
4577 | basic_block bb = BASIC_BLOCK (i); | |
4578 | int r; | |
4579 | rtx head = bb->head; | |
4580 | ||
4581 | /* We only need such notes at code labels. */ | |
4582 | if (GET_CODE (head) != CODE_LABEL) | |
4583 | continue; | |
4584 | if (GET_CODE (NEXT_INSN (head)) == NOTE | |
4585 | && NOTE_LINE_NUMBER (NEXT_INSN (head)) == NOTE_INSN_BASIC_BLOCK) | |
4586 | head = NEXT_INSN (head); | |
4587 | ||
4588 | for (r = PR_REG (0); r < PR_REG (64); r += 2) | |
4589 | if (REGNO_REG_SET_P (bb->global_live_at_start, r)) | |
4590 | { | |
f2f90c63 | 4591 | rtx p = gen_rtx_REG (BImode, r); |
054451ea | 4592 | rtx n = emit_insn_after (gen_pred_rel_mutex (p), head); |
3b572406 RH |
4593 | if (head == bb->end) |
4594 | bb->end = n; | |
4595 | head = n; | |
4596 | } | |
4597 | } | |
ca3920ad JW |
4598 | |
4599 | /* Look for conditional calls that do not return, and protect predicate | |
4600 | relations around them. Otherwise the assembler will assume the call | |
4601 | returns, and complain about uses of call-clobbered predicates after | |
4602 | the call. */ | |
4603 | for (i = n_basic_blocks - 1; i >= 0; --i) | |
4604 | { | |
4605 | basic_block bb = BASIC_BLOCK (i); | |
4606 | rtx insn = bb->head; | |
4607 | ||
4608 | while (1) | |
4609 | { | |
4610 | if (GET_CODE (insn) == CALL_INSN | |
4611 | && GET_CODE (PATTERN (insn)) == COND_EXEC | |
4612 | && find_reg_note (insn, REG_NORETURN, NULL_RTX)) | |
4613 | { | |
4614 | rtx b = emit_insn_before (gen_safe_across_calls_all (), insn); | |
4615 | rtx a = emit_insn_after (gen_safe_across_calls_normal (), insn); | |
4616 | if (bb->head == insn) | |
4617 | bb->head = b; | |
4618 | if (bb->end == insn) | |
4619 | bb->end = a; | |
4620 | } | |
4621 | ||
4622 | if (insn == bb->end) | |
4623 | break; | |
4624 | insn = NEXT_INSN (insn); | |
4625 | } | |
4626 | } | |
3b572406 RH |
4627 | } |
4628 | ||
c65ebc55 JW |
4629 | /* Perform machine dependent operations on the rtl chain INSNS. */ |
4630 | ||
4631 | void | |
4632 | ia64_reorg (insns) | |
4633 | rtx insns; | |
4634 | { | |
9b7bf67d RH |
4635 | /* If optimizing, we'll have split before scheduling. */ |
4636 | if (optimize == 0) | |
4637 | split_all_insns (0); | |
4638 | ||
f2f90c63 RH |
4639 | /* Make sure the CFG and global_live_at_start are correct |
4640 | for emit_predicate_relation_info. */ | |
4641 | find_basic_blocks (insns, max_reg_num (), NULL); | |
4642 | life_analysis (insns, NULL, 0); | |
4643 | ||
c65ebc55 | 4644 | emit_insn_group_barriers (insns); |
f2f90c63 | 4645 | emit_predicate_relation_info (); |
c65ebc55 JW |
4646 | } |
4647 | \f | |
4648 | /* Return true if REGNO is used by the epilogue. */ | |
4649 | ||
4650 | int | |
4651 | ia64_epilogue_uses (regno) | |
4652 | int regno; | |
4653 | { | |
59da9a7d JW |
4654 | /* When a function makes a call through a function descriptor, we |
4655 | will write a (potentially) new value to "gp". After returning | |
4656 | from such a call, we need to make sure the function restores the | |
4657 | original gp-value, even if the function itself does not use the | |
4658 | gp anymore. */ | |
6b6c1201 RH |
4659 | if (regno == R_GR (1) |
4660 | && TARGET_CONST_GP | |
4661 | && !(TARGET_AUTO_PIC || TARGET_NO_PIC)) | |
59da9a7d JW |
4662 | return 1; |
4663 | ||
c65ebc55 JW |
4664 | /* For functions defined with the syscall_linkage attribute, all input |
4665 | registers are marked as live at all function exits. This prevents the | |
4666 | register allocator from using the input registers, which in turn makes it | |
4667 | possible to restart a system call after an interrupt without having to | |
4668 | save/restore the input registers. */ | |
4669 | ||
4670 | if (IN_REGNO_P (regno) | |
4671 | && (regno < IN_REG (current_function_args_info.words)) | |
4672 | && lookup_attribute ("syscall_linkage", | |
4673 | TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))) | |
4674 | return 1; | |
4675 | ||
6b6c1201 RH |
4676 | /* Conditional return patterns can't represent the use of `b0' as |
4677 | the return address, so we force the value live this way. */ | |
4678 | if (regno == R_BR (0)) | |
4679 | return 1; | |
4680 | ||
97e242b0 RH |
4681 | if (regs_ever_live[AR_LC_REGNUM] && regno == AR_LC_REGNUM) |
4682 | return 1; | |
4683 | if (! current_function_is_leaf && regno == AR_PFS_REGNUM) | |
4684 | return 1; | |
4685 | if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM) | |
4686 | && regno == AR_UNAT_REGNUM) | |
5527bf14 RH |
4687 | return 1; |
4688 | ||
c65ebc55 JW |
4689 | return 0; |
4690 | } | |
4691 | ||
4692 | /* Return true if IDENTIFIER is a valid attribute for TYPE. */ | |
4693 | ||
4694 | int | |
4695 | ia64_valid_type_attribute (type, attributes, identifier, args) | |
4696 | tree type; | |
4697 | tree attributes ATTRIBUTE_UNUSED; | |
4698 | tree identifier; | |
4699 | tree args; | |
4700 | { | |
4701 | /* We only support an attribute for function calls. */ | |
4702 | ||
4703 | if (TREE_CODE (type) != FUNCTION_TYPE | |
4704 | && TREE_CODE (type) != METHOD_TYPE) | |
4705 | return 0; | |
4706 | ||
4707 | /* The "syscall_linkage" attribute says the callee is a system call entry | |
4708 | point. This affects ia64_epilogue_uses. */ | |
4709 | ||
4710 | if (is_attribute_p ("syscall_linkage", identifier)) | |
4711 | return args == NULL_TREE; | |
4712 | ||
4713 | return 0; | |
4714 | } | |
4715 | \f | |
4716 | /* For ia64, SYMBOL_REF_FLAG set means that it is a function. | |
4717 | ||
4718 | We add @ to the name if this goes in small data/bss. We can only put | |
4719 | a variable in small data/bss if it is defined in this module or a module | |
4720 | that we are statically linked with. We can't check the second condition, | |
4721 | but TREE_STATIC gives us the first one. */ | |
4722 | ||
4723 | /* ??? If we had IPA, we could check the second condition. We could support | |
4724 | programmer added section attributes if the variable is not defined in this | |
4725 | module. */ | |
4726 | ||
4727 | /* ??? See the v850 port for a cleaner way to do this. */ | |
4728 | ||
4729 | /* ??? We could also support own long data here. Generating movl/add/ld8 | |
4730 | instead of addl,ld8/ld8. This makes the code bigger, but should make the | |
4731 | code faster because there is one less load. This also includes incomplete | |
4732 | types which can't go in sdata/sbss. */ | |
4733 | ||
4734 | /* ??? See select_section. We must put short own readonly variables in | |
4735 | sdata/sbss instead of the more natural rodata, because we can't perform | |
4736 | the DECL_READONLY_SECTION test here. */ | |
4737 | ||
4738 | extern struct obstack * saveable_obstack; | |
4739 | ||
4740 | void | |
4741 | ia64_encode_section_info (decl) | |
4742 | tree decl; | |
4743 | { | |
549f0725 RH |
4744 | const char *symbol_str; |
4745 | ||
c65ebc55 | 4746 | if (TREE_CODE (decl) == FUNCTION_DECL) |
549f0725 RH |
4747 | { |
4748 | SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1; | |
4749 | return; | |
4750 | } | |
4751 | ||
4752 | /* Careful not to prod global register variables. */ | |
4753 | if (TREE_CODE (decl) != VAR_DECL | |
3b572406 RH |
4754 | || GET_CODE (DECL_RTL (decl)) != MEM |
4755 | || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF) | |
549f0725 RH |
4756 | return; |
4757 | ||
4758 | symbol_str = XSTR (XEXP (DECL_RTL (decl), 0), 0); | |
4759 | ||
c65ebc55 JW |
4760 | /* We assume that -fpic is used only to create a shared library (dso). |
4761 | With -fpic, no global data can ever be sdata. | |
4762 | Without -fpic, global common uninitialized data can never be sdata, since | |
4763 | it can unify with a real definition in a dso. */ | |
4764 | /* ??? Actually, we can put globals in sdata, as long as we don't use gprel | |
4765 | to access them. The linker may then be able to do linker relaxation to | |
4766 | optimize references to them. Currently sdata implies use of gprel. */ | |
74fe26b2 JW |
4767 | /* We need the DECL_EXTERNAL check for C++. static class data members get |
4768 | both TREE_STATIC and DECL_EXTERNAL set, to indicate that they are | |
4769 | statically allocated, but the space is allocated somewhere else. Such | |
4770 | decls can not be own data. */ | |
549f0725 | 4771 | if (! TARGET_NO_SDATA |
74fe26b2 | 4772 | && TREE_STATIC (decl) && ! DECL_EXTERNAL (decl) |
549f0725 RH |
4773 | && ! (DECL_ONE_ONLY (decl) || DECL_WEAK (decl)) |
4774 | && ! (TREE_PUBLIC (decl) | |
4775 | && (flag_pic | |
4776 | || (DECL_COMMON (decl) | |
4777 | && (DECL_INITIAL (decl) == 0 | |
4778 | || DECL_INITIAL (decl) == error_mark_node)))) | |
4779 | /* Either the variable must be declared without a section attribute, | |
4780 | or the section must be sdata or sbss. */ | |
4781 | && (DECL_SECTION_NAME (decl) == 0 | |
4782 | || ! strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), | |
4783 | ".sdata") | |
4784 | || ! strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), | |
4785 | ".sbss"))) | |
c65ebc55 | 4786 | { |
97e242b0 | 4787 | HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl)); |
c65ebc55 | 4788 | |
59da9a7d JW |
4789 | /* If the variable has already been defined in the output file, then it |
4790 | is too late to put it in sdata if it wasn't put there in the first | |
4791 | place. The test is here rather than above, because if it is already | |
4792 | in sdata, then it can stay there. */ | |
809d4ef1 | 4793 | |
549f0725 | 4794 | if (TREE_ASM_WRITTEN (decl)) |
59da9a7d JW |
4795 | ; |
4796 | ||
c65ebc55 JW |
4797 | /* If this is an incomplete type with size 0, then we can't put it in |
4798 | sdata because it might be too big when completed. */ | |
97e242b0 RH |
4799 | else if (size > 0 |
4800 | && size <= (HOST_WIDE_INT) ia64_section_threshold | |
549f0725 | 4801 | && symbol_str[0] != SDATA_NAME_FLAG_CHAR) |
c65ebc55 | 4802 | { |
97e242b0 | 4803 | size_t len = strlen (symbol_str); |
520a57c8 | 4804 | char *newstr = alloca (len + 1); |
549f0725 | 4805 | |
c65ebc55 | 4806 | *newstr = SDATA_NAME_FLAG_CHAR; |
549f0725 | 4807 | memcpy (newstr + 1, symbol_str, len + 1); |
520a57c8 ZW |
4808 | |
4809 | newstr = ggc_alloc_string (newstr, len + 1); | |
c65ebc55 JW |
4810 | XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr; |
4811 | } | |
809d4ef1 | 4812 | } |
32adf8e6 AH |
4813 | /* This decl is marked as being in small data/bss but it shouldn't |
4814 | be; one likely explanation for this is that the decl has been | |
4815 | moved into a different section from the one it was in when | |
4816 | ENCODE_SECTION_INFO was first called. Remove the '@'.*/ | |
549f0725 | 4817 | else if (symbol_str[0] == SDATA_NAME_FLAG_CHAR) |
32adf8e6 | 4818 | { |
1f8f4a0b MM |
4819 | XSTR (XEXP (DECL_RTL (decl), 0), 0) |
4820 | = ggc_alloc_string (symbol_str + 1, -1); | |
c65ebc55 JW |
4821 | } |
4822 | } | |
0c96007e AM |
4823 | \f |
4824 | /* Output assmebly directives for prologue regions. */ | |
4825 | ||
0c96007e AM |
4826 | /* This function processes a SET pattern looking for specific patterns |
4827 | which result in emitting an assembly directive required for unwinding. */ | |
97e242b0 | 4828 | |
0c96007e AM |
4829 | static int |
4830 | process_set (asm_out_file, pat) | |
4831 | FILE *asm_out_file; | |
4832 | rtx pat; | |
4833 | { | |
4834 | rtx src = SET_SRC (pat); | |
4835 | rtx dest = SET_DEST (pat); | |
97e242b0 | 4836 | int src_regno, dest_regno; |
0c96007e | 4837 | |
97e242b0 RH |
4838 | /* Look for the ALLOC insn. */ |
4839 | if (GET_CODE (src) == UNSPEC_VOLATILE | |
4840 | && XINT (src, 1) == 0 | |
4841 | && GET_CODE (dest) == REG) | |
0c96007e | 4842 | { |
97e242b0 RH |
4843 | dest_regno = REGNO (dest); |
4844 | ||
4845 | /* If this isn't the final destination for ar.pfs, the alloc | |
4846 | shouldn't have been marked frame related. */ | |
4847 | if (dest_regno != current_frame_info.reg_save_ar_pfs) | |
4848 | abort (); | |
4849 | ||
809d4ef1 | 4850 | fprintf (asm_out_file, "\t.save ar.pfs, r%d\n", |
97e242b0 | 4851 | ia64_dbx_register_number (dest_regno)); |
0c96007e AM |
4852 | return 1; |
4853 | } | |
4854 | ||
97e242b0 | 4855 | /* Look for SP = .... */ |
0c96007e AM |
4856 | if (GET_CODE (dest) == REG && REGNO (dest) == STACK_POINTER_REGNUM) |
4857 | { | |
4858 | if (GET_CODE (src) == PLUS) | |
4859 | { | |
4860 | rtx op0 = XEXP (src, 0); | |
4861 | rtx op1 = XEXP (src, 1); | |
4862 | if (op0 == dest && GET_CODE (op1) == CONST_INT) | |
4863 | { | |
0186257f JW |
4864 | if (INTVAL (op1) < 0) |
4865 | { | |
4866 | fputs ("\t.fframe ", asm_out_file); | |
4867 | fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, | |
4868 | -INTVAL (op1)); | |
4869 | fputc ('\n', asm_out_file); | |
0186257f JW |
4870 | } |
4871 | else | |
4872 | fprintf (asm_out_file, "\t.restore sp\n"); | |
0c96007e | 4873 | } |
0186257f JW |
4874 | else |
4875 | abort (); | |
0c96007e | 4876 | } |
97e242b0 RH |
4877 | else if (GET_CODE (src) == REG |
4878 | && REGNO (src) == HARD_FRAME_POINTER_REGNUM) | |
0186257f JW |
4879 | fprintf (asm_out_file, "\t.restore sp\n"); |
4880 | else | |
4881 | abort (); | |
4882 | ||
4883 | return 1; | |
0c96007e | 4884 | } |
0c96007e AM |
4885 | |
4886 | /* Register move we need to look at. */ | |
4887 | if (GET_CODE (dest) == REG && GET_CODE (src) == REG) | |
4888 | { | |
97e242b0 RH |
4889 | src_regno = REGNO (src); |
4890 | dest_regno = REGNO (dest); | |
4891 | ||
4892 | switch (src_regno) | |
4893 | { | |
4894 | case BR_REG (0): | |
0c96007e | 4895 | /* Saving return address pointer. */ |
97e242b0 RH |
4896 | if (dest_regno != current_frame_info.reg_save_b0) |
4897 | abort (); | |
4898 | fprintf (asm_out_file, "\t.save rp, r%d\n", | |
4899 | ia64_dbx_register_number (dest_regno)); | |
4900 | return 1; | |
4901 | ||
4902 | case PR_REG (0): | |
4903 | if (dest_regno != current_frame_info.reg_save_pr) | |
4904 | abort (); | |
4905 | fprintf (asm_out_file, "\t.save pr, r%d\n", | |
4906 | ia64_dbx_register_number (dest_regno)); | |
4907 | return 1; | |
4908 | ||
4909 | case AR_UNAT_REGNUM: | |
4910 | if (dest_regno != current_frame_info.reg_save_ar_unat) | |
4911 | abort (); | |
4912 | fprintf (asm_out_file, "\t.save ar.unat, r%d\n", | |
4913 | ia64_dbx_register_number (dest_regno)); | |
4914 | return 1; | |
4915 | ||
4916 | case AR_LC_REGNUM: | |
4917 | if (dest_regno != current_frame_info.reg_save_ar_lc) | |
4918 | abort (); | |
4919 | fprintf (asm_out_file, "\t.save ar.lc, r%d\n", | |
4920 | ia64_dbx_register_number (dest_regno)); | |
4921 | return 1; | |
4922 | ||
4923 | case STACK_POINTER_REGNUM: | |
4924 | if (dest_regno != HARD_FRAME_POINTER_REGNUM | |
4925 | || ! frame_pointer_needed) | |
4926 | abort (); | |
4927 | fprintf (asm_out_file, "\t.vframe r%d\n", | |
4928 | ia64_dbx_register_number (dest_regno)); | |
4929 | return 1; | |
4930 | ||
4931 | default: | |
4932 | /* Everything else should indicate being stored to memory. */ | |
4933 | abort (); | |
0c96007e AM |
4934 | } |
4935 | } | |
97e242b0 RH |
4936 | |
4937 | /* Memory store we need to look at. */ | |
4938 | if (GET_CODE (dest) == MEM && GET_CODE (src) == REG) | |
0c96007e | 4939 | { |
97e242b0 RH |
4940 | long off; |
4941 | rtx base; | |
4942 | const char *saveop; | |
4943 | ||
4944 | if (GET_CODE (XEXP (dest, 0)) == REG) | |
0c96007e | 4945 | { |
97e242b0 RH |
4946 | base = XEXP (dest, 0); |
4947 | off = 0; | |
0c96007e | 4948 | } |
97e242b0 RH |
4949 | else if (GET_CODE (XEXP (dest, 0)) == PLUS |
4950 | && GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT) | |
0c96007e | 4951 | { |
97e242b0 RH |
4952 | base = XEXP (XEXP (dest, 0), 0); |
4953 | off = INTVAL (XEXP (XEXP (dest, 0), 1)); | |
0c96007e | 4954 | } |
97e242b0 RH |
4955 | else |
4956 | abort (); | |
0c96007e | 4957 | |
97e242b0 RH |
4958 | if (base == hard_frame_pointer_rtx) |
4959 | { | |
4960 | saveop = ".savepsp"; | |
4961 | off = - off; | |
4962 | } | |
4963 | else if (base == stack_pointer_rtx) | |
4964 | saveop = ".savesp"; | |
4965 | else | |
4966 | abort (); | |
4967 | ||
4968 | src_regno = REGNO (src); | |
4969 | switch (src_regno) | |
4970 | { | |
4971 | case BR_REG (0): | |
4972 | if (current_frame_info.reg_save_b0 != 0) | |
4973 | abort (); | |
4974 | fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off); | |
4975 | return 1; | |
4976 | ||
4977 | case PR_REG (0): | |
4978 | if (current_frame_info.reg_save_pr != 0) | |
4979 | abort (); | |
4980 | fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off); | |
4981 | return 1; | |
4982 | ||
4983 | case AR_LC_REGNUM: | |
4984 | if (current_frame_info.reg_save_ar_lc != 0) | |
4985 | abort (); | |
4986 | fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off); | |
4987 | return 1; | |
4988 | ||
4989 | case AR_PFS_REGNUM: | |
4990 | if (current_frame_info.reg_save_ar_pfs != 0) | |
4991 | abort (); | |
4992 | fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off); | |
4993 | return 1; | |
4994 | ||
4995 | case AR_UNAT_REGNUM: | |
4996 | if (current_frame_info.reg_save_ar_unat != 0) | |
4997 | abort (); | |
4998 | fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off); | |
4999 | return 1; | |
5000 | ||
5001 | case GR_REG (4): | |
5002 | case GR_REG (5): | |
5003 | case GR_REG (6): | |
5004 | case GR_REG (7): | |
5005 | fprintf (asm_out_file, "\t.save.g 0x%x\n", | |
5006 | 1 << (src_regno - GR_REG (4))); | |
97e242b0 RH |
5007 | return 1; |
5008 | ||
5009 | case BR_REG (1): | |
5010 | case BR_REG (2): | |
5011 | case BR_REG (3): | |
5012 | case BR_REG (4): | |
5013 | case BR_REG (5): | |
5014 | fprintf (asm_out_file, "\t.save.b 0x%x\n", | |
5015 | 1 << (src_regno - BR_REG (1))); | |
0c96007e | 5016 | return 1; |
97e242b0 RH |
5017 | |
5018 | case FR_REG (2): | |
5019 | case FR_REG (3): | |
5020 | case FR_REG (4): | |
5021 | case FR_REG (5): | |
5022 | fprintf (asm_out_file, "\t.save.f 0x%x\n", | |
5023 | 1 << (src_regno - FR_REG (2))); | |
5024 | return 1; | |
5025 | ||
5026 | case FR_REG (16): case FR_REG (17): case FR_REG (18): case FR_REG (19): | |
5027 | case FR_REG (20): case FR_REG (21): case FR_REG (22): case FR_REG (23): | |
5028 | case FR_REG (24): case FR_REG (25): case FR_REG (26): case FR_REG (27): | |
5029 | case FR_REG (28): case FR_REG (29): case FR_REG (30): case FR_REG (31): | |
5030 | fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n", | |
5031 | 1 << (src_regno - FR_REG (12))); | |
5032 | return 1; | |
5033 | ||
5034 | default: | |
5035 | return 0; | |
0c96007e AM |
5036 | } |
5037 | } | |
97e242b0 | 5038 | |
0c96007e AM |
5039 | return 0; |
5040 | } | |
5041 | ||
5042 | ||
5043 | /* This function looks at a single insn and emits any directives | |
5044 | required to unwind this insn. */ | |
5045 | void | |
5046 | process_for_unwind_directive (asm_out_file, insn) | |
5047 | FILE *asm_out_file; | |
5048 | rtx insn; | |
5049 | { | |
809d4ef1 | 5050 | if ((flag_unwind_tables |
0c96007e AM |
5051 | || (flag_exceptions && !exceptions_via_longjmp)) |
5052 | && RTX_FRAME_RELATED_P (insn)) | |
5053 | { | |
97e242b0 RH |
5054 | rtx pat; |
5055 | ||
5056 | pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX); | |
5057 | if (pat) | |
5058 | pat = XEXP (pat, 0); | |
5059 | else | |
5060 | pat = PATTERN (insn); | |
0c96007e AM |
5061 | |
5062 | switch (GET_CODE (pat)) | |
5063 | { | |
809d4ef1 RH |
5064 | case SET: |
5065 | process_set (asm_out_file, pat); | |
5066 | break; | |
5067 | ||
5068 | case PARALLEL: | |
5069 | { | |
5070 | int par_index; | |
5071 | int limit = XVECLEN (pat, 0); | |
5072 | for (par_index = 0; par_index < limit; par_index++) | |
5073 | { | |
5074 | rtx x = XVECEXP (pat, 0, par_index); | |
5075 | if (GET_CODE (x) == SET) | |
5076 | process_set (asm_out_file, x); | |
5077 | } | |
5078 | break; | |
5079 | } | |
5080 | ||
5081 | default: | |
5082 | abort (); | |
0c96007e AM |
5083 | } |
5084 | } | |
5085 | } | |
c65ebc55 | 5086 | |
0551c32d | 5087 | \f |
c65ebc55 JW |
5088 | void |
5089 | ia64_init_builtins () | |
5090 | { | |
c65ebc55 JW |
5091 | tree psi_type_node = build_pointer_type (integer_type_node); |
5092 | tree pdi_type_node = build_pointer_type (long_integer_type_node); | |
5093 | tree endlink = tree_cons (NULL_TREE, void_type_node, NULL_TREE); | |
5094 | ||
c65ebc55 JW |
5095 | /* __sync_val_compare_and_swap_si, __sync_bool_compare_and_swap_si */ |
5096 | tree si_ftype_psi_si_si | |
5097 | = build_function_type (integer_type_node, | |
5098 | tree_cons (NULL_TREE, psi_type_node, | |
5099 | tree_cons (NULL_TREE, integer_type_node, | |
3b572406 RH |
5100 | tree_cons (NULL_TREE, |
5101 | integer_type_node, | |
c65ebc55 JW |
5102 | endlink)))); |
5103 | ||
5104 | /* __sync_val_compare_and_swap_di, __sync_bool_compare_and_swap_di */ | |
5105 | tree di_ftype_pdi_di_di | |
5106 | = build_function_type (long_integer_type_node, | |
5107 | tree_cons (NULL_TREE, pdi_type_node, | |
3b572406 RH |
5108 | tree_cons (NULL_TREE, |
5109 | long_integer_type_node, | |
5110 | tree_cons (NULL_TREE, | |
0551c32d RH |
5111 | long_integer_type_node, |
5112 | endlink)))); | |
c65ebc55 JW |
5113 | /* __sync_synchronize */ |
5114 | tree void_ftype_void | |
5115 | = build_function_type (void_type_node, endlink); | |
5116 | ||
5117 | /* __sync_lock_test_and_set_si */ | |
5118 | tree si_ftype_psi_si | |
5119 | = build_function_type (integer_type_node, | |
5120 | tree_cons (NULL_TREE, psi_type_node, | |
5121 | tree_cons (NULL_TREE, integer_type_node, endlink))); | |
5122 | ||
5123 | /* __sync_lock_test_and_set_di */ | |
5124 | tree di_ftype_pdi_di | |
809d4ef1 | 5125 | = build_function_type (long_integer_type_node, |
c65ebc55 | 5126 | tree_cons (NULL_TREE, pdi_type_node, |
3b572406 RH |
5127 | tree_cons (NULL_TREE, long_integer_type_node, |
5128 | endlink))); | |
c65ebc55 JW |
5129 | |
5130 | /* __sync_lock_release_si */ | |
5131 | tree void_ftype_psi | |
3b572406 RH |
5132 | = build_function_type (void_type_node, tree_cons (NULL_TREE, psi_type_node, |
5133 | endlink)); | |
c65ebc55 JW |
5134 | |
5135 | /* __sync_lock_release_di */ | |
5136 | tree void_ftype_pdi | |
3b572406 RH |
5137 | = build_function_type (void_type_node, tree_cons (NULL_TREE, pdi_type_node, |
5138 | endlink)); | |
c65ebc55 | 5139 | |
0551c32d RH |
5140 | #define def_builtin(name, type, code) \ |
5141 | builtin_function ((name), (type), (code), BUILT_IN_MD, NULL_PTR) | |
5142 | ||
3b572406 RH |
5143 | def_builtin ("__sync_val_compare_and_swap_si", si_ftype_psi_si_si, |
5144 | IA64_BUILTIN_VAL_COMPARE_AND_SWAP_SI); | |
3b572406 RH |
5145 | def_builtin ("__sync_val_compare_and_swap_di", di_ftype_pdi_di_di, |
5146 | IA64_BUILTIN_VAL_COMPARE_AND_SWAP_DI); | |
3b572406 RH |
5147 | def_builtin ("__sync_bool_compare_and_swap_si", si_ftype_psi_si_si, |
5148 | IA64_BUILTIN_BOOL_COMPARE_AND_SWAP_SI); | |
3b572406 RH |
5149 | def_builtin ("__sync_bool_compare_and_swap_di", di_ftype_pdi_di_di, |
5150 | IA64_BUILTIN_BOOL_COMPARE_AND_SWAP_DI); | |
c65ebc55 | 5151 | |
3b572406 RH |
5152 | def_builtin ("__sync_synchronize", void_ftype_void, |
5153 | IA64_BUILTIN_SYNCHRONIZE); | |
c65ebc55 | 5154 | |
3b572406 RH |
5155 | def_builtin ("__sync_lock_test_and_set_si", si_ftype_psi_si, |
5156 | IA64_BUILTIN_LOCK_TEST_AND_SET_SI); | |
3b572406 RH |
5157 | def_builtin ("__sync_lock_test_and_set_di", di_ftype_pdi_di, |
5158 | IA64_BUILTIN_LOCK_TEST_AND_SET_DI); | |
3b572406 RH |
5159 | def_builtin ("__sync_lock_release_si", void_ftype_psi, |
5160 | IA64_BUILTIN_LOCK_RELEASE_SI); | |
3b572406 RH |
5161 | def_builtin ("__sync_lock_release_di", void_ftype_pdi, |
5162 | IA64_BUILTIN_LOCK_RELEASE_DI); | |
c65ebc55 | 5163 | |
3b572406 RH |
5164 | def_builtin ("__builtin_ia64_bsp", |
5165 | build_function_type (ptr_type_node, endlink), | |
5166 | IA64_BUILTIN_BSP); | |
ce152ef8 AM |
5167 | |
5168 | def_builtin ("__builtin_ia64_flushrs", | |
5169 | build_function_type (void_type_node, endlink), | |
5170 | IA64_BUILTIN_FLUSHRS); | |
5171 | ||
0551c32d RH |
5172 | def_builtin ("__sync_fetch_and_add_si", si_ftype_psi_si, |
5173 | IA64_BUILTIN_FETCH_AND_ADD_SI); | |
5174 | def_builtin ("__sync_fetch_and_sub_si", si_ftype_psi_si, | |
5175 | IA64_BUILTIN_FETCH_AND_SUB_SI); | |
5176 | def_builtin ("__sync_fetch_and_or_si", si_ftype_psi_si, | |
5177 | IA64_BUILTIN_FETCH_AND_OR_SI); | |
5178 | def_builtin ("__sync_fetch_and_and_si", si_ftype_psi_si, | |
5179 | IA64_BUILTIN_FETCH_AND_AND_SI); | |
5180 | def_builtin ("__sync_fetch_and_xor_si", si_ftype_psi_si, | |
5181 | IA64_BUILTIN_FETCH_AND_XOR_SI); | |
5182 | def_builtin ("__sync_fetch_and_nand_si", si_ftype_psi_si, | |
5183 | IA64_BUILTIN_FETCH_AND_NAND_SI); | |
5184 | ||
5185 | def_builtin ("__sync_add_and_fetch_si", si_ftype_psi_si, | |
5186 | IA64_BUILTIN_ADD_AND_FETCH_SI); | |
5187 | def_builtin ("__sync_sub_and_fetch_si", si_ftype_psi_si, | |
5188 | IA64_BUILTIN_SUB_AND_FETCH_SI); | |
5189 | def_builtin ("__sync_or_and_fetch_si", si_ftype_psi_si, | |
5190 | IA64_BUILTIN_OR_AND_FETCH_SI); | |
5191 | def_builtin ("__sync_and_and_fetch_si", si_ftype_psi_si, | |
5192 | IA64_BUILTIN_AND_AND_FETCH_SI); | |
5193 | def_builtin ("__sync_xor_and_fetch_si", si_ftype_psi_si, | |
5194 | IA64_BUILTIN_XOR_AND_FETCH_SI); | |
5195 | def_builtin ("__sync_nand_and_fetch_si", si_ftype_psi_si, | |
5196 | IA64_BUILTIN_NAND_AND_FETCH_SI); | |
5197 | ||
5198 | def_builtin ("__sync_fetch_and_add_di", di_ftype_pdi_di, | |
5199 | IA64_BUILTIN_FETCH_AND_ADD_DI); | |
5200 | def_builtin ("__sync_fetch_and_sub_di", di_ftype_pdi_di, | |
5201 | IA64_BUILTIN_FETCH_AND_SUB_DI); | |
5202 | def_builtin ("__sync_fetch_and_or_di", di_ftype_pdi_di, | |
5203 | IA64_BUILTIN_FETCH_AND_OR_DI); | |
5204 | def_builtin ("__sync_fetch_and_and_di", di_ftype_pdi_di, | |
5205 | IA64_BUILTIN_FETCH_AND_AND_DI); | |
5206 | def_builtin ("__sync_fetch_and_xor_di", di_ftype_pdi_di, | |
5207 | IA64_BUILTIN_FETCH_AND_XOR_DI); | |
5208 | def_builtin ("__sync_fetch_and_nand_di", di_ftype_pdi_di, | |
5209 | IA64_BUILTIN_FETCH_AND_NAND_DI); | |
5210 | ||
5211 | def_builtin ("__sync_add_and_fetch_di", di_ftype_pdi_di, | |
5212 | IA64_BUILTIN_ADD_AND_FETCH_DI); | |
5213 | def_builtin ("__sync_sub_and_fetch_di", di_ftype_pdi_di, | |
5214 | IA64_BUILTIN_SUB_AND_FETCH_DI); | |
5215 | def_builtin ("__sync_or_and_fetch_di", di_ftype_pdi_di, | |
5216 | IA64_BUILTIN_OR_AND_FETCH_DI); | |
5217 | def_builtin ("__sync_and_and_fetch_di", di_ftype_pdi_di, | |
5218 | IA64_BUILTIN_AND_AND_FETCH_DI); | |
5219 | def_builtin ("__sync_xor_and_fetch_di", di_ftype_pdi_di, | |
5220 | IA64_BUILTIN_XOR_AND_FETCH_DI); | |
5221 | def_builtin ("__sync_nand_and_fetch_di", di_ftype_pdi_di, | |
5222 | IA64_BUILTIN_NAND_AND_FETCH_DI); | |
5223 | ||
5224 | #undef def_builtin | |
c65ebc55 JW |
5225 | } |
5226 | ||
5227 | /* Expand fetch_and_op intrinsics. The basic code sequence is: | |
5228 | ||
5229 | mf | |
0551c32d | 5230 | tmp = [ptr]; |
c65ebc55 | 5231 | do { |
0551c32d | 5232 | ret = tmp; |
c65ebc55 JW |
5233 | ar.ccv = tmp; |
5234 | tmp <op>= value; | |
5235 | cmpxchgsz.acq tmp = [ptr], tmp | |
0551c32d | 5236 | } while (tmp != ret) |
c65ebc55 | 5237 | */ |
0551c32d RH |
5238 | |
5239 | static rtx | |
5240 | ia64_expand_fetch_and_op (binoptab, mode, arglist, target) | |
5241 | optab binoptab; | |
c65ebc55 | 5242 | enum machine_mode mode; |
0551c32d RH |
5243 | tree arglist; |
5244 | rtx target; | |
c65ebc55 | 5245 | { |
0551c32d RH |
5246 | rtx ret, label, tmp, ccv, insn, mem, value; |
5247 | tree arg0, arg1; | |
97e242b0 | 5248 | |
0551c32d RH |
5249 | arg0 = TREE_VALUE (arglist); |
5250 | arg1 = TREE_VALUE (TREE_CHAIN (arglist)); | |
5251 | mem = expand_expr (arg0, NULL_RTX, Pmode, 0); | |
5252 | value = expand_expr (arg1, NULL_RTX, mode, 0); | |
c65ebc55 | 5253 | |
0551c32d RH |
5254 | mem = gen_rtx_MEM (mode, force_reg (Pmode, mem)); |
5255 | MEM_VOLATILE_P (mem) = 1; | |
c65ebc55 | 5256 | |
0551c32d RH |
5257 | if (target && register_operand (target, mode)) |
5258 | ret = target; | |
5259 | else | |
5260 | ret = gen_reg_rtx (mode); | |
c65ebc55 | 5261 | |
0551c32d RH |
5262 | emit_insn (gen_mf ()); |
5263 | ||
5264 | /* Special case for fetchadd instructions. */ | |
5265 | if (binoptab == add_optab && fetchadd_operand (value, VOIDmode)) | |
c65ebc55 | 5266 | { |
c65ebc55 | 5267 | if (mode == SImode) |
0551c32d | 5268 | insn = gen_fetchadd_acq_si (ret, mem, value); |
c65ebc55 | 5269 | else |
0551c32d RH |
5270 | insn = gen_fetchadd_acq_di (ret, mem, value); |
5271 | emit_insn (insn); | |
5272 | return ret; | |
c65ebc55 JW |
5273 | } |
5274 | ||
0551c32d RH |
5275 | tmp = gen_reg_rtx (mode); |
5276 | ccv = gen_rtx_REG (mode, AR_CCV_REGNUM); | |
5277 | emit_move_insn (tmp, mem); | |
5278 | ||
5279 | label = gen_label_rtx (); | |
5280 | emit_label (label); | |
5281 | emit_move_insn (ret, tmp); | |
5282 | emit_move_insn (ccv, tmp); | |
5283 | ||
5284 | /* Perform the specific operation. Special case NAND by noticing | |
5285 | one_cmpl_optab instead. */ | |
5286 | if (binoptab == one_cmpl_optab) | |
5287 | { | |
5288 | tmp = expand_unop (mode, binoptab, tmp, NULL, OPTAB_WIDEN); | |
5289 | binoptab = and_optab; | |
5290 | } | |
5291 | tmp = expand_binop (mode, binoptab, tmp, value, tmp, 1, OPTAB_WIDEN); | |
809d4ef1 RH |
5292 | |
5293 | if (mode == SImode) | |
0551c32d | 5294 | insn = gen_cmpxchg_acq_si (tmp, mem, tmp, ccv); |
c65ebc55 | 5295 | else |
0551c32d RH |
5296 | insn = gen_cmpxchg_acq_di (tmp, mem, tmp, ccv); |
5297 | emit_insn (insn); | |
5298 | ||
5299 | emit_cmp_and_jump_insns (tmp, ret, NE, 0, mode, 1, 0, label); | |
c65ebc55 | 5300 | |
0551c32d | 5301 | return ret; |
c65ebc55 JW |
5302 | } |
5303 | ||
5304 | /* Expand op_and_fetch intrinsics. The basic code sequence is: | |
5305 | ||
5306 | mf | |
0551c32d | 5307 | tmp = [ptr]; |
c65ebc55 | 5308 | do { |
0551c32d | 5309 | old = tmp; |
c65ebc55 | 5310 | ar.ccv = tmp; |
0551c32d RH |
5311 | ret = tmp + value; |
5312 | cmpxchgsz.acq tmp = [ptr], ret | |
5313 | } while (tmp != old) | |
c65ebc55 | 5314 | */ |
0551c32d RH |
5315 | |
5316 | static rtx | |
5317 | ia64_expand_op_and_fetch (binoptab, mode, arglist, target) | |
5318 | optab binoptab; | |
c65ebc55 | 5319 | enum machine_mode mode; |
0551c32d RH |
5320 | tree arglist; |
5321 | rtx target; | |
c65ebc55 | 5322 | { |
0551c32d RH |
5323 | rtx old, label, tmp, ret, ccv, insn, mem, value; |
5324 | tree arg0, arg1; | |
5325 | ||
5326 | arg0 = TREE_VALUE (arglist); | |
5327 | arg1 = TREE_VALUE (TREE_CHAIN (arglist)); | |
5328 | mem = expand_expr (arg0, NULL_RTX, Pmode, 0); | |
5329 | value = expand_expr (arg1, NULL_RTX, mode, 0); | |
c65ebc55 | 5330 | |
0551c32d RH |
5331 | mem = gen_rtx_MEM (mode, force_reg (Pmode, mem)); |
5332 | MEM_VOLATILE_P (mem) = 1; | |
5333 | ||
5334 | if (target && ! register_operand (target, mode)) | |
5335 | target = NULL_RTX; | |
5336 | ||
5337 | emit_insn (gen_mf ()); | |
5338 | tmp = gen_reg_rtx (mode); | |
5339 | old = gen_reg_rtx (mode); | |
97e242b0 RH |
5340 | ccv = gen_rtx_REG (mode, AR_CCV_REGNUM); |
5341 | ||
0551c32d | 5342 | emit_move_insn (tmp, mem); |
c65ebc55 | 5343 | |
0551c32d RH |
5344 | label = gen_label_rtx (); |
5345 | emit_label (label); | |
5346 | emit_move_insn (old, tmp); | |
5347 | emit_move_insn (ccv, tmp); | |
c65ebc55 | 5348 | |
0551c32d RH |
5349 | /* Perform the specific operation. Special case NAND by noticing |
5350 | one_cmpl_optab instead. */ | |
5351 | if (binoptab == one_cmpl_optab) | |
5352 | { | |
5353 | tmp = expand_unop (mode, binoptab, tmp, NULL, OPTAB_WIDEN); | |
5354 | binoptab = and_optab; | |
5355 | } | |
5356 | ret = expand_binop (mode, binoptab, tmp, value, target, 1, OPTAB_WIDEN); | |
809d4ef1 RH |
5357 | |
5358 | if (mode == SImode) | |
0551c32d | 5359 | insn = gen_cmpxchg_acq_si (tmp, mem, ret, ccv); |
c65ebc55 | 5360 | else |
0551c32d RH |
5361 | insn = gen_cmpxchg_acq_di (tmp, mem, ret, ccv); |
5362 | emit_insn (insn); | |
5363 | ||
5364 | emit_cmp_and_jump_insns (tmp, old, NE, 0, mode, 1, 0, label); | |
c65ebc55 | 5365 | |
0551c32d | 5366 | return ret; |
c65ebc55 JW |
5367 | } |
5368 | ||
5369 | /* Expand val_ and bool_compare_and_swap. For val_ we want: | |
5370 | ||
5371 | ar.ccv = oldval | |
5372 | mf | |
5373 | cmpxchgsz.acq ret = [ptr], newval, ar.ccv | |
5374 | return ret | |
5375 | ||
5376 | For bool_ it's the same except return ret == oldval. | |
5377 | */ | |
0551c32d | 5378 | |
c65ebc55 | 5379 | static rtx |
0551c32d RH |
5380 | ia64_expand_compare_and_swap (mode, boolp, arglist, target) |
5381 | enum machine_mode mode; | |
5382 | int boolp; | |
c65ebc55 JW |
5383 | tree arglist; |
5384 | rtx target; | |
c65ebc55 JW |
5385 | { |
5386 | tree arg0, arg1, arg2; | |
0551c32d | 5387 | rtx mem, old, new, ccv, tmp, insn; |
809d4ef1 | 5388 | |
c65ebc55 JW |
5389 | arg0 = TREE_VALUE (arglist); |
5390 | arg1 = TREE_VALUE (TREE_CHAIN (arglist)); | |
5391 | arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); | |
0551c32d RH |
5392 | mem = expand_expr (arg0, NULL_RTX, Pmode, 0); |
5393 | old = expand_expr (arg1, NULL_RTX, mode, 0); | |
5394 | new = expand_expr (arg2, NULL_RTX, mode, 0); | |
5395 | ||
5396 | mem = gen_rtx_MEM (mode, force_reg (Pmode, mem)); | |
5397 | MEM_VOLATILE_P (mem) = 1; | |
5398 | ||
5399 | if (! register_operand (old, mode)) | |
5400 | old = copy_to_mode_reg (mode, old); | |
5401 | if (! register_operand (new, mode)) | |
5402 | new = copy_to_mode_reg (mode, new); | |
5403 | ||
5404 | if (! boolp && target && register_operand (target, mode)) | |
5405 | tmp = target; | |
5406 | else | |
5407 | tmp = gen_reg_rtx (mode); | |
5408 | ||
5409 | ccv = gen_rtx_REG (mode, AR_CCV_REGNUM); | |
5410 | emit_move_insn (ccv, old); | |
5411 | emit_insn (gen_mf ()); | |
5412 | if (mode == SImode) | |
5413 | insn = gen_cmpxchg_acq_si (tmp, mem, new, ccv); | |
5414 | else | |
5415 | insn = gen_cmpxchg_acq_di (tmp, mem, new, ccv); | |
5416 | emit_insn (insn); | |
5417 | ||
5418 | if (boolp) | |
c65ebc55 | 5419 | { |
0551c32d RH |
5420 | if (! target) |
5421 | target = gen_reg_rtx (mode); | |
5422 | return emit_store_flag_force (target, EQ, tmp, old, mode, 1, 1); | |
c65ebc55 | 5423 | } |
0551c32d RH |
5424 | else |
5425 | return tmp; | |
c65ebc55 JW |
5426 | } |
5427 | ||
0551c32d RH |
5428 | /* Expand lock_test_and_set. I.e. `xchgsz ret = [ptr], new'. */ |
5429 | ||
c65ebc55 | 5430 | static rtx |
0551c32d RH |
5431 | ia64_expand_lock_test_and_set (mode, arglist, target) |
5432 | enum machine_mode mode; | |
c65ebc55 JW |
5433 | tree arglist; |
5434 | rtx target; | |
5435 | { | |
0551c32d RH |
5436 | tree arg0, arg1; |
5437 | rtx mem, new, ret, insn; | |
5438 | ||
5439 | arg0 = TREE_VALUE (arglist); | |
5440 | arg1 = TREE_VALUE (TREE_CHAIN (arglist)); | |
5441 | mem = expand_expr (arg0, NULL_RTX, Pmode, 0); | |
5442 | new = expand_expr (arg1, NULL_RTX, mode, 0); | |
5443 | ||
5444 | mem = gen_rtx_MEM (mode, force_reg (Pmode, mem)); | |
5445 | MEM_VOLATILE_P (mem) = 1; | |
5446 | if (! register_operand (new, mode)) | |
5447 | new = copy_to_mode_reg (mode, new); | |
5448 | ||
5449 | if (target && register_operand (target, mode)) | |
5450 | ret = target; | |
5451 | else | |
5452 | ret = gen_reg_rtx (mode); | |
5453 | ||
5454 | if (mode == SImode) | |
5455 | insn = gen_xchgsi (ret, mem, new); | |
5456 | else | |
5457 | insn = gen_xchgdi (ret, mem, new); | |
5458 | emit_insn (insn); | |
5459 | ||
5460 | return ret; | |
5461 | } | |
5462 | ||
5463 | /* Expand lock_release. I.e. `stsz.rel [ptr] = r0'. */ | |
5464 | ||
5465 | static rtx | |
5466 | ia64_expand_lock_release (mode, arglist, target) | |
5467 | enum machine_mode mode; | |
5468 | tree arglist; | |
5469 | rtx target ATTRIBUTE_UNUSED; | |
5470 | { | |
5471 | tree arg0; | |
5472 | rtx mem; | |
5473 | ||
5474 | arg0 = TREE_VALUE (arglist); | |
5475 | mem = expand_expr (arg0, NULL_RTX, Pmode, 0); | |
5476 | ||
5477 | mem = gen_rtx_MEM (mode, force_reg (Pmode, mem)); | |
5478 | MEM_VOLATILE_P (mem) = 1; | |
5479 | ||
5480 | emit_move_insn (mem, const0_rtx); | |
5481 | ||
5482 | return const0_rtx; | |
c65ebc55 JW |
5483 | } |
5484 | ||
5485 | rtx | |
5486 | ia64_expand_builtin (exp, target, subtarget, mode, ignore) | |
5487 | tree exp; | |
5488 | rtx target; | |
fd7c34b0 RH |
5489 | rtx subtarget ATTRIBUTE_UNUSED; |
5490 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
5491 | int ignore ATTRIBUTE_UNUSED; | |
c65ebc55 | 5492 | { |
c65ebc55 | 5493 | tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); |
97e242b0 | 5494 | unsigned int fcode = DECL_FUNCTION_CODE (fndecl); |
0551c32d | 5495 | tree arglist = TREE_OPERAND (exp, 1); |
c65ebc55 JW |
5496 | |
5497 | switch (fcode) | |
5498 | { | |
5499 | case IA64_BUILTIN_BOOL_COMPARE_AND_SWAP_SI: | |
c65ebc55 | 5500 | case IA64_BUILTIN_VAL_COMPARE_AND_SWAP_SI: |
0551c32d RH |
5501 | case IA64_BUILTIN_LOCK_TEST_AND_SET_SI: |
5502 | case IA64_BUILTIN_LOCK_RELEASE_SI: | |
5503 | case IA64_BUILTIN_FETCH_AND_ADD_SI: | |
5504 | case IA64_BUILTIN_FETCH_AND_SUB_SI: | |
5505 | case IA64_BUILTIN_FETCH_AND_OR_SI: | |
5506 | case IA64_BUILTIN_FETCH_AND_AND_SI: | |
5507 | case IA64_BUILTIN_FETCH_AND_XOR_SI: | |
5508 | case IA64_BUILTIN_FETCH_AND_NAND_SI: | |
5509 | case IA64_BUILTIN_ADD_AND_FETCH_SI: | |
5510 | case IA64_BUILTIN_SUB_AND_FETCH_SI: | |
5511 | case IA64_BUILTIN_OR_AND_FETCH_SI: | |
5512 | case IA64_BUILTIN_AND_AND_FETCH_SI: | |
5513 | case IA64_BUILTIN_XOR_AND_FETCH_SI: | |
5514 | case IA64_BUILTIN_NAND_AND_FETCH_SI: | |
5515 | mode = SImode; | |
5516 | break; | |
809d4ef1 | 5517 | |
c65ebc55 | 5518 | case IA64_BUILTIN_BOOL_COMPARE_AND_SWAP_DI: |
0551c32d RH |
5519 | case IA64_BUILTIN_VAL_COMPARE_AND_SWAP_DI: |
5520 | case IA64_BUILTIN_LOCK_TEST_AND_SET_DI: | |
5521 | case IA64_BUILTIN_LOCK_RELEASE_DI: | |
5522 | case IA64_BUILTIN_FETCH_AND_ADD_DI: | |
5523 | case IA64_BUILTIN_FETCH_AND_SUB_DI: | |
5524 | case IA64_BUILTIN_FETCH_AND_OR_DI: | |
5525 | case IA64_BUILTIN_FETCH_AND_AND_DI: | |
5526 | case IA64_BUILTIN_FETCH_AND_XOR_DI: | |
5527 | case IA64_BUILTIN_FETCH_AND_NAND_DI: | |
5528 | case IA64_BUILTIN_ADD_AND_FETCH_DI: | |
5529 | case IA64_BUILTIN_SUB_AND_FETCH_DI: | |
5530 | case IA64_BUILTIN_OR_AND_FETCH_DI: | |
5531 | case IA64_BUILTIN_AND_AND_FETCH_DI: | |
5532 | case IA64_BUILTIN_XOR_AND_FETCH_DI: | |
5533 | case IA64_BUILTIN_NAND_AND_FETCH_DI: | |
5534 | mode = DImode; | |
5535 | break; | |
809d4ef1 | 5536 | |
0551c32d RH |
5537 | default: |
5538 | break; | |
5539 | } | |
5540 | ||
5541 | switch (fcode) | |
5542 | { | |
5543 | case IA64_BUILTIN_BOOL_COMPARE_AND_SWAP_SI: | |
5544 | case IA64_BUILTIN_BOOL_COMPARE_AND_SWAP_DI: | |
5545 | return ia64_expand_compare_and_swap (mode, 1, arglist, target); | |
5546 | ||
5547 | case IA64_BUILTIN_VAL_COMPARE_AND_SWAP_SI: | |
c65ebc55 | 5548 | case IA64_BUILTIN_VAL_COMPARE_AND_SWAP_DI: |
0551c32d | 5549 | return ia64_expand_compare_and_swap (mode, 0, arglist, target); |
809d4ef1 | 5550 | |
c65ebc55 | 5551 | case IA64_BUILTIN_SYNCHRONIZE: |
0551c32d | 5552 | emit_insn (gen_mf ()); |
3b572406 | 5553 | return const0_rtx; |
c65ebc55 JW |
5554 | |
5555 | case IA64_BUILTIN_LOCK_TEST_AND_SET_SI: | |
c65ebc55 | 5556 | case IA64_BUILTIN_LOCK_TEST_AND_SET_DI: |
0551c32d | 5557 | return ia64_expand_lock_test_and_set (mode, arglist, target); |
c65ebc55 JW |
5558 | |
5559 | case IA64_BUILTIN_LOCK_RELEASE_SI: | |
c65ebc55 | 5560 | case IA64_BUILTIN_LOCK_RELEASE_DI: |
0551c32d | 5561 | return ia64_expand_lock_release (mode, arglist, target); |
c65ebc55 | 5562 | |
ce152ef8 | 5563 | case IA64_BUILTIN_BSP: |
0551c32d RH |
5564 | if (! target || ! register_operand (target, DImode)) |
5565 | target = gen_reg_rtx (DImode); | |
5566 | emit_insn (gen_bsp_value (target)); | |
5567 | return target; | |
ce152ef8 AM |
5568 | |
5569 | case IA64_BUILTIN_FLUSHRS: | |
3b572406 RH |
5570 | emit_insn (gen_flushrs ()); |
5571 | return const0_rtx; | |
ce152ef8 | 5572 | |
0551c32d RH |
5573 | case IA64_BUILTIN_FETCH_AND_ADD_SI: |
5574 | case IA64_BUILTIN_FETCH_AND_ADD_DI: | |
5575 | return ia64_expand_fetch_and_op (add_optab, mode, arglist, target); | |
5576 | ||
5577 | case IA64_BUILTIN_FETCH_AND_SUB_SI: | |
5578 | case IA64_BUILTIN_FETCH_AND_SUB_DI: | |
5579 | return ia64_expand_fetch_and_op (sub_optab, mode, arglist, target); | |
5580 | ||
5581 | case IA64_BUILTIN_FETCH_AND_OR_SI: | |
5582 | case IA64_BUILTIN_FETCH_AND_OR_DI: | |
5583 | return ia64_expand_fetch_and_op (ior_optab, mode, arglist, target); | |
5584 | ||
5585 | case IA64_BUILTIN_FETCH_AND_AND_SI: | |
5586 | case IA64_BUILTIN_FETCH_AND_AND_DI: | |
5587 | return ia64_expand_fetch_and_op (and_optab, mode, arglist, target); | |
5588 | ||
5589 | case IA64_BUILTIN_FETCH_AND_XOR_SI: | |
5590 | case IA64_BUILTIN_FETCH_AND_XOR_DI: | |
5591 | return ia64_expand_fetch_and_op (xor_optab, mode, arglist, target); | |
5592 | ||
5593 | case IA64_BUILTIN_FETCH_AND_NAND_SI: | |
5594 | case IA64_BUILTIN_FETCH_AND_NAND_DI: | |
5595 | return ia64_expand_fetch_and_op (one_cmpl_optab, mode, arglist, target); | |
5596 | ||
5597 | case IA64_BUILTIN_ADD_AND_FETCH_SI: | |
5598 | case IA64_BUILTIN_ADD_AND_FETCH_DI: | |
5599 | return ia64_expand_op_and_fetch (add_optab, mode, arglist, target); | |
5600 | ||
5601 | case IA64_BUILTIN_SUB_AND_FETCH_SI: | |
5602 | case IA64_BUILTIN_SUB_AND_FETCH_DI: | |
5603 | return ia64_expand_op_and_fetch (sub_optab, mode, arglist, target); | |
5604 | ||
5605 | case IA64_BUILTIN_OR_AND_FETCH_SI: | |
5606 | case IA64_BUILTIN_OR_AND_FETCH_DI: | |
5607 | return ia64_expand_op_and_fetch (ior_optab, mode, arglist, target); | |
5608 | ||
5609 | case IA64_BUILTIN_AND_AND_FETCH_SI: | |
5610 | case IA64_BUILTIN_AND_AND_FETCH_DI: | |
5611 | return ia64_expand_op_and_fetch (and_optab, mode, arglist, target); | |
5612 | ||
5613 | case IA64_BUILTIN_XOR_AND_FETCH_SI: | |
5614 | case IA64_BUILTIN_XOR_AND_FETCH_DI: | |
5615 | return ia64_expand_op_and_fetch (xor_optab, mode, arglist, target); | |
5616 | ||
5617 | case IA64_BUILTIN_NAND_AND_FETCH_SI: | |
5618 | case IA64_BUILTIN_NAND_AND_FETCH_DI: | |
5619 | return ia64_expand_op_and_fetch (one_cmpl_optab, mode, arglist, target); | |
5620 | ||
c65ebc55 JW |
5621 | default: |
5622 | break; | |
5623 | } | |
5624 | ||
0551c32d | 5625 | return NULL_RTX; |
c65ebc55 | 5626 | } |