]>
Commit | Line | Data |
---|---|---|
bf2a98b3 | 1 | /* Subroutines used for code generation on the DEC Alpha. |
6d2bbb9f | 2 | Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
934f2848 | 3 | 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. |
0e0a0e7a | 4 | Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) |
bf2a98b3 | 5 | |
187b36cf | 6 | This file is part of GCC. |
bf2a98b3 | 7 | |
187b36cf | 8 | GCC is free software; you can redistribute it and/or modify |
bf2a98b3 | 9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; either version 2, or (at your option) | |
11 | any later version. | |
12 | ||
187b36cf | 13 | GCC is distributed in the hope that it will be useful, |
bf2a98b3 | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
187b36cf | 19 | along with GCC; see the file COPYING. If not, write to |
77b72456 | 20 | the Free Software Foundation, 59 Temple Place - Suite 330, |
21 | Boston, MA 02111-1307, USA. */ | |
bf2a98b3 | 22 | |
23 | ||
bf2a98b3 | 24 | #include "config.h" |
769ea120 | 25 | #include "system.h" |
805e22b2 | 26 | #include "coretypes.h" |
27 | #include "tm.h" | |
bf2a98b3 | 28 | #include "rtl.h" |
d8fc4d0b | 29 | #include "tree.h" |
bf2a98b3 | 30 | #include "regs.h" |
31 | #include "hard-reg-set.h" | |
32 | #include "real.h" | |
33 | #include "insn-config.h" | |
34 | #include "conditions.h" | |
bf2a98b3 | 35 | #include "output.h" |
36 | #include "insn-attr.h" | |
37 | #include "flags.h" | |
38 | #include "recog.h" | |
bf2a98b3 | 39 | #include "expr.h" |
d8fc4d0b | 40 | #include "optabs.h" |
41 | #include "reload.h" | |
bf2a98b3 | 42 | #include "obstack.h" |
0c0464e6 | 43 | #include "except.h" |
44 | #include "function.h" | |
769ea120 | 45 | #include "toplev.h" |
11016d99 | 46 | #include "ggc.h" |
0f37b7a2 | 47 | #include "integrate.h" |
0d50f0b7 | 48 | #include "tm_p.h" |
a767736d | 49 | #include "target.h" |
50 | #include "target-def.h" | |
961d6ddd | 51 | #include "debug.h" |
a1f71e15 | 52 | #include "langhooks.h" |
573aba85 | 53 | #include <splay-tree.h> |
356907d3 | 54 | #include "cfglayout.h" |
de8f9b94 | 55 | #include "tree-gimple.h" |
0c0464e6 | 56 | |
65abff06 | 57 | /* Specify which cpu to schedule for. */ |
0c0464e6 | 58 | |
f141a8b4 | 59 | enum processor_type alpha_cpu; |
ace75b22 | 60 | static const char * const alpha_cpu_name[] = |
07c1a295 | 61 | { |
62 | "ev4", "ev5", "ev6" | |
63 | }; | |
0c5845b3 | 64 | |
c4622276 | 65 | /* Specify how accurate floating-point traps need to be. */ |
66 | ||
67 | enum alpha_trap_precision alpha_tp; | |
68 | ||
69 | /* Specify the floating-point rounding mode. */ | |
70 | ||
71 | enum alpha_fp_rounding_mode alpha_fprm; | |
72 | ||
73 | /* Specify which things cause traps. */ | |
74 | ||
75 | enum alpha_fp_trap_mode alpha_fptm; | |
76 | ||
5f7b9df8 | 77 | /* Specify bit size of immediate TLS offsets. */ |
78 | ||
79 | int alpha_tls_size = 32; | |
80 | ||
c4622276 | 81 | /* Strings decoded into the above options. */ |
0c0464e6 | 82 | |
ace75b22 | 83 | const char *alpha_cpu_string; /* -mcpu= */ |
27de1488 | 84 | const char *alpha_tune_string; /* -mtune= */ |
ace75b22 | 85 | const char *alpha_tp_string; /* -mtrap-precision=[p|s|i] */ |
86 | const char *alpha_fprm_string; /* -mfp-rounding-mode=[n|m|c|d] */ | |
87 | const char *alpha_fptm_string; /* -mfp-trap-mode=[n|u|su|sui] */ | |
88 | const char *alpha_mlat_string; /* -mmemory-latency= */ | |
5f7b9df8 | 89 | const char *alpha_tls_size_string; /* -mtls-size=[16|32|64] */ |
c4622276 | 90 | |
bf2a98b3 | 91 | /* Save information from a "cmpxx" operation until the branch or scc is |
92 | emitted. */ | |
93 | ||
b18b881f | 94 | struct alpha_compare alpha_compare; |
bf2a98b3 | 95 | |
e3e08e7f | 96 | /* Nonzero if inside of a function, because the Alpha asm can't |
449b7f2d | 97 | handle .files inside of functions. */ |
98 | ||
99 | static int inside_function = FALSE; | |
100 | ||
07c1a295 | 101 | /* The number of cycles of latency we should assume on memory reads. */ |
102 | ||
103 | int alpha_memory_latency = 3; | |
104 | ||
b9a5aa8e | 105 | /* Whether the function needs the GP. */ |
106 | ||
107 | static int alpha_function_needs_gp; | |
108 | ||
849674a3 | 109 | /* The alias set for prologue/epilogue register save/restore. */ |
110 | ||
9de382d9 | 111 | static GTY(()) int alpha_sr_alias_set; |
849674a3 | 112 | |
a314eb5e | 113 | /* The assembler name of the current function. */ |
114 | ||
115 | static const char *alpha_fnname; | |
116 | ||
1f0ce6a6 | 117 | /* The next explicit relocation sequence number. */ |
9de382d9 | 118 | extern GTY(()) int alpha_next_sequence_number; |
1f0ce6a6 | 119 | int alpha_next_sequence_number = 1; |
120 | ||
121 | /* The literal and gpdisp sequence numbers for this insn, as printed | |
122 | by %# and %* respectively. */ | |
9de382d9 | 123 | extern GTY(()) int alpha_this_literal_sequence_number; |
124 | extern GTY(()) int alpha_this_gpdisp_sequence_number; | |
1f0ce6a6 | 125 | int alpha_this_literal_sequence_number; |
126 | int alpha_this_gpdisp_sequence_number; | |
127 | ||
fab7adbf | 128 | /* Costs of various operations on the different architectures. */ |
129 | ||
130 | struct alpha_rtx_cost_data | |
131 | { | |
132 | unsigned char fp_add; | |
133 | unsigned char fp_mult; | |
134 | unsigned char fp_div_sf; | |
135 | unsigned char fp_div_df; | |
136 | unsigned char int_mult_si; | |
137 | unsigned char int_mult_di; | |
138 | unsigned char int_shift; | |
139 | unsigned char int_cmov; | |
d7cf2331 | 140 | unsigned short int_div; |
fab7adbf | 141 | }; |
142 | ||
143 | static struct alpha_rtx_cost_data const alpha_rtx_cost_data[PROCESSOR_MAX] = | |
144 | { | |
145 | { /* EV4 */ | |
146 | COSTS_N_INSNS (6), /* fp_add */ | |
147 | COSTS_N_INSNS (6), /* fp_mult */ | |
148 | COSTS_N_INSNS (34), /* fp_div_sf */ | |
149 | COSTS_N_INSNS (63), /* fp_div_df */ | |
150 | COSTS_N_INSNS (23), /* int_mult_si */ | |
151 | COSTS_N_INSNS (23), /* int_mult_di */ | |
152 | COSTS_N_INSNS (2), /* int_shift */ | |
153 | COSTS_N_INSNS (2), /* int_cmov */ | |
d7cf2331 | 154 | COSTS_N_INSNS (70), /* int_div */ |
fab7adbf | 155 | }, |
156 | { /* EV5 */ | |
157 | COSTS_N_INSNS (4), /* fp_add */ | |
158 | COSTS_N_INSNS (4), /* fp_mult */ | |
159 | COSTS_N_INSNS (15), /* fp_div_sf */ | |
160 | COSTS_N_INSNS (22), /* fp_div_df */ | |
161 | COSTS_N_INSNS (8), /* int_mult_si */ | |
162 | COSTS_N_INSNS (12), /* int_mult_di */ | |
163 | COSTS_N_INSNS (1) + 1, /* int_shift */ | |
164 | COSTS_N_INSNS (1), /* int_cmov */ | |
d7cf2331 | 165 | COSTS_N_INSNS (45), /* int_div */ |
fab7adbf | 166 | }, |
167 | { /* EV6 */ | |
168 | COSTS_N_INSNS (4), /* fp_add */ | |
169 | COSTS_N_INSNS (4), /* fp_mult */ | |
170 | COSTS_N_INSNS (12), /* fp_div_sf */ | |
171 | COSTS_N_INSNS (15), /* fp_div_df */ | |
172 | COSTS_N_INSNS (7), /* int_mult_si */ | |
173 | COSTS_N_INSNS (7), /* int_mult_di */ | |
174 | COSTS_N_INSNS (1), /* int_shift */ | |
175 | COSTS_N_INSNS (2), /* int_cmov */ | |
d7cf2331 | 176 | COSTS_N_INSNS (25), /* int_div */ |
fab7adbf | 177 | }, |
178 | }; | |
179 | ||
d7cf2331 | 180 | /* Similar but tuned for code size instead of execution latency. The |
181 | extra +N is fractional cost tuning based on latency. It's used to | |
182 | encourage use of cheaper insns like shift, but only if there's just | |
183 | one of them. */ | |
184 | ||
185 | static struct alpha_rtx_cost_data const alpha_rtx_cost_size = | |
186 | { | |
187 | COSTS_N_INSNS (1), /* fp_add */ | |
188 | COSTS_N_INSNS (1), /* fp_mult */ | |
189 | COSTS_N_INSNS (1), /* fp_div_sf */ | |
190 | COSTS_N_INSNS (1) + 1, /* fp_div_df */ | |
191 | COSTS_N_INSNS (1) + 1, /* int_mult_si */ | |
192 | COSTS_N_INSNS (1) + 2, /* int_mult_di */ | |
193 | COSTS_N_INSNS (1), /* int_shift */ | |
194 | COSTS_N_INSNS (1), /* int_cmov */ | |
195 | COSTS_N_INSNS (6), /* int_div */ | |
196 | }; | |
197 | ||
0dbd1c74 | 198 | /* Get the number of args of a function in one of two ways. */ |
9caef960 | 199 | #if TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK |
0dbd1c74 | 200 | #define NUM_ARGS current_function_args_info.num_args |
201 | #else | |
202 | #define NUM_ARGS current_function_args_info | |
203 | #endif | |
d2832bd8 | 204 | |
d2832bd8 | 205 | #define REG_PV 27 |
206 | #define REG_RA 26 | |
f2cc13dc | 207 | |
92643d95 | 208 | /* Declarations of static functions. */ |
209 | static struct machine_function *alpha_init_machine_status (void); | |
210 | static rtx alpha_emit_xfloating_compare (enum rtx_code, rtx, rtx); | |
805e22b2 | 211 | |
92643d95 | 212 | #if TARGET_ABI_OPEN_VMS |
213 | static void alpha_write_linkage (FILE *, const char *, tree); | |
6988553d | 214 | #endif |
215 | ||
92643d95 | 216 | static void unicosmk_output_deferred_case_vectors (FILE *); |
217 | static void unicosmk_gen_dsib (unsigned long *); | |
218 | static void unicosmk_output_ssib (FILE *, const char *); | |
219 | static int unicosmk_need_dex (rtx); | |
a767736d | 220 | \f |
65abff06 | 221 | /* Parse target option strings. */ |
c4622276 | 222 | |
223 | void | |
92643d95 | 224 | override_options (void) |
c4622276 | 225 | { |
27de1488 | 226 | int i; |
e99c3a1d | 227 | static const struct cpu_table { |
228 | const char *const name; | |
229 | const enum processor_type processor; | |
230 | const int flags; | |
27de1488 | 231 | } cpu_table[] = { |
232 | #define EV5_MASK (MASK_CPU_EV5) | |
233 | #define EV6_MASK (MASK_CPU_EV6|MASK_BWX|MASK_MAX|MASK_FIX) | |
234 | { "ev4", PROCESSOR_EV4, 0 }, | |
235 | { "ev45", PROCESSOR_EV4, 0 }, | |
236 | { "21064", PROCESSOR_EV4, 0 }, | |
237 | { "ev5", PROCESSOR_EV5, EV5_MASK }, | |
238 | { "21164", PROCESSOR_EV5, EV5_MASK }, | |
239 | { "ev56", PROCESSOR_EV5, EV5_MASK|MASK_BWX }, | |
240 | { "21164a", PROCESSOR_EV5, EV5_MASK|MASK_BWX }, | |
241 | { "pca56", PROCESSOR_EV5, EV5_MASK|MASK_BWX|MASK_MAX }, | |
242 | { "21164PC",PROCESSOR_EV5, EV5_MASK|MASK_BWX|MASK_MAX }, | |
243 | { "21164pc",PROCESSOR_EV5, EV5_MASK|MASK_BWX|MASK_MAX }, | |
244 | { "ev6", PROCESSOR_EV6, EV6_MASK }, | |
245 | { "21264", PROCESSOR_EV6, EV6_MASK }, | |
246 | { "ev67", PROCESSOR_EV6, EV6_MASK|MASK_CIX }, | |
247 | { "21264a", PROCESSOR_EV6, EV6_MASK|MASK_CIX }, | |
248 | { 0, 0, 0 } | |
249 | }; | |
250 | ||
9caef960 | 251 | /* Unicos/Mk doesn't have shared libraries. */ |
252 | if (TARGET_ABI_UNICOSMK && flag_pic) | |
253 | { | |
254 | warning ("-f%s ignored for Unicos/Mk (not supported)", | |
255 | (flag_pic > 1) ? "PIC" : "pic"); | |
256 | flag_pic = 0; | |
257 | } | |
258 | ||
8d232dc7 | 259 | /* On Unicos/Mk, the native compiler consistently generates /d suffices for |
9caef960 | 260 | floating-point instructions. Make that the default for this target. */ |
261 | if (TARGET_ABI_UNICOSMK) | |
262 | alpha_fprm = ALPHA_FPRM_DYN; | |
263 | else | |
264 | alpha_fprm = ALPHA_FPRM_NORM; | |
265 | ||
c4622276 | 266 | alpha_tp = ALPHA_TP_PROG; |
c4622276 | 267 | alpha_fptm = ALPHA_FPTM_N; |
268 | ||
9caef960 | 269 | /* We cannot use su and sui qualifiers for conversion instructions on |
270 | Unicos/Mk. I'm not sure if this is due to assembler or hardware | |
271 | limitations. Right now, we issue a warning if -mieee is specified | |
272 | and then ignore it; eventually, we should either get it right or | |
273 | disable the option altogether. */ | |
274 | ||
c4622276 | 275 | if (TARGET_IEEE) |
276 | { | |
9caef960 | 277 | if (TARGET_ABI_UNICOSMK) |
278 | warning ("-mieee not supported on Unicos/Mk"); | |
279 | else | |
280 | { | |
281 | alpha_tp = ALPHA_TP_INSN; | |
282 | alpha_fptm = ALPHA_FPTM_SU; | |
283 | } | |
c4622276 | 284 | } |
285 | ||
286 | if (TARGET_IEEE_WITH_INEXACT) | |
287 | { | |
9caef960 | 288 | if (TARGET_ABI_UNICOSMK) |
289 | warning ("-mieee-with-inexact not supported on Unicos/Mk"); | |
290 | else | |
291 | { | |
292 | alpha_tp = ALPHA_TP_INSN; | |
293 | alpha_fptm = ALPHA_FPTM_SUI; | |
294 | } | |
c4622276 | 295 | } |
296 | ||
297 | if (alpha_tp_string) | |
264f7d8c | 298 | { |
299 | if (! strcmp (alpha_tp_string, "p")) | |
c4622276 | 300 | alpha_tp = ALPHA_TP_PROG; |
264f7d8c | 301 | else if (! strcmp (alpha_tp_string, "f")) |
c4622276 | 302 | alpha_tp = ALPHA_TP_FUNC; |
264f7d8c | 303 | else if (! strcmp (alpha_tp_string, "i")) |
c4622276 | 304 | alpha_tp = ALPHA_TP_INSN; |
264f7d8c | 305 | else |
306 | error ("bad value `%s' for -mtrap-precision switch", alpha_tp_string); | |
307 | } | |
c4622276 | 308 | |
309 | if (alpha_fprm_string) | |
264f7d8c | 310 | { |
311 | if (! strcmp (alpha_fprm_string, "n")) | |
c4622276 | 312 | alpha_fprm = ALPHA_FPRM_NORM; |
264f7d8c | 313 | else if (! strcmp (alpha_fprm_string, "m")) |
c4622276 | 314 | alpha_fprm = ALPHA_FPRM_MINF; |
264f7d8c | 315 | else if (! strcmp (alpha_fprm_string, "c")) |
c4622276 | 316 | alpha_fprm = ALPHA_FPRM_CHOP; |
264f7d8c | 317 | else if (! strcmp (alpha_fprm_string,"d")) |
c4622276 | 318 | alpha_fprm = ALPHA_FPRM_DYN; |
264f7d8c | 319 | else |
320 | error ("bad value `%s' for -mfp-rounding-mode switch", | |
c4622276 | 321 | alpha_fprm_string); |
264f7d8c | 322 | } |
c4622276 | 323 | |
324 | if (alpha_fptm_string) | |
264f7d8c | 325 | { |
326 | if (strcmp (alpha_fptm_string, "n") == 0) | |
327 | alpha_fptm = ALPHA_FPTM_N; | |
328 | else if (strcmp (alpha_fptm_string, "u") == 0) | |
329 | alpha_fptm = ALPHA_FPTM_U; | |
330 | else if (strcmp (alpha_fptm_string, "su") == 0) | |
331 | alpha_fptm = ALPHA_FPTM_SU; | |
332 | else if (strcmp (alpha_fptm_string, "sui") == 0) | |
333 | alpha_fptm = ALPHA_FPTM_SUI; | |
334 | else | |
335 | error ("bad value `%s' for -mfp-trap-mode switch", alpha_fptm_string); | |
336 | } | |
c4622276 | 337 | |
5f7b9df8 | 338 | if (alpha_tls_size_string) |
339 | { | |
340 | if (strcmp (alpha_tls_size_string, "16") == 0) | |
341 | alpha_tls_size = 16; | |
342 | else if (strcmp (alpha_tls_size_string, "32") == 0) | |
343 | alpha_tls_size = 32; | |
344 | else if (strcmp (alpha_tls_size_string, "64") == 0) | |
345 | alpha_tls_size = 64; | |
346 | else | |
347 | error ("bad value `%s' for -mtls-size switch", alpha_tls_size_string); | |
348 | } | |
349 | ||
cbd8ec27 | 350 | alpha_cpu |
351 | = TARGET_CPU_DEFAULT & MASK_CPU_EV6 ? PROCESSOR_EV6 | |
352 | : (TARGET_CPU_DEFAULT & MASK_CPU_EV5 ? PROCESSOR_EV5 : PROCESSOR_EV4); | |
353 | ||
354 | if (alpha_cpu_string) | |
355 | { | |
27de1488 | 356 | for (i = 0; cpu_table [i].name; i++) |
357 | if (! strcmp (alpha_cpu_string, cpu_table [i].name)) | |
358 | { | |
359 | alpha_cpu = cpu_table [i].processor; | |
360 | target_flags &= ~ (MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX | |
361 | | MASK_CPU_EV5 | MASK_CPU_EV6); | |
362 | target_flags |= cpu_table [i].flags; | |
363 | break; | |
364 | } | |
365 | if (! cpu_table [i].name) | |
cbd8ec27 | 366 | error ("bad value `%s' for -mcpu switch", alpha_cpu_string); |
367 | } | |
368 | ||
27de1488 | 369 | if (alpha_tune_string) |
370 | { | |
371 | for (i = 0; cpu_table [i].name; i++) | |
372 | if (! strcmp (alpha_tune_string, cpu_table [i].name)) | |
373 | { | |
374 | alpha_cpu = cpu_table [i].processor; | |
375 | break; | |
376 | } | |
377 | if (! cpu_table [i].name) | |
378 | error ("bad value `%s' for -mcpu switch", alpha_tune_string); | |
379 | } | |
380 | ||
65abff06 | 381 | /* Do some sanity checks on the above options. */ |
c4622276 | 382 | |
9caef960 | 383 | if (TARGET_ABI_UNICOSMK && alpha_fptm != ALPHA_FPTM_N) |
384 | { | |
385 | warning ("trap mode not supported on Unicos/Mk"); | |
386 | alpha_fptm = ALPHA_FPTM_N; | |
387 | } | |
388 | ||
264f7d8c | 389 | if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI) |
27de1488 | 390 | && alpha_tp != ALPHA_TP_INSN && ! TARGET_CPU_EV6) |
c4622276 | 391 | { |
264f7d8c | 392 | warning ("fp software completion requires -mtrap-precision=i"); |
c4622276 | 393 | alpha_tp = ALPHA_TP_INSN; |
394 | } | |
8df4a58b | 395 | |
27de1488 | 396 | if (TARGET_CPU_EV6) |
bc16f0c1 | 397 | { |
398 | /* Except for EV6 pass 1 (not released), we always have precise | |
399 | arithmetic traps. Which means we can do software completion | |
400 | without minding trap shadows. */ | |
401 | alpha_tp = ALPHA_TP_PROG; | |
402 | } | |
403 | ||
8df4a58b | 404 | if (TARGET_FLOAT_VAX) |
405 | { | |
406 | if (alpha_fprm == ALPHA_FPRM_MINF || alpha_fprm == ALPHA_FPRM_DYN) | |
407 | { | |
408 | warning ("rounding mode not supported for VAX floats"); | |
409 | alpha_fprm = ALPHA_FPRM_NORM; | |
410 | } | |
411 | if (alpha_fptm == ALPHA_FPTM_SUI) | |
412 | { | |
413 | warning ("trap mode not supported for VAX floats"); | |
414 | alpha_fptm = ALPHA_FPTM_SU; | |
415 | } | |
ef76af46 | 416 | if (target_flags_explicit & MASK_LONG_DOUBLE_128) |
417 | warning ("128-bit long double not supported for VAX floats"); | |
418 | target_flags &= ~MASK_LONG_DOUBLE_128; | |
8df4a58b | 419 | } |
07c1a295 | 420 | |
421 | { | |
422 | char *end; | |
423 | int lat; | |
424 | ||
425 | if (!alpha_mlat_string) | |
426 | alpha_mlat_string = "L1"; | |
427 | ||
14184418 | 428 | if (ISDIGIT ((unsigned char)alpha_mlat_string[0]) |
07c1a295 | 429 | && (lat = strtol (alpha_mlat_string, &end, 10), *end == '\0')) |
430 | ; | |
431 | else if ((alpha_mlat_string[0] == 'L' || alpha_mlat_string[0] == 'l') | |
14184418 | 432 | && ISDIGIT ((unsigned char)alpha_mlat_string[1]) |
07c1a295 | 433 | && alpha_mlat_string[2] == '\0') |
434 | { | |
435 | static int const cache_latency[][4] = | |
436 | { | |
437 | { 3, 30, -1 }, /* ev4 -- Bcache is a guess */ | |
438 | { 2, 12, 38 }, /* ev5 -- Bcache from PC164 LMbench numbers */ | |
65abff06 | 439 | { 3, 12, 30 }, /* ev6 -- Bcache from DS20 LMbench. */ |
07c1a295 | 440 | }; |
441 | ||
442 | lat = alpha_mlat_string[1] - '0'; | |
88b64d67 | 443 | if (lat <= 0 || lat > 3 || cache_latency[alpha_cpu][lat-1] == -1) |
07c1a295 | 444 | { |
445 | warning ("L%d cache latency unknown for %s", | |
446 | lat, alpha_cpu_name[alpha_cpu]); | |
447 | lat = 3; | |
448 | } | |
449 | else | |
450 | lat = cache_latency[alpha_cpu][lat-1]; | |
451 | } | |
452 | else if (! strcmp (alpha_mlat_string, "main")) | |
453 | { | |
454 | /* Most current memories have about 370ns latency. This is | |
455 | a reasonable guess for a fast cpu. */ | |
456 | lat = 150; | |
457 | } | |
458 | else | |
459 | { | |
460 | warning ("bad value `%s' for -mmemory-latency", alpha_mlat_string); | |
461 | lat = 3; | |
462 | } | |
463 | ||
464 | alpha_memory_latency = lat; | |
465 | } | |
a9fa9190 | 466 | |
467 | /* Default the definition of "small data" to 8 bytes. */ | |
468 | if (!g_switch_set) | |
469 | g_switch_value = 8; | |
849674a3 | 470 | |
5dcb037d | 471 | /* Infer TARGET_SMALL_DATA from -fpic/-fPIC. */ |
472 | if (flag_pic == 1) | |
473 | target_flags |= MASK_SMALL_DATA; | |
474 | else if (flag_pic == 2) | |
475 | target_flags &= ~MASK_SMALL_DATA; | |
476 | ||
0ea5169b | 477 | /* Align labels and loops for optimal branching. */ |
478 | /* ??? Kludge these by not doing anything if we don't optimize and also if | |
65abff06 | 479 | we are writing ECOFF symbols to work around a bug in DEC's assembler. */ |
0ea5169b | 480 | if (optimize > 0 && write_symbols != SDB_DEBUG) |
481 | { | |
482 | if (align_loops <= 0) | |
483 | align_loops = 16; | |
484 | if (align_jumps <= 0) | |
485 | align_jumps = 16; | |
486 | } | |
487 | if (align_functions <= 0) | |
488 | align_functions = 16; | |
489 | ||
849674a3 | 490 | /* Acquire a unique set number for our register saves and restores. */ |
491 | alpha_sr_alias_set = new_alias_set (); | |
9caef960 | 492 | |
493 | /* Register variables and functions with the garbage collector. */ | |
494 | ||
9caef960 | 495 | /* Set up function hooks. */ |
496 | init_machine_status = alpha_init_machine_status; | |
1268285a | 497 | |
498 | /* Tell the compiler when we're using VAX floating point. */ | |
499 | if (TARGET_FLOAT_VAX) | |
500 | { | |
0021bea9 | 501 | REAL_MODE_FORMAT (SFmode) = &vax_f_format; |
502 | REAL_MODE_FORMAT (DFmode) = &vax_g_format; | |
503 | REAL_MODE_FORMAT (TFmode) = NULL; | |
1268285a | 504 | } |
c4622276 | 505 | } |
506 | \f | |
bf2a98b3 | 507 | /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */ |
508 | ||
509 | int | |
92643d95 | 510 | zap_mask (HOST_WIDE_INT value) |
bf2a98b3 | 511 | { |
512 | int i; | |
513 | ||
514 | for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; | |
515 | i++, value >>= 8) | |
516 | if ((value & 0xff) != 0 && (value & 0xff) != 0xff) | |
517 | return 0; | |
518 | ||
519 | return 1; | |
520 | } | |
521 | ||
522 | /* Returns 1 if OP is either the constant zero or a register. If a | |
523 | register, it must be in the proper mode unless MODE is VOIDmode. */ | |
524 | ||
525 | int | |
92643d95 | 526 | reg_or_0_operand (rtx op, enum machine_mode mode) |
bf2a98b3 | 527 | { |
5ce11454 | 528 | return op == CONST0_RTX (mode) || register_operand (op, mode); |
bf2a98b3 | 529 | } |
530 | ||
f203253e | 531 | /* Return 1 if OP is a constant in the range of 0-63 (for a shift) or |
532 | any register. */ | |
533 | ||
534 | int | |
92643d95 | 535 | reg_or_6bit_operand (rtx op, enum machine_mode mode) |
f203253e | 536 | { |
537 | return ((GET_CODE (op) == CONST_INT | |
538 | && (unsigned HOST_WIDE_INT) INTVAL (op) < 64) | |
539 | || register_operand (op, mode)); | |
540 | } | |
541 | ||
542 | ||
bf2a98b3 | 543 | /* Return 1 if OP is an 8-bit constant or any register. */ |
544 | ||
545 | int | |
92643d95 | 546 | reg_or_8bit_operand (rtx op, enum machine_mode mode) |
bf2a98b3 | 547 | { |
548 | return ((GET_CODE (op) == CONST_INT | |
549 | && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100) | |
550 | || register_operand (op, mode)); | |
551 | } | |
552 | ||
f2cc13dc | 553 | /* Return 1 if OP is a constant or any register. */ |
554 | ||
555 | int | |
92643d95 | 556 | reg_or_const_int_operand (rtx op, enum machine_mode mode) |
f2cc13dc | 557 | { |
558 | return GET_CODE (op) == CONST_INT || register_operand (op, mode); | |
559 | } | |
560 | ||
14a2e7f0 | 561 | /* Return 1 if OP is an 8-bit constant. */ |
562 | ||
563 | int | |
92643d95 | 564 | cint8_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
14a2e7f0 | 565 | { |
0e2eb331 | 566 | return ((GET_CODE (op) == CONST_INT |
a249931c | 567 | && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100)); |
14a2e7f0 | 568 | } |
569 | ||
bf2a98b3 | 570 | /* Return 1 if the operand is a valid second operand to an add insn. */ |
571 | ||
572 | int | |
92643d95 | 573 | add_operand (rtx op, enum machine_mode mode) |
bf2a98b3 | 574 | { |
575 | if (GET_CODE (op) == CONST_INT) | |
c7412efd | 576 | /* Constraints I, J, O and P are covered by K. */ |
f7865966 | 577 | return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K') |
c7412efd | 578 | || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L')); |
bf2a98b3 | 579 | |
580 | return register_operand (op, mode); | |
581 | } | |
582 | ||
583 | /* Return 1 if the operand is a valid second operand to a sign-extending | |
584 | add insn. */ | |
585 | ||
586 | int | |
92643d95 | 587 | sext_add_operand (rtx op, enum machine_mode mode) |
bf2a98b3 | 588 | { |
589 | if (GET_CODE (op) == CONST_INT) | |
c7412efd | 590 | return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'I') |
591 | || CONST_OK_FOR_LETTER_P (INTVAL (op), 'O')); | |
bf2a98b3 | 592 | |
7014838c | 593 | return reg_not_elim_operand (op, mode); |
bf2a98b3 | 594 | } |
595 | ||
596 | /* Return 1 if OP is the constant 4 or 8. */ | |
597 | ||
598 | int | |
92643d95 | 599 | const48_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
bf2a98b3 | 600 | { |
601 | return (GET_CODE (op) == CONST_INT | |
602 | && (INTVAL (op) == 4 || INTVAL (op) == 8)); | |
603 | } | |
604 | ||
605 | /* Return 1 if OP is a valid first operand to an AND insn. */ | |
606 | ||
607 | int | |
92643d95 | 608 | and_operand (rtx op, enum machine_mode mode) |
bf2a98b3 | 609 | { |
610 | if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode) | |
611 | return (zap_mask (CONST_DOUBLE_LOW (op)) | |
612 | && zap_mask (CONST_DOUBLE_HIGH (op))); | |
613 | ||
614 | if (GET_CODE (op) == CONST_INT) | |
615 | return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100 | |
616 | || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100 | |
617 | || zap_mask (INTVAL (op))); | |
618 | ||
619 | return register_operand (op, mode); | |
620 | } | |
621 | ||
7eb83e27 | 622 | /* Return 1 if OP is a valid first operand to an IOR or XOR insn. */ |
fb18a037 | 623 | |
624 | int | |
92643d95 | 625 | or_operand (rtx op, enum machine_mode mode) |
fb18a037 | 626 | { |
627 | if (GET_CODE (op) == CONST_INT) | |
628 | return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100 | |
629 | || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100); | |
630 | ||
631 | return register_operand (op, mode); | |
632 | } | |
633 | ||
bf2a98b3 | 634 | /* Return 1 if OP is a constant that is the width, in bits, of an integral |
635 | mode smaller than DImode. */ | |
636 | ||
637 | int | |
92643d95 | 638 | mode_width_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
bf2a98b3 | 639 | { |
640 | return (GET_CODE (op) == CONST_INT | |
34377880 | 641 | && (INTVAL (op) == 8 || INTVAL (op) == 16 |
642 | || INTVAL (op) == 32 || INTVAL (op) == 64)); | |
bf2a98b3 | 643 | } |
644 | ||
645 | /* Return 1 if OP is a constant that is the width of an integral machine mode | |
646 | smaller than an integer. */ | |
647 | ||
648 | int | |
92643d95 | 649 | mode_mask_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
bf2a98b3 | 650 | { |
ae4cd3a5 | 651 | if (GET_CODE (op) == CONST_INT) |
652 | { | |
653 | HOST_WIDE_INT value = INTVAL (op); | |
bf2a98b3 | 654 | |
ae4cd3a5 | 655 | if (value == 0xff) |
656 | return 1; | |
657 | if (value == 0xffff) | |
658 | return 1; | |
659 | if (value == 0xffffffff) | |
660 | return 1; | |
661 | if (value == -1) | |
662 | return 1; | |
663 | } | |
664 | else if (HOST_BITS_PER_WIDE_INT == 32 && GET_CODE (op) == CONST_DOUBLE) | |
665 | { | |
666 | if (CONST_DOUBLE_LOW (op) == 0xffffffff && CONST_DOUBLE_HIGH (op) == 0) | |
667 | return 1; | |
668 | } | |
669 | ||
670 | return 0; | |
bf2a98b3 | 671 | } |
672 | ||
673 | /* Return 1 if OP is a multiple of 8 less than 64. */ | |
674 | ||
675 | int | |
92643d95 | 676 | mul8_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
bf2a98b3 | 677 | { |
678 | return (GET_CODE (op) == CONST_INT | |
679 | && (unsigned HOST_WIDE_INT) INTVAL (op) < 64 | |
680 | && (INTVAL (op) & 7) == 0); | |
681 | } | |
682 | ||
5ce11454 | 683 | /* Return 1 if OP is the zero constant for MODE. */ |
bf2a98b3 | 684 | |
685 | int | |
92643d95 | 686 | const0_operand (rtx op, enum machine_mode mode) |
bf2a98b3 | 687 | { |
5ce11454 | 688 | return op == CONST0_RTX (mode); |
bf2a98b3 | 689 | } |
690 | ||
f62714a1 | 691 | /* Return 1 if OP is a hard floating-point register. */ |
692 | ||
693 | int | |
92643d95 | 694 | hard_fp_register_operand (rtx op, enum machine_mode mode) |
f62714a1 | 695 | { |
cf3c6764 | 696 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) |
697 | return 0; | |
698 | ||
699 | if (GET_CODE (op) == SUBREG) | |
700 | op = SUBREG_REG (op); | |
701 | return GET_CODE (op) == REG && REGNO_REG_CLASS (REGNO (op)) == FLOAT_REGS; | |
702 | } | |
703 | ||
704 | /* Return 1 if OP is a hard general register. */ | |
705 | ||
706 | int | |
92643d95 | 707 | hard_int_register_operand (rtx op, enum machine_mode mode) |
cf3c6764 | 708 | { |
709 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) | |
710 | return 0; | |
711 | ||
712 | if (GET_CODE (op) == SUBREG) | |
713 | op = SUBREG_REG (op); | |
714 | return GET_CODE (op) == REG && REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS; | |
f62714a1 | 715 | } |
716 | ||
bf2a98b3 | 717 | /* Return 1 if OP is a register or a constant integer. */ |
718 | ||
719 | ||
720 | int | |
92643d95 | 721 | reg_or_cint_operand (rtx op, enum machine_mode mode) |
bf2a98b3 | 722 | { |
0e2eb331 | 723 | return (GET_CODE (op) == CONST_INT |
0e2eb331 | 724 | || register_operand (op, mode)); |
bf2a98b3 | 725 | } |
726 | ||
8a5ff806 | 727 | /* Return 1 if OP is something that can be reloaded into a register; |
728 | if it is a MEM, it need not be valid. */ | |
729 | ||
730 | int | |
92643d95 | 731 | some_operand (rtx op, enum machine_mode mode) |
8a5ff806 | 732 | { |
733 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) | |
734 | return 0; | |
735 | ||
736 | switch (GET_CODE (op)) | |
737 | { | |
f2cc13dc | 738 | case REG: |
739 | case MEM: | |
740 | case CONST_INT: | |
741 | case CONST_DOUBLE: | |
742 | case CONST_VECTOR: | |
743 | case LABEL_REF: | |
744 | case SYMBOL_REF: | |
745 | case CONST: | |
746 | case HIGH: | |
8a5ff806 | 747 | return 1; |
748 | ||
749 | case SUBREG: | |
750 | return some_operand (SUBREG_REG (op), VOIDmode); | |
99c14947 | 751 | |
752 | default: | |
753 | break; | |
8a5ff806 | 754 | } |
755 | ||
756 | return 0; | |
757 | } | |
758 | ||
bb4e263c | 759 | /* Likewise, but don't accept constants. */ |
760 | ||
761 | int | |
92643d95 | 762 | some_ni_operand (rtx op, enum machine_mode mode) |
bb4e263c | 763 | { |
764 | if (GET_MODE (op) != mode && mode != VOIDmode) | |
765 | return 0; | |
766 | ||
767 | if (GET_CODE (op) == SUBREG) | |
768 | op = SUBREG_REG (op); | |
769 | ||
770 | return (GET_CODE (op) == REG || GET_CODE (op) == MEM); | |
771 | } | |
772 | ||
bf2a98b3 | 773 | /* Return 1 if OP is a valid operand for the source of a move insn. */ |
774 | ||
775 | int | |
92643d95 | 776 | input_operand (rtx op, enum machine_mode mode) |
bf2a98b3 | 777 | { |
778 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) | |
779 | return 0; | |
780 | ||
781 | if (GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE (op) != mode) | |
782 | return 0; | |
783 | ||
784 | switch (GET_CODE (op)) | |
785 | { | |
786 | case LABEL_REF: | |
787 | case SYMBOL_REF: | |
788 | case CONST: | |
8afb6db4 | 789 | if (TARGET_EXPLICIT_RELOCS) |
f5a60074 | 790 | { |
791 | /* We don't split symbolic operands into something unintelligable | |
792 | until after reload, but we do not wish non-small, non-global | |
793 | symbolic operands to be reconstructed from their high/lo_sum | |
794 | form. */ | |
795 | return (small_symbolic_operand (op, mode) | |
5f7b9df8 | 796 | || global_symbolic_operand (op, mode) |
797 | || gotdtp_symbolic_operand (op, mode) | |
798 | || gottp_symbolic_operand (op, mode)); | |
f5a60074 | 799 | } |
8afb6db4 | 800 | |
0e2eb331 | 801 | /* This handles both the Windows/NT and OSF cases. */ |
2fb6c134 | 802 | return mode == ptr_mode || mode == DImode; |
bf2a98b3 | 803 | |
f5a60074 | 804 | case HIGH: |
805 | return (TARGET_EXPLICIT_RELOCS | |
806 | && local_symbolic_operand (XEXP (op, 0), mode)); | |
807 | ||
bf2a98b3 | 808 | case REG: |
809 | return 1; | |
810 | ||
811 | case SUBREG: | |
812 | if (register_operand (op, mode)) | |
813 | return 1; | |
65abff06 | 814 | /* ... fall through ... */ |
bf2a98b3 | 815 | case MEM: |
0dbd1c74 | 816 | return ((TARGET_BWX || (mode != HImode && mode != QImode)) |
7b6bbf24 | 817 | && general_operand (op, mode)); |
bf2a98b3 | 818 | |
819 | case CONST_DOUBLE: | |
f2cc13dc | 820 | case CONST_VECTOR: |
821 | return op == CONST0_RTX (mode); | |
bf2a98b3 | 822 | |
823 | case CONST_INT: | |
824 | return mode == QImode || mode == HImode || add_operand (op, mode); | |
99c14947 | 825 | |
826 | default: | |
827 | break; | |
bf2a98b3 | 828 | } |
829 | ||
830 | return 0; | |
831 | } | |
832 | ||
16b3392b | 833 | /* Return 1 if OP is a SYMBOL_REF for a function known to be in this |
484edb77 | 834 | file, and in the same section as the current function. */ |
bf2a98b3 | 835 | |
836 | int | |
92643d95 | 837 | samegp_function_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
bf2a98b3 | 838 | { |
8dca7aa1 | 839 | if (GET_CODE (op) != SYMBOL_REF) |
fc932273 | 840 | return false; |
8dca7aa1 | 841 | |
484edb77 | 842 | /* Easy test for recursion. */ |
843 | if (op == XEXP (DECL_RTL (current_function_decl), 0)) | |
fc932273 | 844 | return true; |
845 | ||
846 | /* Functions that are not local can be overridden, and thus may | |
847 | not share the same gp. */ | |
848 | if (! SYMBOL_REF_LOCAL_P (op)) | |
849 | return false; | |
8dca7aa1 | 850 | |
fc932273 | 851 | /* If -msmall-data is in effect, assume that there is only one GP |
852 | for the module, and so any local symbol has this property. We | |
853 | need explicit relocations to be able to enforce this for symbols | |
854 | not defined in this unit of translation, however. */ | |
855 | if (TARGET_EXPLICIT_RELOCS && TARGET_SMALL_DATA) | |
856 | return true; | |
857 | ||
858 | /* Functions that are not external are defined in this UoT, | |
859 | and thus must share the same gp. */ | |
860 | return ! SYMBOL_REF_EXTERNAL_P (op); | |
8dca7aa1 | 861 | } |
862 | ||
863 | /* Return 1 if OP is a SYMBOL_REF for which we can make a call via bsr. */ | |
864 | ||
865 | int | |
92643d95 | 866 | direct_call_operand (rtx op, enum machine_mode mode) |
8dca7aa1 | 867 | { |
fc932273 | 868 | tree op_decl, cfun_sec, op_sec; |
09a1f342 | 869 | |
9bdcc1e5 | 870 | /* Must share the same GP. */ |
871 | if (!samegp_function_operand (op, mode)) | |
fc932273 | 872 | return false; |
8dca7aa1 | 873 | |
874 | /* If profiling is implemented via linker tricks, we can't jump | |
9bdcc1e5 | 875 | to the nogp alternate entry point. Note that current_function_profile |
876 | would not be correct, since that doesn't indicate if the target | |
877 | function uses profiling. */ | |
8dca7aa1 | 878 | /* ??? TARGET_PROFILING_NEEDS_GP isn't really the right test, |
879 | but is approximately correct for the OSF ABIs. Don't know | |
880 | what to do for VMS, NT, or UMK. */ | |
9bdcc1e5 | 881 | if (!TARGET_PROFILING_NEEDS_GP && profile_flag) |
fc932273 | 882 | return false; |
09a1f342 | 883 | |
fc932273 | 884 | /* Must be a function. In some cases folks create thunks in static |
885 | data structures and then make calls to them. If we allow the | |
886 | direct call, we'll get an error from the linker about !samegp reloc | |
887 | against a symbol without a .prologue directive. */ | |
888 | if (!SYMBOL_REF_FUNCTION_P (op)) | |
889 | return false; | |
890 | ||
9bdcc1e5 | 891 | /* Must be "near" so that the branch is assumed to reach. With |
fc932273 | 892 | -msmall-text, this is assumed true of all local symbols. Since |
893 | we've already checked samegp, locality is already assured. */ | |
9bdcc1e5 | 894 | if (TARGET_SMALL_TEXT) |
fc932273 | 895 | return true; |
896 | ||
897 | /* Otherwise, a decl is "near" if it is defined in the same section. */ | |
898 | if (flag_function_sections) | |
899 | return false; | |
9bdcc1e5 | 900 | |
fc932273 | 901 | op_decl = SYMBOL_REF_DECL (op); |
902 | if (DECL_ONE_ONLY (current_function_decl) | |
903 | || (op_decl && DECL_ONE_ONLY (op_decl))) | |
904 | return false; | |
905 | ||
906 | cfun_sec = DECL_SECTION_NAME (current_function_decl); | |
907 | op_sec = op_decl ? DECL_SECTION_NAME (op_decl) : NULL; | |
908 | return ((!cfun_sec && !op_sec) | |
909 | || (cfun_sec && op_sec | |
910 | && strcmp (TREE_STRING_POINTER (cfun_sec), | |
911 | TREE_STRING_POINTER (op_sec)) == 0)); | |
bf2a98b3 | 912 | } |
913 | ||
8afb6db4 | 914 | /* Return true if OP is a LABEL_REF, or SYMBOL_REF or CONST referencing |
487724a7 | 915 | a (non-tls) variable known to be defined in this file. */ |
8afb6db4 | 916 | |
1f0ce6a6 | 917 | int |
92643d95 | 918 | local_symbolic_operand (rtx op, enum machine_mode mode) |
1f0ce6a6 | 919 | { |
9caef960 | 920 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) |
921 | return 0; | |
922 | ||
1f0ce6a6 | 923 | if (GET_CODE (op) == LABEL_REF) |
924 | return 1; | |
925 | ||
926 | if (GET_CODE (op) == CONST | |
927 | && GET_CODE (XEXP (op, 0)) == PLUS | |
928 | && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) | |
929 | op = XEXP (XEXP (op, 0), 0); | |
930 | ||
931 | if (GET_CODE (op) != SYMBOL_REF) | |
932 | return 0; | |
933 | ||
09a1f342 | 934 | return SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op); |
1f0ce6a6 | 935 | } |
936 | ||
5dcb037d | 937 | /* Return true if OP is a SYMBOL_REF or CONST referencing a variable |
938 | known to be defined in this file in the small data area. */ | |
939 | ||
940 | int | |
92643d95 | 941 | small_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
5dcb037d | 942 | { |
5dcb037d | 943 | if (! TARGET_SMALL_DATA) |
944 | return 0; | |
945 | ||
8afb6db4 | 946 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) |
947 | return 0; | |
948 | ||
5dcb037d | 949 | if (GET_CODE (op) == CONST |
950 | && GET_CODE (XEXP (op, 0)) == PLUS | |
951 | && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) | |
952 | op = XEXP (XEXP (op, 0), 0); | |
953 | ||
954 | if (GET_CODE (op) != SYMBOL_REF) | |
955 | return 0; | |
956 | ||
09a1f342 | 957 | /* ??? There's no encode_section_info equivalent for the rtl |
958 | constant pool, so SYMBOL_FLAG_SMALL never gets set. */ | |
5dcb037d | 959 | if (CONSTANT_POOL_ADDRESS_P (op)) |
3be2f219 | 960 | return GET_MODE_SIZE (get_pool_mode (op)) <= g_switch_value; |
09a1f342 | 961 | |
962 | return (SYMBOL_REF_LOCAL_P (op) | |
963 | && SYMBOL_REF_SMALL_P (op) | |
964 | && SYMBOL_REF_TLS_MODEL (op) == 0); | |
5dcb037d | 965 | } |
966 | ||
8afb6db4 | 967 | /* Return true if OP is a SYMBOL_REF or CONST referencing a variable |
968 | not known (or known not) to be defined in this file. */ | |
969 | ||
970 | int | |
92643d95 | 971 | global_symbolic_operand (rtx op, enum machine_mode mode) |
8afb6db4 | 972 | { |
973 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) | |
974 | return 0; | |
975 | ||
976 | if (GET_CODE (op) == CONST | |
977 | && GET_CODE (XEXP (op, 0)) == PLUS | |
978 | && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) | |
979 | op = XEXP (XEXP (op, 0), 0); | |
980 | ||
981 | if (GET_CODE (op) != SYMBOL_REF) | |
982 | return 0; | |
983 | ||
09a1f342 | 984 | return !SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op); |
8afb6db4 | 985 | } |
986 | ||
4901f901 | 987 | /* Return 1 if OP is a valid operand for the MEM of a CALL insn. */ |
988 | ||
989 | int | |
92643d95 | 990 | call_operand (rtx op, enum machine_mode mode) |
4901f901 | 991 | { |
992 | if (mode != Pmode) | |
993 | return 0; | |
994 | ||
1467e953 | 995 | if (GET_CODE (op) == REG) |
996 | { | |
997 | if (TARGET_ABI_OSF) | |
9f0ce87d | 998 | { |
5910bb95 | 999 | /* Disallow virtual registers to cope with pathological test cases |
9f0ce87d | 1000 | such as compile/930117-1.c in which the virtual reg decomposes |
1001 | to the frame pointer. Which is a hard reg that is not $27. */ | |
1002 | return (REGNO (op) == 27 || REGNO (op) > LAST_VIRTUAL_REGISTER); | |
1003 | } | |
1467e953 | 1004 | else |
1005 | return 1; | |
1006 | } | |
8afb6db4 | 1007 | if (TARGET_ABI_UNICOSMK) |
1008 | return 0; | |
1009 | if (GET_CODE (op) == SYMBOL_REF) | |
1010 | return 1; | |
1467e953 | 1011 | |
1012 | return 0; | |
4901f901 | 1013 | } |
1014 | ||
9caef960 | 1015 | /* Returns 1 if OP is a symbolic operand, i.e. a symbol_ref or a label_ref, |
1016 | possibly with an offset. */ | |
1017 | ||
1018 | int | |
92643d95 | 1019 | symbolic_operand (rtx op, enum machine_mode mode) |
9caef960 | 1020 | { |
1021 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) | |
1022 | return 0; | |
1023 | if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) | |
1024 | return 1; | |
1025 | if (GET_CODE (op) == CONST | |
1026 | && GET_CODE (XEXP (op,0)) == PLUS | |
1027 | && GET_CODE (XEXP (XEXP (op,0), 0)) == SYMBOL_REF | |
1028 | && GET_CODE (XEXP (XEXP (op,0), 1)) == CONST_INT) | |
1029 | return 1; | |
1030 | return 0; | |
1031 | } | |
1032 | ||
5f7b9df8 | 1033 | /* Return true if OP is valid for a particular TLS relocation. */ |
1034 | ||
1035 | static int | |
92643d95 | 1036 | tls_symbolic_operand_1 (rtx op, enum machine_mode mode, int size, int unspec) |
5f7b9df8 | 1037 | { |
5f7b9df8 | 1038 | if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) |
1039 | return 0; | |
1040 | ||
1041 | if (GET_CODE (op) != CONST) | |
1042 | return 0; | |
1043 | op = XEXP (op, 0); | |
1044 | ||
1045 | if (GET_CODE (op) != UNSPEC || XINT (op, 1) != unspec) | |
1046 | return 0; | |
1047 | op = XVECEXP (op, 0, 0); | |
1048 | ||
1049 | if (GET_CODE (op) != SYMBOL_REF) | |
1050 | return 0; | |
5f7b9df8 | 1051 | |
09a1f342 | 1052 | if (SYMBOL_REF_LOCAL_P (op)) |
5f7b9df8 | 1053 | { |
09a1f342 | 1054 | if (alpha_tls_size > size) |
5f7b9df8 | 1055 | return 0; |
1056 | } | |
09a1f342 | 1057 | else |
5f7b9df8 | 1058 | { |
09a1f342 | 1059 | if (size != 64) |
5f7b9df8 | 1060 | return 0; |
1061 | } | |
5f7b9df8 | 1062 | |
09a1f342 | 1063 | switch (SYMBOL_REF_TLS_MODEL (op)) |
9bdcc1e5 | 1064 | { |
09a1f342 | 1065 | case TLS_MODEL_LOCAL_DYNAMIC: |
9bdcc1e5 | 1066 | return unspec == UNSPEC_DTPREL; |
09a1f342 | 1067 | case TLS_MODEL_INITIAL_EXEC: |
9bdcc1e5 | 1068 | return unspec == UNSPEC_TPREL && size == 64; |
09a1f342 | 1069 | case TLS_MODEL_LOCAL_EXEC: |
1070 | return unspec == UNSPEC_TPREL; | |
9bdcc1e5 | 1071 | default: |
1072 | abort (); | |
1073 | } | |
5f7b9df8 | 1074 | } |
1075 | ||
1076 | /* Return true if OP is valid for 16-bit DTP relative relocations. */ | |
1077 | ||
1078 | int | |
92643d95 | 1079 | dtp16_symbolic_operand (rtx op, enum machine_mode mode) |
5f7b9df8 | 1080 | { |
1081 | return tls_symbolic_operand_1 (op, mode, 16, UNSPEC_DTPREL); | |
1082 | } | |
1083 | ||
1084 | /* Return true if OP is valid for 32-bit DTP relative relocations. */ | |
1085 | ||
1086 | int | |
92643d95 | 1087 | dtp32_symbolic_operand (rtx op, enum machine_mode mode) |
5f7b9df8 | 1088 | { |
1089 | return tls_symbolic_operand_1 (op, mode, 32, UNSPEC_DTPREL); | |
1090 | } | |
1091 | ||
1092 | /* Return true if OP is valid for 64-bit DTP relative relocations. */ | |
1093 | ||
1094 | int | |
92643d95 | 1095 | gotdtp_symbolic_operand (rtx op, enum machine_mode mode) |
5f7b9df8 | 1096 | { |
1097 | return tls_symbolic_operand_1 (op, mode, 64, UNSPEC_DTPREL); | |
1098 | } | |
1099 | ||
1100 | /* Return true if OP is valid for 16-bit TP relative relocations. */ | |
1101 | ||
1102 | int | |
92643d95 | 1103 | tp16_symbolic_operand (rtx op, enum machine_mode mode) |
5f7b9df8 | 1104 | { |
1105 | return tls_symbolic_operand_1 (op, mode, 16, UNSPEC_TPREL); | |
1106 | } | |
1107 | ||
1108 | /* Return true if OP is valid for 32-bit TP relative relocations. */ | |
1109 | ||
1110 | int | |
92643d95 | 1111 | tp32_symbolic_operand (rtx op, enum machine_mode mode) |
5f7b9df8 | 1112 | { |
1113 | return tls_symbolic_operand_1 (op, mode, 32, UNSPEC_TPREL); | |
1114 | } | |
1115 | ||
1116 | /* Return true if OP is valid for 64-bit TP relative relocations. */ | |
1117 | ||
1118 | int | |
92643d95 | 1119 | gottp_symbolic_operand (rtx op, enum machine_mode mode) |
5f7b9df8 | 1120 | { |
1121 | return tls_symbolic_operand_1 (op, mode, 64, UNSPEC_TPREL); | |
1122 | } | |
1123 | ||
bf2a98b3 | 1124 | /* Return 1 if OP is a valid Alpha comparison operator. Here we know which |
1125 | comparisons are valid in which insn. */ | |
1126 | ||
1127 | int | |
92643d95 | 1128 | alpha_comparison_operator (rtx op, enum machine_mode mode) |
bf2a98b3 | 1129 | { |
1130 | enum rtx_code code = GET_CODE (op); | |
1131 | ||
a4110d9a | 1132 | if (mode != GET_MODE (op) && mode != VOIDmode) |
bf2a98b3 | 1133 | return 0; |
1134 | ||
1135 | return (code == EQ || code == LE || code == LT | |
41ee2fd4 | 1136 | || code == LEU || code == LTU); |
bf2a98b3 | 1137 | } |
1138 | ||
bbf31a61 | 1139 | /* Return 1 if OP is a valid Alpha comparison operator against zero. |
1140 | Here we know which comparisons are valid in which insn. */ | |
1141 | ||
1142 | int | |
92643d95 | 1143 | alpha_zero_comparison_operator (rtx op, enum machine_mode mode) |
bbf31a61 | 1144 | { |
1145 | enum rtx_code code = GET_CODE (op); | |
1146 | ||
1147 | if (mode != GET_MODE (op) && mode != VOIDmode) | |
1148 | return 0; | |
1149 | ||
1150 | return (code == EQ || code == NE || code == LE || code == LT | |
1151 | || code == LEU || code == LTU); | |
1152 | } | |
1153 | ||
2cc5a04b | 1154 | /* Return 1 if OP is a valid Alpha swapped comparison operator. */ |
1155 | ||
1156 | int | |
92643d95 | 1157 | alpha_swapped_comparison_operator (rtx op, enum machine_mode mode) |
2cc5a04b | 1158 | { |
6720e96c | 1159 | enum rtx_code code; |
2cc5a04b | 1160 | |
a4110d9a | 1161 | if ((mode != GET_MODE (op) && mode != VOIDmode) |
405b5ac4 | 1162 | || !COMPARISON_P (op)) |
2cc5a04b | 1163 | return 0; |
1164 | ||
6720e96c | 1165 | code = swap_condition (GET_CODE (op)); |
2cc5a04b | 1166 | return (code == EQ || code == LE || code == LT |
41ee2fd4 | 1167 | || code == LEU || code == LTU); |
2cc5a04b | 1168 | } |
1169 | ||
bf2a98b3 | 1170 | /* Return 1 if OP is a signed comparison operation. */ |
1171 | ||
1172 | int | |
92643d95 | 1173 | signed_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
bf2a98b3 | 1174 | { |
a4110d9a | 1175 | enum rtx_code code = GET_CODE (op); |
99c14947 | 1176 | |
a4110d9a | 1177 | if (mode != GET_MODE (op) && mode != VOIDmode) |
1178 | return 0; | |
bf2a98b3 | 1179 | |
a4110d9a | 1180 | return (code == EQ || code == NE |
1181 | || code == LE || code == LT | |
1182 | || code == GE || code == GT); | |
1183 | } | |
1184 | ||
1185 | /* Return 1 if OP is a valid Alpha floating point comparison operator. | |
1186 | Here we know which comparisons are valid in which insn. */ | |
1187 | ||
1188 | int | |
92643d95 | 1189 | alpha_fp_comparison_operator (rtx op, enum machine_mode mode) |
a4110d9a | 1190 | { |
1191 | enum rtx_code code = GET_CODE (op); | |
1192 | ||
1193 | if (mode != GET_MODE (op) && mode != VOIDmode) | |
1194 | return 0; | |
1195 | ||
1196 | return (code == EQ || code == LE || code == LT || code == UNORDERED); | |
bf2a98b3 | 1197 | } |
1198 | ||
1199 | /* Return 1 if this is a divide or modulus operator. */ | |
1200 | ||
1201 | int | |
92643d95 | 1202 | divmod_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
bf2a98b3 | 1203 | { |
caf6f044 | 1204 | enum rtx_code code = GET_CODE (op); |
99c14947 | 1205 | |
caf6f044 | 1206 | return (code == DIV || code == MOD || code == UDIV || code == UMOD); |
1207 | } | |
bf2a98b3 | 1208 | |
caf6f044 | 1209 | /* Return 1 if this is a float->int conversion operator. */ |
1210 | ||
1211 | int | |
1212 | fix_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
1213 | { | |
1214 | enum rtx_code code = GET_CODE (op); | |
1215 | ||
1216 | return (code == FIX || code == UNSIGNED_FIX); | |
bf2a98b3 | 1217 | } |
1218 | ||
1219 | /* Return 1 if this memory address is a known aligned register plus | |
1220 | a constant. It must be a valid address. This means that we can do | |
1221 | this as an aligned reference plus some offset. | |
1222 | ||
a99a652b | 1223 | Take into account what reload will do. */ |
bf2a98b3 | 1224 | |
1225 | int | |
92643d95 | 1226 | aligned_memory_operand (rtx op, enum machine_mode mode) |
bf2a98b3 | 1227 | { |
cc215844 | 1228 | rtx base; |
bf2a98b3 | 1229 | |
a99a652b | 1230 | if (reload_in_progress) |
1231 | { | |
cc215844 | 1232 | rtx tmp = op; |
1233 | if (GET_CODE (tmp) == SUBREG) | |
1234 | tmp = SUBREG_REG (tmp); | |
1235 | if (GET_CODE (tmp) == REG | |
1236 | && REGNO (tmp) >= FIRST_PSEUDO_REGISTER) | |
1237 | { | |
1238 | op = reg_equiv_memory_loc[REGNO (tmp)]; | |
1239 | if (op == 0) | |
1240 | return 0; | |
1241 | } | |
a99a652b | 1242 | } |
bf2a98b3 | 1243 | |
d67e1866 | 1244 | if (GET_CODE (op) != MEM) |
bf2a98b3 | 1245 | return 0; |
d67e1866 | 1246 | if (MEM_ALIGN (op) >= 32) |
1247 | return 1; | |
bf2a98b3 | 1248 | op = XEXP (op, 0); |
1249 | ||
cc215844 | 1250 | /* LEGITIMIZE_RELOAD_ADDRESS creates (plus (plus reg const_hi) const_lo) |
1251 | sorts of constructs. Dig for the real base register. */ | |
1252 | if (reload_in_progress | |
1253 | && GET_CODE (op) == PLUS | |
1254 | && GET_CODE (XEXP (op, 0)) == PLUS) | |
1255 | base = XEXP (XEXP (op, 0), 0); | |
1256 | else | |
1257 | { | |
1258 | if (! memory_address_p (mode, op)) | |
1259 | return 0; | |
1260 | base = (GET_CODE (op) == PLUS ? XEXP (op, 0) : op); | |
1261 | } | |
bf2a98b3 | 1262 | |
80909c64 | 1263 | return (GET_CODE (base) == REG && REGNO_POINTER_ALIGN (REGNO (base)) >= 32); |
bf2a98b3 | 1264 | } |
1265 | ||
1266 | /* Similar, but return 1 if OP is a MEM which is not alignable. */ | |
1267 | ||
1268 | int | |
92643d95 | 1269 | unaligned_memory_operand (rtx op, enum machine_mode mode) |
bf2a98b3 | 1270 | { |
cc215844 | 1271 | rtx base; |
1272 | ||
1273 | if (reload_in_progress) | |
bf2a98b3 | 1274 | { |
cc215844 | 1275 | rtx tmp = op; |
1276 | if (GET_CODE (tmp) == SUBREG) | |
1277 | tmp = SUBREG_REG (tmp); | |
1278 | if (GET_CODE (tmp) == REG | |
1279 | && REGNO (tmp) >= FIRST_PSEUDO_REGISTER) | |
1280 | { | |
1281 | op = reg_equiv_memory_loc[REGNO (tmp)]; | |
1282 | if (op == 0) | |
1283 | return 0; | |
1284 | } | |
bf2a98b3 | 1285 | } |
1286 | ||
d67e1866 | 1287 | if (GET_CODE (op) != MEM) |
1288 | return 0; | |
1289 | if (MEM_ALIGN (op) >= 32) | |
bf2a98b3 | 1290 | return 0; |
bf2a98b3 | 1291 | op = XEXP (op, 0); |
1292 | ||
cc215844 | 1293 | /* LEGITIMIZE_RELOAD_ADDRESS creates (plus (plus reg const_hi) const_lo) |
1294 | sorts of constructs. Dig for the real base register. */ | |
1295 | if (reload_in_progress | |
1296 | && GET_CODE (op) == PLUS | |
1297 | && GET_CODE (XEXP (op, 0)) == PLUS) | |
1298 | base = XEXP (XEXP (op, 0), 0); | |
1299 | else | |
1300 | { | |
1301 | if (! memory_address_p (mode, op)) | |
1302 | return 0; | |
1303 | base = (GET_CODE (op) == PLUS ? XEXP (op, 0) : op); | |
1304 | } | |
bf2a98b3 | 1305 | |
80909c64 | 1306 | return (GET_CODE (base) == REG && REGNO_POINTER_ALIGN (REGNO (base)) < 32); |
b044f41c | 1307 | } |
1308 | ||
1309 | /* Return 1 if OP is either a register or an unaligned memory location. */ | |
1310 | ||
1311 | int | |
92643d95 | 1312 | reg_or_unaligned_mem_operand (rtx op, enum machine_mode mode) |
b044f41c | 1313 | { |
1314 | return register_operand (op, mode) || unaligned_memory_operand (op, mode); | |
bf2a98b3 | 1315 | } |
1316 | ||
1317 | /* Return 1 if OP is any memory location. During reload a pseudo matches. */ | |
1318 | ||
1319 | int | |
92643d95 | 1320 | any_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
bf2a98b3 | 1321 | { |
1322 | return (GET_CODE (op) == MEM | |
1323 | || (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG) | |
1324 | || (reload_in_progress && GET_CODE (op) == REG | |
1325 | && REGNO (op) >= FIRST_PSEUDO_REGISTER) | |
1326 | || (reload_in_progress && GET_CODE (op) == SUBREG | |
1327 | && GET_CODE (SUBREG_REG (op)) == REG | |
1328 | && REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER)); | |
1329 | } | |
1330 | ||
d882587d | 1331 | /* Returns 1 if OP is not an eliminable register. |
1332 | ||
1333 | This exists to cure a pathological abort in the s8addq (et al) patterns, | |
1334 | ||
1335 | long foo () { long t; bar(); return (long) &t * 26107; } | |
1336 | ||
1337 | which run afoul of a hack in reload to cure a (presumably) similar | |
1338 | problem with lea-type instructions on other targets. But there is | |
1339 | one of us and many of them, so work around the problem by selectively | |
1340 | preventing combine from making the optimization. */ | |
1341 | ||
1342 | int | |
92643d95 | 1343 | reg_not_elim_operand (rtx op, enum machine_mode mode) |
d882587d | 1344 | { |
1345 | rtx inner = op; | |
1346 | if (GET_CODE (op) == SUBREG) | |
1347 | inner = SUBREG_REG (op); | |
1348 | if (inner == frame_pointer_rtx || inner == arg_pointer_rtx) | |
1349 | return 0; | |
1350 | ||
1351 | return register_operand (op, mode); | |
1352 | } | |
b9a5aa8e | 1353 | |
1836306d | 1354 | /* Return 1 is OP is a memory location that is not a reference (using |
be2828ce | 1355 | an AND) to an unaligned location. Take into account what reload |
1356 | will do. */ | |
1357 | ||
1358 | int | |
92643d95 | 1359 | normal_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) |
be2828ce | 1360 | { |
cc215844 | 1361 | if (reload_in_progress) |
be2828ce | 1362 | { |
cc215844 | 1363 | rtx tmp = op; |
1364 | if (GET_CODE (tmp) == SUBREG) | |
1365 | tmp = SUBREG_REG (tmp); | |
1366 | if (GET_CODE (tmp) == REG | |
1367 | && REGNO (tmp) >= FIRST_PSEUDO_REGISTER) | |
1368 | { | |
1369 | op = reg_equiv_memory_loc[REGNO (tmp)]; | |
be2828ce | 1370 | |
cc215844 | 1371 | /* This may not have been assigned an equivalent address if it will |
1372 | be eliminated. In that case, it doesn't matter what we do. */ | |
1373 | if (op == 0) | |
1374 | return 1; | |
1375 | } | |
be2828ce | 1376 | } |
1377 | ||
1378 | return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) != AND; | |
1379 | } | |
1836306d | 1380 | |
1381 | /* Accept a register, but not a subreg of any kind. This allows us to | |
1382 | avoid pathological cases in reload wrt data movement common in | |
1383 | int->fp conversion. */ | |
1384 | ||
1385 | int | |
92643d95 | 1386 | reg_no_subreg_operand (rtx op, enum machine_mode mode) |
1836306d | 1387 | { |
2f1a5feb | 1388 | if (GET_CODE (op) != REG) |
1836306d | 1389 | return 0; |
1390 | return register_operand (op, mode); | |
1391 | } | |
14f7bc98 | 1392 | |
45981c0a | 1393 | /* Recognize an addition operation that includes a constant. Used to |
14f7bc98 | 1394 | convince reload to canonize (plus (plus reg c1) c2) during register |
1395 | elimination. */ | |
1396 | ||
1397 | int | |
92643d95 | 1398 | addition_operation (rtx op, enum machine_mode mode) |
14f7bc98 | 1399 | { |
1400 | if (GET_MODE (op) != mode && mode != VOIDmode) | |
1401 | return 0; | |
1402 | if (GET_CODE (op) == PLUS | |
1403 | && register_operand (XEXP (op, 0), mode) | |
1404 | && GET_CODE (XEXP (op, 1)) == CONST_INT | |
1405 | && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op, 1)), 'K')) | |
1406 | return 1; | |
1407 | return 0; | |
1408 | } | |
1409 | ||
f5a60074 | 1410 | /* Implements CONST_OK_FOR_LETTER_P. Return true if the value matches |
1411 | the range defined for C in [I-P]. */ | |
1412 | ||
1413 | bool | |
92643d95 | 1414 | alpha_const_ok_for_letter_p (HOST_WIDE_INT value, int c) |
f5a60074 | 1415 | { |
1416 | switch (c) | |
1417 | { | |
1418 | case 'I': | |
1419 | /* An unsigned 8 bit constant. */ | |
1420 | return (unsigned HOST_WIDE_INT) value < 0x100; | |
1421 | case 'J': | |
1422 | /* The constant zero. */ | |
1423 | return value == 0; | |
1424 | case 'K': | |
1425 | /* A signed 16 bit constant. */ | |
1426 | return (unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000; | |
1427 | case 'L': | |
1428 | /* A shifted signed 16 bit constant appropriate for LDAH. */ | |
1429 | return ((value & 0xffff) == 0 | |
1430 | && ((value) >> 31 == -1 || value >> 31 == 0)); | |
1431 | case 'M': | |
1432 | /* A constant that can be AND'ed with using a ZAP insn. */ | |
1433 | return zap_mask (value); | |
1434 | case 'N': | |
1435 | /* A complemented unsigned 8 bit constant. */ | |
1436 | return (unsigned HOST_WIDE_INT) (~ value) < 0x100; | |
1437 | case 'O': | |
1438 | /* A negated unsigned 8 bit constant. */ | |
1439 | return (unsigned HOST_WIDE_INT) (- value) < 0x100; | |
1440 | case 'P': | |
1441 | /* The constant 1, 2 or 3. */ | |
1442 | return value == 1 || value == 2 || value == 3; | |
1443 | ||
1444 | default: | |
1445 | return false; | |
1446 | } | |
1447 | } | |
1448 | ||
1449 | /* Implements CONST_DOUBLE_OK_FOR_LETTER_P. Return true if VALUE | |
1450 | matches for C in [GH]. */ | |
1451 | ||
1452 | bool | |
92643d95 | 1453 | alpha_const_double_ok_for_letter_p (rtx value, int c) |
f5a60074 | 1454 | { |
1455 | switch (c) | |
1456 | { | |
1457 | case 'G': | |
1458 | /* The floating point zero constant. */ | |
1459 | return (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT | |
1460 | && value == CONST0_RTX (GET_MODE (value))); | |
1461 | ||
1462 | case 'H': | |
1463 | /* A valid operand of a ZAP insn. */ | |
1464 | return (GET_MODE (value) == VOIDmode | |
1465 | && zap_mask (CONST_DOUBLE_LOW (value)) | |
1466 | && zap_mask (CONST_DOUBLE_HIGH (value))); | |
1467 | ||
1468 | default: | |
1469 | return false; | |
1470 | } | |
1471 | } | |
1472 | ||
1473 | /* Implements CONST_DOUBLE_OK_FOR_LETTER_P. Return true if VALUE | |
1474 | matches for C. */ | |
1475 | ||
1476 | bool | |
92643d95 | 1477 | alpha_extra_constraint (rtx value, int c) |
f5a60074 | 1478 | { |
1479 | switch (c) | |
1480 | { | |
1481 | case 'Q': | |
1482 | return normal_memory_operand (value, VOIDmode); | |
1483 | case 'R': | |
1484 | return direct_call_operand (value, Pmode); | |
1485 | case 'S': | |
1486 | return (GET_CODE (value) == CONST_INT | |
1487 | && (unsigned HOST_WIDE_INT) INTVAL (value) < 64); | |
1488 | case 'T': | |
1489 | return GET_CODE (value) == HIGH; | |
1490 | case 'U': | |
1491 | return TARGET_ABI_UNICOSMK && symbolic_operand (value, VOIDmode); | |
f2cc13dc | 1492 | case 'W': |
1493 | return (GET_CODE (value) == CONST_VECTOR | |
1494 | && value == CONST0_RTX (GET_MODE (value))); | |
f5a60074 | 1495 | default: |
1496 | return false; | |
1497 | } | |
1498 | } | |
1499 | ||
550e415f | 1500 | /* Return 1 if this function can directly return via $26. */ |
1501 | ||
1502 | int | |
92643d95 | 1503 | direct_return (void) |
550e415f | 1504 | { |
9caef960 | 1505 | return (! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK |
1467e953 | 1506 | && reload_completed |
1507 | && alpha_sa_size () == 0 | |
550e415f | 1508 | && get_frame_size () == 0 |
1509 | && current_function_outgoing_args_size == 0 | |
1510 | && current_function_pretend_args_size == 0); | |
1511 | } | |
ecb98d40 | 1512 | |
1513 | /* Return the ADDR_VEC associated with a tablejump insn. */ | |
1514 | ||
1515 | rtx | |
92643d95 | 1516 | alpha_tablejump_addr_vec (rtx insn) |
ecb98d40 | 1517 | { |
1518 | rtx tmp; | |
1519 | ||
1520 | tmp = JUMP_LABEL (insn); | |
1521 | if (!tmp) | |
1522 | return NULL_RTX; | |
1523 | tmp = NEXT_INSN (tmp); | |
1524 | if (!tmp) | |
1525 | return NULL_RTX; | |
1526 | if (GET_CODE (tmp) == JUMP_INSN | |
1527 | && GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC) | |
1528 | return PATTERN (tmp); | |
1529 | return NULL_RTX; | |
1530 | } | |
1531 | ||
1532 | /* Return the label of the predicted edge, or CONST0_RTX if we don't know. */ | |
1533 | ||
1534 | rtx | |
92643d95 | 1535 | alpha_tablejump_best_label (rtx insn) |
ecb98d40 | 1536 | { |
1537 | rtx jump_table = alpha_tablejump_addr_vec (insn); | |
1538 | rtx best_label = NULL_RTX; | |
1539 | ||
1540 | /* ??? Once the CFG doesn't keep getting completely rebuilt, look | |
1541 | there for edge frequency counts from profile data. */ | |
1542 | ||
1543 | if (jump_table) | |
1544 | { | |
1545 | int n_labels = XVECLEN (jump_table, 1); | |
1546 | int best_count = -1; | |
1547 | int i, j; | |
1548 | ||
1549 | for (i = 0; i < n_labels; i++) | |
1550 | { | |
1551 | int count = 1; | |
1552 | ||
1553 | for (j = i + 1; j < n_labels; j++) | |
1554 | if (XEXP (XVECEXP (jump_table, 1, i), 0) | |
1555 | == XEXP (XVECEXP (jump_table, 1, j), 0)) | |
1556 | count++; | |
1557 | ||
1558 | if (count > best_count) | |
1559 | best_count = count, best_label = XVECEXP (jump_table, 1, i); | |
1560 | } | |
1561 | } | |
1562 | ||
1563 | return best_label ? best_label : const0_rtx; | |
1564 | } | |
5f7b9df8 | 1565 | |
1566 | /* Return the TLS model to use for SYMBOL. */ | |
1567 | ||
1568 | static enum tls_model | |
92643d95 | 1569 | tls_symbolic_operand_type (rtx symbol) |
5f7b9df8 | 1570 | { |
09a1f342 | 1571 | enum tls_model model; |
5f7b9df8 | 1572 | |
1573 | if (GET_CODE (symbol) != SYMBOL_REF) | |
1574 | return 0; | |
09a1f342 | 1575 | model = SYMBOL_REF_TLS_MODEL (symbol); |
5f7b9df8 | 1576 | |
09a1f342 | 1577 | /* Local-exec with a 64-bit size is the same code as initial-exec. */ |
1578 | if (model == TLS_MODEL_LOCAL_EXEC && alpha_tls_size == 64) | |
1579 | model = TLS_MODEL_INITIAL_EXEC; | |
5f7b9df8 | 1580 | |
09a1f342 | 1581 | return model; |
5f7b9df8 | 1582 | } |
14f7bc98 | 1583 | \f |
9bdcc1e5 | 1584 | /* Return true if the function DECL will share the same GP as any |
1585 | function in the current unit of translation. */ | |
1586 | ||
1587 | static bool | |
92643d95 | 1588 | decl_has_samegp (tree decl) |
9bdcc1e5 | 1589 | { |
1590 | /* Functions that are not local can be overridden, and thus may | |
1591 | not share the same gp. */ | |
1592 | if (!(*targetm.binds_local_p) (decl)) | |
1593 | return false; | |
1594 | ||
1595 | /* If -msmall-data is in effect, assume that there is only one GP | |
1596 | for the module, and so any local symbol has this property. We | |
1597 | need explicit relocations to be able to enforce this for symbols | |
1598 | not defined in this unit of translation, however. */ | |
1599 | if (TARGET_EXPLICIT_RELOCS && TARGET_SMALL_DATA) | |
1600 | return true; | |
1601 | ||
1602 | /* Functions that are not external are defined in this UoT. */ | |
cf1d67e3 | 1603 | /* ??? Irritatingly, static functions not yet emitted are still |
1604 | marked "external". Apply this to non-static functions only. */ | |
1605 | return !TREE_PUBLIC (decl) || !DECL_EXTERNAL (decl); | |
9bdcc1e5 | 1606 | } |
1607 | ||
52470889 | 1608 | /* Return true if EXP should be placed in the small data section. */ |
1609 | ||
1610 | static bool | |
92643d95 | 1611 | alpha_in_small_data_p (tree exp) |
52470889 | 1612 | { |
0aad4cd2 | 1613 | /* We want to merge strings, so we never consider them small data. */ |
1614 | if (TREE_CODE (exp) == STRING_CST) | |
1615 | return false; | |
1616 | ||
6ac09a46 | 1617 | /* Functions are never in the small data area. Duh. */ |
1618 | if (TREE_CODE (exp) == FUNCTION_DECL) | |
1619 | return false; | |
1620 | ||
52470889 | 1621 | if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) |
1622 | { | |
1623 | const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); | |
1624 | if (strcmp (section, ".sdata") == 0 | |
1625 | || strcmp (section, ".sbss") == 0) | |
1626 | return true; | |
1627 | } | |
1628 | else | |
1629 | { | |
1630 | HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); | |
1631 | ||
1632 | /* If this is an incomplete type with size 0, then we can't put it | |
1633 | in sdata because it might be too big when completed. */ | |
3be2f219 | 1634 | if (size > 0 && (unsigned HOST_WIDE_INT) size <= g_switch_value) |
52470889 | 1635 | return true; |
1636 | } | |
1637 | ||
1638 | return false; | |
1639 | } | |
1640 | ||
cf73d31f | 1641 | #if TARGET_ABI_OPEN_VMS |
1642 | static bool | |
92643d95 | 1643 | alpha_linkage_symbol_p (const char *symname) |
cf73d31f | 1644 | { |
1645 | int symlen = strlen (symname); | |
1646 | ||
1647 | if (symlen > 4) | |
1648 | return strcmp (&symname [symlen - 4], "..lk") == 0; | |
1649 | ||
1650 | return false; | |
1651 | } | |
1652 | ||
1653 | #define LINKAGE_SYMBOL_REF_P(X) \ | |
1654 | ((GET_CODE (X) == SYMBOL_REF \ | |
1655 | && alpha_linkage_symbol_p (XSTR (X, 0))) \ | |
1656 | || (GET_CODE (X) == CONST \ | |
1657 | && GET_CODE (XEXP (X, 0)) == PLUS \ | |
1658 | && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF \ | |
1659 | && alpha_linkage_symbol_p (XSTR (XEXP (XEXP (X, 0), 0), 0)))) | |
1660 | #endif | |
1661 | ||
24b3c0ed | 1662 | /* legitimate_address_p recognizes an RTL expression that is a valid |
1663 | memory address for an instruction. The MODE argument is the | |
1664 | machine mode for the MEM expression that wants to use this address. | |
1665 | ||
1666 | For Alpha, we have either a constant address or the sum of a | |
1667 | register and a constant address, or just a register. For DImode, | |
1668 | any of those forms can be surrounded with an AND that clear the | |
1669 | low-order three bits; this is an "unaligned" access. */ | |
1670 | ||
1671 | bool | |
92643d95 | 1672 | alpha_legitimate_address_p (enum machine_mode mode, rtx x, int strict) |
24b3c0ed | 1673 | { |
1674 | /* If this is an ldq_u type address, discard the outer AND. */ | |
1675 | if (mode == DImode | |
1676 | && GET_CODE (x) == AND | |
1677 | && GET_CODE (XEXP (x, 1)) == CONST_INT | |
1678 | && INTVAL (XEXP (x, 1)) == -8) | |
1679 | x = XEXP (x, 0); | |
1680 | ||
1681 | /* Discard non-paradoxical subregs. */ | |
1682 | if (GET_CODE (x) == SUBREG | |
1683 | && (GET_MODE_SIZE (GET_MODE (x)) | |
1684 | < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) | |
1685 | x = SUBREG_REG (x); | |
1686 | ||
1687 | /* Unadorned general registers are valid. */ | |
1688 | if (REG_P (x) | |
1689 | && (strict | |
1690 | ? STRICT_REG_OK_FOR_BASE_P (x) | |
1691 | : NONSTRICT_REG_OK_FOR_BASE_P (x))) | |
1692 | return true; | |
1693 | ||
1694 | /* Constant addresses (i.e. +/- 32k) are valid. */ | |
1695 | if (CONSTANT_ADDRESS_P (x)) | |
1696 | return true; | |
1697 | ||
cf73d31f | 1698 | #if TARGET_ABI_OPEN_VMS |
1699 | if (LINKAGE_SYMBOL_REF_P (x)) | |
1700 | return true; | |
1701 | #endif | |
1702 | ||
24b3c0ed | 1703 | /* Register plus a small constant offset is valid. */ |
1704 | if (GET_CODE (x) == PLUS) | |
1705 | { | |
1706 | rtx ofs = XEXP (x, 1); | |
1707 | x = XEXP (x, 0); | |
1708 | ||
1709 | /* Discard non-paradoxical subregs. */ | |
1710 | if (GET_CODE (x) == SUBREG | |
1711 | && (GET_MODE_SIZE (GET_MODE (x)) | |
1712 | < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) | |
1713 | x = SUBREG_REG (x); | |
1714 | ||
1715 | if (REG_P (x)) | |
1716 | { | |
1717 | if (! strict | |
1718 | && NONSTRICT_REG_OK_FP_BASE_P (x) | |
1719 | && GET_CODE (ofs) == CONST_INT) | |
1720 | return true; | |
1721 | if ((strict | |
1722 | ? STRICT_REG_OK_FOR_BASE_P (x) | |
1723 | : NONSTRICT_REG_OK_FOR_BASE_P (x)) | |
1724 | && CONSTANT_ADDRESS_P (ofs)) | |
1725 | return true; | |
1726 | } | |
24b3c0ed | 1727 | } |
1728 | ||
f5a60074 | 1729 | /* If we're managing explicit relocations, LO_SUM is valid, as |
1730 | are small data symbols. */ | |
1731 | else if (TARGET_EXPLICIT_RELOCS) | |
1f0ce6a6 | 1732 | { |
f5a60074 | 1733 | if (small_symbolic_operand (x, Pmode)) |
1f0ce6a6 | 1734 | return true; |
f5a60074 | 1735 | |
1736 | if (GET_CODE (x) == LO_SUM) | |
1737 | { | |
1738 | rtx ofs = XEXP (x, 1); | |
1739 | x = XEXP (x, 0); | |
1740 | ||
1741 | /* Discard non-paradoxical subregs. */ | |
1742 | if (GET_CODE (x) == SUBREG | |
1743 | && (GET_MODE_SIZE (GET_MODE (x)) | |
1744 | < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) | |
1745 | x = SUBREG_REG (x); | |
1746 | ||
1747 | /* Must have a valid base register. */ | |
1748 | if (! (REG_P (x) | |
1749 | && (strict | |
1750 | ? STRICT_REG_OK_FOR_BASE_P (x) | |
1751 | : NONSTRICT_REG_OK_FOR_BASE_P (x)))) | |
1752 | return false; | |
1753 | ||
1754 | /* The symbol must be local. */ | |
5f7b9df8 | 1755 | if (local_symbolic_operand (ofs, Pmode) |
1756 | || dtp32_symbolic_operand (ofs, Pmode) | |
1757 | || tp32_symbolic_operand (ofs, Pmode)) | |
f5a60074 | 1758 | return true; |
1759 | } | |
1f0ce6a6 | 1760 | } |
1761 | ||
24b3c0ed | 1762 | return false; |
1763 | } | |
1764 | ||
09a1f342 | 1765 | /* Build the SYMBOL_REF for __tls_get_addr. */ |
1766 | ||
1767 | static GTY(()) rtx tls_get_addr_libfunc; | |
1768 | ||
1769 | static rtx | |
92643d95 | 1770 | get_tls_get_addr (void) |
09a1f342 | 1771 | { |
1772 | if (!tls_get_addr_libfunc) | |
1773 | tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr"); | |
1774 | return tls_get_addr_libfunc; | |
1775 | } | |
1776 | ||
0d50f0b7 | 1777 | /* Try machine-dependent ways of modifying an illegitimate address |
1778 | to be legitimate. If we find one, return the new, valid address. */ | |
1779 | ||
1780 | rtx | |
92643d95 | 1781 | alpha_legitimize_address (rtx x, rtx scratch, |
1782 | enum machine_mode mode ATTRIBUTE_UNUSED) | |
0d50f0b7 | 1783 | { |
1784 | HOST_WIDE_INT addend; | |
1785 | ||
1786 | /* If the address is (plus reg const_int) and the CONST_INT is not a | |
1787 | valid offset, compute the high part of the constant and add it to | |
1788 | the register. Then our address is (plus temp low-part-const). */ | |
1789 | if (GET_CODE (x) == PLUS | |
1790 | && GET_CODE (XEXP (x, 0)) == REG | |
1791 | && GET_CODE (XEXP (x, 1)) == CONST_INT | |
1792 | && ! CONSTANT_ADDRESS_P (XEXP (x, 1))) | |
1793 | { | |
1794 | addend = INTVAL (XEXP (x, 1)); | |
1795 | x = XEXP (x, 0); | |
1796 | goto split_addend; | |
1797 | } | |
1798 | ||
1799 | /* If the address is (const (plus FOO const_int)), find the low-order | |
1800 | part of the CONST_INT. Then load FOO plus any high-order part of the | |
1801 | CONST_INT into a register. Our address is (plus reg low-part-const). | |
1802 | This is done to reduce the number of GOT entries. */ | |
f5a60074 | 1803 | if (!no_new_pseudos |
1804 | && GET_CODE (x) == CONST | |
0d50f0b7 | 1805 | && GET_CODE (XEXP (x, 0)) == PLUS |
1806 | && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) | |
1807 | { | |
1808 | addend = INTVAL (XEXP (XEXP (x, 0), 1)); | |
1809 | x = force_reg (Pmode, XEXP (XEXP (x, 0), 0)); | |
1810 | goto split_addend; | |
1811 | } | |
1812 | ||
1813 | /* If we have a (plus reg const), emit the load as in (2), then add | |
1814 | the two registers, and finally generate (plus reg low-part-const) as | |
1815 | our address. */ | |
f5a60074 | 1816 | if (!no_new_pseudos |
1817 | && GET_CODE (x) == PLUS | |
0d50f0b7 | 1818 | && GET_CODE (XEXP (x, 0)) == REG |
1819 | && GET_CODE (XEXP (x, 1)) == CONST | |
1820 | && GET_CODE (XEXP (XEXP (x, 1), 0)) == PLUS | |
1821 | && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == CONST_INT) | |
1822 | { | |
1823 | addend = INTVAL (XEXP (XEXP (XEXP (x, 1), 0), 1)); | |
1824 | x = expand_simple_binop (Pmode, PLUS, XEXP (x, 0), | |
1825 | XEXP (XEXP (XEXP (x, 1), 0), 0), | |
1826 | NULL_RTX, 1, OPTAB_LIB_WIDEN); | |
1827 | goto split_addend; | |
1828 | } | |
1829 | ||
1f0ce6a6 | 1830 | /* If this is a local symbol, split the address into HIGH/LO_SUM parts. */ |
8afb6db4 | 1831 | if (TARGET_EXPLICIT_RELOCS && symbolic_operand (x, Pmode)) |
1f0ce6a6 | 1832 | { |
5f7b9df8 | 1833 | rtx r0, r16, eqv, tga, tp, insn, dest, seq; |
1834 | ||
1835 | switch (tls_symbolic_operand_type (x)) | |
1836 | { | |
1837 | case TLS_MODEL_GLOBAL_DYNAMIC: | |
1838 | start_sequence (); | |
1839 | ||
1840 | r0 = gen_rtx_REG (Pmode, 0); | |
1841 | r16 = gen_rtx_REG (Pmode, 16); | |
09a1f342 | 1842 | tga = get_tls_get_addr (); |
5f7b9df8 | 1843 | dest = gen_reg_rtx (Pmode); |
1844 | seq = GEN_INT (alpha_next_sequence_number++); | |
1845 | ||
1846 | emit_insn (gen_movdi_er_tlsgd (r16, pic_offset_table_rtx, x, seq)); | |
1847 | insn = gen_call_value_osf_tlsgd (r0, tga, seq); | |
1848 | insn = emit_call_insn (insn); | |
1849 | CONST_OR_PURE_CALL_P (insn) = 1; | |
1850 | use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16); | |
1851 | ||
1852 | insn = get_insns (); | |
1853 | end_sequence (); | |
1854 | ||
1855 | emit_libcall_block (insn, dest, r0, x); | |
1856 | return dest; | |
1857 | ||
1858 | case TLS_MODEL_LOCAL_DYNAMIC: | |
1859 | start_sequence (); | |
1860 | ||
1861 | r0 = gen_rtx_REG (Pmode, 0); | |
1862 | r16 = gen_rtx_REG (Pmode, 16); | |
09a1f342 | 1863 | tga = get_tls_get_addr (); |
5f7b9df8 | 1864 | scratch = gen_reg_rtx (Pmode); |
1865 | seq = GEN_INT (alpha_next_sequence_number++); | |
1866 | ||
1867 | emit_insn (gen_movdi_er_tlsldm (r16, pic_offset_table_rtx, seq)); | |
1868 | insn = gen_call_value_osf_tlsldm (r0, tga, seq); | |
1869 | insn = emit_call_insn (insn); | |
1870 | CONST_OR_PURE_CALL_P (insn) = 1; | |
1871 | use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16); | |
1872 | ||
1873 | insn = get_insns (); | |
1874 | end_sequence (); | |
1875 | ||
1876 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), | |
1877 | UNSPEC_TLSLDM_CALL); | |
1878 | emit_libcall_block (insn, scratch, r0, eqv); | |
1879 | ||
1880 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPREL); | |
1881 | eqv = gen_rtx_CONST (Pmode, eqv); | |
1882 | ||
1883 | if (alpha_tls_size == 64) | |
1884 | { | |
1885 | dest = gen_reg_rtx (Pmode); | |
1886 | emit_insn (gen_rtx_SET (VOIDmode, dest, eqv)); | |
1887 | emit_insn (gen_adddi3 (dest, dest, scratch)); | |
1888 | return dest; | |
1889 | } | |
1890 | if (alpha_tls_size == 32) | |
1891 | { | |
1892 | insn = gen_rtx_HIGH (Pmode, eqv); | |
1893 | insn = gen_rtx_PLUS (Pmode, scratch, insn); | |
1894 | scratch = gen_reg_rtx (Pmode); | |
1895 | emit_insn (gen_rtx_SET (VOIDmode, scratch, insn)); | |
1896 | } | |
1897 | return gen_rtx_LO_SUM (Pmode, scratch, eqv); | |
1898 | ||
1899 | case TLS_MODEL_INITIAL_EXEC: | |
1900 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL); | |
1901 | eqv = gen_rtx_CONST (Pmode, eqv); | |
1902 | tp = gen_reg_rtx (Pmode); | |
1903 | scratch = gen_reg_rtx (Pmode); | |
1904 | dest = gen_reg_rtx (Pmode); | |
1905 | ||
1906 | emit_insn (gen_load_tp (tp)); | |
1907 | emit_insn (gen_rtx_SET (VOIDmode, scratch, eqv)); | |
1908 | emit_insn (gen_adddi3 (dest, tp, scratch)); | |
1909 | return dest; | |
1910 | ||
1911 | case TLS_MODEL_LOCAL_EXEC: | |
1912 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL); | |
1913 | eqv = gen_rtx_CONST (Pmode, eqv); | |
1914 | tp = gen_reg_rtx (Pmode); | |
1915 | ||
1916 | emit_insn (gen_load_tp (tp)); | |
1917 | if (alpha_tls_size == 32) | |
1918 | { | |
1919 | insn = gen_rtx_HIGH (Pmode, eqv); | |
1920 | insn = gen_rtx_PLUS (Pmode, tp, insn); | |
1921 | tp = gen_reg_rtx (Pmode); | |
1922 | emit_insn (gen_rtx_SET (VOIDmode, tp, insn)); | |
1923 | } | |
1924 | return gen_rtx_LO_SUM (Pmode, tp, eqv); | |
1925 | } | |
1926 | ||
8afb6db4 | 1927 | if (local_symbolic_operand (x, Pmode)) |
1928 | { | |
1929 | if (small_symbolic_operand (x, Pmode)) | |
f5a60074 | 1930 | return x; |
8afb6db4 | 1931 | else |
1932 | { | |
f5a60074 | 1933 | if (!no_new_pseudos) |
1934 | scratch = gen_reg_rtx (Pmode); | |
1935 | emit_insn (gen_rtx_SET (VOIDmode, scratch, | |
1936 | gen_rtx_HIGH (Pmode, x))); | |
1937 | return gen_rtx_LO_SUM (Pmode, scratch, x); | |
8afb6db4 | 1938 | } |
5dcb037d | 1939 | } |
1f0ce6a6 | 1940 | } |
1941 | ||
0d50f0b7 | 1942 | return NULL; |
1943 | ||
1944 | split_addend: | |
1945 | { | |
f5a60074 | 1946 | HOST_WIDE_INT low, high; |
1947 | ||
1948 | low = ((addend & 0xffff) ^ 0x8000) - 0x8000; | |
1949 | addend -= low; | |
1950 | high = ((addend & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
1951 | addend -= high; | |
1952 | ||
1953 | if (addend) | |
1954 | x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (addend), | |
1955 | (no_new_pseudos ? scratch : NULL_RTX), | |
1956 | 1, OPTAB_LIB_WIDEN); | |
1957 | if (high) | |
1958 | x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (high), | |
1959 | (no_new_pseudos ? scratch : NULL_RTX), | |
1960 | 1, OPTAB_LIB_WIDEN); | |
1961 | ||
1962 | return plus_constant (x, low); | |
0d50f0b7 | 1963 | } |
1964 | } | |
1965 | ||
805e22b2 | 1966 | /* We do not allow indirect calls to be optimized into sibling calls, nor |
9bdcc1e5 | 1967 | can we allow a call to a function with a different GP to be optimized |
1968 | into a sibcall. */ | |
1969 | ||
805e22b2 | 1970 | static bool |
92643d95 | 1971 | alpha_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) |
805e22b2 | 1972 | { |
9bdcc1e5 | 1973 | /* Can't do indirect tail calls, since we don't know if the target |
1974 | uses the same GP. */ | |
1975 | if (!decl) | |
1976 | return false; | |
1977 | ||
1978 | /* Otherwise, we can make a tail call if the target function shares | |
1979 | the same GP. */ | |
1980 | return decl_has_samegp (decl); | |
805e22b2 | 1981 | } |
1982 | ||
f5a60074 | 1983 | /* For TARGET_EXPLICIT_RELOCS, we don't obfuscate a SYMBOL_REF to a |
1984 | small symbolic operand until after reload. At which point we need | |
1985 | to replace (mem (symbol_ref)) with (mem (lo_sum $29 symbol_ref)) | |
1986 | so that sched2 has the proper dependency information. */ | |
1987 | ||
367e2ab3 | 1988 | static int |
92643d95 | 1989 | some_small_symbolic_operand_1 (rtx *px, void *data ATTRIBUTE_UNUSED) |
367e2ab3 | 1990 | { |
1991 | rtx x = *px; | |
f5a60074 | 1992 | |
792433e3 | 1993 | /* Don't re-split. */ |
1994 | if (GET_CODE (x) == LO_SUM) | |
1995 | return -1; | |
367e2ab3 | 1996 | |
792433e3 | 1997 | return small_symbolic_operand (x, Pmode) != 0; |
f5a60074 | 1998 | } |
1999 | ||
92643d95 | 2000 | int |
2001 | some_small_symbolic_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED) | |
f5a60074 | 2002 | { |
92643d95 | 2003 | return for_each_rtx (&x, some_small_symbolic_operand_1, NULL); |
367e2ab3 | 2004 | } |
f5a60074 | 2005 | |
367e2ab3 | 2006 | static int |
92643d95 | 2007 | split_small_symbolic_operand_1 (rtx *px, void *data ATTRIBUTE_UNUSED) |
367e2ab3 | 2008 | { |
2009 | rtx x = *px; | |
443bb1a6 | 2010 | |
792433e3 | 2011 | /* Don't re-split. */ |
2012 | if (GET_CODE (x) == LO_SUM) | |
2013 | return -1; | |
f5a60074 | 2014 | |
367e2ab3 | 2015 | if (small_symbolic_operand (x, Pmode)) |
2016 | { | |
2017 | x = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, x); | |
2018 | *px = x; | |
792433e3 | 2019 | return -1; |
367e2ab3 | 2020 | } |
2021 | ||
792433e3 | 2022 | return 0; |
f5a60074 | 2023 | } |
2024 | ||
92643d95 | 2025 | rtx |
2026 | split_small_symbolic_operand (rtx x) | |
2027 | { | |
2028 | x = copy_insn (x); | |
2029 | for_each_rtx (&x, split_small_symbolic_operand_1, NULL); | |
2030 | return x; | |
2031 | } | |
2032 | ||
2f58af60 | 2033 | /* Indicate that INSN cannot be duplicated. This is true for any insn |
2034 | that we've marked with gpdisp relocs, since those have to stay in | |
2035 | 1-1 correspondence with one another. | |
2036 | ||
5910bb95 | 2037 | Technically we could copy them if we could set up a mapping from one |
2f58af60 | 2038 | sequence number to another, across the set of insns to be duplicated. |
2039 | This seems overly complicated and error-prone since interblock motion | |
b55f2ed8 | 2040 | from sched-ebb could move one of the pair of insns to a different block. |
2041 | ||
2042 | Also cannot allow jsr insns to be duplicated. If they throw exceptions, | |
2043 | then they'll be in a different block from their ldgp. Which could lead | |
2044 | the bb reorder code to think that it would be ok to copy just the block | |
2045 | containing the call and branch to the block containing the ldgp. */ | |
2f58af60 | 2046 | |
2047 | static bool | |
92643d95 | 2048 | alpha_cannot_copy_insn_p (rtx insn) |
2f58af60 | 2049 | { |
2f58af60 | 2050 | if (!reload_completed || !TARGET_EXPLICIT_RELOCS) |
2051 | return false; | |
b55f2ed8 | 2052 | if (recog_memoized (insn) >= 0) |
2053 | return get_attr_cannot_copy (insn); | |
2054 | else | |
2f58af60 | 2055 | return false; |
2f58af60 | 2056 | } |
2057 | ||
2058 | ||
0d50f0b7 | 2059 | /* Try a machine-dependent way of reloading an illegitimate address |
2060 | operand. If we find one, push the reload and return the new rtx. */ | |
2061 | ||
2062 | rtx | |
92643d95 | 2063 | alpha_legitimize_reload_address (rtx x, |
2064 | enum machine_mode mode ATTRIBUTE_UNUSED, | |
2065 | int opnum, int type, | |
2066 | int ind_levels ATTRIBUTE_UNUSED) | |
0d50f0b7 | 2067 | { |
2068 | /* We must recognize output that we have already generated ourselves. */ | |
2069 | if (GET_CODE (x) == PLUS | |
2070 | && GET_CODE (XEXP (x, 0)) == PLUS | |
2071 | && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG | |
2072 | && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT | |
2073 | && GET_CODE (XEXP (x, 1)) == CONST_INT) | |
2074 | { | |
2075 | push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, | |
2076 | BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, | |
2077 | opnum, type); | |
2078 | return x; | |
2079 | } | |
2080 | ||
2081 | /* We wish to handle large displacements off a base register by | |
2082 | splitting the addend across an ldah and the mem insn. This | |
2083 | cuts number of extra insns needed from 3 to 1. */ | |
2084 | if (GET_CODE (x) == PLUS | |
2085 | && GET_CODE (XEXP (x, 0)) == REG | |
2086 | && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER | |
2087 | && REGNO_OK_FOR_BASE_P (REGNO (XEXP (x, 0))) | |
2088 | && GET_CODE (XEXP (x, 1)) == CONST_INT) | |
2089 | { | |
2090 | HOST_WIDE_INT val = INTVAL (XEXP (x, 1)); | |
2091 | HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000; | |
2092 | HOST_WIDE_INT high | |
2093 | = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
2094 | ||
2095 | /* Check for 32-bit overflow. */ | |
2096 | if (high + low != val) | |
2097 | return NULL_RTX; | |
2098 | ||
2099 | /* Reload the high part into a base reg; leave the low part | |
2100 | in the mem directly. */ | |
2101 | x = gen_rtx_PLUS (GET_MODE (x), | |
2102 | gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0), | |
2103 | GEN_INT (high)), | |
2104 | GEN_INT (low)); | |
2105 | ||
2106 | push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, | |
2107 | BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, | |
2108 | opnum, type); | |
2109 | return x; | |
2110 | } | |
2111 | ||
2112 | return NULL_RTX; | |
2113 | } | |
2114 | \f | |
fab7adbf | 2115 | /* Compute a (partial) cost for rtx X. Return true if the complete |
2116 | cost has been computed, and false if subexpressions should be | |
2117 | scanned. In either case, *TOTAL contains the cost result. */ | |
2118 | ||
2119 | static bool | |
92643d95 | 2120 | alpha_rtx_costs (rtx x, int code, int outer_code, int *total) |
fab7adbf | 2121 | { |
2122 | enum machine_mode mode = GET_MODE (x); | |
2123 | bool float_mode_p = FLOAT_MODE_P (mode); | |
d7cf2331 | 2124 | const struct alpha_rtx_cost_data *cost_data; |
2125 | ||
2126 | if (optimize_size) | |
2127 | cost_data = &alpha_rtx_cost_size; | |
2128 | else | |
2129 | cost_data = &alpha_rtx_cost_data[alpha_cpu]; | |
fab7adbf | 2130 | |
2131 | switch (code) | |
2132 | { | |
d7cf2331 | 2133 | case CONST_INT: |
fab7adbf | 2134 | /* If this is an 8-bit constant, return zero since it can be used |
2135 | nearly anywhere with no cost. If it is a valid operand for an | |
2136 | ADD or AND, likewise return 0 if we know it will be used in that | |
2137 | context. Otherwise, return 2 since it might be used there later. | |
2138 | All other constants take at least two insns. */ | |
fab7adbf | 2139 | if (INTVAL (x) >= 0 && INTVAL (x) < 256) |
2140 | { | |
2141 | *total = 0; | |
2142 | return true; | |
2143 | } | |
8e262b5e | 2144 | /* FALLTHRU */ |
fab7adbf | 2145 | |
2146 | case CONST_DOUBLE: | |
2147 | if (x == CONST0_RTX (mode)) | |
2148 | *total = 0; | |
2149 | else if ((outer_code == PLUS && add_operand (x, VOIDmode)) | |
2150 | || (outer_code == AND && and_operand (x, VOIDmode))) | |
2151 | *total = 0; | |
2152 | else if (add_operand (x, VOIDmode) || and_operand (x, VOIDmode)) | |
2153 | *total = 2; | |
2154 | else | |
2155 | *total = COSTS_N_INSNS (2); | |
2156 | return true; | |
2157 | ||
2158 | case CONST: | |
2159 | case SYMBOL_REF: | |
2160 | case LABEL_REF: | |
2161 | if (TARGET_EXPLICIT_RELOCS && small_symbolic_operand (x, VOIDmode)) | |
2162 | *total = COSTS_N_INSNS (outer_code != MEM); | |
2163 | else if (TARGET_EXPLICIT_RELOCS && local_symbolic_operand (x, VOIDmode)) | |
2164 | *total = COSTS_N_INSNS (1 + (outer_code != MEM)); | |
2165 | else if (tls_symbolic_operand_type (x)) | |
2166 | /* Estimate of cost for call_pal rduniq. */ | |
d7cf2331 | 2167 | /* ??? How many insns do we emit here? More than one... */ |
fab7adbf | 2168 | *total = COSTS_N_INSNS (15); |
2169 | else | |
2170 | /* Otherwise we do a load from the GOT. */ | |
d7cf2331 | 2171 | *total = COSTS_N_INSNS (optimize_size ? 1 : alpha_memory_latency); |
fab7adbf | 2172 | return true; |
2173 | ||
2174 | case PLUS: | |
2175 | case MINUS: | |
2176 | if (float_mode_p) | |
d7cf2331 | 2177 | *total = cost_data->fp_add; |
fab7adbf | 2178 | else if (GET_CODE (XEXP (x, 0)) == MULT |
2179 | && const48_operand (XEXP (XEXP (x, 0), 1), VOIDmode)) | |
2180 | { | |
2181 | *total = (rtx_cost (XEXP (XEXP (x, 0), 0), outer_code) | |
be8c6d9c | 2182 | + rtx_cost (XEXP (x, 1), outer_code) + COSTS_N_INSNS (1)); |
fab7adbf | 2183 | return true; |
2184 | } | |
2185 | return false; | |
2186 | ||
2187 | case MULT: | |
2188 | if (float_mode_p) | |
d7cf2331 | 2189 | *total = cost_data->fp_mult; |
fab7adbf | 2190 | else if (mode == DImode) |
d7cf2331 | 2191 | *total = cost_data->int_mult_di; |
fab7adbf | 2192 | else |
d7cf2331 | 2193 | *total = cost_data->int_mult_si; |
fab7adbf | 2194 | return false; |
2195 | ||
2196 | case ASHIFT: | |
2197 | if (GET_CODE (XEXP (x, 1)) == CONST_INT | |
2198 | && INTVAL (XEXP (x, 1)) <= 3) | |
2199 | { | |
2200 | *total = COSTS_N_INSNS (1); | |
2201 | return false; | |
2202 | } | |
8e262b5e | 2203 | /* FALLTHRU */ |
fab7adbf | 2204 | |
2205 | case ASHIFTRT: | |
2206 | case LSHIFTRT: | |
d7cf2331 | 2207 | *total = cost_data->int_shift; |
fab7adbf | 2208 | return false; |
2209 | ||
2210 | case IF_THEN_ELSE: | |
2211 | if (float_mode_p) | |
d7cf2331 | 2212 | *total = cost_data->fp_add; |
fab7adbf | 2213 | else |
d7cf2331 | 2214 | *total = cost_data->int_cmov; |
fab7adbf | 2215 | return false; |
2216 | ||
2217 | case DIV: | |
2218 | case UDIV: | |
2219 | case MOD: | |
2220 | case UMOD: | |
2221 | if (!float_mode_p) | |
d7cf2331 | 2222 | *total = cost_data->int_div; |
fab7adbf | 2223 | else if (mode == SFmode) |
d7cf2331 | 2224 | *total = cost_data->fp_div_sf; |
fab7adbf | 2225 | else |
d7cf2331 | 2226 | *total = cost_data->fp_div_df; |
fab7adbf | 2227 | return false; |
2228 | ||
2229 | case MEM: | |
d7cf2331 | 2230 | *total = COSTS_N_INSNS (optimize_size ? 1 : alpha_memory_latency); |
fab7adbf | 2231 | return true; |
2232 | ||
2233 | case NEG: | |
2234 | if (! float_mode_p) | |
2235 | { | |
2236 | *total = COSTS_N_INSNS (1); | |
2237 | return false; | |
2238 | } | |
8e262b5e | 2239 | /* FALLTHRU */ |
fab7adbf | 2240 | |
2241 | case ABS: | |
2242 | if (! float_mode_p) | |
2243 | { | |
d7cf2331 | 2244 | *total = COSTS_N_INSNS (1) + cost_data->int_cmov; |
fab7adbf | 2245 | return false; |
2246 | } | |
8e262b5e | 2247 | /* FALLTHRU */ |
fab7adbf | 2248 | |
2249 | case FLOAT: | |
2250 | case UNSIGNED_FLOAT: | |
2251 | case FIX: | |
2252 | case UNSIGNED_FIX: | |
2253 | case FLOAT_EXTEND: | |
2254 | case FLOAT_TRUNCATE: | |
d7cf2331 | 2255 | *total = cost_data->fp_add; |
fab7adbf | 2256 | return false; |
2257 | ||
2258 | default: | |
2259 | return false; | |
2260 | } | |
2261 | } | |
2262 | \f | |
bf2a98b3 | 2263 | /* REF is an alignable memory location. Place an aligned SImode |
2264 | reference into *PALIGNED_MEM and the number of bits to shift into | |
a99a652b | 2265 | *PBITNUM. SCRATCH is a free register for use in reloading out |
2266 | of range stack slots. */ | |
bf2a98b3 | 2267 | |
2268 | void | |
92643d95 | 2269 | get_aligned_mem (rtx ref, rtx *paligned_mem, rtx *pbitnum) |
bf2a98b3 | 2270 | { |
2271 | rtx base; | |
2272 | HOST_WIDE_INT offset = 0; | |
2273 | ||
cc215844 | 2274 | if (GET_CODE (ref) != MEM) |
2275 | abort (); | |
bf2a98b3 | 2276 | |
cc215844 | 2277 | if (reload_in_progress |
2278 | && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0))) | |
a99a652b | 2279 | { |
cc215844 | 2280 | base = find_replacement (&XEXP (ref, 0)); |
2281 | ||
2282 | if (! memory_address_p (GET_MODE (ref), base)) | |
2283 | abort (); | |
a99a652b | 2284 | } |
bf2a98b3 | 2285 | else |
a99a652b | 2286 | { |
a99a652b | 2287 | base = XEXP (ref, 0); |
2288 | } | |
bf2a98b3 | 2289 | |
2290 | if (GET_CODE (base) == PLUS) | |
2291 | offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0); | |
2292 | ||
8259ab07 | 2293 | *paligned_mem |
2294 | = widen_memory_access (ref, SImode, (offset & ~3) - offset); | |
bf2a98b3 | 2295 | |
9caef960 | 2296 | if (WORDS_BIG_ENDIAN) |
2297 | *pbitnum = GEN_INT (32 - (GET_MODE_BITSIZE (GET_MODE (ref)) | |
2298 | + (offset & 3) * 8)); | |
2299 | else | |
2300 | *pbitnum = GEN_INT ((offset & 3) * 8); | |
bf2a98b3 | 2301 | } |
2302 | ||
b044f41c | 2303 | /* Similar, but just get the address. Handle the two reload cases. |
2304 | Add EXTRA_OFFSET to the address we return. */ | |
bf2a98b3 | 2305 | |
2306 | rtx | |
92643d95 | 2307 | get_unaligned_address (rtx ref, int extra_offset) |
bf2a98b3 | 2308 | { |
2309 | rtx base; | |
2310 | HOST_WIDE_INT offset = 0; | |
2311 | ||
cc215844 | 2312 | if (GET_CODE (ref) != MEM) |
2313 | abort (); | |
bf2a98b3 | 2314 | |
cc215844 | 2315 | if (reload_in_progress |
2316 | && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0))) | |
a99a652b | 2317 | { |
a99a652b | 2318 | base = find_replacement (&XEXP (ref, 0)); |
cc215844 | 2319 | |
2320 | if (! memory_address_p (GET_MODE (ref), base)) | |
2321 | abort (); | |
a99a652b | 2322 | } |
bf2a98b3 | 2323 | else |
a99a652b | 2324 | { |
a99a652b | 2325 | base = XEXP (ref, 0); |
2326 | } | |
bf2a98b3 | 2327 | |
2328 | if (GET_CODE (base) == PLUS) | |
2329 | offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0); | |
2330 | ||
b044f41c | 2331 | return plus_constant (base, offset + extra_offset); |
bf2a98b3 | 2332 | } |
14f7bc98 | 2333 | |
f5a60074 | 2334 | /* On the Alpha, all (non-symbolic) constants except zero go into |
2335 | a floating-point register via memory. Note that we cannot | |
2336 | return anything that is not a subset of CLASS, and that some | |
2337 | symbolic constants cannot be dropped to memory. */ | |
2338 | ||
2339 | enum reg_class | |
92643d95 | 2340 | alpha_preferred_reload_class(rtx x, enum reg_class class) |
f5a60074 | 2341 | { |
2342 | /* Zero is present in any register class. */ | |
2343 | if (x == CONST0_RTX (GET_MODE (x))) | |
2344 | return class; | |
2345 | ||
2346 | /* These sorts of constants we can easily drop to memory. */ | |
2347 | if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) | |
2348 | { | |
2349 | if (class == FLOAT_REGS) | |
2350 | return NO_REGS; | |
2351 | if (class == ALL_REGS) | |
2352 | return GENERAL_REGS; | |
2353 | return class; | |
2354 | } | |
2355 | ||
2356 | /* All other kinds of constants should not (and in the case of HIGH | |
2357 | cannot) be dropped to memory -- instead we use a GENERAL_REGS | |
2358 | secondary reload. */ | |
2359 | if (CONSTANT_P (x)) | |
2360 | return (class == ALL_REGS ? GENERAL_REGS : class); | |
2361 | ||
2362 | return class; | |
2363 | } | |
2364 | ||
14f7bc98 | 2365 | /* Loading and storing HImode or QImode values to and from memory |
2366 | usually requires a scratch register. The exceptions are loading | |
2367 | QImode and HImode from an aligned address to a general register | |
2368 | unless byte instructions are permitted. | |
2369 | ||
2370 | We also cannot load an unaligned address or a paradoxical SUBREG | |
2371 | into an FP register. | |
2372 | ||
2373 | We also cannot do integral arithmetic into FP regs, as might result | |
2374 | from register elimination into a DImode fp register. */ | |
2375 | ||
2376 | enum reg_class | |
92643d95 | 2377 | secondary_reload_class (enum reg_class class, enum machine_mode mode, |
2378 | rtx x, int in) | |
14f7bc98 | 2379 | { |
d60e9bbd | 2380 | if ((mode == QImode || mode == HImode) && ! TARGET_BWX) |
d2494d49 | 2381 | { |
d60e9bbd | 2382 | if (GET_CODE (x) == MEM |
2383 | || (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) | |
2384 | || (GET_CODE (x) == SUBREG | |
2385 | && (GET_CODE (SUBREG_REG (x)) == MEM | |
2386 | || (GET_CODE (SUBREG_REG (x)) == REG | |
2387 | && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)))) | |
d2494d49 | 2388 | { |
2389 | if (!in || !aligned_memory_operand(x, mode)) | |
2390 | return GENERAL_REGS; | |
2391 | } | |
2392 | } | |
14f7bc98 | 2393 | |
2394 | if (class == FLOAT_REGS) | |
2395 | { | |
2396 | if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == AND) | |
2397 | return GENERAL_REGS; | |
2398 | ||
2399 | if (GET_CODE (x) == SUBREG | |
2400 | && (GET_MODE_SIZE (GET_MODE (x)) | |
2401 | > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) | |
2402 | return GENERAL_REGS; | |
2403 | ||
1f0ce6a6 | 2404 | if (in && INTEGRAL_MODE_P (mode) |
2405 | && ! (memory_operand (x, mode) || x == const0_rtx)) | |
14f7bc98 | 2406 | return GENERAL_REGS; |
2407 | } | |
2408 | ||
2409 | return NO_REGS; | |
2410 | } | |
bf2a98b3 | 2411 | \f |
2412 | /* Subfunction of the following function. Update the flags of any MEM | |
2413 | found in part of X. */ | |
2414 | ||
2415 | static void | |
92643d95 | 2416 | alpha_set_memflags_1 (rtx x, int in_struct_p, int volatile_p, int unchanging_p) |
bf2a98b3 | 2417 | { |
2418 | int i; | |
2419 | ||
2420 | switch (GET_CODE (x)) | |
2421 | { | |
2422 | case SEQUENCE: | |
31d3e01c | 2423 | abort (); |
2424 | ||
bf2a98b3 | 2425 | case PARALLEL: |
2426 | for (i = XVECLEN (x, 0) - 1; i >= 0; i--) | |
2427 | alpha_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p, | |
e2c8a34a | 2428 | unchanging_p); |
bf2a98b3 | 2429 | break; |
2430 | ||
2431 | case INSN: | |
2432 | alpha_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p, | |
e2c8a34a | 2433 | unchanging_p); |
bf2a98b3 | 2434 | break; |
2435 | ||
2436 | case SET: | |
2437 | alpha_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p, | |
e2c8a34a | 2438 | unchanging_p); |
bf2a98b3 | 2439 | alpha_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p, |
e2c8a34a | 2440 | unchanging_p); |
bf2a98b3 | 2441 | break; |
2442 | ||
2443 | case MEM: | |
2444 | MEM_IN_STRUCT_P (x) = in_struct_p; | |
2445 | MEM_VOLATILE_P (x) = volatile_p; | |
2446 | RTX_UNCHANGING_P (x) = unchanging_p; | |
e2c8a34a | 2447 | /* Sadly, we cannot use alias sets because the extra aliasing |
2448 | produced by the AND interferes. Given that two-byte quantities | |
2449 | are the only thing we would be able to differentiate anyway, | |
2450 | there does not seem to be any point in convoluting the early | |
2451 | out of the alias check. */ | |
bf2a98b3 | 2452 | break; |
99c14947 | 2453 | |
2454 | default: | |
2455 | break; | |
bf2a98b3 | 2456 | } |
2457 | } | |
2458 | ||
31d3e01c | 2459 | /* Given INSN, which is an INSN list or the PATTERN of a single insn |
2460 | generated to perform a memory operation, look for any MEMs in either | |
2461 | a SET_DEST or a SET_SRC and copy the in-struct, unchanging, and | |
2462 | volatile flags from REF into each of the MEMs found. If REF is not | |
2463 | a MEM, don't do anything. */ | |
bf2a98b3 | 2464 | |
2465 | void | |
92643d95 | 2466 | alpha_set_memflags (rtx insn, rtx ref) |
bf2a98b3 | 2467 | { |
e2c8a34a | 2468 | int in_struct_p, volatile_p, unchanging_p; |
849674a3 | 2469 | |
2470 | if (GET_CODE (ref) != MEM) | |
bf2a98b3 | 2471 | return; |
2472 | ||
849674a3 | 2473 | in_struct_p = MEM_IN_STRUCT_P (ref); |
2474 | volatile_p = MEM_VOLATILE_P (ref); | |
2475 | unchanging_p = RTX_UNCHANGING_P (ref); | |
849674a3 | 2476 | |
2477 | /* This is only called from alpha.md, after having had something | |
2478 | generated from one of the insn patterns. So if everything is | |
2479 | zero, the pattern is already up-to-date. */ | |
e2c8a34a | 2480 | if (! in_struct_p && ! volatile_p && ! unchanging_p) |
849674a3 | 2481 | return; |
2482 | ||
e2c8a34a | 2483 | alpha_set_memflags_1 (insn, in_struct_p, volatile_p, unchanging_p); |
bf2a98b3 | 2484 | } |
2485 | \f | |
92643d95 | 2486 | /* Internal routine for alpha_emit_set_const to check for N or below insns. */ |
6f86cb15 | 2487 | |
2488 | static rtx | |
92643d95 | 2489 | alpha_emit_set_const_1 (rtx target, enum machine_mode mode, |
2490 | HOST_WIDE_INT c, int n) | |
bf2a98b3 | 2491 | { |
bdb19034 | 2492 | HOST_WIDE_INT new; |
bf2a98b3 | 2493 | int i, bits; |
ea5db00c | 2494 | /* Use a pseudo if highly optimizing and still generating RTL. */ |
2495 | rtx subtarget | |
d2422fc2 | 2496 | = (flag_expensive_optimizations && !no_new_pseudos ? 0 : target); |
301416af | 2497 | rtx temp, insn; |
bf2a98b3 | 2498 | |
bf2a98b3 | 2499 | /* If this is a sign-extended 32-bit constant, we can do this in at most |
2500 | three insns, so do it if we have enough insns left. We always have | |
65abff06 | 2501 | a sign-extended 32-bit constant when compiling on a narrow machine. */ |
bf2a98b3 | 2502 | |
3bc2043a | 2503 | if (HOST_BITS_PER_WIDE_INT != 64 |
2504 | || c >> 31 == -1 || c >> 31 == 0) | |
bf2a98b3 | 2505 | { |
bdb19034 | 2506 | HOST_WIDE_INT low = ((c & 0xffff) ^ 0x8000) - 0x8000; |
bf2a98b3 | 2507 | HOST_WIDE_INT tmp1 = c - low; |
bdb19034 | 2508 | HOST_WIDE_INT high = (((tmp1 >> 16) & 0xffff) ^ 0x8000) - 0x8000; |
bf2a98b3 | 2509 | HOST_WIDE_INT extra = 0; |
2510 | ||
81d03ebd | 2511 | /* If HIGH will be interpreted as negative but the constant is |
2512 | positive, we must adjust it to do two ldha insns. */ | |
2513 | ||
2514 | if ((high & 0x8000) != 0 && c >= 0) | |
bf2a98b3 | 2515 | { |
2516 | extra = 0x4000; | |
2517 | tmp1 -= 0x40000000; | |
2518 | high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); | |
2519 | } | |
2520 | ||
2521 | if (c == low || (low == 0 && extra == 0)) | |
3bc2043a | 2522 | { |
2523 | /* We used to use copy_to_suggested_reg (GEN_INT (c), target, mode) | |
2524 | but that meant that we can't handle INT_MIN on 32-bit machines | |
2525 | (like NT/Alpha), because we recurse indefinitely through | |
2526 | emit_move_insn to gen_movdi. So instead, since we know exactly | |
2527 | what we want, create it explicitly. */ | |
2528 | ||
2529 | if (target == NULL) | |
2530 | target = gen_reg_rtx (mode); | |
941522d6 | 2531 | emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (c))); |
3bc2043a | 2532 | return target; |
2533 | } | |
6f86cb15 | 2534 | else if (n >= 2 + (extra != 0)) |
bf2a98b3 | 2535 | { |
5b952578 | 2536 | if (no_new_pseudos) |
2537 | { | |
2538 | emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (high << 16))); | |
2539 | temp = target; | |
2540 | } | |
2541 | else | |
2542 | temp = copy_to_suggested_reg (GEN_INT (high << 16), | |
2543 | subtarget, mode); | |
ea5db00c | 2544 | |
301416af | 2545 | /* As of 2002-02-23, addsi3 is only available when not optimizing. |
2546 | This means that if we go through expand_binop, we'll try to | |
2547 | generate extensions, etc, which will require new pseudos, which | |
2548 | will fail during some split phases. The SImode add patterns | |
2549 | still exist, but are not named. So build the insns by hand. */ | |
2550 | ||
bf2a98b3 | 2551 | if (extra != 0) |
301416af | 2552 | { |
2553 | if (! subtarget) | |
2554 | subtarget = gen_reg_rtx (mode); | |
2555 | insn = gen_rtx_PLUS (mode, temp, GEN_INT (extra << 16)); | |
2556 | insn = gen_rtx_SET (VOIDmode, subtarget, insn); | |
2557 | emit_insn (insn); | |
b8585446 | 2558 | temp = subtarget; |
301416af | 2559 | } |
bf2a98b3 | 2560 | |
301416af | 2561 | if (target == NULL) |
2562 | target = gen_reg_rtx (mode); | |
2563 | insn = gen_rtx_PLUS (mode, temp, GEN_INT (low)); | |
2564 | insn = gen_rtx_SET (VOIDmode, target, insn); | |
2565 | emit_insn (insn); | |
2566 | return target; | |
bf2a98b3 | 2567 | } |
2568 | } | |
2569 | ||
dacd345b | 2570 | /* If we couldn't do it that way, try some other methods. But if we have |
07014ed9 | 2571 | no instructions left, don't bother. Likewise, if this is SImode and |
2572 | we can't make pseudos, we can't do anything since the expand_binop | |
2573 | and expand_unop calls will widen and try to make pseudos. */ | |
bf2a98b3 | 2574 | |
d2422fc2 | 2575 | if (n == 1 || (mode == SImode && no_new_pseudos)) |
bf2a98b3 | 2576 | return 0; |
2577 | ||
dacd345b | 2578 | /* Next, see if we can load a related constant and then shift and possibly |
bf2a98b3 | 2579 | negate it to get the constant we want. Try this once each increasing |
2580 | numbers of insns. */ | |
2581 | ||
2582 | for (i = 1; i < n; i++) | |
2583 | { | |
bdb19034 | 2584 | /* First, see if minus some low bits, we've an easy load of |
2585 | high bits. */ | |
2586 | ||
2587 | new = ((c & 0xffff) ^ 0x8000) - 0x8000; | |
2588 | if (new != 0 | |
2589 | && (temp = alpha_emit_set_const (subtarget, mode, c - new, i)) != 0) | |
2590 | return expand_binop (mode, add_optab, temp, GEN_INT (new), | |
2591 | target, 0, OPTAB_WIDEN); | |
2592 | ||
2593 | /* Next try complementing. */ | |
ea5db00c | 2594 | if ((temp = alpha_emit_set_const (subtarget, mode, ~ c, i)) != 0) |
2595 | return expand_unop (mode, one_cmpl_optab, temp, target, 0); | |
bf2a98b3 | 2596 | |
ea5db00c | 2597 | /* Next try to form a constant and do a left shift. We can do this |
bf2a98b3 | 2598 | if some low-order bits are zero; the exact_log2 call below tells |
2599 | us that information. The bits we are shifting out could be any | |
2600 | value, but here we'll just try the 0- and sign-extended forms of | |
2601 | the constant. To try to increase the chance of having the same | |
2602 | constant in more than one insn, start at the highest number of | |
2603 | bits to shift, but try all possibilities in case a ZAPNOT will | |
2604 | be useful. */ | |
2605 | ||
2606 | if ((bits = exact_log2 (c & - c)) > 0) | |
2607 | for (; bits > 0; bits--) | |
dacd345b | 2608 | if ((temp = (alpha_emit_set_const |
bdb19034 | 2609 | (subtarget, mode, c >> bits, i))) != 0 |
ea5db00c | 2610 | || ((temp = (alpha_emit_set_const |
2611 | (subtarget, mode, | |
2612 | ((unsigned HOST_WIDE_INT) c) >> bits, i))) | |
2613 | != 0)) | |
2614 | return expand_binop (mode, ashl_optab, temp, GEN_INT (bits), | |
2615 | target, 0, OPTAB_WIDEN); | |
bf2a98b3 | 2616 | |
2617 | /* Now try high-order zero bits. Here we try the shifted-in bits as | |
066efb8d | 2618 | all zero and all ones. Be careful to avoid shifting outside the |
2619 | mode and to avoid shifting outside the host wide int size. */ | |
3bc2043a | 2620 | /* On narrow hosts, don't shift a 1 into the high bit, since we'll |
2621 | confuse the recursive call and set all of the high 32 bits. */ | |
bf2a98b3 | 2622 | |
066efb8d | 2623 | if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) |
3bc2043a | 2624 | - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64))) > 0) |
bf2a98b3 | 2625 | for (; bits > 0; bits--) |
ea5db00c | 2626 | if ((temp = alpha_emit_set_const (subtarget, mode, |
2627 | c << bits, i)) != 0 | |
2628 | || ((temp = (alpha_emit_set_const | |
2629 | (subtarget, mode, | |
2630 | ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)), | |
2631 | i))) | |
2632 | != 0)) | |
2633 | return expand_binop (mode, lshr_optab, temp, GEN_INT (bits), | |
066efb8d | 2634 | target, 1, OPTAB_WIDEN); |
bf2a98b3 | 2635 | |
2636 | /* Now try high-order 1 bits. We get that with a sign-extension. | |
066efb8d | 2637 | But one bit isn't enough here. Be careful to avoid shifting outside |
65abff06 | 2638 | the mode and to avoid shifting outside the host wide int size. */ |
9caef960 | 2639 | |
066efb8d | 2640 | if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) |
2641 | - floor_log2 (~ c) - 2)) > 0) | |
bf2a98b3 | 2642 | for (; bits > 0; bits--) |
ea5db00c | 2643 | if ((temp = alpha_emit_set_const (subtarget, mode, |
2644 | c << bits, i)) != 0 | |
2645 | || ((temp = (alpha_emit_set_const | |
2646 | (subtarget, mode, | |
2647 | ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)), | |
2648 | i))) | |
2649 | != 0)) | |
2650 | return expand_binop (mode, ashr_optab, temp, GEN_INT (bits), | |
2651 | target, 0, OPTAB_WIDEN); | |
bf2a98b3 | 2652 | } |
2653 | ||
bdb19034 | 2654 | #if HOST_BITS_PER_WIDE_INT == 64 |
2655 | /* Finally, see if can load a value into the target that is the same as the | |
2656 | constant except that all bytes that are 0 are changed to be 0xff. If we | |
2657 | can, then we can do a ZAPNOT to obtain the desired constant. */ | |
2658 | ||
2659 | new = c; | |
2660 | for (i = 0; i < 64; i += 8) | |
2661 | if ((new & ((HOST_WIDE_INT) 0xff << i)) == 0) | |
2662 | new |= (HOST_WIDE_INT) 0xff << i; | |
e52799e9 | 2663 | |
bdb19034 | 2664 | /* We are only called for SImode and DImode. If this is SImode, ensure that |
2665 | we are sign extended to a full word. */ | |
2666 | ||
2667 | if (mode == SImode) | |
2668 | new = ((new & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
2669 | ||
2670 | if (new != c && new != -1 | |
2671 | && (temp = alpha_emit_set_const (subtarget, mode, new, n - 1)) != 0) | |
2672 | return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new), | |
e52799e9 | 2673 | target, 0, OPTAB_WIDEN); |
bdb19034 | 2674 | #endif |
e52799e9 | 2675 | |
bf2a98b3 | 2676 | return 0; |
2677 | } | |
996a379d | 2678 | |
92643d95 | 2679 | /* Try to output insns to set TARGET equal to the constant C if it can be |
2680 | done in less than N insns. Do all computations in MODE. Returns the place | |
2681 | where the output has been placed if it can be done and the insns have been | |
2682 | emitted. If it would take more than N insns, zero is returned and no | |
2683 | insns and emitted. */ | |
2684 | ||
2685 | rtx | |
2686 | alpha_emit_set_const (rtx target, enum machine_mode mode, | |
2687 | HOST_WIDE_INT c, int n) | |
2688 | { | |
2689 | rtx result = 0; | |
2690 | rtx orig_target = target; | |
2691 | int i; | |
2692 | ||
2693 | /* If we can't make any pseudos, TARGET is an SImode hard register, we | |
2694 | can't load this constant in one insn, do this in DImode. */ | |
2695 | if (no_new_pseudos && mode == SImode | |
2696 | && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER | |
2697 | && (result = alpha_emit_set_const_1 (target, mode, c, 1)) == 0) | |
2698 | { | |
2699 | target = gen_lowpart (DImode, target); | |
2700 | mode = DImode; | |
2701 | } | |
2702 | ||
2703 | /* Try 1 insn, then 2, then up to N. */ | |
2704 | for (i = 1; i <= n; i++) | |
2705 | { | |
2706 | result = alpha_emit_set_const_1 (target, mode, c, i); | |
2707 | if (result) | |
2708 | { | |
2709 | rtx insn = get_last_insn (); | |
2710 | rtx set = single_set (insn); | |
2711 | if (! CONSTANT_P (SET_SRC (set))) | |
2712 | set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c)); | |
2713 | break; | |
2714 | } | |
2715 | } | |
2716 | ||
2717 | /* Allow for the case where we changed the mode of TARGET. */ | |
2718 | if (result == target) | |
2719 | result = orig_target; | |
2720 | ||
2721 | return result; | |
2722 | } | |
2723 | ||
2612f626 | 2724 | /* Having failed to find a 3 insn sequence in alpha_emit_set_const, |
2725 | fall back to a straight forward decomposition. We do this to avoid | |
2726 | exponential run times encountered when looking for longer sequences | |
2727 | with alpha_emit_set_const. */ | |
2728 | ||
2729 | rtx | |
92643d95 | 2730 | alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2) |
2612f626 | 2731 | { |
2612f626 | 2732 | HOST_WIDE_INT d1, d2, d3, d4; |
2612f626 | 2733 | |
2734 | /* Decompose the entire word */ | |
af792316 | 2735 | #if HOST_BITS_PER_WIDE_INT >= 64 |
2736 | if (c2 != -(c1 < 0)) | |
2737 | abort (); | |
2738 | d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000; | |
2739 | c1 -= d1; | |
2740 | d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
2741 | c1 = (c1 - d2) >> 32; | |
2742 | d3 = ((c1 & 0xffff) ^ 0x8000) - 0x8000; | |
2743 | c1 -= d3; | |
2744 | d4 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
2745 | if (c1 != d4) | |
2746 | abort (); | |
2747 | #else | |
2748 | d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000; | |
2749 | c1 -= d1; | |
2750 | d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
2751 | if (c1 != d2) | |
2752 | abort (); | |
2753 | c2 += (d2 < 0); | |
2754 | d3 = ((c2 & 0xffff) ^ 0x8000) - 0x8000; | |
2755 | c2 -= d3; | |
2756 | d4 = ((c2 & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
2757 | if (c2 != d4) | |
2758 | abort (); | |
2759 | #endif | |
2612f626 | 2760 | |
2761 | /* Construct the high word */ | |
af792316 | 2762 | if (d4) |
2763 | { | |
2764 | emit_move_insn (target, GEN_INT (d4)); | |
2765 | if (d3) | |
2766 | emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d3))); | |
2767 | } | |
2612f626 | 2768 | else |
af792316 | 2769 | emit_move_insn (target, GEN_INT (d3)); |
2612f626 | 2770 | |
2771 | /* Shift it into place */ | |
af792316 | 2772 | emit_move_insn (target, gen_rtx_ASHIFT (DImode, target, GEN_INT (32))); |
2612f626 | 2773 | |
af792316 | 2774 | /* Add in the low bits. */ |
2775 | if (d2) | |
2776 | emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d2))); | |
2777 | if (d1) | |
2778 | emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d1))); | |
2612f626 | 2779 | |
af792316 | 2780 | return target; |
2612f626 | 2781 | } |
2612f626 | 2782 | |
cb6e3ae1 | 2783 | /* Expand a move instruction; return true if all work is done. |
2784 | We don't handle non-bwx subword loads here. */ | |
2785 | ||
2786 | bool | |
92643d95 | 2787 | alpha_expand_mov (enum machine_mode mode, rtx *operands) |
cb6e3ae1 | 2788 | { |
2789 | /* If the output is not a register, the input must be. */ | |
2790 | if (GET_CODE (operands[0]) == MEM | |
2791 | && ! reg_or_0_operand (operands[1], mode)) | |
2792 | operands[1] = force_reg (mode, operands[1]); | |
2793 | ||
f5a60074 | 2794 | /* Allow legitimize_address to perform some simplifications. */ |
62e050c6 | 2795 | if (mode == Pmode && symbolic_operand (operands[1], mode)) |
1f0ce6a6 | 2796 | { |
05b07808 | 2797 | rtx tmp; |
2798 | ||
2799 | /* With RTL inlining, at -O3, rtl is generated, stored, then actually | |
2800 | compiled at the end of compilation. In the meantime, someone can | |
2801 | re-encode-section-info on some symbol changing it e.g. from global | |
2802 | to local-not-small. If this happens, we'd have emitted a plain | |
2803 | load rather than a high+losum load and not recognize the insn. | |
2804 | ||
2805 | So if rtl inlining is in effect, we delay the global/not-global | |
2806 | decision until rest_of_compilation by wrapping it in an | |
2807 | UNSPEC_SYMBOL. */ | |
2808 | if (TARGET_EXPLICIT_RELOCS && flag_inline_functions | |
2809 | && rtx_equal_function_value_matters | |
2810 | && global_symbolic_operand (operands[1], mode)) | |
2811 | { | |
2812 | emit_insn (gen_movdi_er_maybe_g (operands[0], operands[1])); | |
2813 | return true; | |
2814 | } | |
2815 | ||
2816 | tmp = alpha_legitimize_address (operands[1], operands[0], mode); | |
f5a60074 | 2817 | if (tmp) |
5dcb037d | 2818 | { |
5f7b9df8 | 2819 | if (tmp == operands[0]) |
2820 | return true; | |
f5a60074 | 2821 | operands[1] = tmp; |
8afb6db4 | 2822 | return false; |
2823 | } | |
1f0ce6a6 | 2824 | } |
2825 | ||
cb6e3ae1 | 2826 | /* Early out for non-constants and valid constants. */ |
2827 | if (! CONSTANT_P (operands[1]) || input_operand (operands[1], mode)) | |
2828 | return false; | |
2829 | ||
2830 | /* Split large integers. */ | |
2831 | if (GET_CODE (operands[1]) == CONST_INT | |
2832 | || GET_CODE (operands[1]) == CONST_DOUBLE) | |
2833 | { | |
2834 | HOST_WIDE_INT i0, i1; | |
d1bf99d0 | 2835 | rtx temp = NULL_RTX; |
cb6e3ae1 | 2836 | |
2837 | if (GET_CODE (operands[1]) == CONST_INT) | |
2838 | { | |
2839 | i0 = INTVAL (operands[1]); | |
2840 | i1 = -(i0 < 0); | |
2841 | } | |
2842 | else if (HOST_BITS_PER_WIDE_INT >= 64) | |
2843 | { | |
2844 | i0 = CONST_DOUBLE_LOW (operands[1]); | |
2845 | i1 = -(i0 < 0); | |
2846 | } | |
2847 | else | |
2848 | { | |
2849 | i0 = CONST_DOUBLE_LOW (operands[1]); | |
2850 | i1 = CONST_DOUBLE_HIGH (operands[1]); | |
2851 | } | |
2852 | ||
2853 | if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0)) | |
2854 | temp = alpha_emit_set_const (operands[0], mode, i0, 3); | |
2855 | ||
2856 | if (!temp && TARGET_BUILD_CONSTANTS) | |
2857 | temp = alpha_emit_set_long_const (operands[0], i0, i1); | |
2858 | ||
2859 | if (temp) | |
2860 | { | |
2861 | if (rtx_equal_p (operands[0], temp)) | |
2862 | return true; | |
2863 | operands[1] = temp; | |
2864 | return false; | |
2865 | } | |
2866 | } | |
2867 | ||
2868 | /* Otherwise we've nothing left but to drop the thing to memory. */ | |
d18a1a2b | 2869 | operands[1] = force_const_mem (mode, operands[1]); |
cb6e3ae1 | 2870 | if (reload_in_progress) |
2871 | { | |
2872 | emit_move_insn (operands[0], XEXP (operands[1], 0)); | |
2873 | operands[1] = copy_rtx (operands[1]); | |
2874 | XEXP (operands[1], 0) = operands[0]; | |
2875 | } | |
2876 | else | |
2877 | operands[1] = validize_mem (operands[1]); | |
2878 | return false; | |
2879 | } | |
2880 | ||
2881 | /* Expand a non-bwx QImode or HImode move instruction; | |
2882 | return true if all work is done. */ | |
2883 | ||
2884 | bool | |
92643d95 | 2885 | alpha_expand_mov_nobwx (enum machine_mode mode, rtx *operands) |
cb6e3ae1 | 2886 | { |
2887 | /* If the output is not a register, the input must be. */ | |
2888 | if (GET_CODE (operands[0]) == MEM) | |
2889 | operands[1] = force_reg (mode, operands[1]); | |
2890 | ||
2891 | /* Handle four memory cases, unaligned and aligned for either the input | |
2892 | or the output. The only case where we can be called during reload is | |
2893 | for aligned loads; all other cases require temporaries. */ | |
2894 | ||
2895 | if (GET_CODE (operands[1]) == MEM | |
2896 | || (GET_CODE (operands[1]) == SUBREG | |
2897 | && GET_CODE (SUBREG_REG (operands[1])) == MEM) | |
2898 | || (reload_in_progress && GET_CODE (operands[1]) == REG | |
2899 | && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER) | |
2900 | || (reload_in_progress && GET_CODE (operands[1]) == SUBREG | |
2901 | && GET_CODE (SUBREG_REG (operands[1])) == REG | |
2902 | && REGNO (SUBREG_REG (operands[1])) >= FIRST_PSEUDO_REGISTER)) | |
2903 | { | |
2904 | if (aligned_memory_operand (operands[1], mode)) | |
2905 | { | |
2906 | if (reload_in_progress) | |
2907 | { | |
2908 | emit_insn ((mode == QImode | |
2909 | ? gen_reload_inqi_help | |
2910 | : gen_reload_inhi_help) | |
2911 | (operands[0], operands[1], | |
2912 | gen_rtx_REG (SImode, REGNO (operands[0])))); | |
2913 | } | |
2914 | else | |
2915 | { | |
2916 | rtx aligned_mem, bitnum; | |
2917 | rtx scratch = gen_reg_rtx (SImode); | |
d67e1866 | 2918 | rtx subtarget; |
2919 | bool copyout; | |
cb6e3ae1 | 2920 | |
2921 | get_aligned_mem (operands[1], &aligned_mem, &bitnum); | |
2922 | ||
d67e1866 | 2923 | subtarget = operands[0]; |
2924 | if (GET_CODE (subtarget) == REG) | |
2925 | subtarget = gen_lowpart (DImode, subtarget), copyout = false; | |
2926 | else | |
2927 | subtarget = gen_reg_rtx (DImode), copyout = true; | |
2928 | ||
cb6e3ae1 | 2929 | emit_insn ((mode == QImode |
2930 | ? gen_aligned_loadqi | |
2931 | : gen_aligned_loadhi) | |
d67e1866 | 2932 | (subtarget, aligned_mem, bitnum, scratch)); |
2933 | ||
2934 | if (copyout) | |
2935 | emit_move_insn (operands[0], gen_lowpart (mode, subtarget)); | |
cb6e3ae1 | 2936 | } |
2937 | } | |
2938 | else | |
2939 | { | |
2940 | /* Don't pass these as parameters since that makes the generated | |
2941 | code depend on parameter evaluation order which will cause | |
2942 | bootstrap failures. */ | |
2943 | ||
d67e1866 | 2944 | rtx temp1, temp2, seq, subtarget; |
2945 | bool copyout; | |
2946 | ||
2947 | temp1 = gen_reg_rtx (DImode); | |
2948 | temp2 = gen_reg_rtx (DImode); | |
cb6e3ae1 | 2949 | |
d67e1866 | 2950 | subtarget = operands[0]; |
2951 | if (GET_CODE (subtarget) == REG) | |
2952 | subtarget = gen_lowpart (DImode, subtarget), copyout = false; | |
2953 | else | |
2954 | subtarget = gen_reg_rtx (DImode), copyout = true; | |
2955 | ||
2956 | seq = ((mode == QImode | |
2957 | ? gen_unaligned_loadqi | |
2958 | : gen_unaligned_loadhi) | |
2959 | (subtarget, get_unaligned_address (operands[1], 0), | |
2960 | temp1, temp2)); | |
cb6e3ae1 | 2961 | alpha_set_memflags (seq, operands[1]); |
2962 | emit_insn (seq); | |
d67e1866 | 2963 | |
2964 | if (copyout) | |
2965 | emit_move_insn (operands[0], gen_lowpart (mode, subtarget)); | |
cb6e3ae1 | 2966 | } |
2967 | return true; | |
2968 | } | |
2969 | ||
2970 | if (GET_CODE (operands[0]) == MEM | |
2971 | || (GET_CODE (operands[0]) == SUBREG | |
2972 | && GET_CODE (SUBREG_REG (operands[0])) == MEM) | |
2973 | || (reload_in_progress && GET_CODE (operands[0]) == REG | |
2974 | && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER) | |
2975 | || (reload_in_progress && GET_CODE (operands[0]) == SUBREG | |
2976 | && GET_CODE (SUBREG_REG (operands[0])) == REG | |
2977 | && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)) | |
2978 | { | |
2979 | if (aligned_memory_operand (operands[0], mode)) | |
2980 | { | |
2981 | rtx aligned_mem, bitnum; | |
2982 | rtx temp1 = gen_reg_rtx (SImode); | |
2983 | rtx temp2 = gen_reg_rtx (SImode); | |
2984 | ||
2985 | get_aligned_mem (operands[0], &aligned_mem, &bitnum); | |
2986 | ||
2987 | emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum, | |
2988 | temp1, temp2)); | |
2989 | } | |
2990 | else | |
2991 | { | |
2992 | rtx temp1 = gen_reg_rtx (DImode); | |
2993 | rtx temp2 = gen_reg_rtx (DImode); | |
2994 | rtx temp3 = gen_reg_rtx (DImode); | |
2995 | rtx seq = ((mode == QImode | |
2996 | ? gen_unaligned_storeqi | |
2997 | : gen_unaligned_storehi) | |
2998 | (get_unaligned_address (operands[0], 0), | |
2999 | operands[1], temp1, temp2, temp3)); | |
3000 | ||
3001 | alpha_set_memflags (seq, operands[0]); | |
3002 | emit_insn (seq); | |
3003 | } | |
3004 | return true; | |
3005 | } | |
3006 | ||
3007 | return false; | |
3008 | } | |
3009 | ||
2a42ba09 | 3010 | /* Generate an unsigned DImode to FP conversion. This is the same code |
3011 | optabs would emit if we didn't have TFmode patterns. | |
3012 | ||
3013 | For SFmode, this is the only construction I've found that can pass | |
3014 | gcc.c-torture/execute/ieee/rbug.c. No scenario that uses DFmode | |
3015 | intermediates will work, because you'll get intermediate rounding | |
3016 | that ruins the end result. Some of this could be fixed by turning | |
3017 | on round-to-positive-infinity, but that requires diddling the fpsr, | |
3018 | which kills performance. I tried turning this around and converting | |
3019 | to a negative number, so that I could turn on /m, but either I did | |
3020 | it wrong or there's something else cause I wound up with the exact | |
3021 | same single-bit error. There is a branch-less form of this same code: | |
3022 | ||
3023 | srl $16,1,$1 | |
3024 | and $16,1,$2 | |
3025 | cmplt $16,0,$3 | |
3026 | or $1,$2,$2 | |
3027 | cmovge $16,$16,$2 | |
3028 | itoft $3,$f10 | |
3029 | itoft $2,$f11 | |
3030 | cvtqs $f11,$f11 | |
3031 | adds $f11,$f11,$f0 | |
3032 | fcmoveq $f10,$f11,$f0 | |
3033 | ||
3034 | I'm not using it because it's the same number of instructions as | |
3035 | this branch-full form, and it has more serialized long latency | |
3036 | instructions on the critical path. | |
3037 | ||
3038 | For DFmode, we can avoid rounding errors by breaking up the word | |
3039 | into two pieces, converting them separately, and adding them back: | |
3040 | ||
3041 | LC0: .long 0,0x5f800000 | |
3042 | ||
3043 | itoft $16,$f11 | |
3044 | lda $2,LC0 | |
093c0196 | 3045 | cmplt $16,0,$1 |
2a42ba09 | 3046 | cpyse $f11,$f31,$f10 |
3047 | cpyse $f31,$f11,$f11 | |
3048 | s4addq $1,$2,$1 | |
3049 | lds $f12,0($1) | |
3050 | cvtqt $f10,$f10 | |
3051 | cvtqt $f11,$f11 | |
3052 | addt $f12,$f10,$f0 | |
3053 | addt $f0,$f11,$f0 | |
3054 | ||
3055 | This doesn't seem to be a clear-cut win over the optabs form. | |
3056 | It probably all depends on the distribution of numbers being | |
3057 | converted -- in the optabs form, all but high-bit-set has a | |
3058 | much lower minimum execution time. */ | |
3059 | ||
3060 | void | |
92643d95 | 3061 | alpha_emit_floatuns (rtx operands[2]) |
2a42ba09 | 3062 | { |
3063 | rtx neglab, donelab, i0, i1, f0, in, out; | |
3064 | enum machine_mode mode; | |
3065 | ||
3066 | out = operands[0]; | |
8e2025b4 | 3067 | in = force_reg (DImode, operands[1]); |
2a42ba09 | 3068 | mode = GET_MODE (out); |
3069 | neglab = gen_label_rtx (); | |
3070 | donelab = gen_label_rtx (); | |
3071 | i0 = gen_reg_rtx (DImode); | |
3072 | i1 = gen_reg_rtx (DImode); | |
3073 | f0 = gen_reg_rtx (mode); | |
3074 | ||
7e69f45b | 3075 | emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab); |
2a42ba09 | 3076 | |
3077 | emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in))); | |
3078 | emit_jump_insn (gen_jump (donelab)); | |
093c0196 | 3079 | emit_barrier (); |
2a42ba09 | 3080 | |
3081 | emit_label (neglab); | |
3082 | ||
3083 | emit_insn (gen_lshrdi3 (i0, in, const1_rtx)); | |
3084 | emit_insn (gen_anddi3 (i1, in, const1_rtx)); | |
3085 | emit_insn (gen_iordi3 (i0, i0, i1)); | |
3086 | emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0))); | |
3087 | emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0))); | |
3088 | ||
3089 | emit_label (donelab); | |
3090 | } | |
3091 | ||
3a2a3a7f | 3092 | /* Generate the comparison for a conditional branch. */ |
3093 | ||
3094 | rtx | |
92643d95 | 3095 | alpha_emit_conditional_branch (enum rtx_code code) |
3a2a3a7f | 3096 | { |
3097 | enum rtx_code cmp_code, branch_code; | |
3098 | enum machine_mode cmp_mode, branch_mode = VOIDmode; | |
b18b881f | 3099 | rtx op0 = alpha_compare.op0, op1 = alpha_compare.op1; |
3a2a3a7f | 3100 | rtx tem; |
3101 | ||
915c336f | 3102 | if (alpha_compare.fp_p && GET_MODE (op0) == TFmode) |
3103 | { | |
3104 | if (! TARGET_HAS_XFLOATING_LIBS) | |
3105 | abort (); | |
3106 | ||
3107 | /* X_floating library comparison functions return | |
3108 | -1 unordered | |
3109 | 0 false | |
3110 | 1 true | |
3111 | Convert the compare against the raw return value. */ | |
3112 | ||
a92123e9 | 3113 | switch (code) |
3114 | { | |
3115 | case UNORDERED: | |
3116 | cmp_code = EQ; | |
3117 | code = LT; | |
3118 | break; | |
3119 | case ORDERED: | |
3120 | cmp_code = EQ; | |
3121 | code = GE; | |
3122 | break; | |
3123 | case NE: | |
3124 | cmp_code = NE; | |
3125 | code = NE; | |
3126 | break; | |
3127 | default: | |
3128 | cmp_code = code; | |
f4a6c960 | 3129 | code = GT; |
a92123e9 | 3130 | break; |
3131 | } | |
d74ce6fa | 3132 | |
3133 | op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1); | |
915c336f | 3134 | op1 = const0_rtx; |
3135 | alpha_compare.fp_p = 0; | |
915c336f | 3136 | } |
3137 | ||
3a2a3a7f | 3138 | /* The general case: fold the comparison code to the types of compares |
3139 | that we have, choosing the branch as necessary. */ | |
3140 | switch (code) | |
3141 | { | |
3142 | case EQ: case LE: case LT: case LEU: case LTU: | |
a4110d9a | 3143 | case UNORDERED: |
3a2a3a7f | 3144 | /* We have these compares: */ |
3145 | cmp_code = code, branch_code = NE; | |
3146 | break; | |
3147 | ||
3148 | case NE: | |
a4110d9a | 3149 | case ORDERED: |
65abff06 | 3150 | /* These must be reversed. */ |
a4110d9a | 3151 | cmp_code = reverse_condition (code), branch_code = EQ; |
3a2a3a7f | 3152 | break; |
3153 | ||
3154 | case GE: case GT: case GEU: case GTU: | |
3155 | /* For FP, we swap them, for INT, we reverse them. */ | |
b18b881f | 3156 | if (alpha_compare.fp_p) |
3a2a3a7f | 3157 | { |
3158 | cmp_code = swap_condition (code); | |
3159 | branch_code = NE; | |
3160 | tem = op0, op0 = op1, op1 = tem; | |
3161 | } | |
3162 | else | |
3163 | { | |
3164 | cmp_code = reverse_condition (code); | |
3165 | branch_code = EQ; | |
3166 | } | |
3167 | break; | |
3168 | ||
3169 | default: | |
3170 | abort (); | |
3171 | } | |
3172 | ||
b18b881f | 3173 | if (alpha_compare.fp_p) |
3a2a3a7f | 3174 | { |
3175 | cmp_mode = DFmode; | |
7f3be425 | 3176 | if (flag_unsafe_math_optimizations) |
3a2a3a7f | 3177 | { |
3178 | /* When we are not as concerned about non-finite values, and we | |
3179 | are comparing against zero, we can branch directly. */ | |
3180 | if (op1 == CONST0_RTX (DFmode)) | |
3181 | cmp_code = NIL, branch_code = code; | |
3182 | else if (op0 == CONST0_RTX (DFmode)) | |
3183 | { | |
3184 | /* Undo the swap we probably did just above. */ | |
3185 | tem = op0, op0 = op1, op1 = tem; | |
4899654e | 3186 | branch_code = swap_condition (cmp_code); |
3187 | cmp_code = NIL; | |
3a2a3a7f | 3188 | } |
3189 | } | |
3190 | else | |
3191 | { | |
d30e015b | 3192 | /* ??? We mark the branch mode to be CCmode to prevent the |
3a2a3a7f | 3193 | compare and branch from being combined, since the compare |
3194 | insn follows IEEE rules that the branch does not. */ | |
3195 | branch_mode = CCmode; | |
3196 | } | |
3197 | } | |
3198 | else | |
3199 | { | |
3200 | cmp_mode = DImode; | |
3201 | ||
3202 | /* The following optimizations are only for signed compares. */ | |
3203 | if (code != LEU && code != LTU && code != GEU && code != GTU) | |
3204 | { | |
3205 | /* Whee. Compare and branch against 0 directly. */ | |
3206 | if (op1 == const0_rtx) | |
3207 | cmp_code = NIL, branch_code = code; | |
3208 | ||
3a2f3420 | 3209 | /* If the constants doesn't fit into an immediate, but can |
3210 | be generated by lda/ldah, we adjust the argument and | |
3211 | compare against zero, so we can use beq/bne directly. */ | |
62350d6c | 3212 | /* ??? Don't do this when comparing against symbols, otherwise |
3213 | we'll reduce (&x == 0x1234) to (&x-0x1234 == 0), which will | |
3214 | be declared false out of hand (at least for non-weak). */ | |
3215 | else if (GET_CODE (op1) == CONST_INT | |
3216 | && (code == EQ || code == NE) | |
3217 | && !(symbolic_operand (op0, VOIDmode) | |
3218 | || (GET_CODE (op0) == REG && REG_POINTER (op0)))) | |
3a2a3a7f | 3219 | { |
3220 | HOST_WIDE_INT v = INTVAL (op1), n = -v; | |
3221 | ||
3222 | if (! CONST_OK_FOR_LETTER_P (v, 'I') | |
3223 | && (CONST_OK_FOR_LETTER_P (n, 'K') | |
3224 | || CONST_OK_FOR_LETTER_P (n, 'L'))) | |
3225 | { | |
3226 | cmp_code = PLUS, branch_code = code; | |
3227 | op1 = GEN_INT (n); | |
3228 | } | |
3229 | } | |
3230 | } | |
3a2a3a7f | 3231 | |
d74ce6fa | 3232 | if (!reg_or_0_operand (op0, DImode)) |
3233 | op0 = force_reg (DImode, op0); | |
3234 | if (cmp_code != PLUS && !reg_or_8bit_operand (op1, DImode)) | |
3235 | op1 = force_reg (DImode, op1); | |
3236 | } | |
3a2a3a7f | 3237 | |
3238 | /* Emit an initial compare instruction, if necessary. */ | |
3239 | tem = op0; | |
3240 | if (cmp_code != NIL) | |
3241 | { | |
3242 | tem = gen_reg_rtx (cmp_mode); | |
3243 | emit_move_insn (tem, gen_rtx_fmt_ee (cmp_code, cmp_mode, op0, op1)); | |
3244 | } | |
3245 | ||
b18b881f | 3246 | /* Zero the operands. */ |
3247 | memset (&alpha_compare, 0, sizeof (alpha_compare)); | |
3248 | ||
3a2a3a7f | 3249 | /* Return the branch comparison. */ |
3250 | return gen_rtx_fmt_ee (branch_code, branch_mode, tem, CONST0_RTX (cmp_mode)); | |
3251 | } | |
3252 | ||
d74ce6fa | 3253 | /* Certain simplifications can be done to make invalid setcc operations |
3254 | valid. Return the final comparison, or NULL if we can't work. */ | |
3255 | ||
3256 | rtx | |
92643d95 | 3257 | alpha_emit_setcc (enum rtx_code code) |
d74ce6fa | 3258 | { |
3259 | enum rtx_code cmp_code; | |
3260 | rtx op0 = alpha_compare.op0, op1 = alpha_compare.op1; | |
3261 | int fp_p = alpha_compare.fp_p; | |
3262 | rtx tmp; | |
3263 | ||
3264 | /* Zero the operands. */ | |
3265 | memset (&alpha_compare, 0, sizeof (alpha_compare)); | |
3266 | ||
3267 | if (fp_p && GET_MODE (op0) == TFmode) | |
3268 | { | |
3269 | if (! TARGET_HAS_XFLOATING_LIBS) | |
3270 | abort (); | |
3271 | ||
3272 | /* X_floating library comparison functions return | |
3273 | -1 unordered | |
3274 | 0 false | |
3275 | 1 true | |
3276 | Convert the compare against the raw return value. */ | |
3277 | ||
3278 | if (code == UNORDERED || code == ORDERED) | |
3279 | cmp_code = EQ; | |
3280 | else | |
3281 | cmp_code = code; | |
3282 | ||
3283 | op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1); | |
3284 | op1 = const0_rtx; | |
3285 | fp_p = 0; | |
3286 | ||
3287 | if (code == UNORDERED) | |
3288 | code = LT; | |
3289 | else if (code == ORDERED) | |
3290 | code = GE; | |
3291 | else | |
3292 | code = GT; | |
3293 | } | |
3294 | ||
3295 | if (fp_p && !TARGET_FIX) | |
3296 | return NULL_RTX; | |
3297 | ||
3298 | /* The general case: fold the comparison code to the types of compares | |
3299 | that we have, choosing the branch as necessary. */ | |
3300 | ||
3301 | cmp_code = NIL; | |
3302 | switch (code) | |
3303 | { | |
3304 | case EQ: case LE: case LT: case LEU: case LTU: | |
3305 | case UNORDERED: | |
3306 | /* We have these compares. */ | |
3307 | if (fp_p) | |
3308 | cmp_code = code, code = NE; | |
3309 | break; | |
3310 | ||
3311 | case NE: | |
3312 | if (!fp_p && op1 == const0_rtx) | |
3313 | break; | |
8e262b5e | 3314 | /* FALLTHRU */ |
d74ce6fa | 3315 | |
3316 | case ORDERED: | |
3317 | cmp_code = reverse_condition (code); | |
3318 | code = EQ; | |
3319 | break; | |
3320 | ||
3321 | case GE: case GT: case GEU: case GTU: | |
75b3314a | 3322 | /* These normally need swapping, but for integer zero we have |
bc882521 | 3323 | special patterns that recognize swapped operands. */ |
3324 | if (!fp_p && op1 == const0_rtx) | |
3325 | break; | |
d74ce6fa | 3326 | code = swap_condition (code); |
3327 | if (fp_p) | |
3328 | cmp_code = code, code = NE; | |
3329 | tmp = op0, op0 = op1, op1 = tmp; | |
3330 | break; | |
3331 | ||
3332 | default: | |
3333 | abort (); | |
3334 | } | |
3335 | ||
3336 | if (!fp_p) | |
3337 | { | |
bc882521 | 3338 | if (!register_operand (op0, DImode)) |
d74ce6fa | 3339 | op0 = force_reg (DImode, op0); |
3340 | if (!reg_or_8bit_operand (op1, DImode)) | |
3341 | op1 = force_reg (DImode, op1); | |
3342 | } | |
3343 | ||
3344 | /* Emit an initial compare instruction, if necessary. */ | |
3345 | if (cmp_code != NIL) | |
3346 | { | |
3347 | enum machine_mode mode = fp_p ? DFmode : DImode; | |
3348 | ||
3349 | tmp = gen_reg_rtx (mode); | |
3350 | emit_insn (gen_rtx_SET (VOIDmode, tmp, | |
3351 | gen_rtx_fmt_ee (cmp_code, mode, op0, op1))); | |
3352 | ||
3353 | op0 = fp_p ? gen_lowpart (DImode, tmp) : tmp; | |
3354 | op1 = const0_rtx; | |
3355 | } | |
3356 | ||
3357 | /* Return the setcc comparison. */ | |
3358 | return gen_rtx_fmt_ee (code, DImode, op0, op1); | |
3359 | } | |
3360 | ||
3a2a3a7f | 3361 | |
996a379d | 3362 | /* Rewrite a comparison against zero CMP of the form |
3363 | (CODE (cc0) (const_int 0)) so it can be written validly in | |
3364 | a conditional move (if_then_else CMP ...). | |
e3e08e7f | 3365 | If both of the operands that set cc0 are nonzero we must emit |
996a379d | 3366 | an insn to perform the compare (it can't be done within |
65abff06 | 3367 | the conditional move). */ |
92643d95 | 3368 | |
996a379d | 3369 | rtx |
92643d95 | 3370 | alpha_emit_conditional_move (rtx cmp, enum machine_mode mode) |
996a379d | 3371 | { |
23be97c5 | 3372 | enum rtx_code code = GET_CODE (cmp); |
c60bc286 | 3373 | enum rtx_code cmov_code = NE; |
b18b881f | 3374 | rtx op0 = alpha_compare.op0; |
3375 | rtx op1 = alpha_compare.op1; | |
3376 | int fp_p = alpha_compare.fp_p; | |
23be97c5 | 3377 | enum machine_mode cmp_mode |
3378 | = (GET_MODE (op0) == VOIDmode ? DImode : GET_MODE (op0)); | |
b18b881f | 3379 | enum machine_mode cmp_op_mode = fp_p ? DFmode : DImode; |
3a2a3a7f | 3380 | enum machine_mode cmov_mode = VOIDmode; |
7f3be425 | 3381 | int local_fast_math = flag_unsafe_math_optimizations; |
23be97c5 | 3382 | rtx tem; |
996a379d | 3383 | |
b18b881f | 3384 | /* Zero the operands. */ |
3385 | memset (&alpha_compare, 0, sizeof (alpha_compare)); | |
3386 | ||
3387 | if (fp_p != FLOAT_MODE_P (mode)) | |
d6cc9868 | 3388 | { |
3389 | enum rtx_code cmp_code; | |
3390 | ||
3391 | if (! TARGET_FIX) | |
3392 | return 0; | |
3393 | ||
3394 | /* If we have fp<->int register move instructions, do a cmov by | |
3395 | performing the comparison in fp registers, and move the | |
e3e08e7f | 3396 | zero/nonzero value to integer registers, where we can then |
d6cc9868 | 3397 | use a normal cmov, or vice-versa. */ |
3398 | ||
3399 | switch (code) | |
3400 | { | |
3401 | case EQ: case LE: case LT: case LEU: case LTU: | |
3402 | /* We have these compares. */ | |
3403 | cmp_code = code, code = NE; | |
3404 | break; | |
3405 | ||
3406 | case NE: | |
3407 | /* This must be reversed. */ | |
3408 | cmp_code = EQ, code = EQ; | |
3409 | break; | |
3410 | ||
3411 | case GE: case GT: case GEU: case GTU: | |
75b3314a | 3412 | /* These normally need swapping, but for integer zero we have |
3413 | special patterns that recognize swapped operands. */ | |
3414 | if (!fp_p && op1 == const0_rtx) | |
88f8f2a2 | 3415 | cmp_code = code, code = NE; |
3416 | else | |
3417 | { | |
3418 | cmp_code = swap_condition (code); | |
3419 | code = NE; | |
3420 | tem = op0, op0 = op1, op1 = tem; | |
3421 | } | |
d6cc9868 | 3422 | break; |
3423 | ||
3424 | default: | |
3425 | abort (); | |
3426 | } | |
3427 | ||
3428 | tem = gen_reg_rtx (cmp_op_mode); | |
3429 | emit_insn (gen_rtx_SET (VOIDmode, tem, | |
3430 | gen_rtx_fmt_ee (cmp_code, cmp_op_mode, | |
3431 | op0, op1))); | |
3432 | ||
3433 | cmp_mode = cmp_op_mode = fp_p ? DImode : DFmode; | |
3434 | op0 = gen_lowpart (cmp_op_mode, tem); | |
3435 | op1 = CONST0_RTX (cmp_op_mode); | |
3436 | fp_p = !fp_p; | |
3437 | local_fast_math = 1; | |
3438 | } | |
996a379d | 3439 | |
3440 | /* We may be able to use a conditional move directly. | |
65abff06 | 3441 | This avoids emitting spurious compares. */ |
2a42ba09 | 3442 | if (signed_comparison_operator (cmp, VOIDmode) |
d6cc9868 | 3443 | && (!fp_p || local_fast_math) |
23be97c5 | 3444 | && (op0 == CONST0_RTX (cmp_mode) || op1 == CONST0_RTX (cmp_mode))) |
941522d6 | 3445 | return gen_rtx_fmt_ee (code, VOIDmode, op0, op1); |
996a379d | 3446 | |
3029ee00 | 3447 | /* We can't put the comparison inside the conditional move; |
996a379d | 3448 | emit a compare instruction and put that inside the |
23be97c5 | 3449 | conditional move. Make sure we emit only comparisons we have; |
3450 | swap or reverse as necessary. */ | |
996a379d | 3451 | |
3029ee00 | 3452 | if (no_new_pseudos) |
3453 | return NULL_RTX; | |
3454 | ||
996a379d | 3455 | switch (code) |
3456 | { | |
23be97c5 | 3457 | case EQ: case LE: case LT: case LEU: case LTU: |
3458 | /* We have these compares: */ | |
996a379d | 3459 | break; |
23be97c5 | 3460 | |
996a379d | 3461 | case NE: |
65abff06 | 3462 | /* This must be reversed. */ |
23be97c5 | 3463 | code = reverse_condition (code); |
c60bc286 | 3464 | cmov_code = EQ; |
996a379d | 3465 | break; |
23be97c5 | 3466 | |
3467 | case GE: case GT: case GEU: case GTU: | |
d74ce6fa | 3468 | /* These must be swapped. */ |
88f8f2a2 | 3469 | if (op1 != CONST0_RTX (cmp_mode)) |
3470 | { | |
3471 | code = swap_condition (code); | |
3472 | tem = op0, op0 = op1, op1 = tem; | |
3473 | } | |
996a379d | 3474 | break; |
23be97c5 | 3475 | |
996a379d | 3476 | default: |
23be97c5 | 3477 | abort (); |
996a379d | 3478 | } |
3479 | ||
d74ce6fa | 3480 | if (!fp_p) |
3481 | { | |
3482 | if (!reg_or_0_operand (op0, DImode)) | |
3483 | op0 = force_reg (DImode, op0); | |
3484 | if (!reg_or_8bit_operand (op1, DImode)) | |
3485 | op1 = force_reg (DImode, op1); | |
3486 | } | |
3487 | ||
b9b4428b | 3488 | /* ??? We mark the branch mode to be CCmode to prevent the compare |
3a2a3a7f | 3489 | and cmov from being combined, since the compare insn follows IEEE |
3490 | rules that the cmov does not. */ | |
d6cc9868 | 3491 | if (fp_p && !local_fast_math) |
3a2a3a7f | 3492 | cmov_mode = CCmode; |
3493 | ||
23be97c5 | 3494 | tem = gen_reg_rtx (cmp_op_mode); |
941522d6 | 3495 | emit_move_insn (tem, gen_rtx_fmt_ee (code, cmp_op_mode, op0, op1)); |
3a2a3a7f | 3496 | return gen_rtx_fmt_ee (cmov_code, cmov_mode, tem, CONST0_RTX (cmp_op_mode)); |
996a379d | 3497 | } |
bbf31a61 | 3498 | |
3499 | /* Simplify a conditional move of two constants into a setcc with | |
3500 | arithmetic. This is done with a splitter since combine would | |
3501 | just undo the work if done during code generation. It also catches | |
3502 | cases we wouldn't have before cse. */ | |
3503 | ||
3504 | int | |
92643d95 | 3505 | alpha_split_conditional_move (enum rtx_code code, rtx dest, rtx cond, |
3506 | rtx t_rtx, rtx f_rtx) | |
bbf31a61 | 3507 | { |
3508 | HOST_WIDE_INT t, f, diff; | |
3509 | enum machine_mode mode; | |
3510 | rtx target, subtarget, tmp; | |
3511 | ||
3512 | mode = GET_MODE (dest); | |
3513 | t = INTVAL (t_rtx); | |
3514 | f = INTVAL (f_rtx); | |
3515 | diff = t - f; | |
3516 | ||
3517 | if (((code == NE || code == EQ) && diff < 0) | |
3518 | || (code == GE || code == GT)) | |
3519 | { | |
3520 | code = reverse_condition (code); | |
3521 | diff = t, t = f, f = diff; | |
3522 | diff = t - f; | |
3523 | } | |
3524 | ||
3525 | subtarget = target = dest; | |
3526 | if (mode != DImode) | |
3527 | { | |
3528 | target = gen_lowpart (DImode, dest); | |
3529 | if (! no_new_pseudos) | |
3530 | subtarget = gen_reg_rtx (DImode); | |
3531 | else | |
3532 | subtarget = target; | |
3533 | } | |
64656695 | 3534 | /* Below, we must be careful to use copy_rtx on target and subtarget |
3535 | in intermediate insns, as they may be a subreg rtx, which may not | |
3536 | be shared. */ | |
bbf31a61 | 3537 | |
3538 | if (f == 0 && exact_log2 (diff) > 0 | |
8d232dc7 | 3539 | /* On EV6, we've got enough shifters to make non-arithmetic shifts |
bbf31a61 | 3540 | viable over a longer latency cmove. On EV5, the E0 slot is a |
65abff06 | 3541 | scarce resource, and on EV4 shift has the same latency as a cmove. */ |
bbf31a61 | 3542 | && (diff <= 8 || alpha_cpu == PROCESSOR_EV6)) |
3543 | { | |
3544 | tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx); | |
64656695 | 3545 | emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp)); |
bbf31a61 | 3546 | |
64656695 | 3547 | tmp = gen_rtx_ASHIFT (DImode, copy_rtx (subtarget), |
3548 | GEN_INT (exact_log2 (t))); | |
bbf31a61 | 3549 | emit_insn (gen_rtx_SET (VOIDmode, target, tmp)); |
3550 | } | |
3551 | else if (f == 0 && t == -1) | |
3552 | { | |
3553 | tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx); | |
64656695 | 3554 | emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp)); |
bbf31a61 | 3555 | |
64656695 | 3556 | emit_insn (gen_negdi2 (target, copy_rtx (subtarget))); |
bbf31a61 | 3557 | } |
3558 | else if (diff == 1 || diff == 4 || diff == 8) | |
3559 | { | |
3560 | rtx add_op; | |
3561 | ||
3562 | tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx); | |
64656695 | 3563 | emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp)); |
bbf31a61 | 3564 | |
3565 | if (diff == 1) | |
64656695 | 3566 | emit_insn (gen_adddi3 (target, copy_rtx (subtarget), GEN_INT (f))); |
bbf31a61 | 3567 | else |
3568 | { | |
3569 | add_op = GEN_INT (f); | |
3570 | if (sext_add_operand (add_op, mode)) | |
3571 | { | |
64656695 | 3572 | tmp = gen_rtx_MULT (DImode, copy_rtx (subtarget), |
3573 | GEN_INT (diff)); | |
bbf31a61 | 3574 | tmp = gen_rtx_PLUS (DImode, tmp, add_op); |
3575 | emit_insn (gen_rtx_SET (VOIDmode, target, tmp)); | |
3576 | } | |
3577 | else | |
3578 | return 0; | |
3579 | } | |
3580 | } | |
3581 | else | |
3582 | return 0; | |
3583 | ||
3584 | return 1; | |
3585 | } | |
34377880 | 3586 | \f |
915c336f | 3587 | /* Look up the function X_floating library function name for the |
3588 | given operation. */ | |
3589 | ||
2d7c492e | 3590 | struct xfloating_op GTY(()) |
3591 | { | |
3592 | const enum rtx_code code; | |
7035b2ab | 3593 | const char *const GTY((skip)) osf_func; |
3594 | const char *const GTY((skip)) vms_func; | |
2d7c492e | 3595 | rtx libcall; |
3596 | }; | |
3597 | ||
3598 | static GTY(()) struct xfloating_op xfloating_ops[] = | |
3599 | { | |
3600 | { PLUS, "_OtsAddX", "OTS$ADD_X", 0 }, | |
3601 | { MINUS, "_OtsSubX", "OTS$SUB_X", 0 }, | |
3602 | { MULT, "_OtsMulX", "OTS$MUL_X", 0 }, | |
3603 | { DIV, "_OtsDivX", "OTS$DIV_X", 0 }, | |
3604 | { EQ, "_OtsEqlX", "OTS$EQL_X", 0 }, | |
3605 | { NE, "_OtsNeqX", "OTS$NEQ_X", 0 }, | |
3606 | { LT, "_OtsLssX", "OTS$LSS_X", 0 }, | |
3607 | { LE, "_OtsLeqX", "OTS$LEQ_X", 0 }, | |
3608 | { GT, "_OtsGtrX", "OTS$GTR_X", 0 }, | |
3609 | { GE, "_OtsGeqX", "OTS$GEQ_X", 0 }, | |
3610 | { FIX, "_OtsCvtXQ", "OTS$CVTXQ", 0 }, | |
3611 | { FLOAT, "_OtsCvtQX", "OTS$CVTQX", 0 }, | |
3612 | { UNSIGNED_FLOAT, "_OtsCvtQUX", "OTS$CVTQUX", 0 }, | |
3613 | { FLOAT_EXTEND, "_OtsConvertFloatTX", "OTS$CVT_FLOAT_T_X", 0 }, | |
3614 | { FLOAT_TRUNCATE, "_OtsConvertFloatXT", "OTS$CVT_FLOAT_X_T", 0 } | |
3615 | }; | |
3616 | ||
3617 | static GTY(()) struct xfloating_op vax_cvt_ops[] = | |
3618 | { | |
3619 | { FLOAT_EXTEND, "_OtsConvertFloatGX", "OTS$CVT_FLOAT_G_X", 0 }, | |
3620 | { FLOAT_TRUNCATE, "_OtsConvertFloatXG", "OTS$CVT_FLOAT_X_G", 0 } | |
3621 | }; | |
3622 | ||
3623 | static rtx | |
92643d95 | 3624 | alpha_lookup_xfloating_lib_func (enum rtx_code code) |
915c336f | 3625 | { |
2d7c492e | 3626 | struct xfloating_op *ops = xfloating_ops; |
3627 | long n = ARRAY_SIZE (xfloating_ops); | |
915c336f | 3628 | long i; |
3629 | ||
2d7c492e | 3630 | /* How irritating. Nothing to key off for the main table. */ |
3631 | if (TARGET_FLOAT_VAX && (code == FLOAT_EXTEND || code == FLOAT_TRUNCATE)) | |
915c336f | 3632 | { |
2d7c492e | 3633 | ops = vax_cvt_ops; |
3634 | n = ARRAY_SIZE (vax_cvt_ops); | |
915c336f | 3635 | } |
3636 | ||
2d7c492e | 3637 | for (i = 0; i < n; ++i, ++ops) |
3638 | if (ops->code == code) | |
3639 | { | |
3640 | rtx func = ops->libcall; | |
3641 | if (!func) | |
3642 | { | |
3643 | func = init_one_libfunc (TARGET_ABI_OPEN_VMS | |
3644 | ? ops->vms_func : ops->osf_func); | |
3645 | ops->libcall = func; | |
3646 | } | |
3647 | return func; | |
3648 | } | |
915c336f | 3649 | |
3650 | abort(); | |
3651 | } | |
3652 | ||
3653 | /* Most X_floating operations take the rounding mode as an argument. | |
3654 | Compute that here. */ | |
3655 | ||
3656 | static int | |
92643d95 | 3657 | alpha_compute_xfloating_mode_arg (enum rtx_code code, |
3658 | enum alpha_fp_rounding_mode round) | |
915c336f | 3659 | { |
3660 | int mode; | |
3661 | ||
3662 | switch (round) | |
3663 | { | |
3664 | case ALPHA_FPRM_NORM: | |
3665 | mode = 2; | |
3666 | break; | |
3667 | case ALPHA_FPRM_MINF: | |
3668 | mode = 1; | |
3669 | break; | |
3670 | case ALPHA_FPRM_CHOP: | |
3671 | mode = 0; | |
3672 | break; | |
3673 | case ALPHA_FPRM_DYN: | |
3674 | mode = 4; | |
3675 | break; | |
3676 | default: | |
3677 | abort (); | |
3678 | ||
3679 | /* XXX For reference, round to +inf is mode = 3. */ | |
3680 | } | |
3681 | ||
3682 | if (code == FLOAT_TRUNCATE && alpha_fptm == ALPHA_FPTM_N) | |
3683 | mode |= 0x10000; | |
3684 | ||
3685 | return mode; | |
3686 | } | |
3687 | ||
3688 | /* Emit an X_floating library function call. | |
3689 | ||
3690 | Note that these functions do not follow normal calling conventions: | |
3691 | TFmode arguments are passed in two integer registers (as opposed to | |
3692 | indirect); TFmode return values appear in R16+R17. | |
3693 | ||
2d7c492e | 3694 | FUNC is the function to call. |
915c336f | 3695 | TARGET is where the output belongs. |
3696 | OPERANDS are the inputs. | |
3697 | NOPERANDS is the count of inputs. | |
3698 | EQUIV is the expression equivalent for the function. | |
3699 | */ | |
3700 | ||
3701 | static void | |
2d7c492e | 3702 | alpha_emit_xfloating_libcall (rtx func, rtx target, rtx operands[], |
92643d95 | 3703 | int noperands, rtx equiv) |
915c336f | 3704 | { |
3705 | rtx usage = NULL_RTX, tmp, reg; | |
3706 | int regno = 16, i; | |
3707 | ||
3708 | start_sequence (); | |
3709 | ||
3710 | for (i = 0; i < noperands; ++i) | |
3711 | { | |
3712 | switch (GET_MODE (operands[i])) | |
3713 | { | |
3714 | case TFmode: | |
3715 | reg = gen_rtx_REG (TFmode, regno); | |
3716 | regno += 2; | |
3717 | break; | |
3718 | ||
3719 | case DFmode: | |
3720 | reg = gen_rtx_REG (DFmode, regno + 32); | |
3721 | regno += 1; | |
3722 | break; | |
3723 | ||
3724 | case VOIDmode: | |
3725 | if (GET_CODE (operands[i]) != CONST_INT) | |
3726 | abort (); | |
8e262b5e | 3727 | /* FALLTHRU */ |
915c336f | 3728 | case DImode: |
3729 | reg = gen_rtx_REG (DImode, regno); | |
3730 | regno += 1; | |
3731 | break; | |
3732 | ||
3733 | default: | |
3734 | abort (); | |
3735 | } | |
3736 | ||
3737 | emit_move_insn (reg, operands[i]); | |
3738 | usage = alloc_EXPR_LIST (0, gen_rtx_USE (VOIDmode, reg), usage); | |
3739 | } | |
3740 | ||
3741 | switch (GET_MODE (target)) | |
3742 | { | |
3743 | case TFmode: | |
3744 | reg = gen_rtx_REG (TFmode, 16); | |
3745 | break; | |
3746 | case DFmode: | |
3747 | reg = gen_rtx_REG (DFmode, 32); | |
3748 | break; | |
3749 | case DImode: | |
3750 | reg = gen_rtx_REG (DImode, 0); | |
3751 | break; | |
3752 | default: | |
3753 | abort (); | |
3754 | } | |
3755 | ||
2d7c492e | 3756 | tmp = gen_rtx_MEM (QImode, func); |
2c6f8e4d | 3757 | tmp = emit_call_insn (GEN_CALL_VALUE (reg, tmp, const0_rtx, |
915c336f | 3758 | const0_rtx, const0_rtx)); |
3759 | CALL_INSN_FUNCTION_USAGE (tmp) = usage; | |
2d7c492e | 3760 | CONST_OR_PURE_CALL_P (tmp) = 1; |
915c336f | 3761 | |
3762 | tmp = get_insns (); | |
3763 | end_sequence (); | |
3764 | ||
3765 | emit_libcall_block (tmp, target, reg, equiv); | |
3766 | } | |
3767 | ||
3768 | /* Emit an X_floating library function call for arithmetic (+,-,*,/). */ | |
3769 | ||
3770 | void | |
92643d95 | 3771 | alpha_emit_xfloating_arith (enum rtx_code code, rtx operands[]) |
915c336f | 3772 | { |
2d7c492e | 3773 | rtx func; |
915c336f | 3774 | int mode; |
b90b6519 | 3775 | rtx out_operands[3]; |
915c336f | 3776 | |
3777 | func = alpha_lookup_xfloating_lib_func (code); | |
3778 | mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm); | |
3779 | ||
b90b6519 | 3780 | out_operands[0] = operands[1]; |
3781 | out_operands[1] = operands[2]; | |
3782 | out_operands[2] = GEN_INT (mode); | |
3783 | alpha_emit_xfloating_libcall (func, operands[0], out_operands, 3, | |
915c336f | 3784 | gen_rtx_fmt_ee (code, TFmode, operands[1], |
3785 | operands[2])); | |
3786 | } | |
3787 | ||
3788 | /* Emit an X_floating library function call for a comparison. */ | |
3789 | ||
3790 | static rtx | |
92643d95 | 3791 | alpha_emit_xfloating_compare (enum rtx_code code, rtx op0, rtx op1) |
915c336f | 3792 | { |
2d7c492e | 3793 | rtx func; |
915c336f | 3794 | rtx out, operands[2]; |
3795 | ||
3796 | func = alpha_lookup_xfloating_lib_func (code); | |
3797 | ||
3798 | operands[0] = op0; | |
3799 | operands[1] = op1; | |
3800 | out = gen_reg_rtx (DImode); | |
3801 | ||
d1324b4b | 3802 | /* ??? Strange mode for equiv because what's actually returned |
3803 | is -1,0,1, not a proper boolean value. */ | |
3804 | alpha_emit_xfloating_libcall (func, out, operands, 2, | |
3805 | gen_rtx_fmt_ee (code, CCmode, op0, op1)); | |
915c336f | 3806 | |
3807 | return out; | |
3808 | } | |
3809 | ||
3810 | /* Emit an X_floating library function call for a conversion. */ | |
3811 | ||
3812 | void | |
caf6f044 | 3813 | alpha_emit_xfloating_cvt (enum rtx_code orig_code, rtx operands[]) |
915c336f | 3814 | { |
3815 | int noperands = 1, mode; | |
b90b6519 | 3816 | rtx out_operands[2]; |
2d7c492e | 3817 | rtx func; |
caf6f044 | 3818 | enum rtx_code code = orig_code; |
3819 | ||
3820 | if (code == UNSIGNED_FIX) | |
3821 | code = FIX; | |
915c336f | 3822 | |
3823 | func = alpha_lookup_xfloating_lib_func (code); | |
3824 | ||
b90b6519 | 3825 | out_operands[0] = operands[1]; |
3826 | ||
915c336f | 3827 | switch (code) |
3828 | { | |
3829 | case FIX: | |
3830 | mode = alpha_compute_xfloating_mode_arg (code, ALPHA_FPRM_CHOP); | |
b90b6519 | 3831 | out_operands[1] = GEN_INT (mode); |
8581412d | 3832 | noperands = 2; |
915c336f | 3833 | break; |
3834 | case FLOAT_TRUNCATE: | |
3835 | mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm); | |
b90b6519 | 3836 | out_operands[1] = GEN_INT (mode); |
8581412d | 3837 | noperands = 2; |
915c336f | 3838 | break; |
3839 | default: | |
3840 | break; | |
3841 | } | |
3842 | ||
b90b6519 | 3843 | alpha_emit_xfloating_libcall (func, operands[0], out_operands, noperands, |
caf6f044 | 3844 | gen_rtx_fmt_e (orig_code, |
3845 | GET_MODE (operands[0]), | |
915c336f | 3846 | operands[1])); |
3847 | } | |
3420680b | 3848 | |
2267ca84 | 3849 | /* Split a TFmode OP[1] into DImode OP[2,3] and likewise for |
3850 | OP[0] into OP[0,1]. Naturally, output operand ordering is | |
3851 | little-endian. */ | |
3852 | ||
3420680b | 3853 | void |
92643d95 | 3854 | alpha_split_tfmode_pair (rtx operands[4]) |
3420680b | 3855 | { |
3856 | if (GET_CODE (operands[1]) == REG) | |
3857 | { | |
3858 | operands[3] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1); | |
3859 | operands[2] = gen_rtx_REG (DImode, REGNO (operands[1])); | |
3860 | } | |
3861 | else if (GET_CODE (operands[1]) == MEM) | |
3862 | { | |
e513d163 | 3863 | operands[3] = adjust_address (operands[1], DImode, 8); |
3864 | operands[2] = adjust_address (operands[1], DImode, 0); | |
3420680b | 3865 | } |
3866 | else if (operands[1] == CONST0_RTX (TFmode)) | |
3867 | operands[2] = operands[3] = const0_rtx; | |
3868 | else | |
3869 | abort (); | |
3870 | ||
3871 | if (GET_CODE (operands[0]) == REG) | |
3872 | { | |
3873 | operands[1] = gen_rtx_REG (DImode, REGNO (operands[0]) + 1); | |
3874 | operands[0] = gen_rtx_REG (DImode, REGNO (operands[0])); | |
3875 | } | |
3876 | else if (GET_CODE (operands[0]) == MEM) | |
3877 | { | |
e513d163 | 3878 | operands[1] = adjust_address (operands[0], DImode, 8); |
3879 | operands[0] = adjust_address (operands[0], DImode, 0); | |
3420680b | 3880 | } |
3881 | else | |
3882 | abort (); | |
3883 | } | |
2267ca84 | 3884 | |
3885 | /* Implement negtf2 or abstf2. Op0 is destination, op1 is source, | |
3886 | op2 is a register containing the sign bit, operation is the | |
3887 | logical operation to be performed. */ | |
3888 | ||
3889 | void | |
92643d95 | 3890 | alpha_split_tfmode_frobsign (rtx operands[3], rtx (*operation) (rtx, rtx, rtx)) |
2267ca84 | 3891 | { |
3892 | rtx high_bit = operands[2]; | |
3893 | rtx scratch; | |
3894 | int move; | |
3895 | ||
3896 | alpha_split_tfmode_pair (operands); | |
3897 | ||
e3e08e7f | 3898 | /* Detect three flavors of operand overlap. */ |
2267ca84 | 3899 | move = 1; |
3900 | if (rtx_equal_p (operands[0], operands[2])) | |
3901 | move = 0; | |
3902 | else if (rtx_equal_p (operands[1], operands[2])) | |
3903 | { | |
3904 | if (rtx_equal_p (operands[0], high_bit)) | |
3905 | move = 2; | |
3906 | else | |
3907 | move = -1; | |
3908 | } | |
3909 | ||
3910 | if (move < 0) | |
3911 | emit_move_insn (operands[0], operands[2]); | |
3912 | ||
3913 | /* ??? If the destination overlaps both source tf and high_bit, then | |
3914 | assume source tf is dead in its entirety and use the other half | |
3915 | for a scratch register. Otherwise "scratch" is just the proper | |
3916 | destination register. */ | |
3917 | scratch = operands[move < 2 ? 1 : 3]; | |
3918 | ||
3919 | emit_insn ((*operation) (scratch, high_bit, operands[3])); | |
3920 | ||
3921 | if (move > 0) | |
3922 | { | |
3923 | emit_move_insn (operands[0], operands[2]); | |
3924 | if (move > 1) | |
3925 | emit_move_insn (operands[1], scratch); | |
3926 | } | |
3927 | } | |
915c336f | 3928 | \f |
34377880 | 3929 | /* Use ext[wlq][lh] as the Architecture Handbook describes for extracting |
3930 | unaligned data: | |
3931 | ||
3932 | unsigned: signed: | |
3933 | word: ldq_u r1,X(r11) ldq_u r1,X(r11) | |
3934 | ldq_u r2,X+1(r11) ldq_u r2,X+1(r11) | |
3935 | lda r3,X(r11) lda r3,X+2(r11) | |
3936 | extwl r1,r3,r1 extql r1,r3,r1 | |
3937 | extwh r2,r3,r2 extqh r2,r3,r2 | |
3938 | or r1.r2.r1 or r1,r2,r1 | |
3939 | sra r1,48,r1 | |
3940 | ||
3941 | long: ldq_u r1,X(r11) ldq_u r1,X(r11) | |
3942 | ldq_u r2,X+3(r11) ldq_u r2,X+3(r11) | |
3943 | lda r3,X(r11) lda r3,X(r11) | |
3944 | extll r1,r3,r1 extll r1,r3,r1 | |
3945 | extlh r2,r3,r2 extlh r2,r3,r2 | |
3946 | or r1.r2.r1 addl r1,r2,r1 | |
3947 | ||
3948 | quad: ldq_u r1,X(r11) | |
3949 | ldq_u r2,X+7(r11) | |
3950 | lda r3,X(r11) | |
3951 | extql r1,r3,r1 | |
3952 | extqh r2,r3,r2 | |
3953 | or r1.r2.r1 | |
3954 | */ | |
3955 | ||
3956 | void | |
92643d95 | 3957 | alpha_expand_unaligned_load (rtx tgt, rtx mem, HOST_WIDE_INT size, |
3958 | HOST_WIDE_INT ofs, int sign) | |
34377880 | 3959 | { |
1f0ce6a6 | 3960 | rtx meml, memh, addr, extl, exth, tmp, mema; |
2cc46ade | 3961 | enum machine_mode mode; |
34377880 | 3962 | |
3963 | meml = gen_reg_rtx (DImode); | |
3964 | memh = gen_reg_rtx (DImode); | |
3965 | addr = gen_reg_rtx (DImode); | |
3966 | extl = gen_reg_rtx (DImode); | |
3967 | exth = gen_reg_rtx (DImode); | |
3968 | ||
1f0ce6a6 | 3969 | mema = XEXP (mem, 0); |
3970 | if (GET_CODE (mema) == LO_SUM) | |
3971 | mema = force_reg (Pmode, mema); | |
3972 | ||
3024e9f8 | 3973 | /* AND addresses cannot be in any alias set, since they may implicitly |
3974 | alias surrounding code. Ideally we'd have some alias set that | |
3975 | covered all types except those with alignment 8 or higher. */ | |
3976 | ||
3977 | tmp = change_address (mem, DImode, | |
3978 | gen_rtx_AND (DImode, | |
1f0ce6a6 | 3979 | plus_constant (mema, ofs), |
3024e9f8 | 3980 | GEN_INT (-8))); |
ab6ab77e | 3981 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3982 | emit_move_insn (meml, tmp); |
3983 | ||
3984 | tmp = change_address (mem, DImode, | |
3985 | gen_rtx_AND (DImode, | |
1f0ce6a6 | 3986 | plus_constant (mema, ofs + size - 1), |
3024e9f8 | 3987 | GEN_INT (-8))); |
ab6ab77e | 3988 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3989 | emit_move_insn (memh, tmp); |
34377880 | 3990 | |
9caef960 | 3991 | if (WORDS_BIG_ENDIAN && sign && (size == 2 || size == 4)) |
3992 | { | |
3993 | emit_move_insn (addr, plus_constant (mema, -1)); | |
3994 | ||
3995 | emit_insn (gen_extqh_be (extl, meml, addr)); | |
3996 | emit_insn (gen_extxl_be (exth, memh, GEN_INT (64), addr)); | |
3997 | ||
3998 | addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN); | |
3999 | addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (64 - size*8), | |
4000 | addr, 1, OPTAB_WIDEN); | |
4001 | } | |
4002 | else if (sign && size == 2) | |
34377880 | 4003 | { |
1f0ce6a6 | 4004 | emit_move_insn (addr, plus_constant (mema, ofs+2)); |
34377880 | 4005 | |
9caef960 | 4006 | emit_insn (gen_extxl_le (extl, meml, GEN_INT (64), addr)); |
4007 | emit_insn (gen_extqh_le (exth, memh, addr)); | |
34377880 | 4008 | |
ba4a7733 | 4009 | /* We must use tgt here for the target. Alpha-vms port fails if we use |
4010 | addr for the target, because addr is marked as a pointer and combine | |
4011 | knows that pointers are always sign-extended 32 bit values. */ | |
4012 | addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN); | |
2cc46ade | 4013 | addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (48), |
4014 | addr, 1, OPTAB_WIDEN); | |
34377880 | 4015 | } |
2cc46ade | 4016 | else |
34377880 | 4017 | { |
9caef960 | 4018 | if (WORDS_BIG_ENDIAN) |
2cc46ade | 4019 | { |
9caef960 | 4020 | emit_move_insn (addr, plus_constant (mema, ofs+size-1)); |
4021 | switch ((int) size) | |
4022 | { | |
4023 | case 2: | |
4024 | emit_insn (gen_extwh_be (extl, meml, addr)); | |
4025 | mode = HImode; | |
4026 | break; | |
34377880 | 4027 | |
9caef960 | 4028 | case 4: |
4029 | emit_insn (gen_extlh_be (extl, meml, addr)); | |
4030 | mode = SImode; | |
4031 | break; | |
34377880 | 4032 | |
9caef960 | 4033 | case 8: |
4034 | emit_insn (gen_extqh_be (extl, meml, addr)); | |
4035 | mode = DImode; | |
4036 | break; | |
915c336f | 4037 | |
9caef960 | 4038 | default: |
4039 | abort (); | |
4040 | } | |
4041 | emit_insn (gen_extxl_be (exth, memh, GEN_INT (size*8), addr)); | |
4042 | } | |
4043 | else | |
4044 | { | |
4045 | emit_move_insn (addr, plus_constant (mema, ofs)); | |
4046 | emit_insn (gen_extxl_le (extl, meml, GEN_INT (size*8), addr)); | |
4047 | switch ((int) size) | |
4048 | { | |
4049 | case 2: | |
4050 | emit_insn (gen_extwh_le (exth, memh, addr)); | |
4051 | mode = HImode; | |
4052 | break; | |
4053 | ||
4054 | case 4: | |
4055 | emit_insn (gen_extlh_le (exth, memh, addr)); | |
4056 | mode = SImode; | |
4057 | break; | |
4058 | ||
4059 | case 8: | |
4060 | emit_insn (gen_extqh_le (exth, memh, addr)); | |
4061 | mode = DImode; | |
4062 | break; | |
4063 | ||
4064 | default: | |
4065 | abort(); | |
4066 | } | |
2cc46ade | 4067 | } |
4068 | ||
4069 | addr = expand_binop (mode, ior_optab, gen_lowpart (mode, extl), | |
4070 | gen_lowpart (mode, exth), gen_lowpart (mode, tgt), | |
4071 | sign, OPTAB_WIDEN); | |
34377880 | 4072 | } |
4073 | ||
2cc46ade | 4074 | if (addr != tgt) |
4075 | emit_move_insn (tgt, gen_lowpart(GET_MODE (tgt), addr)); | |
34377880 | 4076 | } |
4077 | ||
4078 | /* Similarly, use ins and msk instructions to perform unaligned stores. */ | |
4079 | ||
4080 | void | |
92643d95 | 4081 | alpha_expand_unaligned_store (rtx dst, rtx src, |
4082 | HOST_WIDE_INT size, HOST_WIDE_INT ofs) | |
34377880 | 4083 | { |
1f0ce6a6 | 4084 | rtx dstl, dsth, addr, insl, insh, meml, memh, dsta; |
34377880 | 4085 | |
4086 | dstl = gen_reg_rtx (DImode); | |
4087 | dsth = gen_reg_rtx (DImode); | |
4088 | insl = gen_reg_rtx (DImode); | |
4089 | insh = gen_reg_rtx (DImode); | |
4090 | ||
1f0ce6a6 | 4091 | dsta = XEXP (dst, 0); |
4092 | if (GET_CODE (dsta) == LO_SUM) | |
4093 | dsta = force_reg (Pmode, dsta); | |
4094 | ||
3024e9f8 | 4095 | /* AND addresses cannot be in any alias set, since they may implicitly |
4096 | alias surrounding code. Ideally we'd have some alias set that | |
4097 | covered all types except those with alignment 8 or higher. */ | |
4098 | ||
34377880 | 4099 | meml = change_address (dst, DImode, |
941522d6 | 4100 | gen_rtx_AND (DImode, |
1f0ce6a6 | 4101 | plus_constant (dsta, ofs), |
941522d6 | 4102 | GEN_INT (-8))); |
ab6ab77e | 4103 | set_mem_alias_set (meml, 0); |
3024e9f8 | 4104 | |
34377880 | 4105 | memh = change_address (dst, DImode, |
941522d6 | 4106 | gen_rtx_AND (DImode, |
1f0ce6a6 | 4107 | plus_constant (dsta, ofs + size - 1), |
941522d6 | 4108 | GEN_INT (-8))); |
ab6ab77e | 4109 | set_mem_alias_set (memh, 0); |
34377880 | 4110 | |
4111 | emit_move_insn (dsth, memh); | |
4112 | emit_move_insn (dstl, meml); | |
9caef960 | 4113 | if (WORDS_BIG_ENDIAN) |
34377880 | 4114 | { |
9caef960 | 4115 | addr = copy_addr_to_reg (plus_constant (dsta, ofs+size-1)); |
4116 | ||
4117 | if (src != const0_rtx) | |
4118 | { | |
4119 | switch ((int) size) | |
4120 | { | |
4121 | case 2: | |
4122 | emit_insn (gen_inswl_be (insh, gen_lowpart (HImode,src), addr)); | |
4123 | break; | |
4124 | case 4: | |
4125 | emit_insn (gen_insll_be (insh, gen_lowpart (SImode,src), addr)); | |
4126 | break; | |
4127 | case 8: | |
4128 | emit_insn (gen_insql_be (insh, gen_lowpart (DImode,src), addr)); | |
4129 | break; | |
4130 | } | |
4131 | emit_insn (gen_insxh (insl, gen_lowpart (DImode, src), | |
4132 | GEN_INT (size*8), addr)); | |
4133 | } | |
34377880 | 4134 | |
29768226 | 4135 | switch ((int) size) |
34377880 | 4136 | { |
4137 | case 2: | |
9caef960 | 4138 | emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffff), addr)); |
34377880 | 4139 | break; |
4140 | case 4: | |
9caef960 | 4141 | { |
ae4cd3a5 | 4142 | rtx msk = immed_double_const (0xffffffff, 0, DImode); |
9caef960 | 4143 | emit_insn (gen_mskxl_be (dsth, dsth, msk, addr)); |
ae4cd3a5 | 4144 | break; |
9caef960 | 4145 | } |
ae4cd3a5 | 4146 | case 8: |
4147 | emit_insn (gen_mskxl_be (dsth, dsth, constm1_rtx, addr)); | |
34377880 | 4148 | break; |
4149 | } | |
9caef960 | 4150 | |
4151 | emit_insn (gen_mskxh (dstl, dstl, GEN_INT (size*8), addr)); | |
34377880 | 4152 | } |
9caef960 | 4153 | else |
4154 | { | |
4155 | addr = copy_addr_to_reg (plus_constant (dsta, ofs)); | |
34377880 | 4156 | |
9caef960 | 4157 | if (src != const0_rtx) |
4158 | { | |
4159 | emit_insn (gen_insxh (insh, gen_lowpart (DImode, src), | |
4160 | GEN_INT (size*8), addr)); | |
34377880 | 4161 | |
9caef960 | 4162 | switch ((int) size) |
4163 | { | |
4164 | case 2: | |
4165 | emit_insn (gen_inswl_le (insl, gen_lowpart (HImode, src), addr)); | |
4166 | break; | |
4167 | case 4: | |
4168 | emit_insn (gen_insll_le (insl, gen_lowpart (SImode, src), addr)); | |
4169 | break; | |
4170 | case 8: | |
4171 | emit_insn (gen_insql_le (insl, src, addr)); | |
4172 | break; | |
4173 | } | |
4174 | } | |
4175 | ||
4176 | emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr)); | |
4177 | ||
4178 | switch ((int) size) | |
4179 | { | |
4180 | case 2: | |
4181 | emit_insn (gen_mskxl_le (dstl, dstl, GEN_INT (0xffff), addr)); | |
4182 | break; | |
4183 | case 4: | |
9caef960 | 4184 | { |
ae4cd3a5 | 4185 | rtx msk = immed_double_const (0xffffffff, 0, DImode); |
9caef960 | 4186 | emit_insn (gen_mskxl_le (dstl, dstl, msk, addr)); |
ae4cd3a5 | 4187 | break; |
9caef960 | 4188 | } |
ae4cd3a5 | 4189 | case 8: |
4190 | emit_insn (gen_mskxl_le (dstl, dstl, constm1_rtx, addr)); | |
9caef960 | 4191 | break; |
4192 | } | |
34377880 | 4193 | } |
4194 | ||
4195 | if (src != const0_rtx) | |
4196 | { | |
2cc46ade | 4197 | dsth = expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN); |
4198 | dstl = expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN); | |
34377880 | 4199 | } |
9caef960 | 4200 | |
4201 | if (WORDS_BIG_ENDIAN) | |
4202 | { | |
4203 | emit_move_insn (meml, dstl); | |
4204 | emit_move_insn (memh, dsth); | |
4205 | } | |
4206 | else | |
4207 | { | |
4208 | /* Must store high before low for degenerate case of aligned. */ | |
4209 | emit_move_insn (memh, dsth); | |
4210 | emit_move_insn (meml, dstl); | |
4211 | } | |
34377880 | 4212 | } |
4213 | ||
2cc46ade | 4214 | /* The block move code tries to maximize speed by separating loads and |
4215 | stores at the expense of register pressure: we load all of the data | |
4216 | before we store it back out. There are two secondary effects worth | |
4217 | mentioning, that this speeds copying to/from aligned and unaligned | |
4218 | buffers, and that it makes the code significantly easier to write. */ | |
34377880 | 4219 | |
2cc46ade | 4220 | #define MAX_MOVE_WORDS 8 |
4221 | ||
4222 | /* Load an integral number of consecutive unaligned quadwords. */ | |
34377880 | 4223 | |
4224 | static void | |
92643d95 | 4225 | alpha_expand_unaligned_load_words (rtx *out_regs, rtx smem, |
4226 | HOST_WIDE_INT words, HOST_WIDE_INT ofs) | |
34377880 | 4227 | { |
4228 | rtx const im8 = GEN_INT (-8); | |
4229 | rtx const i64 = GEN_INT (64); | |
2cc46ade | 4230 | rtx ext_tmps[MAX_MOVE_WORDS], data_regs[MAX_MOVE_WORDS+1]; |
1f0ce6a6 | 4231 | rtx sreg, areg, tmp, smema; |
34377880 | 4232 | HOST_WIDE_INT i; |
4233 | ||
1f0ce6a6 | 4234 | smema = XEXP (smem, 0); |
4235 | if (GET_CODE (smema) == LO_SUM) | |
4236 | smema = force_reg (Pmode, smema); | |
4237 | ||
34377880 | 4238 | /* Generate all the tmp registers we need. */ |
4239 | for (i = 0; i < words; ++i) | |
2cc46ade | 4240 | { |
4241 | data_regs[i] = out_regs[i]; | |
4242 | ext_tmps[i] = gen_reg_rtx (DImode); | |
4243 | } | |
4244 | data_regs[words] = gen_reg_rtx (DImode); | |
4245 | ||
4246 | if (ofs != 0) | |
e513d163 | 4247 | smem = adjust_address (smem, GET_MODE (smem), ofs); |
34377880 | 4248 | |
4249 | /* Load up all of the source data. */ | |
4250 | for (i = 0; i < words; ++i) | |
4251 | { | |
3024e9f8 | 4252 | tmp = change_address (smem, DImode, |
4253 | gen_rtx_AND (DImode, | |
1f0ce6a6 | 4254 | plus_constant (smema, 8*i), |
3024e9f8 | 4255 | im8)); |
ab6ab77e | 4256 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 4257 | emit_move_insn (data_regs[i], tmp); |
34377880 | 4258 | } |
3024e9f8 | 4259 | |
4260 | tmp = change_address (smem, DImode, | |
4261 | gen_rtx_AND (DImode, | |
1f0ce6a6 | 4262 | plus_constant (smema, 8*words - 1), |
3024e9f8 | 4263 | im8)); |
ab6ab77e | 4264 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 4265 | emit_move_insn (data_regs[words], tmp); |
34377880 | 4266 | |
4267 | /* Extract the half-word fragments. Unfortunately DEC decided to make | |
4268 | extxh with offset zero a noop instead of zeroing the register, so | |
4269 | we must take care of that edge condition ourselves with cmov. */ | |
4270 | ||
1f0ce6a6 | 4271 | sreg = copy_addr_to_reg (smema); |
2cc46ade | 4272 | areg = expand_binop (DImode, and_optab, sreg, GEN_INT (7), NULL, |
4273 | 1, OPTAB_WIDEN); | |
9caef960 | 4274 | if (WORDS_BIG_ENDIAN) |
4275 | emit_move_insn (sreg, plus_constant (sreg, 7)); | |
34377880 | 4276 | for (i = 0; i < words; ++i) |
4277 | { | |
9caef960 | 4278 | if (WORDS_BIG_ENDIAN) |
4279 | { | |
4280 | emit_insn (gen_extqh_be (data_regs[i], data_regs[i], sreg)); | |
4281 | emit_insn (gen_extxl_be (ext_tmps[i], data_regs[i+1], i64, sreg)); | |
4282 | } | |
4283 | else | |
4284 | { | |
4285 | emit_insn (gen_extxl_le (data_regs[i], data_regs[i], i64, sreg)); | |
4286 | emit_insn (gen_extqh_le (ext_tmps[i], data_regs[i+1], sreg)); | |
4287 | } | |
941522d6 | 4288 | emit_insn (gen_rtx_SET (VOIDmode, ext_tmps[i], |
4289 | gen_rtx_IF_THEN_ELSE (DImode, | |
2cc46ade | 4290 | gen_rtx_EQ (DImode, areg, |
4291 | const0_rtx), | |
941522d6 | 4292 | const0_rtx, ext_tmps[i]))); |
34377880 | 4293 | } |
4294 | ||
4295 | /* Merge the half-words into whole words. */ | |
4296 | for (i = 0; i < words; ++i) | |
4297 | { | |
2cc46ade | 4298 | out_regs[i] = expand_binop (DImode, ior_optab, data_regs[i], |
4299 | ext_tmps[i], data_regs[i], 1, OPTAB_WIDEN); | |
34377880 | 4300 | } |
4301 | } | |
4302 | ||
4303 | /* Store an integral number of consecutive unaligned quadwords. DATA_REGS | |
4304 | may be NULL to store zeros. */ | |
4305 | ||
4306 | static void | |
92643d95 | 4307 | alpha_expand_unaligned_store_words (rtx *data_regs, rtx dmem, |
4308 | HOST_WIDE_INT words, HOST_WIDE_INT ofs) | |
34377880 | 4309 | { |
4310 | rtx const im8 = GEN_INT (-8); | |
4311 | rtx const i64 = GEN_INT (64); | |
34377880 | 4312 | rtx ins_tmps[MAX_MOVE_WORDS]; |
2cc46ade | 4313 | rtx st_tmp_1, st_tmp_2, dreg; |
1f0ce6a6 | 4314 | rtx st_addr_1, st_addr_2, dmema; |
34377880 | 4315 | HOST_WIDE_INT i; |
4316 | ||
1f0ce6a6 | 4317 | dmema = XEXP (dmem, 0); |
4318 | if (GET_CODE (dmema) == LO_SUM) | |
4319 | dmema = force_reg (Pmode, dmema); | |
4320 | ||
34377880 | 4321 | /* Generate all the tmp registers we need. */ |
4322 | if (data_regs != NULL) | |
4323 | for (i = 0; i < words; ++i) | |
4324 | ins_tmps[i] = gen_reg_rtx(DImode); | |
4325 | st_tmp_1 = gen_reg_rtx(DImode); | |
4326 | st_tmp_2 = gen_reg_rtx(DImode); | |
4327 | ||
2cc46ade | 4328 | if (ofs != 0) |
e513d163 | 4329 | dmem = adjust_address (dmem, GET_MODE (dmem), ofs); |
2cc46ade | 4330 | |
4331 | st_addr_2 = change_address (dmem, DImode, | |
941522d6 | 4332 | gen_rtx_AND (DImode, |
1f0ce6a6 | 4333 | plus_constant (dmema, words*8 - 1), |
34377880 | 4334 | im8)); |
ab6ab77e | 4335 | set_mem_alias_set (st_addr_2, 0); |
3024e9f8 | 4336 | |
2cc46ade | 4337 | st_addr_1 = change_address (dmem, DImode, |
1f0ce6a6 | 4338 | gen_rtx_AND (DImode, dmema, im8)); |
ab6ab77e | 4339 | set_mem_alias_set (st_addr_1, 0); |
34377880 | 4340 | |
4341 | /* Load up the destination end bits. */ | |
4342 | emit_move_insn (st_tmp_2, st_addr_2); | |
4343 | emit_move_insn (st_tmp_1, st_addr_1); | |
4344 | ||
4345 | /* Shift the input data into place. */ | |
1f0ce6a6 | 4346 | dreg = copy_addr_to_reg (dmema); |
9caef960 | 4347 | if (WORDS_BIG_ENDIAN) |
4348 | emit_move_insn (dreg, plus_constant (dreg, 7)); | |
34377880 | 4349 | if (data_regs != NULL) |
4350 | { | |
4351 | for (i = words-1; i >= 0; --i) | |
4352 | { | |
9caef960 | 4353 | if (WORDS_BIG_ENDIAN) |
4354 | { | |
4355 | emit_insn (gen_insql_be (ins_tmps[i], data_regs[i], dreg)); | |
4356 | emit_insn (gen_insxh (data_regs[i], data_regs[i], i64, dreg)); | |
4357 | } | |
4358 | else | |
4359 | { | |
4360 | emit_insn (gen_insxh (ins_tmps[i], data_regs[i], i64, dreg)); | |
4361 | emit_insn (gen_insql_le (data_regs[i], data_regs[i], dreg)); | |
4362 | } | |
34377880 | 4363 | } |
34377880 | 4364 | for (i = words-1; i > 0; --i) |
4365 | { | |
2cc46ade | 4366 | ins_tmps[i-1] = expand_binop (DImode, ior_optab, data_regs[i], |
4367 | ins_tmps[i-1], ins_tmps[i-1], 1, | |
4368 | OPTAB_WIDEN); | |
34377880 | 4369 | } |
4370 | } | |
4371 | ||
4372 | /* Split and merge the ends with the destination data. */ | |
9caef960 | 4373 | if (WORDS_BIG_ENDIAN) |
4374 | { | |
ae4cd3a5 | 4375 | emit_insn (gen_mskxl_be (st_tmp_2, st_tmp_2, constm1_rtx, dreg)); |
9caef960 | 4376 | emit_insn (gen_mskxh (st_tmp_1, st_tmp_1, i64, dreg)); |
4377 | } | |
4378 | else | |
4379 | { | |
4380 | emit_insn (gen_mskxh (st_tmp_2, st_tmp_2, i64, dreg)); | |
ae4cd3a5 | 4381 | emit_insn (gen_mskxl_le (st_tmp_1, st_tmp_1, constm1_rtx, dreg)); |
9caef960 | 4382 | } |
34377880 | 4383 | |
4384 | if (data_regs != NULL) | |
4385 | { | |
2cc46ade | 4386 | st_tmp_2 = expand_binop (DImode, ior_optab, st_tmp_2, ins_tmps[words-1], |
4387 | st_tmp_2, 1, OPTAB_WIDEN); | |
4388 | st_tmp_1 = expand_binop (DImode, ior_optab, st_tmp_1, data_regs[0], | |
4389 | st_tmp_1, 1, OPTAB_WIDEN); | |
34377880 | 4390 | } |
4391 | ||
4392 | /* Store it all. */ | |
9caef960 | 4393 | if (WORDS_BIG_ENDIAN) |
4394 | emit_move_insn (st_addr_1, st_tmp_1); | |
4395 | else | |
4396 | emit_move_insn (st_addr_2, st_tmp_2); | |
34377880 | 4397 | for (i = words-1; i > 0; --i) |
4398 | { | |
3024e9f8 | 4399 | rtx tmp = change_address (dmem, DImode, |
4400 | gen_rtx_AND (DImode, | |
9caef960 | 4401 | plus_constant(dmema, |
4402 | WORDS_BIG_ENDIAN ? i*8-1 : i*8), | |
3024e9f8 | 4403 | im8)); |
ab6ab77e | 4404 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 4405 | emit_move_insn (tmp, data_regs ? ins_tmps[i-1] : const0_rtx); |
34377880 | 4406 | } |
9caef960 | 4407 | if (WORDS_BIG_ENDIAN) |
4408 | emit_move_insn (st_addr_2, st_tmp_2); | |
4409 | else | |
4410 | emit_move_insn (st_addr_1, st_tmp_1); | |
34377880 | 4411 | } |
4412 | ||
4413 | ||
4414 | /* Expand string/block move operations. | |
4415 | ||
4416 | operands[0] is the pointer to the destination. | |
4417 | operands[1] is the pointer to the source. | |
4418 | operands[2] is the number of bytes to move. | |
4419 | operands[3] is the alignment. */ | |
4420 | ||
4421 | int | |
92643d95 | 4422 | alpha_expand_block_move (rtx operands[]) |
34377880 | 4423 | { |
4424 | rtx bytes_rtx = operands[2]; | |
4425 | rtx align_rtx = operands[3]; | |
d94b545b | 4426 | HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx); |
a9aaae37 | 4427 | HOST_WIDE_INT bytes = orig_bytes; |
4428 | HOST_WIDE_INT src_align = INTVAL (align_rtx) * BITS_PER_UNIT; | |
4429 | HOST_WIDE_INT dst_align = src_align; | |
80909c64 | 4430 | rtx orig_src = operands[1]; |
4431 | rtx orig_dst = operands[0]; | |
4432 | rtx data_regs[2 * MAX_MOVE_WORDS + 16]; | |
2cc46ade | 4433 | rtx tmp; |
1f0ce6a6 | 4434 | unsigned int i, words, ofs, nregs = 0; |
34377880 | 4435 | |
80909c64 | 4436 | if (orig_bytes <= 0) |
34377880 | 4437 | return 1; |
a9aaae37 | 4438 | else if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD) |
34377880 | 4439 | return 0; |
4440 | ||
2cc46ade | 4441 | /* Look for additional alignment information from recorded register info. */ |
4442 | ||
4443 | tmp = XEXP (orig_src, 0); | |
4444 | if (GET_CODE (tmp) == REG) | |
80909c64 | 4445 | src_align = MAX (src_align, REGNO_POINTER_ALIGN (REGNO (tmp))); |
2cc46ade | 4446 | else if (GET_CODE (tmp) == PLUS |
4447 | && GET_CODE (XEXP (tmp, 0)) == REG | |
4448 | && GET_CODE (XEXP (tmp, 1)) == CONST_INT) | |
4449 | { | |
80909c64 | 4450 | unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); |
4451 | unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); | |
2cc46ade | 4452 | |
4453 | if (a > src_align) | |
4454 | { | |
80909c64 | 4455 | if (a >= 64 && c % 8 == 0) |
4456 | src_align = 64; | |
4457 | else if (a >= 32 && c % 4 == 0) | |
4458 | src_align = 32; | |
4459 | else if (a >= 16 && c % 2 == 0) | |
4460 | src_align = 16; | |
2cc46ade | 4461 | } |
4462 | } | |
4463 | ||
4464 | tmp = XEXP (orig_dst, 0); | |
4465 | if (GET_CODE (tmp) == REG) | |
80909c64 | 4466 | dst_align = MAX (dst_align, REGNO_POINTER_ALIGN (REGNO (tmp))); |
2cc46ade | 4467 | else if (GET_CODE (tmp) == PLUS |
4468 | && GET_CODE (XEXP (tmp, 0)) == REG | |
4469 | && GET_CODE (XEXP (tmp, 1)) == CONST_INT) | |
4470 | { | |
80909c64 | 4471 | unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); |
4472 | unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); | |
2cc46ade | 4473 | |
4474 | if (a > dst_align) | |
4475 | { | |
80909c64 | 4476 | if (a >= 64 && c % 8 == 0) |
4477 | dst_align = 64; | |
4478 | else if (a >= 32 && c % 4 == 0) | |
4479 | dst_align = 32; | |
4480 | else if (a >= 16 && c % 2 == 0) | |
4481 | dst_align = 16; | |
2cc46ade | 4482 | } |
4483 | } | |
4484 | ||
2cc46ade | 4485 | ofs = 0; |
80909c64 | 4486 | if (src_align >= 64 && bytes >= 8) |
34377880 | 4487 | { |
4488 | words = bytes / 8; | |
4489 | ||
34377880 | 4490 | for (i = 0; i < words; ++i) |
27d0c333 | 4491 | data_regs[nregs + i] = gen_reg_rtx (DImode); |
34377880 | 4492 | |
34377880 | 4493 | for (i = 0; i < words; ++i) |
80909c64 | 4494 | emit_move_insn (data_regs[nregs + i], |
e513d163 | 4495 | adjust_address (orig_src, DImode, ofs + i * 8)); |
34377880 | 4496 | |
2cc46ade | 4497 | nregs += words; |
34377880 | 4498 | bytes -= words * 8; |
7597afe9 | 4499 | ofs += words * 8; |
34377880 | 4500 | } |
80909c64 | 4501 | |
4502 | if (src_align >= 32 && bytes >= 4) | |
34377880 | 4503 | { |
4504 | words = bytes / 4; | |
4505 | ||
34377880 | 4506 | for (i = 0; i < words; ++i) |
27d0c333 | 4507 | data_regs[nregs + i] = gen_reg_rtx (SImode); |
34377880 | 4508 | |
34377880 | 4509 | for (i = 0; i < words; ++i) |
80909c64 | 4510 | emit_move_insn (data_regs[nregs + i], |
537ffcfc | 4511 | adjust_address (orig_src, SImode, ofs + i * 4)); |
34377880 | 4512 | |
2cc46ade | 4513 | nregs += words; |
34377880 | 4514 | bytes -= words * 4; |
7597afe9 | 4515 | ofs += words * 4; |
34377880 | 4516 | } |
80909c64 | 4517 | |
a9aaae37 | 4518 | if (bytes >= 8) |
34377880 | 4519 | { |
4520 | words = bytes / 8; | |
4521 | ||
34377880 | 4522 | for (i = 0; i < words+1; ++i) |
27d0c333 | 4523 | data_regs[nregs + i] = gen_reg_rtx (DImode); |
34377880 | 4524 | |
b47268cf | 4525 | alpha_expand_unaligned_load_words (data_regs + nregs, orig_src, |
4526 | words, ofs); | |
34377880 | 4527 | |
2cc46ade | 4528 | nregs += words; |
34377880 | 4529 | bytes -= words * 8; |
7597afe9 | 4530 | ofs += words * 8; |
34377880 | 4531 | } |
80909c64 | 4532 | |
80909c64 | 4533 | if (! TARGET_BWX && bytes >= 4) |
34377880 | 4534 | { |
2cc46ade | 4535 | data_regs[nregs++] = tmp = gen_reg_rtx (SImode); |
34377880 | 4536 | alpha_expand_unaligned_load (tmp, orig_src, 4, ofs, 0); |
34377880 | 4537 | bytes -= 4; |
4538 | ofs += 4; | |
4539 | } | |
80909c64 | 4540 | |
34377880 | 4541 | if (bytes >= 2) |
4542 | { | |
80909c64 | 4543 | if (src_align >= 16) |
34377880 | 4544 | { |
4545 | do { | |
2cc46ade | 4546 | data_regs[nregs++] = tmp = gen_reg_rtx (HImode); |
e513d163 | 4547 | emit_move_insn (tmp, adjust_address (orig_src, HImode, ofs)); |
34377880 | 4548 | bytes -= 2; |
4549 | ofs += 2; | |
4550 | } while (bytes >= 2); | |
4551 | } | |
80909c64 | 4552 | else if (! TARGET_BWX) |
34377880 | 4553 | { |
2cc46ade | 4554 | data_regs[nregs++] = tmp = gen_reg_rtx (HImode); |
34377880 | 4555 | alpha_expand_unaligned_load (tmp, orig_src, 2, ofs, 0); |
34377880 | 4556 | bytes -= 2; |
4557 | ofs += 2; | |
4558 | } | |
4559 | } | |
80909c64 | 4560 | |
34377880 | 4561 | while (bytes > 0) |
4562 | { | |
2cc46ade | 4563 | data_regs[nregs++] = tmp = gen_reg_rtx (QImode); |
e513d163 | 4564 | emit_move_insn (tmp, adjust_address (orig_src, QImode, ofs)); |
34377880 | 4565 | bytes -= 1; |
4566 | ofs += 1; | |
4567 | } | |
80909c64 | 4568 | |
d6a88f01 | 4569 | if (nregs > ARRAY_SIZE (data_regs)) |
80909c64 | 4570 | abort (); |
2cc46ade | 4571 | |
80909c64 | 4572 | /* Now save it back out again. */ |
2cc46ade | 4573 | |
4574 | i = 0, ofs = 0; | |
4575 | ||
2cc46ade | 4576 | /* Write out the data in whatever chunks reading the source allowed. */ |
80909c64 | 4577 | if (dst_align >= 64) |
2cc46ade | 4578 | { |
4579 | while (i < nregs && GET_MODE (data_regs[i]) == DImode) | |
4580 | { | |
e513d163 | 4581 | emit_move_insn (adjust_address (orig_dst, DImode, ofs), |
2cc46ade | 4582 | data_regs[i]); |
4583 | ofs += 8; | |
4584 | i++; | |
4585 | } | |
4586 | } | |
80909c64 | 4587 | |
4588 | if (dst_align >= 32) | |
2cc46ade | 4589 | { |
4590 | /* If the source has remaining DImode regs, write them out in | |
4591 | two pieces. */ | |
4592 | while (i < nregs && GET_MODE (data_regs[i]) == DImode) | |
4593 | { | |
4594 | tmp = expand_binop (DImode, lshr_optab, data_regs[i], GEN_INT (32), | |
4595 | NULL_RTX, 1, OPTAB_WIDEN); | |
4596 | ||
e513d163 | 4597 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), |
2cc46ade | 4598 | gen_lowpart (SImode, data_regs[i])); |
e513d163 | 4599 | emit_move_insn (adjust_address (orig_dst, SImode, ofs + 4), |
2cc46ade | 4600 | gen_lowpart (SImode, tmp)); |
4601 | ofs += 8; | |
4602 | i++; | |
4603 | } | |
4604 | ||
4605 | while (i < nregs && GET_MODE (data_regs[i]) == SImode) | |
4606 | { | |
e513d163 | 4607 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), |
2cc46ade | 4608 | data_regs[i]); |
4609 | ofs += 4; | |
4610 | i++; | |
4611 | } | |
4612 | } | |
80909c64 | 4613 | |
2cc46ade | 4614 | if (i < nregs && GET_MODE (data_regs[i]) == DImode) |
4615 | { | |
4616 | /* Write out a remaining block of words using unaligned methods. */ | |
4617 | ||
80909c64 | 4618 | for (words = 1; i + words < nregs; words++) |
4619 | if (GET_MODE (data_regs[i + words]) != DImode) | |
2cc46ade | 4620 | break; |
4621 | ||
4622 | if (words == 1) | |
4623 | alpha_expand_unaligned_store (orig_dst, data_regs[i], 8, ofs); | |
4624 | else | |
80909c64 | 4625 | alpha_expand_unaligned_store_words (data_regs + i, orig_dst, |
4626 | words, ofs); | |
2cc46ade | 4627 | |
4628 | i += words; | |
4629 | ofs += words * 8; | |
4630 | } | |
4631 | ||
4632 | /* Due to the above, this won't be aligned. */ | |
4633 | /* ??? If we have more than one of these, consider constructing full | |
4634 | words in registers and using alpha_expand_unaligned_store_words. */ | |
4635 | while (i < nregs && GET_MODE (data_regs[i]) == SImode) | |
4636 | { | |
4637 | alpha_expand_unaligned_store (orig_dst, data_regs[i], 4, ofs); | |
4638 | ofs += 4; | |
4639 | i++; | |
4640 | } | |
4641 | ||
80909c64 | 4642 | if (dst_align >= 16) |
2cc46ade | 4643 | while (i < nregs && GET_MODE (data_regs[i]) == HImode) |
4644 | { | |
e513d163 | 4645 | emit_move_insn (adjust_address (orig_dst, HImode, ofs), data_regs[i]); |
2cc46ade | 4646 | i++; |
4647 | ofs += 2; | |
4648 | } | |
4649 | else | |
4650 | while (i < nregs && GET_MODE (data_regs[i]) == HImode) | |
4651 | { | |
4652 | alpha_expand_unaligned_store (orig_dst, data_regs[i], 2, ofs); | |
4653 | i++; | |
4654 | ofs += 2; | |
4655 | } | |
80909c64 | 4656 | |
2cc46ade | 4657 | while (i < nregs && GET_MODE (data_regs[i]) == QImode) |
4658 | { | |
e513d163 | 4659 | emit_move_insn (adjust_address (orig_dst, QImode, ofs), data_regs[i]); |
2cc46ade | 4660 | i++; |
4661 | ofs += 1; | |
4662 | } | |
80909c64 | 4663 | |
2cc46ade | 4664 | if (i != nregs) |
80909c64 | 4665 | abort (); |
34377880 | 4666 | |
4667 | return 1; | |
4668 | } | |
4669 | ||
4670 | int | |
92643d95 | 4671 | alpha_expand_block_clear (rtx operands[]) |
34377880 | 4672 | { |
4673 | rtx bytes_rtx = operands[1]; | |
4674 | rtx align_rtx = operands[2]; | |
80909c64 | 4675 | HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx); |
a9aaae37 | 4676 | HOST_WIDE_INT bytes = orig_bytes; |
4677 | HOST_WIDE_INT align = INTVAL (align_rtx) * BITS_PER_UNIT; | |
4678 | HOST_WIDE_INT alignofs = 0; | |
80909c64 | 4679 | rtx orig_dst = operands[0]; |
2cc46ade | 4680 | rtx tmp; |
a9aaae37 | 4681 | int i, words, ofs = 0; |
34377880 | 4682 | |
80909c64 | 4683 | if (orig_bytes <= 0) |
34377880 | 4684 | return 1; |
a9aaae37 | 4685 | if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD) |
34377880 | 4686 | return 0; |
4687 | ||
2cc46ade | 4688 | /* Look for stricter alignment. */ |
2cc46ade | 4689 | tmp = XEXP (orig_dst, 0); |
4690 | if (GET_CODE (tmp) == REG) | |
80909c64 | 4691 | align = MAX (align, REGNO_POINTER_ALIGN (REGNO (tmp))); |
2cc46ade | 4692 | else if (GET_CODE (tmp) == PLUS |
4693 | && GET_CODE (XEXP (tmp, 0)) == REG | |
4694 | && GET_CODE (XEXP (tmp, 1)) == CONST_INT) | |
4695 | { | |
a9aaae37 | 4696 | HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); |
4697 | int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); | |
2cc46ade | 4698 | |
4699 | if (a > align) | |
4700 | { | |
a9aaae37 | 4701 | if (a >= 64) |
4702 | align = a, alignofs = 8 - c % 8; | |
4703 | else if (a >= 32) | |
4704 | align = a, alignofs = 4 - c % 4; | |
4705 | else if (a >= 16) | |
4706 | align = a, alignofs = 2 - c % 2; | |
2cc46ade | 4707 | } |
4708 | } | |
4709 | ||
a9aaae37 | 4710 | /* Handle an unaligned prefix first. */ |
4711 | ||
4712 | if (alignofs > 0) | |
4713 | { | |
4714 | #if HOST_BITS_PER_WIDE_INT >= 64 | |
4715 | /* Given that alignofs is bounded by align, the only time BWX could | |
4716 | generate three stores is for a 7 byte fill. Prefer two individual | |
4717 | stores over a load/mask/store sequence. */ | |
4718 | if ((!TARGET_BWX || alignofs == 7) | |
4719 | && align >= 32 | |
4720 | && !(alignofs == 4 && bytes >= 4)) | |
4721 | { | |
4722 | enum machine_mode mode = (align >= 64 ? DImode : SImode); | |
4723 | int inv_alignofs = (align >= 64 ? 8 : 4) - alignofs; | |
4724 | rtx mem, tmp; | |
4725 | HOST_WIDE_INT mask; | |
4726 | ||
e513d163 | 4727 | mem = adjust_address (orig_dst, mode, ofs - inv_alignofs); |
ab6ab77e | 4728 | set_mem_alias_set (mem, 0); |
a9aaae37 | 4729 | |
4730 | mask = ~(~(HOST_WIDE_INT)0 << (inv_alignofs * 8)); | |
4731 | if (bytes < alignofs) | |
4732 | { | |
4733 | mask |= ~(HOST_WIDE_INT)0 << ((inv_alignofs + bytes) * 8); | |
4734 | ofs += bytes; | |
4735 | bytes = 0; | |
4736 | } | |
4737 | else | |
4738 | { | |
4739 | bytes -= alignofs; | |
4740 | ofs += alignofs; | |
4741 | } | |
4742 | alignofs = 0; | |
4743 | ||
4744 | tmp = expand_binop (mode, and_optab, mem, GEN_INT (mask), | |
4745 | NULL_RTX, 1, OPTAB_WIDEN); | |
4746 | ||
4747 | emit_move_insn (mem, tmp); | |
4748 | } | |
4749 | #endif | |
4750 | ||
4751 | if (TARGET_BWX && (alignofs & 1) && bytes >= 1) | |
4752 | { | |
e513d163 | 4753 | emit_move_insn (adjust_address (orig_dst, QImode, ofs), const0_rtx); |
a9aaae37 | 4754 | bytes -= 1; |
4755 | ofs += 1; | |
4756 | alignofs -= 1; | |
4757 | } | |
4758 | if (TARGET_BWX && align >= 16 && (alignofs & 3) == 2 && bytes >= 2) | |
4759 | { | |
e513d163 | 4760 | emit_move_insn (adjust_address (orig_dst, HImode, ofs), const0_rtx); |
a9aaae37 | 4761 | bytes -= 2; |
4762 | ofs += 2; | |
4763 | alignofs -= 2; | |
4764 | } | |
4765 | if (alignofs == 4 && bytes >= 4) | |
4766 | { | |
e513d163 | 4767 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx); |
a9aaae37 | 4768 | bytes -= 4; |
4769 | ofs += 4; | |
4770 | alignofs = 0; | |
4771 | } | |
4772 | ||
4773 | /* If we've not used the extra lead alignment information by now, | |
4774 | we won't be able to. Downgrade align to match what's left over. */ | |
4775 | if (alignofs > 0) | |
4776 | { | |
4777 | alignofs = alignofs & -alignofs; | |
4778 | align = MIN (align, alignofs * BITS_PER_UNIT); | |
4779 | } | |
4780 | } | |
4781 | ||
4782 | /* Handle a block of contiguous long-words. */ | |
34377880 | 4783 | |
80909c64 | 4784 | if (align >= 64 && bytes >= 8) |
34377880 | 4785 | { |
4786 | words = bytes / 8; | |
4787 | ||
4788 | for (i = 0; i < words; ++i) | |
1f0ce6a6 | 4789 | emit_move_insn (adjust_address (orig_dst, DImode, ofs + i * 8), |
e513d163 | 4790 | const0_rtx); |
34377880 | 4791 | |
4792 | bytes -= words * 8; | |
7597afe9 | 4793 | ofs += words * 8; |
34377880 | 4794 | } |
80909c64 | 4795 | |
a9aaae37 | 4796 | /* If the block is large and appropriately aligned, emit a single |
4797 | store followed by a sequence of stq_u insns. */ | |
4798 | ||
4799 | if (align >= 32 && bytes > 16) | |
4800 | { | |
1f0ce6a6 | 4801 | rtx orig_dsta; |
4802 | ||
e513d163 | 4803 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx); |
a9aaae37 | 4804 | bytes -= 4; |
4805 | ofs += 4; | |
4806 | ||
1f0ce6a6 | 4807 | orig_dsta = XEXP (orig_dst, 0); |
4808 | if (GET_CODE (orig_dsta) == LO_SUM) | |
4809 | orig_dsta = force_reg (Pmode, orig_dsta); | |
4810 | ||
a9aaae37 | 4811 | words = bytes / 8; |
4812 | for (i = 0; i < words; ++i) | |
4813 | { | |
ab6ab77e | 4814 | rtx mem |
4815 | = change_address (orig_dst, DImode, | |
4816 | gen_rtx_AND (DImode, | |
1f0ce6a6 | 4817 | plus_constant (orig_dsta, ofs + i*8), |
ab6ab77e | 4818 | GEN_INT (-8))); |
4819 | set_mem_alias_set (mem, 0); | |
a9aaae37 | 4820 | emit_move_insn (mem, const0_rtx); |
4821 | } | |
4822 | ||
4823 | /* Depending on the alignment, the first stq_u may have overlapped | |
4824 | with the initial stl, which means that the last stq_u didn't | |
4825 | write as much as it would appear. Leave those questionable bytes | |
4826 | unaccounted for. */ | |
4827 | bytes -= words * 8 - 4; | |
4828 | ofs += words * 8 - 4; | |
4829 | } | |
4830 | ||
4831 | /* Handle a smaller block of aligned words. */ | |
4832 | ||
4833 | if ((align >= 64 && bytes == 4) | |
4834 | || (align == 32 && bytes >= 4)) | |
34377880 | 4835 | { |
4836 | words = bytes / 4; | |
4837 | ||
4838 | for (i = 0; i < words; ++i) | |
e513d163 | 4839 | emit_move_insn (adjust_address (orig_dst, SImode, ofs + i * 4), |
80909c64 | 4840 | const0_rtx); |
34377880 | 4841 | |
4842 | bytes -= words * 4; | |
7597afe9 | 4843 | ofs += words * 4; |
34377880 | 4844 | } |
80909c64 | 4845 | |
a9aaae37 | 4846 | /* An unaligned block uses stq_u stores for as many as possible. */ |
4847 | ||
4848 | if (bytes >= 8) | |
34377880 | 4849 | { |
4850 | words = bytes / 8; | |
4851 | ||
7597afe9 | 4852 | alpha_expand_unaligned_store_words (NULL, orig_dst, words, ofs); |
34377880 | 4853 | |
4854 | bytes -= words * 8; | |
7597afe9 | 4855 | ofs += words * 8; |
34377880 | 4856 | } |
4857 | ||
a9aaae37 | 4858 | /* Next clean up any trailing pieces. */ |
34377880 | 4859 | |
a9aaae37 | 4860 | #if HOST_BITS_PER_WIDE_INT >= 64 |
4861 | /* Count the number of bits in BYTES for which aligned stores could | |
4862 | be emitted. */ | |
4863 | words = 0; | |
4864 | for (i = (TARGET_BWX ? 1 : 4); i * BITS_PER_UNIT <= align ; i <<= 1) | |
4865 | if (bytes & i) | |
4866 | words += 1; | |
4867 | ||
4868 | /* If we have appropriate alignment (and it wouldn't take too many | |
4869 | instructions otherwise), mask out the bytes we need. */ | |
4870 | if (TARGET_BWX ? words > 2 : bytes > 0) | |
4871 | { | |
4872 | if (align >= 64) | |
4873 | { | |
4874 | rtx mem, tmp; | |
4875 | HOST_WIDE_INT mask; | |
4876 | ||
e513d163 | 4877 | mem = adjust_address (orig_dst, DImode, ofs); |
ab6ab77e | 4878 | set_mem_alias_set (mem, 0); |
a9aaae37 | 4879 | |
4880 | mask = ~(HOST_WIDE_INT)0 << (bytes * 8); | |
4881 | ||
4882 | tmp = expand_binop (DImode, and_optab, mem, GEN_INT (mask), | |
4883 | NULL_RTX, 1, OPTAB_WIDEN); | |
4884 | ||
4885 | emit_move_insn (mem, tmp); | |
4886 | return 1; | |
4887 | } | |
4888 | else if (align >= 32 && bytes < 4) | |
4889 | { | |
4890 | rtx mem, tmp; | |
4891 | HOST_WIDE_INT mask; | |
4892 | ||
e513d163 | 4893 | mem = adjust_address (orig_dst, SImode, ofs); |
ab6ab77e | 4894 | set_mem_alias_set (mem, 0); |
a9aaae37 | 4895 | |
4896 | mask = ~(HOST_WIDE_INT)0 << (bytes * 8); | |
4897 | ||
4898 | tmp = expand_binop (SImode, and_optab, mem, GEN_INT (mask), | |
4899 | NULL_RTX, 1, OPTAB_WIDEN); | |
4900 | ||
4901 | emit_move_insn (mem, tmp); | |
4902 | return 1; | |
4903 | } | |
34377880 | 4904 | } |
a9aaae37 | 4905 | #endif |
80909c64 | 4906 | |
34377880 | 4907 | if (!TARGET_BWX && bytes >= 4) |
4908 | { | |
4909 | alpha_expand_unaligned_store (orig_dst, const0_rtx, 4, ofs); | |
4910 | bytes -= 4; | |
4911 | ofs += 4; | |
4912 | } | |
80909c64 | 4913 | |
34377880 | 4914 | if (bytes >= 2) |
4915 | { | |
80909c64 | 4916 | if (align >= 16) |
34377880 | 4917 | { |
4918 | do { | |
e513d163 | 4919 | emit_move_insn (adjust_address (orig_dst, HImode, ofs), |
34377880 | 4920 | const0_rtx); |
4921 | bytes -= 2; | |
4922 | ofs += 2; | |
4923 | } while (bytes >= 2); | |
4924 | } | |
80909c64 | 4925 | else if (! TARGET_BWX) |
34377880 | 4926 | { |
4927 | alpha_expand_unaligned_store (orig_dst, const0_rtx, 2, ofs); | |
4928 | bytes -= 2; | |
4929 | ofs += 2; | |
4930 | } | |
4931 | } | |
80909c64 | 4932 | |
34377880 | 4933 | while (bytes > 0) |
4934 | { | |
e513d163 | 4935 | emit_move_insn (adjust_address (orig_dst, QImode, ofs), const0_rtx); |
34377880 | 4936 | bytes -= 1; |
4937 | ofs += 1; | |
4938 | } | |
4939 | ||
4940 | return 1; | |
4941 | } | |
f2cc13dc | 4942 | |
4943 | /* Returns a mask so that zap(x, value) == x & mask. */ | |
4944 | ||
4945 | rtx | |
92643d95 | 4946 | alpha_expand_zap_mask (HOST_WIDE_INT value) |
f2cc13dc | 4947 | { |
4948 | rtx result; | |
4949 | int i; | |
4950 | ||
4951 | if (HOST_BITS_PER_WIDE_INT >= 64) | |
4952 | { | |
4953 | HOST_WIDE_INT mask = 0; | |
4954 | ||
4955 | for (i = 7; i >= 0; --i) | |
4956 | { | |
4957 | mask <<= 8; | |
4958 | if (!((value >> i) & 1)) | |
4959 | mask |= 0xff; | |
4960 | } | |
4961 | ||
4962 | result = gen_int_mode (mask, DImode); | |
4963 | } | |
4964 | else if (HOST_BITS_PER_WIDE_INT == 32) | |
4965 | { | |
4966 | HOST_WIDE_INT mask_lo = 0, mask_hi = 0; | |
4967 | ||
4968 | for (i = 7; i >= 4; --i) | |
4969 | { | |
4970 | mask_hi <<= 8; | |
4971 | if (!((value >> i) & 1)) | |
4972 | mask_hi |= 0xff; | |
4973 | } | |
4974 | ||
4975 | for (i = 3; i >= 0; --i) | |
4976 | { | |
4977 | mask_lo <<= 8; | |
4978 | if (!((value >> i) & 1)) | |
4979 | mask_lo |= 0xff; | |
4980 | } | |
4981 | ||
4982 | result = immed_double_const (mask_lo, mask_hi, DImode); | |
4983 | } | |
4984 | else | |
4985 | abort (); | |
4986 | ||
4987 | return result; | |
4988 | } | |
4989 | ||
4990 | void | |
92643d95 | 4991 | alpha_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx), |
4992 | enum machine_mode mode, | |
4993 | rtx op0, rtx op1, rtx op2) | |
f2cc13dc | 4994 | { |
4995 | op0 = gen_lowpart (mode, op0); | |
4996 | ||
4997 | if (op1 == const0_rtx) | |
4998 | op1 = CONST0_RTX (mode); | |
4999 | else | |
5000 | op1 = gen_lowpart (mode, op1); | |
ae4cd3a5 | 5001 | |
5002 | if (op2 == const0_rtx) | |
f2cc13dc | 5003 | op2 = CONST0_RTX (mode); |
5004 | else | |
5005 | op2 = gen_lowpart (mode, op2); | |
5006 | ||
5007 | emit_insn ((*gen) (op0, op1, op2)); | |
5008 | } | |
bf2a98b3 | 5009 | \f |
5010 | /* Adjust the cost of a scheduling dependency. Return the new cost of | |
5011 | a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ | |
5012 | ||
747af5e7 | 5013 | static int |
92643d95 | 5014 | alpha_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost) |
bf2a98b3 | 5015 | { |
d2832bd8 | 5016 | enum attr_type insn_type, dep_insn_type; |
bf2a98b3 | 5017 | |
5018 | /* If the dependence is an anti-dependence, there is no cost. For an | |
5019 | output dependence, there is sometimes a cost, but it doesn't seem | |
5020 | worth handling those few cases. */ | |
bf2a98b3 | 5021 | if (REG_NOTE_KIND (link) != 0) |
7eb0c947 | 5022 | return cost; |
bf2a98b3 | 5023 | |
d2832bd8 | 5024 | /* If we can't recognize the insns, we can't really do anything. */ |
5025 | if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0) | |
5026 | return cost; | |
5027 | ||
5028 | insn_type = get_attr_type (insn); | |
5029 | dep_insn_type = get_attr_type (dep_insn); | |
5030 | ||
07c1a295 | 5031 | /* Bring in the user-defined memory latency. */ |
e7a69d05 | 5032 | if (dep_insn_type == TYPE_ILD |
5033 | || dep_insn_type == TYPE_FLD | |
5034 | || dep_insn_type == TYPE_LDSYM) | |
07c1a295 | 5035 | cost += alpha_memory_latency-1; |
5036 | ||
7eb0c947 | 5037 | /* Everything else handled in DFA bypasses now. */ |
3680ac41 | 5038 | |
bf2a98b3 | 5039 | return cost; |
5040 | } | |
747af5e7 | 5041 | |
7eb0c947 | 5042 | /* The number of instructions that can be issued per cycle. */ |
5043 | ||
747af5e7 | 5044 | static int |
92643d95 | 5045 | alpha_issue_rate (void) |
747af5e7 | 5046 | { |
5047 | return (alpha_cpu == PROCESSOR_EV4 ? 2 : 4); | |
5048 | } | |
5049 | ||
7eb0c947 | 5050 | /* How many alternative schedules to try. This should be as wide as the |
5051 | scheduling freedom in the DFA, but no wider. Making this value too | |
5052 | large results extra work for the scheduler. | |
5053 | ||
5054 | For EV4, loads can be issued to either IB0 or IB1, thus we have 2 | |
5055 | alternative schedules. For EV5, we can choose between E0/E1 and | |
8d232dc7 | 5056 | FA/FM. For EV6, an arithmetic insn can be issued to U0/U1/L0/L1. */ |
7eb0c947 | 5057 | |
5058 | static int | |
92643d95 | 5059 | alpha_multipass_dfa_lookahead (void) |
7eb0c947 | 5060 | { |
5061 | return (alpha_cpu == PROCESSOR_EV6 ? 4 : 2); | |
5062 | } | |
0c0464e6 | 5063 | \f |
5f7b9df8 | 5064 | /* Machine-specific function data. */ |
5065 | ||
1f3233d1 | 5066 | struct machine_function GTY(()) |
5f7b9df8 | 5067 | { |
674a8f0b | 5068 | /* For unicosmk. */ |
5f7b9df8 | 5069 | /* List of call information words for calls from this function. */ |
5070 | struct rtx_def *first_ciw; | |
5071 | struct rtx_def *last_ciw; | |
5072 | int ciw_count; | |
5073 | ||
5074 | /* List of deferred case vectors. */ | |
5075 | struct rtx_def *addr_list; | |
1f3233d1 | 5076 | |
674a8f0b | 5077 | /* For OSF. */ |
5f7b9df8 | 5078 | const char *some_ld_name; |
a221313c | 5079 | |
5080 | /* For TARGET_LD_BUGGY_LDGP. */ | |
5081 | struct rtx_def *gp_save_rtx; | |
5f7b9df8 | 5082 | }; |
5083 | ||
1f3233d1 | 5084 | /* How to allocate a 'struct machine_function'. */ |
9caef960 | 5085 | |
1f3233d1 | 5086 | static struct machine_function * |
92643d95 | 5087 | alpha_init_machine_status (void) |
9caef960 | 5088 | { |
1f3233d1 | 5089 | return ((struct machine_function *) |
5090 | ggc_alloc_cleared (sizeof (struct machine_function))); | |
9caef960 | 5091 | } |
9caef960 | 5092 | |
0c0464e6 | 5093 | /* Functions to save and restore alpha_return_addr_rtx. */ |
5094 | ||
0c0464e6 | 5095 | /* Start the ball rolling with RETURN_ADDR_RTX. */ |
5096 | ||
5097 | rtx | |
92643d95 | 5098 | alpha_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) |
0c0464e6 | 5099 | { |
0c0464e6 | 5100 | if (count != 0) |
5101 | return const0_rtx; | |
5102 | ||
0f37b7a2 | 5103 | return get_hard_reg_initial_val (Pmode, REG_RA); |
0c0464e6 | 5104 | } |
5105 | ||
a221313c | 5106 | /* Return or create a memory slot containing the gp value for the current |
66561750 | 5107 | function. Needed only if TARGET_LD_BUGGY_LDGP. */ |
5108 | ||
5109 | rtx | |
92643d95 | 5110 | alpha_gp_save_rtx (void) |
66561750 | 5111 | { |
a221313c | 5112 | rtx seq, m = cfun->machine->gp_save_rtx; |
5113 | ||
5114 | if (m == NULL) | |
5115 | { | |
5116 | start_sequence (); | |
5117 | ||
5118 | m = assign_stack_local (DImode, UNITS_PER_WORD, BITS_PER_WORD); | |
5119 | m = validize_mem (m); | |
5120 | emit_move_insn (m, pic_offset_table_rtx); | |
5121 | ||
5122 | seq = get_insns (); | |
5123 | end_sequence (); | |
5124 | emit_insn_after (seq, entry_of_function ()); | |
5125 | ||
5126 | cfun->machine->gp_save_rtx = m; | |
5127 | } | |
5128 | ||
5129 | return m; | |
66561750 | 5130 | } |
5131 | ||
0c0464e6 | 5132 | static int |
92643d95 | 5133 | alpha_ra_ever_killed (void) |
0c0464e6 | 5134 | { |
5a965225 | 5135 | rtx top; |
5136 | ||
0f37b7a2 | 5137 | if (!has_hard_reg_initial_val (Pmode, REG_RA)) |
0c0464e6 | 5138 | return regs_ever_live[REG_RA]; |
5139 | ||
5a965225 | 5140 | push_topmost_sequence (); |
5141 | top = get_insns (); | |
5142 | pop_topmost_sequence (); | |
5143 | ||
5144 | return reg_set_between_p (gen_rtx_REG (Pmode, REG_RA), top, NULL_RTX); | |
0c0464e6 | 5145 | } |
5146 | ||
bf2a98b3 | 5147 | \f |
6fec94c5 | 5148 | /* Return the trap mode suffix applicable to the current |
65abff06 | 5149 | instruction, or NULL. */ |
bf2a98b3 | 5150 | |
6fec94c5 | 5151 | static const char * |
92643d95 | 5152 | get_trap_mode_suffix (void) |
bf2a98b3 | 5153 | { |
6fec94c5 | 5154 | enum attr_trap_suffix s = get_attr_trap_suffix (current_output_insn); |
bf2a98b3 | 5155 | |
6fec94c5 | 5156 | switch (s) |
bf2a98b3 | 5157 | { |
6fec94c5 | 5158 | case TRAP_SUFFIX_NONE: |
5159 | return NULL; | |
c4622276 | 5160 | |
6fec94c5 | 5161 | case TRAP_SUFFIX_SU: |
bc16f0c1 | 5162 | if (alpha_fptm >= ALPHA_FPTM_SU) |
6fec94c5 | 5163 | return "su"; |
5164 | return NULL; | |
c4622276 | 5165 | |
6fec94c5 | 5166 | case TRAP_SUFFIX_SUI: |
5167 | if (alpha_fptm >= ALPHA_FPTM_SUI) | |
5168 | return "sui"; | |
5169 | return NULL; | |
5170 | ||
5171 | case TRAP_SUFFIX_V_SV: | |
39344852 | 5172 | switch (alpha_fptm) |
5173 | { | |
5174 | case ALPHA_FPTM_N: | |
6fec94c5 | 5175 | return NULL; |
39344852 | 5176 | case ALPHA_FPTM_U: |
6fec94c5 | 5177 | return "v"; |
39344852 | 5178 | case ALPHA_FPTM_SU: |
5179 | case ALPHA_FPTM_SUI: | |
6fec94c5 | 5180 | return "sv"; |
39344852 | 5181 | } |
5182 | break; | |
5183 | ||
6fec94c5 | 5184 | case TRAP_SUFFIX_V_SV_SVI: |
b5ea3193 | 5185 | switch (alpha_fptm) |
5186 | { | |
5187 | case ALPHA_FPTM_N: | |
6fec94c5 | 5188 | return NULL; |
b5ea3193 | 5189 | case ALPHA_FPTM_U: |
6fec94c5 | 5190 | return "v"; |
b5ea3193 | 5191 | case ALPHA_FPTM_SU: |
6fec94c5 | 5192 | return "sv"; |
b5ea3193 | 5193 | case ALPHA_FPTM_SUI: |
6fec94c5 | 5194 | return "svi"; |
b5ea3193 | 5195 | } |
5196 | break; | |
5197 | ||
6fec94c5 | 5198 | case TRAP_SUFFIX_U_SU_SUI: |
c4622276 | 5199 | switch (alpha_fptm) |
5200 | { | |
5201 | case ALPHA_FPTM_N: | |
6fec94c5 | 5202 | return NULL; |
c4622276 | 5203 | case ALPHA_FPTM_U: |
6fec94c5 | 5204 | return "u"; |
c4622276 | 5205 | case ALPHA_FPTM_SU: |
6fec94c5 | 5206 | return "su"; |
c4622276 | 5207 | case ALPHA_FPTM_SUI: |
6fec94c5 | 5208 | return "sui"; |
c4622276 | 5209 | } |
5210 | break; | |
6fec94c5 | 5211 | } |
5212 | abort (); | |
5213 | } | |
c4622276 | 5214 | |
6fec94c5 | 5215 | /* Return the rounding mode suffix applicable to the current |
65abff06 | 5216 | instruction, or NULL. */ |
6fec94c5 | 5217 | |
5218 | static const char * | |
92643d95 | 5219 | get_round_mode_suffix (void) |
6fec94c5 | 5220 | { |
5221 | enum attr_round_suffix s = get_attr_round_suffix (current_output_insn); | |
5222 | ||
5223 | switch (s) | |
5224 | { | |
5225 | case ROUND_SUFFIX_NONE: | |
5226 | return NULL; | |
5227 | case ROUND_SUFFIX_NORMAL: | |
5228 | switch (alpha_fprm) | |
c4622276 | 5229 | { |
6fec94c5 | 5230 | case ALPHA_FPRM_NORM: |
5231 | return NULL; | |
5232 | case ALPHA_FPRM_MINF: | |
5233 | return "m"; | |
5234 | case ALPHA_FPRM_CHOP: | |
5235 | return "c"; | |
5236 | case ALPHA_FPRM_DYN: | |
5237 | return "d"; | |
c4622276 | 5238 | } |
5239 | break; | |
5240 | ||
6fec94c5 | 5241 | case ROUND_SUFFIX_C: |
5242 | return "c"; | |
5243 | } | |
5244 | abort (); | |
5245 | } | |
5246 | ||
5f7b9df8 | 5247 | /* Locate some local-dynamic symbol still in use by this function |
5248 | so that we can print its name in some movdi_er_tlsldm pattern. */ | |
5249 | ||
92643d95 | 5250 | static int |
5251 | get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED) | |
5252 | { | |
5253 | rtx x = *px; | |
5254 | ||
5255 | if (GET_CODE (x) == SYMBOL_REF | |
5256 | && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC) | |
5257 | { | |
5258 | cfun->machine->some_ld_name = XSTR (x, 0); | |
5259 | return 1; | |
5260 | } | |
5261 | ||
5262 | return 0; | |
5263 | } | |
5264 | ||
5f7b9df8 | 5265 | static const char * |
92643d95 | 5266 | get_some_local_dynamic_name (void) |
5f7b9df8 | 5267 | { |
5268 | rtx insn; | |
5269 | ||
5270 | if (cfun->machine->some_ld_name) | |
5271 | return cfun->machine->some_ld_name; | |
5272 | ||
5273 | for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) | |
5274 | if (INSN_P (insn) | |
5275 | && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0)) | |
5276 | return cfun->machine->some_ld_name; | |
5277 | ||
5278 | abort (); | |
5279 | } | |
5280 | ||
6fec94c5 | 5281 | /* Print an operand. Recognize special options, documented below. */ |
5282 | ||
5283 | void | |
92643d95 | 5284 | print_operand (FILE *file, rtx x, int code) |
6fec94c5 | 5285 | { |
5286 | int i; | |
5287 | ||
5288 | switch (code) | |
5289 | { | |
5290 | case '~': | |
5291 | /* Print the assembler name of the current function. */ | |
5292 | assemble_name (file, alpha_fnname); | |
5293 | break; | |
5294 | ||
5f7b9df8 | 5295 | case '&': |
5296 | assemble_name (file, get_some_local_dynamic_name ()); | |
5297 | break; | |
5298 | ||
6fec94c5 | 5299 | case '/': |
5300 | { | |
5301 | const char *trap = get_trap_mode_suffix (); | |
5302 | const char *round = get_round_mode_suffix (); | |
5303 | ||
5304 | if (trap || round) | |
9caef960 | 5305 | fprintf (file, (TARGET_AS_SLASH_BEFORE_SUFFIX ? "/%s%s" : "%s%s"), |
5306 | (trap ? trap : ""), (round ? round : "")); | |
6fec94c5 | 5307 | break; |
5308 | } | |
5309 | ||
8df4a58b | 5310 | case ',': |
5311 | /* Generates single precision instruction suffix. */ | |
6fec94c5 | 5312 | fputc ((TARGET_FLOAT_VAX ? 'f' : 's'), file); |
8df4a58b | 5313 | break; |
5314 | ||
5315 | case '-': | |
5316 | /* Generates double precision instruction suffix. */ | |
6fec94c5 | 5317 | fputc ((TARGET_FLOAT_VAX ? 'g' : 't'), file); |
8df4a58b | 5318 | break; |
5319 | ||
822c7fc8 | 5320 | case '+': |
5321 | /* Generates a nop after a noreturn call at the very end of the | |
5322 | function. */ | |
5323 | if (next_real_insn (current_output_insn) == 0) | |
5324 | fprintf (file, "\n\tnop"); | |
5325 | break; | |
5326 | ||
1f0ce6a6 | 5327 | case '#': |
5328 | if (alpha_this_literal_sequence_number == 0) | |
5329 | alpha_this_literal_sequence_number = alpha_next_sequence_number++; | |
5330 | fprintf (file, "%d", alpha_this_literal_sequence_number); | |
5331 | break; | |
5332 | ||
5333 | case '*': | |
5334 | if (alpha_this_gpdisp_sequence_number == 0) | |
5335 | alpha_this_gpdisp_sequence_number = alpha_next_sequence_number++; | |
5336 | fprintf (file, "%d", alpha_this_gpdisp_sequence_number); | |
5337 | break; | |
5338 | ||
5339 | case 'H': | |
5340 | if (GET_CODE (x) == HIGH) | |
5dcb037d | 5341 | output_addr_const (file, XEXP (x, 0)); |
1f0ce6a6 | 5342 | else |
5343 | output_operand_lossage ("invalid %%H value"); | |
5344 | break; | |
5345 | ||
ad2ed779 | 5346 | case 'J': |
5f7b9df8 | 5347 | { |
5348 | const char *lituse; | |
5349 | ||
5350 | if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD_CALL) | |
5351 | { | |
5352 | x = XVECEXP (x, 0, 0); | |
5353 | lituse = "lituse_tlsgd"; | |
5354 | } | |
5355 | else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSLDM_CALL) | |
5356 | { | |
5357 | x = XVECEXP (x, 0, 0); | |
5358 | lituse = "lituse_tlsldm"; | |
5359 | } | |
5360 | else if (GET_CODE (x) == CONST_INT) | |
5361 | lituse = "lituse_jsr"; | |
5362 | else | |
5363 | { | |
5364 | output_operand_lossage ("invalid %%J value"); | |
5365 | break; | |
5366 | } | |
5367 | ||
5368 | if (x != const0_rtx) | |
5369 | fprintf (file, "\t\t!%s!%d", lituse, (int) INTVAL (x)); | |
5370 | } | |
ad2ed779 | 5371 | break; |
5372 | ||
bf2a98b3 | 5373 | case 'r': |
5374 | /* If this operand is the constant zero, write it as "$31". */ | |
5375 | if (GET_CODE (x) == REG) | |
5376 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
5377 | else if (x == CONST0_RTX (GET_MODE (x))) | |
5378 | fprintf (file, "$31"); | |
5379 | else | |
5380 | output_operand_lossage ("invalid %%r value"); | |
bf2a98b3 | 5381 | break; |
5382 | ||
5383 | case 'R': | |
5384 | /* Similar, but for floating-point. */ | |
5385 | if (GET_CODE (x) == REG) | |
5386 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
5387 | else if (x == CONST0_RTX (GET_MODE (x))) | |
5388 | fprintf (file, "$f31"); | |
5389 | else | |
5390 | output_operand_lossage ("invalid %%R value"); | |
bf2a98b3 | 5391 | break; |
5392 | ||
5393 | case 'N': | |
5394 | /* Write the 1's complement of a constant. */ | |
5395 | if (GET_CODE (x) != CONST_INT) | |
5396 | output_operand_lossage ("invalid %%N value"); | |
5397 | ||
61a63ca5 | 5398 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INTVAL (x)); |
bf2a98b3 | 5399 | break; |
5400 | ||
5401 | case 'P': | |
5402 | /* Write 1 << C, for a constant C. */ | |
5403 | if (GET_CODE (x) != CONST_INT) | |
5404 | output_operand_lossage ("invalid %%P value"); | |
5405 | ||
61a63ca5 | 5406 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT) 1 << INTVAL (x)); |
bf2a98b3 | 5407 | break; |
5408 | ||
5409 | case 'h': | |
5410 | /* Write the high-order 16 bits of a constant, sign-extended. */ | |
5411 | if (GET_CODE (x) != CONST_INT) | |
5412 | output_operand_lossage ("invalid %%h value"); | |
5413 | ||
61a63ca5 | 5414 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) >> 16); |
bf2a98b3 | 5415 | break; |
5416 | ||
5417 | case 'L': | |
5418 | /* Write the low-order 16 bits of a constant, sign-extended. */ | |
5419 | if (GET_CODE (x) != CONST_INT) | |
5420 | output_operand_lossage ("invalid %%L value"); | |
5421 | ||
61a63ca5 | 5422 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, |
5423 | (INTVAL (x) & 0xffff) - 2 * (INTVAL (x) & 0x8000)); | |
bf2a98b3 | 5424 | break; |
5425 | ||
5426 | case 'm': | |
5427 | /* Write mask for ZAP insn. */ | |
5428 | if (GET_CODE (x) == CONST_DOUBLE) | |
5429 | { | |
5430 | HOST_WIDE_INT mask = 0; | |
5431 | HOST_WIDE_INT value; | |
5432 | ||
5433 | value = CONST_DOUBLE_LOW (x); | |
5434 | for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; | |
5435 | i++, value >>= 8) | |
5436 | if (value & 0xff) | |
5437 | mask |= (1 << i); | |
5438 | ||
5439 | value = CONST_DOUBLE_HIGH (x); | |
5440 | for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; | |
5441 | i++, value >>= 8) | |
5442 | if (value & 0xff) | |
5443 | mask |= (1 << (i + sizeof (int))); | |
5444 | ||
61a63ca5 | 5445 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask & 0xff); |
bf2a98b3 | 5446 | } |
5447 | ||
5448 | else if (GET_CODE (x) == CONST_INT) | |
5449 | { | |
5450 | HOST_WIDE_INT mask = 0, value = INTVAL (x); | |
5451 | ||
5452 | for (i = 0; i < 8; i++, value >>= 8) | |
5453 | if (value & 0xff) | |
5454 | mask |= (1 << i); | |
5455 | ||
61a63ca5 | 5456 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask); |
bf2a98b3 | 5457 | } |
5458 | else | |
5459 | output_operand_lossage ("invalid %%m value"); | |
5460 | break; | |
5461 | ||
5462 | case 'M': | |
34377880 | 5463 | /* 'b', 'w', 'l', or 'q' as the value of the constant. */ |
bf2a98b3 | 5464 | if (GET_CODE (x) != CONST_INT |
34377880 | 5465 | || (INTVAL (x) != 8 && INTVAL (x) != 16 |
5466 | && INTVAL (x) != 32 && INTVAL (x) != 64)) | |
bf2a98b3 | 5467 | output_operand_lossage ("invalid %%M value"); |
5468 | ||
5469 | fprintf (file, "%s", | |
34377880 | 5470 | (INTVAL (x) == 8 ? "b" |
5471 | : INTVAL (x) == 16 ? "w" | |
5472 | : INTVAL (x) == 32 ? "l" | |
5473 | : "q")); | |
bf2a98b3 | 5474 | break; |
5475 | ||
5476 | case 'U': | |
5477 | /* Similar, except do it from the mask. */ | |
ae4cd3a5 | 5478 | if (GET_CODE (x) == CONST_INT) |
5479 | { | |
5480 | HOST_WIDE_INT value = INTVAL (x); | |
5481 | ||
5482 | if (value == 0xff) | |
5483 | { | |
5484 | fputc ('b', file); | |
5485 | break; | |
5486 | } | |
5487 | if (value == 0xffff) | |
5488 | { | |
5489 | fputc ('w', file); | |
5490 | break; | |
5491 | } | |
5492 | if (value == 0xffffffff) | |
5493 | { | |
5494 | fputc ('l', file); | |
5495 | break; | |
5496 | } | |
5497 | if (value == -1) | |
5498 | { | |
5499 | fputc ('q', file); | |
5500 | break; | |
5501 | } | |
5502 | } | |
5503 | else if (HOST_BITS_PER_WIDE_INT == 32 | |
5504 | && GET_CODE (x) == CONST_DOUBLE | |
5505 | && CONST_DOUBLE_LOW (x) == 0xffffffff | |
5506 | && CONST_DOUBLE_HIGH (x) == 0) | |
5507 | { | |
5508 | fputc ('l', file); | |
5509 | break; | |
5510 | } | |
5511 | output_operand_lossage ("invalid %%U value"); | |
bf2a98b3 | 5512 | break; |
5513 | ||
5514 | case 's': | |
9caef960 | 5515 | /* Write the constant value divided by 8 for little-endian mode or |
5516 | (56 - value) / 8 for big-endian mode. */ | |
5517 | ||
bf2a98b3 | 5518 | if (GET_CODE (x) != CONST_INT |
9caef960 | 5519 | || (unsigned HOST_WIDE_INT) INTVAL (x) >= (WORDS_BIG_ENDIAN |
5520 | ? 56 | |
5521 | : 64) | |
5522 | || (INTVAL (x) & 7) != 0) | |
bf2a98b3 | 5523 | output_operand_lossage ("invalid %%s value"); |
5524 | ||
9caef960 | 5525 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, |
5526 | WORDS_BIG_ENDIAN | |
5527 | ? (56 - INTVAL (x)) / 8 | |
5528 | : INTVAL (x) / 8); | |
bf2a98b3 | 5529 | break; |
5530 | ||
5531 | case 'S': | |
5532 | /* Same, except compute (64 - c) / 8 */ | |
5533 | ||
5534 | if (GET_CODE (x) != CONST_INT | |
5535 | && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 | |
5536 | && (INTVAL (x) & 7) != 8) | |
5537 | output_operand_lossage ("invalid %%s value"); | |
5538 | ||
61a63ca5 | 5539 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, (64 - INTVAL (x)) / 8); |
bf2a98b3 | 5540 | break; |
5541 | ||
9caef960 | 5542 | case 't': |
5543 | { | |
5544 | /* On Unicos/Mk systems: use a DEX expression if the symbol | |
5545 | clashes with a register name. */ | |
5546 | int dex = unicosmk_need_dex (x); | |
5547 | if (dex) | |
5548 | fprintf (file, "DEX(%d)", dex); | |
5549 | else | |
5550 | output_addr_const (file, x); | |
5551 | } | |
5552 | break; | |
5553 | ||
62dc3582 | 5554 | case 'C': case 'D': case 'c': case 'd': |
bf2a98b3 | 5555 | /* Write out comparison name. */ |
62dc3582 | 5556 | { |
5557 | enum rtx_code c = GET_CODE (x); | |
5558 | ||
6720e96c | 5559 | if (!COMPARISON_P (x)) |
62dc3582 | 5560 | output_operand_lossage ("invalid %%C value"); |
5561 | ||
f3d263a7 | 5562 | else if (code == 'D') |
62dc3582 | 5563 | c = reverse_condition (c); |
5564 | else if (code == 'c') | |
5565 | c = swap_condition (c); | |
5566 | else if (code == 'd') | |
5567 | c = swap_condition (reverse_condition (c)); | |
5568 | ||
5569 | if (c == LEU) | |
5570 | fprintf (file, "ule"); | |
5571 | else if (c == LTU) | |
5572 | fprintf (file, "ult"); | |
a4110d9a | 5573 | else if (c == UNORDERED) |
5574 | fprintf (file, "un"); | |
62dc3582 | 5575 | else |
5576 | fprintf (file, "%s", GET_RTX_NAME (c)); | |
5577 | } | |
8ad50a44 | 5578 | break; |
5579 | ||
bf2a98b3 | 5580 | case 'E': |
5581 | /* Write the divide or modulus operator. */ | |
5582 | switch (GET_CODE (x)) | |
5583 | { | |
5584 | case DIV: | |
5585 | fprintf (file, "div%s", GET_MODE (x) == SImode ? "l" : "q"); | |
5586 | break; | |
5587 | case UDIV: | |
5588 | fprintf (file, "div%su", GET_MODE (x) == SImode ? "l" : "q"); | |
5589 | break; | |
5590 | case MOD: | |
5591 | fprintf (file, "rem%s", GET_MODE (x) == SImode ? "l" : "q"); | |
5592 | break; | |
5593 | case UMOD: | |
5594 | fprintf (file, "rem%su", GET_MODE (x) == SImode ? "l" : "q"); | |
5595 | break; | |
5596 | default: | |
5597 | output_operand_lossage ("invalid %%E value"); | |
5598 | break; | |
5599 | } | |
5600 | break; | |
5601 | ||
bf2a98b3 | 5602 | case 'A': |
5603 | /* Write "_u" for unaligned access. */ | |
5604 | if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == AND) | |
5605 | fprintf (file, "_u"); | |
5606 | break; | |
5607 | ||
5608 | case 0: | |
5609 | if (GET_CODE (x) == REG) | |
5610 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
5611 | else if (GET_CODE (x) == MEM) | |
5612 | output_address (XEXP (x, 0)); | |
5f7b9df8 | 5613 | else if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC) |
5614 | { | |
5615 | switch (XINT (XEXP (x, 0), 1)) | |
5616 | { | |
5617 | case UNSPEC_DTPREL: | |
5618 | case UNSPEC_TPREL: | |
5619 | output_addr_const (file, XVECEXP (XEXP (x, 0), 0, 0)); | |
5620 | break; | |
5621 | default: | |
5622 | output_operand_lossage ("unknown relocation unspec"); | |
5623 | break; | |
5624 | } | |
5625 | } | |
bf2a98b3 | 5626 | else |
5627 | output_addr_const (file, x); | |
5628 | break; | |
5629 | ||
5630 | default: | |
5631 | output_operand_lossage ("invalid %%xn code"); | |
5632 | } | |
5633 | } | |
6e0fe99e | 5634 | |
5635 | void | |
92643d95 | 5636 | print_operand_address (FILE *file, rtx addr) |
6e0fe99e | 5637 | { |
a3e39a24 | 5638 | int basereg = 31; |
6e0fe99e | 5639 | HOST_WIDE_INT offset = 0; |
5640 | ||
5641 | if (GET_CODE (addr) == AND) | |
5642 | addr = XEXP (addr, 0); | |
6e0fe99e | 5643 | |
a3e39a24 | 5644 | if (GET_CODE (addr) == PLUS |
5645 | && GET_CODE (XEXP (addr, 1)) == CONST_INT) | |
6e0fe99e | 5646 | { |
5647 | offset = INTVAL (XEXP (addr, 1)); | |
a3e39a24 | 5648 | addr = XEXP (addr, 0); |
6e0fe99e | 5649 | } |
1f0ce6a6 | 5650 | |
5651 | if (GET_CODE (addr) == LO_SUM) | |
5652 | { | |
5f7b9df8 | 5653 | const char *reloc16, *reloclo; |
5654 | rtx op1 = XEXP (addr, 1); | |
5655 | ||
5656 | if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1, 0)) == UNSPEC) | |
5657 | { | |
5658 | op1 = XEXP (op1, 0); | |
5659 | switch (XINT (op1, 1)) | |
5660 | { | |
5661 | case UNSPEC_DTPREL: | |
5662 | reloc16 = NULL; | |
5663 | reloclo = (alpha_tls_size == 16 ? "dtprel" : "dtprello"); | |
5664 | break; | |
5665 | case UNSPEC_TPREL: | |
5666 | reloc16 = NULL; | |
5667 | reloclo = (alpha_tls_size == 16 ? "tprel" : "tprello"); | |
5668 | break; | |
5669 | default: | |
5670 | output_operand_lossage ("unknown relocation unspec"); | |
5671 | return; | |
5672 | } | |
5673 | ||
5674 | output_addr_const (file, XVECEXP (op1, 0, 0)); | |
5675 | } | |
5676 | else | |
5677 | { | |
5678 | reloc16 = "gprel"; | |
5679 | reloclo = "gprellow"; | |
5680 | output_addr_const (file, op1); | |
5681 | } | |
5682 | ||
1f0ce6a6 | 5683 | if (offset) |
4840a03a | 5684 | fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset); |
1f0ce6a6 | 5685 | |
5686 | addr = XEXP (addr, 0); | |
5687 | if (GET_CODE (addr) == REG) | |
5688 | basereg = REGNO (addr); | |
5689 | else if (GET_CODE (addr) == SUBREG | |
5690 | && GET_CODE (SUBREG_REG (addr)) == REG) | |
5691 | basereg = subreg_regno (addr); | |
5692 | else | |
5693 | abort (); | |
5dcb037d | 5694 | |
5695 | fprintf (file, "($%d)\t\t!%s", basereg, | |
5f7b9df8 | 5696 | (basereg == 29 ? reloc16 : reloclo)); |
1f0ce6a6 | 5697 | return; |
5698 | } | |
5699 | ||
a3e39a24 | 5700 | if (GET_CODE (addr) == REG) |
5701 | basereg = REGNO (addr); | |
5702 | else if (GET_CODE (addr) == SUBREG | |
5703 | && GET_CODE (SUBREG_REG (addr)) == REG) | |
1f0ce6a6 | 5704 | basereg = subreg_regno (addr); |
a3e39a24 | 5705 | else if (GET_CODE (addr) == CONST_INT) |
5706 | offset = INTVAL (addr); | |
cf73d31f | 5707 | |
5708 | #if TARGET_ABI_OPEN_VMS | |
5709 | else if (GET_CODE (addr) == SYMBOL_REF) | |
5710 | { | |
5711 | fprintf (file, "%s", XSTR (addr, 0)); | |
5712 | return; | |
5713 | } | |
5714 | else if (GET_CODE (addr) == CONST | |
5715 | && GET_CODE (XEXP (addr, 0)) == PLUS | |
5716 | && GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF) | |
5717 | { | |
6433714e | 5718 | fprintf (file, "%s+" HOST_WIDE_INT_PRINT_DEC, |
cf73d31f | 5719 | XSTR (XEXP (XEXP (addr, 0), 0), 0), |
5720 | INTVAL (XEXP (XEXP (addr, 0), 1))); | |
5721 | return; | |
5722 | } | |
5723 | #endif | |
5724 | ||
6e0fe99e | 5725 | else |
5726 | abort (); | |
5727 | ||
4840a03a | 5728 | fprintf (file, HOST_WIDE_INT_PRINT_DEC "($%d)", offset, basereg); |
6e0fe99e | 5729 | } |
bf2a98b3 | 5730 | \f |
9e042f31 | 5731 | /* Emit RTL insns to initialize the variable parts of a trampoline at |
5732 | TRAMP. FNADDR is an RTX for the address of the function's pure | |
5733 | code. CXT is an RTX for the static chain value for the function. | |
96297568 | 5734 | |
5735 | The three offset parameters are for the individual template's | |
5736 | layout. A JMPOFS < 0 indicates that the trampoline does not | |
5737 | contain instructions at all. | |
5738 | ||
9e042f31 | 5739 | We assume here that a function will be called many more times than |
5740 | its address is taken (e.g., it might be passed to qsort), so we | |
5741 | take the trouble to initialize the "hint" field in the JMP insn. | |
5742 | Note that the hint field is PC (new) + 4 * bits 13:0. */ | |
5743 | ||
5744 | void | |
92643d95 | 5745 | alpha_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt, |
5746 | int fnofs, int cxtofs, int jmpofs) | |
9e042f31 | 5747 | { |
5748 | rtx temp, temp1, addr; | |
17683b9f | 5749 | /* VMS really uses DImode pointers in memory at this point. */ |
1467e953 | 5750 | enum machine_mode mode = TARGET_ABI_OPEN_VMS ? Pmode : ptr_mode; |
9e042f31 | 5751 | |
17683b9f | 5752 | #ifdef POINTERS_EXTEND_UNSIGNED |
5753 | fnaddr = convert_memory_address (mode, fnaddr); | |
5754 | cxt = convert_memory_address (mode, cxt); | |
5755 | #endif | |
5756 | ||
9e042f31 | 5757 | /* Store function address and CXT. */ |
46ba8e1c | 5758 | addr = memory_address (mode, plus_constant (tramp, fnofs)); |
7014838c | 5759 | emit_move_insn (gen_rtx_MEM (mode, addr), fnaddr); |
46ba8e1c | 5760 | addr = memory_address (mode, plus_constant (tramp, cxtofs)); |
7014838c | 5761 | emit_move_insn (gen_rtx_MEM (mode, addr), cxt); |
96297568 | 5762 | |
5763 | /* This has been disabled since the hint only has a 32k range, and in | |
65abff06 | 5764 | no existing OS is the stack within 32k of the text segment. */ |
96297568 | 5765 | if (0 && jmpofs >= 0) |
5766 | { | |
5767 | /* Compute hint value. */ | |
5768 | temp = force_operand (plus_constant (tramp, jmpofs+4), NULL_RTX); | |
5769 | temp = expand_binop (DImode, sub_optab, fnaddr, temp, temp, 1, | |
5770 | OPTAB_WIDEN); | |
5771 | temp = expand_shift (RSHIFT_EXPR, Pmode, temp, | |
5772 | build_int_2 (2, 0), NULL_RTX, 1); | |
6de9716c | 5773 | temp = expand_and (SImode, gen_lowpart (SImode, temp), |
5774 | GEN_INT (0x3fff), 0); | |
96297568 | 5775 | |
5776 | /* Merge in the hint. */ | |
5777 | addr = memory_address (SImode, plus_constant (tramp, jmpofs)); | |
7014838c | 5778 | temp1 = force_reg (SImode, gen_rtx_MEM (SImode, addr)); |
6de9716c | 5779 | temp1 = expand_and (SImode, temp1, GEN_INT (0xffffc000), NULL_RTX); |
96297568 | 5780 | temp1 = expand_binop (SImode, ior_optab, temp1, temp, temp1, 1, |
5781 | OPTAB_WIDEN); | |
7014838c | 5782 | emit_move_insn (gen_rtx_MEM (SImode, addr), temp1); |
96297568 | 5783 | } |
9e042f31 | 5784 | |
5785 | #ifdef TRANSFER_FROM_TRAMPOLINE | |
09a1f342 | 5786 | emit_library_call (init_one_libfunc ("__enable_execute_stack"), |
f0bdd254 | 5787 | 0, VOIDmode, 1, tramp, Pmode); |
9e042f31 | 5788 | #endif |
5789 | ||
96297568 | 5790 | if (jmpofs >= 0) |
5791 | emit_insn (gen_imb ()); | |
9e042f31 | 5792 | } |
5793 | \f | |
915c336f | 5794 | /* Determine where to put an argument to a function. |
5795 | Value is zero to push the argument on the stack, | |
5796 | or a hard register in which to store the argument. | |
5797 | ||
5798 | MODE is the argument's machine mode. | |
5799 | TYPE is the data type of the argument (as a tree). | |
5800 | This is null for libcalls where that information may | |
5801 | not be available. | |
5802 | CUM is a variable of type CUMULATIVE_ARGS which gives info about | |
5803 | the preceding args and about the function being called. | |
5804 | NAMED is nonzero if this argument is a named parameter | |
5805 | (otherwise it is an extra parameter matching an ellipsis). | |
5806 | ||
5807 | On Alpha the first 6 words of args are normally in registers | |
5808 | and the rest are pushed. */ | |
5809 | ||
5810 | rtx | |
92643d95 | 5811 | function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type, |
5812 | int named ATTRIBUTE_UNUSED) | |
915c336f | 5813 | { |
5814 | int basereg; | |
57e47080 | 5815 | int num_args; |
915c336f | 5816 | |
a685f5d8 | 5817 | /* Don't get confused and pass small structures in FP registers. */ |
5818 | if (type && AGGREGATE_TYPE_P (type)) | |
9caef960 | 5819 | basereg = 16; |
a685f5d8 | 5820 | else |
5821 | { | |
5822 | #ifdef ENABLE_CHECKING | |
92d40bc4 | 5823 | /* With alpha_split_complex_arg, we shouldn't see any raw complex |
a685f5d8 | 5824 | values here. */ |
5825 | if (COMPLEX_MODE_P (mode)) | |
5826 | abort (); | |
5827 | #endif | |
5828 | ||
5829 | /* Set up defaults for FP operands passed in FP registers, and | |
5830 | integral operands passed in integer registers. */ | |
5831 | if (TARGET_FPREGS && GET_MODE_CLASS (mode) == MODE_FLOAT) | |
5832 | basereg = 32 + 16; | |
5833 | else | |
5834 | basereg = 16; | |
5835 | } | |
9caef960 | 5836 | |
5837 | /* ??? Irritatingly, the definition of CUMULATIVE_ARGS is different for | |
5838 | the three platforms, so we can't avoid conditional compilation. */ | |
1467e953 | 5839 | #if TARGET_ABI_OPEN_VMS |
9caef960 | 5840 | { |
5841 | if (mode == VOIDmode) | |
5842 | return alpha_arg_info_reg_val (cum); | |
1467e953 | 5843 | |
9caef960 | 5844 | num_args = cum.num_args; |
0336f0f0 | 5845 | if (num_args >= 6 |
5846 | || targetm.calls.must_pass_in_stack (mode, type)) | |
9caef960 | 5847 | return NULL_RTX; |
5848 | } | |
a685f5d8 | 5849 | #elif TARGET_ABI_UNICOSMK |
9caef960 | 5850 | { |
5851 | int size; | |
915c336f | 5852 | |
9caef960 | 5853 | /* If this is the last argument, generate the call info word (CIW). */ |
5854 | /* ??? We don't include the caller's line number in the CIW because | |
5855 | I don't know how to determine it if debug infos are turned off. */ | |
5856 | if (mode == VOIDmode) | |
5857 | { | |
5858 | int i; | |
5859 | HOST_WIDE_INT lo; | |
5860 | HOST_WIDE_INT hi; | |
5861 | rtx ciw; | |
5862 | ||
5863 | lo = 0; | |
5864 | ||
5865 | for (i = 0; i < cum.num_reg_words && i < 5; i++) | |
5866 | if (cum.reg_args_type[i]) | |
5867 | lo |= (1 << (7 - i)); | |
5868 | ||
5869 | if (cum.num_reg_words == 6 && cum.reg_args_type[5]) | |
5870 | lo |= 7; | |
5871 | else | |
5872 | lo |= cum.num_reg_words; | |
5873 | ||
5874 | #if HOST_BITS_PER_WIDE_INT == 32 | |
5875 | hi = (cum.num_args << 20) | cum.num_arg_words; | |
5876 | #else | |
e162157f | 5877 | lo = lo | ((HOST_WIDE_INT) cum.num_args << 52) |
5878 | | ((HOST_WIDE_INT) cum.num_arg_words << 32); | |
9caef960 | 5879 | hi = 0; |
5880 | #endif | |
5881 | ciw = immed_double_const (lo, hi, DImode); | |
5882 | ||
5883 | return gen_rtx_UNSPEC (DImode, gen_rtvec (1, ciw), | |
5884 | UNSPEC_UMK_LOAD_CIW); | |
5885 | } | |
5886 | ||
5887 | size = ALPHA_ARG_SIZE (mode, type, named); | |
5888 | num_args = cum.num_reg_words; | |
0336f0f0 | 5889 | if (cum.force_stack |
5890 | || cum.num_reg_words + size > 6 | |
5891 | || targetm.calls.must_pass_in_stack (mode, type)) | |
9caef960 | 5892 | return NULL_RTX; |
5893 | else if (type && TYPE_MODE (type) == BLKmode) | |
5894 | { | |
5895 | rtx reg1, reg2; | |
5896 | ||
5897 | reg1 = gen_rtx_REG (DImode, num_args + 16); | |
5898 | reg1 = gen_rtx_EXPR_LIST (DImode, reg1, const0_rtx); | |
5899 | ||
5900 | /* The argument fits in two registers. Note that we still need to | |
5901 | reserve a register for empty structures. */ | |
5902 | if (size == 0) | |
5903 | return NULL_RTX; | |
5904 | else if (size == 1) | |
5905 | return gen_rtx_PARALLEL (mode, gen_rtvec (1, reg1)); | |
5906 | else | |
5907 | { | |
5908 | reg2 = gen_rtx_REG (DImode, num_args + 17); | |
5909 | reg2 = gen_rtx_EXPR_LIST (DImode, reg2, GEN_INT (8)); | |
5910 | return gen_rtx_PARALLEL (mode, gen_rtvec (2, reg1, reg2)); | |
5911 | } | |
5912 | } | |
5913 | } | |
a685f5d8 | 5914 | #elif TARGET_ABI_OSF |
9caef960 | 5915 | { |
5916 | if (cum >= 6) | |
5917 | return NULL_RTX; | |
5918 | num_args = cum; | |
5919 | ||
5920 | /* VOID is passed as a special flag for "last argument". */ | |
5921 | if (type == void_type_node) | |
5922 | basereg = 16; | |
0336f0f0 | 5923 | else if (targetm.calls.must_pass_in_stack (mode, type)) |
9caef960 | 5924 | return NULL_RTX; |
9caef960 | 5925 | } |
a685f5d8 | 5926 | #else |
5927 | #error Unhandled ABI | |
5928 | #endif | |
915c336f | 5929 | |
57e47080 | 5930 | return gen_rtx_REG (mode, num_args + basereg); |
915c336f | 5931 | } |
5932 | ||
a685f5d8 | 5933 | /* Return true if TYPE must be returned in memory, instead of in registers. */ |
5934 | ||
dd9f3024 | 5935 | static bool |
5936 | alpha_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED) | |
a685f5d8 | 5937 | { |
dd9f3024 | 5938 | enum machine_mode mode = VOIDmode; |
a685f5d8 | 5939 | int size; |
5940 | ||
5941 | if (type) | |
5942 | { | |
5943 | mode = TYPE_MODE (type); | |
5944 | ||
5945 | /* All aggregates are returned in memory. */ | |
5946 | if (AGGREGATE_TYPE_P (type)) | |
5947 | return true; | |
5948 | } | |
5949 | ||
5950 | size = GET_MODE_SIZE (mode); | |
5951 | switch (GET_MODE_CLASS (mode)) | |
5952 | { | |
5953 | case MODE_VECTOR_FLOAT: | |
5954 | /* Pass all float vectors in memory, like an aggregate. */ | |
5955 | return true; | |
5956 | ||
5957 | case MODE_COMPLEX_FLOAT: | |
5958 | /* We judge complex floats on the size of their element, | |
5959 | not the size of the whole type. */ | |
5960 | size = GET_MODE_UNIT_SIZE (mode); | |
5961 | break; | |
5962 | ||
5963 | case MODE_INT: | |
5964 | case MODE_FLOAT: | |
5965 | case MODE_COMPLEX_INT: | |
5966 | case MODE_VECTOR_INT: | |
5967 | break; | |
5968 | ||
5969 | default: | |
5970 | /* ??? We get called on all sorts of random stuff from | |
5971 | aggregate_value_p. We can't abort, but it's not clear | |
5972 | what's safe to return. Pretend it's a struct I guess. */ | |
5973 | return true; | |
5974 | } | |
5975 | ||
5976 | /* Otherwise types must fit in one register. */ | |
5977 | return size > UNITS_PER_WORD; | |
5978 | } | |
5979 | ||
b981d932 | 5980 | /* Return true if TYPE should be passed by invisible reference. */ |
5981 | ||
5982 | static bool | |
5983 | alpha_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED, | |
5984 | enum machine_mode mode, | |
5985 | tree type ATTRIBUTE_UNUSED, | |
5986 | bool named ATTRIBUTE_UNUSED) | |
5987 | { | |
5988 | return mode == TFmode || mode == TCmode; | |
5989 | } | |
5990 | ||
a685f5d8 | 5991 | /* Define how to find the value returned by a function. VALTYPE is the |
5992 | data type of the value (as a tree). If the precise function being | |
5993 | called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0. | |
5994 | MODE is set instead of VALTYPE for libcalls. | |
5995 | ||
5996 | On Alpha the value is found in $0 for integer functions and | |
5997 | $f0 for floating-point functions. */ | |
5998 | ||
5999 | rtx | |
6000 | function_value (tree valtype, tree func ATTRIBUTE_UNUSED, | |
6001 | enum machine_mode mode) | |
6002 | { | |
6003 | unsigned int regnum; | |
6004 | enum mode_class class; | |
6005 | ||
6006 | #ifdef ENABLE_CHECKING | |
aaca40a8 | 6007 | if (valtype && alpha_return_in_memory (valtype, func)) |
a685f5d8 | 6008 | abort (); |
6009 | #endif | |
6010 | ||
6011 | if (valtype) | |
6012 | mode = TYPE_MODE (valtype); | |
6013 | ||
6014 | class = GET_MODE_CLASS (mode); | |
6015 | switch (class) | |
6016 | { | |
6017 | case MODE_INT: | |
6018 | /* Do the same thing as PROMOTE_MODE. */ | |
6019 | mode = DImode; | |
8e262b5e | 6020 | /* FALLTHRU */ |
a685f5d8 | 6021 | |
6022 | case MODE_COMPLEX_INT: | |
6023 | case MODE_VECTOR_INT: | |
6024 | regnum = 0; | |
6025 | break; | |
6026 | ||
6027 | case MODE_FLOAT: | |
6028 | regnum = 32; | |
6029 | break; | |
6030 | ||
6031 | case MODE_COMPLEX_FLOAT: | |
6032 | { | |
6033 | enum machine_mode cmode = GET_MODE_INNER (mode); | |
6034 | ||
6035 | return gen_rtx_PARALLEL | |
6036 | (VOIDmode, | |
6037 | gen_rtvec (2, | |
6038 | gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 32), | |
bcd9bd66 | 6039 | const0_rtx), |
a685f5d8 | 6040 | gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 33), |
6041 | GEN_INT (GET_MODE_SIZE (cmode))))); | |
6042 | } | |
6043 | ||
6044 | default: | |
6045 | abort (); | |
6046 | } | |
6047 | ||
6048 | return gen_rtx_REG (mode, regnum); | |
6049 | } | |
6050 | ||
92d40bc4 | 6051 | /* TCmode complex values are passed by invisible reference. We |
6052 | should not split these values. */ | |
6053 | ||
6054 | static bool | |
6055 | alpha_split_complex_arg (tree type) | |
6056 | { | |
6057 | return TYPE_MODE (type) != TCmode; | |
6058 | } | |
6059 | ||
2e15d750 | 6060 | static tree |
6061 | alpha_build_builtin_va_list (void) | |
bf2a98b3 | 6062 | { |
7ba21c9f | 6063 | tree base, ofs, space, record, type_decl; |
bf2a98b3 | 6064 | |
9caef960 | 6065 | if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK) |
e7aabeab | 6066 | return ptr_type_node; |
6067 | ||
a1f71e15 | 6068 | record = (*lang_hooks.types.make_type) (RECORD_TYPE); |
0054fd98 | 6069 | type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record); |
6070 | TREE_CHAIN (record) = type_decl; | |
6071 | TYPE_NAME (record) = type_decl; | |
6072 | ||
e7aabeab | 6073 | /* C++? SET_IS_AGGR_TYPE (record, 1); */ |
bf2a98b3 | 6074 | |
7ba21c9f | 6075 | /* Dummy field to prevent alignment warnings. */ |
6076 | space = build_decl (FIELD_DECL, NULL_TREE, integer_type_node); | |
6077 | DECL_FIELD_CONTEXT (space) = record; | |
6078 | DECL_ARTIFICIAL (space) = 1; | |
6079 | DECL_IGNORED_P (space) = 1; | |
6080 | ||
e7aabeab | 6081 | ofs = build_decl (FIELD_DECL, get_identifier ("__offset"), |
6082 | integer_type_node); | |
6083 | DECL_FIELD_CONTEXT (ofs) = record; | |
7ba21c9f | 6084 | TREE_CHAIN (ofs) = space; |
fc4c89ed | 6085 | |
e7aabeab | 6086 | base = build_decl (FIELD_DECL, get_identifier ("__base"), |
6087 | ptr_type_node); | |
6088 | DECL_FIELD_CONTEXT (base) = record; | |
6089 | TREE_CHAIN (base) = ofs; | |
fc4c89ed | 6090 | |
e7aabeab | 6091 | TYPE_FIELDS (record) = base; |
6092 | layout_type (record); | |
6093 | ||
6094 | return record; | |
6095 | } | |
6096 | ||
4310aa50 | 6097 | /* Perform any needed actions needed for a function that is receiving a |
dd9f3024 | 6098 | variable number of arguments. */ |
4310aa50 | 6099 | |
dd9f3024 | 6100 | static void |
6101 | alpha_setup_incoming_varargs (CUMULATIVE_ARGS *pcum, | |
6102 | enum machine_mode mode ATTRIBUTE_UNUSED, | |
6103 | tree type ATTRIBUTE_UNUSED, | |
6104 | int *pretend_size, int no_rtl) | |
6105 | { | |
6106 | #if TARGET_ABI_UNICOSMK | |
6107 | /* On Unicos/Mk, the standard subroutine __T3E_MISMATCH stores all register | |
6108 | arguments on the stack. Unfortunately, it doesn't always store the first | |
6109 | one (i.e. the one that arrives in $16 or $f16). This is not a problem | |
6110 | with stdargs as we always have at least one named argument there. */ | |
6111 | int num_reg_words = pcum->num_reg_words; | |
6112 | if (num_reg_words < 6) | |
6113 | { | |
6114 | if (!no_rtl) | |
6115 | { | |
6116 | emit_insn (gen_umk_mismatch_args (GEN_INT (num_reg_words + 1))); | |
6117 | emit_insn (gen_arg_home_umk ()); | |
6118 | } | |
6119 | *pretend_size = 0; | |
6120 | } | |
6121 | #elif TARGET_ABI_OPEN_VMS | |
6122 | /* For VMS, we allocate space for all 6 arg registers plus a count. | |
4310aa50 | 6123 | |
dd9f3024 | 6124 | However, if NO registers need to be saved, don't allocate any space. |
6125 | This is not only because we won't need the space, but because AP | |
6126 | includes the current_pretend_args_size and we don't want to mess up | |
6127 | any ap-relative addresses already made. */ | |
6128 | if (pcum->num_args < 6) | |
6129 | { | |
6130 | if (!no_rtl) | |
6131 | { | |
6132 | emit_move_insn (gen_rtx_REG (DImode, 1), virtual_incoming_args_rtx); | |
6133 | emit_insn (gen_arg_home ()); | |
6134 | } | |
6135 | *pretend_size = 7 * UNITS_PER_WORD; | |
6136 | } | |
6137 | #else | |
6138 | /* On OSF/1 and friends, we allocate space for all 12 arg registers, but | |
6139 | only push those that are remaining. However, if NO registers need to | |
6140 | be saved, don't allocate any space. This is not only because we won't | |
6141 | need the space, but because AP includes the current_pretend_args_size | |
6142 | and we don't want to mess up any ap-relative addresses already made. | |
6143 | ||
6144 | If we are not to use the floating-point registers, save the integer | |
6145 | registers where we would put the floating-point registers. This is | |
6146 | not the most efficient way to implement varargs with just one register | |
6147 | class, but it isn't worth doing anything more efficient in this rare | |
6148 | case. */ | |
6149 | CUMULATIVE_ARGS cum = *pcum; | |
96f8cdd2 | 6150 | |
4310aa50 | 6151 | if (cum >= 6) |
6152 | return; | |
6153 | ||
6154 | if (!no_rtl) | |
6155 | { | |
6156 | int set = get_varargs_alias_set (); | |
6157 | rtx tmp; | |
6158 | ||
6159 | tmp = gen_rtx_MEM (BLKmode, | |
6160 | plus_constant (virtual_incoming_args_rtx, | |
6161 | (cum + 6) * UNITS_PER_WORD)); | |
6162 | set_mem_alias_set (tmp, set); | |
530178a9 | 6163 | move_block_from_reg (16 + cum, tmp, 6 - cum); |
4310aa50 | 6164 | |
6165 | tmp = gen_rtx_MEM (BLKmode, | |
6166 | plus_constant (virtual_incoming_args_rtx, | |
6167 | cum * UNITS_PER_WORD)); | |
6168 | set_mem_alias_set (tmp, set); | |
6169 | move_block_from_reg (16 + (TARGET_FPREGS ? 32 : 0) + cum, tmp, | |
530178a9 | 6170 | 6 - cum); |
4310aa50 | 6171 | } |
6172 | *pretend_size = 12 * UNITS_PER_WORD; | |
f6940372 | 6173 | #endif |
dd9f3024 | 6174 | } |
4310aa50 | 6175 | |
e7aabeab | 6176 | void |
92643d95 | 6177 | alpha_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) |
e7aabeab | 6178 | { |
6179 | HOST_WIDE_INT offset; | |
6180 | tree t, offset_field, base_field; | |
fc4c89ed | 6181 | |
80909c64 | 6182 | if (TREE_CODE (TREE_TYPE (valist)) == ERROR_MARK) |
6183 | return; | |
6184 | ||
fc264da3 | 6185 | if (TARGET_ABI_UNICOSMK) |
7df226a2 | 6186 | std_expand_builtin_va_start (valist, nextarg); |
e7aabeab | 6187 | |
6644435d | 6188 | /* For Unix, TARGET_SETUP_INCOMING_VARARGS moves the starting address base |
e7aabeab | 6189 | up by 48, storing fp arg registers in the first 48 bytes, and the |
6190 | integer arg registers in the next 48 bytes. This is only done, | |
6191 | however, if any integer registers need to be stored. | |
6192 | ||
6193 | If no integer registers need be stored, then we must subtract 48 | |
6194 | in order to account for the integer arg registers which are counted | |
4310aa50 | 6195 | in argsize above, but which are not actually stored on the stack. |
6196 | Must further be careful here about structures straddling the last | |
6197 | integer argument register; that futzes with pretend_args_size, | |
6198 | which changes the meaning of AP. */ | |
e7aabeab | 6199 | |
7ccc713a | 6200 | if (NUM_ARGS <= 6) |
fc264da3 | 6201 | offset = TARGET_ABI_OPEN_VMS ? UNITS_PER_WORD : 6 * UNITS_PER_WORD; |
8df4a58b | 6202 | else |
4310aa50 | 6203 | offset = -6 * UNITS_PER_WORD + current_function_pretend_args_size; |
e7aabeab | 6204 | |
fc264da3 | 6205 | if (TARGET_ABI_OPEN_VMS) |
6206 | { | |
6207 | nextarg = plus_constant (nextarg, offset); | |
6208 | nextarg = plus_constant (nextarg, NUM_ARGS * UNITS_PER_WORD); | |
6209 | t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, | |
6210 | make_tree (ptr_type_node, nextarg)); | |
6211 | TREE_SIDE_EFFECTS (t) = 1; | |
e7aabeab | 6212 | |
fc264da3 | 6213 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); |
6214 | } | |
6215 | else | |
6216 | { | |
6217 | base_field = TYPE_FIELDS (TREE_TYPE (valist)); | |
6218 | offset_field = TREE_CHAIN (base_field); | |
6219 | ||
6220 | base_field = build (COMPONENT_REF, TREE_TYPE (base_field), | |
6374121b | 6221 | valist, base_field, NULL_TREE); |
fc264da3 | 6222 | offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field), |
6374121b | 6223 | valist, offset_field, NULL_TREE); |
fc264da3 | 6224 | |
6225 | t = make_tree (ptr_type_node, virtual_incoming_args_rtx); | |
6226 | t = build (PLUS_EXPR, ptr_type_node, t, build_int_2 (offset, 0)); | |
6227 | t = build (MODIFY_EXPR, TREE_TYPE (base_field), base_field, t); | |
6228 | TREE_SIDE_EFFECTS (t) = 1; | |
6229 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
6230 | ||
6231 | t = build_int_2 (NUM_ARGS * UNITS_PER_WORD, 0); | |
6232 | t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, t); | |
6233 | TREE_SIDE_EFFECTS (t) = 1; | |
6234 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
6235 | } | |
e7aabeab | 6236 | } |
6237 | ||
de8f9b94 | 6238 | static tree |
c7b3f103 | 6239 | alpha_gimplify_va_arg_1 (tree type, tree base, tree offset, tree *pre_p) |
de8f9b94 | 6240 | { |
c7b3f103 | 6241 | tree type_size, ptr_type, addend, t, addr, internal_post; |
de8f9b94 | 6242 | |
de8f9b94 | 6243 | /* If the type could not be passed in registers, skip the block |
6244 | reserved for the registers. */ | |
0336f0f0 | 6245 | if (targetm.calls.must_pass_in_stack (TYPE_MODE (type), type)) |
de8f9b94 | 6246 | { |
6247 | t = fold_convert (TREE_TYPE (offset), build_int_2 (6*8, 0)); | |
6248 | t = build (MODIFY_EXPR, TREE_TYPE (offset), offset, | |
6249 | build (MAX_EXPR, TREE_TYPE (offset), offset, t)); | |
6250 | gimplify_and_add (t, pre_p); | |
6251 | } | |
6252 | ||
6253 | addend = offset; | |
6254 | ptr_type = build_pointer_type (type); | |
de8f9b94 | 6255 | |
2cd7bb84 | 6256 | if (TREE_CODE (type) == COMPLEX_TYPE) |
de8f9b94 | 6257 | { |
6258 | tree real_part, imag_part, real_temp; | |
6259 | ||
c7b3f103 | 6260 | real_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, |
6261 | offset, pre_p); | |
6262 | ||
6263 | /* Copy the value into a new temporary, lest the formal temporary | |
de8f9b94 | 6264 | be reused out from under us. */ |
c7b3f103 | 6265 | real_temp = get_initialized_tmp_var (real_part, pre_p, NULL); |
de8f9b94 | 6266 | |
c7b3f103 | 6267 | imag_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, |
6268 | offset, pre_p); | |
de8f9b94 | 6269 | |
6270 | return build (COMPLEX_EXPR, type, real_temp, imag_part); | |
6271 | } | |
6272 | else if (TREE_CODE (type) == REAL_TYPE) | |
6273 | { | |
6274 | tree fpaddend, cond, fourtyeight; | |
6275 | ||
6276 | fourtyeight = fold_convert (TREE_TYPE (addend), build_int_2 (6*8, 0)); | |
6277 | fpaddend = fold (build (MINUS_EXPR, TREE_TYPE (addend), | |
6278 | addend, fourtyeight)); | |
6279 | cond = fold (build (LT_EXPR, boolean_type_node, addend, fourtyeight)); | |
6280 | addend = fold (build (COND_EXPR, TREE_TYPE (addend), cond, | |
6281 | fpaddend, addend)); | |
6282 | } | |
6283 | ||
6284 | /* Build the final address and force that value into a temporary. */ | |
6285 | addr = build (PLUS_EXPR, ptr_type, fold_convert (ptr_type, base), | |
6286 | fold_convert (ptr_type, addend)); | |
c7b3f103 | 6287 | internal_post = NULL; |
6288 | gimplify_expr (&addr, pre_p, &internal_post, is_gimple_val, fb_rvalue); | |
6289 | append_to_statement_list (internal_post, pre_p); | |
de8f9b94 | 6290 | |
6291 | /* Update the offset field. */ | |
c7b3f103 | 6292 | type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type)); |
6293 | if (type_size == NULL || TREE_OVERFLOW (type_size)) | |
6294 | t = size_zero_node; | |
6295 | else | |
6296 | { | |
6297 | t = size_binop (PLUS_EXPR, type_size, size_int (7)); | |
6298 | t = size_binop (TRUNC_DIV_EXPR, t, size_int (8)); | |
6299 | t = size_binop (MULT_EXPR, t, size_int (8)); | |
6300 | } | |
6301 | t = fold_convert (TREE_TYPE (offset), t); | |
de8f9b94 | 6302 | t = build (MODIFY_EXPR, void_type_node, offset, |
6303 | build (PLUS_EXPR, TREE_TYPE (offset), offset, t)); | |
6304 | gimplify_and_add (t, pre_p); | |
6305 | ||
6306 | return build_fold_indirect_ref (addr); | |
6307 | } | |
6308 | ||
e0eca1fa | 6309 | static tree |
6310 | alpha_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) | |
de8f9b94 | 6311 | { |
e0eca1fa | 6312 | tree offset_field, base_field, offset, base, t, r; |
2cd7bb84 | 6313 | bool indirect; |
de8f9b94 | 6314 | |
6315 | if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK) | |
e0eca1fa | 6316 | return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); |
de8f9b94 | 6317 | |
6318 | base_field = TYPE_FIELDS (va_list_type_node); | |
6319 | offset_field = TREE_CHAIN (base_field); | |
6320 | base_field = build (COMPONENT_REF, TREE_TYPE (base_field), | |
6374121b | 6321 | valist, base_field, NULL_TREE); |
de8f9b94 | 6322 | offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field), |
6374121b | 6323 | valist, offset_field, NULL_TREE); |
de8f9b94 | 6324 | |
c7b3f103 | 6325 | /* Pull the fields of the structure out into temporaries. Since we never |
6326 | modify the base field, we can use a formal temporary. Sign-extend the | |
6327 | offset field so that it's the proper width for pointer arithmetic. */ | |
6328 | base = get_formal_tmp_var (base_field, pre_p); | |
de8f9b94 | 6329 | |
c7b3f103 | 6330 | t = fold_convert (lang_hooks.types.type_for_size (64, 0), offset_field); |
6331 | offset = get_initialized_tmp_var (t, pre_p, NULL); | |
de8f9b94 | 6332 | |
2cd7bb84 | 6333 | indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false); |
6334 | if (indirect) | |
6335 | type = build_pointer_type (type); | |
6336 | ||
de8f9b94 | 6337 | /* Find the value. Note that this will be a stable indirection, or |
6338 | a composite of stable indirections in the case of complex. */ | |
c7b3f103 | 6339 | r = alpha_gimplify_va_arg_1 (type, base, offset, pre_p); |
de8f9b94 | 6340 | |
6341 | /* Stuff the offset temporary back into its field. */ | |
6342 | t = build (MODIFY_EXPR, void_type_node, offset_field, | |
6343 | fold_convert (TREE_TYPE (offset_field), offset)); | |
6344 | gimplify_and_add (t, pre_p); | |
e0eca1fa | 6345 | |
2cd7bb84 | 6346 | if (indirect) |
6347 | r = build_fold_indirect_ref (r); | |
6348 | ||
e0eca1fa | 6349 | return r; |
de8f9b94 | 6350 | } |
bf2a98b3 | 6351 | \f |
f2cc13dc | 6352 | /* Builtins. */ |
6353 | ||
6354 | enum alpha_builtin | |
6355 | { | |
6356 | ALPHA_BUILTIN_CMPBGE, | |
ae4cd3a5 | 6357 | ALPHA_BUILTIN_EXTBL, |
6358 | ALPHA_BUILTIN_EXTWL, | |
6359 | ALPHA_BUILTIN_EXTLL, | |
f2cc13dc | 6360 | ALPHA_BUILTIN_EXTQL, |
ae4cd3a5 | 6361 | ALPHA_BUILTIN_EXTWH, |
6362 | ALPHA_BUILTIN_EXTLH, | |
f2cc13dc | 6363 | ALPHA_BUILTIN_EXTQH, |
ae4cd3a5 | 6364 | ALPHA_BUILTIN_INSBL, |
6365 | ALPHA_BUILTIN_INSWL, | |
6366 | ALPHA_BUILTIN_INSLL, | |
6367 | ALPHA_BUILTIN_INSQL, | |
6368 | ALPHA_BUILTIN_INSWH, | |
6369 | ALPHA_BUILTIN_INSLH, | |
6370 | ALPHA_BUILTIN_INSQH, | |
6371 | ALPHA_BUILTIN_MSKBL, | |
6372 | ALPHA_BUILTIN_MSKWL, | |
6373 | ALPHA_BUILTIN_MSKLL, | |
6374 | ALPHA_BUILTIN_MSKQL, | |
6375 | ALPHA_BUILTIN_MSKWH, | |
6376 | ALPHA_BUILTIN_MSKLH, | |
6377 | ALPHA_BUILTIN_MSKQH, | |
6378 | ALPHA_BUILTIN_UMULH, | |
f2cc13dc | 6379 | ALPHA_BUILTIN_ZAP, |
6380 | ALPHA_BUILTIN_ZAPNOT, | |
6381 | ALPHA_BUILTIN_AMASK, | |
6382 | ALPHA_BUILTIN_IMPLVER, | |
6383 | ALPHA_BUILTIN_RPCC, | |
938e069b | 6384 | ALPHA_BUILTIN_THREAD_POINTER, |
6385 | ALPHA_BUILTIN_SET_THREAD_POINTER, | |
f2cc13dc | 6386 | |
6387 | /* TARGET_MAX */ | |
6388 | ALPHA_BUILTIN_MINUB8, | |
6389 | ALPHA_BUILTIN_MINSB8, | |
6390 | ALPHA_BUILTIN_MINUW4, | |
6391 | ALPHA_BUILTIN_MINSW4, | |
6392 | ALPHA_BUILTIN_MAXUB8, | |
6393 | ALPHA_BUILTIN_MAXSB8, | |
6394 | ALPHA_BUILTIN_MAXUW4, | |
6395 | ALPHA_BUILTIN_MAXSW4, | |
6396 | ALPHA_BUILTIN_PERR, | |
6397 | ALPHA_BUILTIN_PKLB, | |
6398 | ALPHA_BUILTIN_PKWB, | |
6399 | ALPHA_BUILTIN_UNPKBL, | |
6400 | ALPHA_BUILTIN_UNPKBW, | |
6401 | ||
ae4cd3a5 | 6402 | /* TARGET_CIX */ |
6403 | ALPHA_BUILTIN_CTTZ, | |
6404 | ALPHA_BUILTIN_CTLZ, | |
6405 | ALPHA_BUILTIN_CTPOP, | |
6406 | ||
f2cc13dc | 6407 | ALPHA_BUILTIN_max |
6408 | }; | |
6409 | ||
ae4cd3a5 | 6410 | static unsigned int const code_for_builtin[ALPHA_BUILTIN_max] = { |
6411 | CODE_FOR_builtin_cmpbge, | |
6412 | CODE_FOR_builtin_extbl, | |
6413 | CODE_FOR_builtin_extwl, | |
6414 | CODE_FOR_builtin_extll, | |
6415 | CODE_FOR_builtin_extql, | |
6416 | CODE_FOR_builtin_extwh, | |
6417 | CODE_FOR_builtin_extlh, | |
6418 | CODE_FOR_builtin_extqh, | |
6419 | CODE_FOR_builtin_insbl, | |
6420 | CODE_FOR_builtin_inswl, | |
6421 | CODE_FOR_builtin_insll, | |
6422 | CODE_FOR_builtin_insql, | |
6423 | CODE_FOR_builtin_inswh, | |
6424 | CODE_FOR_builtin_inslh, | |
6425 | CODE_FOR_builtin_insqh, | |
6426 | CODE_FOR_builtin_mskbl, | |
6427 | CODE_FOR_builtin_mskwl, | |
6428 | CODE_FOR_builtin_mskll, | |
6429 | CODE_FOR_builtin_mskql, | |
6430 | CODE_FOR_builtin_mskwh, | |
6431 | CODE_FOR_builtin_msklh, | |
6432 | CODE_FOR_builtin_mskqh, | |
6433 | CODE_FOR_umuldi3_highpart, | |
6434 | CODE_FOR_builtin_zap, | |
6435 | CODE_FOR_builtin_zapnot, | |
6436 | CODE_FOR_builtin_amask, | |
6437 | CODE_FOR_builtin_implver, | |
6438 | CODE_FOR_builtin_rpcc, | |
938e069b | 6439 | CODE_FOR_load_tp, |
6440 | CODE_FOR_set_tp, | |
ae4cd3a5 | 6441 | |
6442 | /* TARGET_MAX */ | |
6443 | CODE_FOR_builtin_minub8, | |
6444 | CODE_FOR_builtin_minsb8, | |
6445 | CODE_FOR_builtin_minuw4, | |
6446 | CODE_FOR_builtin_minsw4, | |
6447 | CODE_FOR_builtin_maxub8, | |
6448 | CODE_FOR_builtin_maxsb8, | |
6449 | CODE_FOR_builtin_maxuw4, | |
6450 | CODE_FOR_builtin_maxsw4, | |
6451 | CODE_FOR_builtin_perr, | |
6452 | CODE_FOR_builtin_pklb, | |
6453 | CODE_FOR_builtin_pkwb, | |
6454 | CODE_FOR_builtin_unpkbl, | |
6455 | CODE_FOR_builtin_unpkbw, | |
6456 | ||
6457 | /* TARGET_CIX */ | |
6458 | CODE_FOR_builtin_cttz, | |
6459 | CODE_FOR_builtin_ctlz, | |
6460 | CODE_FOR_builtin_ctpop | |
6461 | }; | |
6462 | ||
f2cc13dc | 6463 | struct alpha_builtin_def |
6464 | { | |
6465 | const char *name; | |
6466 | enum alpha_builtin code; | |
6467 | unsigned int target_mask; | |
6468 | }; | |
6469 | ||
6470 | static struct alpha_builtin_def const zero_arg_builtins[] = { | |
6471 | { "__builtin_alpha_implver", ALPHA_BUILTIN_IMPLVER, 0 }, | |
6472 | { "__builtin_alpha_rpcc", ALPHA_BUILTIN_RPCC, 0 } | |
6473 | }; | |
6474 | ||
6475 | static struct alpha_builtin_def const one_arg_builtins[] = { | |
6476 | { "__builtin_alpha_amask", ALPHA_BUILTIN_AMASK, 0 }, | |
6477 | { "__builtin_alpha_pklb", ALPHA_BUILTIN_PKLB, MASK_MAX }, | |
6478 | { "__builtin_alpha_pkwb", ALPHA_BUILTIN_PKWB, MASK_MAX }, | |
6479 | { "__builtin_alpha_unpkbl", ALPHA_BUILTIN_UNPKBL, MASK_MAX }, | |
ae4cd3a5 | 6480 | { "__builtin_alpha_unpkbw", ALPHA_BUILTIN_UNPKBW, MASK_MAX }, |
6481 | { "__builtin_alpha_cttz", ALPHA_BUILTIN_CTTZ, MASK_CIX }, | |
6482 | { "__builtin_alpha_ctlz", ALPHA_BUILTIN_CTLZ, MASK_CIX }, | |
6483 | { "__builtin_alpha_ctpop", ALPHA_BUILTIN_CTPOP, MASK_CIX } | |
f2cc13dc | 6484 | }; |
6485 | ||
6486 | static struct alpha_builtin_def const two_arg_builtins[] = { | |
6487 | { "__builtin_alpha_cmpbge", ALPHA_BUILTIN_CMPBGE, 0 }, | |
ae4cd3a5 | 6488 | { "__builtin_alpha_extbl", ALPHA_BUILTIN_EXTBL, 0 }, |
6489 | { "__builtin_alpha_extwl", ALPHA_BUILTIN_EXTWL, 0 }, | |
6490 | { "__builtin_alpha_extll", ALPHA_BUILTIN_EXTLL, 0 }, | |
f2cc13dc | 6491 | { "__builtin_alpha_extql", ALPHA_BUILTIN_EXTQL, 0 }, |
ae4cd3a5 | 6492 | { "__builtin_alpha_extwh", ALPHA_BUILTIN_EXTWH, 0 }, |
6493 | { "__builtin_alpha_extlh", ALPHA_BUILTIN_EXTLH, 0 }, | |
f2cc13dc | 6494 | { "__builtin_alpha_extqh", ALPHA_BUILTIN_EXTQH, 0 }, |
ae4cd3a5 | 6495 | { "__builtin_alpha_insbl", ALPHA_BUILTIN_INSBL, 0 }, |
6496 | { "__builtin_alpha_inswl", ALPHA_BUILTIN_INSWL, 0 }, | |
6497 | { "__builtin_alpha_insll", ALPHA_BUILTIN_INSLL, 0 }, | |
6498 | { "__builtin_alpha_insql", ALPHA_BUILTIN_INSQL, 0 }, | |
6499 | { "__builtin_alpha_inswh", ALPHA_BUILTIN_INSWH, 0 }, | |
6500 | { "__builtin_alpha_inslh", ALPHA_BUILTIN_INSLH, 0 }, | |
6501 | { "__builtin_alpha_insqh", ALPHA_BUILTIN_INSQH, 0 }, | |
6502 | { "__builtin_alpha_mskbl", ALPHA_BUILTIN_MSKBL, 0 }, | |
6503 | { "__builtin_alpha_mskwl", ALPHA_BUILTIN_MSKWL, 0 }, | |
6504 | { "__builtin_alpha_mskll", ALPHA_BUILTIN_MSKLL, 0 }, | |
6505 | { "__builtin_alpha_mskql", ALPHA_BUILTIN_MSKQL, 0 }, | |
6506 | { "__builtin_alpha_mskwh", ALPHA_BUILTIN_MSKWH, 0 }, | |
6507 | { "__builtin_alpha_msklh", ALPHA_BUILTIN_MSKLH, 0 }, | |
6508 | { "__builtin_alpha_mskqh", ALPHA_BUILTIN_MSKQH, 0 }, | |
6509 | { "__builtin_alpha_umulh", ALPHA_BUILTIN_UMULH, 0 }, | |
f2cc13dc | 6510 | { "__builtin_alpha_zap", ALPHA_BUILTIN_ZAP, 0 }, |
6511 | { "__builtin_alpha_zapnot", ALPHA_BUILTIN_ZAPNOT, 0 }, | |
6512 | { "__builtin_alpha_minub8", ALPHA_BUILTIN_MINUB8, MASK_MAX }, | |
6513 | { "__builtin_alpha_minsb8", ALPHA_BUILTIN_MINSB8, MASK_MAX }, | |
6514 | { "__builtin_alpha_minuw4", ALPHA_BUILTIN_MINUW4, MASK_MAX }, | |
6515 | { "__builtin_alpha_minsw4", ALPHA_BUILTIN_MINSW4, MASK_MAX }, | |
6516 | { "__builtin_alpha_maxub8", ALPHA_BUILTIN_MAXUB8, MASK_MAX }, | |
6517 | { "__builtin_alpha_maxsb8", ALPHA_BUILTIN_MAXSB8, MASK_MAX }, | |
6518 | { "__builtin_alpha_maxuw4", ALPHA_BUILTIN_MAXUW4, MASK_MAX }, | |
6519 | { "__builtin_alpha_maxsw4", ALPHA_BUILTIN_MAXSW4, MASK_MAX }, | |
6520 | { "__builtin_alpha_perr", ALPHA_BUILTIN_PERR, MASK_MAX } | |
6521 | }; | |
6522 | ||
6523 | static void | |
92643d95 | 6524 | alpha_init_builtins (void) |
f2cc13dc | 6525 | { |
6526 | const struct alpha_builtin_def *p; | |
6527 | tree ftype; | |
6528 | size_t i; | |
6529 | ||
6530 | ftype = build_function_type (long_integer_type_node, void_list_node); | |
6531 | ||
6532 | p = zero_arg_builtins; | |
6533 | for (i = 0; i < ARRAY_SIZE (zero_arg_builtins); ++i, ++p) | |
6534 | if ((target_flags & p->target_mask) == p->target_mask) | |
e60d3615 | 6535 | lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD, |
6536 | NULL, NULL_TREE); | |
f2cc13dc | 6537 | |
8b55c4ba | 6538 | ftype = build_function_type_list (long_integer_type_node, |
6539 | long_integer_type_node, NULL_TREE); | |
f2cc13dc | 6540 | |
6541 | p = one_arg_builtins; | |
6542 | for (i = 0; i < ARRAY_SIZE (one_arg_builtins); ++i, ++p) | |
6543 | if ((target_flags & p->target_mask) == p->target_mask) | |
e60d3615 | 6544 | lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD, |
6545 | NULL, NULL_TREE); | |
f2cc13dc | 6546 | |
8b55c4ba | 6547 | ftype = build_function_type_list (long_integer_type_node, |
6548 | long_integer_type_node, | |
6549 | long_integer_type_node, NULL_TREE); | |
f2cc13dc | 6550 | |
6551 | p = two_arg_builtins; | |
6552 | for (i = 0; i < ARRAY_SIZE (two_arg_builtins); ++i, ++p) | |
6553 | if ((target_flags & p->target_mask) == p->target_mask) | |
e60d3615 | 6554 | lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD, |
6555 | NULL, NULL_TREE); | |
938e069b | 6556 | |
6557 | ftype = build_function_type (ptr_type_node, void_list_node); | |
e60d3615 | 6558 | lang_hooks.builtin_function ("__builtin_thread_pointer", ftype, |
6559 | ALPHA_BUILTIN_THREAD_POINTER, BUILT_IN_MD, | |
6560 | NULL, NULL_TREE); | |
938e069b | 6561 | |
8b55c4ba | 6562 | ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); |
e60d3615 | 6563 | lang_hooks.builtin_function ("__builtin_set_thread_pointer", ftype, |
6564 | ALPHA_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD, | |
6565 | NULL, NULL_TREE); | |
f2cc13dc | 6566 | } |
6567 | ||
6568 | /* Expand an expression EXP that calls a built-in function, | |
6569 | with result going to TARGET if that's convenient | |
6570 | (and in mode MODE if that's convenient). | |
6571 | SUBTARGET may be used as the target for computing one of EXP's operands. | |
6572 | IGNORE is nonzero if the value is to be ignored. */ | |
6573 | ||
6574 | static rtx | |
92643d95 | 6575 | alpha_expand_builtin (tree exp, rtx target, |
6576 | rtx subtarget ATTRIBUTE_UNUSED, | |
6577 | enum machine_mode mode ATTRIBUTE_UNUSED, | |
6578 | int ignore ATTRIBUTE_UNUSED) | |
f2cc13dc | 6579 | { |
f2cc13dc | 6580 | #define MAX_ARGS 2 |
6581 | ||
6582 | tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); | |
6583 | unsigned int fcode = DECL_FUNCTION_CODE (fndecl); | |
6584 | tree arglist = TREE_OPERAND (exp, 1); | |
6585 | enum insn_code icode; | |
6586 | rtx op[MAX_ARGS], pat; | |
6587 | int arity; | |
938e069b | 6588 | bool nonvoid; |
f2cc13dc | 6589 | |
6590 | if (fcode >= ALPHA_BUILTIN_max) | |
6591 | internal_error ("bad builtin fcode"); | |
6592 | icode = code_for_builtin[fcode]; | |
6593 | if (icode == 0) | |
6594 | internal_error ("bad builtin fcode"); | |
6595 | ||
938e069b | 6596 | nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; |
6597 | ||
f2cc13dc | 6598 | for (arglist = TREE_OPERAND (exp, 1), arity = 0; |
6599 | arglist; | |
6600 | arglist = TREE_CHAIN (arglist), arity++) | |
6601 | { | |
6602 | const struct insn_operand_data *insn_op; | |
6603 | ||
6604 | tree arg = TREE_VALUE (arglist); | |
6605 | if (arg == error_mark_node) | |
6606 | return NULL_RTX; | |
6607 | if (arity > MAX_ARGS) | |
6608 | return NULL_RTX; | |
6609 | ||
938e069b | 6610 | insn_op = &insn_data[icode].operand[arity + nonvoid]; |
6611 | ||
6612 | op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, 0); | |
f2cc13dc | 6613 | |
f2cc13dc | 6614 | if (!(*insn_op->predicate) (op[arity], insn_op->mode)) |
6615 | op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]); | |
6616 | } | |
6617 | ||
938e069b | 6618 | if (nonvoid) |
6619 | { | |
6620 | enum machine_mode tmode = insn_data[icode].operand[0].mode; | |
6621 | if (!target | |
6622 | || GET_MODE (target) != tmode | |
6623 | || !(*insn_data[icode].operand[0].predicate) (target, tmode)) | |
6624 | target = gen_reg_rtx (tmode); | |
6625 | } | |
f2cc13dc | 6626 | |
6627 | switch (arity) | |
6628 | { | |
6629 | case 0: | |
6630 | pat = GEN_FCN (icode) (target); | |
6631 | break; | |
6632 | case 1: | |
938e069b | 6633 | if (nonvoid) |
6634 | pat = GEN_FCN (icode) (target, op[0]); | |
6635 | else | |
6636 | pat = GEN_FCN (icode) (op[0]); | |
f2cc13dc | 6637 | break; |
6638 | case 2: | |
6639 | pat = GEN_FCN (icode) (target, op[0], op[1]); | |
6640 | break; | |
6641 | default: | |
6642 | abort (); | |
6643 | } | |
6644 | if (!pat) | |
6645 | return NULL_RTX; | |
6646 | emit_insn (pat); | |
6647 | ||
938e069b | 6648 | if (nonvoid) |
6649 | return target; | |
6650 | else | |
6651 | return const0_rtx; | |
f2cc13dc | 6652 | } |
6653 | \f | |
bf2a98b3 | 6654 | /* This page contains routines that are used to determine what the function |
6655 | prologue and epilogue code will do and write them out. */ | |
6656 | ||
6657 | /* Compute the size of the save area in the stack. */ | |
6658 | ||
8df4a58b | 6659 | /* These variables are used for communication between the following functions. |
6660 | They indicate various things about the current function being compiled | |
6661 | that are used to tell what kind of prologue, epilogue and procedure | |
efee20da | 6662 | descriptor to generate. */ |
8df4a58b | 6663 | |
6664 | /* Nonzero if we need a stack procedure. */ | |
b19d7ab1 | 6665 | enum alpha_procedure_types {PT_NULL = 0, PT_REGISTER = 1, PT_STACK = 2}; |
6666 | static enum alpha_procedure_types alpha_procedure_type; | |
8df4a58b | 6667 | |
6668 | /* Register number (either FP or SP) that is used to unwind the frame. */ | |
b9a5aa8e | 6669 | static int vms_unwind_regno; |
8df4a58b | 6670 | |
6671 | /* Register number used to save FP. We need not have one for RA since | |
6672 | we don't modify it for register procedures. This is only defined | |
6673 | for register frame procedures. */ | |
b9a5aa8e | 6674 | static int vms_save_fp_regno; |
8df4a58b | 6675 | |
6676 | /* Register number used to reference objects off our PV. */ | |
b9a5aa8e | 6677 | static int vms_base_regno; |
8df4a58b | 6678 | |
2cf1388a | 6679 | /* Compute register masks for saved registers. */ |
8df4a58b | 6680 | |
6681 | static void | |
92643d95 | 6682 | alpha_sa_mask (unsigned long *imaskP, unsigned long *fmaskP) |
8df4a58b | 6683 | { |
6684 | unsigned long imask = 0; | |
6685 | unsigned long fmask = 0; | |
1f0ce6a6 | 6686 | unsigned int i; |
8df4a58b | 6687 | |
eaa112a0 | 6688 | /* When outputting a thunk, we don't have valid register life info, |
6689 | but assemble_start_function wants to output .frame and .mask | |
6690 | directives. */ | |
6691 | if (current_function_is_thunk) | |
2cf1388a | 6692 | { |
961d6ddd | 6693 | *imaskP = 0; |
6694 | *fmaskP = 0; | |
6695 | return; | |
6696 | } | |
8df4a58b | 6697 | |
b19d7ab1 | 6698 | if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK) |
df7d0d23 | 6699 | imask |= (1UL << HARD_FRAME_POINTER_REGNUM); |
8df4a58b | 6700 | |
961d6ddd | 6701 | /* One for every register we have to save. */ |
6702 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
6703 | if (! fixed_regs[i] && ! call_used_regs[i] | |
6704 | && regs_ever_live[i] && i != REG_RA | |
6705 | && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM)) | |
6706 | { | |
6707 | if (i < 32) | |
df7d0d23 | 6708 | imask |= (1UL << i); |
961d6ddd | 6709 | else |
df7d0d23 | 6710 | fmask |= (1UL << (i - 32)); |
961d6ddd | 6711 | } |
6712 | ||
6713 | /* We need to restore these for the handler. */ | |
6714 | if (current_function_calls_eh_return) | |
c49ad9ef | 6715 | { |
6716 | for (i = 0; ; ++i) | |
6717 | { | |
6718 | unsigned regno = EH_RETURN_DATA_REGNO (i); | |
6719 | if (regno == INVALID_REGNUM) | |
6720 | break; | |
6721 | imask |= 1UL << regno; | |
6722 | } | |
6723 | ||
6724 | /* Glibc likes to use $31 as an unwind stopper for crt0. To | |
6725 | avoid hackery in unwind-dw2.c, we need to actively store a | |
6726 | zero in the prologue of _Unwind_RaiseException et al. */ | |
6727 | imask |= 1UL << 31; | |
6728 | } | |
9caef960 | 6729 | |
961d6ddd | 6730 | /* If any register spilled, then spill the return address also. */ |
6731 | /* ??? This is required by the Digital stack unwind specification | |
6732 | and isn't needed if we're doing Dwarf2 unwinding. */ | |
6733 | if (imask || fmask || alpha_ra_ever_killed ()) | |
df7d0d23 | 6734 | imask |= (1UL << REG_RA); |
b9a5aa8e | 6735 | |
8df4a58b | 6736 | *imaskP = imask; |
6737 | *fmaskP = fmask; | |
8df4a58b | 6738 | } |
6739 | ||
6740 | int | |
92643d95 | 6741 | alpha_sa_size (void) |
8df4a58b | 6742 | { |
5aae9d06 | 6743 | unsigned long mask[2]; |
8df4a58b | 6744 | int sa_size = 0; |
5aae9d06 | 6745 | int i, j; |
8df4a58b | 6746 | |
5aae9d06 | 6747 | alpha_sa_mask (&mask[0], &mask[1]); |
6748 | ||
6749 | if (TARGET_ABI_UNICOSMK) | |
6750 | { | |
6751 | if (mask[0] || mask[1]) | |
6752 | sa_size = 14; | |
6753 | } | |
2cf1388a | 6754 | else |
2cf1388a | 6755 | { |
5aae9d06 | 6756 | for (j = 0; j < 2; ++j) |
6757 | for (i = 0; i < 32; ++i) | |
6758 | if ((mask[j] >> i) & 1) | |
6759 | sa_size++; | |
2cf1388a | 6760 | } |
8df4a58b | 6761 | |
9caef960 | 6762 | if (TARGET_ABI_UNICOSMK) |
6763 | { | |
6764 | /* We might not need to generate a frame if we don't make any calls | |
6765 | (including calls to __T3E_MISMATCH if this is a vararg function), | |
6766 | don't have any local variables which require stack slots, don't | |
6767 | use alloca and have not determined that we need a frame for other | |
6768 | reasons. */ | |
6769 | ||
b19d7ab1 | 6770 | alpha_procedure_type |
6771 | = (sa_size || get_frame_size() != 0 | |
7ccc713a | 6772 | || current_function_outgoing_args_size |
b19d7ab1 | 6773 | || current_function_stdarg || current_function_calls_alloca |
6774 | || frame_pointer_needed) | |
6775 | ? PT_STACK : PT_REGISTER; | |
9caef960 | 6776 | |
6777 | /* Always reserve space for saving callee-saved registers if we | |
6778 | need a frame as required by the calling convention. */ | |
b19d7ab1 | 6779 | if (alpha_procedure_type == PT_STACK) |
9caef960 | 6780 | sa_size = 14; |
6781 | } | |
6782 | else if (TARGET_ABI_OPEN_VMS) | |
b9a5aa8e | 6783 | { |
6784 | /* Start by assuming we can use a register procedure if we don't | |
6785 | make any calls (REG_RA not used) or need to save any | |
6786 | registers and a stack procedure if we do. */ | |
b19d7ab1 | 6787 | if ((mask[0] >> REG_RA) & 1) |
6788 | alpha_procedure_type = PT_STACK; | |
6789 | else if (get_frame_size() != 0) | |
6790 | alpha_procedure_type = PT_REGISTER; | |
6791 | else | |
6792 | alpha_procedure_type = PT_NULL; | |
5aae9d06 | 6793 | |
2ab60bb1 | 6794 | /* Don't reserve space for saving FP & RA yet. Do that later after we've |
5aae9d06 | 6795 | made the final decision on stack procedure vs register procedure. */ |
b19d7ab1 | 6796 | if (alpha_procedure_type == PT_STACK) |
2ab60bb1 | 6797 | sa_size -= 2; |
b9a5aa8e | 6798 | |
6799 | /* Decide whether to refer to objects off our PV via FP or PV. | |
6800 | If we need FP for something else or if we receive a nonlocal | |
6801 | goto (which expects PV to contain the value), we must use PV. | |
6802 | Otherwise, start by assuming we can use FP. */ | |
b19d7ab1 | 6803 | |
6804 | vms_base_regno | |
6805 | = (frame_pointer_needed | |
6806 | || current_function_has_nonlocal_label | |
6807 | || alpha_procedure_type == PT_STACK | |
6808 | || current_function_outgoing_args_size) | |
6809 | ? REG_PV : HARD_FRAME_POINTER_REGNUM; | |
b9a5aa8e | 6810 | |
6811 | /* If we want to copy PV into FP, we need to find some register | |
6812 | in which to save FP. */ | |
6813 | ||
6814 | vms_save_fp_regno = -1; | |
6815 | if (vms_base_regno == HARD_FRAME_POINTER_REGNUM) | |
6816 | for (i = 0; i < 32; i++) | |
6817 | if (! fixed_regs[i] && call_used_regs[i] && ! regs_ever_live[i]) | |
6818 | vms_save_fp_regno = i; | |
6819 | ||
b19d7ab1 | 6820 | if (vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER) |
6821 | vms_base_regno = REG_PV, alpha_procedure_type = PT_STACK; | |
6822 | else if (alpha_procedure_type == PT_NULL) | |
6823 | vms_base_regno = REG_PV; | |
b9a5aa8e | 6824 | |
6825 | /* Stack unwinding should be done via FP unless we use it for PV. */ | |
6826 | vms_unwind_regno = (vms_base_regno == REG_PV | |
6827 | ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); | |
6828 | ||
6829 | /* If this is a stack procedure, allow space for saving FP and RA. */ | |
b19d7ab1 | 6830 | if (alpha_procedure_type == PT_STACK) |
b9a5aa8e | 6831 | sa_size += 2; |
6832 | } | |
6833 | else | |
6834 | { | |
b9a5aa8e | 6835 | /* Our size must be even (multiple of 16 bytes). */ |
6836 | if (sa_size & 1) | |
6837 | sa_size++; | |
6838 | } | |
8df4a58b | 6839 | |
6840 | return sa_size * 8; | |
6841 | } | |
6842 | ||
4310aa50 | 6843 | /* Define the offset between two registers, one to be eliminated, |
6844 | and the other its replacement, at the start of a routine. */ | |
6845 | ||
6846 | HOST_WIDE_INT | |
92643d95 | 6847 | alpha_initial_elimination_offset (unsigned int from, |
6848 | unsigned int to ATTRIBUTE_UNUSED) | |
4310aa50 | 6849 | { |
6850 | HOST_WIDE_INT ret; | |
6851 | ||
6852 | ret = alpha_sa_size (); | |
6853 | ret += ALPHA_ROUND (current_function_outgoing_args_size); | |
6854 | ||
6855 | if (from == FRAME_POINTER_REGNUM) | |
6856 | ; | |
6857 | else if (from == ARG_POINTER_REGNUM) | |
6858 | ret += (ALPHA_ROUND (get_frame_size () | |
6859 | + current_function_pretend_args_size) | |
6860 | - current_function_pretend_args_size); | |
6861 | else | |
6862 | abort (); | |
6863 | ||
6864 | return ret; | |
6865 | } | |
6866 | ||
8df4a58b | 6867 | int |
92643d95 | 6868 | alpha_pv_save_size (void) |
8df4a58b | 6869 | { |
6870 | alpha_sa_size (); | |
b19d7ab1 | 6871 | return alpha_procedure_type == PT_STACK ? 8 : 0; |
8df4a58b | 6872 | } |
6873 | ||
6874 | int | |
92643d95 | 6875 | alpha_using_fp (void) |
8df4a58b | 6876 | { |
6877 | alpha_sa_size (); | |
b9a5aa8e | 6878 | return vms_unwind_regno == HARD_FRAME_POINTER_REGNUM; |
8df4a58b | 6879 | } |
6880 | ||
1467e953 | 6881 | #if TARGET_ABI_OPEN_VMS |
2d280039 | 6882 | |
e3c541f0 | 6883 | const struct attribute_spec vms_attribute_table[] = |
bf2a98b3 | 6884 | { |
e3c541f0 | 6885 | /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ |
c64a8830 | 6886 | { "overlaid", 0, 0, true, false, false, NULL }, |
6887 | { "global", 0, 0, true, false, false, NULL }, | |
6888 | { "initialize", 0, 0, true, false, false, NULL }, | |
6889 | { NULL, 0, 0, false, false, false, NULL } | |
e3c541f0 | 6890 | }; |
bf2a98b3 | 6891 | |
2d280039 | 6892 | #endif |
6893 | ||
1f0ce6a6 | 6894 | static int |
92643d95 | 6895 | find_lo_sum_using_gp (rtx *px, void *data ATTRIBUTE_UNUSED) |
1f0ce6a6 | 6896 | { |
a3859c0f | 6897 | return GET_CODE (*px) == LO_SUM && XEXP (*px, 0) == pic_offset_table_rtx; |
6898 | } | |
6899 | ||
6900 | int | |
92643d95 | 6901 | alpha_find_lo_sum_using_gp (rtx insn) |
a3859c0f | 6902 | { |
6903 | return for_each_rtx (&PATTERN (insn), find_lo_sum_using_gp, NULL) > 0; | |
1f0ce6a6 | 6904 | } |
6905 | ||
b9a5aa8e | 6906 | static int |
92643d95 | 6907 | alpha_does_function_need_gp (void) |
b9a5aa8e | 6908 | { |
6909 | rtx insn; | |
bf2a98b3 | 6910 | |
9caef960 | 6911 | /* The GP being variable is an OSF abi thing. */ |
6912 | if (! TARGET_ABI_OSF) | |
b9a5aa8e | 6913 | return 0; |
bf2a98b3 | 6914 | |
008fdc59 | 6915 | /* We need the gp to load the address of __mcount. */ |
7811c823 | 6916 | if (TARGET_PROFILING_NEEDS_GP && current_function_profile) |
b9a5aa8e | 6917 | return 1; |
0e0a0e7a | 6918 | |
008fdc59 | 6919 | /* The code emitted by alpha_output_mi_thunk_osf uses the gp. */ |
2cf1388a | 6920 | if (current_function_is_thunk) |
6921 | return 1; | |
2cf1388a | 6922 | |
008fdc59 | 6923 | /* The nonlocal receiver pattern assumes that the gp is valid for |
6924 | the nested function. Reasonable because it's almost always set | |
6925 | correctly already. For the cases where that's wrong, make sure | |
6926 | the nested function loads its gp on entry. */ | |
6927 | if (current_function_has_nonlocal_goto) | |
6928 | return 1; | |
6929 | ||
b9a5aa8e | 6930 | /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first. |
6931 | Even if we are a static function, we still need to do this in case | |
6932 | our address is taken and passed to something like qsort. */ | |
bf2a98b3 | 6933 | |
b9a5aa8e | 6934 | push_topmost_sequence (); |
6935 | insn = get_insns (); | |
6936 | pop_topmost_sequence (); | |
8df4a58b | 6937 | |
b9a5aa8e | 6938 | for (; insn; insn = NEXT_INSN (insn)) |
9204e736 | 6939 | if (INSN_P (insn) |
b9a5aa8e | 6940 | && GET_CODE (PATTERN (insn)) != USE |
a3859c0f | 6941 | && GET_CODE (PATTERN (insn)) != CLOBBER |
6942 | && get_attr_usegp (insn)) | |
6943 | return 1; | |
bf2a98b3 | 6944 | |
b9a5aa8e | 6945 | return 0; |
bf2a98b3 | 6946 | } |
6947 | ||
7d73bc2a | 6948 | \f |
5a965225 | 6949 | /* Helper function to set RTX_FRAME_RELATED_P on instructions, including |
6950 | sequences. */ | |
6951 | ||
6952 | static rtx | |
92643d95 | 6953 | set_frame_related_p (void) |
5a965225 | 6954 | { |
31d3e01c | 6955 | rtx seq = get_insns (); |
6956 | rtx insn; | |
6957 | ||
5a965225 | 6958 | end_sequence (); |
6959 | ||
31d3e01c | 6960 | if (!seq) |
6961 | return NULL_RTX; | |
6962 | ||
6963 | if (INSN_P (seq)) | |
5a965225 | 6964 | { |
31d3e01c | 6965 | insn = seq; |
6966 | while (insn != NULL_RTX) | |
6967 | { | |
6968 | RTX_FRAME_RELATED_P (insn) = 1; | |
6969 | insn = NEXT_INSN (insn); | |
6970 | } | |
6971 | seq = emit_insn (seq); | |
5a965225 | 6972 | } |
6973 | else | |
6974 | { | |
6975 | seq = emit_insn (seq); | |
6976 | RTX_FRAME_RELATED_P (seq) = 1; | |
5a965225 | 6977 | } |
31d3e01c | 6978 | return seq; |
5a965225 | 6979 | } |
6980 | ||
6981 | #define FRP(exp) (start_sequence (), exp, set_frame_related_p ()) | |
6982 | ||
bf2a98b3 | 6983 | /* Write function prologue. */ |
6984 | ||
8df4a58b | 6985 | /* On vms we have two kinds of functions: |
6986 | ||
6987 | - stack frame (PROC_STACK) | |
6988 | these are 'normal' functions with local vars and which are | |
6989 | calling other functions | |
6990 | - register frame (PROC_REGISTER) | |
6991 | keeps all data in registers, needs no stack | |
6992 | ||
6993 | We must pass this to the assembler so it can generate the | |
6994 | proper pdsc (procedure descriptor) | |
6995 | This is done with the '.pdesc' command. | |
6996 | ||
b9a5aa8e | 6997 | On not-vms, we don't really differentiate between the two, as we can |
6998 | simply allocate stack without saving registers. */ | |
8df4a58b | 6999 | |
7000 | void | |
92643d95 | 7001 | alpha_expand_prologue (void) |
8df4a58b | 7002 | { |
b9a5aa8e | 7003 | /* Registers to save. */ |
8df4a58b | 7004 | unsigned long imask = 0; |
7005 | unsigned long fmask = 0; | |
7006 | /* Stack space needed for pushing registers clobbered by us. */ | |
7007 | HOST_WIDE_INT sa_size; | |
7008 | /* Complete stack size needed. */ | |
7009 | HOST_WIDE_INT frame_size; | |
7010 | /* Offset from base reg to register save area. */ | |
b9a5aa8e | 7011 | HOST_WIDE_INT reg_offset; |
849674a3 | 7012 | rtx sa_reg, mem; |
8df4a58b | 7013 | int i; |
7014 | ||
7015 | sa_size = alpha_sa_size (); | |
8df4a58b | 7016 | |
b9a5aa8e | 7017 | frame_size = get_frame_size (); |
1467e953 | 7018 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7019 | frame_size = ALPHA_ROUND (sa_size |
b19d7ab1 | 7020 | + (alpha_procedure_type == PT_STACK ? 8 : 0) |
b9a5aa8e | 7021 | + frame_size |
7022 | + current_function_pretend_args_size); | |
9caef960 | 7023 | else if (TARGET_ABI_UNICOSMK) |
7024 | /* We have to allocate space for the DSIB if we generate a frame. */ | |
7025 | frame_size = ALPHA_ROUND (sa_size | |
b19d7ab1 | 7026 | + (alpha_procedure_type == PT_STACK ? 48 : 0)) |
9caef960 | 7027 | + ALPHA_ROUND (frame_size |
7028 | + current_function_outgoing_args_size); | |
b9a5aa8e | 7029 | else |
7030 | frame_size = (ALPHA_ROUND (current_function_outgoing_args_size) | |
7031 | + sa_size | |
7032 | + ALPHA_ROUND (frame_size | |
7033 | + current_function_pretend_args_size)); | |
8df4a58b | 7034 | |
1467e953 | 7035 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7036 | reg_offset = 8; |
7037 | else | |
7038 | reg_offset = ALPHA_ROUND (current_function_outgoing_args_size); | |
8df4a58b | 7039 | |
b9a5aa8e | 7040 | alpha_sa_mask (&imask, &fmask); |
8df4a58b | 7041 | |
a314eb5e | 7042 | /* Emit an insn to reload GP, if needed. */ |
1467e953 | 7043 | if (TARGET_ABI_OSF) |
a314eb5e | 7044 | { |
7045 | alpha_function_needs_gp = alpha_does_function_need_gp (); | |
7046 | if (alpha_function_needs_gp) | |
7047 | emit_insn (gen_prologue_ldgp ()); | |
7048 | } | |
7049 | ||
30dceb30 | 7050 | /* TARGET_PROFILING_NEEDS_GP actually implies that we need to insert |
7051 | the call to mcount ourselves, rather than having the linker do it | |
7052 | magically in response to -pg. Since _mcount has special linkage, | |
7053 | don't represent the call as a call. */ | |
7811c823 | 7054 | if (TARGET_PROFILING_NEEDS_GP && current_function_profile) |
30dceb30 | 7055 | emit_insn (gen_prologue_mcount ()); |
9caef960 | 7056 | |
7057 | if (TARGET_ABI_UNICOSMK) | |
7058 | unicosmk_gen_dsib (&imask); | |
7059 | ||
8df4a58b | 7060 | /* Adjust the stack by the frame size. If the frame size is > 4096 |
7061 | bytes, we need to be sure we probe somewhere in the first and last | |
7062 | 4096 bytes (we can probably get away without the latter test) and | |
7063 | every 8192 bytes in between. If the frame size is > 32768, we | |
7064 | do this in a loop. Otherwise, we generate the explicit probe | |
7065 | instructions. | |
7066 | ||
7067 | Note that we are only allowed to adjust sp once in the prologue. */ | |
7068 | ||
b9a5aa8e | 7069 | if (frame_size <= 32768) |
8df4a58b | 7070 | { |
7071 | if (frame_size > 4096) | |
7072 | { | |
7073 | int probed = 4096; | |
7074 | ||
b9a5aa8e | 7075 | do |
9caef960 | 7076 | emit_insn (gen_probe_stack (GEN_INT (TARGET_ABI_UNICOSMK |
7077 | ? -probed + 64 | |
7078 | : -probed))); | |
b9a5aa8e | 7079 | while ((probed += 8192) < frame_size); |
8df4a58b | 7080 | |
7081 | /* We only have to do this probe if we aren't saving registers. */ | |
7082 | if (sa_size == 0 && probed + 4096 < frame_size) | |
b9a5aa8e | 7083 | emit_insn (gen_probe_stack (GEN_INT (-frame_size))); |
8df4a58b | 7084 | } |
7085 | ||
7086 | if (frame_size != 0) | |
205b281f | 7087 | FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, |
9caef960 | 7088 | GEN_INT (TARGET_ABI_UNICOSMK |
7089 | ? -frame_size + 64 | |
7090 | : -frame_size)))); | |
8df4a58b | 7091 | } |
7092 | else | |
7093 | { | |
b9a5aa8e | 7094 | /* Here we generate code to set R22 to SP + 4096 and set R23 to the |
8df4a58b | 7095 | number of 8192 byte blocks to probe. We then probe each block |
7096 | in the loop and then set SP to the proper location. If the | |
7097 | amount remaining is > 4096, we have to do one more probe if we | |
7098 | are not saving any registers. */ | |
7099 | ||
7100 | HOST_WIDE_INT blocks = (frame_size + 4096) / 8192; | |
7101 | HOST_WIDE_INT leftover = frame_size + 4096 - blocks * 8192; | |
b9a5aa8e | 7102 | rtx ptr = gen_rtx_REG (DImode, 22); |
7103 | rtx count = gen_rtx_REG (DImode, 23); | |
cd28cb76 | 7104 | rtx seq; |
8df4a58b | 7105 | |
b9a5aa8e | 7106 | emit_move_insn (count, GEN_INT (blocks)); |
9caef960 | 7107 | emit_insn (gen_adddi3 (ptr, stack_pointer_rtx, |
7108 | GEN_INT (TARGET_ABI_UNICOSMK ? 4096 - 64 : 4096))); | |
8df4a58b | 7109 | |
b9a5aa8e | 7110 | /* Because of the difficulty in emitting a new basic block this |
7111 | late in the compilation, generate the loop as a single insn. */ | |
7112 | emit_insn (gen_prologue_stack_probe_loop (count, ptr)); | |
8df4a58b | 7113 | |
7114 | if (leftover > 4096 && sa_size == 0) | |
b9a5aa8e | 7115 | { |
7116 | rtx last = gen_rtx_MEM (DImode, plus_constant (ptr, -leftover)); | |
7117 | MEM_VOLATILE_P (last) = 1; | |
7118 | emit_move_insn (last, const0_rtx); | |
7119 | } | |
8df4a58b | 7120 | |
1467e953 | 7121 | if (TARGET_ABI_WINDOWS_NT) |
f88f2646 | 7122 | { |
7123 | /* For NT stack unwind (done by 'reverse execution'), it's | |
7124 | not OK to take the result of a loop, even though the value | |
7125 | is already in ptr, so we reload it via a single operation | |
cd28cb76 | 7126 | and subtract it to sp. |
7127 | ||
7128 | Yes, that's correct -- we have to reload the whole constant | |
df9e12ce | 7129 | into a temporary via ldah+lda then subtract from sp. */ |
f88f2646 | 7130 | |
7131 | HOST_WIDE_INT lo, hi; | |
05bea6dd | 7132 | lo = ((frame_size & 0xffff) ^ 0x8000) - 0x8000; |
7133 | hi = frame_size - lo; | |
5a965225 | 7134 | |
cd28cb76 | 7135 | emit_move_insn (ptr, GEN_INT (hi)); |
df9e12ce | 7136 | emit_insn (gen_adddi3 (ptr, ptr, GEN_INT (lo))); |
cd28cb76 | 7137 | seq = emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, |
7138 | ptr)); | |
f88f2646 | 7139 | } |
7140 | else | |
7141 | { | |
f88f2646 | 7142 | seq = emit_insn (gen_adddi3 (stack_pointer_rtx, ptr, |
7143 | GEN_INT (-leftover))); | |
f88f2646 | 7144 | } |
cd28cb76 | 7145 | |
7146 | /* This alternative is special, because the DWARF code cannot | |
7147 | possibly intuit through the loop above. So we invent this | |
7148 | note it looks at instead. */ | |
7149 | RTX_FRAME_RELATED_P (seq) = 1; | |
7150 | REG_NOTES (seq) | |
7151 | = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, | |
7152 | gen_rtx_SET (VOIDmode, stack_pointer_rtx, | |
7153 | gen_rtx_PLUS (Pmode, stack_pointer_rtx, | |
9caef960 | 7154 | GEN_INT (TARGET_ABI_UNICOSMK |
7155 | ? -frame_size + 64 | |
7156 | : -frame_size))), | |
cd28cb76 | 7157 | REG_NOTES (seq)); |
8df4a58b | 7158 | } |
7159 | ||
9caef960 | 7160 | if (!TARGET_ABI_UNICOSMK) |
8df4a58b | 7161 | { |
9caef960 | 7162 | /* Cope with very large offsets to the register save area. */ |
7163 | sa_reg = stack_pointer_rtx; | |
7164 | if (reg_offset + sa_size > 0x8000) | |
7165 | { | |
7166 | int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000; | |
7167 | HOST_WIDE_INT bias; | |
8df4a58b | 7168 | |
9caef960 | 7169 | if (low + sa_size <= 0x8000) |
7170 | bias = reg_offset - low, reg_offset = low; | |
7171 | else | |
7172 | bias = reg_offset, reg_offset = 0; | |
8df4a58b | 7173 | |
9caef960 | 7174 | sa_reg = gen_rtx_REG (DImode, 24); |
7175 | FRP (emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, | |
7176 | GEN_INT (bias)))); | |
7177 | } | |
b9a5aa8e | 7178 | |
9caef960 | 7179 | /* Save regs in stack order. Beginning with VMS PV. */ |
b19d7ab1 | 7180 | if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK) |
9caef960 | 7181 | { |
7182 | mem = gen_rtx_MEM (DImode, stack_pointer_rtx); | |
7183 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7184 | FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_PV))); | |
7185 | } | |
8df4a58b | 7186 | |
9caef960 | 7187 | /* Save register RA next. */ |
df7d0d23 | 7188 | if (imask & (1UL << REG_RA)) |
9caef960 | 7189 | { |
7190 | mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); | |
7191 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7192 | FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA))); | |
df7d0d23 | 7193 | imask &= ~(1UL << REG_RA); |
9caef960 | 7194 | reg_offset += 8; |
7195 | } | |
8df4a58b | 7196 | |
9caef960 | 7197 | /* Now save any other registers required to be saved. */ |
c49ad9ef | 7198 | for (i = 0; i < 31; i++) |
df7d0d23 | 7199 | if (imask & (1UL << i)) |
9caef960 | 7200 | { |
7201 | mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); | |
7202 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7203 | FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i))); | |
7204 | reg_offset += 8; | |
7205 | } | |
8df4a58b | 7206 | |
c49ad9ef | 7207 | /* Store a zero if requested for unwinding. */ |
7208 | if (imask & (1UL << 31)) | |
7209 | { | |
7210 | rtx insn, t; | |
7211 | ||
7212 | mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); | |
7213 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7214 | insn = emit_move_insn (mem, const0_rtx); | |
7215 | ||
7216 | RTX_FRAME_RELATED_P (insn) = 1; | |
7217 | t = gen_rtx_REG (Pmode, 31); | |
7218 | t = gen_rtx_SET (VOIDmode, mem, t); | |
7219 | t = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, t, REG_NOTES (insn)); | |
7220 | REG_NOTES (insn) = t; | |
7221 | ||
7222 | reg_offset += 8; | |
7223 | } | |
7224 | ||
7225 | for (i = 0; i < 31; i++) | |
df7d0d23 | 7226 | if (fmask & (1UL << i)) |
9caef960 | 7227 | { |
7228 | mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset)); | |
7229 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7230 | FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32))); | |
7231 | reg_offset += 8; | |
7232 | } | |
7233 | } | |
b19d7ab1 | 7234 | else if (TARGET_ABI_UNICOSMK && alpha_procedure_type == PT_STACK) |
9caef960 | 7235 | { |
7236 | /* The standard frame on the T3E includes space for saving registers. | |
7237 | We just have to use it. We don't have to save the return address and | |
7238 | the old frame pointer here - they are saved in the DSIB. */ | |
7239 | ||
7240 | reg_offset = -56; | |
7241 | for (i = 9; i < 15; i++) | |
df7d0d23 | 7242 | if (imask & (1UL << i)) |
9caef960 | 7243 | { |
7244 | mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx, | |
7245 | reg_offset)); | |
7246 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7247 | FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i))); | |
7248 | reg_offset -= 8; | |
7249 | } | |
7250 | for (i = 2; i < 10; i++) | |
df7d0d23 | 7251 | if (fmask & (1UL << i)) |
9caef960 | 7252 | { |
7253 | mem = gen_rtx_MEM (DFmode, plus_constant (hard_frame_pointer_rtx, | |
7254 | reg_offset)); | |
7255 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7256 | FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32))); | |
7257 | reg_offset -= 8; | |
7258 | } | |
7259 | } | |
8df4a58b | 7260 | |
1467e953 | 7261 | if (TARGET_ABI_OPEN_VMS) |
8df4a58b | 7262 | { |
b19d7ab1 | 7263 | if (alpha_procedure_type == PT_REGISTER) |
7264 | /* Register frame procedures save the fp. | |
7265 | ?? Ought to have a dwarf2 save for this. */ | |
6d50e356 | 7266 | emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno), |
7267 | hard_frame_pointer_rtx); | |
8df4a58b | 7268 | |
b19d7ab1 | 7269 | if (alpha_procedure_type != PT_NULL && vms_base_regno != REG_PV) |
6d50e356 | 7270 | emit_insn (gen_force_movdi (gen_rtx_REG (DImode, vms_base_regno), |
7271 | gen_rtx_REG (DImode, REG_PV))); | |
8df4a58b | 7272 | |
b19d7ab1 | 7273 | if (alpha_procedure_type != PT_NULL |
7274 | && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM) | |
205b281f | 7275 | FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); |
8df4a58b | 7276 | |
b9a5aa8e | 7277 | /* If we have to allocate space for outgoing args, do it now. */ |
7278 | if (current_function_outgoing_args_size != 0) | |
81a5b286 | 7279 | { |
7280 | rtx seq | |
7281 | = emit_move_insn (stack_pointer_rtx, | |
7282 | plus_constant | |
7283 | (hard_frame_pointer_rtx, | |
7284 | - (ALPHA_ROUND | |
7285 | (current_function_outgoing_args_size)))); | |
7286 | ||
7287 | /* Only set FRAME_RELATED_P on the stack adjustment we just emitted | |
7288 | if ! frame_pointer_needed. Setting the bit will change the CFA | |
7289 | computation rule to use sp again, which would be wrong if we had | |
7290 | frame_pointer_needed, as this means sp might move unpredictably | |
7291 | later on. | |
7292 | ||
7293 | Also, note that | |
7294 | frame_pointer_needed | |
7295 | => vms_unwind_regno == HARD_FRAME_POINTER_REGNUM | |
7296 | and | |
7297 | current_function_outgoing_args_size != 0 | |
7298 | => alpha_procedure_type != PT_NULL, | |
7299 | ||
7300 | so when we are not setting the bit here, we are guaranteed to | |
5910bb95 | 7301 | have emitted an FRP frame pointer update just before. */ |
81a5b286 | 7302 | RTX_FRAME_RELATED_P (seq) = ! frame_pointer_needed; |
7303 | } | |
b9a5aa8e | 7304 | } |
9caef960 | 7305 | else if (!TARGET_ABI_UNICOSMK) |
b9a5aa8e | 7306 | { |
7307 | /* If we need a frame pointer, set it from the stack pointer. */ | |
7308 | if (frame_pointer_needed) | |
7309 | { | |
7310 | if (TARGET_CAN_FAULT_IN_PROLOGUE) | |
5a965225 | 7311 | FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); |
8df4a58b | 7312 | else |
205b281f | 7313 | /* This must always be the last instruction in the |
7314 | prologue, thus we emit a special move + clobber. */ | |
5a965225 | 7315 | FRP (emit_insn (gen_init_fp (hard_frame_pointer_rtx, |
7316 | stack_pointer_rtx, sa_reg))); | |
8df4a58b | 7317 | } |
8df4a58b | 7318 | } |
7319 | ||
b9a5aa8e | 7320 | /* The ABIs for VMS and OSF/1 say that while we can schedule insns into |
7321 | the prologue, for exception handling reasons, we cannot do this for | |
7322 | any insn that might fault. We could prevent this for mems with a | |
7323 | (clobber:BLK (scratch)), but this doesn't work for fp insns. So we | |
7324 | have to prevent all such scheduling with a blockage. | |
8df4a58b | 7325 | |
b9a5aa8e | 7326 | Linux, on the other hand, never bothered to implement OSF/1's |
7327 | exception handling, and so doesn't care about such things. Anyone | |
7328 | planning to use dwarf2 frame-unwind info can also omit the blockage. */ | |
8df4a58b | 7329 | |
b9a5aa8e | 7330 | if (! TARGET_CAN_FAULT_IN_PROLOGUE) |
7331 | emit_insn (gen_blockage ()); | |
1fce2e8a | 7332 | } |
7333 | ||
2cf1388a | 7334 | /* Output the textual info surrounding the prologue. */ |
8df4a58b | 7335 | |
b9a5aa8e | 7336 | void |
92643d95 | 7337 | alpha_start_function (FILE *file, const char *fnname, |
7338 | tree decl ATTRIBUTE_UNUSED) | |
0c0464e6 | 7339 | { |
b9a5aa8e | 7340 | unsigned long imask = 0; |
7341 | unsigned long fmask = 0; | |
7342 | /* Stack space needed for pushing registers clobbered by us. */ | |
7343 | HOST_WIDE_INT sa_size; | |
7344 | /* Complete stack size needed. */ | |
f9e9d81d | 7345 | unsigned HOST_WIDE_INT frame_size; |
b9a5aa8e | 7346 | /* Offset from base reg to register save area. */ |
7347 | HOST_WIDE_INT reg_offset; | |
2cf1388a | 7348 | char *entry_label = (char *) alloca (strlen (fnname) + 6); |
b9a5aa8e | 7349 | int i; |
0c0464e6 | 7350 | |
9caef960 | 7351 | /* Don't emit an extern directive for functions defined in the same file. */ |
7352 | if (TARGET_ABI_UNICOSMK) | |
7353 | { | |
7354 | tree name_tree; | |
7355 | name_tree = get_identifier (fnname); | |
7356 | TREE_ASM_WRITTEN (name_tree) = 1; | |
7357 | } | |
7358 | ||
a314eb5e | 7359 | alpha_fnname = fnname; |
b9a5aa8e | 7360 | sa_size = alpha_sa_size (); |
0c0464e6 | 7361 | |
b9a5aa8e | 7362 | frame_size = get_frame_size (); |
1467e953 | 7363 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7364 | frame_size = ALPHA_ROUND (sa_size |
b19d7ab1 | 7365 | + (alpha_procedure_type == PT_STACK ? 8 : 0) |
b9a5aa8e | 7366 | + frame_size |
7367 | + current_function_pretend_args_size); | |
9caef960 | 7368 | else if (TARGET_ABI_UNICOSMK) |
7369 | frame_size = ALPHA_ROUND (sa_size | |
b19d7ab1 | 7370 | + (alpha_procedure_type == PT_STACK ? 48 : 0)) |
9caef960 | 7371 | + ALPHA_ROUND (frame_size |
7372 | + current_function_outgoing_args_size); | |
b9a5aa8e | 7373 | else |
7374 | frame_size = (ALPHA_ROUND (current_function_outgoing_args_size) | |
7375 | + sa_size | |
7376 | + ALPHA_ROUND (frame_size | |
7377 | + current_function_pretend_args_size)); | |
0c0464e6 | 7378 | |
1467e953 | 7379 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7380 | reg_offset = 8; |
7381 | else | |
7382 | reg_offset = ALPHA_ROUND (current_function_outgoing_args_size); | |
0c0464e6 | 7383 | |
b9a5aa8e | 7384 | alpha_sa_mask (&imask, &fmask); |
bf2a98b3 | 7385 | |
0e0a0e7a | 7386 | /* Ecoff can handle multiple .file directives, so put out file and lineno. |
449b7f2d | 7387 | We have to do that before the .ent directive as we cannot switch |
7388 | files within procedures with native ecoff because line numbers are | |
7389 | linked to procedure descriptors. | |
7390 | Outputting the lineno helps debugging of one line functions as they | |
7391 | would otherwise get no line number at all. Please note that we would | |
01cc3b75 | 7392 | like to put out last_linenum from final.c, but it is not accessible. */ |
449b7f2d | 7393 | |
7394 | if (write_symbols == SDB_DEBUG) | |
7395 | { | |
9caef960 | 7396 | #ifdef ASM_OUTPUT_SOURCE_FILENAME |
346064d9 | 7397 | ASM_OUTPUT_SOURCE_FILENAME (file, |
7398 | DECL_SOURCE_FILE (current_function_decl)); | |
9caef960 | 7399 | #endif |
7400 | #ifdef ASM_OUTPUT_SOURCE_LINE | |
449b7f2d | 7401 | if (debug_info_level != DINFO_LEVEL_TERSE) |
346064d9 | 7402 | ASM_OUTPUT_SOURCE_LINE (file, |
7403 | DECL_SOURCE_LINE (current_function_decl), 0); | |
9caef960 | 7404 | #endif |
449b7f2d | 7405 | } |
7406 | ||
b9a5aa8e | 7407 | /* Issue function start and label. */ |
9caef960 | 7408 | if (TARGET_ABI_OPEN_VMS |
7409 | || (!TARGET_ABI_UNICOSMK && !flag_inhibit_size_directive)) | |
f1fe649e | 7410 | { |
b9a5aa8e | 7411 | fputs ("\t.ent ", file); |
2cf1388a | 7412 | assemble_name (file, fnname); |
b9a5aa8e | 7413 | putc ('\n', file); |
a314eb5e | 7414 | |
7415 | /* If the function needs GP, we'll write the "..ng" label there. | |
7416 | Otherwise, do it here. */ | |
961d6ddd | 7417 | if (TARGET_ABI_OSF |
7418 | && ! alpha_function_needs_gp | |
7419 | && ! current_function_is_thunk) | |
a314eb5e | 7420 | { |
7421 | putc ('$', file); | |
7422 | assemble_name (file, fnname); | |
7423 | fputs ("..ng:\n", file); | |
7424 | } | |
f1fe649e | 7425 | } |
449b7f2d | 7426 | |
2cf1388a | 7427 | strcpy (entry_label, fnname); |
1467e953 | 7428 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7429 | strcat (entry_label, "..en"); |
9caef960 | 7430 | |
7431 | /* For public functions, the label must be globalized by appending an | |
7432 | additional colon. */ | |
7433 | if (TARGET_ABI_UNICOSMK && TREE_PUBLIC (decl)) | |
7434 | strcat (entry_label, ":"); | |
7435 | ||
b9a5aa8e | 7436 | ASM_OUTPUT_LABEL (file, entry_label); |
7437 | inside_function = TRUE; | |
449b7f2d | 7438 | |
1467e953 | 7439 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7440 | fprintf (file, "\t.base $%d\n", vms_base_regno); |
bf2a98b3 | 7441 | |
9caef960 | 7442 | if (!TARGET_ABI_OPEN_VMS && !TARGET_ABI_UNICOSMK && TARGET_IEEE_CONFORMANT |
b9a5aa8e | 7443 | && !flag_inhibit_size_directive) |
9c0e5703 | 7444 | { |
b9a5aa8e | 7445 | /* Set flags in procedure descriptor to request IEEE-conformant |
7446 | math-library routines. The value we set it to is PDSC_EXC_IEEE | |
65abff06 | 7447 | (/usr/include/pdsc.h). */ |
b9a5aa8e | 7448 | fputs ("\t.eflag 48\n", file); |
9c0e5703 | 7449 | } |
bf2a98b3 | 7450 | |
b9a5aa8e | 7451 | /* Set up offsets to alpha virtual arg/local debugging pointer. */ |
7452 | alpha_auto_offset = -frame_size + current_function_pretend_args_size; | |
7453 | alpha_arg_offset = -frame_size + 48; | |
cb015df5 | 7454 | |
b9a5aa8e | 7455 | /* Describe our frame. If the frame size is larger than an integer, |
7456 | print it as zero to avoid an assembler error. We won't be | |
7457 | properly describing such a frame, but that's the best we can do. */ | |
9caef960 | 7458 | if (TARGET_ABI_UNICOSMK) |
7459 | ; | |
7460 | else if (TARGET_ABI_OPEN_VMS) | |
4840a03a | 7461 | fprintf (file, "\t.frame $%d," HOST_WIDE_INT_PRINT_DEC ",$26," |
7462 | HOST_WIDE_INT_PRINT_DEC "\n", | |
7463 | vms_unwind_regno, | |
7464 | frame_size >= (1UL << 31) ? 0 : frame_size, | |
7465 | reg_offset); | |
b9a5aa8e | 7466 | else if (!flag_inhibit_size_directive) |
4840a03a | 7467 | fprintf (file, "\t.frame $%d," HOST_WIDE_INT_PRINT_DEC ",$26,%d\n", |
7468 | (frame_pointer_needed | |
7469 | ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM), | |
7470 | frame_size >= (1UL << 31) ? 0 : frame_size, | |
7471 | current_function_pretend_args_size); | |
15d5236f | 7472 | |
b9a5aa8e | 7473 | /* Describe which registers were spilled. */ |
9caef960 | 7474 | if (TARGET_ABI_UNICOSMK) |
7475 | ; | |
7476 | else if (TARGET_ABI_OPEN_VMS) | |
15d5236f | 7477 | { |
b9a5aa8e | 7478 | if (imask) |
9caef960 | 7479 | /* ??? Does VMS care if mask contains ra? The old code didn't |
b9a5aa8e | 7480 | set it, so I don't here. */ |
df7d0d23 | 7481 | fprintf (file, "\t.mask 0x%lx,0\n", imask & ~(1UL << REG_RA)); |
b9a5aa8e | 7482 | if (fmask) |
769ea120 | 7483 | fprintf (file, "\t.fmask 0x%lx,0\n", fmask); |
b19d7ab1 | 7484 | if (alpha_procedure_type == PT_REGISTER) |
b9a5aa8e | 7485 | fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno); |
7486 | } | |
7487 | else if (!flag_inhibit_size_directive) | |
7488 | { | |
7489 | if (imask) | |
15d5236f | 7490 | { |
4840a03a | 7491 | fprintf (file, "\t.mask 0x%lx," HOST_WIDE_INT_PRINT_DEC "\n", imask, |
df7d0d23 | 7492 | frame_size >= (1UL << 31) ? 0 : reg_offset - frame_size); |
b9a5aa8e | 7493 | |
7494 | for (i = 0; i < 32; ++i) | |
df7d0d23 | 7495 | if (imask & (1UL << i)) |
b9a5aa8e | 7496 | reg_offset += 8; |
15d5236f | 7497 | } |
b9a5aa8e | 7498 | |
7499 | if (fmask) | |
4840a03a | 7500 | fprintf (file, "\t.fmask 0x%lx," HOST_WIDE_INT_PRINT_DEC "\n", fmask, |
7501 | frame_size >= (1UL << 31) ? 0 : reg_offset - frame_size); | |
bf2a98b3 | 7502 | } |
7503 | ||
1467e953 | 7504 | #if TARGET_ABI_OPEN_VMS |
6cde52a2 | 7505 | /* Ifdef'ed cause link_section are only available then. */ |
7506 | readonly_data_section (); | |
b9a5aa8e | 7507 | fprintf (file, "\t.align 3\n"); |
2cf1388a | 7508 | assemble_name (file, fnname); fputs ("..na:\n", file); |
b9a5aa8e | 7509 | fputs ("\t.ascii \"", file); |
2cf1388a | 7510 | assemble_name (file, fnname); |
b9a5aa8e | 7511 | fputs ("\\0\"\n", file); |
2cf1388a | 7512 | alpha_need_linkage (fnname, 1); |
b9a5aa8e | 7513 | text_section (); |
7514 | #endif | |
7515 | } | |
bf2a98b3 | 7516 | |
b9a5aa8e | 7517 | /* Emit the .prologue note at the scheduled end of the prologue. */ |
16b3392b | 7518 | |
85ae73e8 | 7519 | static void |
92643d95 | 7520 | alpha_output_function_end_prologue (FILE *file) |
b9a5aa8e | 7521 | { |
9caef960 | 7522 | if (TARGET_ABI_UNICOSMK) |
7523 | ; | |
7524 | else if (TARGET_ABI_OPEN_VMS) | |
b9a5aa8e | 7525 | fputs ("\t.prologue\n", file); |
1467e953 | 7526 | else if (TARGET_ABI_WINDOWS_NT) |
b9a5aa8e | 7527 | fputs ("\t.prologue 0\n", file); |
7528 | else if (!flag_inhibit_size_directive) | |
961d6ddd | 7529 | fprintf (file, "\t.prologue %d\n", |
7530 | alpha_function_needs_gp || current_function_is_thunk); | |
bf2a98b3 | 7531 | } |
7532 | ||
7533 | /* Write function epilogue. */ | |
7534 | ||
5a965225 | 7535 | /* ??? At some point we will want to support full unwind, and so will |
7536 | need to mark the epilogue as well. At the moment, we just confuse | |
7537 | dwarf2out. */ | |
7538 | #undef FRP | |
7539 | #define FRP(exp) exp | |
7540 | ||
bf2a98b3 | 7541 | void |
92643d95 | 7542 | alpha_expand_epilogue (void) |
bf2a98b3 | 7543 | { |
b9a5aa8e | 7544 | /* Registers to save. */ |
7545 | unsigned long imask = 0; | |
7546 | unsigned long fmask = 0; | |
7547 | /* Stack space needed for pushing registers clobbered by us. */ | |
7548 | HOST_WIDE_INT sa_size; | |
7549 | /* Complete stack size needed. */ | |
7550 | HOST_WIDE_INT frame_size; | |
7551 | /* Offset from base reg to register save area. */ | |
7552 | HOST_WIDE_INT reg_offset; | |
7553 | int fp_is_frame_pointer, fp_offset; | |
7554 | rtx sa_reg, sa_reg_exp = NULL; | |
849674a3 | 7555 | rtx sp_adj1, sp_adj2, mem; |
11016d99 | 7556 | rtx eh_ofs; |
bf2a98b3 | 7557 | int i; |
7558 | ||
b9a5aa8e | 7559 | sa_size = alpha_sa_size (); |
bf2a98b3 | 7560 | |
b9a5aa8e | 7561 | frame_size = get_frame_size (); |
1467e953 | 7562 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7563 | frame_size = ALPHA_ROUND (sa_size |
b19d7ab1 | 7564 | + (alpha_procedure_type == PT_STACK ? 8 : 0) |
b9a5aa8e | 7565 | + frame_size |
7566 | + current_function_pretend_args_size); | |
9caef960 | 7567 | else if (TARGET_ABI_UNICOSMK) |
7568 | frame_size = ALPHA_ROUND (sa_size | |
b19d7ab1 | 7569 | + (alpha_procedure_type == PT_STACK ? 48 : 0)) |
9caef960 | 7570 | + ALPHA_ROUND (frame_size |
7571 | + current_function_outgoing_args_size); | |
b9a5aa8e | 7572 | else |
7573 | frame_size = (ALPHA_ROUND (current_function_outgoing_args_size) | |
7574 | + sa_size | |
7575 | + ALPHA_ROUND (frame_size | |
7576 | + current_function_pretend_args_size)); | |
bf2a98b3 | 7577 | |
1467e953 | 7578 | if (TARGET_ABI_OPEN_VMS) |
b19d7ab1 | 7579 | { |
7580 | if (alpha_procedure_type == PT_STACK) | |
7581 | reg_offset = 8; | |
7582 | else | |
7583 | reg_offset = 0; | |
7584 | } | |
b9a5aa8e | 7585 | else |
7586 | reg_offset = ALPHA_ROUND (current_function_outgoing_args_size); | |
7587 | ||
7588 | alpha_sa_mask (&imask, &fmask); | |
7589 | ||
b19d7ab1 | 7590 | fp_is_frame_pointer |
7591 | = ((TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK) | |
7592 | || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed)); | |
29768226 | 7593 | fp_offset = 0; |
7594 | sa_reg = stack_pointer_rtx; | |
b9a5aa8e | 7595 | |
c92c328f | 7596 | if (current_function_calls_eh_return) |
7597 | eh_ofs = EH_RETURN_STACKADJ_RTX; | |
7598 | else | |
7599 | eh_ofs = NULL_RTX; | |
7600 | ||
9caef960 | 7601 | if (!TARGET_ABI_UNICOSMK && sa_size) |
b9a5aa8e | 7602 | { |
7603 | /* If we have a frame pointer, restore SP from it. */ | |
1467e953 | 7604 | if ((TARGET_ABI_OPEN_VMS |
b9a5aa8e | 7605 | && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM) |
1467e953 | 7606 | || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed)) |
205b281f | 7607 | FRP (emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx)); |
15d5236f | 7608 | |
b9a5aa8e | 7609 | /* Cope with very large offsets to the register save area. */ |
b9a5aa8e | 7610 | if (reg_offset + sa_size > 0x8000) |
bf2a98b3 | 7611 | { |
b9a5aa8e | 7612 | int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000; |
7613 | HOST_WIDE_INT bias; | |
7614 | ||
7615 | if (low + sa_size <= 0x8000) | |
7616 | bias = reg_offset - low, reg_offset = low; | |
7617 | else | |
7618 | bias = reg_offset, reg_offset = 0; | |
7619 | ||
7620 | sa_reg = gen_rtx_REG (DImode, 22); | |
7621 | sa_reg_exp = plus_constant (stack_pointer_rtx, bias); | |
7622 | ||
5a965225 | 7623 | FRP (emit_move_insn (sa_reg, sa_reg_exp)); |
bf2a98b3 | 7624 | } |
b9a5aa8e | 7625 | |
65abff06 | 7626 | /* Restore registers in order, excepting a true frame pointer. */ |
bf2a98b3 | 7627 | |
c92c328f | 7628 | mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); |
11016d99 | 7629 | if (! eh_ofs) |
ab6ab77e | 7630 | set_mem_alias_set (mem, alpha_sr_alias_set); |
c92c328f | 7631 | FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem)); |
7632 | ||
b9a5aa8e | 7633 | reg_offset += 8; |
df7d0d23 | 7634 | imask &= ~(1UL << REG_RA); |
16b3392b | 7635 | |
c49ad9ef | 7636 | for (i = 0; i < 31; ++i) |
df7d0d23 | 7637 | if (imask & (1UL << i)) |
bf2a98b3 | 7638 | { |
b9a5aa8e | 7639 | if (i == HARD_FRAME_POINTER_REGNUM && fp_is_frame_pointer) |
16b3392b | 7640 | fp_offset = reg_offset; |
7641 | else | |
b9a5aa8e | 7642 | { |
849674a3 | 7643 | mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset)); |
ab6ab77e | 7644 | set_mem_alias_set (mem, alpha_sr_alias_set); |
849674a3 | 7645 | FRP (emit_move_insn (gen_rtx_REG (DImode, i), mem)); |
b9a5aa8e | 7646 | } |
bf2a98b3 | 7647 | reg_offset += 8; |
7648 | } | |
7649 | ||
c49ad9ef | 7650 | if (imask & (1UL << 31)) |
7651 | reg_offset += 8; | |
7652 | ||
7653 | for (i = 0; i < 31; ++i) | |
df7d0d23 | 7654 | if (fmask & (1UL << i)) |
bf2a98b3 | 7655 | { |
849674a3 | 7656 | mem = gen_rtx_MEM (DFmode, plus_constant(sa_reg, reg_offset)); |
ab6ab77e | 7657 | set_mem_alias_set (mem, alpha_sr_alias_set); |
849674a3 | 7658 | FRP (emit_move_insn (gen_rtx_REG (DFmode, i+32), mem)); |
bf2a98b3 | 7659 | reg_offset += 8; |
7660 | } | |
b9a5aa8e | 7661 | } |
b19d7ab1 | 7662 | else if (TARGET_ABI_UNICOSMK && alpha_procedure_type == PT_STACK) |
9caef960 | 7663 | { |
7664 | /* Restore callee-saved general-purpose registers. */ | |
7665 | ||
7666 | reg_offset = -56; | |
7667 | ||
7668 | for (i = 9; i < 15; i++) | |
df7d0d23 | 7669 | if (imask & (1UL << i)) |
9caef960 | 7670 | { |
7671 | mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx, | |
7672 | reg_offset)); | |
7673 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7674 | FRP (emit_move_insn (gen_rtx_REG (DImode, i), mem)); | |
7675 | reg_offset -= 8; | |
7676 | } | |
7677 | ||
7678 | for (i = 2; i < 10; i++) | |
df7d0d23 | 7679 | if (fmask & (1UL << i)) |
9caef960 | 7680 | { |
7681 | mem = gen_rtx_MEM (DFmode, plus_constant(hard_frame_pointer_rtx, | |
7682 | reg_offset)); | |
7683 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7684 | FRP (emit_move_insn (gen_rtx_REG (DFmode, i+32), mem)); | |
7685 | reg_offset -= 8; | |
7686 | } | |
7687 | ||
7688 | /* Restore the return address from the DSIB. */ | |
7689 | ||
7690 | mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx, -8)); | |
7691 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7692 | FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem)); | |
7693 | } | |
bf2a98b3 | 7694 | |
11016d99 | 7695 | if (frame_size || eh_ofs) |
b9a5aa8e | 7696 | { |
ec37ccb4 | 7697 | sp_adj1 = stack_pointer_rtx; |
7698 | ||
11016d99 | 7699 | if (eh_ofs) |
ec37ccb4 | 7700 | { |
7701 | sp_adj1 = gen_rtx_REG (DImode, 23); | |
7702 | emit_move_insn (sp_adj1, | |
11016d99 | 7703 | gen_rtx_PLUS (Pmode, stack_pointer_rtx, eh_ofs)); |
ec37ccb4 | 7704 | } |
7705 | ||
b9a5aa8e | 7706 | /* If the stack size is large, begin computation into a temporary |
7707 | register so as not to interfere with a potential fp restore, | |
7708 | which must be consecutive with an SP restore. */ | |
9caef960 | 7709 | if (frame_size < 32768 |
7710 | && ! (TARGET_ABI_UNICOSMK && current_function_calls_alloca)) | |
ec37ccb4 | 7711 | sp_adj2 = GEN_INT (frame_size); |
9caef960 | 7712 | else if (TARGET_ABI_UNICOSMK) |
7713 | { | |
7714 | sp_adj1 = gen_rtx_REG (DImode, 23); | |
7715 | FRP (emit_move_insn (sp_adj1, hard_frame_pointer_rtx)); | |
7716 | sp_adj2 = const0_rtx; | |
7717 | } | |
b9a5aa8e | 7718 | else if (frame_size < 0x40007fffL) |
7719 | { | |
7720 | int low = ((frame_size & 0xffff) ^ 0x8000) - 0x8000; | |
7721 | ||
ec37ccb4 | 7722 | sp_adj2 = plus_constant (sp_adj1, frame_size - low); |
b9a5aa8e | 7723 | if (sa_reg_exp && rtx_equal_p (sa_reg_exp, sp_adj2)) |
7724 | sp_adj1 = sa_reg; | |
7725 | else | |
7726 | { | |
7727 | sp_adj1 = gen_rtx_REG (DImode, 23); | |
5a965225 | 7728 | FRP (emit_move_insn (sp_adj1, sp_adj2)); |
b9a5aa8e | 7729 | } |
7730 | sp_adj2 = GEN_INT (low); | |
7731 | } | |
0e0a0e7a | 7732 | else |
b9a5aa8e | 7733 | { |
ec37ccb4 | 7734 | rtx tmp = gen_rtx_REG (DImode, 23); |
7735 | FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, 3)); | |
7736 | if (!sp_adj2) | |
b9a5aa8e | 7737 | { |
7738 | /* We can't drop new things to memory this late, afaik, | |
7739 | so build it up by pieces. */ | |
af792316 | 7740 | FRP (sp_adj2 = alpha_emit_set_long_const (tmp, frame_size, |
7741 | -(frame_size < 0))); | |
ec37ccb4 | 7742 | if (!sp_adj2) |
b9a5aa8e | 7743 | abort (); |
b9a5aa8e | 7744 | } |
b9a5aa8e | 7745 | } |
bf2a98b3 | 7746 | |
b9a5aa8e | 7747 | /* From now on, things must be in order. So emit blockages. */ |
7748 | ||
7749 | /* Restore the frame pointer. */ | |
9caef960 | 7750 | if (TARGET_ABI_UNICOSMK) |
7751 | { | |
7752 | emit_insn (gen_blockage ()); | |
7753 | mem = gen_rtx_MEM (DImode, | |
7754 | plus_constant (hard_frame_pointer_rtx, -16)); | |
7755 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
7756 | FRP (emit_move_insn (hard_frame_pointer_rtx, mem)); | |
7757 | } | |
7758 | else if (fp_is_frame_pointer) | |
b9a5aa8e | 7759 | { |
7760 | emit_insn (gen_blockage ()); | |
205b281f | 7761 | mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, fp_offset)); |
ab6ab77e | 7762 | set_mem_alias_set (mem, alpha_sr_alias_set); |
849674a3 | 7763 | FRP (emit_move_insn (hard_frame_pointer_rtx, mem)); |
b9a5aa8e | 7764 | } |
1467e953 | 7765 | else if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7766 | { |
7767 | emit_insn (gen_blockage ()); | |
5a965225 | 7768 | FRP (emit_move_insn (hard_frame_pointer_rtx, |
7769 | gen_rtx_REG (DImode, vms_save_fp_regno))); | |
b9a5aa8e | 7770 | } |
7771 | ||
7772 | /* Restore the stack pointer. */ | |
7773 | emit_insn (gen_blockage ()); | |
9caef960 | 7774 | if (sp_adj2 == const0_rtx) |
7775 | FRP (emit_move_insn (stack_pointer_rtx, sp_adj1)); | |
7776 | else | |
7777 | FRP (emit_move_insn (stack_pointer_rtx, | |
7778 | gen_rtx_PLUS (DImode, sp_adj1, sp_adj2))); | |
b9a5aa8e | 7779 | } |
7780 | else | |
7781 | { | |
b19d7ab1 | 7782 | if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_REGISTER) |
b9a5aa8e | 7783 | { |
7784 | emit_insn (gen_blockage ()); | |
5a965225 | 7785 | FRP (emit_move_insn (hard_frame_pointer_rtx, |
7786 | gen_rtx_REG (DImode, vms_save_fp_regno))); | |
b9a5aa8e | 7787 | } |
b19d7ab1 | 7788 | else if (TARGET_ABI_UNICOSMK && alpha_procedure_type != PT_STACK) |
9caef960 | 7789 | { |
7790 | /* Decrement the frame pointer if the function does not have a | |
7791 | frame. */ | |
7792 | ||
7793 | emit_insn (gen_blockage ()); | |
7794 | FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx, | |
bcd9bd66 | 7795 | hard_frame_pointer_rtx, constm1_rtx))); |
9caef960 | 7796 | } |
bf2a98b3 | 7797 | } |
b9a5aa8e | 7798 | } |
cf73d31f | 7799 | \f |
b9a5aa8e | 7800 | /* Output the rest of the textual info surrounding the epilogue. */ |
7801 | ||
7802 | void | |
92643d95 | 7803 | alpha_end_function (FILE *file, const char *fnname, tree decl ATTRIBUTE_UNUSED) |
b9a5aa8e | 7804 | { |
04b0d94a | 7805 | #if TARGET_ABI_OPEN_VMS |
7806 | alpha_write_linkage (file, fnname, decl); | |
7807 | #endif | |
7808 | ||
bf2a98b3 | 7809 | /* End the function. */ |
9caef960 | 7810 | if (!TARGET_ABI_UNICOSMK && !flag_inhibit_size_directive) |
f1fe649e | 7811 | { |
b9a5aa8e | 7812 | fputs ("\t.end ", file); |
2cf1388a | 7813 | assemble_name (file, fnname); |
b9a5aa8e | 7814 | putc ('\n', file); |
f1fe649e | 7815 | } |
449b7f2d | 7816 | inside_function = FALSE; |
9c0e5703 | 7817 | |
9caef960 | 7818 | /* Output jump tables and the static subroutine information block. */ |
7819 | if (TARGET_ABI_UNICOSMK) | |
7820 | { | |
7821 | unicosmk_output_ssib (file, fnname); | |
7822 | unicosmk_output_deferred_case_vectors (file); | |
7823 | } | |
bf2a98b3 | 7824 | } |
961d6ddd | 7825 | |
6988553d | 7826 | #if TARGET_ABI_OSF |
7827 | /* Emit a tail call to FUNCTION after adjusting THIS by DELTA. | |
961d6ddd | 7828 | |
7829 | In order to avoid the hordes of differences between generated code | |
7830 | with and without TARGET_EXPLICIT_RELOCS, and to avoid duplicating | |
7831 | lots of code loading up large constants, generate rtl and emit it | |
7832 | instead of going straight to text. | |
7833 | ||
7834 | Not sure why this idea hasn't been explored before... */ | |
7835 | ||
6988553d | 7836 | static void |
92643d95 | 7837 | alpha_output_mi_thunk_osf (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, |
7838 | HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, | |
7839 | tree function) | |
961d6ddd | 7840 | { |
7841 | HOST_WIDE_INT hi, lo; | |
7842 | rtx this, insn, funexp; | |
7843 | ||
656047bf | 7844 | reset_block_changes (); |
7845 | ||
961d6ddd | 7846 | /* We always require a valid GP. */ |
7847 | emit_insn (gen_prologue_ldgp ()); | |
31b97e8f | 7848 | emit_note (NOTE_INSN_PROLOGUE_END); |
961d6ddd | 7849 | |
7850 | /* Find the "this" pointer. If the function returns a structure, | |
7851 | the structure return pointer is in $16. */ | |
45550790 | 7852 | if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) |
961d6ddd | 7853 | this = gen_rtx_REG (Pmode, 17); |
7854 | else | |
7855 | this = gen_rtx_REG (Pmode, 16); | |
7856 | ||
7857 | /* Add DELTA. When possible we use ldah+lda. Otherwise load the | |
7858 | entire constant for the add. */ | |
7859 | lo = ((delta & 0xffff) ^ 0x8000) - 0x8000; | |
7860 | hi = (((delta - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
7861 | if (hi + lo == delta) | |
7862 | { | |
7863 | if (hi) | |
7864 | emit_insn (gen_adddi3 (this, this, GEN_INT (hi))); | |
7865 | if (lo) | |
7866 | emit_insn (gen_adddi3 (this, this, GEN_INT (lo))); | |
7867 | } | |
7868 | else | |
7869 | { | |
7870 | rtx tmp = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 0), | |
7871 | delta, -(delta < 0)); | |
7872 | emit_insn (gen_adddi3 (this, this, tmp)); | |
7873 | } | |
7874 | ||
a19ec9da | 7875 | /* Add a delta stored in the vtable at VCALL_OFFSET. */ |
7876 | if (vcall_offset) | |
7877 | { | |
7878 | rtx tmp, tmp2; | |
7879 | ||
7880 | tmp = gen_rtx_REG (Pmode, 0); | |
7881 | emit_move_insn (tmp, gen_rtx_MEM (Pmode, this)); | |
7882 | ||
7883 | lo = ((vcall_offset & 0xffff) ^ 0x8000) - 0x8000; | |
7884 | hi = (((vcall_offset - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
7885 | if (hi + lo == vcall_offset) | |
7886 | { | |
7887 | if (hi) | |
7888 | emit_insn (gen_adddi3 (tmp, tmp, GEN_INT (hi))); | |
7889 | } | |
7890 | else | |
7891 | { | |
7892 | tmp2 = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 1), | |
7893 | vcall_offset, -(vcall_offset < 0)); | |
7894 | emit_insn (gen_adddi3 (tmp, tmp, tmp2)); | |
7895 | lo = 0; | |
7896 | } | |
7897 | if (lo) | |
7898 | tmp2 = gen_rtx_PLUS (Pmode, tmp, GEN_INT (lo)); | |
7899 | else | |
7900 | tmp2 = tmp; | |
7901 | emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp2)); | |
7902 | ||
7903 | emit_insn (gen_adddi3 (this, this, tmp)); | |
7904 | } | |
7905 | ||
961d6ddd | 7906 | /* Generate a tail call to the target function. */ |
7907 | if (! TREE_USED (function)) | |
7908 | { | |
7909 | assemble_external (function); | |
7910 | TREE_USED (function) = 1; | |
7911 | } | |
7912 | funexp = XEXP (DECL_RTL (function), 0); | |
7913 | funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); | |
7914 | insn = emit_call_insn (gen_sibcall (funexp, const0_rtx)); | |
7915 | SIBLING_CALL_P (insn) = 1; | |
7916 | ||
7917 | /* Run just enough of rest_of_compilation to get the insns emitted. | |
7918 | There's not really enough bulk here to make other passes such as | |
7919 | instruction scheduling worth while. Note that use_thunk calls | |
7920 | assemble_start_function and assemble_end_function. */ | |
7921 | insn = get_insns (); | |
50494502 | 7922 | insn_locators_initialize (); |
961d6ddd | 7923 | shorten_branches (insn); |
7924 | final_start_function (insn, file, 1); | |
7925 | final (insn, file, 1, 0); | |
7926 | final_end_function (); | |
7927 | } | |
6988553d | 7928 | #endif /* TARGET_ABI_OSF */ |
449b7f2d | 7929 | \f |
7930 | /* Debugging support. */ | |
7931 | ||
7932 | #include "gstab.h" | |
7933 | ||
7934 | /* Count the number of sdb related labels are generated (to find block | |
7935 | start and end boundaries). */ | |
7936 | ||
7937 | int sdb_label_count = 0; | |
7938 | ||
7939 | /* Next label # for each statement. */ | |
7940 | ||
7941 | static int sym_lineno = 0; | |
7942 | ||
7943 | /* Count the number of .file directives, so that .loc is up to date. */ | |
7944 | ||
7945 | static int num_source_filenames = 0; | |
7946 | ||
7947 | /* Name of the file containing the current function. */ | |
7948 | ||
ace75b22 | 7949 | static const char *current_function_file = ""; |
449b7f2d | 7950 | |
7951 | /* Offsets to alpha virtual arg/local debugging pointers. */ | |
7952 | ||
7953 | long alpha_arg_offset; | |
7954 | long alpha_auto_offset; | |
7955 | \f | |
7956 | /* Emit a new filename to a stream. */ | |
7957 | ||
7958 | void | |
92643d95 | 7959 | alpha_output_filename (FILE *stream, const char *name) |
449b7f2d | 7960 | { |
7961 | static int first_time = TRUE; | |
7962 | char ltext_label_name[100]; | |
7963 | ||
7964 | if (first_time) | |
7965 | { | |
7966 | first_time = FALSE; | |
7967 | ++num_source_filenames; | |
7968 | current_function_file = name; | |
7969 | fprintf (stream, "\t.file\t%d ", num_source_filenames); | |
7970 | output_quoted_string (stream, name); | |
7971 | fprintf (stream, "\n"); | |
7972 | if (!TARGET_GAS && write_symbols == DBX_DEBUG) | |
7973 | fprintf (stream, "\t#@stabs\n"); | |
7974 | } | |
7975 | ||
8763f243 | 7976 | else if (write_symbols == DBX_DEBUG) |
449b7f2d | 7977 | { |
7978 | ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0); | |
95d655c3 | 7979 | fprintf (stream, "%s", ASM_STABS_OP); |
449b7f2d | 7980 | output_quoted_string (stream, name); |
7981 | fprintf (stream, ",%d,0,0,%s\n", N_SOL, <ext_label_name[1]); | |
7982 | } | |
7983 | ||
7984 | else if (name != current_function_file | |
be3797c1 | 7985 | && strcmp (name, current_function_file) != 0) |
449b7f2d | 7986 | { |
7987 | if (inside_function && ! TARGET_GAS) | |
7988 | fprintf (stream, "\t#.file\t%d ", num_source_filenames); | |
7989 | else | |
7990 | { | |
7991 | ++num_source_filenames; | |
7992 | current_function_file = name; | |
7993 | fprintf (stream, "\t.file\t%d ", num_source_filenames); | |
7994 | } | |
7995 | ||
7996 | output_quoted_string (stream, name); | |
7997 | fprintf (stream, "\n"); | |
7998 | } | |
7999 | } | |
92643d95 | 8000 | |
449b7f2d | 8001 | /* Emit a linenumber to a stream. */ |
8002 | ||
8003 | void | |
92643d95 | 8004 | alpha_output_lineno (FILE *stream, int line) |
449b7f2d | 8005 | { |
8763f243 | 8006 | if (write_symbols == DBX_DEBUG) |
449b7f2d | 8007 | { |
8008 | /* mips-tfile doesn't understand .stabd directives. */ | |
8009 | ++sym_lineno; | |
95d655c3 | 8010 | fprintf (stream, "$LM%d:\n%s%d,0,%d,$LM%d\n", |
449b7f2d | 8011 | sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno); |
8012 | } | |
8013 | else | |
cffb5069 | 8014 | fprintf (stream, "\n\t.loc\t%d %d\n", num_source_filenames, line); |
449b7f2d | 8015 | } |
c4622276 | 8016 | \f |
8017 | /* Structure to show the current status of registers and memory. */ | |
8018 | ||
8019 | struct shadow_summary | |
8020 | { | |
8021 | struct { | |
495c4a78 | 8022 | unsigned int i : 31; /* Mask of int regs */ |
8023 | unsigned int fp : 31; /* Mask of fp regs */ | |
8024 | unsigned int mem : 1; /* mem == imem | fpmem */ | |
c4622276 | 8025 | } used, defd; |
8026 | }; | |
8027 | ||
8028 | /* Summary the effects of expression X on the machine. Update SUM, a pointer | |
8029 | to the summary structure. SET is nonzero if the insn is setting the | |
8030 | object, otherwise zero. */ | |
8031 | ||
8032 | static void | |
92643d95 | 8033 | summarize_insn (rtx x, struct shadow_summary *sum, int set) |
c4622276 | 8034 | { |
d2ca078f | 8035 | const char *format_ptr; |
c4622276 | 8036 | int i, j; |
8037 | ||
8038 | if (x == 0) | |
8039 | return; | |
8040 | ||
8041 | switch (GET_CODE (x)) | |
8042 | { | |
8043 | /* ??? Note that this case would be incorrect if the Alpha had a | |
8044 | ZERO_EXTRACT in SET_DEST. */ | |
8045 | case SET: | |
8046 | summarize_insn (SET_SRC (x), sum, 0); | |
8047 | summarize_insn (SET_DEST (x), sum, 1); | |
8048 | break; | |
8049 | ||
8050 | case CLOBBER: | |
8051 | summarize_insn (XEXP (x, 0), sum, 1); | |
8052 | break; | |
8053 | ||
8054 | case USE: | |
8055 | summarize_insn (XEXP (x, 0), sum, 0); | |
8056 | break; | |
8057 | ||
a886cc41 | 8058 | case ASM_OPERANDS: |
8059 | for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--) | |
8060 | summarize_insn (ASM_OPERANDS_INPUT (x, i), sum, 0); | |
8061 | break; | |
8062 | ||
c4622276 | 8063 | case PARALLEL: |
3a5dbb5e | 8064 | for (i = XVECLEN (x, 0) - 1; i >= 0; i--) |
c4622276 | 8065 | summarize_insn (XVECEXP (x, 0, i), sum, 0); |
8066 | break; | |
8067 | ||
a886cc41 | 8068 | case SUBREG: |
b9a5aa8e | 8069 | summarize_insn (SUBREG_REG (x), sum, 0); |
8070 | break; | |
a886cc41 | 8071 | |
c4622276 | 8072 | case REG: |
8073 | { | |
8074 | int regno = REGNO (x); | |
f3d263a7 | 8075 | unsigned long mask = ((unsigned long) 1) << (regno % 32); |
c4622276 | 8076 | |
8077 | if (regno == 31 || regno == 63) | |
8078 | break; | |
8079 | ||
8080 | if (set) | |
8081 | { | |
8082 | if (regno < 32) | |
8083 | sum->defd.i |= mask; | |
8084 | else | |
8085 | sum->defd.fp |= mask; | |
8086 | } | |
8087 | else | |
8088 | { | |
8089 | if (regno < 32) | |
8090 | sum->used.i |= mask; | |
8091 | else | |
8092 | sum->used.fp |= mask; | |
8093 | } | |
8094 | } | |
8095 | break; | |
8096 | ||
8097 | case MEM: | |
8098 | if (set) | |
8099 | sum->defd.mem = 1; | |
8100 | else | |
8101 | sum->used.mem = 1; | |
8102 | ||
8103 | /* Find the regs used in memory address computation: */ | |
8104 | summarize_insn (XEXP (x, 0), sum, 0); | |
8105 | break; | |
8106 | ||
2d710b28 | 8107 | case CONST_INT: case CONST_DOUBLE: |
8108 | case SYMBOL_REF: case LABEL_REF: case CONST: | |
5bdbf614 | 8109 | case SCRATCH: case ASM_INPUT: |
2d710b28 | 8110 | break; |
8111 | ||
c4622276 | 8112 | /* Handle common unary and binary ops for efficiency. */ |
8113 | case COMPARE: case PLUS: case MINUS: case MULT: case DIV: | |
8114 | case MOD: case UDIV: case UMOD: case AND: case IOR: | |
8115 | case XOR: case ASHIFT: case ROTATE: case ASHIFTRT: case LSHIFTRT: | |
8116 | case ROTATERT: case SMIN: case SMAX: case UMIN: case UMAX: | |
8117 | case NE: case EQ: case GE: case GT: case LE: | |
8118 | case LT: case GEU: case GTU: case LEU: case LTU: | |
8119 | summarize_insn (XEXP (x, 0), sum, 0); | |
8120 | summarize_insn (XEXP (x, 1), sum, 0); | |
8121 | break; | |
8122 | ||
8123 | case NEG: case NOT: case SIGN_EXTEND: case ZERO_EXTEND: | |
8124 | case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: case FLOAT: | |
8125 | case FIX: case UNSIGNED_FLOAT: case UNSIGNED_FIX: case ABS: | |
8126 | case SQRT: case FFS: | |
8127 | summarize_insn (XEXP (x, 0), sum, 0); | |
8128 | break; | |
8129 | ||
8130 | default: | |
8131 | format_ptr = GET_RTX_FORMAT (GET_CODE (x)); | |
3a5dbb5e | 8132 | for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) |
cada32d3 | 8133 | switch (format_ptr[i]) |
c4622276 | 8134 | { |
8135 | case 'e': | |
8136 | summarize_insn (XEXP (x, i), sum, 0); | |
8137 | break; | |
8138 | ||
8139 | case 'E': | |
3a5dbb5e | 8140 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) |
c4622276 | 8141 | summarize_insn (XVECEXP (x, i, j), sum, 0); |
8142 | break; | |
8143 | ||
1dc5f36f | 8144 | case 'i': |
8145 | break; | |
8146 | ||
c4622276 | 8147 | default: |
8148 | abort (); | |
8149 | } | |
8150 | } | |
8151 | } | |
c4622276 | 8152 | |
b9a5aa8e | 8153 | /* Ensure a sufficient number of `trapb' insns are in the code when |
8154 | the user requests code with a trap precision of functions or | |
8155 | instructions. | |
8156 | ||
8157 | In naive mode, when the user requests a trap-precision of | |
8158 | "instruction", a trapb is needed after every instruction that may | |
8159 | generate a trap. This ensures that the code is resumption safe but | |
8160 | it is also slow. | |
8161 | ||
8162 | When optimizations are turned on, we delay issuing a trapb as long | |
8163 | as possible. In this context, a trap shadow is the sequence of | |
8164 | instructions that starts with a (potentially) trap generating | |
8165 | instruction and extends to the next trapb or call_pal instruction | |
8166 | (but GCC never generates call_pal by itself). We can delay (and | |
8167 | therefore sometimes omit) a trapb subject to the following | |
8168 | conditions: | |
8169 | ||
8170 | (a) On entry to the trap shadow, if any Alpha register or memory | |
8171 | location contains a value that is used as an operand value by some | |
8172 | instruction in the trap shadow (live on entry), then no instruction | |
8173 | in the trap shadow may modify the register or memory location. | |
8174 | ||
8175 | (b) Within the trap shadow, the computation of the base register | |
8176 | for a memory load or store instruction may not involve using the | |
8177 | result of an instruction that might generate an UNPREDICTABLE | |
8178 | result. | |
8179 | ||
8180 | (c) Within the trap shadow, no register may be used more than once | |
8181 | as a destination register. (This is to make life easier for the | |
8182 | trap-handler.) | |
c4622276 | 8183 | |
18adf4f6 | 8184 | (d) The trap shadow may not include any branch instructions. */ |
c4622276 | 8185 | |
18adf4f6 | 8186 | static void |
92643d95 | 8187 | alpha_handle_trap_shadows (void) |
c4622276 | 8188 | { |
18adf4f6 | 8189 | struct shadow_summary shadow; |
8190 | int trap_pending, exception_nesting; | |
b9b4428b | 8191 | rtx i, n; |
c4622276 | 8192 | |
18adf4f6 | 8193 | trap_pending = 0; |
8194 | exception_nesting = 0; | |
8195 | shadow.used.i = 0; | |
8196 | shadow.used.fp = 0; | |
8197 | shadow.used.mem = 0; | |
8198 | shadow.defd = shadow.used; | |
8199 | ||
2efea8c0 | 8200 | for (i = get_insns (); i ; i = NEXT_INSN (i)) |
18adf4f6 | 8201 | { |
8202 | if (GET_CODE (i) == NOTE) | |
8203 | { | |
8204 | switch (NOTE_LINE_NUMBER (i)) | |
8205 | { | |
8206 | case NOTE_INSN_EH_REGION_BEG: | |
8207 | exception_nesting++; | |
8208 | if (trap_pending) | |
8209 | goto close_shadow; | |
8210 | break; | |
8211 | ||
8212 | case NOTE_INSN_EH_REGION_END: | |
8213 | exception_nesting--; | |
8214 | if (trap_pending) | |
8215 | goto close_shadow; | |
8216 | break; | |
8217 | ||
8218 | case NOTE_INSN_EPILOGUE_BEG: | |
8219 | if (trap_pending && alpha_tp >= ALPHA_TP_FUNC) | |
8220 | goto close_shadow; | |
8221 | break; | |
8222 | } | |
8223 | } | |
8224 | else if (trap_pending) | |
8225 | { | |
8226 | if (alpha_tp == ALPHA_TP_FUNC) | |
8227 | { | |
8228 | if (GET_CODE (i) == JUMP_INSN | |
8229 | && GET_CODE (PATTERN (i)) == RETURN) | |
8230 | goto close_shadow; | |
8231 | } | |
8232 | else if (alpha_tp == ALPHA_TP_INSN) | |
8233 | { | |
8234 | if (optimize > 0) | |
8235 | { | |
8236 | struct shadow_summary sum; | |
8237 | ||
8238 | sum.used.i = 0; | |
8239 | sum.used.fp = 0; | |
8240 | sum.used.mem = 0; | |
a886cc41 | 8241 | sum.defd = sum.used; |
18adf4f6 | 8242 | |
8243 | switch (GET_CODE (i)) | |
8244 | { | |
8245 | case INSN: | |
fad0a39b | 8246 | /* Annoyingly, get_attr_trap will abort on these. */ |
8247 | if (GET_CODE (PATTERN (i)) == USE | |
8248 | || GET_CODE (PATTERN (i)) == CLOBBER) | |
18adf4f6 | 8249 | break; |
8250 | ||
8251 | summarize_insn (PATTERN (i), &sum, 0); | |
8252 | ||
8253 | if ((sum.defd.i & shadow.defd.i) | |
8254 | || (sum.defd.fp & shadow.defd.fp)) | |
8255 | { | |
8256 | /* (c) would be violated */ | |
8257 | goto close_shadow; | |
8258 | } | |
8259 | ||
8260 | /* Combine shadow with summary of current insn: */ | |
8261 | shadow.used.i |= sum.used.i; | |
8262 | shadow.used.fp |= sum.used.fp; | |
8263 | shadow.used.mem |= sum.used.mem; | |
8264 | shadow.defd.i |= sum.defd.i; | |
8265 | shadow.defd.fp |= sum.defd.fp; | |
8266 | shadow.defd.mem |= sum.defd.mem; | |
8267 | ||
8268 | if ((sum.defd.i & shadow.used.i) | |
8269 | || (sum.defd.fp & shadow.used.fp) | |
8270 | || (sum.defd.mem & shadow.used.mem)) | |
8271 | { | |
8272 | /* (a) would be violated (also takes care of (b)) */ | |
8273 | if (get_attr_trap (i) == TRAP_YES | |
8274 | && ((sum.defd.i & sum.used.i) | |
8275 | || (sum.defd.fp & sum.used.fp))) | |
8276 | abort (); | |
8277 | ||
8278 | goto close_shadow; | |
8279 | } | |
8280 | break; | |
8281 | ||
8282 | case JUMP_INSN: | |
8283 | case CALL_INSN: | |
8284 | case CODE_LABEL: | |
8285 | goto close_shadow; | |
8286 | ||
8287 | default: | |
c4622276 | 8288 | abort (); |
18adf4f6 | 8289 | } |
8290 | } | |
8291 | else | |
8292 | { | |
8293 | close_shadow: | |
b9b4428b | 8294 | n = emit_insn_before (gen_trapb (), i); |
8295 | PUT_MODE (n, TImode); | |
8296 | PUT_MODE (i, TImode); | |
18adf4f6 | 8297 | trap_pending = 0; |
8298 | shadow.used.i = 0; | |
8299 | shadow.used.fp = 0; | |
8300 | shadow.used.mem = 0; | |
8301 | shadow.defd = shadow.used; | |
8302 | } | |
8303 | } | |
8304 | } | |
c4622276 | 8305 | |
609d4083 | 8306 | if ((exception_nesting > 0 || alpha_tp >= ALPHA_TP_FUNC) |
8307 | && GET_CODE (i) == INSN | |
8308 | && GET_CODE (PATTERN (i)) != USE | |
8309 | && GET_CODE (PATTERN (i)) != CLOBBER | |
8310 | && get_attr_trap (i) == TRAP_YES) | |
8311 | { | |
8312 | if (optimize && !trap_pending) | |
8313 | summarize_insn (PATTERN (i), &shadow, 0); | |
8314 | trap_pending = 1; | |
8315 | } | |
c4622276 | 8316 | } |
8317 | } | |
b9b4428b | 8318 | \f |
b9b4428b | 8319 | /* Alpha can only issue instruction groups simultaneously if they are |
5910bb95 | 8320 | suitably aligned. This is very processor-specific. */ |
b9b4428b | 8321 | |
849674a3 | 8322 | enum alphaev4_pipe { |
8323 | EV4_STOP = 0, | |
8324 | EV4_IB0 = 1, | |
8325 | EV4_IB1 = 2, | |
8326 | EV4_IBX = 4 | |
8327 | }; | |
8328 | ||
b9b4428b | 8329 | enum alphaev5_pipe { |
8330 | EV5_STOP = 0, | |
8331 | EV5_NONE = 1, | |
8332 | EV5_E01 = 2, | |
8333 | EV5_E0 = 4, | |
8334 | EV5_E1 = 8, | |
8335 | EV5_FAM = 16, | |
8336 | EV5_FA = 32, | |
8337 | EV5_FM = 64 | |
8338 | }; | |
8339 | ||
849674a3 | 8340 | static enum alphaev4_pipe |
92643d95 | 8341 | alphaev4_insn_pipe (rtx insn) |
849674a3 | 8342 | { |
8343 | if (recog_memoized (insn) < 0) | |
8344 | return EV4_STOP; | |
8345 | if (get_attr_length (insn) != 4) | |
8346 | return EV4_STOP; | |
8347 | ||
8348 | switch (get_attr_type (insn)) | |
8349 | { | |
8350 | case TYPE_ILD: | |
8351 | case TYPE_FLD: | |
8352 | return EV4_IBX; | |
8353 | ||
8354 | case TYPE_LDSYM: | |
8355 | case TYPE_IADD: | |
8356 | case TYPE_ILOG: | |
8357 | case TYPE_ICMOV: | |
8358 | case TYPE_ICMP: | |
8359 | case TYPE_IST: | |
8360 | case TYPE_FST: | |
8361 | case TYPE_SHIFT: | |
8362 | case TYPE_IMUL: | |
8363 | case TYPE_FBR: | |
8364 | return EV4_IB0; | |
8365 | ||
8366 | case TYPE_MISC: | |
8367 | case TYPE_IBR: | |
8368 | case TYPE_JSR: | |
1050b77e | 8369 | case TYPE_CALLPAL: |
849674a3 | 8370 | case TYPE_FCPYS: |
8371 | case TYPE_FCMOV: | |
8372 | case TYPE_FADD: | |
8373 | case TYPE_FDIV: | |
8374 | case TYPE_FMUL: | |
8375 | return EV4_IB1; | |
8376 | ||
8377 | default: | |
b53f315c | 8378 | abort (); |
849674a3 | 8379 | } |
8380 | } | |
8381 | ||
b9b4428b | 8382 | static enum alphaev5_pipe |
92643d95 | 8383 | alphaev5_insn_pipe (rtx insn) |
b9b4428b | 8384 | { |
8385 | if (recog_memoized (insn) < 0) | |
8386 | return EV5_STOP; | |
8387 | if (get_attr_length (insn) != 4) | |
8388 | return EV5_STOP; | |
8389 | ||
8390 | switch (get_attr_type (insn)) | |
8391 | { | |
8392 | case TYPE_ILD: | |
8393 | case TYPE_FLD: | |
8394 | case TYPE_LDSYM: | |
8395 | case TYPE_IADD: | |
8396 | case TYPE_ILOG: | |
8397 | case TYPE_ICMOV: | |
8398 | case TYPE_ICMP: | |
8399 | return EV5_E01; | |
8400 | ||
8401 | case TYPE_IST: | |
8402 | case TYPE_FST: | |
8403 | case TYPE_SHIFT: | |
8404 | case TYPE_IMUL: | |
8405 | case TYPE_MISC: | |
8406 | case TYPE_MVI: | |
8407 | return EV5_E0; | |
8408 | ||
8409 | case TYPE_IBR: | |
8410 | case TYPE_JSR: | |
1050b77e | 8411 | case TYPE_CALLPAL: |
b9b4428b | 8412 | return EV5_E1; |
8413 | ||
8414 | case TYPE_FCPYS: | |
8415 | return EV5_FAM; | |
8416 | ||
8417 | case TYPE_FBR: | |
8418 | case TYPE_FCMOV: | |
8419 | case TYPE_FADD: | |
8420 | case TYPE_FDIV: | |
8421 | return EV5_FA; | |
8422 | ||
8423 | case TYPE_FMUL: | |
8424 | return EV5_FM; | |
ddca68f8 | 8425 | |
8426 | default: | |
8427 | abort(); | |
b9b4428b | 8428 | } |
b9b4428b | 8429 | } |
8430 | ||
849674a3 | 8431 | /* IN_USE is a mask of the slots currently filled within the insn group. |
8432 | The mask bits come from alphaev4_pipe above. If EV4_IBX is set, then | |
8433 | the insn in EV4_IB0 can be swapped by the hardware into EV4_IB1. | |
8434 | ||
8435 | LEN is, of course, the length of the group in bytes. */ | |
8436 | ||
8437 | static rtx | |
92643d95 | 8438 | alphaev4_next_group (rtx insn, int *pin_use, int *plen) |
849674a3 | 8439 | { |
8440 | int len, in_use; | |
8441 | ||
8442 | len = in_use = 0; | |
8443 | ||
9204e736 | 8444 | if (! INSN_P (insn) |
849674a3 | 8445 | || GET_CODE (PATTERN (insn)) == CLOBBER |
8446 | || GET_CODE (PATTERN (insn)) == USE) | |
8447 | goto next_and_done; | |
8448 | ||
8449 | while (1) | |
8450 | { | |
8451 | enum alphaev4_pipe pipe; | |
8452 | ||
8453 | pipe = alphaev4_insn_pipe (insn); | |
8454 | switch (pipe) | |
8455 | { | |
8456 | case EV4_STOP: | |
8457 | /* Force complex instructions to start new groups. */ | |
8458 | if (in_use) | |
8459 | goto done; | |
8460 | ||
8461 | /* If this is a completely unrecognized insn, its an asm. | |
8462 | We don't know how long it is, so record length as -1 to | |
8463 | signal a needed realignment. */ | |
8464 | if (recog_memoized (insn) < 0) | |
8465 | len = -1; | |
8466 | else | |
8467 | len = get_attr_length (insn); | |
8468 | goto next_and_done; | |
8469 | ||
8470 | case EV4_IBX: | |
8471 | if (in_use & EV4_IB0) | |
8472 | { | |
8473 | if (in_use & EV4_IB1) | |
8474 | goto done; | |
8475 | in_use |= EV4_IB1; | |
8476 | } | |
8477 | else | |
8478 | in_use |= EV4_IB0 | EV4_IBX; | |
8479 | break; | |
8480 | ||
8481 | case EV4_IB0: | |
8482 | if (in_use & EV4_IB0) | |
8483 | { | |
8484 | if (!(in_use & EV4_IBX) || (in_use & EV4_IB1)) | |
8485 | goto done; | |
8486 | in_use |= EV4_IB1; | |
8487 | } | |
8488 | in_use |= EV4_IB0; | |
8489 | break; | |
8490 | ||
8491 | case EV4_IB1: | |
8492 | if (in_use & EV4_IB1) | |
8493 | goto done; | |
8494 | in_use |= EV4_IB1; | |
8495 | break; | |
8496 | ||
8497 | default: | |
8498 | abort(); | |
8499 | } | |
8500 | len += 4; | |
8501 | ||
8502 | /* Haifa doesn't do well scheduling branches. */ | |
8503 | if (GET_CODE (insn) == JUMP_INSN) | |
8504 | goto next_and_done; | |
8505 | ||
8506 | next: | |
8507 | insn = next_nonnote_insn (insn); | |
8508 | ||
9204e736 | 8509 | if (!insn || ! INSN_P (insn)) |
849674a3 | 8510 | goto done; |
8511 | ||
8512 | /* Let Haifa tell us where it thinks insn group boundaries are. */ | |
8513 | if (GET_MODE (insn) == TImode) | |
8514 | goto done; | |
8515 | ||
8516 | if (GET_CODE (insn) == CLOBBER || GET_CODE (insn) == USE) | |
8517 | goto next; | |
8518 | } | |
8519 | ||
8520 | next_and_done: | |
8521 | insn = next_nonnote_insn (insn); | |
8522 | ||
8523 | done: | |
8524 | *plen = len; | |
8525 | *pin_use = in_use; | |
8526 | return insn; | |
8527 | } | |
8528 | ||
8529 | /* IN_USE is a mask of the slots currently filled within the insn group. | |
8530 | The mask bits come from alphaev5_pipe above. If EV5_E01 is set, then | |
8531 | the insn in EV5_E0 can be swapped by the hardware into EV5_E1. | |
b9b4428b | 8532 | |
8533 | LEN is, of course, the length of the group in bytes. */ | |
8534 | ||
8535 | static rtx | |
92643d95 | 8536 | alphaev5_next_group (rtx insn, int *pin_use, int *plen) |
b9b4428b | 8537 | { |
8538 | int len, in_use; | |
8539 | ||
8540 | len = in_use = 0; | |
8541 | ||
9204e736 | 8542 | if (! INSN_P (insn) |
ddca68f8 | 8543 | || GET_CODE (PATTERN (insn)) == CLOBBER |
8544 | || GET_CODE (PATTERN (insn)) == USE) | |
8545 | goto next_and_done; | |
b9b4428b | 8546 | |
ddca68f8 | 8547 | while (1) |
b9b4428b | 8548 | { |
8549 | enum alphaev5_pipe pipe; | |
b9b4428b | 8550 | |
8551 | pipe = alphaev5_insn_pipe (insn); | |
8552 | switch (pipe) | |
8553 | { | |
8554 | case EV5_STOP: | |
8555 | /* Force complex instructions to start new groups. */ | |
8556 | if (in_use) | |
8557 | goto done; | |
8558 | ||
8559 | /* If this is a completely unrecognized insn, its an asm. | |
8560 | We don't know how long it is, so record length as -1 to | |
8561 | signal a needed realignment. */ | |
8562 | if (recog_memoized (insn) < 0) | |
8563 | len = -1; | |
8564 | else | |
8565 | len = get_attr_length (insn); | |
ddca68f8 | 8566 | goto next_and_done; |
b9b4428b | 8567 | |
8568 | /* ??? Most of the places below, we would like to abort, as | |
8569 | it would indicate an error either in Haifa, or in the | |
8570 | scheduling description. Unfortunately, Haifa never | |
8571 | schedules the last instruction of the BB, so we don't | |
8572 | have an accurate TI bit to go off. */ | |
8573 | case EV5_E01: | |
8574 | if (in_use & EV5_E0) | |
8575 | { | |
8576 | if (in_use & EV5_E1) | |
8577 | goto done; | |
8578 | in_use |= EV5_E1; | |
8579 | } | |
8580 | else | |
8581 | in_use |= EV5_E0 | EV5_E01; | |
8582 | break; | |
8583 | ||
8584 | case EV5_E0: | |
8585 | if (in_use & EV5_E0) | |
8586 | { | |
849674a3 | 8587 | if (!(in_use & EV5_E01) || (in_use & EV5_E1)) |
b9b4428b | 8588 | goto done; |
8589 | in_use |= EV5_E1; | |
8590 | } | |
8591 | in_use |= EV5_E0; | |
8592 | break; | |
8593 | ||
8594 | case EV5_E1: | |
8595 | if (in_use & EV5_E1) | |
8596 | goto done; | |
8597 | in_use |= EV5_E1; | |
8598 | break; | |
8599 | ||
8600 | case EV5_FAM: | |
8601 | if (in_use & EV5_FA) | |
8602 | { | |
8603 | if (in_use & EV5_FM) | |
8604 | goto done; | |
8605 | in_use |= EV5_FM; | |
8606 | } | |
8607 | else | |
8608 | in_use |= EV5_FA | EV5_FAM; | |
8609 | break; | |
8610 | ||
8611 | case EV5_FA: | |
8612 | if (in_use & EV5_FA) | |
8613 | goto done; | |
8614 | in_use |= EV5_FA; | |
8615 | break; | |
8616 | ||
8617 | case EV5_FM: | |
8618 | if (in_use & EV5_FM) | |
8619 | goto done; | |
8620 | in_use |= EV5_FM; | |
8621 | break; | |
8622 | ||
8623 | case EV5_NONE: | |
8624 | break; | |
8625 | ||
8626 | default: | |
8627 | abort(); | |
8628 | } | |
8629 | len += 4; | |
8630 | ||
8631 | /* Haifa doesn't do well scheduling branches. */ | |
8632 | /* ??? If this is predicted not-taken, slotting continues, except | |
8633 | that no more IBR, FBR, or JSR insns may be slotted. */ | |
8634 | if (GET_CODE (insn) == JUMP_INSN) | |
ddca68f8 | 8635 | goto next_and_done; |
b9b4428b | 8636 | |
ddca68f8 | 8637 | next: |
b9b4428b | 8638 | insn = next_nonnote_insn (insn); |
8639 | ||
9204e736 | 8640 | if (!insn || ! INSN_P (insn)) |
b9b4428b | 8641 | goto done; |
f9137da0 | 8642 | |
b9b4428b | 8643 | /* Let Haifa tell us where it thinks insn group boundaries are. */ |
8644 | if (GET_MODE (insn) == TImode) | |
8645 | goto done; | |
8646 | ||
ddca68f8 | 8647 | if (GET_CODE (insn) == CLOBBER || GET_CODE (insn) == USE) |
8648 | goto next; | |
b9b4428b | 8649 | } |
ddca68f8 | 8650 | |
8651 | next_and_done: | |
8652 | insn = next_nonnote_insn (insn); | |
b9b4428b | 8653 | |
8654 | done: | |
8655 | *plen = len; | |
8656 | *pin_use = in_use; | |
8657 | return insn; | |
b9b4428b | 8658 | } |
8659 | ||
849674a3 | 8660 | static rtx |
92643d95 | 8661 | alphaev4_next_nop (int *pin_use) |
849674a3 | 8662 | { |
8663 | int in_use = *pin_use; | |
8664 | rtx nop; | |
8665 | ||
8666 | if (!(in_use & EV4_IB0)) | |
8667 | { | |
8668 | in_use |= EV4_IB0; | |
8669 | nop = gen_nop (); | |
8670 | } | |
8671 | else if ((in_use & (EV4_IBX|EV4_IB1)) == EV4_IBX) | |
8672 | { | |
8673 | in_use |= EV4_IB1; | |
8674 | nop = gen_nop (); | |
8675 | } | |
8676 | else if (TARGET_FP && !(in_use & EV4_IB1)) | |
8677 | { | |
8678 | in_use |= EV4_IB1; | |
8679 | nop = gen_fnop (); | |
8680 | } | |
8681 | else | |
8682 | nop = gen_unop (); | |
8683 | ||
8684 | *pin_use = in_use; | |
8685 | return nop; | |
8686 | } | |
8687 | ||
8688 | static rtx | |
92643d95 | 8689 | alphaev5_next_nop (int *pin_use) |
849674a3 | 8690 | { |
8691 | int in_use = *pin_use; | |
8692 | rtx nop; | |
8693 | ||
8694 | if (!(in_use & EV5_E1)) | |
8695 | { | |
8696 | in_use |= EV5_E1; | |
8697 | nop = gen_nop (); | |
8698 | } | |
8699 | else if (TARGET_FP && !(in_use & EV5_FA)) | |
8700 | { | |
8701 | in_use |= EV5_FA; | |
8702 | nop = gen_fnop (); | |
8703 | } | |
8704 | else if (TARGET_FP && !(in_use & EV5_FM)) | |
8705 | { | |
8706 | in_use |= EV5_FM; | |
8707 | nop = gen_fnop (); | |
8708 | } | |
8709 | else | |
8710 | nop = gen_unop (); | |
8711 | ||
8712 | *pin_use = in_use; | |
8713 | return nop; | |
8714 | } | |
8715 | ||
8716 | /* The instruction group alignment main loop. */ | |
8717 | ||
b9b4428b | 8718 | static void |
92643d95 | 8719 | alpha_align_insns (unsigned int max_align, |
8720 | rtx (*next_group) (rtx, int *, int *), | |
8721 | rtx (*next_nop) (int *)) | |
b9b4428b | 8722 | { |
8723 | /* ALIGN is the known alignment for the insn group. */ | |
b53f315c | 8724 | unsigned int align; |
b9b4428b | 8725 | /* OFS is the offset of the current insn in the insn group. */ |
8726 | int ofs; | |
8727 | int prev_in_use, in_use, len; | |
8728 | rtx i, next; | |
8729 | ||
8730 | /* Let shorten branches care for assigning alignments to code labels. */ | |
2efea8c0 | 8731 | shorten_branches (get_insns ()); |
b9b4428b | 8732 | |
d815ce59 | 8733 | if (align_functions < 4) |
8734 | align = 4; | |
eeca3ba1 | 8735 | else if ((unsigned int) align_functions < max_align) |
d815ce59 | 8736 | align = align_functions; |
8737 | else | |
8738 | align = max_align; | |
e2c8a34a | 8739 | |
b9b4428b | 8740 | ofs = prev_in_use = 0; |
2efea8c0 | 8741 | i = get_insns (); |
b9b4428b | 8742 | if (GET_CODE (i) == NOTE) |
8743 | i = next_nonnote_insn (i); | |
8744 | ||
8745 | while (i) | |
8746 | { | |
b53f315c | 8747 | next = (*next_group) (i, &in_use, &len); |
b9b4428b | 8748 | |
8749 | /* When we see a label, resync alignment etc. */ | |
8750 | if (GET_CODE (i) == CODE_LABEL) | |
8751 | { | |
b53f315c | 8752 | unsigned int new_align = 1 << label_to_alignment (i); |
8753 | ||
b9b4428b | 8754 | if (new_align >= align) |
8755 | { | |
849674a3 | 8756 | align = new_align < max_align ? new_align : max_align; |
b9b4428b | 8757 | ofs = 0; |
8758 | } | |
b53f315c | 8759 | |
b9b4428b | 8760 | else if (ofs & (new_align-1)) |
8761 | ofs = (ofs | (new_align-1)) + 1; | |
8762 | if (len != 0) | |
8763 | abort(); | |
8764 | } | |
8765 | ||
8766 | /* Handle complex instructions special. */ | |
8767 | else if (in_use == 0) | |
8768 | { | |
8769 | /* Asms will have length < 0. This is a signal that we have | |
8770 | lost alignment knowledge. Assume, however, that the asm | |
8771 | will not mis-align instructions. */ | |
8772 | if (len < 0) | |
8773 | { | |
8774 | ofs = 0; | |
8775 | align = 4; | |
8776 | len = 0; | |
8777 | } | |
8778 | } | |
8779 | ||
8780 | /* If the known alignment is smaller than the recognized insn group, | |
8781 | realign the output. */ | |
1f0ce6a6 | 8782 | else if ((int) align < len) |
b9b4428b | 8783 | { |
b53f315c | 8784 | unsigned int new_log_align = len > 8 ? 4 : 3; |
943a1b57 | 8785 | rtx prev, where; |
b9b4428b | 8786 | |
943a1b57 | 8787 | where = prev = prev_nonnote_insn (i); |
b9b4428b | 8788 | if (!where || GET_CODE (where) != CODE_LABEL) |
8789 | where = i; | |
8790 | ||
943a1b57 | 8791 | /* Can't realign between a call and its gp reload. */ |
8792 | if (! (TARGET_EXPLICIT_RELOCS | |
8793 | && prev && GET_CODE (prev) == CALL_INSN)) | |
8794 | { | |
8795 | emit_insn_before (gen_realign (GEN_INT (new_log_align)), where); | |
8796 | align = 1 << new_log_align; | |
8797 | ofs = 0; | |
8798 | } | |
b9b4428b | 8799 | } |
8800 | ||
8801 | /* If the group won't fit in the same INT16 as the previous, | |
8802 | we need to add padding to keep the group together. Rather | |
8803 | than simply leaving the insn filling to the assembler, we | |
8804 | can make use of the knowledge of what sorts of instructions | |
8805 | were issued in the previous group to make sure that all of | |
8806 | the added nops are really free. */ | |
1f0ce6a6 | 8807 | else if (ofs + len > (int) align) |
b9b4428b | 8808 | { |
8809 | int nop_count = (align - ofs) / 4; | |
8810 | rtx where; | |
8811 | ||
efee20da | 8812 | /* Insert nops before labels, branches, and calls to truly merge |
943a1b57 | 8813 | the execution of the nops with the previous instruction group. */ |
b9b4428b | 8814 | where = prev_nonnote_insn (i); |
849674a3 | 8815 | if (where) |
b9b4428b | 8816 | { |
849674a3 | 8817 | if (GET_CODE (where) == CODE_LABEL) |
b9b4428b | 8818 | { |
849674a3 | 8819 | rtx where2 = prev_nonnote_insn (where); |
8820 | if (where2 && GET_CODE (where2) == JUMP_INSN) | |
8821 | where = where2; | |
b9b4428b | 8822 | } |
943a1b57 | 8823 | else if (GET_CODE (where) == INSN) |
849674a3 | 8824 | where = i; |
b9b4428b | 8825 | } |
849674a3 | 8826 | else |
8827 | where = i; | |
8828 | ||
8829 | do | |
8830 | emit_insn_before ((*next_nop)(&prev_in_use), where); | |
b9b4428b | 8831 | while (--nop_count); |
8832 | ofs = 0; | |
8833 | } | |
8834 | ||
8835 | ofs = (ofs + len) & (align - 1); | |
8836 | prev_in_use = in_use; | |
8837 | i = next; | |
8838 | } | |
8839 | } | |
b9b4428b | 8840 | \f |
35a3065a | 8841 | /* Machine dependent reorg pass. */ |
18adf4f6 | 8842 | |
2efea8c0 | 8843 | static void |
92643d95 | 8844 | alpha_reorg (void) |
18adf4f6 | 8845 | { |
b9b4428b | 8846 | if (alpha_tp != ALPHA_TP_PROG || flag_exceptions) |
2efea8c0 | 8847 | alpha_handle_trap_shadows (); |
b9b4428b | 8848 | |
b9b4428b | 8849 | /* Due to the number of extra trapb insns, don't bother fixing up |
8850 | alignment when trap precision is instruction. Moreover, we can | |
b53f315c | 8851 | only do our job when sched2 is run. */ |
b9b4428b | 8852 | if (optimize && !optimize_size |
8853 | && alpha_tp != ALPHA_TP_INSN | |
8854 | && flag_schedule_insns_after_reload) | |
8855 | { | |
849674a3 | 8856 | if (alpha_cpu == PROCESSOR_EV4) |
2efea8c0 | 8857 | alpha_align_insns (8, alphaev4_next_group, alphaev4_next_nop); |
849674a3 | 8858 | else if (alpha_cpu == PROCESSOR_EV5) |
2efea8c0 | 8859 | alpha_align_insns (16, alphaev5_next_group, alphaev5_next_nop); |
b9b4428b | 8860 | } |
18adf4f6 | 8861 | } |
18adf4f6 | 8862 | \f |
92c473b8 | 8863 | #if !TARGET_ABI_UNICOSMK |
8864 | ||
8865 | #ifdef HAVE_STAMP_H | |
8866 | #include <stamp.h> | |
8867 | #endif | |
8868 | ||
8869 | static void | |
8870 | alpha_file_start (void) | |
8871 | { | |
0fdc84d7 | 8872 | #ifdef OBJECT_FORMAT_ELF |
8873 | /* If emitting dwarf2 debug information, we cannot generate a .file | |
8874 | directive to start the file, as it will conflict with dwarf2out | |
8875 | file numbers. So it's only useful when emitting mdebug output. */ | |
8876 | targetm.file_start_file_directive = (write_symbols == DBX_DEBUG); | |
8877 | #endif | |
8878 | ||
92c473b8 | 8879 | default_file_start (); |
8880 | #ifdef MS_STAMP | |
bc964653 | 8881 | fprintf (asm_out_file, "\t.verstamp %d %d\n", MS_STAMP, LS_STAMP); |
92c473b8 | 8882 | #endif |
8883 | ||
8884 | fputs ("\t.set noreorder\n", asm_out_file); | |
8885 | fputs ("\t.set volatile\n", asm_out_file); | |
8886 | if (!TARGET_ABI_OPEN_VMS) | |
8887 | fputs ("\t.set noat\n", asm_out_file); | |
8888 | if (TARGET_EXPLICIT_RELOCS) | |
8889 | fputs ("\t.set nomacro\n", asm_out_file); | |
8890 | if (TARGET_SUPPORT_ARCH | TARGET_BWX | TARGET_MAX | TARGET_FIX | TARGET_CIX) | |
8891 | fprintf (asm_out_file, | |
8892 | "\t.arch %s\n", | |
8893 | TARGET_CPU_EV6 ? "ev6" | |
8894 | : (TARGET_CPU_EV5 | |
8895 | ? (TARGET_MAX ? "pca56" : TARGET_BWX ? "ev56" : "ev5") | |
8896 | : "ev4")); | |
8897 | } | |
8898 | #endif | |
8899 | ||
bbfbe351 | 8900 | #ifdef OBJECT_FORMAT_ELF |
8901 | ||
8902 | /* Switch to the section to which we should output X. The only thing | |
8903 | special we do here is to honor small data. */ | |
8904 | ||
8905 | static void | |
92643d95 | 8906 | alpha_elf_select_rtx_section (enum machine_mode mode, rtx x, |
8907 | unsigned HOST_WIDE_INT align) | |
bbfbe351 | 8908 | { |
8909 | if (TARGET_SMALL_DATA && GET_MODE_SIZE (mode) <= g_switch_value) | |
5910bb95 | 8910 | /* ??? Consider using mergeable sdata sections. */ |
bbfbe351 | 8911 | sdata_section (); |
8912 | else | |
8913 | default_elf_select_rtx_section (mode, x, align); | |
8914 | } | |
8915 | ||
8916 | #endif /* OBJECT_FORMAT_ELF */ | |
8917 | \f | |
9de382d9 | 8918 | /* Structure to collect function names for final output in link section. */ |
8919 | /* Note that items marked with GTY can't be ifdef'ed out. */ | |
573aba85 | 8920 | |
8921 | enum links_kind {KIND_UNUSED, KIND_LOCAL, KIND_EXTERN}; | |
9de382d9 | 8922 | enum reloc_kind {KIND_LINKAGE, KIND_CODEADDR}; |
573aba85 | 8923 | |
8924 | struct alpha_links GTY(()) | |
8925 | { | |
9de382d9 | 8926 | int num; |
573aba85 | 8927 | rtx linkage; |
9de382d9 | 8928 | enum links_kind lkind; |
8929 | enum reloc_kind rkind; | |
8930 | }; | |
8931 | ||
8932 | struct alpha_funcs GTY(()) | |
8933 | { | |
8934 | int num; | |
8935 | splay_tree GTY ((param1_is (char *), param2_is (struct alpha_links *))) | |
8936 | links; | |
573aba85 | 8937 | }; |
8938 | ||
8939 | static GTY ((param1_is (char *), param2_is (struct alpha_links *))) | |
9de382d9 | 8940 | splay_tree alpha_links_tree; |
8941 | static GTY ((param1_is (tree), param2_is (struct alpha_funcs *))) | |
8942 | splay_tree alpha_funcs_tree; | |
8943 | ||
8944 | static GTY(()) int alpha_funcs_num; | |
573aba85 | 8945 | |
1467e953 | 8946 | #if TARGET_ABI_OPEN_VMS |
8df4a58b | 8947 | |
0dbd1c74 | 8948 | /* Return the VMS argument type corresponding to MODE. */ |
8df4a58b | 8949 | |
0dbd1c74 | 8950 | enum avms_arg_type |
92643d95 | 8951 | alpha_arg_type (enum machine_mode mode) |
0dbd1c74 | 8952 | { |
8953 | switch (mode) | |
8df4a58b | 8954 | { |
0dbd1c74 | 8955 | case SFmode: |
8956 | return TARGET_FLOAT_VAX ? FF : FS; | |
8957 | case DFmode: | |
8958 | return TARGET_FLOAT_VAX ? FD : FT; | |
8959 | default: | |
8960 | return I64; | |
8df4a58b | 8961 | } |
0dbd1c74 | 8962 | } |
8df4a58b | 8963 | |
0dbd1c74 | 8964 | /* Return an rtx for an integer representing the VMS Argument Information |
8965 | register value. */ | |
8df4a58b | 8966 | |
1dd6c958 | 8967 | rtx |
92643d95 | 8968 | alpha_arg_info_reg_val (CUMULATIVE_ARGS cum) |
0dbd1c74 | 8969 | { |
8970 | unsigned HOST_WIDE_INT regval = cum.num_args; | |
8971 | int i; | |
8df4a58b | 8972 | |
0dbd1c74 | 8973 | for (i = 0; i < 6; i++) |
8974 | regval |= ((int) cum.atypes[i]) << (i * 3 + 8); | |
8df4a58b | 8975 | |
0dbd1c74 | 8976 | return GEN_INT (regval); |
8977 | } | |
8978 | \f | |
8df4a58b | 8979 | /* Make (or fake) .linkage entry for function call. |
8980 | ||
57e47080 | 8981 | IS_LOCAL is 0 if name is used in call, 1 if name is used in definition. |
8df4a58b | 8982 | |
57e47080 | 8983 | Return an SYMBOL_REF rtx for the linkage. */ |
8984 | ||
8985 | rtx | |
92643d95 | 8986 | alpha_need_linkage (const char *name, int is_local) |
8df4a58b | 8987 | { |
57e47080 | 8988 | splay_tree_node node; |
8989 | struct alpha_links *al; | |
8df4a58b | 8990 | |
8991 | if (name[0] == '*') | |
8992 | name++; | |
8993 | ||
cf73d31f | 8994 | if (is_local) |
8995 | { | |
9de382d9 | 8996 | struct alpha_funcs *cfaf; |
8997 | ||
8998 | if (!alpha_funcs_tree) | |
8999 | alpha_funcs_tree = splay_tree_new_ggc ((splay_tree_compare_fn) | |
9000 | splay_tree_compare_pointers); | |
cf73d31f | 9001 | |
9de382d9 | 9002 | cfaf = (struct alpha_funcs *) ggc_alloc (sizeof (struct alpha_funcs)); |
cf73d31f | 9003 | |
9004 | cfaf->links = 0; | |
9005 | cfaf->num = ++alpha_funcs_num; | |
9006 | ||
9007 | splay_tree_insert (alpha_funcs_tree, | |
9008 | (splay_tree_key) current_function_decl, | |
9009 | (splay_tree_value) cfaf); | |
cf73d31f | 9010 | } |
9011 | ||
9012 | if (alpha_links_tree) | |
57e47080 | 9013 | { |
9014 | /* Is this name already defined? */ | |
8df4a58b | 9015 | |
cf73d31f | 9016 | node = splay_tree_lookup (alpha_links_tree, (splay_tree_key) name); |
57e47080 | 9017 | if (node) |
9018 | { | |
9019 | al = (struct alpha_links *) node->value; | |
9020 | if (is_local) | |
9021 | { | |
9022 | /* Defined here but external assumed. */ | |
cf73d31f | 9023 | if (al->lkind == KIND_EXTERN) |
9024 | al->lkind = KIND_LOCAL; | |
57e47080 | 9025 | } |
9026 | else | |
9027 | { | |
9028 | /* Used here but unused assumed. */ | |
cf73d31f | 9029 | if (al->lkind == KIND_UNUSED) |
9030 | al->lkind = KIND_LOCAL; | |
57e47080 | 9031 | } |
9032 | return al->linkage; | |
9033 | } | |
9034 | } | |
9035 | else | |
8482c296 | 9036 | alpha_links_tree = splay_tree_new_ggc ((splay_tree_compare_fn) strcmp); |
8df4a58b | 9037 | |
573aba85 | 9038 | al = (struct alpha_links *) ggc_alloc (sizeof (struct alpha_links)); |
9039 | name = ggc_strdup (name); | |
8df4a58b | 9040 | |
9041 | /* Assume external if no definition. */ | |
cf73d31f | 9042 | al->lkind = (is_local ? KIND_UNUSED : KIND_EXTERN); |
8df4a58b | 9043 | |
57e47080 | 9044 | /* Ensure we have an IDENTIFIER so assemble_name can mark it used. */ |
d2899e26 | 9045 | get_identifier (name); |
9046 | ||
57e47080 | 9047 | /* Construct a SYMBOL_REF for us to call. */ |
9048 | { | |
9049 | size_t name_len = strlen (name); | |
44acf429 | 9050 | char *linksym = alloca (name_len + 6); |
57e47080 | 9051 | linksym[0] = '$'; |
9052 | memcpy (linksym + 1, name, name_len); | |
9053 | memcpy (linksym + 1 + name_len, "..lk", 5); | |
44acf429 | 9054 | al->linkage = gen_rtx_SYMBOL_REF (Pmode, |
9055 | ggc_alloc_string (linksym, name_len + 5)); | |
57e47080 | 9056 | } |
9057 | ||
cf73d31f | 9058 | splay_tree_insert (alpha_links_tree, (splay_tree_key) name, |
57e47080 | 9059 | (splay_tree_value) al); |
8df4a58b | 9060 | |
57e47080 | 9061 | return al->linkage; |
8df4a58b | 9062 | } |
9063 | ||
cf73d31f | 9064 | rtx |
92643d95 | 9065 | alpha_use_linkage (rtx linkage, tree cfundecl, int lflag, int rflag) |
cf73d31f | 9066 | { |
9067 | splay_tree_node cfunnode; | |
9068 | struct alpha_funcs *cfaf; | |
9069 | struct alpha_links *al; | |
9070 | const char *name = XSTR (linkage, 0); | |
9071 | ||
9072 | cfaf = (struct alpha_funcs *) 0; | |
9073 | al = (struct alpha_links *) 0; | |
9074 | ||
9075 | cfunnode = splay_tree_lookup (alpha_funcs_tree, (splay_tree_key) cfundecl); | |
9076 | cfaf = (struct alpha_funcs *) cfunnode->value; | |
9077 | ||
9078 | if (cfaf->links) | |
9079 | { | |
9080 | splay_tree_node lnode; | |
9081 | ||
9082 | /* Is this name already defined? */ | |
9083 | ||
9084 | lnode = splay_tree_lookup (cfaf->links, (splay_tree_key) name); | |
9085 | if (lnode) | |
9086 | al = (struct alpha_links *) lnode->value; | |
9087 | } | |
9088 | else | |
9de382d9 | 9089 | cfaf->links = splay_tree_new_ggc ((splay_tree_compare_fn) strcmp); |
cf73d31f | 9090 | |
9091 | if (!al) | |
9092 | { | |
9093 | size_t name_len; | |
9094 | size_t buflen; | |
9095 | char buf [512]; | |
9096 | char *linksym; | |
9097 | splay_tree_node node = 0; | |
9098 | struct alpha_links *anl; | |
9099 | ||
9100 | if (name[0] == '*') | |
9101 | name++; | |
9102 | ||
9103 | name_len = strlen (name); | |
9104 | ||
9de382d9 | 9105 | al = (struct alpha_links *) ggc_alloc (sizeof (struct alpha_links)); |
cf73d31f | 9106 | al->num = cfaf->num; |
9107 | ||
9108 | node = splay_tree_lookup (alpha_links_tree, (splay_tree_key) name); | |
9109 | if (node) | |
9110 | { | |
9111 | anl = (struct alpha_links *) node->value; | |
9112 | al->lkind = anl->lkind; | |
9113 | } | |
9114 | ||
9115 | sprintf (buf, "$%d..%s..lk", cfaf->num, name); | |
9116 | buflen = strlen (buf); | |
9117 | linksym = alloca (buflen + 1); | |
9118 | memcpy (linksym, buf, buflen + 1); | |
9119 | ||
9120 | al->linkage = gen_rtx_SYMBOL_REF | |
9121 | (Pmode, ggc_alloc_string (linksym, buflen + 1)); | |
9122 | ||
9123 | splay_tree_insert (cfaf->links, (splay_tree_key) name, | |
9124 | (splay_tree_value) al); | |
9125 | } | |
9126 | ||
9127 | if (rflag) | |
9128 | al->rkind = KIND_CODEADDR; | |
9129 | else | |
9130 | al->rkind = KIND_LINKAGE; | |
9131 | ||
9132 | if (lflag) | |
9133 | return gen_rtx_MEM (Pmode, plus_constant (al->linkage, 8)); | |
9134 | else | |
9135 | return al->linkage; | |
9136 | } | |
9137 | ||
57e47080 | 9138 | static int |
92643d95 | 9139 | alpha_write_one_linkage (splay_tree_node node, void *data) |
57e47080 | 9140 | { |
0d95286f | 9141 | const char *const name = (const char *) node->key; |
cf73d31f | 9142 | struct alpha_links *link = (struct alpha_links *) node->value; |
57e47080 | 9143 | FILE *stream = (FILE *) data; |
9144 | ||
cf73d31f | 9145 | fprintf (stream, "$%d..%s..lk:\n", link->num, name); |
9146 | if (link->rkind == KIND_CODEADDR) | |
57e47080 | 9147 | { |
cf73d31f | 9148 | if (link->lkind == KIND_LOCAL) |
9149 | { | |
9150 | /* Local and used */ | |
9151 | fprintf (stream, "\t.quad %s..en\n", name); | |
9152 | } | |
9153 | else | |
9154 | { | |
9155 | /* External and used, request code address. */ | |
9156 | fprintf (stream, "\t.code_address %s\n", name); | |
9157 | } | |
57e47080 | 9158 | } |
9159 | else | |
9160 | { | |
cf73d31f | 9161 | if (link->lkind == KIND_LOCAL) |
9162 | { | |
9163 | /* Local and used, build linkage pair. */ | |
9164 | fprintf (stream, "\t.quad %s..en\n", name); | |
9165 | fprintf (stream, "\t.quad %s\n", name); | |
9166 | } | |
9167 | else | |
9168 | { | |
9169 | /* External and used, request linkage pair. */ | |
9170 | fprintf (stream, "\t.linkage %s\n", name); | |
9171 | } | |
57e47080 | 9172 | } |
9173 | ||
9174 | return 0; | |
9175 | } | |
8df4a58b | 9176 | |
cf73d31f | 9177 | static void |
92643d95 | 9178 | alpha_write_linkage (FILE *stream, const char *funname, tree fundecl) |
8df4a58b | 9179 | { |
cf73d31f | 9180 | splay_tree_node node; |
9181 | struct alpha_funcs *func; | |
9182 | ||
9183 | link_section (); | |
9184 | fprintf (stream, "\t.align 3\n"); | |
9185 | node = splay_tree_lookup (alpha_funcs_tree, (splay_tree_key) fundecl); | |
9186 | func = (struct alpha_funcs *) node->value; | |
9187 | ||
9188 | fputs ("\t.name ", stream); | |
9189 | assemble_name (stream, funname); | |
9190 | fputs ("..na\n", stream); | |
9191 | ASM_OUTPUT_LABEL (stream, funname); | |
9192 | fprintf (stream, "\t.pdesc "); | |
9193 | assemble_name (stream, funname); | |
9194 | fprintf (stream, "..en,%s\n", | |
9195 | alpha_procedure_type == PT_STACK ? "stack" | |
9196 | : alpha_procedure_type == PT_REGISTER ? "reg" : "null"); | |
9197 | ||
9198 | if (func->links) | |
c64a8830 | 9199 | { |
cf73d31f | 9200 | splay_tree_foreach (func->links, alpha_write_one_linkage, stream); |
9201 | /* splay_tree_delete (func->links); */ | |
c64a8830 | 9202 | } |
8df4a58b | 9203 | } |
9204 | ||
2cb4ac60 | 9205 | /* Given a decl, a section name, and whether the decl initializer |
9206 | has relocs, choose attributes for the section. */ | |
9207 | ||
9208 | #define SECTION_VMS_OVERLAY SECTION_FORGET | |
c64a8830 | 9209 | #define SECTION_VMS_GLOBAL SECTION_MACH_DEP |
9210 | #define SECTION_VMS_INITIALIZE (SECTION_VMS_GLOBAL << 1) | |
2cb4ac60 | 9211 | |
9212 | static unsigned int | |
92643d95 | 9213 | vms_section_type_flags (tree decl, const char *name, int reloc) |
2cb4ac60 | 9214 | { |
9215 | unsigned int flags = default_section_type_flags (decl, name, reloc); | |
9216 | ||
e3c541f0 | 9217 | if (decl && DECL_ATTRIBUTES (decl) |
9218 | && lookup_attribute ("overlaid", DECL_ATTRIBUTES (decl))) | |
2cb4ac60 | 9219 | flags |= SECTION_VMS_OVERLAY; |
c64a8830 | 9220 | if (decl && DECL_ATTRIBUTES (decl) |
9221 | && lookup_attribute ("global", DECL_ATTRIBUTES (decl))) | |
9222 | flags |= SECTION_VMS_GLOBAL; | |
9223 | if (decl && DECL_ATTRIBUTES (decl) | |
9224 | && lookup_attribute ("initialize", DECL_ATTRIBUTES (decl))) | |
9225 | flags |= SECTION_VMS_INITIALIZE; | |
2cb4ac60 | 9226 | |
9227 | return flags; | |
9228 | } | |
9229 | ||
9230 | /* Switch to an arbitrary section NAME with attributes as specified | |
9231 | by FLAGS. ALIGN specifies any known alignment requirements for | |
9232 | the section; 0 if the default should be used. */ | |
9233 | ||
9234 | static void | |
92643d95 | 9235 | vms_asm_named_section (const char *name, unsigned int flags) |
2cb4ac60 | 9236 | { |
c64a8830 | 9237 | fputc ('\n', asm_out_file); |
9238 | fprintf (asm_out_file, ".section\t%s", name); | |
2cb4ac60 | 9239 | |
9240 | if (flags & SECTION_VMS_OVERLAY) | |
c64a8830 | 9241 | fprintf (asm_out_file, ",OVR"); |
9242 | if (flags & SECTION_VMS_GLOBAL) | |
9243 | fprintf (asm_out_file, ",GBL"); | |
9244 | if (flags & SECTION_VMS_INITIALIZE) | |
9245 | fprintf (asm_out_file, ",NOMOD"); | |
9246 | if (flags & SECTION_DEBUG) | |
9247 | fprintf (asm_out_file, ",NOWRT"); | |
9248 | ||
9249 | fputc ('\n', asm_out_file); | |
2cb4ac60 | 9250 | } |
9251 | ||
01d15dc5 | 9252 | /* Record an element in the table of global constructors. SYMBOL is |
9253 | a SYMBOL_REF of the function to be called; PRIORITY is a number | |
9254 | between 0 and MAX_INIT_PRIORITY. | |
9255 | ||
9256 | Differs from default_ctors_section_asm_out_constructor in that the | |
9257 | width of the .ctors entry is always 64 bits, rather than the 32 bits | |
9258 | used by a normal pointer. */ | |
9259 | ||
9260 | static void | |
92643d95 | 9261 | vms_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED) |
01d15dc5 | 9262 | { |
9263 | ctors_section (); | |
09d688ff | 9264 | assemble_align (BITS_PER_WORD); |
9265 | assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1); | |
01d15dc5 | 9266 | } |
9267 | ||
9268 | static void | |
92643d95 | 9269 | vms_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED) |
01d15dc5 | 9270 | { |
9271 | dtors_section (); | |
09d688ff | 9272 | assemble_align (BITS_PER_WORD); |
9273 | assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1); | |
01d15dc5 | 9274 | } |
8df4a58b | 9275 | #else |
9276 | ||
57e47080 | 9277 | rtx |
92643d95 | 9278 | alpha_need_linkage (const char *name ATTRIBUTE_UNUSED, |
9279 | int is_local ATTRIBUTE_UNUSED) | |
8df4a58b | 9280 | { |
57e47080 | 9281 | return NULL_RTX; |
8df4a58b | 9282 | } |
9283 | ||
cf73d31f | 9284 | rtx |
92643d95 | 9285 | alpha_use_linkage (rtx linkage ATTRIBUTE_UNUSED, |
9286 | tree cfundecl ATTRIBUTE_UNUSED, | |
9287 | int lflag ATTRIBUTE_UNUSED, | |
9288 | int rflag ATTRIBUTE_UNUSED) | |
cf73d31f | 9289 | { |
9290 | return NULL_RTX; | |
9291 | } | |
9292 | ||
1467e953 | 9293 | #endif /* TARGET_ABI_OPEN_VMS */ |
9caef960 | 9294 | \f |
9295 | #if TARGET_ABI_UNICOSMK | |
9296 | ||
0336f0f0 | 9297 | /* This evaluates to true if we do not know how to pass TYPE solely in |
9298 | registers. This is the case for all arguments that do not fit in two | |
9299 | registers. */ | |
9300 | ||
9301 | static bool | |
9302 | unicosmk_must_pass_in_stack (enum machine_mode mode, tree type) | |
9303 | { | |
9304 | if (type == NULL) | |
9305 | return false; | |
9306 | ||
9307 | if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) | |
9308 | return true; | |
9309 | if (TREE_ADDRESSABLE (type)) | |
9310 | return true; | |
9311 | ||
9312 | return ALPHA_ARG_SIZE (mode, type, 0) > 2; | |
9313 | } | |
9314 | ||
9caef960 | 9315 | /* Define the offset between two registers, one to be eliminated, and the |
9316 | other its replacement, at the start of a routine. */ | |
9317 | ||
9318 | int | |
92643d95 | 9319 | unicosmk_initial_elimination_offset (int from, int to) |
9caef960 | 9320 | { |
9321 | int fixed_size; | |
9322 | ||
9323 | fixed_size = alpha_sa_size(); | |
9324 | if (fixed_size != 0) | |
9325 | fixed_size += 48; | |
9326 | ||
9327 | if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) | |
9328 | return -fixed_size; | |
9329 | else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) | |
9330 | return 0; | |
9331 | else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) | |
9332 | return (ALPHA_ROUND (current_function_outgoing_args_size) | |
9333 | + ALPHA_ROUND (get_frame_size())); | |
9334 | else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) | |
9335 | return (ALPHA_ROUND (fixed_size) | |
9336 | + ALPHA_ROUND (get_frame_size() | |
9337 | + current_function_outgoing_args_size)); | |
9338 | else | |
9339 | abort (); | |
9340 | } | |
9341 | ||
9342 | /* Output the module name for .ident and .end directives. We have to strip | |
9343 | directories and add make sure that the module name starts with a letter | |
9344 | or '$'. */ | |
9345 | ||
9346 | static void | |
92643d95 | 9347 | unicosmk_output_module_name (FILE *file) |
9caef960 | 9348 | { |
8789d51c | 9349 | const char *name = lbasename (main_input_filename); |
9350 | unsigned len = strlen (name); | |
9351 | char *clean_name = alloca (len + 2); | |
9352 | char *ptr = clean_name; | |
9353 | ||
9caef960 | 9354 | /* CAM only accepts module names that start with a letter or '$'. We |
9355 | prefix the module name with a '$' if necessary. */ | |
9356 | ||
9357 | if (!ISALPHA (*name)) | |
8789d51c | 9358 | *ptr++ = '$'; |
9359 | memcpy (ptr, name, len + 1); | |
9360 | clean_symbol_name (clean_name); | |
9361 | fputs (clean_name, file); | |
9caef960 | 9362 | } |
9363 | ||
92643d95 | 9364 | /* Output the definition of a common variable. */ |
9caef960 | 9365 | |
92643d95 | 9366 | void |
9367 | unicosmk_output_common (FILE *file, const char *name, int size, int align) | |
9caef960 | 9368 | { |
92643d95 | 9369 | tree name_tree; |
9370 | printf ("T3E__: common %s\n", name); | |
9caef960 | 9371 | |
9372 | common_section (); | |
9373 | fputs("\t.endp\n\n\t.psect ", file); | |
9374 | assemble_name(file, name); | |
9375 | fprintf(file, ",%d,common\n", floor_log2 (align / BITS_PER_UNIT)); | |
9376 | fprintf(file, "\t.byte\t0:%d\n", size); | |
9377 | ||
9378 | /* Mark the symbol as defined in this module. */ | |
9379 | name_tree = get_identifier (name); | |
9380 | TREE_ASM_WRITTEN (name_tree) = 1; | |
9381 | } | |
9382 | ||
9383 | #define SECTION_PUBLIC SECTION_MACH_DEP | |
9384 | #define SECTION_MAIN (SECTION_PUBLIC << 1) | |
9385 | static int current_section_align; | |
9386 | ||
9387 | static unsigned int | |
92643d95 | 9388 | unicosmk_section_type_flags (tree decl, const char *name, |
9389 | int reloc ATTRIBUTE_UNUSED) | |
9caef960 | 9390 | { |
9391 | unsigned int flags = default_section_type_flags (decl, name, reloc); | |
9392 | ||
9393 | if (!decl) | |
9394 | return flags; | |
9395 | ||
9396 | if (TREE_CODE (decl) == FUNCTION_DECL) | |
9397 | { | |
9398 | current_section_align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); | |
9399 | if (align_functions_log > current_section_align) | |
9400 | current_section_align = align_functions_log; | |
9401 | ||
9402 | if (! strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), "main")) | |
9403 | flags |= SECTION_MAIN; | |
9404 | } | |
9405 | else | |
9406 | current_section_align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT); | |
9407 | ||
9408 | if (TREE_PUBLIC (decl)) | |
9409 | flags |= SECTION_PUBLIC; | |
9410 | ||
9411 | return flags; | |
9412 | } | |
9413 | ||
9414 | /* Generate a section name for decl and associate it with the | |
9415 | declaration. */ | |
9416 | ||
52470889 | 9417 | static void |
92643d95 | 9418 | unicosmk_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED) |
9caef960 | 9419 | { |
9420 | const char *name; | |
9421 | int len; | |
9422 | ||
9423 | if (!decl) | |
9424 | abort (); | |
9425 | ||
9426 | name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); | |
09a1f342 | 9427 | name = default_strip_name_encoding (name); |
9caef960 | 9428 | len = strlen (name); |
9429 | ||
9430 | if (TREE_CODE (decl) == FUNCTION_DECL) | |
9431 | { | |
9432 | char *string; | |
9433 | ||
9434 | /* It is essential that we prefix the section name here because | |
9435 | otherwise the section names generated for constructors and | |
9436 | destructors confuse collect2. */ | |
9437 | ||
9438 | string = alloca (len + 6); | |
9439 | sprintf (string, "code@%s", name); | |
9440 | DECL_SECTION_NAME (decl) = build_string (len + 5, string); | |
9441 | } | |
9442 | else if (TREE_PUBLIC (decl)) | |
9443 | DECL_SECTION_NAME (decl) = build_string (len, name); | |
9444 | else | |
9445 | { | |
9446 | char *string; | |
9447 | ||
9448 | string = alloca (len + 6); | |
9449 | sprintf (string, "data@%s", name); | |
9450 | DECL_SECTION_NAME (decl) = build_string (len + 5, string); | |
9451 | } | |
9452 | } | |
9453 | ||
9454 | /* Switch to an arbitrary section NAME with attributes as specified | |
9455 | by FLAGS. ALIGN specifies any known alignment requirements for | |
9456 | the section; 0 if the default should be used. */ | |
9457 | ||
9458 | static void | |
92643d95 | 9459 | unicosmk_asm_named_section (const char *name, unsigned int flags) |
9caef960 | 9460 | { |
9461 | const char *kind; | |
9462 | ||
9463 | /* Close the previous section. */ | |
9464 | ||
9465 | fputs ("\t.endp\n\n", asm_out_file); | |
9466 | ||
9467 | /* Find out what kind of section we are opening. */ | |
9468 | ||
9469 | if (flags & SECTION_MAIN) | |
9470 | fputs ("\t.start\tmain\n", asm_out_file); | |
9471 | ||
9472 | if (flags & SECTION_CODE) | |
9473 | kind = "code"; | |
9474 | else if (flags & SECTION_PUBLIC) | |
9475 | kind = "common"; | |
9476 | else | |
9477 | kind = "data"; | |
9478 | ||
9479 | if (current_section_align != 0) | |
9480 | fprintf (asm_out_file, "\t.psect\t%s,%d,%s\n", name, | |
9481 | current_section_align, kind); | |
9482 | else | |
9483 | fprintf (asm_out_file, "\t.psect\t%s,%s\n", name, kind); | |
9484 | } | |
9485 | ||
9486 | static void | |
92643d95 | 9487 | unicosmk_insert_attributes (tree decl, tree *attr_ptr ATTRIBUTE_UNUSED) |
9caef960 | 9488 | { |
9489 | if (DECL_P (decl) | |
9490 | && (TREE_PUBLIC (decl) || TREE_CODE (decl) == FUNCTION_DECL)) | |
52470889 | 9491 | unicosmk_unique_section (decl, 0); |
9caef960 | 9492 | } |
9493 | ||
9494 | /* Output an alignment directive. We have to use the macro 'gcc@code@align' | |
9495 | in code sections because .align fill unused space with zeroes. */ | |
9496 | ||
9497 | void | |
92643d95 | 9498 | unicosmk_output_align (FILE *file, int align) |
9caef960 | 9499 | { |
9500 | if (inside_function) | |
9501 | fprintf (file, "\tgcc@code@align\t%d\n", align); | |
9502 | else | |
9503 | fprintf (file, "\t.align\t%d\n", align); | |
9504 | } | |
9505 | ||
9506 | /* Add a case vector to the current function's list of deferred case | |
9507 | vectors. Case vectors have to be put into a separate section because CAM | |
9508 | does not allow data definitions in code sections. */ | |
9509 | ||
9510 | void | |
92643d95 | 9511 | unicosmk_defer_case_vector (rtx lab, rtx vec) |
9caef960 | 9512 | { |
9513 | struct machine_function *machine = cfun->machine; | |
9514 | ||
9515 | vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec); | |
9516 | machine->addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, | |
9517 | machine->addr_list); | |
9518 | } | |
9519 | ||
9520 | /* Output a case vector. */ | |
9521 | ||
9522 | static void | |
92643d95 | 9523 | unicosmk_output_addr_vec (FILE *file, rtx vec) |
9caef960 | 9524 | { |
9525 | rtx lab = XEXP (vec, 0); | |
9526 | rtx body = XEXP (vec, 1); | |
9527 | int vlen = XVECLEN (body, 0); | |
9528 | int idx; | |
9529 | ||
805e22b2 | 9530 | (*targetm.asm_out.internal_label) (file, "L", CODE_LABEL_NUMBER (lab)); |
9caef960 | 9531 | |
9532 | for (idx = 0; idx < vlen; idx++) | |
9533 | { | |
9534 | ASM_OUTPUT_ADDR_VEC_ELT | |
9535 | (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); | |
9536 | } | |
9537 | } | |
9538 | ||
9539 | /* Output current function's deferred case vectors. */ | |
9540 | ||
9541 | static void | |
92643d95 | 9542 | unicosmk_output_deferred_case_vectors (FILE *file) |
9caef960 | 9543 | { |
9544 | struct machine_function *machine = cfun->machine; | |
9545 | rtx t; | |
9546 | ||
9547 | if (machine->addr_list == NULL_RTX) | |
9548 | return; | |
9549 | ||
9550 | data_section (); | |
9551 | for (t = machine->addr_list; t; t = XEXP (t, 1)) | |
9552 | unicosmk_output_addr_vec (file, XEXP (t, 0)); | |
9553 | } | |
9554 | ||
92643d95 | 9555 | /* Generate the name of the SSIB section for the current function. */ |
9556 | ||
9557 | #define SSIB_PREFIX "__SSIB_" | |
9558 | #define SSIB_PREFIX_LEN 7 | |
9559 | ||
9560 | static const char * | |
9561 | unicosmk_ssib_name (void) | |
9562 | { | |
9563 | /* This is ok since CAM won't be able to deal with names longer than that | |
9564 | anyway. */ | |
9565 | ||
9566 | static char name[256]; | |
9567 | ||
9568 | rtx x; | |
9569 | const char *fnname; | |
9570 | int len; | |
9571 | ||
9572 | x = DECL_RTL (cfun->decl); | |
9573 | if (GET_CODE (x) != MEM) | |
9574 | abort (); | |
9575 | x = XEXP (x, 0); | |
9576 | if (GET_CODE (x) != SYMBOL_REF) | |
9577 | abort (); | |
9578 | fnname = XSTR (x, 0); | |
9579 | ||
9580 | len = strlen (fnname); | |
9581 | if (len + SSIB_PREFIX_LEN > 255) | |
9582 | len = 255 - SSIB_PREFIX_LEN; | |
9583 | ||
9584 | strcpy (name, SSIB_PREFIX); | |
9585 | strncpy (name + SSIB_PREFIX_LEN, fnname, len); | |
9586 | name[len + SSIB_PREFIX_LEN] = 0; | |
9587 | ||
9588 | return name; | |
9589 | } | |
9590 | ||
9caef960 | 9591 | /* Set up the dynamic subprogram information block (DSIB) and update the |
9592 | frame pointer register ($15) for subroutines which have a frame. If the | |
9593 | subroutine doesn't have a frame, simply increment $15. */ | |
9594 | ||
9595 | static void | |
92643d95 | 9596 | unicosmk_gen_dsib (unsigned long *imaskP) |
9caef960 | 9597 | { |
b19d7ab1 | 9598 | if (alpha_procedure_type == PT_STACK) |
9caef960 | 9599 | { |
9600 | const char *ssib_name; | |
9601 | rtx mem; | |
9602 | ||
9603 | /* Allocate 64 bytes for the DSIB. */ | |
9604 | ||
9605 | FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, | |
9606 | GEN_INT (-64)))); | |
9607 | emit_insn (gen_blockage ()); | |
9608 | ||
9609 | /* Save the return address. */ | |
9610 | ||
9611 | mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 56)); | |
9612 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
9613 | FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA))); | |
df7d0d23 | 9614 | (*imaskP) &= ~(1UL << REG_RA); |
9caef960 | 9615 | |
9616 | /* Save the old frame pointer. */ | |
9617 | ||
9618 | mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 48)); | |
9619 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
9620 | FRP (emit_move_insn (mem, hard_frame_pointer_rtx)); | |
df7d0d23 | 9621 | (*imaskP) &= ~(1UL << HARD_FRAME_POINTER_REGNUM); |
9caef960 | 9622 | |
9623 | emit_insn (gen_blockage ()); | |
9624 | ||
9625 | /* Store the SSIB pointer. */ | |
9626 | ||
9627 | ssib_name = ggc_strdup (unicosmk_ssib_name ()); | |
9628 | mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 32)); | |
9629 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
9630 | ||
9631 | FRP (emit_move_insn (gen_rtx_REG (DImode, 5), | |
9632 | gen_rtx_SYMBOL_REF (Pmode, ssib_name))); | |
9633 | FRP (emit_move_insn (mem, gen_rtx_REG (DImode, 5))); | |
9634 | ||
9635 | /* Save the CIW index. */ | |
9636 | ||
9637 | mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 24)); | |
9638 | set_mem_alias_set (mem, alpha_sr_alias_set); | |
9639 | FRP (emit_move_insn (mem, gen_rtx_REG (DImode, 25))); | |
9640 | ||
9641 | emit_insn (gen_blockage ()); | |
9642 | ||
9643 | /* Set the new frame pointer. */ | |
9644 | ||
9645 | FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx, | |
9646 | stack_pointer_rtx, GEN_INT (64)))); | |
9647 | ||
9648 | } | |
9649 | else | |
9650 | { | |
9651 | /* Increment the frame pointer register to indicate that we do not | |
9652 | have a frame. */ | |
9653 | ||
9654 | FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx, | |
bcd9bd66 | 9655 | hard_frame_pointer_rtx, const1_rtx))); |
9caef960 | 9656 | } |
9657 | } | |
9658 | ||
9caef960 | 9659 | /* Output the static subroutine information block for the current |
9660 | function. */ | |
9661 | ||
9662 | static void | |
92643d95 | 9663 | unicosmk_output_ssib (FILE *file, const char *fnname) |
9caef960 | 9664 | { |
9665 | int len; | |
9666 | int i; | |
9667 | rtx x; | |
9668 | rtx ciw; | |
9669 | struct machine_function *machine = cfun->machine; | |
9670 | ||
9671 | ssib_section (); | |
9672 | fprintf (file, "\t.endp\n\n\t.psect\t%s%s,data\n", user_label_prefix, | |
9673 | unicosmk_ssib_name ()); | |
9674 | ||
9675 | /* Some required stuff and the function name length. */ | |
9676 | ||
9677 | len = strlen (fnname); | |
9678 | fprintf (file, "\t.quad\t^X20008%2.2X28\n", len); | |
9679 | ||
9680 | /* Saved registers | |
9681 | ??? We don't do that yet. */ | |
9682 | ||
9683 | fputs ("\t.quad\t0\n", file); | |
9684 | ||
9685 | /* Function address. */ | |
9686 | ||
9687 | fputs ("\t.quad\t", file); | |
9688 | assemble_name (file, fnname); | |
9689 | putc ('\n', file); | |
9690 | ||
9691 | fputs ("\t.quad\t0\n", file); | |
9692 | fputs ("\t.quad\t0\n", file); | |
9693 | ||
9694 | /* Function name. | |
9695 | ??? We do it the same way Cray CC does it but this could be | |
9696 | simplified. */ | |
9697 | ||
9698 | for( i = 0; i < len; i++ ) | |
9699 | fprintf (file, "\t.byte\t%d\n", (int)(fnname[i])); | |
9700 | if( (len % 8) == 0 ) | |
9701 | fputs ("\t.quad\t0\n", file); | |
9702 | else | |
9703 | fprintf (file, "\t.bits\t%d : 0\n", (8 - (len % 8))*8); | |
9704 | ||
9705 | /* All call information words used in the function. */ | |
9706 | ||
9707 | for (x = machine->first_ciw; x; x = XEXP (x, 1)) | |
9708 | { | |
9709 | ciw = XEXP (x, 0); | |
9caef960 | 9710 | #if HOST_BITS_PER_WIDE_INT == 32 |
4840a03a | 9711 | fprintf (file, "\t.quad\t" HOST_WIDE_INT_PRINT_DOUBLE_HEX "\n", |
9caef960 | 9712 | CONST_DOUBLE_HIGH (ciw), CONST_DOUBLE_LOW (ciw)); |
9713 | #else | |
4840a03a | 9714 | fprintf (file, "\t.quad\t" HOST_WIDE_INT_PRINT_HEX "\n", INTVAL (ciw)); |
9caef960 | 9715 | #endif |
9caef960 | 9716 | } |
9717 | } | |
9718 | ||
9719 | /* Add a call information word (CIW) to the list of the current function's | |
9720 | CIWs and return its index. | |
9721 | ||
9722 | X is a CONST_INT or CONST_DOUBLE representing the CIW. */ | |
9723 | ||
9724 | rtx | |
92643d95 | 9725 | unicosmk_add_call_info_word (rtx x) |
9caef960 | 9726 | { |
9727 | rtx node; | |
9728 | struct machine_function *machine = cfun->machine; | |
9729 | ||
9730 | node = gen_rtx_EXPR_LIST (VOIDmode, x, NULL_RTX); | |
9731 | if (machine->first_ciw == NULL_RTX) | |
9732 | machine->first_ciw = node; | |
9733 | else | |
9734 | XEXP (machine->last_ciw, 1) = node; | |
9735 | ||
9736 | machine->last_ciw = node; | |
9737 | ++machine->ciw_count; | |
9738 | ||
9739 | return GEN_INT (machine->ciw_count | |
35901471 | 9740 | + strlen (current_function_name ())/8 + 5); |
9caef960 | 9741 | } |
9742 | ||
9743 | static char unicosmk_section_buf[100]; | |
9744 | ||
9745 | char * | |
92643d95 | 9746 | unicosmk_text_section (void) |
9caef960 | 9747 | { |
9748 | static int count = 0; | |
9749 | sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@text___%d,code", | |
9750 | count++); | |
9751 | return unicosmk_section_buf; | |
9752 | } | |
9753 | ||
9754 | char * | |
92643d95 | 9755 | unicosmk_data_section (void) |
9caef960 | 9756 | { |
9757 | static int count = 1; | |
9758 | sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@data___%d,data", | |
9759 | count++); | |
9760 | return unicosmk_section_buf; | |
9761 | } | |
9762 | ||
9763 | /* The Cray assembler doesn't accept extern declarations for symbols which | |
9764 | are defined in the same file. We have to keep track of all global | |
9765 | symbols which are referenced and/or defined in a source file and output | |
9766 | extern declarations for those which are referenced but not defined at | |
9767 | the end of file. */ | |
9768 | ||
9769 | /* List of identifiers for which an extern declaration might have to be | |
9770 | emitted. */ | |
9de382d9 | 9771 | /* FIXME: needs to use GC, so it can be saved and restored for PCH. */ |
9caef960 | 9772 | |
9773 | struct unicosmk_extern_list | |
9774 | { | |
9775 | struct unicosmk_extern_list *next; | |
9776 | const char *name; | |
9777 | }; | |
9778 | ||
9779 | static struct unicosmk_extern_list *unicosmk_extern_head = 0; | |
9780 | ||
9781 | /* Output extern declarations which are required for every asm file. */ | |
9782 | ||
9783 | static void | |
92643d95 | 9784 | unicosmk_output_default_externs (FILE *file) |
9caef960 | 9785 | { |
0d95286f | 9786 | static const char *const externs[] = |
9caef960 | 9787 | { "__T3E_MISMATCH" }; |
9788 | ||
9789 | int i; | |
9790 | int n; | |
9791 | ||
9792 | n = ARRAY_SIZE (externs); | |
9793 | ||
9794 | for (i = 0; i < n; i++) | |
9795 | fprintf (file, "\t.extern\t%s\n", externs[i]); | |
9796 | } | |
9797 | ||
9798 | /* Output extern declarations for global symbols which are have been | |
9799 | referenced but not defined. */ | |
9800 | ||
9801 | static void | |
92643d95 | 9802 | unicosmk_output_externs (FILE *file) |
9caef960 | 9803 | { |
9804 | struct unicosmk_extern_list *p; | |
9805 | const char *real_name; | |
9806 | int len; | |
9807 | tree name_tree; | |
9808 | ||
9809 | len = strlen (user_label_prefix); | |
9810 | for (p = unicosmk_extern_head; p != 0; p = p->next) | |
9811 | { | |
9812 | /* We have to strip the encoding and possibly remove user_label_prefix | |
9813 | from the identifier in order to handle -fleading-underscore and | |
9814 | explicit asm names correctly (cf. gcc.dg/asm-names-1.c). */ | |
09a1f342 | 9815 | real_name = default_strip_name_encoding (p->name); |
9caef960 | 9816 | if (len && p->name[0] == '*' |
9817 | && !memcmp (real_name, user_label_prefix, len)) | |
9818 | real_name += len; | |
9819 | ||
9820 | name_tree = get_identifier (real_name); | |
9821 | if (! TREE_ASM_WRITTEN (name_tree)) | |
9822 | { | |
9823 | TREE_ASM_WRITTEN (name_tree) = 1; | |
9824 | fputs ("\t.extern\t", file); | |
9825 | assemble_name (file, p->name); | |
9826 | putc ('\n', file); | |
9827 | } | |
9828 | } | |
9829 | } | |
9830 | ||
9831 | /* Record an extern. */ | |
9832 | ||
9833 | void | |
92643d95 | 9834 | unicosmk_add_extern (const char *name) |
9caef960 | 9835 | { |
9836 | struct unicosmk_extern_list *p; | |
9837 | ||
9838 | p = (struct unicosmk_extern_list *) | |
92192583 | 9839 | xmalloc (sizeof (struct unicosmk_extern_list)); |
9caef960 | 9840 | p->next = unicosmk_extern_head; |
9841 | p->name = name; | |
9842 | unicosmk_extern_head = p; | |
9843 | } | |
9844 | ||
9845 | /* The Cray assembler generates incorrect code if identifiers which | |
9846 | conflict with register names are used as instruction operands. We have | |
9847 | to replace such identifiers with DEX expressions. */ | |
9848 | ||
9849 | /* Structure to collect identifiers which have been replaced by DEX | |
9850 | expressions. */ | |
9de382d9 | 9851 | /* FIXME: needs to use GC, so it can be saved and restored for PCH. */ |
9caef960 | 9852 | |
9853 | struct unicosmk_dex { | |
9854 | struct unicosmk_dex *next; | |
9855 | const char *name; | |
9856 | }; | |
9857 | ||
9858 | /* List of identifiers which have been replaced by DEX expressions. The DEX | |
9859 | number is determined by the position in the list. */ | |
9860 | ||
9861 | static struct unicosmk_dex *unicosmk_dex_list = NULL; | |
9862 | ||
9863 | /* The number of elements in the DEX list. */ | |
9864 | ||
9865 | static int unicosmk_dex_count = 0; | |
9866 | ||
9867 | /* Check if NAME must be replaced by a DEX expression. */ | |
9868 | ||
9869 | static int | |
92643d95 | 9870 | unicosmk_special_name (const char *name) |
9caef960 | 9871 | { |
9872 | if (name[0] == '*') | |
9873 | ++name; | |
9874 | ||
9875 | if (name[0] == '$') | |
9876 | ++name; | |
9877 | ||
9878 | if (name[0] != 'r' && name[0] != 'f' && name[0] != 'R' && name[0] != 'F') | |
9879 | return 0; | |
9880 | ||
9881 | switch (name[1]) | |
9882 | { | |
9883 | case '1': case '2': | |
9884 | return (name[2] == '\0' || (ISDIGIT (name[2]) && name[3] == '\0')); | |
9885 | ||
9886 | case '3': | |
9887 | return (name[2] == '\0' | |
9888 | || ((name[2] == '0' || name[2] == '1') && name[3] == '\0')); | |
9889 | ||
9890 | default: | |
9891 | return (ISDIGIT (name[1]) && name[2] == '\0'); | |
9892 | } | |
9893 | } | |
9894 | ||
9895 | /* Return the DEX number if X must be replaced by a DEX expression and 0 | |
9896 | otherwise. */ | |
9897 | ||
9898 | static int | |
92643d95 | 9899 | unicosmk_need_dex (rtx x) |
9caef960 | 9900 | { |
9901 | struct unicosmk_dex *dex; | |
9902 | const char *name; | |
9903 | int i; | |
9904 | ||
9905 | if (GET_CODE (x) != SYMBOL_REF) | |
9906 | return 0; | |
9907 | ||
9908 | name = XSTR (x,0); | |
9909 | if (! unicosmk_special_name (name)) | |
9910 | return 0; | |
9911 | ||
9912 | i = unicosmk_dex_count; | |
9913 | for (dex = unicosmk_dex_list; dex; dex = dex->next) | |
9914 | { | |
9915 | if (! strcmp (name, dex->name)) | |
9916 | return i; | |
9917 | --i; | |
9918 | } | |
9919 | ||
92192583 | 9920 | dex = (struct unicosmk_dex *) xmalloc (sizeof (struct unicosmk_dex)); |
9caef960 | 9921 | dex->name = name; |
9922 | dex->next = unicosmk_dex_list; | |
9923 | unicosmk_dex_list = dex; | |
9924 | ||
9925 | ++unicosmk_dex_count; | |
9926 | return unicosmk_dex_count; | |
9927 | } | |
9928 | ||
9929 | /* Output the DEX definitions for this file. */ | |
9930 | ||
9931 | static void | |
92643d95 | 9932 | unicosmk_output_dex (FILE *file) |
9caef960 | 9933 | { |
9934 | struct unicosmk_dex *dex; | |
9935 | int i; | |
9936 | ||
9937 | if (unicosmk_dex_list == NULL) | |
9938 | return; | |
9939 | ||
9940 | fprintf (file, "\t.dexstart\n"); | |
9941 | ||
9942 | i = unicosmk_dex_count; | |
9943 | for (dex = unicosmk_dex_list; dex; dex = dex->next) | |
9944 | { | |
9945 | fprintf (file, "\tDEX (%d) = ", i); | |
9946 | assemble_name (file, dex->name); | |
9947 | putc ('\n', file); | |
9948 | --i; | |
9949 | } | |
9950 | ||
9951 | fprintf (file, "\t.dexend\n"); | |
9952 | } | |
9953 | ||
92643d95 | 9954 | /* Output text that to appear at the beginning of an assembler file. */ |
9955 | ||
92c473b8 | 9956 | static void |
9957 | unicosmk_file_start (void) | |
92643d95 | 9958 | { |
9959 | int i; | |
9960 | ||
92c473b8 | 9961 | fputs ("\t.ident\t", asm_out_file); |
9962 | unicosmk_output_module_name (asm_out_file); | |
9963 | fputs ("\n\n", asm_out_file); | |
92643d95 | 9964 | |
9965 | /* The Unicos/Mk assembler uses different register names. Instead of trying | |
9966 | to support them, we simply use micro definitions. */ | |
9967 | ||
9968 | /* CAM has different register names: rN for the integer register N and fN | |
9969 | for the floating-point register N. Instead of trying to use these in | |
9970 | alpha.md, we define the symbols $N and $fN to refer to the appropriate | |
9971 | register. */ | |
9972 | ||
9973 | for (i = 0; i < 32; ++i) | |
92c473b8 | 9974 | fprintf (asm_out_file, "$%d <- r%d\n", i, i); |
92643d95 | 9975 | |
9976 | for (i = 0; i < 32; ++i) | |
92c473b8 | 9977 | fprintf (asm_out_file, "$f%d <- f%d\n", i, i); |
92643d95 | 9978 | |
92c473b8 | 9979 | putc ('\n', asm_out_file); |
92643d95 | 9980 | |
9981 | /* The .align directive fill unused space with zeroes which does not work | |
9982 | in code sections. We define the macro 'gcc@code@align' which uses nops | |
9983 | instead. Note that it assumes that code sections always have the | |
9984 | biggest possible alignment since . refers to the current offset from | |
9985 | the beginning of the section. */ | |
9986 | ||
92c473b8 | 9987 | fputs ("\t.macro gcc@code@align n\n", asm_out_file); |
9988 | fputs ("gcc@n@bytes = 1 << n\n", asm_out_file); | |
9989 | fputs ("gcc@here = . % gcc@n@bytes\n", asm_out_file); | |
9990 | fputs ("\t.if ne, gcc@here, 0\n", asm_out_file); | |
9991 | fputs ("\t.repeat (gcc@n@bytes - gcc@here) / 4\n", asm_out_file); | |
9992 | fputs ("\tbis r31,r31,r31\n", asm_out_file); | |
9993 | fputs ("\t.endr\n", asm_out_file); | |
9994 | fputs ("\t.endif\n", asm_out_file); | |
9995 | fputs ("\t.endm gcc@code@align\n\n", asm_out_file); | |
92643d95 | 9996 | |
9997 | /* Output extern declarations which should always be visible. */ | |
92c473b8 | 9998 | unicosmk_output_default_externs (asm_out_file); |
92643d95 | 9999 | |
10000 | /* Open a dummy section. We always need to be inside a section for the | |
10001 | section-switching code to work correctly. | |
10002 | ??? This should be a module id or something like that. I still have to | |
10003 | figure out what the rules for those are. */ | |
92c473b8 | 10004 | fputs ("\n\t.psect\t$SG00000,data\n", asm_out_file); |
92643d95 | 10005 | } |
10006 | ||
10007 | /* Output text to appear at the end of an assembler file. This includes all | |
10008 | pending extern declarations and DEX expressions. */ | |
10009 | ||
10010 | static void | |
10011 | unicosmk_file_end (void) | |
10012 | { | |
10013 | fputs ("\t.endp\n\n", asm_out_file); | |
10014 | ||
10015 | /* Output all pending externs. */ | |
10016 | ||
10017 | unicosmk_output_externs (asm_out_file); | |
10018 | ||
10019 | /* Output dex definitions used for functions whose names conflict with | |
10020 | register names. */ | |
10021 | ||
10022 | unicosmk_output_dex (asm_out_file); | |
10023 | ||
10024 | fputs ("\t.end\t", asm_out_file); | |
10025 | unicosmk_output_module_name (asm_out_file); | |
10026 | putc ('\n', asm_out_file); | |
10027 | } | |
10028 | ||
9caef960 | 10029 | #else |
10030 | ||
10031 | static void | |
92643d95 | 10032 | unicosmk_output_deferred_case_vectors (FILE *file ATTRIBUTE_UNUSED) |
9caef960 | 10033 | {} |
10034 | ||
10035 | static void | |
92643d95 | 10036 | unicosmk_gen_dsib (unsigned long *imaskP ATTRIBUTE_UNUSED) |
9caef960 | 10037 | {} |
10038 | ||
10039 | static void | |
92643d95 | 10040 | unicosmk_output_ssib (FILE * file ATTRIBUTE_UNUSED, |
10041 | const char * fnname ATTRIBUTE_UNUSED) | |
9caef960 | 10042 | {} |
10043 | ||
10044 | rtx | |
92643d95 | 10045 | unicosmk_add_call_info_word (rtx x ATTRIBUTE_UNUSED) |
9caef960 | 10046 | { |
10047 | return NULL_RTX; | |
10048 | } | |
10049 | ||
10050 | static int | |
92643d95 | 10051 | unicosmk_need_dex (rtx x ATTRIBUTE_UNUSED) |
9caef960 | 10052 | { |
10053 | return 0; | |
10054 | } | |
10055 | ||
10056 | #endif /* TARGET_ABI_UNICOSMK */ | |
1f3233d1 | 10057 | |
f2f543a3 | 10058 | static void |
10059 | alpha_init_libfuncs (void) | |
10060 | { | |
10061 | if (TARGET_ABI_UNICOSMK) | |
10062 | { | |
10063 | /* Prevent gcc from generating calls to __divsi3. */ | |
10064 | set_optab_libfunc (sdiv_optab, SImode, 0); | |
10065 | set_optab_libfunc (udiv_optab, SImode, 0); | |
10066 | ||
10067 | /* Use the functions provided by the system library | |
10068 | for DImode integer division. */ | |
10069 | set_optab_libfunc (sdiv_optab, DImode, "$sldiv"); | |
10070 | set_optab_libfunc (udiv_optab, DImode, "$uldiv"); | |
10071 | } | |
10072 | else if (TARGET_ABI_OPEN_VMS) | |
10073 | { | |
10074 | /* Use the VMS runtime library functions for division and | |
10075 | remainder. */ | |
10076 | set_optab_libfunc (sdiv_optab, SImode, "OTS$DIV_I"); | |
10077 | set_optab_libfunc (sdiv_optab, DImode, "OTS$DIV_L"); | |
10078 | set_optab_libfunc (udiv_optab, SImode, "OTS$DIV_UI"); | |
10079 | set_optab_libfunc (udiv_optab, DImode, "OTS$DIV_UL"); | |
10080 | set_optab_libfunc (smod_optab, SImode, "OTS$REM_I"); | |
10081 | set_optab_libfunc (smod_optab, DImode, "OTS$REM_L"); | |
10082 | set_optab_libfunc (umod_optab, SImode, "OTS$REM_UI"); | |
10083 | set_optab_libfunc (umod_optab, DImode, "OTS$REM_UL"); | |
10084 | } | |
10085 | } | |
10086 | ||
92643d95 | 10087 | \f |
10088 | /* Initialize the GCC target structure. */ | |
10089 | #if TARGET_ABI_OPEN_VMS | |
10090 | # undef TARGET_ATTRIBUTE_TABLE | |
10091 | # define TARGET_ATTRIBUTE_TABLE vms_attribute_table | |
10092 | # undef TARGET_SECTION_TYPE_FLAGS | |
10093 | # define TARGET_SECTION_TYPE_FLAGS vms_section_type_flags | |
10094 | #endif | |
10095 | ||
10096 | #undef TARGET_IN_SMALL_DATA_P | |
10097 | #define TARGET_IN_SMALL_DATA_P alpha_in_small_data_p | |
10098 | ||
10099 | #if TARGET_ABI_UNICOSMK | |
10100 | # undef TARGET_INSERT_ATTRIBUTES | |
10101 | # define TARGET_INSERT_ATTRIBUTES unicosmk_insert_attributes | |
10102 | # undef TARGET_SECTION_TYPE_FLAGS | |
10103 | # define TARGET_SECTION_TYPE_FLAGS unicosmk_section_type_flags | |
10104 | # undef TARGET_ASM_UNIQUE_SECTION | |
10105 | # define TARGET_ASM_UNIQUE_SECTION unicosmk_unique_section | |
10106 | # undef TARGET_ASM_GLOBALIZE_LABEL | |
10107 | # define TARGET_ASM_GLOBALIZE_LABEL hook_void_FILEptr_constcharptr | |
0336f0f0 | 10108 | # undef TARGET_MUST_PASS_IN_STACK |
10109 | # define TARGET_MUST_PASS_IN_STACK unicosmk_must_pass_in_stack | |
92643d95 | 10110 | #endif |
10111 | ||
10112 | #undef TARGET_ASM_ALIGNED_HI_OP | |
10113 | #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" | |
10114 | #undef TARGET_ASM_ALIGNED_DI_OP | |
10115 | #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" | |
10116 | ||
10117 | /* Default unaligned ops are provided for ELF systems. To get unaligned | |
10118 | data for non-ELF systems, we have to turn off auto alignment. */ | |
10119 | #ifndef OBJECT_FORMAT_ELF | |
10120 | #undef TARGET_ASM_UNALIGNED_HI_OP | |
10121 | #define TARGET_ASM_UNALIGNED_HI_OP "\t.align 0\n\t.word\t" | |
10122 | #undef TARGET_ASM_UNALIGNED_SI_OP | |
10123 | #define TARGET_ASM_UNALIGNED_SI_OP "\t.align 0\n\t.long\t" | |
10124 | #undef TARGET_ASM_UNALIGNED_DI_OP | |
10125 | #define TARGET_ASM_UNALIGNED_DI_OP "\t.align 0\n\t.quad\t" | |
10126 | #endif | |
10127 | ||
10128 | #ifdef OBJECT_FORMAT_ELF | |
10129 | #undef TARGET_ASM_SELECT_RTX_SECTION | |
10130 | #define TARGET_ASM_SELECT_RTX_SECTION alpha_elf_select_rtx_section | |
10131 | #endif | |
10132 | ||
10133 | #undef TARGET_ASM_FUNCTION_END_PROLOGUE | |
10134 | #define TARGET_ASM_FUNCTION_END_PROLOGUE alpha_output_function_end_prologue | |
10135 | ||
f2f543a3 | 10136 | #undef TARGET_INIT_LIBFUNCS |
10137 | #define TARGET_INIT_LIBFUNCS alpha_init_libfuncs | |
10138 | ||
92c473b8 | 10139 | #if TARGET_ABI_UNICOSMK |
10140 | #undef TARGET_ASM_FILE_START | |
10141 | #define TARGET_ASM_FILE_START unicosmk_file_start | |
10142 | #undef TARGET_ASM_FILE_END | |
10143 | #define TARGET_ASM_FILE_END unicosmk_file_end | |
10144 | #else | |
10145 | #undef TARGET_ASM_FILE_START | |
10146 | #define TARGET_ASM_FILE_START alpha_file_start | |
10147 | #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE | |
10148 | #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true | |
10149 | #endif | |
10150 | ||
92643d95 | 10151 | #undef TARGET_SCHED_ADJUST_COST |
10152 | #define TARGET_SCHED_ADJUST_COST alpha_adjust_cost | |
10153 | #undef TARGET_SCHED_ISSUE_RATE | |
10154 | #define TARGET_SCHED_ISSUE_RATE alpha_issue_rate | |
10155 | #undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE | |
5e611c5f | 10156 | #define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE hook_int_void_1 |
92643d95 | 10157 | #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD |
10158 | #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \ | |
10159 | alpha_multipass_dfa_lookahead | |
10160 | ||
10161 | #undef TARGET_HAVE_TLS | |
10162 | #define TARGET_HAVE_TLS HAVE_AS_TLS | |
10163 | ||
10164 | #undef TARGET_INIT_BUILTINS | |
10165 | #define TARGET_INIT_BUILTINS alpha_init_builtins | |
10166 | #undef TARGET_EXPAND_BUILTIN | |
10167 | #define TARGET_EXPAND_BUILTIN alpha_expand_builtin | |
10168 | ||
10169 | #undef TARGET_FUNCTION_OK_FOR_SIBCALL | |
10170 | #define TARGET_FUNCTION_OK_FOR_SIBCALL alpha_function_ok_for_sibcall | |
10171 | #undef TARGET_CANNOT_COPY_INSN_P | |
10172 | #define TARGET_CANNOT_COPY_INSN_P alpha_cannot_copy_insn_p | |
10173 | ||
10174 | #if TARGET_ABI_OSF | |
10175 | #undef TARGET_ASM_OUTPUT_MI_THUNK | |
10176 | #define TARGET_ASM_OUTPUT_MI_THUNK alpha_output_mi_thunk_osf | |
10177 | #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK | |
10178 | #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true | |
10179 | #endif | |
10180 | ||
10181 | #undef TARGET_RTX_COSTS | |
10182 | #define TARGET_RTX_COSTS alpha_rtx_costs | |
10183 | #undef TARGET_ADDRESS_COST | |
10184 | #define TARGET_ADDRESS_COST hook_int_rtx_0 | |
10185 | ||
10186 | #undef TARGET_MACHINE_DEPENDENT_REORG | |
10187 | #define TARGET_MACHINE_DEPENDENT_REORG alpha_reorg | |
10188 | ||
dd9f3024 | 10189 | #undef TARGET_PROMOTE_FUNCTION_ARGS |
10190 | #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true | |
10191 | #undef TARGET_PROMOTE_FUNCTION_RETURN | |
10192 | #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true | |
10193 | #undef TARGET_PROMOTE_PROTOTYPES | |
10194 | #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_false | |
dd9f3024 | 10195 | #undef TARGET_RETURN_IN_MEMORY |
10196 | #define TARGET_RETURN_IN_MEMORY alpha_return_in_memory | |
b981d932 | 10197 | #undef TARGET_PASS_BY_REFERENCE |
10198 | #define TARGET_PASS_BY_REFERENCE alpha_pass_by_reference | |
dd9f3024 | 10199 | #undef TARGET_SETUP_INCOMING_VARARGS |
10200 | #define TARGET_SETUP_INCOMING_VARARGS alpha_setup_incoming_varargs | |
10201 | #undef TARGET_STRICT_ARGUMENT_NAMING | |
10202 | #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true | |
10203 | #undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED | |
10204 | #define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true | |
92d40bc4 | 10205 | #undef TARGET_SPLIT_COMPLEX_ARG |
10206 | #define TARGET_SPLIT_COMPLEX_ARG alpha_split_complex_arg | |
de8f9b94 | 10207 | #undef TARGET_GIMPLIFY_VA_ARG_EXPR |
10208 | #define TARGET_GIMPLIFY_VA_ARG_EXPR alpha_gimplify_va_arg | |
dd9f3024 | 10209 | |
2e15d750 | 10210 | #undef TARGET_BUILD_BUILTIN_VA_LIST |
10211 | #define TARGET_BUILD_BUILTIN_VA_LIST alpha_build_builtin_va_list | |
10212 | ||
92643d95 | 10213 | struct gcc_target targetm = TARGET_INITIALIZER; |
10214 | ||
10215 | \f | |
1f3233d1 | 10216 | #include "gt-alpha.h" |
10217 |