]>
Commit | Line | Data |
---|---|---|
a6f12d7c | 1 | /* Subroutines used for code generation on the DEC Alpha. |
7f11fbd5 | 2 | Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. |
d60a05a1 | 3 | Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) |
a6f12d7c RK |
4 | |
5 | This file is part of GNU CC. | |
6 | ||
7 | GNU CC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GNU CC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GNU CC; see the file COPYING. If not, write to | |
38ead7f3 RK |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, |
20 | Boston, MA 02111-1307, USA. */ | |
a6f12d7c RK |
21 | |
22 | ||
a6f12d7c | 23 | #include "config.h" |
e9a25f70 | 24 | #include <stdio.h> |
a6f12d7c RK |
25 | #include "rtl.h" |
26 | #include "regs.h" | |
27 | #include "hard-reg-set.h" | |
28 | #include "real.h" | |
29 | #include "insn-config.h" | |
30 | #include "conditions.h" | |
31 | #include "insn-flags.h" | |
32 | #include "output.h" | |
33 | #include "insn-attr.h" | |
34 | #include "flags.h" | |
35 | #include "recog.h" | |
36 | #include "reload.h" | |
37 | #include "expr.h" | |
38 | #include "obstack.h" | |
39 | #include "tree.h" | |
9ecc37f0 RH |
40 | #include "except.h" |
41 | #include "function.h" | |
42 | ||
43 | /* External data. */ | |
44 | extern char *version_string; | |
45 | extern int rtx_equal_function_value_matters; | |
a6f12d7c | 46 | |
da792a68 | 47 | /* Specify which cpu to schedule for. */ |
9ecc37f0 | 48 | |
9b009d45 | 49 | enum processor_type alpha_cpu; |
da792a68 | 50 | |
6245e3df RK |
51 | /* Specify how accurate floating-point traps need to be. */ |
52 | ||
53 | enum alpha_trap_precision alpha_tp; | |
54 | ||
55 | /* Specify the floating-point rounding mode. */ | |
56 | ||
57 | enum alpha_fp_rounding_mode alpha_fprm; | |
58 | ||
59 | /* Specify which things cause traps. */ | |
60 | ||
61 | enum alpha_fp_trap_mode alpha_fptm; | |
62 | ||
63 | /* Strings decoded into the above options. */ | |
9ecc37f0 | 64 | |
da792a68 | 65 | char *alpha_cpu_string; /* -mcpu=ev[4|5] */ |
6245e3df RK |
66 | char *alpha_tp_string; /* -mtrap-precision=[p|s|i] */ |
67 | char *alpha_fprm_string; /* -mfp-rounding-mode=[n|m|c|d] */ | |
68 | char *alpha_fptm_string; /* -mfp-trap-mode=[n|u|su|sui] */ | |
69 | ||
a6f12d7c RK |
70 | /* Save information from a "cmpxx" operation until the branch or scc is |
71 | emitted. */ | |
72 | ||
73 | rtx alpha_compare_op0, alpha_compare_op1; | |
74 | int alpha_compare_fp_p; | |
75 | ||
76 | /* Save the name of the current function as used by the assembler. This | |
77 | is used by the epilogue. */ | |
78 | ||
79 | char *alpha_function_name; | |
80 | ||
48f6bfac RK |
81 | /* Non-zero if inside of a function, because the Alpha asm can't |
82 | handle .files inside of functions. */ | |
83 | ||
84 | static int inside_function = FALSE; | |
85 | ||
a6f12d7c RK |
86 | /* Nonzero if the current function needs gp. */ |
87 | ||
88 | int alpha_function_needs_gp; | |
0f33506c | 89 | |
9ecc37f0 RH |
90 | /* If non-null, this rtx holds the return address for the function. */ |
91 | ||
92 | static rtx alpha_return_addr_rtx; | |
d60a05a1 RK |
93 | |
94 | /* Declarations of static functions. */ | |
95 | static void alpha_set_memflags_1 PROTO((rtx, int, int, int)); | |
9102cd1f RK |
96 | static rtx alpha_emit_set_const_1 PROTO((rtx, enum machine_mode, |
97 | HOST_WIDE_INT, int)); | |
d60a05a1 | 98 | static void add_long_const PROTO((FILE *, HOST_WIDE_INT, int, int, int)); |
89cfc2c6 RK |
99 | |
100 | /* Compute the size of the save area in the stack. */ | |
101 | static void alpha_sa_mask PROTO((unsigned long *imaskP, | |
102 | unsigned long *fmaskP)); | |
e9a25f70 JL |
103 | /* Get the number of args of a function in one of two ways. */ |
104 | #ifdef OPEN_VMS | |
105 | #define NUM_ARGS current_function_args_info.num_args | |
106 | #else | |
107 | #define NUM_ARGS current_function_args_info | |
108 | #endif | |
a6f12d7c | 109 | \f |
6245e3df RK |
110 | /* Parse target option strings. */ |
111 | ||
112 | void | |
113 | override_options () | |
114 | { | |
74dad6ce | 115 | alpha_cpu |
e9a25f70 JL |
116 | = TARGET_CPU_DEFAULT & MASK_CPU_EV6 ? PROCESSOR_EV6 |
117 | : (TARGET_CPU_DEFAULT & MASK_CPU_EV5 ? PROCESSOR_EV5 : PROCESSOR_EV4); | |
10d5c73f | 118 | |
da792a68 RK |
119 | if (alpha_cpu_string) |
120 | { | |
10d5c73f RK |
121 | if (! strcmp (alpha_cpu_string, "ev4") |
122 | || ! strcmp (alpha_cpu_string, "21064")) | |
e9a25f70 JL |
123 | { |
124 | alpha_cpu = PROCESSOR_EV4; | |
125 | target_flags &= ~ (MASK_BWX | MASK_CIX | MASK_MAX); | |
126 | } | |
10d5c73f RK |
127 | else if (! strcmp (alpha_cpu_string, "ev5") |
128 | || ! strcmp (alpha_cpu_string, "21164")) | |
e9a25f70 JL |
129 | { |
130 | alpha_cpu = PROCESSOR_EV5; | |
131 | target_flags &= ~ (MASK_BWX | MASK_CIX | MASK_MAX); | |
132 | } | |
9b009d45 RK |
133 | else if (! strcmp (alpha_cpu_string, "ev56") |
134 | || ! strcmp (alpha_cpu_string, "21164a")) | |
135 | { | |
136 | alpha_cpu = PROCESSOR_EV5; | |
e9a25f70 JL |
137 | target_flags |= MASK_BWX; |
138 | target_flags &= ~ (MASK_CIX | MASK_MAX); | |
139 | } | |
140 | else if (! strcmp (alpha_cpu_string, "pca56") | |
141 | || ! strcmp (alpha_cpu_string, "21164PC")) | |
142 | { | |
143 | alpha_cpu = PROCESSOR_EV5; | |
144 | target_flags |= MASK_BWX | MASK_MAX; | |
145 | target_flags &= ~ MASK_CIX; | |
146 | } | |
147 | else if (! strcmp (alpha_cpu_string, "ev6") | |
148 | || ! strcmp (alpha_cpu_string, "21264")) | |
149 | { | |
150 | alpha_cpu = PROCESSOR_EV6; | |
151 | target_flags |= MASK_BWX | MASK_CIX | MASK_MAX; | |
9b009d45 | 152 | } |
da792a68 | 153 | else |
10d5c73f | 154 | error ("bad value `%s' for -mcpu switch", alpha_cpu_string); |
da792a68 RK |
155 | } |
156 | ||
6245e3df RK |
157 | alpha_tp = ALPHA_TP_PROG; |
158 | alpha_fprm = ALPHA_FPRM_NORM; | |
159 | alpha_fptm = ALPHA_FPTM_N; | |
160 | ||
161 | if (TARGET_IEEE) | |
162 | { | |
10d5c73f RK |
163 | alpha_tp = ALPHA_TP_INSN; |
164 | alpha_fptm = ALPHA_FPTM_SU; | |
6245e3df RK |
165 | } |
166 | ||
167 | if (TARGET_IEEE_WITH_INEXACT) | |
168 | { | |
10d5c73f RK |
169 | alpha_tp = ALPHA_TP_INSN; |
170 | alpha_fptm = ALPHA_FPTM_SUI; | |
6245e3df RK |
171 | } |
172 | ||
173 | if (alpha_tp_string) | |
10d5c73f RK |
174 | { |
175 | if (! strcmp (alpha_tp_string, "p")) | |
6245e3df | 176 | alpha_tp = ALPHA_TP_PROG; |
10d5c73f | 177 | else if (! strcmp (alpha_tp_string, "f")) |
6245e3df | 178 | alpha_tp = ALPHA_TP_FUNC; |
10d5c73f | 179 | else if (! strcmp (alpha_tp_string, "i")) |
6245e3df | 180 | alpha_tp = ALPHA_TP_INSN; |
10d5c73f RK |
181 | else |
182 | error ("bad value `%s' for -mtrap-precision switch", alpha_tp_string); | |
183 | } | |
6245e3df RK |
184 | |
185 | if (alpha_fprm_string) | |
10d5c73f RK |
186 | { |
187 | if (! strcmp (alpha_fprm_string, "n")) | |
6245e3df | 188 | alpha_fprm = ALPHA_FPRM_NORM; |
10d5c73f | 189 | else if (! strcmp (alpha_fprm_string, "m")) |
6245e3df | 190 | alpha_fprm = ALPHA_FPRM_MINF; |
10d5c73f | 191 | else if (! strcmp (alpha_fprm_string, "c")) |
6245e3df | 192 | alpha_fprm = ALPHA_FPRM_CHOP; |
10d5c73f | 193 | else if (! strcmp (alpha_fprm_string,"d")) |
6245e3df | 194 | alpha_fprm = ALPHA_FPRM_DYN; |
10d5c73f RK |
195 | else |
196 | error ("bad value `%s' for -mfp-rounding-mode switch", | |
6245e3df | 197 | alpha_fprm_string); |
10d5c73f | 198 | } |
6245e3df RK |
199 | |
200 | if (alpha_fptm_string) | |
10d5c73f RK |
201 | { |
202 | if (strcmp (alpha_fptm_string, "n") == 0) | |
203 | alpha_fptm = ALPHA_FPTM_N; | |
204 | else if (strcmp (alpha_fptm_string, "u") == 0) | |
205 | alpha_fptm = ALPHA_FPTM_U; | |
206 | else if (strcmp (alpha_fptm_string, "su") == 0) | |
207 | alpha_fptm = ALPHA_FPTM_SU; | |
208 | else if (strcmp (alpha_fptm_string, "sui") == 0) | |
209 | alpha_fptm = ALPHA_FPTM_SUI; | |
210 | else | |
211 | error ("bad value `%s' for -mfp-trap-mode switch", alpha_fptm_string); | |
212 | } | |
6245e3df RK |
213 | |
214 | /* Do some sanity checks on the above option. */ | |
215 | ||
10d5c73f RK |
216 | if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI) |
217 | && alpha_tp != ALPHA_TP_INSN) | |
6245e3df | 218 | { |
10d5c73f | 219 | warning ("fp software completion requires -mtrap-precision=i"); |
6245e3df RK |
220 | alpha_tp = ALPHA_TP_INSN; |
221 | } | |
89cfc2c6 RK |
222 | |
223 | if (TARGET_FLOAT_VAX) | |
224 | { | |
225 | if (alpha_fprm == ALPHA_FPRM_MINF || alpha_fprm == ALPHA_FPRM_DYN) | |
226 | { | |
227 | warning ("rounding mode not supported for VAX floats"); | |
228 | alpha_fprm = ALPHA_FPRM_NORM; | |
229 | } | |
230 | if (alpha_fptm == ALPHA_FPTM_SUI) | |
231 | { | |
232 | warning ("trap mode not supported for VAX floats"); | |
233 | alpha_fptm = ALPHA_FPTM_SU; | |
234 | } | |
235 | } | |
6245e3df RK |
236 | } |
237 | \f | |
a6f12d7c RK |
238 | /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */ |
239 | ||
240 | int | |
241 | zap_mask (value) | |
242 | HOST_WIDE_INT value; | |
243 | { | |
244 | int i; | |
245 | ||
246 | for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; | |
247 | i++, value >>= 8) | |
248 | if ((value & 0xff) != 0 && (value & 0xff) != 0xff) | |
249 | return 0; | |
250 | ||
251 | return 1; | |
252 | } | |
253 | ||
254 | /* Returns 1 if OP is either the constant zero or a register. If a | |
255 | register, it must be in the proper mode unless MODE is VOIDmode. */ | |
256 | ||
257 | int | |
258 | reg_or_0_operand (op, mode) | |
259 | register rtx op; | |
260 | enum machine_mode mode; | |
261 | { | |
262 | return op == const0_rtx || register_operand (op, mode); | |
263 | } | |
264 | ||
f4014bfd RK |
265 | /* Return 1 if OP is a constant in the range of 0-63 (for a shift) or |
266 | any register. */ | |
267 | ||
268 | int | |
269 | reg_or_6bit_operand (op, mode) | |
270 | register rtx op; | |
271 | enum machine_mode mode; | |
272 | { | |
273 | return ((GET_CODE (op) == CONST_INT | |
274 | && (unsigned HOST_WIDE_INT) INTVAL (op) < 64) | |
275 | || register_operand (op, mode)); | |
276 | } | |
277 | ||
278 | ||
a6f12d7c RK |
279 | /* Return 1 if OP is an 8-bit constant or any register. */ |
280 | ||
281 | int | |
282 | reg_or_8bit_operand (op, mode) | |
283 | register rtx op; | |
284 | enum machine_mode mode; | |
285 | { | |
286 | return ((GET_CODE (op) == CONST_INT | |
287 | && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100) | |
288 | || register_operand (op, mode)); | |
289 | } | |
290 | ||
14edc0e4 TG |
291 | /* Return 1 if OP is an 8-bit constant. */ |
292 | ||
293 | int | |
294 | cint8_operand (op, mode) | |
295 | register rtx op; | |
296 | enum machine_mode mode; | |
297 | { | |
298 | return (GET_CODE (op) == CONST_INT | |
299 | && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100); | |
300 | } | |
301 | ||
a6f12d7c RK |
302 | /* Return 1 if the operand is a valid second operand to an add insn. */ |
303 | ||
304 | int | |
305 | add_operand (op, mode) | |
306 | register rtx op; | |
307 | enum machine_mode mode; | |
308 | { | |
309 | if (GET_CODE (op) == CONST_INT) | |
e6118f89 RK |
310 | return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K') |
311 | || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L') | |
312 | || CONST_OK_FOR_LETTER_P (INTVAL (op), 'O')); | |
a6f12d7c RK |
313 | |
314 | return register_operand (op, mode); | |
315 | } | |
316 | ||
317 | /* Return 1 if the operand is a valid second operand to a sign-extending | |
318 | add insn. */ | |
319 | ||
320 | int | |
321 | sext_add_operand (op, mode) | |
322 | register rtx op; | |
323 | enum machine_mode mode; | |
324 | { | |
325 | if (GET_CODE (op) == CONST_INT) | |
326 | return ((unsigned HOST_WIDE_INT) INTVAL (op) < 255 | |
327 | || (unsigned HOST_WIDE_INT) (- INTVAL (op)) < 255); | |
328 | ||
329 | return register_operand (op, mode); | |
330 | } | |
331 | ||
332 | /* Return 1 if OP is the constant 4 or 8. */ | |
333 | ||
334 | int | |
335 | const48_operand (op, mode) | |
336 | register rtx op; | |
337 | enum machine_mode mode; | |
338 | { | |
339 | return (GET_CODE (op) == CONST_INT | |
340 | && (INTVAL (op) == 4 || INTVAL (op) == 8)); | |
341 | } | |
342 | ||
343 | /* Return 1 if OP is a valid first operand to an AND insn. */ | |
344 | ||
345 | int | |
346 | and_operand (op, mode) | |
347 | register rtx op; | |
348 | enum machine_mode mode; | |
349 | { | |
350 | if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode) | |
351 | return (zap_mask (CONST_DOUBLE_LOW (op)) | |
352 | && zap_mask (CONST_DOUBLE_HIGH (op))); | |
353 | ||
354 | if (GET_CODE (op) == CONST_INT) | |
355 | return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100 | |
356 | || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100 | |
357 | || zap_mask (INTVAL (op))); | |
358 | ||
359 | return register_operand (op, mode); | |
360 | } | |
361 | ||
c7def335 | 362 | /* Return 1 if OP is a valid first operand to an IOR or XOR insn. */ |
8088469d RK |
363 | |
364 | int | |
c7def335 | 365 | or_operand (op, mode) |
8088469d RK |
366 | register rtx op; |
367 | enum machine_mode mode; | |
368 | { | |
369 | if (GET_CODE (op) == CONST_INT) | |
370 | return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100 | |
371 | || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100); | |
372 | ||
373 | return register_operand (op, mode); | |
374 | } | |
375 | ||
a6f12d7c RK |
376 | /* Return 1 if OP is a constant that is the width, in bits, of an integral |
377 | mode smaller than DImode. */ | |
378 | ||
379 | int | |
380 | mode_width_operand (op, mode) | |
381 | register rtx op; | |
382 | enum machine_mode mode; | |
383 | { | |
384 | return (GET_CODE (op) == CONST_INT | |
385 | && (INTVAL (op) == 8 || INTVAL (op) == 16 || INTVAL (op) == 32)); | |
386 | } | |
387 | ||
388 | /* Return 1 if OP is a constant that is the width of an integral machine mode | |
389 | smaller than an integer. */ | |
390 | ||
391 | int | |
392 | mode_mask_operand (op, mode) | |
393 | register rtx op; | |
394 | enum machine_mode mode; | |
395 | { | |
396 | #if HOST_BITS_PER_WIDE_INT == 32 | |
397 | if (GET_CODE (op) == CONST_DOUBLE) | |
398 | return CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == -1; | |
399 | #endif | |
400 | ||
16b02ae0 RK |
401 | return (GET_CODE (op) == CONST_INT |
402 | && (INTVAL (op) == 0xff | |
403 | || INTVAL (op) == 0xffff | |
a6f12d7c | 404 | #if HOST_BITS_PER_WIDE_INT == 64 |
16b02ae0 | 405 | || INTVAL (op) == 0xffffffff |
a6f12d7c | 406 | #endif |
16b02ae0 | 407 | )); |
a6f12d7c RK |
408 | } |
409 | ||
410 | /* Return 1 if OP is a multiple of 8 less than 64. */ | |
411 | ||
412 | int | |
413 | mul8_operand (op, mode) | |
414 | register rtx op; | |
415 | enum machine_mode mode; | |
416 | { | |
417 | return (GET_CODE (op) == CONST_INT | |
418 | && (unsigned HOST_WIDE_INT) INTVAL (op) < 64 | |
419 | && (INTVAL (op) & 7) == 0); | |
420 | } | |
421 | ||
422 | /* Return 1 if OP is the constant zero in floating-point. */ | |
423 | ||
424 | int | |
425 | fp0_operand (op, mode) | |
426 | register rtx op; | |
427 | enum machine_mode mode; | |
428 | { | |
429 | return (GET_MODE (op) == mode | |
430 | && GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode)); | |
431 | } | |
432 | ||
433 | /* Return 1 if OP is the floating-point constant zero or a register. */ | |
434 | ||
435 | int | |
436 | reg_or_fp0_operand (op, mode) | |
437 | register rtx op; | |
438 | enum machine_mode mode; | |
439 | { | |
440 | return fp0_operand (op, mode) || register_operand (op, mode); | |
441 | } | |
442 | ||
443 | /* Return 1 if OP is a register or a constant integer. */ | |
444 | ||
445 | ||
446 | int | |
447 | reg_or_cint_operand (op, mode) | |
448 | register rtx op; | |
449 | enum machine_mode mode; | |
450 | { | |
451 | return GET_CODE (op) == CONST_INT || register_operand (op, mode); | |
452 | } | |
453 | ||
8d36d33b RK |
454 | /* Return 1 if OP is something that can be reloaded into a register; |
455 | if it is a MEM, it need not be valid. */ | |
456 | ||
457 | int | |
458 | some_operand (op, mode) | |
459 | register rtx op; | |
460 | enum machine_mode mode; | |
461 | { | |
462 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) | |
463 | return 0; | |
464 | ||
465 | switch (GET_CODE (op)) | |
466 | { | |
467 | case REG: case MEM: case CONST_DOUBLE: | |
468 | case CONST_INT: case LABEL_REF: case SYMBOL_REF: case CONST: | |
469 | return 1; | |
470 | ||
471 | case SUBREG: | |
472 | return some_operand (SUBREG_REG (op), VOIDmode); | |
473 | } | |
474 | ||
475 | return 0; | |
476 | } | |
477 | ||
a6f12d7c RK |
478 | /* Return 1 if OP is a valid operand for the source of a move insn. */ |
479 | ||
480 | int | |
481 | input_operand (op, mode) | |
482 | register rtx op; | |
483 | enum machine_mode mode; | |
484 | { | |
485 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) | |
486 | return 0; | |
487 | ||
488 | if (GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE (op) != mode) | |
489 | return 0; | |
490 | ||
491 | switch (GET_CODE (op)) | |
492 | { | |
493 | case LABEL_REF: | |
494 | case SYMBOL_REF: | |
495 | case CONST: | |
7daa56f5 RK |
496 | /* This handles both the Windows/NT and OSF cases. */ |
497 | return mode == ptr_mode || mode == DImode; | |
a6f12d7c RK |
498 | |
499 | case REG: | |
500 | return 1; | |
501 | ||
502 | case SUBREG: | |
503 | if (register_operand (op, mode)) | |
504 | return 1; | |
505 | /* ... fall through ... */ | |
506 | case MEM: | |
e9a25f70 | 507 | return ((TARGET_BWX || (mode != HImode && mode != QImode)) |
a2574dbe | 508 | && general_operand (op, mode)); |
a6f12d7c RK |
509 | |
510 | case CONST_DOUBLE: | |
511 | return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode); | |
512 | ||
513 | case CONST_INT: | |
514 | return mode == QImode || mode == HImode || add_operand (op, mode); | |
515 | } | |
516 | ||
517 | return 0; | |
518 | } | |
519 | ||
0f33506c RK |
520 | /* Return 1 if OP is a SYMBOL_REF for a function known to be in this |
521 | file. */ | |
a6f12d7c RK |
522 | |
523 | int | |
0f33506c | 524 | current_file_function_operand (op, mode) |
a6f12d7c RK |
525 | rtx op; |
526 | enum machine_mode mode; | |
527 | { | |
528 | return (GET_CODE (op) == SYMBOL_REF | |
d14d353d | 529 | && ! profile_flag && ! profile_block_flag |
0f33506c RK |
530 | && (SYMBOL_REF_FLAG (op) |
531 | || op == XEXP (DECL_RTL (current_function_decl), 0))); | |
a6f12d7c RK |
532 | } |
533 | ||
6bcf5f0a RK |
534 | /* Return 1 if OP is a valid operand for the MEM of a CALL insn. */ |
535 | ||
536 | int | |
537 | call_operand (op, mode) | |
538 | rtx op; | |
539 | enum machine_mode mode; | |
540 | { | |
541 | if (mode != Pmode) | |
542 | return 0; | |
543 | ||
7e277025 | 544 | return (GET_CODE (op) == SYMBOL_REF |
89cfc2c6 | 545 | || (GET_CODE (op) == REG && (TARGET_OPEN_VMS || REGNO (op) == 27))); |
6bcf5f0a RK |
546 | } |
547 | ||
a6f12d7c RK |
548 | /* Return 1 if OP is a valid Alpha comparison operator. Here we know which |
549 | comparisons are valid in which insn. */ | |
550 | ||
551 | int | |
552 | alpha_comparison_operator (op, mode) | |
553 | register rtx op; | |
554 | enum machine_mode mode; | |
555 | { | |
556 | enum rtx_code code = GET_CODE (op); | |
557 | ||
558 | if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<') | |
559 | return 0; | |
560 | ||
561 | return (code == EQ || code == LE || code == LT | |
562 | || (mode == DImode && (code == LEU || code == LTU))); | |
563 | } | |
564 | ||
5bf6c48a RK |
565 | /* Return 1 if OP is a valid Alpha swapped comparison operator. */ |
566 | ||
567 | int | |
568 | alpha_swapped_comparison_operator (op, mode) | |
569 | register rtx op; | |
570 | enum machine_mode mode; | |
571 | { | |
572 | enum rtx_code code = GET_CODE (op); | |
573 | ||
574 | if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<') | |
575 | return 0; | |
576 | ||
577 | code = swap_condition (code); | |
578 | return (code == EQ || code == LE || code == LT | |
579 | || (mode == DImode && (code == LEU || code == LTU))); | |
580 | } | |
581 | ||
a6f12d7c RK |
582 | /* Return 1 if OP is a signed comparison operation. */ |
583 | ||
584 | int | |
585 | signed_comparison_operator (op, mode) | |
586 | register rtx op; | |
587 | enum machine_mode mode; | |
588 | { | |
589 | switch (GET_CODE (op)) | |
590 | { | |
591 | case EQ: case NE: case LE: case LT: case GE: case GT: | |
592 | return 1; | |
593 | } | |
594 | ||
595 | return 0; | |
596 | } | |
597 | ||
598 | /* Return 1 if this is a divide or modulus operator. */ | |
599 | ||
600 | int | |
601 | divmod_operator (op, mode) | |
602 | register rtx op; | |
603 | enum machine_mode mode; | |
604 | { | |
605 | switch (GET_CODE (op)) | |
606 | { | |
607 | case DIV: case MOD: case UDIV: case UMOD: | |
608 | return 1; | |
609 | } | |
610 | ||
611 | return 0; | |
612 | } | |
613 | ||
614 | /* Return 1 if this memory address is a known aligned register plus | |
615 | a constant. It must be a valid address. This means that we can do | |
616 | this as an aligned reference plus some offset. | |
617 | ||
618 | Take into account what reload will do. | |
619 | ||
620 | We could say that out-of-range stack slots are alignable, but that would | |
621 | complicate get_aligned_mem and it isn't worth the trouble since few | |
622 | functions have large stack space. */ | |
623 | ||
624 | int | |
625 | aligned_memory_operand (op, mode) | |
626 | register rtx op; | |
627 | enum machine_mode mode; | |
628 | { | |
629 | if (GET_CODE (op) == SUBREG) | |
630 | { | |
631 | if (GET_MODE (op) != mode) | |
632 | return 0; | |
633 | op = SUBREG_REG (op); | |
634 | mode = GET_MODE (op); | |
635 | } | |
636 | ||
637 | if (reload_in_progress && GET_CODE (op) == REG | |
638 | && REGNO (op) >= FIRST_PSEUDO_REGISTER) | |
639 | op = reg_equiv_mem[REGNO (op)]; | |
640 | ||
641 | if (GET_CODE (op) != MEM || GET_MODE (op) != mode | |
642 | || ! memory_address_p (mode, XEXP (op, 0))) | |
643 | return 0; | |
644 | ||
645 | op = XEXP (op, 0); | |
646 | ||
647 | if (GET_CODE (op) == PLUS) | |
648 | op = XEXP (op, 0); | |
649 | ||
650 | return (GET_CODE (op) == REG | |
adb18b68 | 651 | && REGNO_POINTER_ALIGN (REGNO (op)) >= 4); |
a6f12d7c RK |
652 | } |
653 | ||
654 | /* Similar, but return 1 if OP is a MEM which is not alignable. */ | |
655 | ||
656 | int | |
657 | unaligned_memory_operand (op, mode) | |
658 | register rtx op; | |
659 | enum machine_mode mode; | |
660 | { | |
661 | if (GET_CODE (op) == SUBREG) | |
662 | { | |
663 | if (GET_MODE (op) != mode) | |
664 | return 0; | |
665 | op = SUBREG_REG (op); | |
666 | mode = GET_MODE (op); | |
667 | } | |
668 | ||
669 | if (reload_in_progress && GET_CODE (op) == REG | |
670 | && REGNO (op) >= FIRST_PSEUDO_REGISTER) | |
671 | op = reg_equiv_mem[REGNO (op)]; | |
672 | ||
673 | if (GET_CODE (op) != MEM || GET_MODE (op) != mode) | |
674 | return 0; | |
675 | ||
676 | op = XEXP (op, 0); | |
677 | ||
678 | if (! memory_address_p (mode, op)) | |
679 | return 1; | |
680 | ||
681 | if (GET_CODE (op) == PLUS) | |
682 | op = XEXP (op, 0); | |
683 | ||
684 | return (GET_CODE (op) != REG | |
adb18b68 RK |
685 | || REGNO_POINTER_ALIGN (REGNO (op)) < 4); |
686 | } | |
687 | ||
688 | /* Return 1 if OP is either a register or an unaligned memory location. */ | |
689 | ||
690 | int | |
691 | reg_or_unaligned_mem_operand (op, mode) | |
692 | rtx op; | |
693 | enum machine_mode mode; | |
694 | { | |
695 | return register_operand (op, mode) || unaligned_memory_operand (op, mode); | |
a6f12d7c RK |
696 | } |
697 | ||
698 | /* Return 1 if OP is any memory location. During reload a pseudo matches. */ | |
699 | ||
700 | int | |
701 | any_memory_operand (op, mode) | |
702 | register rtx op; | |
703 | enum machine_mode mode; | |
704 | { | |
705 | return (GET_CODE (op) == MEM | |
706 | || (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG) | |
707 | || (reload_in_progress && GET_CODE (op) == REG | |
708 | && REGNO (op) >= FIRST_PSEUDO_REGISTER) | |
709 | || (reload_in_progress && GET_CODE (op) == SUBREG | |
710 | && GET_CODE (SUBREG_REG (op)) == REG | |
711 | && REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)); | |
712 | } | |
713 | ||
714 | /* REF is an alignable memory location. Place an aligned SImode | |
715 | reference into *PALIGNED_MEM and the number of bits to shift into | |
716 | *PBITNUM. */ | |
717 | ||
718 | void | |
719 | get_aligned_mem (ref, paligned_mem, pbitnum) | |
720 | rtx ref; | |
721 | rtx *paligned_mem, *pbitnum; | |
722 | { | |
723 | rtx base; | |
724 | HOST_WIDE_INT offset = 0; | |
725 | ||
726 | if (GET_CODE (ref) == SUBREG) | |
727 | { | |
728 | offset = SUBREG_WORD (ref) * UNITS_PER_WORD; | |
729 | if (BYTES_BIG_ENDIAN) | |
730 | offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (ref))) | |
731 | - MIN (UNITS_PER_WORD, | |
732 | GET_MODE_SIZE (GET_MODE (SUBREG_REG (ref))))); | |
733 | ref = SUBREG_REG (ref); | |
734 | } | |
735 | ||
736 | if (GET_CODE (ref) == REG) | |
737 | ref = reg_equiv_mem[REGNO (ref)]; | |
738 | ||
739 | if (reload_in_progress) | |
740 | base = find_replacement (&XEXP (ref, 0)); | |
741 | else | |
742 | base = XEXP (ref, 0); | |
743 | ||
744 | if (GET_CODE (base) == PLUS) | |
745 | offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0); | |
746 | ||
747 | *paligned_mem = gen_rtx (MEM, SImode, | |
748 | plus_constant (base, offset & ~3)); | |
749 | MEM_IN_STRUCT_P (*paligned_mem) = MEM_IN_STRUCT_P (ref); | |
750 | MEM_VOLATILE_P (*paligned_mem) = MEM_VOLATILE_P (ref); | |
751 | RTX_UNCHANGING_P (*paligned_mem) = RTX_UNCHANGING_P (ref); | |
752 | ||
753 | *pbitnum = GEN_INT ((offset & 3) * 8); | |
754 | } | |
755 | ||
adb18b68 RK |
756 | /* Similar, but just get the address. Handle the two reload cases. |
757 | Add EXTRA_OFFSET to the address we return. */ | |
a6f12d7c RK |
758 | |
759 | rtx | |
adb18b68 | 760 | get_unaligned_address (ref, extra_offset) |
a6f12d7c | 761 | rtx ref; |
adb18b68 | 762 | int extra_offset; |
a6f12d7c RK |
763 | { |
764 | rtx base; | |
765 | HOST_WIDE_INT offset = 0; | |
766 | ||
767 | if (GET_CODE (ref) == SUBREG) | |
768 | { | |
769 | offset = SUBREG_WORD (ref) * UNITS_PER_WORD; | |
770 | if (BYTES_BIG_ENDIAN) | |
771 | offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (ref))) | |
772 | - MIN (UNITS_PER_WORD, | |
773 | GET_MODE_SIZE (GET_MODE (SUBREG_REG (ref))))); | |
774 | ref = SUBREG_REG (ref); | |
775 | } | |
776 | ||
777 | if (GET_CODE (ref) == REG) | |
778 | ref = reg_equiv_mem[REGNO (ref)]; | |
779 | ||
780 | if (reload_in_progress) | |
781 | base = find_replacement (&XEXP (ref, 0)); | |
782 | else | |
783 | base = XEXP (ref, 0); | |
784 | ||
785 | if (GET_CODE (base) == PLUS) | |
786 | offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0); | |
787 | ||
adb18b68 | 788 | return plus_constant (base, offset + extra_offset); |
a6f12d7c RK |
789 | } |
790 | \f | |
791 | /* Subfunction of the following function. Update the flags of any MEM | |
792 | found in part of X. */ | |
793 | ||
794 | static void | |
795 | alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p) | |
796 | rtx x; | |
797 | int in_struct_p, volatile_p, unchanging_p; | |
798 | { | |
799 | int i; | |
800 | ||
801 | switch (GET_CODE (x)) | |
802 | { | |
803 | case SEQUENCE: | |
804 | case PARALLEL: | |
805 | for (i = XVECLEN (x, 0) - 1; i >= 0; i--) | |
806 | alpha_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p, | |
807 | unchanging_p); | |
808 | break; | |
809 | ||
810 | case INSN: | |
811 | alpha_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p, | |
812 | unchanging_p); | |
813 | break; | |
814 | ||
815 | case SET: | |
816 | alpha_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p, | |
817 | unchanging_p); | |
818 | alpha_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p, | |
819 | unchanging_p); | |
820 | break; | |
821 | ||
822 | case MEM: | |
823 | MEM_IN_STRUCT_P (x) = in_struct_p; | |
824 | MEM_VOLATILE_P (x) = volatile_p; | |
825 | RTX_UNCHANGING_P (x) = unchanging_p; | |
826 | break; | |
827 | } | |
828 | } | |
829 | ||
830 | /* Given INSN, which is either an INSN or a SEQUENCE generated to | |
831 | perform a memory operation, look for any MEMs in either a SET_DEST or | |
832 | a SET_SRC and copy the in-struct, unchanging, and volatile flags from | |
833 | REF into each of the MEMs found. If REF is not a MEM, don't do | |
834 | anything. */ | |
835 | ||
836 | void | |
837 | alpha_set_memflags (insn, ref) | |
838 | rtx insn; | |
839 | rtx ref; | |
840 | { | |
841 | /* Note that it is always safe to get these flags, though they won't | |
842 | be what we think if REF is not a MEM. */ | |
843 | int in_struct_p = MEM_IN_STRUCT_P (ref); | |
844 | int volatile_p = MEM_VOLATILE_P (ref); | |
845 | int unchanging_p = RTX_UNCHANGING_P (ref); | |
846 | ||
847 | if (GET_CODE (ref) != MEM | |
848 | || (! in_struct_p && ! volatile_p && ! unchanging_p)) | |
849 | return; | |
850 | ||
851 | alpha_set_memflags_1 (insn, in_struct_p, volatile_p, unchanging_p); | |
852 | } | |
853 | \f | |
854 | /* Try to output insns to set TARGET equal to the constant C if it can be | |
fd94addf RK |
855 | done in less than N insns. Do all computations in MODE. Returns the place |
856 | where the output has been placed if it can be done and the insns have been | |
857 | emitted. If it would take more than N insns, zero is returned and no | |
858 | insns and emitted. */ | |
a6f12d7c | 859 | |
fd94addf RK |
860 | rtx |
861 | alpha_emit_set_const (target, mode, c, n) | |
a6f12d7c | 862 | rtx target; |
fd94addf | 863 | enum machine_mode mode; |
a6f12d7c RK |
864 | HOST_WIDE_INT c; |
865 | int n; | |
9102cd1f RK |
866 | { |
867 | rtx pat; | |
868 | int i; | |
869 | ||
870 | /* Try 1 insn, then 2, then up to N. */ | |
871 | for (i = 1; i <= n; i++) | |
872 | if ((pat = alpha_emit_set_const_1 (target, mode, c, i)) != 0) | |
873 | return pat; | |
874 | ||
875 | return 0; | |
876 | } | |
877 | ||
878 | /* Internal routine for the above to check for N or below insns. */ | |
879 | ||
880 | static rtx | |
881 | alpha_emit_set_const_1 (target, mode, c, n) | |
882 | rtx target; | |
883 | enum machine_mode mode; | |
884 | HOST_WIDE_INT c; | |
885 | int n; | |
a6f12d7c RK |
886 | { |
887 | HOST_WIDE_INT new = c; | |
888 | int i, bits; | |
fd94addf RK |
889 | /* Use a pseudo if highly optimizing and still generating RTL. */ |
890 | rtx subtarget | |
891 | = (flag_expensive_optimizations && rtx_equal_function_value_matters | |
892 | ? 0 : target); | |
893 | rtx temp; | |
a6f12d7c RK |
894 | |
895 | #if HOST_BITS_PER_WIDE_INT == 64 | |
896 | /* We are only called for SImode and DImode. If this is SImode, ensure that | |
897 | we are sign extended to a full word. This does not make any sense when | |
898 | cross-compiling on a narrow machine. */ | |
899 | ||
fd94addf | 900 | if (mode == SImode) |
a6f12d7c RK |
901 | c = (c & 0xffffffff) - 2 * (c & 0x80000000); |
902 | #endif | |
903 | ||
904 | /* If this is a sign-extended 32-bit constant, we can do this in at most | |
905 | three insns, so do it if we have enough insns left. We always have | |
0af3ee30 RK |
906 | a sign-extended 32-bit constant when compiling on a narrow machine. |
907 | Note that we cannot handle the constant 0x80000000. */ | |
a6f12d7c | 908 | |
0af3ee30 RK |
909 | if ((HOST_BITS_PER_WIDE_INT != 64 |
910 | || c >> 31 == -1 || c >> 31 == 0) | |
5c71c5b1 | 911 | && c != 0x80000000U) |
a6f12d7c RK |
912 | { |
913 | HOST_WIDE_INT low = (c & 0xffff) - 2 * (c & 0x8000); | |
914 | HOST_WIDE_INT tmp1 = c - low; | |
915 | HOST_WIDE_INT high | |
916 | = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); | |
a6f12d7c RK |
917 | HOST_WIDE_INT extra = 0; |
918 | ||
ab034cfc RK |
919 | /* If HIGH will be interpreted as negative but the constant is |
920 | positive, we must adjust it to do two ldha insns. */ | |
921 | ||
922 | if ((high & 0x8000) != 0 && c >= 0) | |
a6f12d7c RK |
923 | { |
924 | extra = 0x4000; | |
925 | tmp1 -= 0x40000000; | |
926 | high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); | |
927 | } | |
928 | ||
929 | if (c == low || (low == 0 && extra == 0)) | |
fd94addf | 930 | return copy_to_suggested_reg (GEN_INT (c), target, mode); |
9102cd1f | 931 | else if (n >= 2 + (extra != 0)) |
a6f12d7c | 932 | { |
fd94addf RK |
933 | temp = copy_to_suggested_reg (GEN_INT (low), subtarget, mode); |
934 | ||
a6f12d7c | 935 | if (extra != 0) |
fd94addf RK |
936 | temp = expand_binop (mode, add_optab, temp, GEN_INT (extra << 16), |
937 | subtarget, 0, OPTAB_WIDEN); | |
a6f12d7c | 938 | |
fd94addf RK |
939 | return expand_binop (mode, add_optab, temp, GEN_INT (high << 16), |
940 | target, 0, OPTAB_WIDEN); | |
a6f12d7c RK |
941 | } |
942 | } | |
943 | ||
0af3ee30 | 944 | /* If we couldn't do it that way, try some other methods. But if we have |
f444f304 RK |
945 | no instructions left, don't bother. Likewise, if this is SImode and |
946 | we can't make pseudos, we can't do anything since the expand_binop | |
947 | and expand_unop calls will widen and try to make pseudos. */ | |
a6f12d7c | 948 | |
f444f304 RK |
949 | if (n == 1 |
950 | || (mode == SImode && ! rtx_equal_function_value_matters)) | |
a6f12d7c RK |
951 | return 0; |
952 | ||
0af3ee30 | 953 | #if HOST_BITS_PER_WIDE_INT == 64 |
a6f12d7c RK |
954 | /* First, see if can load a value into the target that is the same as the |
955 | constant except that all bytes that are 0 are changed to be 0xff. If we | |
956 | can, then we can do a ZAPNOT to obtain the desired constant. */ | |
957 | ||
958 | for (i = 0; i < 64; i += 8) | |
959 | if ((new & ((HOST_WIDE_INT) 0xff << i)) == 0) | |
960 | new |= (HOST_WIDE_INT) 0xff << i; | |
961 | ||
57cfde96 RK |
962 | /* We are only called for SImode and DImode. If this is SImode, ensure that |
963 | we are sign extended to a full word. */ | |
964 | ||
965 | if (mode == SImode) | |
966 | new = (new & 0xffffffff) - 2 * (new & 0x80000000); | |
967 | ||
968 | if (new != c | |
969 | && (temp = alpha_emit_set_const (subtarget, mode, new, n - 1)) != 0) | |
fd94addf RK |
970 | return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new), |
971 | target, 0, OPTAB_WIDEN); | |
0af3ee30 | 972 | #endif |
a6f12d7c | 973 | |
0af3ee30 | 974 | /* Next, see if we can load a related constant and then shift and possibly |
a6f12d7c RK |
975 | negate it to get the constant we want. Try this once each increasing |
976 | numbers of insns. */ | |
977 | ||
978 | for (i = 1; i < n; i++) | |
979 | { | |
980 | /* First try complementing. */ | |
fd94addf RK |
981 | if ((temp = alpha_emit_set_const (subtarget, mode, ~ c, i)) != 0) |
982 | return expand_unop (mode, one_cmpl_optab, temp, target, 0); | |
a6f12d7c | 983 | |
fd94addf | 984 | /* Next try to form a constant and do a left shift. We can do this |
a6f12d7c RK |
985 | if some low-order bits are zero; the exact_log2 call below tells |
986 | us that information. The bits we are shifting out could be any | |
987 | value, but here we'll just try the 0- and sign-extended forms of | |
988 | the constant. To try to increase the chance of having the same | |
989 | constant in more than one insn, start at the highest number of | |
990 | bits to shift, but try all possibilities in case a ZAPNOT will | |
991 | be useful. */ | |
992 | ||
993 | if ((bits = exact_log2 (c & - c)) > 0) | |
994 | for (; bits > 0; bits--) | |
0af3ee30 RK |
995 | if ((temp = (alpha_emit_set_const |
996 | (subtarget, mode, | |
997 | (unsigned HOST_WIDE_INT) c >> bits, i))) != 0 | |
fd94addf RK |
998 | || ((temp = (alpha_emit_set_const |
999 | (subtarget, mode, | |
1000 | ((unsigned HOST_WIDE_INT) c) >> bits, i))) | |
1001 | != 0)) | |
1002 | return expand_binop (mode, ashl_optab, temp, GEN_INT (bits), | |
1003 | target, 0, OPTAB_WIDEN); | |
a6f12d7c RK |
1004 | |
1005 | /* Now try high-order zero bits. Here we try the shifted-in bits as | |
57cfde96 RK |
1006 | all zero and all ones. Be careful to avoid shifting outside the |
1007 | mode and to avoid shifting outside the host wide int size. */ | |
a6f12d7c | 1008 | |
57cfde96 RK |
1009 | if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) |
1010 | - floor_log2 (c) - 1)) > 0) | |
a6f12d7c | 1011 | for (; bits > 0; bits--) |
fd94addf RK |
1012 | if ((temp = alpha_emit_set_const (subtarget, mode, |
1013 | c << bits, i)) != 0 | |
1014 | || ((temp = (alpha_emit_set_const | |
1015 | (subtarget, mode, | |
1016 | ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)), | |
1017 | i))) | |
1018 | != 0)) | |
1019 | return expand_binop (mode, lshr_optab, temp, GEN_INT (bits), | |
57cfde96 | 1020 | target, 1, OPTAB_WIDEN); |
a6f12d7c RK |
1021 | |
1022 | /* Now try high-order 1 bits. We get that with a sign-extension. | |
57cfde96 RK |
1023 | But one bit isn't enough here. Be careful to avoid shifting outside |
1024 | the mode and to avoid shifting outside the host wide int size. */ | |
a6f12d7c | 1025 | |
57cfde96 RK |
1026 | if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) |
1027 | - floor_log2 (~ c) - 2)) > 0) | |
a6f12d7c | 1028 | for (; bits > 0; bits--) |
fd94addf RK |
1029 | if ((temp = alpha_emit_set_const (subtarget, mode, |
1030 | c << bits, i)) != 0 | |
1031 | || ((temp = (alpha_emit_set_const | |
1032 | (subtarget, mode, | |
1033 | ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)), | |
1034 | i))) | |
1035 | != 0)) | |
1036 | return expand_binop (mode, ashr_optab, temp, GEN_INT (bits), | |
1037 | target, 0, OPTAB_WIDEN); | |
a6f12d7c RK |
1038 | } |
1039 | ||
1040 | return 0; | |
1041 | } | |
758d2c0c | 1042 | |
97aea203 RK |
1043 | #if HOST_BITS_PER_WIDE_INT == 64 |
1044 | /* Having failed to find a 3 insn sequence in alpha_emit_set_const, | |
1045 | fall back to a straight forward decomposition. We do this to avoid | |
1046 | exponential run times encountered when looking for longer sequences | |
1047 | with alpha_emit_set_const. */ | |
1048 | ||
1049 | rtx | |
1050 | alpha_emit_set_long_const (target, c) | |
1051 | rtx target; | |
1052 | HOST_WIDE_INT c; | |
1053 | { | |
1054 | /* Use a pseudo if highly optimizing and still generating RTL. */ | |
1055 | rtx subtarget | |
1056 | = (flag_expensive_optimizations && rtx_equal_function_value_matters | |
1057 | ? 0 : target); | |
1058 | HOST_WIDE_INT d1, d2, d3, d4; | |
c3741733 | 1059 | rtx r1, r2; |
97aea203 RK |
1060 | |
1061 | /* Decompose the entire word */ | |
1062 | d1 = ((c & 0xffff) ^ 0x8000) - 0x8000; | |
1063 | c -= d1; | |
1064 | d2 = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
1065 | c = (c - d2) >> 32; | |
1066 | d3 = ((c & 0xffff) ^ 0x8000) - 0x8000; | |
1067 | c -= d3; | |
1068 | d4 = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
1069 | ||
1070 | if (c - d4 != 0) | |
1071 | abort(); | |
1072 | ||
1073 | /* Construct the high word */ | |
1074 | if (d3 == 0) | |
c3741733 | 1075 | r1 = copy_to_suggested_reg (GEN_INT (d4), subtarget, DImode); |
97aea203 | 1076 | else if (d4 == 0) |
c3741733 | 1077 | r1 = copy_to_suggested_reg (GEN_INT (d3), subtarget, DImode); |
97aea203 | 1078 | else |
c3741733 RK |
1079 | r1 = expand_binop (DImode, add_optab, GEN_INT (d3), GEN_INT (d4), |
1080 | subtarget, 0, OPTAB_WIDEN); | |
97aea203 RK |
1081 | |
1082 | /* Shift it into place */ | |
c3741733 RK |
1083 | r2 = expand_binop (DImode, ashl_optab, r1, GEN_INT (32), |
1084 | subtarget, 0, OPTAB_WIDEN); | |
97aea203 | 1085 | |
c3741733 RK |
1086 | if (subtarget == 0 && d1 == d3 && d2 == d4) |
1087 | r1 = expand_binop (DImode, add_optab, r1, r2, subtarget, 0, OPTAB_WIDEN); | |
1088 | else | |
1089 | { | |
1090 | r1 = r2; | |
1091 | ||
1092 | /* Add in the low word */ | |
1093 | if (d2 != 0) | |
1094 | r1 = expand_binop (DImode, add_optab, r1, GEN_INT (d2), | |
1095 | subtarget, 0, OPTAB_WIDEN); | |
1096 | if (d1 != 0) | |
1097 | r1 = expand_binop (DImode, add_optab, r1, GEN_INT (d1), | |
1098 | subtarget, 0, OPTAB_WIDEN); | |
1099 | } | |
97aea203 RK |
1100 | |
1101 | if (subtarget == 0) | |
c3741733 | 1102 | r1 = copy_to_suggested_reg(r1, target, DImode); |
97aea203 | 1103 | |
c3741733 | 1104 | return r1; |
97aea203 RK |
1105 | } |
1106 | #endif /* HOST_BITS_PER_WIDE_INT == 64 */ | |
1107 | ||
758d2c0c RK |
1108 | /* Rewrite a comparison against zero CMP of the form |
1109 | (CODE (cc0) (const_int 0)) so it can be written validly in | |
1110 | a conditional move (if_then_else CMP ...). | |
1111 | If both of the operands that set cc0 are non-zero we must emit | |
1112 | an insn to perform the compare (it can't be done within | |
1113 | the conditional move). */ | |
1114 | rtx | |
1115 | alpha_emit_conditional_move (cmp, mode) | |
1116 | rtx cmp; | |
1117 | enum machine_mode mode; | |
1118 | { | |
1ad2a62d | 1119 | enum rtx_code code = GET_CODE (cmp); |
89b7c471 | 1120 | enum rtx_code cmov_code = NE; |
758d2c0c RK |
1121 | rtx op0 = alpha_compare_op0; |
1122 | rtx op1 = alpha_compare_op1; | |
1ad2a62d RK |
1123 | enum machine_mode cmp_mode |
1124 | = (GET_MODE (op0) == VOIDmode ? DImode : GET_MODE (op0)); | |
1125 | enum machine_mode cmp_op_mode = alpha_compare_fp_p ? DFmode : DImode; | |
1126 | rtx tem; | |
758d2c0c | 1127 | |
1ad2a62d | 1128 | if (alpha_compare_fp_p != FLOAT_MODE_P (mode)) |
758d2c0c RK |
1129 | return 0; |
1130 | ||
1131 | /* We may be able to use a conditional move directly. | |
1132 | This avoids emitting spurious compares. */ | |
1ad2a62d RK |
1133 | if (signed_comparison_operator (cmp, cmp_op_mode) |
1134 | && (op0 == CONST0_RTX (cmp_mode) || op1 == CONST0_RTX (cmp_mode))) | |
1135 | return gen_rtx (code, VOIDmode, op0, op1); | |
758d2c0c RK |
1136 | |
1137 | /* We can't put the comparison insides a conditional move; | |
1138 | emit a compare instruction and put that inside the | |
1ad2a62d RK |
1139 | conditional move. Make sure we emit only comparisons we have; |
1140 | swap or reverse as necessary. */ | |
758d2c0c | 1141 | |
758d2c0c RK |
1142 | switch (code) |
1143 | { | |
1ad2a62d RK |
1144 | case EQ: case LE: case LT: case LEU: case LTU: |
1145 | /* We have these compares: */ | |
758d2c0c | 1146 | break; |
1ad2a62d | 1147 | |
758d2c0c | 1148 | case NE: |
1ad2a62d RK |
1149 | /* This must be reversed. */ |
1150 | code = reverse_condition (code); | |
89b7c471 | 1151 | cmov_code = EQ; |
758d2c0c | 1152 | break; |
1ad2a62d RK |
1153 | |
1154 | case GE: case GT: case GEU: case GTU: | |
1155 | /* These must be swapped. Make sure the new first operand is in | |
1156 | a register. */ | |
1157 | code = swap_condition (code); | |
1158 | tem = op0, op0 = op1, op1 = tem; | |
1159 | op0 = force_reg (cmp_mode, op0); | |
758d2c0c | 1160 | break; |
1ad2a62d | 1161 | |
758d2c0c | 1162 | default: |
1ad2a62d | 1163 | abort (); |
758d2c0c RK |
1164 | } |
1165 | ||
1ad2a62d RK |
1166 | tem = gen_reg_rtx (cmp_op_mode); |
1167 | emit_move_insn (tem, gen_rtx (code, cmp_op_mode, op0, op1)); | |
89b7c471 | 1168 | return gen_rtx (cmov_code, VOIDmode, tem, CONST0_RTX (cmp_op_mode)); |
758d2c0c | 1169 | } |
a6f12d7c RK |
1170 | \f |
1171 | /* Adjust the cost of a scheduling dependency. Return the new cost of | |
1172 | a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ | |
1173 | ||
1174 | int | |
1175 | alpha_adjust_cost (insn, link, dep_insn, cost) | |
1176 | rtx insn; | |
1177 | rtx link; | |
1178 | rtx dep_insn; | |
1179 | int cost; | |
1180 | { | |
74835ed8 | 1181 | rtx set, set_src; |
a6f12d7c RK |
1182 | |
1183 | /* If the dependence is an anti-dependence, there is no cost. For an | |
1184 | output dependence, there is sometimes a cost, but it doesn't seem | |
1185 | worth handling those few cases. */ | |
1186 | ||
1187 | if (REG_NOTE_KIND (link) != 0) | |
1188 | return 0; | |
1189 | ||
da792a68 RK |
1190 | if (alpha_cpu == PROCESSOR_EV5) |
1191 | { | |
74835ed8 RH |
1192 | /* On EV5, "A special bypass provides an effective latency of 0 |
1193 | cycles for an ICMP or ILOG insn producing the test operand of an | |
1194 | IBR or CMOV insn." */ | |
1195 | ||
da792a68 RK |
1196 | if (recog_memoized (dep_insn) >= 0 |
1197 | && (get_attr_type (dep_insn) == TYPE_ICMP | |
1198 | || get_attr_type (dep_insn) == TYPE_ILOG) | |
1199 | && recog_memoized (insn) >= 0 | |
1200 | && (get_attr_type (insn) == TYPE_IBR | |
1201 | || (get_attr_type (insn) == TYPE_CMOV | |
1202 | && !((set = single_set (dep_insn)) != 0 | |
1203 | && GET_CODE (PATTERN (insn)) == SET | |
74835ed8 RH |
1204 | && (set_src = SET_SRC (PATTERN (insn)), |
1205 | GET_CODE (set_src) == IF_THEN_ELSE) | |
1206 | && (set = SET_DEST (set), | |
1207 | rtx_equal_p (set, XEXP (set_src, 1)) | |
1208 | || rtx_equal_p (set, XEXP (set_src, 2))))))) | |
1209 | return 0; | |
1210 | ||
1211 | /* On EV5 it takes longer to get data to the multiplier than to | |
1212 | anywhere else, so increase costs. */ | |
1213 | ||
1214 | if (recog_memoized (insn) >= 0 | |
1215 | && recog_memoized (dep_insn) >= 0 | |
1216 | && (get_attr_type (insn) == TYPE_IMULL | |
1217 | || get_attr_type (insn) == TYPE_IMULQ | |
1218 | || get_attr_type (insn) == TYPE_IMULH) | |
1219 | && (set = single_set (dep_insn)) != 0 | |
1220 | && GET_CODE (PATTERN (insn)) == SET | |
1221 | && (set_src = SET_SRC (PATTERN (insn)), | |
1222 | GET_CODE (set_src) == MULT) | |
1223 | && (set = SET_DEST (set), | |
1224 | rtx_equal_p (set, XEXP (set_src, 0)) | |
1225 | || rtx_equal_p (set, XEXP (set_src, 1)))) | |
1226 | { | |
1227 | switch (get_attr_type (insn)) | |
1228 | { | |
1229 | case TYPE_LD: | |
1230 | case TYPE_CMOV: | |
1231 | case TYPE_IMULL: | |
1232 | case TYPE_IMULQ: | |
1233 | case TYPE_IMULH: | |
1234 | return cost + 1; | |
1235 | case TYPE_JSR: | |
1236 | case TYPE_IADD: | |
1237 | case TYPE_ILOG: | |
1238 | case TYPE_SHIFT: | |
1239 | case TYPE_ICMP: | |
1240 | return cost + 2; | |
1241 | } | |
1242 | } | |
1243 | } | |
1244 | else | |
1245 | { | |
1246 | /* On EV4, if INSN is a store insn and DEP_INSN is setting the data | |
1247 | being stored, we can sometimes lower the cost. */ | |
1248 | ||
1249 | if (recog_memoized (insn) >= 0 && get_attr_type (insn) == TYPE_ST | |
1250 | && (set = single_set (dep_insn)) != 0 | |
1251 | && GET_CODE (PATTERN (insn)) == SET | |
1252 | && rtx_equal_p (SET_DEST (set), SET_SRC (PATTERN (insn)))) | |
1253 | { | |
1254 | switch (get_attr_type (dep_insn)) | |
1255 | { | |
1256 | case TYPE_LD: | |
1257 | /* No savings here. */ | |
1258 | return cost; | |
1259 | ||
1260 | case TYPE_IMULL: | |
1261 | case TYPE_IMULQ: | |
1262 | case TYPE_IMULH: | |
1263 | /* In these cases, we save one cycle. */ | |
1264 | return cost - 1; | |
1265 | ||
1266 | default: | |
1267 | /* In all other cases, we save two cycles. */ | |
1268 | return MAX (0, cost - 2); | |
1269 | } | |
1270 | } | |
1271 | ||
1272 | /* Another case that needs adjustment is an arithmetic or logical | |
1273 | operation. It's cost is usually one cycle, but we default it to | |
1274 | two in the MD file. The only case that it is actually two is | |
1275 | for the address in loads and stores. */ | |
1276 | ||
1277 | if (recog_memoized (dep_insn) >= 0 | |
1278 | && (get_attr_type (dep_insn) == TYPE_IADD | |
1279 | || get_attr_type (dep_insn) == TYPE_ILOG)) | |
1280 | { | |
1281 | switch (get_attr_type (insn)) | |
1282 | { | |
1283 | case TYPE_LD: | |
1284 | case TYPE_ST: | |
1285 | return cost; | |
1286 | default: | |
1287 | return 1; | |
1288 | } | |
1289 | } | |
1290 | ||
1291 | /* The final case is when a compare feeds into an integer branch; | |
1292 | the cost is only one cycle in that case. */ | |
1293 | ||
1294 | if (recog_memoized (dep_insn) >= 0 | |
1295 | && get_attr_type (dep_insn) == TYPE_ICMP | |
1296 | && recog_memoized (insn) >= 0 | |
1297 | && get_attr_type (insn) == TYPE_IBR) | |
da792a68 | 1298 | return 1; |
74835ed8 | 1299 | } |
a6f12d7c RK |
1300 | |
1301 | /* Otherwise, return the default cost. */ | |
a6f12d7c RK |
1302 | return cost; |
1303 | } | |
9ecc37f0 RH |
1304 | \f |
1305 | /* Functions to save and restore alpha_return_addr_rtx. */ | |
1306 | ||
1307 | struct machine_function | |
1308 | { | |
1309 | rtx ra_rtx; | |
1310 | }; | |
1311 | ||
1312 | static void | |
1313 | alpha_save_machine_status (p) | |
1314 | struct function *p; | |
1315 | { | |
1316 | struct machine_function *machine = | |
1317 | (struct machine_function *) xmalloc (sizeof (struct machine_function)); | |
1318 | ||
1319 | p->machine = machine; | |
1320 | machine->ra_rtx = alpha_return_addr_rtx; | |
1321 | } | |
1322 | ||
1323 | static void | |
1324 | alpha_restore_machine_status (p) | |
1325 | struct function *p; | |
1326 | { | |
1327 | struct machine_function *machine = p->machine; | |
1328 | ||
1329 | alpha_return_addr_rtx = machine->ra_rtx; | |
1330 | ||
1331 | free (machine); | |
1332 | p->machine = (struct machine_function *)0; | |
1333 | } | |
1334 | ||
1335 | /* Do anything needed before RTL is emitted for each function. */ | |
1336 | ||
1337 | void | |
1338 | alpha_init_expanders () | |
1339 | { | |
1340 | alpha_return_addr_rtx = NULL_RTX; | |
1341 | ||
1342 | /* Arrange to save and restore machine status around nested functions. */ | |
1343 | save_machine_status = alpha_save_machine_status; | |
1344 | restore_machine_status = alpha_restore_machine_status; | |
1345 | } | |
1346 | ||
1347 | /* Start the ball rolling with RETURN_ADDR_RTX. */ | |
1348 | ||
1349 | rtx | |
1350 | alpha_return_addr (count, frame) | |
1351 | int count; | |
1352 | rtx frame; | |
1353 | { | |
1354 | rtx init, first; | |
1355 | ||
1356 | if (count != 0) | |
1357 | return const0_rtx; | |
1358 | ||
1359 | if (alpha_return_addr_rtx) | |
1360 | return alpha_return_addr_rtx; | |
1361 | ||
1362 | /* No rtx yet. Invent one, and initialize it from $26 in the prologue. */ | |
1363 | alpha_return_addr_rtx = gen_reg_rtx (Pmode); | |
1364 | init = gen_rtx (SET, Pmode, alpha_return_addr_rtx, gen_rtx (REG, Pmode, 26)); | |
1365 | ||
1366 | /* Emit the insn to the prologue with the other argument copies. */ | |
1367 | push_topmost_sequence (); | |
1368 | emit_insn_after (init, get_insns ()); | |
1369 | pop_topmost_sequence (); | |
1370 | ||
1371 | return alpha_return_addr_rtx; | |
1372 | } | |
1373 | ||
1374 | static int | |
1375 | alpha_ra_ever_killed () | |
1376 | { | |
1377 | rtx i, ra; | |
1378 | ||
1379 | if (!alpha_return_addr_rtx) | |
1380 | return regs_ever_live[REG_RA]; | |
1381 | ||
1382 | return reg_set_between_p (gen_rtx (REG, REG_RA), get_insns(), NULL_RTX); | |
1383 | } | |
1384 | ||
a6f12d7c RK |
1385 | \f |
1386 | /* Print an operand. Recognize special options, documented below. */ | |
1387 | ||
1388 | void | |
1389 | print_operand (file, x, code) | |
1390 | FILE *file; | |
1391 | rtx x; | |
1392 | char code; | |
1393 | { | |
1394 | int i; | |
1395 | ||
1396 | switch (code) | |
1397 | { | |
6245e3df RK |
1398 | case '&': |
1399 | /* Generates fp-rounding mode suffix: nothing for normal, 'c' for | |
1400 | chopped, 'm' for minus-infinity, and 'd' for dynamic rounding | |
1401 | mode. alpha_fprm controls which suffix is generated. */ | |
1402 | switch (alpha_fprm) | |
1403 | { | |
1404 | case ALPHA_FPRM_NORM: | |
1405 | break; | |
1406 | case ALPHA_FPRM_MINF: | |
1407 | fputc ('m', file); | |
1408 | break; | |
1409 | case ALPHA_FPRM_CHOP: | |
1410 | fputc ('c', file); | |
1411 | break; | |
1412 | case ALPHA_FPRM_DYN: | |
1413 | fputc ('d', file); | |
1414 | break; | |
1415 | } | |
1416 | break; | |
1417 | ||
1418 | case '\'': | |
1419 | /* Generates trap-mode suffix for instructions that accept the su | |
1420 | suffix only (cmpt et al). */ | |
1421 | if (alpha_tp == ALPHA_TP_INSN) | |
1422 | fputs ("su", file); | |
1423 | break; | |
1424 | ||
1425 | case ')': | |
1426 | /* Generates trap-mode suffix for instructions that accept the u, su, | |
1427 | and sui suffix. This is the bulk of the IEEE floating point | |
1428 | instructions (addt et al). */ | |
1429 | switch (alpha_fptm) | |
1430 | { | |
1431 | case ALPHA_FPTM_N: | |
1432 | break; | |
1433 | case ALPHA_FPTM_U: | |
1434 | fputc ('u', file); | |
1435 | break; | |
1436 | case ALPHA_FPTM_SU: | |
1437 | fputs ("su", file); | |
1438 | break; | |
1439 | case ALPHA_FPTM_SUI: | |
1440 | fputs ("sui", file); | |
1441 | break; | |
1442 | } | |
1443 | break; | |
1444 | ||
1445 | case '+': | |
1446 | /* Generates trap-mode suffix for instructions that accept the sui | |
1447 | suffix (cvtqt and cvtqs). */ | |
1448 | switch (alpha_fptm) | |
1449 | { | |
1450 | case ALPHA_FPTM_N: case ALPHA_FPTM_U: | |
1451 | case ALPHA_FPTM_SU: /* cvtqt/cvtqs can't cause underflow */ | |
1452 | break; | |
1453 | case ALPHA_FPTM_SUI: | |
1454 | fputs ("sui", file); | |
1455 | break; | |
1456 | } | |
1457 | break; | |
1458 | ||
89cfc2c6 RK |
1459 | case ',': |
1460 | /* Generates single precision instruction suffix. */ | |
e9a25f70 | 1461 | fprintf (file, "%c", (TARGET_FLOAT_VAX ? 'f' : 's')); |
89cfc2c6 RK |
1462 | break; |
1463 | ||
1464 | case '-': | |
1465 | /* Generates double precision instruction suffix. */ | |
e9a25f70 | 1466 | fprintf (file, "%c", (TARGET_FLOAT_VAX ? 'g' : 't')); |
89cfc2c6 RK |
1467 | break; |
1468 | ||
a6f12d7c RK |
1469 | case 'r': |
1470 | /* If this operand is the constant zero, write it as "$31". */ | |
1471 | if (GET_CODE (x) == REG) | |
1472 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
1473 | else if (x == CONST0_RTX (GET_MODE (x))) | |
1474 | fprintf (file, "$31"); | |
1475 | else | |
1476 | output_operand_lossage ("invalid %%r value"); | |
1477 | ||
1478 | break; | |
1479 | ||
1480 | case 'R': | |
1481 | /* Similar, but for floating-point. */ | |
1482 | if (GET_CODE (x) == REG) | |
1483 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
1484 | else if (x == CONST0_RTX (GET_MODE (x))) | |
1485 | fprintf (file, "$f31"); | |
1486 | else | |
1487 | output_operand_lossage ("invalid %%R value"); | |
1488 | ||
1489 | break; | |
1490 | ||
1491 | case 'N': | |
1492 | /* Write the 1's complement of a constant. */ | |
1493 | if (GET_CODE (x) != CONST_INT) | |
1494 | output_operand_lossage ("invalid %%N value"); | |
1495 | ||
0bc8ae6e | 1496 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INTVAL (x)); |
a6f12d7c RK |
1497 | break; |
1498 | ||
1499 | case 'P': | |
1500 | /* Write 1 << C, for a constant C. */ | |
1501 | if (GET_CODE (x) != CONST_INT) | |
1502 | output_operand_lossage ("invalid %%P value"); | |
1503 | ||
0bc8ae6e | 1504 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT) 1 << INTVAL (x)); |
a6f12d7c RK |
1505 | break; |
1506 | ||
1507 | case 'h': | |
1508 | /* Write the high-order 16 bits of a constant, sign-extended. */ | |
1509 | if (GET_CODE (x) != CONST_INT) | |
1510 | output_operand_lossage ("invalid %%h value"); | |
1511 | ||
0bc8ae6e | 1512 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) >> 16); |
a6f12d7c RK |
1513 | break; |
1514 | ||
1515 | case 'L': | |
1516 | /* Write the low-order 16 bits of a constant, sign-extended. */ | |
1517 | if (GET_CODE (x) != CONST_INT) | |
1518 | output_operand_lossage ("invalid %%L value"); | |
1519 | ||
0bc8ae6e RK |
1520 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, |
1521 | (INTVAL (x) & 0xffff) - 2 * (INTVAL (x) & 0x8000)); | |
a6f12d7c RK |
1522 | break; |
1523 | ||
1524 | case 'm': | |
1525 | /* Write mask for ZAP insn. */ | |
1526 | if (GET_CODE (x) == CONST_DOUBLE) | |
1527 | { | |
1528 | HOST_WIDE_INT mask = 0; | |
1529 | HOST_WIDE_INT value; | |
1530 | ||
1531 | value = CONST_DOUBLE_LOW (x); | |
1532 | for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; | |
1533 | i++, value >>= 8) | |
1534 | if (value & 0xff) | |
1535 | mask |= (1 << i); | |
1536 | ||
1537 | value = CONST_DOUBLE_HIGH (x); | |
1538 | for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; | |
1539 | i++, value >>= 8) | |
1540 | if (value & 0xff) | |
1541 | mask |= (1 << (i + sizeof (int))); | |
1542 | ||
0bc8ae6e | 1543 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask & 0xff); |
a6f12d7c RK |
1544 | } |
1545 | ||
1546 | else if (GET_CODE (x) == CONST_INT) | |
1547 | { | |
1548 | HOST_WIDE_INT mask = 0, value = INTVAL (x); | |
1549 | ||
1550 | for (i = 0; i < 8; i++, value >>= 8) | |
1551 | if (value & 0xff) | |
1552 | mask |= (1 << i); | |
1553 | ||
0bc8ae6e | 1554 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask); |
a6f12d7c RK |
1555 | } |
1556 | else | |
1557 | output_operand_lossage ("invalid %%m value"); | |
1558 | break; | |
1559 | ||
1560 | case 'M': | |
1561 | /* 'b', 'w', or 'l' as the value of the constant. */ | |
1562 | if (GET_CODE (x) != CONST_INT | |
1563 | || (INTVAL (x) != 8 && INTVAL (x) != 16 && INTVAL (x) != 32)) | |
1564 | output_operand_lossage ("invalid %%M value"); | |
1565 | ||
1566 | fprintf (file, "%s", | |
1567 | INTVAL (x) == 8 ? "b" : INTVAL (x) == 16 ? "w" : "l"); | |
1568 | break; | |
1569 | ||
1570 | case 'U': | |
1571 | /* Similar, except do it from the mask. */ | |
1572 | if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xff) | |
1573 | fprintf (file, "b"); | |
1574 | else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffff) | |
1575 | fprintf (file, "w"); | |
1576 | #if HOST_BITS_PER_WIDE_INT == 32 | |
1577 | else if (GET_CODE (x) == CONST_DOUBLE | |
1578 | && CONST_DOUBLE_HIGH (x) == 0 | |
1579 | && CONST_DOUBLE_LOW (x) == -1) | |
1580 | fprintf (file, "l"); | |
1581 | #else | |
1582 | else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffff) | |
1583 | fprintf (file, "l"); | |
1584 | #endif | |
1585 | else | |
1586 | output_operand_lossage ("invalid %%U value"); | |
1587 | break; | |
1588 | ||
1589 | case 's': | |
1590 | /* Write the constant value divided by 8. */ | |
1591 | if (GET_CODE (x) != CONST_INT | |
1592 | && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 | |
1593 | && (INTVAL (x) & 7) != 8) | |
1594 | output_operand_lossage ("invalid %%s value"); | |
1595 | ||
0bc8ae6e | 1596 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) / 8); |
a6f12d7c RK |
1597 | break; |
1598 | ||
1599 | case 'S': | |
1600 | /* Same, except compute (64 - c) / 8 */ | |
1601 | ||
1602 | if (GET_CODE (x) != CONST_INT | |
1603 | && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 | |
1604 | && (INTVAL (x) & 7) != 8) | |
1605 | output_operand_lossage ("invalid %%s value"); | |
1606 | ||
0bc8ae6e | 1607 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, (64 - INTVAL (x)) / 8); |
a6f12d7c RK |
1608 | break; |
1609 | ||
bdd4c95a | 1610 | case 'C': case 'D': case 'c': case 'd': |
a6f12d7c | 1611 | /* Write out comparison name. */ |
bdd4c95a RK |
1612 | { |
1613 | enum rtx_code c = GET_CODE (x); | |
1614 | ||
1615 | if (GET_RTX_CLASS (c) != '<') | |
1616 | output_operand_lossage ("invalid %%C value"); | |
1617 | ||
1618 | if (code == 'D') | |
1619 | c = reverse_condition (c); | |
1620 | else if (code == 'c') | |
1621 | c = swap_condition (c); | |
1622 | else if (code == 'd') | |
1623 | c = swap_condition (reverse_condition (c)); | |
1624 | ||
1625 | if (c == LEU) | |
1626 | fprintf (file, "ule"); | |
1627 | else if (c == LTU) | |
1628 | fprintf (file, "ult"); | |
1629 | else | |
1630 | fprintf (file, "%s", GET_RTX_NAME (c)); | |
1631 | } | |
ab561e66 RK |
1632 | break; |
1633 | ||
a6f12d7c RK |
1634 | case 'E': |
1635 | /* Write the divide or modulus operator. */ | |
1636 | switch (GET_CODE (x)) | |
1637 | { | |
1638 | case DIV: | |
1639 | fprintf (file, "div%s", GET_MODE (x) == SImode ? "l" : "q"); | |
1640 | break; | |
1641 | case UDIV: | |
1642 | fprintf (file, "div%su", GET_MODE (x) == SImode ? "l" : "q"); | |
1643 | break; | |
1644 | case MOD: | |
1645 | fprintf (file, "rem%s", GET_MODE (x) == SImode ? "l" : "q"); | |
1646 | break; | |
1647 | case UMOD: | |
1648 | fprintf (file, "rem%su", GET_MODE (x) == SImode ? "l" : "q"); | |
1649 | break; | |
1650 | default: | |
1651 | output_operand_lossage ("invalid %%E value"); | |
1652 | break; | |
1653 | } | |
1654 | break; | |
1655 | ||
a6f12d7c RK |
1656 | case 'A': |
1657 | /* Write "_u" for unaligned access. */ | |
1658 | if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == AND) | |
1659 | fprintf (file, "_u"); | |
1660 | break; | |
1661 | ||
1662 | case 0: | |
1663 | if (GET_CODE (x) == REG) | |
1664 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
1665 | else if (GET_CODE (x) == MEM) | |
1666 | output_address (XEXP (x, 0)); | |
1667 | else | |
1668 | output_addr_const (file, x); | |
1669 | break; | |
1670 | ||
1671 | default: | |
1672 | output_operand_lossage ("invalid %%xn code"); | |
1673 | } | |
1674 | } | |
1675 | \f | |
1676 | /* Do what is necessary for `va_start'. The argument is ignored; | |
937868a2 | 1677 | We look at the current function to determine if stdarg or varargs |
a6f12d7c RK |
1678 | is used and fill in an initial va_list. A pointer to this constructor |
1679 | is returned. */ | |
1680 | ||
1681 | struct rtx_def * | |
1682 | alpha_builtin_saveregs (arglist) | |
1683 | tree arglist; | |
1684 | { | |
5b838011 | 1685 | rtx block, addr, dest, argsize; |
a6f12d7c | 1686 | tree fntype = TREE_TYPE (current_function_decl); |
937868a2 RK |
1687 | int stdarg = (TYPE_ARG_TYPES (fntype) != 0 |
1688 | && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) | |
1689 | != void_type_node)); | |
a6f12d7c | 1690 | |
0f33506c | 1691 | /* Compute the current position into the args, taking into account |
29587b1c | 1692 | both registers and memory. Both of these are already included in |
e9a25f70 | 1693 | NUM_ARGS. */ |
a6f12d7c | 1694 | |
e9a25f70 | 1695 | argsize = GEN_INT (NUM_ARGS * UNITS_PER_WORD); |
29587b1c | 1696 | |
89cfc2c6 | 1697 | /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base up by 48, |
29587b1c JW |
1698 | storing fp arg registers in the first 48 bytes, and the integer arg |
1699 | registers in the next 48 bytes. This is only done, however, if any | |
1700 | integer registers need to be stored. | |
1701 | ||
1702 | If no integer registers need be stored, then we must subtract 48 in | |
1703 | order to account for the integer arg registers which are counted in | |
1704 | argsize above, but which are not actually stored on the stack. */ | |
1705 | ||
89cfc2c6 RK |
1706 | if (TARGET_OPEN_VMS) |
1707 | addr = plus_constant (virtual_incoming_args_rtx, | |
e9a25f70 | 1708 | NUM_ARGS <= 5 + stdarg |
89cfc2c6 RK |
1709 | ? UNITS_PER_WORD : - 6 * UNITS_PER_WORD); |
1710 | else | |
e9a25f70 | 1711 | addr = (NUM_ARGS <= 5 + stdarg |
89cfc2c6 RK |
1712 | ? plus_constant (virtual_incoming_args_rtx, |
1713 | 6 * UNITS_PER_WORD) | |
1714 | : plus_constant (virtual_incoming_args_rtx, | |
1715 | - (6 * UNITS_PER_WORD))); | |
1d783d31 | 1716 | |
89cfc2c6 RK |
1717 | /* For VMS, we include the argsize, while on Unix, it's handled as |
1718 | a separate field. */ | |
1719 | if (TARGET_OPEN_VMS) | |
1720 | addr = plus_constant (addr, INTVAL (argsize)); | |
a6f12d7c | 1721 | |
89cfc2c6 | 1722 | addr = force_operand (addr, NULL_RTX); |
1d783d31 RK |
1723 | |
1724 | #ifdef POINTERS_EXTEND_UNSIGNED | |
1725 | addr = convert_memory_address (ptr_mode, addr); | |
1726 | #endif | |
1727 | ||
89cfc2c6 RK |
1728 | if (TARGET_OPEN_VMS) |
1729 | return addr; | |
1730 | else | |
1731 | { | |
1732 | /* Allocate the va_list constructor */ | |
1733 | block = assign_stack_local (BLKmode, 2 * UNITS_PER_WORD, BITS_PER_WORD); | |
1734 | RTX_UNCHANGING_P (block) = 1; | |
1735 | RTX_UNCHANGING_P (XEXP (block, 0)) = 1; | |
1736 | ||
1737 | /* Store the address of the first integer register in the __base | |
1738 | member. */ | |
1739 | ||
5b838011 RK |
1740 | dest = change_address (block, ptr_mode, XEXP (block, 0)); |
1741 | emit_move_insn (dest, addr); | |
89cfc2c6 | 1742 | |
5b838011 RK |
1743 | if (flag_check_memory_usage) |
1744 | emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, dest, | |
1745 | ptr_mode, GEN_INT (GET_MODE_SIZE (ptr_mode)), | |
1746 | TYPE_MODE (sizetype), | |
1747 | GEN_INT (MEMORY_USE_RW), QImode); | |
1748 | ||
89cfc2c6 | 1749 | /* Store the argsize as the __va_offset member. */ |
5b838011 RK |
1750 | dest = change_address (block, TYPE_MODE (integer_type_node), |
1751 | plus_constant (XEXP (block, 0), | |
1752 | POINTER_SIZE/BITS_PER_UNIT)); | |
1753 | emit_move_insn (dest, argsize); | |
1754 | ||
1755 | if (flag_check_memory_usage) | |
1756 | emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, dest, | |
1757 | ptr_mode, | |
1758 | GEN_INT (GET_MODE_SIZE | |
1759 | (TYPE_MODE (integer_type_node))), | |
1760 | TYPE_MODE (sizetype), | |
1761 | GEN_INT (MEMORY_USE_RW), QImode); | |
89cfc2c6 RK |
1762 | |
1763 | /* Return the address of the va_list constructor, but don't put it in a | |
1764 | register. Doing so would fail when not optimizing and produce worse | |
1765 | code when optimizing. */ | |
1766 | return XEXP (block, 0); | |
1767 | } | |
a6f12d7c RK |
1768 | } |
1769 | \f | |
e9a25f70 JL |
1770 | #if OPEN_VMS |
1771 | #define REG_PV 27 | |
1772 | #define REG_RA 26 | |
1773 | #else | |
1774 | #define REG_RA 26 | |
1775 | #endif | |
1776 | ||
1777 | /* Find the current function's return address. | |
1778 | ||
1779 | ??? It would be better to arrange things such that if we would ordinarily | |
1780 | have been a leaf function and we didn't spill the hard reg that we | |
1781 | wouldn't have to save the register in the prolog. But it's not clear | |
1782 | how to get the right information at the right time. */ | |
1783 | ||
1784 | static rtx alpha_return_addr_rtx; | |
1785 | ||
1786 | rtx | |
1787 | alpha_return_addr () | |
1788 | { | |
1789 | rtx ret; | |
1790 | ||
1791 | if ((ret = alpha_return_addr_rtx) == NULL) | |
1792 | { | |
1793 | alpha_return_addr_rtx = ret = gen_reg_rtx (Pmode); | |
1794 | ||
1795 | emit_insn_after (gen_rtx (SET, VOIDmode, ret, | |
1796 | gen_rtx (REG, Pmode, REG_RA)), | |
1797 | get_insns ()); | |
1798 | } | |
1799 | ||
1800 | return ret; | |
1801 | } | |
1802 | ||
a6f12d7c RK |
1803 | /* This page contains routines that are used to determine what the function |
1804 | prologue and epilogue code will do and write them out. */ | |
1805 | ||
1806 | /* Compute the size of the save area in the stack. */ | |
1807 | ||
89cfc2c6 RK |
1808 | #if OPEN_VMS |
1809 | ||
89cfc2c6 RK |
1810 | /* These variables are used for communication between the following functions. |
1811 | They indicate various things about the current function being compiled | |
1812 | that are used to tell what kind of prologue, epilogue and procedure | |
1813 | descriptior to generate. */ | |
1814 | ||
1815 | /* Nonzero if we need a stack procedure. */ | |
1816 | static int is_stack_procedure; | |
1817 | ||
1818 | /* Register number (either FP or SP) that is used to unwind the frame. */ | |
1819 | static int unwind_regno; | |
1820 | ||
1821 | /* Register number used to save FP. We need not have one for RA since | |
1822 | we don't modify it for register procedures. This is only defined | |
1823 | for register frame procedures. */ | |
1824 | static int save_fp_regno; | |
1825 | ||
1826 | /* Register number used to reference objects off our PV. */ | |
1827 | static int base_regno; | |
1828 | ||
1829 | /* Compute register masks for saved registers. */ | |
1830 | ||
1831 | static void | |
1832 | alpha_sa_mask (imaskP, fmaskP) | |
1833 | unsigned long *imaskP; | |
1834 | unsigned long *fmaskP; | |
1835 | { | |
1836 | unsigned long imask = 0; | |
1837 | unsigned long fmask = 0; | |
1838 | int i; | |
1839 | ||
1840 | if (is_stack_procedure) | |
1841 | imask |= (1L << HARD_FRAME_POINTER_REGNUM); | |
1842 | ||
1843 | /* One for every register we have to save. */ | |
1844 | ||
1845 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
9ecc37f0 RH |
1846 | if (! fixed_regs[i] && ! call_used_regs[i] |
1847 | && regs_ever_live[i] && i != REG_RA) | |
89cfc2c6 RK |
1848 | { |
1849 | if (i < 32) | |
1850 | imask |= (1L << i); | |
1851 | else | |
1852 | fmask |= (1L << (i - 32)); | |
1853 | } | |
1854 | ||
1855 | *imaskP = imask; | |
1856 | *fmaskP = fmask; | |
1857 | ||
1858 | return; | |
1859 | } | |
1860 | ||
1861 | int | |
1862 | alpha_sa_size () | |
1863 | { | |
1864 | int sa_size = 0; | |
1865 | HOST_WIDE_INT stack_needed; | |
1866 | int i; | |
1867 | ||
1868 | /* One for every register we have to save. */ | |
1869 | ||
1870 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
9ecc37f0 RH |
1871 | if (! fixed_regs[i] && ! call_used_regs[i] |
1872 | && regs_ever_live[i] && i != REG_RA) | |
89cfc2c6 RK |
1873 | sa_size++; |
1874 | ||
1875 | /* Start by assuming we can use a register procedure if we don't make any | |
1876 | calls (REG_RA not used) or need to save any registers and a stack | |
1877 | procedure if we do. */ | |
9ecc37f0 | 1878 | is_stack_procedure = sa_size != 0 || alpha_ra_ever_killed (); |
89cfc2c6 RK |
1879 | |
1880 | /* Decide whether to refer to objects off our PV via FP or PV. | |
1881 | If we need need FP for something else or if we receive a nonlocal | |
1882 | goto (which expects PV to contain the value), we must use PV. | |
1883 | Otherwise, start by assuming we can use FP. */ | |
1884 | base_regno = (frame_pointer_needed || current_function_has_nonlocal_label | |
1885 | || is_stack_procedure | |
1886 | || current_function_outgoing_args_size | |
1887 | ? REG_PV : HARD_FRAME_POINTER_REGNUM); | |
1888 | ||
1889 | /* If we want to copy PV into FP, we need to find some register in which to | |
1890 | save FP. */ | |
1891 | ||
1892 | save_fp_regno = -1; | |
1893 | ||
1894 | if (base_regno == HARD_FRAME_POINTER_REGNUM) | |
1895 | for (i = 0; i < 32; i++) | |
1896 | if (! fixed_regs[i] && call_used_regs[i] && ! regs_ever_live[i]) | |
1897 | save_fp_regno = i; | |
1898 | ||
1899 | if (save_fp_regno == -1) | |
1900 | base_regno = REG_PV, is_stack_procedure = 1; | |
1901 | ||
1902 | /* Stack unwinding should be done via FP unless we use it for PV. */ | |
1903 | unwind_regno | |
1904 | = base_regno == REG_PV ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM; | |
1905 | ||
1906 | /* If this is a stack procedure, allow space for saving FP and RA. */ | |
1907 | if (is_stack_procedure) | |
1908 | sa_size += 2; | |
1909 | ||
1910 | return sa_size * 8; | |
1911 | } | |
1912 | ||
1913 | int | |
1914 | alpha_pv_save_size () | |
1915 | { | |
1916 | alpha_sa_size (); | |
1917 | return is_stack_procedure ? 8 : 0; | |
1918 | } | |
1919 | ||
1920 | int | |
1921 | alpha_using_fp () | |
1922 | { | |
1923 | alpha_sa_size (); | |
1924 | return unwind_regno == HARD_FRAME_POINTER_REGNUM; | |
1925 | } | |
1926 | ||
1927 | #else /* ! OPEN_VMS */ | |
1928 | ||
a6f12d7c RK |
1929 | int |
1930 | alpha_sa_size () | |
1931 | { | |
1932 | int size = 0; | |
1933 | int i; | |
1934 | ||
1935 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
9ecc37f0 RH |
1936 | if (! fixed_regs[i] && ! call_used_regs[i] |
1937 | && regs_ever_live[i] && i != REG_RA) | |
a6f12d7c RK |
1938 | size++; |
1939 | ||
c97e3db7 RK |
1940 | /* If some registers were saved but not reg 26, reg 26 must also |
1941 | be saved, so leave space for it. */ | |
9ecc37f0 | 1942 | if (size != 0 || alpha_ra_ever_killed ()) |
0f33506c | 1943 | size++; |
a6f12d7c | 1944 | |
d60a05a1 RK |
1945 | /* Our size must be even (multiple of 16 bytes). */ |
1946 | if (size & 1) | |
1947 | size ++; | |
1948 | ||
0f33506c | 1949 | return size * 8; |
a6f12d7c RK |
1950 | } |
1951 | ||
89cfc2c6 RK |
1952 | #endif /* ! OPEN_VMS */ |
1953 | ||
a6f12d7c RK |
1954 | /* Return 1 if this function can directly return via $26. */ |
1955 | ||
1956 | int | |
1957 | direct_return () | |
1958 | { | |
89cfc2c6 | 1959 | return (! TARGET_OPEN_VMS && reload_completed && alpha_sa_size () == 0 |
a6f12d7c | 1960 | && get_frame_size () == 0 |
f13703f9 | 1961 | && current_function_outgoing_args_size == 0 |
a6f12d7c RK |
1962 | && current_function_pretend_args_size == 0); |
1963 | } | |
1964 | ||
0f33506c RK |
1965 | /* Write a version stamp. Don't write anything if we are running as a |
1966 | cross-compiler. Otherwise, use the versions in /usr/include/stamp.h. */ | |
1967 | ||
89cfc2c6 | 1968 | #if !defined(CROSS_COMPILE) && !defined(_WIN32) && !defined(__linux__) && !defined(VMS) |
0f33506c RK |
1969 | #include <stamp.h> |
1970 | #endif | |
1971 | ||
1972 | void | |
1973 | alpha_write_verstamp (file) | |
1974 | FILE *file; | |
1975 | { | |
1976 | #ifdef MS_STAMP | |
aec4ca5e | 1977 | fprintf (file, "\t.verstamp %d %d\n", MS_STAMP, LS_STAMP); |
0f33506c RK |
1978 | #endif |
1979 | } | |
ec6840c1 RK |
1980 | \f |
1981 | /* Write code to add constant C to register number IN_REG (possibly 31) | |
d60a05a1 RK |
1982 | and put the result into OUT_REG. Use TEMP_REG as a scratch register; |
1983 | usually this will be OUT_REG, but should not be if OUT_REG is | |
1984 | STACK_POINTER_REGNUM, since it must be updated in a single instruction. | |
1985 | Write the code to FILE. */ | |
ec6840c1 RK |
1986 | |
1987 | static void | |
d60a05a1 | 1988 | add_long_const (file, c, in_reg, out_reg, temp_reg) |
ec6840c1 | 1989 | FILE *file; |
d60a05a1 RK |
1990 | HOST_WIDE_INT c; |
1991 | int in_reg, out_reg, temp_reg; | |
ec6840c1 RK |
1992 | { |
1993 | HOST_WIDE_INT low = (c & 0xffff) - 2 * (c & 0x8000); | |
1994 | HOST_WIDE_INT tmp1 = c - low; | |
1995 | HOST_WIDE_INT high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); | |
1996 | HOST_WIDE_INT extra = 0; | |
1997 | ||
1998 | /* We don't have code to write out constants larger than 32 bits. */ | |
1999 | #if HOST_BITS_PER_LONG_INT == 64 | |
2000 | if ((unsigned HOST_WIDE_INT) c >> 32 != 0) | |
2001 | abort (); | |
2002 | #endif | |
2003 | ||
2004 | /* If HIGH will be interpreted as negative, we must adjust it to do two | |
2005 | ldha insns. Note that we will never be building a negative constant | |
2006 | here. */ | |
2007 | ||
2008 | if (high & 0x8000) | |
2009 | { | |
2010 | extra = 0x4000; | |
2011 | tmp1 -= 0x40000000; | |
2012 | high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); | |
2013 | } | |
2014 | ||
2015 | if (low != 0) | |
2016 | { | |
d60a05a1 RK |
2017 | int result_reg = (extra == 0 && high == 0) ? out_reg : temp_reg; |
2018 | ||
ec6840c1 | 2019 | if (low >= 0 && low < 255) |
d60a05a1 | 2020 | fprintf (file, "\taddq $%d,%d,$%d\n", in_reg, low, result_reg); |
ec6840c1 | 2021 | else |
d60a05a1 RK |
2022 | fprintf (file, "\tlda $%d,%d($%d)\n", result_reg, low, in_reg); |
2023 | ||
2024 | in_reg = result_reg; | |
ec6840c1 RK |
2025 | } |
2026 | ||
2027 | if (extra) | |
2028 | { | |
d60a05a1 RK |
2029 | int result_reg = (high == 0) ? out_reg : temp_reg; |
2030 | ||
2031 | fprintf (file, "\tldah $%d,%d($%d)\n", result_reg, extra, in_reg); | |
2032 | in_reg = result_reg; | |
ec6840c1 RK |
2033 | } |
2034 | ||
2035 | if (high) | |
2036 | fprintf (file, "\tldah $%d,%d($%d)\n", out_reg, high, in_reg); | |
2037 | } | |
0f33506c | 2038 | |
a6f12d7c RK |
2039 | /* Write function prologue. */ |
2040 | ||
89cfc2c6 RK |
2041 | #if OPEN_VMS |
2042 | ||
89cfc2c6 RK |
2043 | /* On vms we have two kinds of functions: |
2044 | ||
2045 | - stack frame (PROC_STACK) | |
2046 | these are 'normal' functions with local vars and which are | |
2047 | calling other functions | |
2048 | - register frame (PROC_REGISTER) | |
2049 | keeps all data in registers, needs no stack | |
2050 | ||
2051 | We must pass this to the assembler so it can generate the | |
2052 | proper pdsc (procedure descriptor) | |
2053 | This is done with the '.pdesc' command. | |
2054 | ||
2055 | size is the stack size needed for local variables. */ | |
2056 | ||
2057 | void | |
2058 | output_prolog (file, size) | |
2059 | FILE *file; | |
44afaf6d | 2060 | HOST_WIDE_INT size; |
89cfc2c6 RK |
2061 | { |
2062 | unsigned long imask = 0; | |
2063 | unsigned long fmask = 0; | |
2064 | /* Stack space needed for pushing registers clobbered by us. */ | |
2065 | HOST_WIDE_INT sa_size; | |
2066 | /* Complete stack size needed. */ | |
2067 | HOST_WIDE_INT frame_size; | |
2068 | /* Offset from base reg to register save area. */ | |
2069 | int rsa_offset = 8; | |
2070 | /* Offset during register save. */ | |
2071 | int reg_offset; | |
2072 | /* Label for the procedure entry. */ | |
a3b0df2d | 2073 | char *entry_label = (char *) alloca (strlen (alpha_function_name) + 5); |
89cfc2c6 RK |
2074 | int i; |
2075 | ||
2076 | sa_size = alpha_sa_size (); | |
2077 | frame_size | |
2078 | = ALPHA_ROUND (sa_size | |
2079 | + (is_stack_procedure ? 8 : 0) | |
2080 | + size + current_function_pretend_args_size); | |
2081 | ||
89cfc2c6 RK |
2082 | /* Issue function start and label. */ |
2083 | fprintf (file, "\t.ent "); | |
2084 | assemble_name (file, alpha_function_name); | |
2085 | fprintf (file, "\n"); | |
a3b0df2d | 2086 | sprintf (entry_label, "%s..en", alpha_function_name); |
89cfc2c6 RK |
2087 | ASM_OUTPUT_LABEL (file, entry_label); |
2088 | inside_function = TRUE; | |
2089 | ||
2090 | fprintf (file, "\t.base $%d\n", base_regno); | |
2091 | ||
2092 | /* Calculate register masks for clobbered registers. */ | |
2093 | ||
2094 | if (is_stack_procedure) | |
2095 | alpha_sa_mask (&imask, &fmask); | |
2096 | ||
2097 | /* Adjust the stack by the frame size. If the frame size is > 4096 | |
2098 | bytes, we need to be sure we probe somewhere in the first and last | |
2099 | 4096 bytes (we can probably get away without the latter test) and | |
2100 | every 8192 bytes in between. If the frame size is > 32768, we | |
2101 | do this in a loop. Otherwise, we generate the explicit probe | |
2102 | instructions. | |
2103 | ||
2104 | Note that we are only allowed to adjust sp once in the prologue. */ | |
2105 | ||
2106 | if (frame_size < 32768) | |
2107 | { | |
2108 | if (frame_size > 4096) | |
2109 | { | |
2110 | int probed = 4096; | |
2111 | ||
2112 | fprintf (file, "\tstq $31,-%d($30)\n", probed); | |
2113 | ||
2114 | while (probed + 8192 < frame_size) | |
2115 | fprintf (file, "\tstq $31,-%d($30)\n", probed += 8192); | |
2116 | ||
2117 | /* We only have to do this probe if we aren't saving registers. */ | |
2118 | if (sa_size == 0 && probed + 4096 < frame_size) | |
2119 | fprintf (file, "\tstq $31,-%d($30)\n", frame_size); | |
2120 | } | |
2121 | ||
2122 | if (frame_size != 0) | |
2123 | fprintf (file, "\tlda $30,-%d($30)\n", frame_size); | |
2124 | } | |
2125 | else | |
2126 | { | |
2127 | /* Here we generate code to set R4 to SP + 4096 and set R23 to the | |
2128 | number of 8192 byte blocks to probe. We then probe each block | |
2129 | in the loop and then set SP to the proper location. If the | |
2130 | amount remaining is > 4096, we have to do one more probe if we | |
2131 | are not saving any registers. */ | |
2132 | ||
2133 | HOST_WIDE_INT blocks = (frame_size + 4096) / 8192; | |
2134 | HOST_WIDE_INT leftover = frame_size + 4096 - blocks * 8192; | |
2135 | ||
2136 | add_long_const (file, blocks, 31, 23, 23); | |
2137 | ||
2138 | fprintf (file, "\tlda $22,4096($30)\n"); | |
2139 | ||
2140 | assemble_name (file, alpha_function_name); | |
2141 | fprintf (file, "..sc:\n"); | |
2142 | ||
2143 | fprintf (file, "\tstq $31,-8192($22)\n"); | |
2144 | fprintf (file, "\tsubq $23,1,$23\n"); | |
2145 | fprintf (file, "\tlda $22,-8192($22)\n"); | |
2146 | ||
2147 | fprintf (file, "\tbne $23,"); | |
2148 | assemble_name (file, alpha_function_name); | |
2149 | fprintf (file, "..sc\n"); | |
2150 | ||
2151 | if (leftover > 4096 && sa_size == 0) | |
2152 | fprintf (file, "\tstq $31,-%d($22)\n", leftover); | |
2153 | ||
2154 | fprintf (file, "\tlda $30,-%d($22)\n", leftover); | |
2155 | } | |
2156 | ||
2157 | if (is_stack_procedure) | |
2158 | { | |
2159 | int reg_offset = rsa_offset; | |
2160 | ||
2161 | /* Store R26 (RA) first. */ | |
2162 | fprintf (file, "\tstq $26,%d($30)\n", reg_offset); | |
2163 | reg_offset += 8; | |
2164 | ||
2165 | /* Store integer regs. according to mask. */ | |
2166 | for (i = 0; i < 32; i++) | |
2167 | if (imask & (1L<<i)) | |
2168 | { | |
2169 | fprintf (file, "\tstq $%d,%d($30)\n", i, reg_offset); | |
2170 | reg_offset += 8; | |
2171 | } | |
2172 | ||
2173 | /* Print the register mask and do floating-point saves. */ | |
2174 | ||
2175 | if (imask) | |
2176 | fprintf (file, "\t.mask 0x%x,0\n", imask); | |
2177 | ||
2178 | for (i = 0; i < 32; i++) | |
2179 | { | |
2180 | if (fmask & (1L << i)) | |
2181 | { | |
2182 | fprintf (file, "\tstt $f%d,%d($30)\n", i, reg_offset); | |
2183 | reg_offset += 8; | |
2184 | } | |
2185 | } | |
2186 | ||
2187 | /* Print the floating-point mask, if we've saved any fp register. */ | |
2188 | if (fmask) | |
2189 | fprintf (file, "\t.fmask 0x%x,0\n", fmask); | |
2190 | ||
2191 | fprintf (file, "\tstq $27,0($30)\n"); | |
2192 | } | |
2193 | else | |
2194 | { | |
2195 | fprintf (file, "\t.fp_save $%d\n", save_fp_regno); | |
2196 | fprintf (file, "\tbis $%d,$%d,$%d\n", HARD_FRAME_POINTER_REGNUM, | |
2197 | HARD_FRAME_POINTER_REGNUM, save_fp_regno); | |
2198 | } | |
2199 | ||
2200 | if (base_regno != REG_PV) | |
2201 | fprintf (file, "\tbis $%d,$%d,$%d\n", REG_PV, REG_PV, base_regno); | |
2202 | ||
2203 | if (unwind_regno == HARD_FRAME_POINTER_REGNUM) | |
2204 | fprintf (file, "\tbis $%d,$%d,$%d\n", STACK_POINTER_REGNUM, | |
2205 | STACK_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM); | |
2206 | ||
2207 | /* Describe our frame. */ | |
2208 | fprintf (file, "\t.frame $%d,%d,$26,%d\n", | |
2209 | unwind_regno, frame_size, rsa_offset); | |
2210 | ||
2211 | /* If we have to allocate space for outgoing args, do it now. */ | |
2212 | if (current_function_outgoing_args_size != 0) | |
2213 | fprintf (file, "\tlda $%d,%d($%d)\n", STACK_POINTER_REGNUM, | |
2214 | - ALPHA_ROUND (current_function_outgoing_args_size), | |
2215 | HARD_FRAME_POINTER_REGNUM); | |
2216 | ||
2217 | fprintf (file, "\t.prologue\n"); | |
2218 | ||
2219 | link_section (); | |
2220 | fprintf (file, "\t.align 3\n"); | |
2221 | ASM_OUTPUT_LABEL (file, alpha_function_name); | |
2222 | fprintf (file, "\t.pdesc "); | |
2223 | assemble_name (file, alpha_function_name); | |
2224 | fprintf (file, "..en,%s\n", is_stack_procedure ? "stack" : "reg"); | |
2225 | alpha_need_linkage (alpha_function_name, 1); | |
2226 | text_section (); | |
2227 | ||
2228 | return; | |
2229 | } | |
2230 | ||
2231 | /* Write function epilogue. */ | |
2232 | ||
2233 | void | |
2234 | output_epilog (file, size) | |
2235 | FILE *file; | |
2236 | int size; | |
2237 | { | |
2238 | unsigned long imask = 0; | |
2239 | unsigned long fmask = 0; | |
2240 | /* Stack space needed for pushing registers clobbered by us. */ | |
2241 | HOST_WIDE_INT sa_size = alpha_sa_size (); | |
2242 | /* Complete stack size needed. */ | |
2243 | HOST_WIDE_INT frame_size | |
2244 | = ALPHA_ROUND (sa_size | |
2245 | + (is_stack_procedure ? 8 : 0) | |
2246 | + size + current_function_pretend_args_size); | |
2247 | int i; | |
2248 | rtx insn = get_last_insn (); | |
2249 | ||
2250 | /* If the last insn was a BARRIER, we don't have to write anything except | |
2251 | the .end pseudo-op. */ | |
2252 | ||
2253 | if (GET_CODE (insn) == NOTE) | |
2254 | insn = prev_nonnote_insn (insn); | |
2255 | ||
2256 | if (insn == 0 || GET_CODE (insn) != BARRIER) | |
2257 | { | |
2258 | /* Restore clobbered registers, load FP last. */ | |
2259 | ||
2260 | if (is_stack_procedure) | |
2261 | { | |
2262 | int rsa_offset = 8; | |
2263 | int reg_offset; | |
2264 | int fp_offset; | |
2265 | ||
2266 | if (unwind_regno == HARD_FRAME_POINTER_REGNUM) | |
2267 | fprintf (file, "\tbis $%d,$%d,$%d\n", HARD_FRAME_POINTER_REGNUM, | |
2268 | HARD_FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM); | |
2269 | ||
2270 | alpha_sa_mask (&imask, &fmask); | |
2271 | ||
2272 | /* Start reloading registers after RA. */ | |
2273 | reg_offset = rsa_offset + 8; | |
2274 | ||
2275 | for (i = 0; i < 32; i++) | |
2276 | if (imask & (1L<<i)) | |
2277 | { | |
2278 | if (i == HARD_FRAME_POINTER_REGNUM) | |
2279 | fp_offset = reg_offset; | |
2280 | else | |
2281 | fprintf (file, "\tldq $%d,%d($30)\n", | |
2282 | i, reg_offset); | |
2283 | reg_offset += 8; | |
2284 | } | |
2285 | ||
2286 | for (i = 0; i < 32; i++) | |
2287 | if (fmask & (1L << i)) | |
2288 | { | |
2289 | fprintf (file, "\tldt $f%d,%d($30)\n", i, reg_offset); | |
2290 | reg_offset += 8; | |
2291 | } | |
2292 | ||
2293 | /* Restore R26 (RA). */ | |
2294 | fprintf (file, "\tldq $26,%d($30)\n", rsa_offset); | |
2295 | ||
2296 | /* Restore R29 (FP). */ | |
2297 | fprintf (file, "\tldq $29,%d($30)\n", fp_offset); | |
2298 | } | |
2299 | else | |
2300 | fprintf (file, "\tbis $%d,$%d,$%d\n", save_fp_regno, save_fp_regno, | |
2301 | HARD_FRAME_POINTER_REGNUM); | |
2302 | ||
2303 | if (frame_size != 0) | |
2304 | { | |
2305 | if (frame_size < 32768) | |
2306 | fprintf (file, "\tlda $30,%d($30)\n", frame_size); | |
2307 | else | |
2308 | { | |
2309 | long high = frame_size >> 16; | |
2310 | long low = frame_size & 0xffff; | |
2311 | if (low & 0x8000) | |
2312 | { | |
2313 | high++; | |
2314 | low = -32768 + (low & 0x7fff); | |
2315 | } | |
2316 | fprintf (file, "\tldah $2,%ld($31)\n", high); | |
2317 | fprintf (file, "\tlda $2,%ld($2)\n", low); | |
2318 | fprintf (file, "\taddq $30,$2,$30\n"); | |
2319 | } | |
2320 | } | |
2321 | ||
2322 | /* Finally return to the caller. */ | |
2323 | fprintf (file, "\tret $31,($26),1\n"); | |
2324 | } | |
2325 | ||
2326 | /* End the function. */ | |
2327 | fprintf (file, "\t.end "); | |
2328 | assemble_name (file, alpha_function_name); | |
2329 | fprintf (file, "\n"); | |
2330 | inside_function = FALSE; | |
2331 | ||
2332 | /* Show that we know this function if it is called again. */ | |
2333 | SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1; | |
2334 | } | |
2335 | ||
2336 | #else /* !OPEN_VMS */ | |
2337 | ||
9ecc37f0 RH |
2338 | static int |
2339 | alpha_does_function_need_gp () | |
2340 | { | |
2341 | rtx insn; | |
2342 | ||
2343 | /* We never need a GP for Windows/NT. */ | |
2344 | if (TARGET_WINDOWS_NT) | |
2345 | return 0; | |
2346 | ||
2347 | #ifdef TARGET_PROFILING_NEEDS_GP | |
2348 | if (profile_flag) | |
2349 | return 1; | |
2350 | #endif | |
2351 | ||
2352 | /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first. | |
2353 | Even if we are a static function, we still need to do this in case | |
2354 | our address is taken and passed to something like qsort. */ | |
2355 | ||
2356 | for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) | |
2357 | if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' | |
2358 | && GET_CODE (PATTERN (insn)) != USE | |
2359 | && GET_CODE (PATTERN (insn)) != CLOBBER) | |
2360 | { | |
2361 | enum attr_type type = get_attr_type (insn); | |
2362 | if (type == TYPE_LDSYM || type == TYPE_JSR) | |
2363 | return 1; | |
2364 | } | |
2365 | ||
2366 | return 0; | |
2367 | } | |
2368 | ||
e9a25f70 JL |
2369 | int |
2370 | vms_valid_decl_attribute_p (decl, attributes, identifier, args) | |
2371 | tree decl; | |
2372 | tree attributes; | |
2373 | tree identifier; | |
2374 | tree args; | |
2375 | { | |
2376 | if (is_attribute_p ("overlaid", identifier)) | |
2377 | return (args == NULL_TREE); | |
2378 | return 0; | |
2379 | } | |
2380 | ||
a6f12d7c RK |
2381 | void |
2382 | output_prolog (file, size) | |
2383 | FILE *file; | |
2384 | int size; | |
2385 | { | |
d60a05a1 RK |
2386 | HOST_WIDE_INT out_args_size |
2387 | = ALPHA_ROUND (current_function_outgoing_args_size); | |
2388 | HOST_WIDE_INT sa_size = alpha_sa_size (); | |
2389 | HOST_WIDE_INT frame_size | |
2390 | = (out_args_size + sa_size | |
2391 | + ALPHA_ROUND (size + current_function_pretend_args_size)); | |
2392 | HOST_WIDE_INT reg_offset = out_args_size; | |
ec6840c1 RK |
2393 | HOST_WIDE_INT start_reg_offset = reg_offset; |
2394 | HOST_WIDE_INT actual_start_reg_offset = start_reg_offset; | |
0273f326 | 2395 | int int_reg_save_area_size = 0; |
a6f12d7c | 2396 | unsigned reg_mask = 0; |
0d24ff5d | 2397 | int i, sa_reg; |
a6f12d7c | 2398 | |
d60a05a1 | 2399 | /* Ecoff can handle multiple .file directives, so put out file and lineno. |
48f6bfac RK |
2400 | We have to do that before the .ent directive as we cannot switch |
2401 | files within procedures with native ecoff because line numbers are | |
2402 | linked to procedure descriptors. | |
2403 | Outputting the lineno helps debugging of one line functions as they | |
2404 | would otherwise get no line number at all. Please note that we would | |
ddd5a7c1 | 2405 | like to put out last_linenum from final.c, but it is not accessible. */ |
48f6bfac RK |
2406 | |
2407 | if (write_symbols == SDB_DEBUG) | |
2408 | { | |
2409 | ASM_OUTPUT_SOURCE_FILENAME (file, | |
2410 | DECL_SOURCE_FILE (current_function_decl)); | |
2411 | if (debug_info_level != DINFO_LEVEL_TERSE) | |
d60a05a1 RK |
2412 | ASM_OUTPUT_SOURCE_LINE (file, |
2413 | DECL_SOURCE_LINE (current_function_decl)); | |
48f6bfac RK |
2414 | } |
2415 | ||
2416 | /* The assembly language programmer's guide states that the second argument | |
2417 | to the .ent directive, the lex_level, is ignored by the assembler, | |
2418 | so we might as well omit it. */ | |
2419 | ||
33d01c33 RK |
2420 | if (!flag_inhibit_size_directive) |
2421 | { | |
2422 | fprintf (file, "\t.ent "); | |
2423 | assemble_name (file, alpha_function_name); | |
2424 | fprintf (file, "\n"); | |
2425 | } | |
48f6bfac RK |
2426 | ASM_OUTPUT_LABEL (file, alpha_function_name); |
2427 | inside_function = TRUE; | |
2428 | ||
33d01c33 | 2429 | if (TARGET_IEEE_CONFORMANT && !flag_inhibit_size_directive) |
6245e3df RK |
2430 | /* Set flags in procedure descriptor to request IEEE-conformant |
2431 | math-library routines. The value we set it to is PDSC_EXC_IEEE | |
2432 | (/usr/include/pdsc.h). */ | |
2433 | fprintf (file, "\t.eflag 48\n"); | |
2434 | ||
48f6bfac RK |
2435 | /* Set up offsets to alpha virtual arg/local debugging pointer. */ |
2436 | ||
2437 | alpha_auto_offset = -frame_size + current_function_pretend_args_size; | |
2438 | alpha_arg_offset = -frame_size + 48; | |
2439 | ||
9ecc37f0 | 2440 | alpha_function_needs_gp = alpha_does_function_need_gp (); |
a6f12d7c | 2441 | |
6c882425 | 2442 | if (TARGET_WINDOWS_NT == 0) |
9973f4a2 RK |
2443 | { |
2444 | if (alpha_function_needs_gp) | |
2445 | fprintf (file, "\tldgp $29,0($27)\n"); | |
a6f12d7c | 2446 | |
9973f4a2 RK |
2447 | /* Put a label after the GP load so we can enter the function at it. */ |
2448 | assemble_name (file, alpha_function_name); | |
2449 | fprintf (file, "..ng:\n"); | |
2450 | } | |
a6f12d7c | 2451 | |
c97e3db7 RK |
2452 | /* Adjust the stack by the frame size. If the frame size is > 4096 |
2453 | bytes, we need to be sure we probe somewhere in the first and last | |
2454 | 4096 bytes (we can probably get away without the latter test) and | |
2455 | every 8192 bytes in between. If the frame size is > 32768, we | |
2456 | do this in a loop. Otherwise, we generate the explicit probe | |
2457 | instructions. | |
a6f12d7c | 2458 | |
c97e3db7 RK |
2459 | Note that we are only allowed to adjust sp once in the prologue. */ |
2460 | ||
2461 | if (frame_size < 32768) | |
2462 | { | |
2463 | if (frame_size > 4096) | |
2464 | { | |
2465 | int probed = 4096; | |
c97e3db7 | 2466 | |
ea8e4ec5 | 2467 | fprintf (file, "\tstq $31,-%d($30)\n", probed); |
c97e3db7 RK |
2468 | |
2469 | while (probed + 8192 < frame_size) | |
ea8e4ec5 | 2470 | fprintf (file, "\tstq $31,-%d($30)\n", probed += 8192); |
c97e3db7 | 2471 | |
d60a05a1 RK |
2472 | /* We only have to do this probe if we aren't saving registers. */ |
2473 | if (sa_size == 0 && probed + 4096 < frame_size) | |
ea8e4ec5 | 2474 | fprintf (file, "\tstq $31,-%d($30)\n", frame_size); |
c97e3db7 RK |
2475 | } |
2476 | ||
2477 | if (frame_size != 0) | |
2478 | fprintf (file, "\tlda $30,-%d($30)\n", frame_size); | |
2479 | } | |
2480 | else | |
a6f12d7c | 2481 | { |
c97e3db7 RK |
2482 | /* Here we generate code to set R4 to SP + 4096 and set R5 to the |
2483 | number of 8192 byte blocks to probe. We then probe each block | |
2484 | in the loop and then set SP to the proper location. If the | |
d60a05a1 RK |
2485 | amount remaining is > 4096, we have to do one more probe if we |
2486 | are not saving any registers. */ | |
c97e3db7 RK |
2487 | |
2488 | HOST_WIDE_INT blocks = (frame_size + 4096) / 8192; | |
2489 | HOST_WIDE_INT leftover = frame_size + 4096 - blocks * 8192; | |
a6f12d7c | 2490 | |
d60a05a1 | 2491 | add_long_const (file, blocks, 31, 5, 5); |
c97e3db7 RK |
2492 | |
2493 | fprintf (file, "\tlda $4,4096($30)\n"); | |
5b9589fe RK |
2494 | |
2495 | assemble_name (file, alpha_function_name); | |
2496 | fprintf (file, "..sc:\n"); | |
2497 | ||
ea8e4ec5 | 2498 | fprintf (file, "\tstq $31,-8192($4)\n"); |
c97e3db7 RK |
2499 | fprintf (file, "\tsubq $5,1,$5\n"); |
2500 | fprintf (file, "\tlda $4,-8192($4)\n"); | |
5b9589fe | 2501 | |
28c1753a | 2502 | fprintf (file, "\tbne $5,"); |
5b9589fe | 2503 | assemble_name (file, alpha_function_name); |
28c1753a | 2504 | fprintf (file, "..sc\n"); |
5b9589fe | 2505 | |
d60a05a1 | 2506 | if (leftover > 4096 && sa_size == 0) |
ea8e4ec5 RK |
2507 | fprintf (file, "\tstq $31,-%d($4)\n", leftover); |
2508 | ||
2509 | fprintf (file, "\tlda $30,-%d($4)\n", leftover); | |
a6f12d7c | 2510 | } |
a6f12d7c | 2511 | |
0f33506c | 2512 | /* Describe our frame. */ |
33d01c33 RK |
2513 | if (!flag_inhibit_size_directive) |
2514 | { | |
2515 | fprintf (file, "\t.frame $%d,%d,$26,%d\n", | |
2516 | (frame_pointer_needed | |
2517 | ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM), | |
2518 | frame_size, current_function_pretend_args_size); | |
2519 | } | |
0d24ff5d RH |
2520 | |
2521 | /* Cope with very large offsets to the register save area. */ | |
2522 | sa_reg = 30; | |
2523 | if (reg_offset + sa_size > 0x8000) | |
2524 | { | |
2525 | int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000; | |
2526 | if (low + sa_size <= 0x8000) | |
2527 | { | |
2528 | add_long_const (file, reg_offset - low, 30, 24, 24); | |
2529 | reg_offset = low; | |
2530 | } | |
2531 | else | |
2532 | { | |
2533 | add_long_const (file, reg_offset, 30, 24, 24); | |
2534 | reg_offset = 0; | |
2535 | } | |
2536 | sa_reg = 24; | |
2537 | } | |
a6f12d7c | 2538 | |
9ecc37f0 | 2539 | /* Save register RA if any other register needs to be saved. */ |
d60a05a1 | 2540 | if (sa_size != 0) |
a6f12d7c | 2541 | { |
9ecc37f0 | 2542 | reg_mask |= 1 << REG_RA; |
0d24ff5d | 2543 | fprintf (file, "\tstq $26,%d($%d)\n", reg_offset, sa_reg); |
a6f12d7c | 2544 | reg_offset += 8; |
0273f326 | 2545 | int_reg_save_area_size += 8; |
a6f12d7c RK |
2546 | } |
2547 | ||
0f33506c | 2548 | /* Now save any other used integer registers required to be saved. */ |
a6f12d7c | 2549 | for (i = 0; i < 32; i++) |
9ecc37f0 RH |
2550 | if (! fixed_regs[i] && ! call_used_regs[i] |
2551 | && regs_ever_live[i] && i != REG_RA) | |
a6f12d7c RK |
2552 | { |
2553 | reg_mask |= 1 << i; | |
0d24ff5d | 2554 | fprintf (file, "\tstq $%d,%d($%d)\n", i, reg_offset, sa_reg); |
a6f12d7c | 2555 | reg_offset += 8; |
0273f326 | 2556 | int_reg_save_area_size += 8; |
a6f12d7c RK |
2557 | } |
2558 | ||
2559 | /* Print the register mask and do floating-point saves. */ | |
33d01c33 | 2560 | if (reg_mask && !flag_inhibit_size_directive) |
a6f12d7c | 2561 | fprintf (file, "\t.mask 0x%x,%d\n", reg_mask, |
ec6840c1 | 2562 | actual_start_reg_offset - frame_size); |
a6f12d7c RK |
2563 | |
2564 | start_reg_offset = reg_offset; | |
2565 | reg_mask = 0; | |
2566 | ||
2567 | for (i = 0; i < 32; i++) | |
2568 | if (! fixed_regs[i + 32] && ! call_used_regs[i + 32] | |
2569 | && regs_ever_live[i + 32]) | |
2570 | { | |
2571 | reg_mask |= 1 << i; | |
0d24ff5d | 2572 | fprintf (file, "\tstt $f%d,%d($%d)\n", i, reg_offset, sa_reg); |
a6f12d7c RK |
2573 | reg_offset += 8; |
2574 | } | |
2575 | ||
2576 | /* Print the floating-point mask, if we've saved any fp register. */ | |
33d01c33 | 2577 | if (reg_mask && !flag_inhibit_size_directive) |
0273f326 RK |
2578 | fprintf (file, "\t.fmask 0x%x,%d\n", reg_mask, |
2579 | actual_start_reg_offset - frame_size + int_reg_save_area_size); | |
a6f12d7c | 2580 | |
0f33506c RK |
2581 | /* If we need a frame pointer, set it from the stack pointer. Note that |
2582 | this must always be the last instruction in the prologue. */ | |
a6f12d7c | 2583 | if (frame_pointer_needed) |
0f33506c RK |
2584 | fprintf (file, "\tbis $30,$30,$15\n"); |
2585 | ||
2586 | /* End the prologue and say if we used gp. */ | |
33d01c33 RK |
2587 | if (!flag_inhibit_size_directive) |
2588 | fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp); | |
a6f12d7c RK |
2589 | } |
2590 | ||
2591 | /* Write function epilogue. */ | |
2592 | ||
2593 | void | |
2594 | output_epilog (file, size) | |
2595 | FILE *file; | |
2596 | int size; | |
2597 | { | |
2598 | rtx insn = get_last_insn (); | |
d60a05a1 RK |
2599 | HOST_WIDE_INT out_args_size |
2600 | = ALPHA_ROUND (current_function_outgoing_args_size); | |
2601 | HOST_WIDE_INT sa_size = alpha_sa_size (); | |
2602 | HOST_WIDE_INT frame_size | |
2603 | = (out_args_size + sa_size | |
2604 | + ALPHA_ROUND (size + current_function_pretend_args_size)); | |
2605 | HOST_WIDE_INT reg_offset = out_args_size; | |
ec6840c1 | 2606 | HOST_WIDE_INT frame_size_from_reg_save = frame_size - reg_offset; |
d60a05a1 RK |
2607 | int restore_fp |
2608 | = frame_pointer_needed && regs_ever_live[HARD_FRAME_POINTER_REGNUM]; | |
a6f12d7c RK |
2609 | int i; |
2610 | ||
2611 | /* If the last insn was a BARRIER, we don't have to write anything except | |
2612 | the .end pseudo-op. */ | |
2613 | if (GET_CODE (insn) == NOTE) | |
2614 | insn = prev_nonnote_insn (insn); | |
2615 | if (insn == 0 || GET_CODE (insn) != BARRIER) | |
2616 | { | |
d1085180 | 2617 | int fp_offset = 0; |
0d24ff5d | 2618 | int sa_reg; |
a6f12d7c | 2619 | |
0f33506c | 2620 | /* If we have a frame pointer, restore SP from it. */ |
a6f12d7c | 2621 | if (frame_pointer_needed) |
0f33506c | 2622 | fprintf (file, "\tbis $15,$15,$30\n"); |
a6f12d7c | 2623 | |
0d24ff5d RH |
2624 | /* Cope with large offsets to the register save area. */ |
2625 | sa_reg = 30; | |
2626 | if (reg_offset + sa_size > 0x8000) | |
2627 | { | |
2628 | int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000; | |
2629 | if (low + sa_size <= 0x8000) | |
2630 | { | |
2631 | add_long_const (file, reg_offset - low, 30, 24, 24); | |
2632 | reg_offset = low; | |
2633 | } | |
2634 | else | |
2635 | { | |
2636 | add_long_const (file, reg_offset, 30, 24, 24); | |
2637 | reg_offset = 0; | |
2638 | } | |
2639 | sa_reg = 24; | |
2640 | } | |
2641 | ||
a6f12d7c RK |
2642 | /* Restore all the registers, starting with the return address |
2643 | register. */ | |
d60a05a1 | 2644 | if (sa_size != 0) |
a6f12d7c | 2645 | { |
0d24ff5d | 2646 | fprintf (file, "\tldq $26,%d($%d)\n", reg_offset, sa_reg); |
a6f12d7c RK |
2647 | reg_offset += 8; |
2648 | } | |
2649 | ||
0f33506c RK |
2650 | /* Now restore any other used integer registers that that we saved, |
2651 | except for FP if it is being used as FP, since it must be | |
2652 | restored last. */ | |
2653 | ||
a6f12d7c RK |
2654 | for (i = 0; i < 32; i++) |
2655 | if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i] | |
2656 | && i != 26) | |
2657 | { | |
d60a05a1 | 2658 | if (i == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) |
0f33506c RK |
2659 | fp_offset = reg_offset; |
2660 | else | |
0d24ff5d | 2661 | fprintf (file, "\tldq $%d,%d($%d)\n", i, reg_offset, sa_reg); |
a6f12d7c RK |
2662 | reg_offset += 8; |
2663 | } | |
2664 | ||
2665 | for (i = 0; i < 32; i++) | |
2666 | if (! fixed_regs[i + 32] && ! call_used_regs[i + 32] | |
2667 | && regs_ever_live[i + 32]) | |
2668 | { | |
0d24ff5d | 2669 | fprintf (file, "\tldt $f%d,%d($%d)\n", i, reg_offset, sa_reg); |
a6f12d7c RK |
2670 | reg_offset += 8; |
2671 | } | |
2672 | ||
d60a05a1 RK |
2673 | /* If the stack size is large and we have a frame pointer, compute the |
2674 | size of the stack into a register because the old FP restore, stack | |
2675 | pointer adjust, and return are required to be consecutive | |
2676 | instructions. */ | |
2677 | if (frame_size > 32767 && restore_fp) | |
2678 | add_long_const (file, frame_size, 31, 1, 1); | |
0f33506c RK |
2679 | |
2680 | /* If we needed a frame pointer and we have to restore it, do it | |
ec6840c1 RK |
2681 | now. This must be done in one instruction immediately |
2682 | before the SP update. */ | |
d1085180 | 2683 | if (restore_fp && fp_offset) |
0d24ff5d | 2684 | fprintf (file, "\tldq $15,%d($%d)\n", fp_offset, sa_reg); |
0f33506c | 2685 | |
d60a05a1 RK |
2686 | /* Now update the stack pointer, if needed. Only one instruction must |
2687 | modify the stack pointer. It must be the last instruction in the | |
2688 | sequence and must be an ADDQ or LDA instruction. If the frame | |
2689 | pointer was loaded above, we may only put one instruction here. */ | |
2690 | ||
2691 | if (frame_size > 32768 && restore_fp) | |
2692 | fprintf (file, "\taddq $1,$30,$30\n"); | |
2693 | else | |
2694 | add_long_const (file, frame_size, 30, 30, 1); | |
a6f12d7c | 2695 | |
0f33506c | 2696 | /* Finally return to the caller. */ |
a6f12d7c RK |
2697 | fprintf (file, "\tret $31,($26),1\n"); |
2698 | } | |
2699 | ||
2700 | /* End the function. */ | |
33d01c33 RK |
2701 | if (!flag_inhibit_size_directive) |
2702 | { | |
2703 | fprintf (file, "\t.end "); | |
2704 | assemble_name (file, alpha_function_name); | |
2705 | fprintf (file, "\n"); | |
2706 | } | |
48f6bfac | 2707 | inside_function = FALSE; |
9973f4a2 RK |
2708 | |
2709 | /* Show that we know this function if it is called again. */ | |
2710 | SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1; | |
e9a25f70 JL |
2711 | |
2712 | alpha_return_addr_rtx = 0; | |
a6f12d7c | 2713 | } |
89cfc2c6 | 2714 | #endif /* !OPEN_VMS */ |
48f6bfac RK |
2715 | \f |
2716 | /* Debugging support. */ | |
2717 | ||
2718 | #include "gstab.h" | |
2719 | ||
2720 | /* Count the number of sdb related labels are generated (to find block | |
2721 | start and end boundaries). */ | |
2722 | ||
2723 | int sdb_label_count = 0; | |
2724 | ||
2725 | /* Next label # for each statement. */ | |
2726 | ||
2727 | static int sym_lineno = 0; | |
2728 | ||
2729 | /* Count the number of .file directives, so that .loc is up to date. */ | |
2730 | ||
2731 | static int num_source_filenames = 0; | |
2732 | ||
2733 | /* Name of the file containing the current function. */ | |
2734 | ||
2735 | static char *current_function_file = ""; | |
2736 | ||
2737 | /* Offsets to alpha virtual arg/local debugging pointers. */ | |
2738 | ||
2739 | long alpha_arg_offset; | |
2740 | long alpha_auto_offset; | |
2741 | \f | |
2742 | /* Emit a new filename to a stream. */ | |
2743 | ||
2744 | void | |
2745 | alpha_output_filename (stream, name) | |
2746 | FILE *stream; | |
2747 | char *name; | |
2748 | { | |
2749 | static int first_time = TRUE; | |
2750 | char ltext_label_name[100]; | |
2751 | ||
2752 | if (first_time) | |
2753 | { | |
2754 | first_time = FALSE; | |
2755 | ++num_source_filenames; | |
2756 | current_function_file = name; | |
2757 | fprintf (stream, "\t.file\t%d ", num_source_filenames); | |
2758 | output_quoted_string (stream, name); | |
2759 | fprintf (stream, "\n"); | |
2760 | if (!TARGET_GAS && write_symbols == DBX_DEBUG) | |
2761 | fprintf (stream, "\t#@stabs\n"); | |
2762 | } | |
2763 | ||
6af601b3 | 2764 | else if (write_symbols == DBX_DEBUG) |
48f6bfac RK |
2765 | { |
2766 | ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0); | |
2767 | fprintf (stream, "%s ", ASM_STABS_OP); | |
2768 | output_quoted_string (stream, name); | |
2769 | fprintf (stream, ",%d,0,0,%s\n", N_SOL, <ext_label_name[1]); | |
2770 | } | |
2771 | ||
2772 | else if (name != current_function_file | |
2773 | && strcmp (name, current_function_file) != 0) | |
2774 | { | |
2775 | if (inside_function && ! TARGET_GAS) | |
2776 | fprintf (stream, "\t#.file\t%d ", num_source_filenames); | |
2777 | else | |
2778 | { | |
2779 | ++num_source_filenames; | |
2780 | current_function_file = name; | |
2781 | fprintf (stream, "\t.file\t%d ", num_source_filenames); | |
2782 | } | |
2783 | ||
2784 | output_quoted_string (stream, name); | |
2785 | fprintf (stream, "\n"); | |
2786 | } | |
2787 | } | |
2788 | \f | |
2789 | /* Emit a linenumber to a stream. */ | |
2790 | ||
2791 | void | |
2792 | alpha_output_lineno (stream, line) | |
2793 | FILE *stream; | |
2794 | int line; | |
2795 | { | |
6af601b3 | 2796 | if (write_symbols == DBX_DEBUG) |
48f6bfac RK |
2797 | { |
2798 | /* mips-tfile doesn't understand .stabd directives. */ | |
2799 | ++sym_lineno; | |
2800 | fprintf (stream, "$LM%d:\n\t%s %d,0,%d,$LM%d\n", | |
2801 | sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno); | |
2802 | } | |
2803 | else | |
40828e35 | 2804 | fprintf (stream, "\n\t.loc\t%d %d\n", num_source_filenames, line); |
48f6bfac | 2805 | } |
6245e3df RK |
2806 | \f |
2807 | /* Structure to show the current status of registers and memory. */ | |
2808 | ||
2809 | struct shadow_summary | |
2810 | { | |
2811 | struct { | |
2ea844d3 RH |
2812 | unsigned long i : 31; /* Mask of int regs */ |
2813 | unsigned long fp : 31; /* Mask of fp regs */ | |
6245e3df RK |
2814 | unsigned long mem : 1; /* mem == imem | fpmem */ |
2815 | } used, defd; | |
2816 | }; | |
2817 | ||
2818 | /* Summary the effects of expression X on the machine. Update SUM, a pointer | |
2819 | to the summary structure. SET is nonzero if the insn is setting the | |
2820 | object, otherwise zero. */ | |
2821 | ||
2822 | static void | |
2823 | summarize_insn (x, sum, set) | |
2824 | rtx x; | |
2825 | struct shadow_summary *sum; | |
2826 | int set; | |
2827 | { | |
2828 | char *format_ptr; | |
2829 | int i, j; | |
2830 | ||
2831 | if (x == 0) | |
2832 | return; | |
2833 | ||
2834 | switch (GET_CODE (x)) | |
2835 | { | |
2836 | /* ??? Note that this case would be incorrect if the Alpha had a | |
2837 | ZERO_EXTRACT in SET_DEST. */ | |
2838 | case SET: | |
2839 | summarize_insn (SET_SRC (x), sum, 0); | |
2840 | summarize_insn (SET_DEST (x), sum, 1); | |
2841 | break; | |
2842 | ||
2843 | case CLOBBER: | |
2844 | summarize_insn (XEXP (x, 0), sum, 1); | |
2845 | break; | |
2846 | ||
2847 | case USE: | |
2848 | summarize_insn (XEXP (x, 0), sum, 0); | |
2849 | break; | |
2850 | ||
2851 | case PARALLEL: | |
8fed04e5 | 2852 | for (i = XVECLEN (x, 0) - 1; i >= 0; i--) |
6245e3df RK |
2853 | summarize_insn (XVECEXP (x, 0, i), sum, 0); |
2854 | break; | |
2855 | ||
2856 | case REG: | |
2857 | { | |
2858 | int regno = REGNO (x); | |
2859 | unsigned long mask = 1UL << (regno % 32); | |
2860 | ||
2861 | if (regno == 31 || regno == 63) | |
2862 | break; | |
2863 | ||
2864 | if (set) | |
2865 | { | |
2866 | if (regno < 32) | |
2867 | sum->defd.i |= mask; | |
2868 | else | |
2869 | sum->defd.fp |= mask; | |
2870 | } | |
2871 | else | |
2872 | { | |
2873 | if (regno < 32) | |
2874 | sum->used.i |= mask; | |
2875 | else | |
2876 | sum->used.fp |= mask; | |
2877 | } | |
2878 | } | |
2879 | break; | |
2880 | ||
2881 | case MEM: | |
2882 | if (set) | |
2883 | sum->defd.mem = 1; | |
2884 | else | |
2885 | sum->used.mem = 1; | |
2886 | ||
2887 | /* Find the regs used in memory address computation: */ | |
2888 | summarize_insn (XEXP (x, 0), sum, 0); | |
2889 | break; | |
2890 | ||
8ba46994 | 2891 | case SUBREG: |
66d91cb9 | 2892 | summarize_insn (SUBREG_REG (x), sum, set); |
8ba46994 RK |
2893 | break; |
2894 | ||
2895 | case CONST_INT: case CONST_DOUBLE: | |
2896 | case SYMBOL_REF: case LABEL_REF: case CONST: | |
2897 | break; | |
2898 | ||
6245e3df RK |
2899 | /* Handle common unary and binary ops for efficiency. */ |
2900 | case COMPARE: case PLUS: case MINUS: case MULT: case DIV: | |
2901 | case MOD: case UDIV: case UMOD: case AND: case IOR: | |
2902 | case XOR: case ASHIFT: case ROTATE: case ASHIFTRT: case LSHIFTRT: | |
2903 | case ROTATERT: case SMIN: case SMAX: case UMIN: case UMAX: | |
2904 | case NE: case EQ: case GE: case GT: case LE: | |
2905 | case LT: case GEU: case GTU: case LEU: case LTU: | |
2906 | summarize_insn (XEXP (x, 0), sum, 0); | |
2907 | summarize_insn (XEXP (x, 1), sum, 0); | |
2908 | break; | |
2909 | ||
2910 | case NEG: case NOT: case SIGN_EXTEND: case ZERO_EXTEND: | |
2911 | case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: case FLOAT: | |
2912 | case FIX: case UNSIGNED_FLOAT: case UNSIGNED_FIX: case ABS: | |
2913 | case SQRT: case FFS: | |
2914 | summarize_insn (XEXP (x, 0), sum, 0); | |
2915 | break; | |
2916 | ||
2917 | default: | |
2918 | format_ptr = GET_RTX_FORMAT (GET_CODE (x)); | |
8fed04e5 | 2919 | for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) |
bed95fa1 | 2920 | switch (format_ptr[i]) |
6245e3df RK |
2921 | { |
2922 | case 'e': | |
2923 | summarize_insn (XEXP (x, i), sum, 0); | |
2924 | break; | |
2925 | ||
2926 | case 'E': | |
8fed04e5 | 2927 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) |
6245e3df RK |
2928 | summarize_insn (XVECEXP (x, i, j), sum, 0); |
2929 | break; | |
2930 | ||
2931 | default: | |
2932 | abort (); | |
2933 | } | |
2934 | } | |
2935 | } | |
6245e3df | 2936 | |
2ea844d3 RH |
2937 | /* Ensure a sufficient number of `trapb' insns are in the code when the user |
2938 | requests code with a trap precision of functions or instructions. | |
6245e3df RK |
2939 | |
2940 | In naive mode, when the user requests a trap-precision of "instruction", a | |
2941 | trapb is needed after every instruction that may generate a trap (and after | |
2942 | jsr/bsr instructions, because called functions may import a trap from the | |
2943 | caller). This ensures that the code is resumption safe but it is also slow. | |
2944 | ||
2945 | When optimizations are turned on, we delay issuing a trapb as long as | |
2946 | possible. In this context, a trap shadow is the sequence of instructions | |
2947 | that starts with a (potentially) trap generating instruction and extends to | |
2948 | the next trapb or call_pal instruction (but GCC never generates call_pal by | |
2949 | itself). We can delay (and therefore sometimes omit) a trapb subject to the | |
2950 | following conditions: | |
2951 | ||
2952 | (a) On entry to the trap shadow, if any Alpha register or memory location | |
2953 | contains a value that is used as an operand value by some instruction in | |
2954 | the trap shadow (live on entry), then no instruction in the trap shadow | |
2955 | may modify the register or memory location. | |
2956 | ||
2957 | (b) Within the trap shadow, the computation of the base register for a | |
2958 | memory load or store instruction may not involve using the result | |
2959 | of an instruction that might generate an UNPREDICTABLE result. | |
2960 | ||
2961 | (c) Within the trap shadow, no register may be used more than once as a | |
2962 | destination register. (This is to make life easier for the trap-handler.) | |
2963 | ||
2ea844d3 | 2964 | (d) The trap shadow may not include any branch instructions. */ |
6245e3df | 2965 | |
2ea844d3 RH |
2966 | static void |
2967 | alpha_handle_trap_shadows (insns) | |
2968 | rtx insns; | |
6245e3df | 2969 | { |
2ea844d3 RH |
2970 | struct shadow_summary shadow; |
2971 | int trap_pending, exception_nesting; | |
2972 | rtx i; | |
6245e3df | 2973 | |
2ea844d3 RH |
2974 | if (alpha_tp == ALPHA_TP_PROG && !flag_exceptions) |
2975 | return; | |
6245e3df | 2976 | |
2ea844d3 RH |
2977 | trap_pending = 0; |
2978 | exception_nesting = 0; | |
2979 | shadow.used.i = 0; | |
2980 | shadow.used.fp = 0; | |
2981 | shadow.used.mem = 0; | |
2982 | shadow.defd = shadow.used; | |
2983 | ||
2984 | for (i = insns; i ; i = NEXT_INSN (i)) | |
2985 | { | |
2986 | if (GET_CODE (i) == NOTE) | |
2987 | { | |
2988 | switch (NOTE_LINE_NUMBER (i)) | |
2989 | { | |
2990 | case NOTE_INSN_EH_REGION_BEG: | |
2991 | exception_nesting++; | |
2992 | if (trap_pending) | |
2993 | goto close_shadow; | |
2994 | break; | |
2995 | ||
2996 | case NOTE_INSN_EH_REGION_END: | |
2997 | exception_nesting--; | |
2998 | if (trap_pending) | |
2999 | goto close_shadow; | |
3000 | break; | |
3001 | ||
3002 | case NOTE_INSN_EPILOGUE_BEG: | |
3003 | if (trap_pending && alpha_tp >= ALPHA_TP_FUNC) | |
3004 | goto close_shadow; | |
3005 | break; | |
3006 | } | |
3007 | } | |
3008 | else if (trap_pending) | |
3009 | { | |
3010 | if (alpha_tp == ALPHA_TP_FUNC) | |
3011 | { | |
3012 | if (GET_CODE (i) == JUMP_INSN | |
3013 | && GET_CODE (PATTERN (i)) == RETURN) | |
3014 | goto close_shadow; | |
3015 | } | |
3016 | else if (alpha_tp == ALPHA_TP_INSN) | |
3017 | { | |
3018 | if (optimize > 0) | |
3019 | { | |
3020 | struct shadow_summary sum; | |
3021 | ||
3022 | sum.used.i = 0; | |
3023 | sum.used.fp = 0; | |
3024 | sum.used.mem = 0; | |
3025 | sum.defd = shadow.used; | |
3026 | ||
3027 | switch (GET_CODE (i)) | |
3028 | { | |
3029 | case INSN: | |
3030 | /* Annoyingly, get_attr_trap will abort on USE. */ | |
3031 | if (GET_CODE (PATTERN (i)) == USE) | |
3032 | break; | |
3033 | ||
3034 | summarize_insn (PATTERN (i), &sum, 0); | |
3035 | ||
3036 | if ((sum.defd.i & shadow.defd.i) | |
3037 | || (sum.defd.fp & shadow.defd.fp)) | |
3038 | { | |
3039 | /* (c) would be violated */ | |
3040 | goto close_shadow; | |
3041 | } | |
3042 | ||
3043 | /* Combine shadow with summary of current insn: */ | |
3044 | shadow.used.i |= sum.used.i; | |
3045 | shadow.used.fp |= sum.used.fp; | |
3046 | shadow.used.mem |= sum.used.mem; | |
3047 | shadow.defd.i |= sum.defd.i; | |
3048 | shadow.defd.fp |= sum.defd.fp; | |
3049 | shadow.defd.mem |= sum.defd.mem; | |
3050 | ||
3051 | if ((sum.defd.i & shadow.used.i) | |
3052 | || (sum.defd.fp & shadow.used.fp) | |
3053 | || (sum.defd.mem & shadow.used.mem)) | |
3054 | { | |
3055 | /* (a) would be violated (also takes care of (b)) */ | |
3056 | if (get_attr_trap (i) == TRAP_YES | |
3057 | && ((sum.defd.i & sum.used.i) | |
3058 | || (sum.defd.fp & sum.used.fp))) | |
3059 | abort (); | |
3060 | ||
3061 | goto close_shadow; | |
3062 | } | |
3063 | break; | |
3064 | ||
3065 | case JUMP_INSN: | |
3066 | case CALL_INSN: | |
3067 | case CODE_LABEL: | |
3068 | goto close_shadow; | |
3069 | ||
3070 | default: | |
6245e3df | 3071 | abort (); |
2ea844d3 RH |
3072 | } |
3073 | } | |
3074 | else | |
3075 | { | |
3076 | close_shadow: | |
3077 | emit_insn_before (gen_trapb (), i); | |
3078 | trap_pending = 0; | |
3079 | shadow.used.i = 0; | |
3080 | shadow.used.fp = 0; | |
3081 | shadow.used.mem = 0; | |
3082 | shadow.defd = shadow.used; | |
3083 | } | |
3084 | } | |
3085 | } | |
6245e3df | 3086 | |
4f3f5e9f RH |
3087 | if ((exception_nesting > 0 || alpha_tp >= ALPHA_TP_FUNC) |
3088 | && GET_CODE (i) == INSN | |
3089 | && GET_CODE (PATTERN (i)) != USE | |
3090 | && GET_CODE (PATTERN (i)) != CLOBBER | |
3091 | && get_attr_trap (i) == TRAP_YES) | |
3092 | { | |
3093 | if (optimize && !trap_pending) | |
3094 | summarize_insn (PATTERN (i), &shadow, 0); | |
3095 | trap_pending = 1; | |
3096 | } | |
6245e3df RK |
3097 | } |
3098 | } | |
a874dd18 | 3099 | |
2ea844d3 RH |
3100 | /* Machine dependant reorg pass. */ |
3101 | ||
3102 | void | |
3103 | alpha_reorg (insns) | |
3104 | rtx insns; | |
3105 | { | |
3106 | alpha_handle_trap_shadows (insns); | |
3107 | } | |
3108 | ||
3109 | \f | |
a874dd18 RK |
3110 | /* Check a floating-point value for validity for a particular machine mode. */ |
3111 | ||
3112 | static char *float_strings[] = | |
3113 | { | |
39d78b32 | 3114 | /* These are for FLOAT_VAX. */ |
a874dd18 RK |
3115 | "1.70141173319264430e+38", /* 2^127 (2^24 - 1) / 2^24 */ |
3116 | "-1.70141173319264430e+38", | |
3117 | "2.93873587705571877e-39", /* 2^-128 */ | |
39d78b32 RK |
3118 | "-2.93873587705571877e-39", |
3119 | /* These are for the default broken IEEE mode, which traps | |
3120 | on infinity or denormal numbers. */ | |
3121 | "3.402823466385288598117e+38", /* 2^128 (1 - 2^-24) */ | |
3122 | "-3.402823466385288598117e+38", | |
3123 | "1.1754943508222875079687e-38", /* 2^-126 */ | |
3124 | "-1.1754943508222875079687e-38", | |
a874dd18 RK |
3125 | }; |
3126 | ||
39d78b32 | 3127 | static REAL_VALUE_TYPE float_values[8]; |
a874dd18 RK |
3128 | static int inited_float_values = 0; |
3129 | ||
3130 | int | |
3131 | check_float_value (mode, d, overflow) | |
3132 | enum machine_mode mode; | |
3133 | REAL_VALUE_TYPE *d; | |
3134 | int overflow; | |
3135 | { | |
3136 | ||
3137 | if (TARGET_IEEE || TARGET_IEEE_CONFORMANT || TARGET_IEEE_WITH_INEXACT) | |
3138 | return 0; | |
3139 | ||
3140 | if (inited_float_values == 0) | |
3141 | { | |
3142 | int i; | |
39d78b32 | 3143 | for (i = 0; i < 8; i++) |
a874dd18 RK |
3144 | float_values[i] = REAL_VALUE_ATOF (float_strings[i], DFmode); |
3145 | ||
3146 | inited_float_values = 1; | |
3147 | } | |
3148 | ||
3149 | if (mode == SFmode) | |
3150 | { | |
3151 | REAL_VALUE_TYPE r; | |
39d78b32 RK |
3152 | REAL_VALUE_TYPE *fvptr; |
3153 | ||
3154 | if (TARGET_FLOAT_VAX) | |
3155 | fvptr = &float_values[0]; | |
3156 | else | |
3157 | fvptr = &float_values[4]; | |
a874dd18 | 3158 | |
acbdd7dd | 3159 | bcopy ((char *) d, (char *) &r, sizeof (REAL_VALUE_TYPE)); |
39d78b32 | 3160 | if (REAL_VALUES_LESS (fvptr[0], r)) |
a874dd18 | 3161 | { |
39d78b32 | 3162 | bcopy ((char *) &fvptr[0], (char *) d, |
acbdd7dd | 3163 | sizeof (REAL_VALUE_TYPE)); |
a874dd18 RK |
3164 | return 1; |
3165 | } | |
39d78b32 | 3166 | else if (REAL_VALUES_LESS (r, fvptr[1])) |
a874dd18 | 3167 | { |
39d78b32 | 3168 | bcopy ((char *) &fvptr[1], (char *) d, |
acbdd7dd | 3169 | sizeof (REAL_VALUE_TYPE)); |
a874dd18 RK |
3170 | return 1; |
3171 | } | |
3172 | else if (REAL_VALUES_LESS (dconst0, r) | |
39d78b32 | 3173 | && REAL_VALUES_LESS (r, fvptr[2])) |
a874dd18 | 3174 | { |
acbdd7dd | 3175 | bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE)); |
a874dd18 RK |
3176 | return 1; |
3177 | } | |
3178 | else if (REAL_VALUES_LESS (r, dconst0) | |
39d78b32 | 3179 | && REAL_VALUES_LESS (fvptr[3], r)) |
a874dd18 | 3180 | { |
acbdd7dd | 3181 | bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE)); |
a874dd18 RK |
3182 | return 1; |
3183 | } | |
3184 | } | |
3185 | ||
3186 | return 0; | |
3187 | } | |
89cfc2c6 RK |
3188 | |
3189 | #if OPEN_VMS | |
3190 | ||
e9a25f70 | 3191 | /* Return the VMS argument type corresponding to MODE. */ |
89cfc2c6 | 3192 | |
e9a25f70 JL |
3193 | enum avms_arg_type |
3194 | alpha_arg_type (mode) | |
3195 | enum machine_mode mode; | |
3196 | { | |
3197 | switch (mode) | |
89cfc2c6 | 3198 | { |
e9a25f70 JL |
3199 | case SFmode: |
3200 | return TARGET_FLOAT_VAX ? FF : FS; | |
3201 | case DFmode: | |
3202 | return TARGET_FLOAT_VAX ? FD : FT; | |
3203 | default: | |
3204 | return I64; | |
89cfc2c6 | 3205 | } |
e9a25f70 | 3206 | } |
89cfc2c6 | 3207 | |
e9a25f70 JL |
3208 | /* Return an rtx for an integer representing the VMS Argument Information |
3209 | register value. */ | |
89cfc2c6 | 3210 | |
e9a25f70 JL |
3211 | struct rtx_def * |
3212 | alpha_arg_info_reg_val (cum) | |
3213 | CUMULATIVE_ARGS cum; | |
3214 | { | |
3215 | unsigned HOST_WIDE_INT regval = cum.num_args; | |
3216 | int i; | |
89cfc2c6 | 3217 | |
e9a25f70 JL |
3218 | for (i = 0; i < 6; i++) |
3219 | regval |= ((int) cum.atypes[i]) << (i * 3 + 8); | |
89cfc2c6 | 3220 | |
e9a25f70 JL |
3221 | return GEN_INT (regval); |
3222 | } | |
3223 | \f | |
89cfc2c6 RK |
3224 | /* Structure to collect function names for final output |
3225 | in link section. */ | |
3226 | ||
3227 | enum links_kind {KIND_UNUSED, KIND_LOCAL, KIND_EXTERN}; | |
3228 | ||
3229 | ||
3230 | struct alpha_links { | |
3231 | struct alpha_links *next; | |
3232 | char *name; | |
3233 | enum links_kind kind; | |
3234 | }; | |
3235 | ||
3236 | static struct alpha_links *alpha_links_base = 0; | |
3237 | ||
3238 | /* Make (or fake) .linkage entry for function call. | |
3239 | ||
3240 | IS_LOCAL is 0 if name is used in call, 1 if name is used in definition. */ | |
3241 | ||
3242 | void | |
3243 | alpha_need_linkage (name, is_local) | |
3244 | char *name; | |
3245 | int is_local; | |
3246 | { | |
3247 | rtx x; | |
3248 | struct alpha_links *lptr, *nptr; | |
3249 | ||
3250 | if (name[0] == '*') | |
3251 | name++; | |
3252 | ||
3253 | /* Is this name already defined ? */ | |
3254 | ||
3255 | for (lptr = alpha_links_base; lptr; lptr = lptr->next) | |
3256 | if (strcmp (lptr->name, name) == 0) | |
3257 | { | |
3258 | if (is_local) | |
3259 | { | |
9398dc27 | 3260 | /* Defined here but external assumed. */ |
89cfc2c6 RK |
3261 | if (lptr->kind == KIND_EXTERN) |
3262 | lptr->kind = KIND_LOCAL; | |
3263 | } | |
3264 | else | |
3265 | { | |
9398dc27 | 3266 | /* Used here but unused assumed. */ |
89cfc2c6 RK |
3267 | if (lptr->kind == KIND_UNUSED) |
3268 | lptr->kind = KIND_LOCAL; | |
3269 | } | |
3270 | return; | |
3271 | } | |
3272 | ||
3273 | nptr = (struct alpha_links *) xmalloc (sizeof (struct alpha_links)); | |
3274 | nptr->next = alpha_links_base; | |
3275 | nptr->name = xstrdup (name); | |
3276 | ||
3277 | /* Assume external if no definition. */ | |
3278 | nptr->kind = (is_local ? KIND_UNUSED : KIND_EXTERN); | |
3279 | ||
9398dc27 RK |
3280 | /* Ensure we have an IDENTIFIER so assemble_name can mark is used. */ |
3281 | get_identifier (name); | |
3282 | ||
89cfc2c6 RK |
3283 | alpha_links_base = nptr; |
3284 | ||
3285 | return; | |
3286 | } | |
3287 | ||
3288 | ||
3289 | void | |
3290 | alpha_write_linkage (stream) | |
3291 | FILE *stream; | |
3292 | { | |
3293 | struct alpha_links *lptr, *nptr; | |
3294 | ||
3295 | readonly_section (); | |
3296 | ||
3297 | fprintf (stream, "\t.align 3\n"); | |
3298 | ||
3299 | for (lptr = alpha_links_base; lptr; lptr = nptr) | |
3300 | { | |
3301 | nptr = lptr->next; | |
3302 | ||
3303 | if (lptr->kind == KIND_UNUSED | |
3304 | || ! TREE_SYMBOL_REFERENCED (get_identifier (lptr->name))) | |
3305 | continue; | |
3306 | ||
3307 | fprintf (stream, "%s..lk:\n", lptr->name); | |
3308 | if (lptr->kind == KIND_LOCAL) | |
3309 | { | |
3310 | /* Local and used, build linkage pair. */ | |
3311 | fprintf (stream, "\t.quad %s..en\n", lptr->name); | |
3312 | fprintf (stream, "\t.quad %s\n", lptr->name); | |
3313 | } | |
3314 | else | |
3315 | /* External and used, request linkage pair. */ | |
3316 | fprintf (stream, "\t.linkage %s\n", lptr->name); | |
3317 | } | |
3318 | } | |
3319 | ||
3320 | #else | |
3321 | ||
3322 | void | |
3323 | alpha_need_linkage (name, is_local) | |
3324 | char *name; | |
3325 | int is_local; | |
3326 | { | |
3327 | } | |
3328 | ||
3329 | #endif /* OPEN_VMS */ | |
3330 |