]>
Commit | Line | Data |
---|---|---|
bf2a98b3 | 1 | /* Subroutines used for code generation on the DEC Alpha. |
fbd26352 | 2 | Copyright (C) 1992-2019 Free Software Foundation, Inc. |
0e0a0e7a | 3 | Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) |
bf2a98b3 | 4 | |
187b36cf | 5 | This file is part of GCC. |
bf2a98b3 | 6 | |
187b36cf | 7 | GCC is free software; you can redistribute it and/or modify |
bf2a98b3 | 8 | it under the terms of the GNU General Public License as published by |
038d1e19 | 9 | the Free Software Foundation; either version 3, or (at your option) |
bf2a98b3 | 10 | any later version. |
11 | ||
187b36cf | 12 | GCC is distributed in the hope that it will be useful, |
bf2a98b3 | 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
038d1e19 | 18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ | |
bf2a98b3 | 20 | |
21 | ||
785790dc | 22 | #define IN_TARGET_CODE 1 |
23 | ||
bf2a98b3 | 24 | #include "config.h" |
769ea120 | 25 | #include "system.h" |
805e22b2 | 26 | #include "coretypes.h" |
9ef16211 | 27 | #include "backend.h" |
c1eb80de | 28 | #include "target.h" |
29 | #include "rtl.h" | |
9ef16211 | 30 | #include "tree.h" |
30a86690 | 31 | #include "stringpool.h" |
32 | #include "attribs.h" | |
ea36272b | 33 | #include "memmodel.h" |
9ef16211 | 34 | #include "gimple.h" |
9ef16211 | 35 | #include "df.h" |
ef319c24 | 36 | #include "predict.h" |
c1eb80de | 37 | #include "tm_p.h" |
9ef16211 | 38 | #include "ssa.h" |
c1eb80de | 39 | #include "expmed.h" |
40 | #include "optabs.h" | |
41 | #include "regs.h" | |
42 | #include "emit-rtl.h" | |
43 | #include "recog.h" | |
44 | #include "diagnostic-core.h" | |
b20a8bb4 | 45 | #include "alias.h" |
b20a8bb4 | 46 | #include "fold-const.h" |
9ed99284 | 47 | #include "stor-layout.h" |
48 | #include "calls.h" | |
49 | #include "varasm.h" | |
bf2a98b3 | 50 | #include "output.h" |
51 | #include "insn-attr.h" | |
d53441c8 | 52 | #include "explow.h" |
bf2a98b3 | 53 | #include "expr.h" |
d8fc4d0b | 54 | #include "reload.h" |
0c0464e6 | 55 | #include "except.h" |
218e3e4e | 56 | #include "common/common-target.h" |
961d6ddd | 57 | #include "debug.h" |
a1f71e15 | 58 | #include "langhooks.h" |
94ea8568 | 59 | #include "cfgrtl.h" |
b80c91bc | 60 | #include "tree-pass.h" |
61 | #include "context.h" | |
e3825818 | 62 | #include "gimple-iterator.h" |
a8783bee | 63 | #include "gimplify.h" |
a6c787e5 | 64 | #include "tree-stdarg.h" |
1dffd068 | 65 | #include "tm-constrs.h" |
2db66e7c | 66 | #include "libfuncs.h" |
56317318 | 67 | #include "params.h" |
f7715905 | 68 | #include "builtins.h" |
97a30fee | 69 | #include "rtl-iter.h" |
6848a0ae | 70 | #include "flags.h" |
0c0464e6 | 71 | |
0c71fb4f | 72 | /* This file should be included last. */ |
4b498588 | 73 | #include "target-def.h" |
74 | ||
65abff06 | 75 | /* Specify which cpu to schedule for. */ |
fb64edde | 76 | enum processor_type alpha_tune; |
0c0464e6 | 77 | |
fb64edde | 78 | /* Which cpu we're generating code for. */ |
f141a8b4 | 79 | enum processor_type alpha_cpu; |
fb64edde | 80 | |
9e7454d0 | 81 | static const char * const alpha_cpu_name[] = |
07c1a295 | 82 | { |
83 | "ev4", "ev5", "ev6" | |
84 | }; | |
0c5845b3 | 85 | |
c4622276 | 86 | /* Specify how accurate floating-point traps need to be. */ |
87 | ||
88 | enum alpha_trap_precision alpha_tp; | |
89 | ||
90 | /* Specify the floating-point rounding mode. */ | |
91 | ||
92 | enum alpha_fp_rounding_mode alpha_fprm; | |
93 | ||
94 | /* Specify which things cause traps. */ | |
95 | ||
96 | enum alpha_fp_trap_mode alpha_fptm; | |
97 | ||
e3e08e7f | 98 | /* Nonzero if inside of a function, because the Alpha asm can't |
449b7f2d | 99 | handle .files inside of functions. */ |
100 | ||
101 | static int inside_function = FALSE; | |
102 | ||
07c1a295 | 103 | /* The number of cycles of latency we should assume on memory reads. */ |
104 | ||
8647dea5 | 105 | static int alpha_memory_latency = 3; |
07c1a295 | 106 | |
b9a5aa8e | 107 | /* Whether the function needs the GP. */ |
108 | ||
109 | static int alpha_function_needs_gp; | |
110 | ||
a314eb5e | 111 | /* The assembler name of the current function. */ |
112 | ||
113 | static const char *alpha_fnname; | |
114 | ||
1f0ce6a6 | 115 | /* The next explicit relocation sequence number. */ |
9de382d9 | 116 | extern GTY(()) int alpha_next_sequence_number; |
1f0ce6a6 | 117 | int alpha_next_sequence_number = 1; |
118 | ||
119 | /* The literal and gpdisp sequence numbers for this insn, as printed | |
120 | by %# and %* respectively. */ | |
9de382d9 | 121 | extern GTY(()) int alpha_this_literal_sequence_number; |
122 | extern GTY(()) int alpha_this_gpdisp_sequence_number; | |
1f0ce6a6 | 123 | int alpha_this_literal_sequence_number; |
124 | int alpha_this_gpdisp_sequence_number; | |
125 | ||
fab7adbf | 126 | /* Costs of various operations on the different architectures. */ |
127 | ||
128 | struct alpha_rtx_cost_data | |
129 | { | |
130 | unsigned char fp_add; | |
131 | unsigned char fp_mult; | |
132 | unsigned char fp_div_sf; | |
133 | unsigned char fp_div_df; | |
134 | unsigned char int_mult_si; | |
135 | unsigned char int_mult_di; | |
136 | unsigned char int_shift; | |
137 | unsigned char int_cmov; | |
d7cf2331 | 138 | unsigned short int_div; |
fab7adbf | 139 | }; |
140 | ||
141 | static struct alpha_rtx_cost_data const alpha_rtx_cost_data[PROCESSOR_MAX] = | |
142 | { | |
143 | { /* EV4 */ | |
144 | COSTS_N_INSNS (6), /* fp_add */ | |
145 | COSTS_N_INSNS (6), /* fp_mult */ | |
146 | COSTS_N_INSNS (34), /* fp_div_sf */ | |
147 | COSTS_N_INSNS (63), /* fp_div_df */ | |
148 | COSTS_N_INSNS (23), /* int_mult_si */ | |
149 | COSTS_N_INSNS (23), /* int_mult_di */ | |
150 | COSTS_N_INSNS (2), /* int_shift */ | |
151 | COSTS_N_INSNS (2), /* int_cmov */ | |
f6777b0a | 152 | COSTS_N_INSNS (97), /* int_div */ |
fab7adbf | 153 | }, |
154 | { /* EV5 */ | |
155 | COSTS_N_INSNS (4), /* fp_add */ | |
156 | COSTS_N_INSNS (4), /* fp_mult */ | |
157 | COSTS_N_INSNS (15), /* fp_div_sf */ | |
158 | COSTS_N_INSNS (22), /* fp_div_df */ | |
159 | COSTS_N_INSNS (8), /* int_mult_si */ | |
160 | COSTS_N_INSNS (12), /* int_mult_di */ | |
161 | COSTS_N_INSNS (1) + 1, /* int_shift */ | |
162 | COSTS_N_INSNS (1), /* int_cmov */ | |
f6777b0a | 163 | COSTS_N_INSNS (83), /* int_div */ |
fab7adbf | 164 | }, |
165 | { /* EV6 */ | |
166 | COSTS_N_INSNS (4), /* fp_add */ | |
167 | COSTS_N_INSNS (4), /* fp_mult */ | |
168 | COSTS_N_INSNS (12), /* fp_div_sf */ | |
169 | COSTS_N_INSNS (15), /* fp_div_df */ | |
170 | COSTS_N_INSNS (7), /* int_mult_si */ | |
171 | COSTS_N_INSNS (7), /* int_mult_di */ | |
172 | COSTS_N_INSNS (1), /* int_shift */ | |
173 | COSTS_N_INSNS (2), /* int_cmov */ | |
f6777b0a | 174 | COSTS_N_INSNS (86), /* int_div */ |
fab7adbf | 175 | }, |
176 | }; | |
177 | ||
d7cf2331 | 178 | /* Similar but tuned for code size instead of execution latency. The |
179 | extra +N is fractional cost tuning based on latency. It's used to | |
180 | encourage use of cheaper insns like shift, but only if there's just | |
181 | one of them. */ | |
182 | ||
183 | static struct alpha_rtx_cost_data const alpha_rtx_cost_size = | |
184 | { | |
185 | COSTS_N_INSNS (1), /* fp_add */ | |
186 | COSTS_N_INSNS (1), /* fp_mult */ | |
187 | COSTS_N_INSNS (1), /* fp_div_sf */ | |
188 | COSTS_N_INSNS (1) + 1, /* fp_div_df */ | |
189 | COSTS_N_INSNS (1) + 1, /* int_mult_si */ | |
190 | COSTS_N_INSNS (1) + 2, /* int_mult_di */ | |
191 | COSTS_N_INSNS (1), /* int_shift */ | |
192 | COSTS_N_INSNS (1), /* int_cmov */ | |
193 | COSTS_N_INSNS (6), /* int_div */ | |
194 | }; | |
195 | ||
0dbd1c74 | 196 | /* Get the number of args of a function in one of two ways. */ |
04d75965 | 197 | #if TARGET_ABI_OPEN_VMS |
abe32cce | 198 | #define NUM_ARGS crtl->args.info.num_args |
0dbd1c74 | 199 | #else |
abe32cce | 200 | #define NUM_ARGS crtl->args.info |
0dbd1c74 | 201 | #endif |
d2832bd8 | 202 | |
d2832bd8 | 203 | #define REG_PV 27 |
204 | #define REG_RA 26 | |
f2cc13dc | 205 | |
92643d95 | 206 | /* Declarations of static functions. */ |
207 | static struct machine_function *alpha_init_machine_status (void); | |
8c3428a6 | 208 | static rtx alpha_emit_xfloating_compare (enum rtx_code *, rtx, rtx); |
b80c91bc | 209 | static void alpha_handle_trap_shadows (void); |
210 | static void alpha_align_insns (void); | |
3032a4ea | 211 | static void alpha_override_options_after_change (void); |
805e22b2 | 212 | |
92643d95 | 213 | #if TARGET_ABI_OPEN_VMS |
5ce94904 | 214 | static void alpha_write_linkage (FILE *, const char *); |
f77c4496 | 215 | static bool vms_valid_pointer_mode (scalar_int_mode); |
044f30d8 | 216 | #else |
217 | #define vms_patch_builtins() gcc_unreachable() | |
6988553d | 218 | #endif |
a767736d | 219 | \f |
b80c91bc | 220 | static unsigned int |
221 | rest_of_handle_trap_shadows (void) | |
222 | { | |
223 | alpha_handle_trap_shadows (); | |
224 | return 0; | |
225 | } | |
226 | ||
227 | namespace { | |
228 | ||
229 | const pass_data pass_data_handle_trap_shadows = | |
230 | { | |
231 | RTL_PASS, | |
232 | "trap_shadows", /* name */ | |
233 | OPTGROUP_NONE, /* optinfo_flags */ | |
234 | TV_NONE, /* tv_id */ | |
235 | 0, /* properties_required */ | |
236 | 0, /* properties_provided */ | |
237 | 0, /* properties_destroyed */ | |
238 | 0, /* todo_flags_start */ | |
239 | TODO_df_finish, /* todo_flags_finish */ | |
240 | }; | |
241 | ||
242 | class pass_handle_trap_shadows : public rtl_opt_pass | |
243 | { | |
244 | public: | |
245 | pass_handle_trap_shadows(gcc::context *ctxt) | |
246 | : rtl_opt_pass(pass_data_handle_trap_shadows, ctxt) | |
247 | {} | |
248 | ||
249 | /* opt_pass methods: */ | |
250 | virtual bool gate (function *) | |
251 | { | |
252 | return alpha_tp != ALPHA_TP_PROG || flag_exceptions; | |
253 | } | |
254 | ||
255 | virtual unsigned int execute (function *) | |
256 | { | |
257 | return rest_of_handle_trap_shadows (); | |
258 | } | |
259 | ||
260 | }; // class pass_handle_trap_shadows | |
261 | ||
262 | } // anon namespace | |
263 | ||
264 | rtl_opt_pass * | |
265 | make_pass_handle_trap_shadows (gcc::context *ctxt) | |
266 | { | |
267 | return new pass_handle_trap_shadows (ctxt); | |
268 | } | |
269 | ||
270 | static unsigned int | |
271 | rest_of_align_insns (void) | |
272 | { | |
273 | alpha_align_insns (); | |
274 | return 0; | |
275 | } | |
276 | ||
277 | namespace { | |
278 | ||
279 | const pass_data pass_data_align_insns = | |
280 | { | |
281 | RTL_PASS, | |
282 | "align_insns", /* name */ | |
283 | OPTGROUP_NONE, /* optinfo_flags */ | |
284 | TV_NONE, /* tv_id */ | |
285 | 0, /* properties_required */ | |
286 | 0, /* properties_provided */ | |
287 | 0, /* properties_destroyed */ | |
288 | 0, /* todo_flags_start */ | |
289 | TODO_df_finish, /* todo_flags_finish */ | |
290 | }; | |
291 | ||
292 | class pass_align_insns : public rtl_opt_pass | |
293 | { | |
294 | public: | |
295 | pass_align_insns(gcc::context *ctxt) | |
296 | : rtl_opt_pass(pass_data_align_insns, ctxt) | |
297 | {} | |
298 | ||
299 | /* opt_pass methods: */ | |
300 | virtual bool gate (function *) | |
301 | { | |
302 | /* Due to the number of extra trapb insns, don't bother fixing up | |
303 | alignment when trap precision is instruction. Moreover, we can | |
304 | only do our job when sched2 is run. */ | |
305 | return ((alpha_tune == PROCESSOR_EV4 | |
306 | || alpha_tune == PROCESSOR_EV5) | |
307 | && optimize && !optimize_size | |
308 | && alpha_tp != ALPHA_TP_INSN | |
309 | && flag_schedule_insns_after_reload); | |
310 | } | |
311 | ||
312 | virtual unsigned int execute (function *) | |
313 | { | |
314 | return rest_of_align_insns (); | |
315 | } | |
316 | ||
317 | }; // class pass_align_insns | |
318 | ||
319 | } // anon namespace | |
320 | ||
321 | rtl_opt_pass * | |
322 | make_pass_align_insns (gcc::context *ctxt) | |
323 | { | |
324 | return new pass_align_insns (ctxt); | |
325 | } | |
326 | ||
4257b08a | 327 | #ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING |
eddcdde1 | 328 | /* Implement TARGET_MANGLE_TYPE. */ |
4257b08a | 329 | |
330 | static const char * | |
a9f1838b | 331 | alpha_mangle_type (const_tree type) |
4257b08a | 332 | { |
333 | if (TYPE_MAIN_VARIANT (type) == long_double_type_node | |
334 | && TARGET_LONG_DOUBLE_128) | |
335 | return "g"; | |
336 | ||
337 | /* For all other types, use normal C++ mangling. */ | |
338 | return NULL; | |
339 | } | |
340 | #endif | |
341 | ||
65abff06 | 342 | /* Parse target option strings. */ |
c4622276 | 343 | |
4c834714 | 344 | static void |
345 | alpha_option_override (void) | |
c4622276 | 346 | { |
e99c3a1d | 347 | static const struct cpu_table { |
348 | const char *const name; | |
349 | const enum processor_type processor; | |
350 | const int flags; | |
56317318 | 351 | const unsigned short line_size; /* in bytes */ |
352 | const unsigned short l1_size; /* in kb. */ | |
353 | const unsigned short l2_size; /* in kb. */ | |
27de1488 | 354 | } cpu_table[] = { |
56317318 | 355 | /* EV4/LCA45 had 8k L1 caches; EV45 had 16k L1 caches. |
356 | EV4/EV45 had 128k to 16M 32-byte direct Bcache. LCA45 | |
357 | had 64k to 8M 8-byte direct Bcache. */ | |
358 | { "ev4", PROCESSOR_EV4, 0, 32, 8, 8*1024 }, | |
359 | { "21064", PROCESSOR_EV4, 0, 32, 8, 8*1024 }, | |
360 | { "ev45", PROCESSOR_EV4, 0, 32, 16, 16*1024 }, | |
361 | ||
362 | /* EV5 or EV56 had 8k 32 byte L1, 96k 32 or 64 byte L2, | |
363 | and 1M to 16M 64 byte L3 (not modeled). | |
364 | PCA56 had 16k 64-byte cache; PCA57 had 32k Icache. | |
365 | PCA56 had 8k 64-byte cache; PCA57 had 16k Dcache. */ | |
366 | { "ev5", PROCESSOR_EV5, 0, 32, 8, 96 }, | |
367 | { "21164", PROCESSOR_EV5, 0, 32, 8, 96 }, | |
368 | { "ev56", PROCESSOR_EV5, MASK_BWX, 32, 8, 96 }, | |
369 | { "21164a", PROCESSOR_EV5, MASK_BWX, 32, 8, 96 }, | |
370 | { "pca56", PROCESSOR_EV5, MASK_BWX|MASK_MAX, 64, 16, 4*1024 }, | |
371 | { "21164PC",PROCESSOR_EV5, MASK_BWX|MASK_MAX, 64, 16, 4*1024 }, | |
372 | { "21164pc",PROCESSOR_EV5, MASK_BWX|MASK_MAX, 64, 16, 4*1024 }, | |
373 | ||
374 | /* EV6 had 64k 64 byte L1, 1M to 16M Bcache. */ | |
375 | { "ev6", PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX, 64, 64, 16*1024 }, | |
376 | { "21264", PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX, 64, 64, 16*1024 }, | |
377 | { "ev67", PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX|MASK_CIX, | |
378 | 64, 64, 16*1024 }, | |
379 | { "21264a", PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX|MASK_CIX, | |
380 | 64, 64, 16*1024 } | |
27de1488 | 381 | }; |
9e7454d0 | 382 | |
afba4ec8 | 383 | int const ct_size = ARRAY_SIZE (cpu_table); |
56317318 | 384 | int line_size = 0, l1_size = 0, l2_size = 0; |
fb64edde | 385 | int i; |
386 | ||
4c834714 | 387 | #ifdef SUBTARGET_OVERRIDE_OPTIONS |
388 | SUBTARGET_OVERRIDE_OPTIONS; | |
389 | #endif | |
390 | ||
669cf718 | 391 | /* Default to full IEEE compliance mode for Go language. */ |
392 | if (strcmp (lang_hooks.name, "GNU Go") == 0 | |
393 | && !(target_flags_explicit & MASK_IEEE)) | |
394 | target_flags |= MASK_IEEE; | |
395 | ||
04d75965 | 396 | alpha_fprm = ALPHA_FPRM_NORM; |
c4622276 | 397 | alpha_tp = ALPHA_TP_PROG; |
c4622276 | 398 | alpha_fptm = ALPHA_FPTM_N; |
399 | ||
400 | if (TARGET_IEEE) | |
401 | { | |
04d75965 | 402 | alpha_tp = ALPHA_TP_INSN; |
403 | alpha_fptm = ALPHA_FPTM_SU; | |
c4622276 | 404 | } |
c4622276 | 405 | if (TARGET_IEEE_WITH_INEXACT) |
406 | { | |
04d75965 | 407 | alpha_tp = ALPHA_TP_INSN; |
408 | alpha_fptm = ALPHA_FPTM_SUI; | |
c4622276 | 409 | } |
410 | ||
411 | if (alpha_tp_string) | |
264f7d8c | 412 | { |
413 | if (! strcmp (alpha_tp_string, "p")) | |
c4622276 | 414 | alpha_tp = ALPHA_TP_PROG; |
264f7d8c | 415 | else if (! strcmp (alpha_tp_string, "f")) |
c4622276 | 416 | alpha_tp = ALPHA_TP_FUNC; |
264f7d8c | 417 | else if (! strcmp (alpha_tp_string, "i")) |
c4622276 | 418 | alpha_tp = ALPHA_TP_INSN; |
264f7d8c | 419 | else |
1e5fcbe2 | 420 | error ("bad value %qs for -mtrap-precision switch", alpha_tp_string); |
264f7d8c | 421 | } |
c4622276 | 422 | |
423 | if (alpha_fprm_string) | |
264f7d8c | 424 | { |
425 | if (! strcmp (alpha_fprm_string, "n")) | |
c4622276 | 426 | alpha_fprm = ALPHA_FPRM_NORM; |
264f7d8c | 427 | else if (! strcmp (alpha_fprm_string, "m")) |
c4622276 | 428 | alpha_fprm = ALPHA_FPRM_MINF; |
264f7d8c | 429 | else if (! strcmp (alpha_fprm_string, "c")) |
c4622276 | 430 | alpha_fprm = ALPHA_FPRM_CHOP; |
264f7d8c | 431 | else if (! strcmp (alpha_fprm_string,"d")) |
c4622276 | 432 | alpha_fprm = ALPHA_FPRM_DYN; |
264f7d8c | 433 | else |
1e5fcbe2 | 434 | error ("bad value %qs for -mfp-rounding-mode switch", |
c4622276 | 435 | alpha_fprm_string); |
264f7d8c | 436 | } |
c4622276 | 437 | |
438 | if (alpha_fptm_string) | |
264f7d8c | 439 | { |
440 | if (strcmp (alpha_fptm_string, "n") == 0) | |
441 | alpha_fptm = ALPHA_FPTM_N; | |
442 | else if (strcmp (alpha_fptm_string, "u") == 0) | |
443 | alpha_fptm = ALPHA_FPTM_U; | |
444 | else if (strcmp (alpha_fptm_string, "su") == 0) | |
445 | alpha_fptm = ALPHA_FPTM_SU; | |
446 | else if (strcmp (alpha_fptm_string, "sui") == 0) | |
447 | alpha_fptm = ALPHA_FPTM_SUI; | |
448 | else | |
1e5fcbe2 | 449 | error ("bad value %qs for -mfp-trap-mode switch", alpha_fptm_string); |
264f7d8c | 450 | } |
c4622276 | 451 | |
cbd8ec27 | 452 | if (alpha_cpu_string) |
453 | { | |
afba4ec8 | 454 | for (i = 0; i < ct_size; i++) |
27de1488 | 455 | if (! strcmp (alpha_cpu_string, cpu_table [i].name)) |
456 | { | |
56317318 | 457 | alpha_tune = alpha_cpu = cpu_table[i].processor; |
458 | line_size = cpu_table[i].line_size; | |
459 | l1_size = cpu_table[i].l1_size; | |
460 | l2_size = cpu_table[i].l2_size; | |
fb64edde | 461 | target_flags &= ~ (MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX); |
56317318 | 462 | target_flags |= cpu_table[i].flags; |
27de1488 | 463 | break; |
464 | } | |
afba4ec8 | 465 | if (i == ct_size) |
1e5fcbe2 | 466 | error ("bad value %qs for -mcpu switch", alpha_cpu_string); |
cbd8ec27 | 467 | } |
468 | ||
27de1488 | 469 | if (alpha_tune_string) |
470 | { | |
afba4ec8 | 471 | for (i = 0; i < ct_size; i++) |
27de1488 | 472 | if (! strcmp (alpha_tune_string, cpu_table [i].name)) |
473 | { | |
56317318 | 474 | alpha_tune = cpu_table[i].processor; |
475 | line_size = cpu_table[i].line_size; | |
476 | l1_size = cpu_table[i].l1_size; | |
477 | l2_size = cpu_table[i].l2_size; | |
27de1488 | 478 | break; |
479 | } | |
afba4ec8 | 480 | if (i == ct_size) |
89b3c92a | 481 | error ("bad value %qs for -mtune switch", alpha_tune_string); |
27de1488 | 482 | } |
483 | ||
56317318 | 484 | if (line_size) |
485 | maybe_set_param_value (PARAM_L1_CACHE_LINE_SIZE, line_size, | |
486 | global_options.x_param_values, | |
487 | global_options_set.x_param_values); | |
488 | if (l1_size) | |
489 | maybe_set_param_value (PARAM_L1_CACHE_SIZE, l1_size, | |
490 | global_options.x_param_values, | |
491 | global_options_set.x_param_values); | |
492 | if (l2_size) | |
493 | maybe_set_param_value (PARAM_L2_CACHE_SIZE, l2_size, | |
494 | global_options.x_param_values, | |
495 | global_options_set.x_param_values); | |
496 | ||
65abff06 | 497 | /* Do some sanity checks on the above options. */ |
c4622276 | 498 | |
264f7d8c | 499 | if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI) |
fb64edde | 500 | && alpha_tp != ALPHA_TP_INSN && alpha_cpu != PROCESSOR_EV6) |
c4622276 | 501 | { |
c3ceba8e | 502 | warning (0, "fp software completion requires -mtrap-precision=i"); |
c4622276 | 503 | alpha_tp = ALPHA_TP_INSN; |
504 | } | |
8df4a58b | 505 | |
fb64edde | 506 | if (alpha_cpu == PROCESSOR_EV6) |
bc16f0c1 | 507 | { |
508 | /* Except for EV6 pass 1 (not released), we always have precise | |
509 | arithmetic traps. Which means we can do software completion | |
510 | without minding trap shadows. */ | |
511 | alpha_tp = ALPHA_TP_PROG; | |
512 | } | |
513 | ||
8df4a58b | 514 | if (TARGET_FLOAT_VAX) |
515 | { | |
516 | if (alpha_fprm == ALPHA_FPRM_MINF || alpha_fprm == ALPHA_FPRM_DYN) | |
517 | { | |
c3ceba8e | 518 | warning (0, "rounding mode not supported for VAX floats"); |
8df4a58b | 519 | alpha_fprm = ALPHA_FPRM_NORM; |
520 | } | |
521 | if (alpha_fptm == ALPHA_FPTM_SUI) | |
522 | { | |
c3ceba8e | 523 | warning (0, "trap mode not supported for VAX floats"); |
8df4a58b | 524 | alpha_fptm = ALPHA_FPTM_SU; |
525 | } | |
ef76af46 | 526 | if (target_flags_explicit & MASK_LONG_DOUBLE_128) |
c3ceba8e | 527 | warning (0, "128-bit long double not supported for VAX floats"); |
ef76af46 | 528 | target_flags &= ~MASK_LONG_DOUBLE_128; |
8df4a58b | 529 | } |
07c1a295 | 530 | |
531 | { | |
532 | char *end; | |
533 | int lat; | |
534 | ||
535 | if (!alpha_mlat_string) | |
536 | alpha_mlat_string = "L1"; | |
537 | ||
14184418 | 538 | if (ISDIGIT ((unsigned char)alpha_mlat_string[0]) |
07c1a295 | 539 | && (lat = strtol (alpha_mlat_string, &end, 10), *end == '\0')) |
540 | ; | |
541 | else if ((alpha_mlat_string[0] == 'L' || alpha_mlat_string[0] == 'l') | |
14184418 | 542 | && ISDIGIT ((unsigned char)alpha_mlat_string[1]) |
07c1a295 | 543 | && alpha_mlat_string[2] == '\0') |
544 | { | |
9e7454d0 | 545 | static int const cache_latency[][4] = |
07c1a295 | 546 | { |
547 | { 3, 30, -1 }, /* ev4 -- Bcache is a guess */ | |
548 | { 2, 12, 38 }, /* ev5 -- Bcache from PC164 LMbench numbers */ | |
65abff06 | 549 | { 3, 12, 30 }, /* ev6 -- Bcache from DS20 LMbench. */ |
07c1a295 | 550 | }; |
551 | ||
552 | lat = alpha_mlat_string[1] - '0'; | |
fb64edde | 553 | if (lat <= 0 || lat > 3 || cache_latency[alpha_tune][lat-1] == -1) |
07c1a295 | 554 | { |
c3ceba8e | 555 | warning (0, "L%d cache latency unknown for %s", |
fb64edde | 556 | lat, alpha_cpu_name[alpha_tune]); |
07c1a295 | 557 | lat = 3; |
558 | } | |
559 | else | |
fb64edde | 560 | lat = cache_latency[alpha_tune][lat-1]; |
07c1a295 | 561 | } |
562 | else if (! strcmp (alpha_mlat_string, "main")) | |
563 | { | |
564 | /* Most current memories have about 370ns latency. This is | |
565 | a reasonable guess for a fast cpu. */ | |
566 | lat = 150; | |
567 | } | |
568 | else | |
569 | { | |
c3ceba8e | 570 | warning (0, "bad value %qs for -mmemory-latency", alpha_mlat_string); |
07c1a295 | 571 | lat = 3; |
572 | } | |
573 | ||
574 | alpha_memory_latency = lat; | |
575 | } | |
a9fa9190 | 576 | |
577 | /* Default the definition of "small data" to 8 bytes. */ | |
13a54dd9 | 578 | if (!global_options_set.x_g_switch_value) |
a9fa9190 | 579 | g_switch_value = 8; |
849674a3 | 580 | |
5dcb037d | 581 | /* Infer TARGET_SMALL_DATA from -fpic/-fPIC. */ |
582 | if (flag_pic == 1) | |
583 | target_flags |= MASK_SMALL_DATA; | |
584 | else if (flag_pic == 2) | |
585 | target_flags &= ~MASK_SMALL_DATA; | |
586 | ||
3032a4ea | 587 | alpha_override_options_after_change (); |
0ea5169b | 588 | |
9caef960 | 589 | /* Register variables and functions with the garbage collector. */ |
590 | ||
9caef960 | 591 | /* Set up function hooks. */ |
592 | init_machine_status = alpha_init_machine_status; | |
1268285a | 593 | |
594 | /* Tell the compiler when we're using VAX floating point. */ | |
595 | if (TARGET_FLOAT_VAX) | |
596 | { | |
0021bea9 | 597 | REAL_MODE_FORMAT (SFmode) = &vax_f_format; |
598 | REAL_MODE_FORMAT (DFmode) = &vax_g_format; | |
599 | REAL_MODE_FORMAT (TFmode) = NULL; | |
1268285a | 600 | } |
2dde0cc6 | 601 | |
602 | #ifdef TARGET_DEFAULT_LONG_DOUBLE_128 | |
603 | if (!(target_flags_explicit & MASK_LONG_DOUBLE_128)) | |
604 | target_flags |= MASK_LONG_DOUBLE_128; | |
605 | #endif | |
b80c91bc | 606 | |
c4622276 | 607 | } |
3032a4ea | 608 | |
609 | /* Implement targetm.override_options_after_change. */ | |
610 | ||
611 | static void | |
612 | alpha_override_options_after_change (void) | |
613 | { | |
614 | /* Align labels and loops for optimal branching. */ | |
615 | /* ??? Kludge these by not doing anything if we don't optimize. */ | |
616 | if (optimize > 0) | |
617 | { | |
6848a0ae | 618 | if (flag_align_loops && !str_align_loops) |
619 | str_align_loops = "16"; | |
620 | if (flag_align_jumps && !str_align_jumps) | |
621 | str_align_jumps = "16"; | |
3032a4ea | 622 | } |
6848a0ae | 623 | if (flag_align_functions && !str_align_functions) |
624 | str_align_functions = "16"; | |
3032a4ea | 625 | } |
c4622276 | 626 | \f |
bf2a98b3 | 627 | /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */ |
628 | ||
629 | int | |
92643d95 | 630 | zap_mask (HOST_WIDE_INT value) |
bf2a98b3 | 631 | { |
632 | int i; | |
633 | ||
634 | for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; | |
635 | i++, value >>= 8) | |
636 | if ((value & 0xff) != 0 && (value & 0xff) != 0xff) | |
637 | return 0; | |
638 | ||
639 | return 1; | |
640 | } | |
641 | ||
9e7454d0 | 642 | /* Return true if OP is valid for a particular TLS relocation. |
41421c64 | 643 | We are already guaranteed that OP is a CONST. */ |
bf2a98b3 | 644 | |
645 | int | |
41421c64 | 646 | tls_symbolic_operand_1 (rtx op, int size, int unspec) |
bf2a98b3 | 647 | { |
5f7b9df8 | 648 | op = XEXP (op, 0); |
649 | ||
650 | if (GET_CODE (op) != UNSPEC || XINT (op, 1) != unspec) | |
651 | return 0; | |
652 | op = XVECEXP (op, 0, 0); | |
653 | ||
654 | if (GET_CODE (op) != SYMBOL_REF) | |
655 | return 0; | |
5f7b9df8 | 656 | |
09a1f342 | 657 | switch (SYMBOL_REF_TLS_MODEL (op)) |
9bdcc1e5 | 658 | { |
09a1f342 | 659 | case TLS_MODEL_LOCAL_DYNAMIC: |
ea284d73 | 660 | return unspec == UNSPEC_DTPREL && size == alpha_tls_size; |
09a1f342 | 661 | case TLS_MODEL_INITIAL_EXEC: |
9bdcc1e5 | 662 | return unspec == UNSPEC_TPREL && size == 64; |
09a1f342 | 663 | case TLS_MODEL_LOCAL_EXEC: |
ea284d73 | 664 | return unspec == UNSPEC_TPREL && size == alpha_tls_size; |
9bdcc1e5 | 665 | default: |
4d10b463 | 666 | gcc_unreachable (); |
9bdcc1e5 | 667 | } |
5f7b9df8 | 668 | } |
669 | ||
41421c64 | 670 | /* Used by aligned_memory_operand and unaligned_memory_operand to |
671 | resolve what reload is going to do with OP if it's a register. */ | |
bbf31a61 | 672 | |
41421c64 | 673 | rtx |
674 | resolve_reload_operand (rtx op) | |
bf2a98b3 | 675 | { |
cc215844 | 676 | if (reload_in_progress) |
bf2a98b3 | 677 | { |
cc215844 | 678 | rtx tmp = op; |
6b213686 | 679 | if (SUBREG_P (tmp)) |
cc215844 | 680 | tmp = SUBREG_REG (tmp); |
c933fb42 | 681 | if (REG_P (tmp) |
cc215844 | 682 | && REGNO (tmp) >= FIRST_PSEUDO_REGISTER) |
683 | { | |
1c654ff1 | 684 | op = reg_equiv_memory_loc (REGNO (tmp)); |
cc215844 | 685 | if (op == 0) |
686 | return 0; | |
687 | } | |
bf2a98b3 | 688 | } |
41421c64 | 689 | return op; |
14f7bc98 | 690 | } |
691 | ||
b2aef146 | 692 | /* The scalar modes supported differs from the default check-what-c-supports |
693 | version in that sometimes TFmode is available even when long double | |
04d75965 | 694 | indicates only DFmode. */ |
b2aef146 | 695 | |
696 | static bool | |
8aec1ebb | 697 | alpha_scalar_mode_supported_p (scalar_mode mode) |
b2aef146 | 698 | { |
699 | switch (mode) | |
700 | { | |
916ace94 | 701 | case E_QImode: |
702 | case E_HImode: | |
703 | case E_SImode: | |
704 | case E_DImode: | |
705 | case E_TImode: /* via optabs.c */ | |
b2aef146 | 706 | return true; |
707 | ||
916ace94 | 708 | case E_SFmode: |
709 | case E_DFmode: | |
b2aef146 | 710 | return true; |
711 | ||
916ace94 | 712 | case E_TFmode: |
b2aef146 | 713 | return TARGET_HAS_XFLOATING_LIBS; |
714 | ||
715 | default: | |
716 | return false; | |
717 | } | |
718 | } | |
719 | ||
720 | /* Alpha implements a couple of integer vector mode operations when | |
b739144f | 721 | TARGET_MAX is enabled. We do not check TARGET_MAX here, however, |
722 | which allows the vectorizer to operate on e.g. move instructions, | |
723 | or when expand_vector_operations can do something useful. */ | |
b2aef146 | 724 | |
9e7454d0 | 725 | static bool |
3754d046 | 726 | alpha_vector_mode_supported_p (machine_mode mode) |
9e7454d0 | 727 | { |
b739144f | 728 | return mode == V8QImode || mode == V4HImode || mode == V2SImode; |
9e7454d0 | 729 | } |
730 | ||
550e415f | 731 | /* Return 1 if this function can directly return via $26. */ |
732 | ||
733 | int | |
92643d95 | 734 | direct_return (void) |
550e415f | 735 | { |
4505d022 | 736 | return (TARGET_ABI_OSF |
1467e953 | 737 | && reload_completed |
738 | && alpha_sa_size () == 0 | |
550e415f | 739 | && get_frame_size () == 0 |
abe32cce | 740 | && crtl->outgoing_args_size == 0 |
741 | && crtl->args.pretend_args_size == 0); | |
550e415f | 742 | } |
ecb98d40 | 743 | |
5f7b9df8 | 744 | /* Return the TLS model to use for SYMBOL. */ |
745 | ||
746 | static enum tls_model | |
92643d95 | 747 | tls_symbolic_operand_type (rtx symbol) |
5f7b9df8 | 748 | { |
09a1f342 | 749 | enum tls_model model; |
5f7b9df8 | 750 | |
751 | if (GET_CODE (symbol) != SYMBOL_REF) | |
afba4ec8 | 752 | return TLS_MODEL_NONE; |
09a1f342 | 753 | model = SYMBOL_REF_TLS_MODEL (symbol); |
5f7b9df8 | 754 | |
09a1f342 | 755 | /* Local-exec with a 64-bit size is the same code as initial-exec. */ |
756 | if (model == TLS_MODEL_LOCAL_EXEC && alpha_tls_size == 64) | |
757 | model = TLS_MODEL_INITIAL_EXEC; | |
5f7b9df8 | 758 | |
09a1f342 | 759 | return model; |
5f7b9df8 | 760 | } |
14f7bc98 | 761 | \f |
9bdcc1e5 | 762 | /* Return true if the function DECL will share the same GP as any |
763 | function in the current unit of translation. */ | |
764 | ||
765 | static bool | |
a9f1838b | 766 | decl_has_samegp (const_tree decl) |
9bdcc1e5 | 767 | { |
768 | /* Functions that are not local can be overridden, and thus may | |
769 | not share the same gp. */ | |
770 | if (!(*targetm.binds_local_p) (decl)) | |
771 | return false; | |
772 | ||
773 | /* If -msmall-data is in effect, assume that there is only one GP | |
774 | for the module, and so any local symbol has this property. We | |
775 | need explicit relocations to be able to enforce this for symbols | |
776 | not defined in this unit of translation, however. */ | |
777 | if (TARGET_EXPLICIT_RELOCS && TARGET_SMALL_DATA) | |
778 | return true; | |
779 | ||
780 | /* Functions that are not external are defined in this UoT. */ | |
cf1d67e3 | 781 | /* ??? Irritatingly, static functions not yet emitted are still |
782 | marked "external". Apply this to non-static functions only. */ | |
783 | return !TREE_PUBLIC (decl) || !DECL_EXTERNAL (decl); | |
9bdcc1e5 | 784 | } |
785 | ||
52470889 | 786 | /* Return true if EXP should be placed in the small data section. */ |
787 | ||
788 | static bool | |
a9f1838b | 789 | alpha_in_small_data_p (const_tree exp) |
52470889 | 790 | { |
0aad4cd2 | 791 | /* We want to merge strings, so we never consider them small data. */ |
792 | if (TREE_CODE (exp) == STRING_CST) | |
793 | return false; | |
794 | ||
6ac09a46 | 795 | /* Functions are never in the small data area. Duh. */ |
796 | if (TREE_CODE (exp) == FUNCTION_DECL) | |
797 | return false; | |
798 | ||
6ca5d410 | 799 | /* COMMON symbols are never small data. */ |
800 | if (TREE_CODE (exp) == VAR_DECL && DECL_COMMON (exp)) | |
801 | return false; | |
802 | ||
52470889 | 803 | if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) |
804 | { | |
738a6bda | 805 | const char *section = DECL_SECTION_NAME (exp); |
52470889 | 806 | if (strcmp (section, ".sdata") == 0 |
807 | || strcmp (section, ".sbss") == 0) | |
808 | return true; | |
809 | } | |
810 | else | |
811 | { | |
812 | HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); | |
813 | ||
814 | /* If this is an incomplete type with size 0, then we can't put it | |
815 | in sdata because it might be too big when completed. */ | |
13a54dd9 | 816 | if (size > 0 && size <= g_switch_value) |
52470889 | 817 | return true; |
818 | } | |
819 | ||
820 | return false; | |
821 | } | |
822 | ||
cf73d31f | 823 | #if TARGET_ABI_OPEN_VMS |
656ad977 | 824 | static bool |
f77c4496 | 825 | vms_valid_pointer_mode (scalar_int_mode mode) |
656ad977 | 826 | { |
827 | return (mode == SImode || mode == DImode); | |
828 | } | |
829 | ||
cf73d31f | 830 | static bool |
92643d95 | 831 | alpha_linkage_symbol_p (const char *symname) |
cf73d31f | 832 | { |
833 | int symlen = strlen (symname); | |
834 | ||
835 | if (symlen > 4) | |
836 | return strcmp (&symname [symlen - 4], "..lk") == 0; | |
837 | ||
838 | return false; | |
839 | } | |
840 | ||
841 | #define LINKAGE_SYMBOL_REF_P(X) \ | |
842 | ((GET_CODE (X) == SYMBOL_REF \ | |
843 | && alpha_linkage_symbol_p (XSTR (X, 0))) \ | |
844 | || (GET_CODE (X) == CONST \ | |
845 | && GET_CODE (XEXP (X, 0)) == PLUS \ | |
846 | && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF \ | |
847 | && alpha_linkage_symbol_p (XSTR (XEXP (XEXP (X, 0), 0), 0)))) | |
848 | #endif | |
849 | ||
24b3c0ed | 850 | /* legitimate_address_p recognizes an RTL expression that is a valid |
851 | memory address for an instruction. The MODE argument is the | |
852 | machine mode for the MEM expression that wants to use this address. | |
853 | ||
854 | For Alpha, we have either a constant address or the sum of a | |
855 | register and a constant address, or just a register. For DImode, | |
856 | any of those forms can be surrounded with an AND that clear the | |
857 | low-order three bits; this is an "unaligned" access. */ | |
858 | ||
fd50b071 | 859 | static bool |
3754d046 | 860 | alpha_legitimate_address_p (machine_mode mode, rtx x, bool strict) |
24b3c0ed | 861 | { |
862 | /* If this is an ldq_u type address, discard the outer AND. */ | |
863 | if (mode == DImode | |
864 | && GET_CODE (x) == AND | |
c933fb42 | 865 | && CONST_INT_P (XEXP (x, 1)) |
24b3c0ed | 866 | && INTVAL (XEXP (x, 1)) == -8) |
867 | x = XEXP (x, 0); | |
868 | ||
869 | /* Discard non-paradoxical subregs. */ | |
6b213686 | 870 | if (SUBREG_P (x) |
24b3c0ed | 871 | && (GET_MODE_SIZE (GET_MODE (x)) |
872 | < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) | |
873 | x = SUBREG_REG (x); | |
874 | ||
875 | /* Unadorned general registers are valid. */ | |
876 | if (REG_P (x) | |
877 | && (strict | |
878 | ? STRICT_REG_OK_FOR_BASE_P (x) | |
879 | : NONSTRICT_REG_OK_FOR_BASE_P (x))) | |
880 | return true; | |
881 | ||
882 | /* Constant addresses (i.e. +/- 32k) are valid. */ | |
883 | if (CONSTANT_ADDRESS_P (x)) | |
884 | return true; | |
885 | ||
cf73d31f | 886 | #if TARGET_ABI_OPEN_VMS |
887 | if (LINKAGE_SYMBOL_REF_P (x)) | |
888 | return true; | |
889 | #endif | |
890 | ||
24b3c0ed | 891 | /* Register plus a small constant offset is valid. */ |
892 | if (GET_CODE (x) == PLUS) | |
893 | { | |
894 | rtx ofs = XEXP (x, 1); | |
895 | x = XEXP (x, 0); | |
896 | ||
897 | /* Discard non-paradoxical subregs. */ | |
6b213686 | 898 | if (SUBREG_P (x) |
24b3c0ed | 899 | && (GET_MODE_SIZE (GET_MODE (x)) |
900 | < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) | |
901 | x = SUBREG_REG (x); | |
902 | ||
903 | if (REG_P (x)) | |
904 | { | |
905 | if (! strict | |
906 | && NONSTRICT_REG_OK_FP_BASE_P (x) | |
c933fb42 | 907 | && CONST_INT_P (ofs)) |
24b3c0ed | 908 | return true; |
909 | if ((strict | |
910 | ? STRICT_REG_OK_FOR_BASE_P (x) | |
911 | : NONSTRICT_REG_OK_FOR_BASE_P (x)) | |
912 | && CONSTANT_ADDRESS_P (ofs)) | |
913 | return true; | |
914 | } | |
24b3c0ed | 915 | } |
916 | ||
d6c48eee | 917 | /* If we're managing explicit relocations, LO_SUM is valid, as are small |
918 | data symbols. Avoid explicit relocations of modes larger than word | |
919 | mode since i.e. $LC0+8($1) can fold around +/- 32k offset. */ | |
920 | else if (TARGET_EXPLICIT_RELOCS | |
921 | && GET_MODE_SIZE (mode) <= UNITS_PER_WORD) | |
1f0ce6a6 | 922 | { |
f5a60074 | 923 | if (small_symbolic_operand (x, Pmode)) |
1f0ce6a6 | 924 | return true; |
f5a60074 | 925 | |
926 | if (GET_CODE (x) == LO_SUM) | |
927 | { | |
928 | rtx ofs = XEXP (x, 1); | |
929 | x = XEXP (x, 0); | |
930 | ||
931 | /* Discard non-paradoxical subregs. */ | |
6b213686 | 932 | if (SUBREG_P (x) |
f5a60074 | 933 | && (GET_MODE_SIZE (GET_MODE (x)) |
934 | < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) | |
935 | x = SUBREG_REG (x); | |
936 | ||
937 | /* Must have a valid base register. */ | |
938 | if (! (REG_P (x) | |
939 | && (strict | |
940 | ? STRICT_REG_OK_FOR_BASE_P (x) | |
941 | : NONSTRICT_REG_OK_FOR_BASE_P (x)))) | |
942 | return false; | |
943 | ||
944 | /* The symbol must be local. */ | |
5f7b9df8 | 945 | if (local_symbolic_operand (ofs, Pmode) |
946 | || dtp32_symbolic_operand (ofs, Pmode) | |
947 | || tp32_symbolic_operand (ofs, Pmode)) | |
f5a60074 | 948 | return true; |
949 | } | |
1f0ce6a6 | 950 | } |
951 | ||
24b3c0ed | 952 | return false; |
953 | } | |
954 | ||
09a1f342 | 955 | /* Build the SYMBOL_REF for __tls_get_addr. */ |
956 | ||
957 | static GTY(()) rtx tls_get_addr_libfunc; | |
958 | ||
959 | static rtx | |
92643d95 | 960 | get_tls_get_addr (void) |
09a1f342 | 961 | { |
962 | if (!tls_get_addr_libfunc) | |
963 | tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr"); | |
964 | return tls_get_addr_libfunc; | |
965 | } | |
966 | ||
0d50f0b7 | 967 | /* Try machine-dependent ways of modifying an illegitimate address |
968 | to be legitimate. If we find one, return the new, valid address. */ | |
969 | ||
41e3a0c7 | 970 | static rtx |
3754d046 | 971 | alpha_legitimize_address_1 (rtx x, rtx scratch, machine_mode mode) |
0d50f0b7 | 972 | { |
973 | HOST_WIDE_INT addend; | |
974 | ||
975 | /* If the address is (plus reg const_int) and the CONST_INT is not a | |
976 | valid offset, compute the high part of the constant and add it to | |
977 | the register. Then our address is (plus temp low-part-const). */ | |
978 | if (GET_CODE (x) == PLUS | |
c933fb42 | 979 | && REG_P (XEXP (x, 0)) |
980 | && CONST_INT_P (XEXP (x, 1)) | |
0d50f0b7 | 981 | && ! CONSTANT_ADDRESS_P (XEXP (x, 1))) |
982 | { | |
983 | addend = INTVAL (XEXP (x, 1)); | |
984 | x = XEXP (x, 0); | |
985 | goto split_addend; | |
986 | } | |
987 | ||
988 | /* If the address is (const (plus FOO const_int)), find the low-order | |
989 | part of the CONST_INT. Then load FOO plus any high-order part of the | |
990 | CONST_INT into a register. Our address is (plus reg low-part-const). | |
991 | This is done to reduce the number of GOT entries. */ | |
e1ba4a27 | 992 | if (can_create_pseudo_p () |
f5a60074 | 993 | && GET_CODE (x) == CONST |
0d50f0b7 | 994 | && GET_CODE (XEXP (x, 0)) == PLUS |
c933fb42 | 995 | && CONST_INT_P (XEXP (XEXP (x, 0), 1))) |
0d50f0b7 | 996 | { |
997 | addend = INTVAL (XEXP (XEXP (x, 0), 1)); | |
998 | x = force_reg (Pmode, XEXP (XEXP (x, 0), 0)); | |
999 | goto split_addend; | |
1000 | } | |
1001 | ||
1002 | /* If we have a (plus reg const), emit the load as in (2), then add | |
1003 | the two registers, and finally generate (plus reg low-part-const) as | |
1004 | our address. */ | |
e1ba4a27 | 1005 | if (can_create_pseudo_p () |
f5a60074 | 1006 | && GET_CODE (x) == PLUS |
c933fb42 | 1007 | && REG_P (XEXP (x, 0)) |
0d50f0b7 | 1008 | && GET_CODE (XEXP (x, 1)) == CONST |
1009 | && GET_CODE (XEXP (XEXP (x, 1), 0)) == PLUS | |
c933fb42 | 1010 | && CONST_INT_P (XEXP (XEXP (XEXP (x, 1), 0), 1))) |
0d50f0b7 | 1011 | { |
1012 | addend = INTVAL (XEXP (XEXP (XEXP (x, 1), 0), 1)); | |
1013 | x = expand_simple_binop (Pmode, PLUS, XEXP (x, 0), | |
1014 | XEXP (XEXP (XEXP (x, 1), 0), 0), | |
1015 | NULL_RTX, 1, OPTAB_LIB_WIDEN); | |
1016 | goto split_addend; | |
1017 | } | |
1018 | ||
d6c48eee | 1019 | /* If this is a local symbol, split the address into HIGH/LO_SUM parts. |
1020 | Avoid modes larger than word mode since i.e. $LC0+8($1) can fold | |
1021 | around +/- 32k offset. */ | |
1022 | if (TARGET_EXPLICIT_RELOCS | |
1023 | && GET_MODE_SIZE (mode) <= UNITS_PER_WORD | |
1024 | && symbolic_operand (x, Pmode)) | |
1f0ce6a6 | 1025 | { |
8793a4a1 | 1026 | rtx r0, r16, eqv, tga, tp, dest, seq; |
1027 | rtx_insn *insn; | |
5f7b9df8 | 1028 | |
1029 | switch (tls_symbolic_operand_type (x)) | |
1030 | { | |
dda53cd5 | 1031 | case TLS_MODEL_NONE: |
1032 | break; | |
1033 | ||
5f7b9df8 | 1034 | case TLS_MODEL_GLOBAL_DYNAMIC: |
8793a4a1 | 1035 | { |
1036 | start_sequence (); | |
5f7b9df8 | 1037 | |
8793a4a1 | 1038 | r0 = gen_rtx_REG (Pmode, 0); |
1039 | r16 = gen_rtx_REG (Pmode, 16); | |
1040 | tga = get_tls_get_addr (); | |
1041 | dest = gen_reg_rtx (Pmode); | |
1042 | seq = GEN_INT (alpha_next_sequence_number++); | |
9e7454d0 | 1043 | |
8793a4a1 | 1044 | emit_insn (gen_movdi_er_tlsgd (r16, pic_offset_table_rtx, x, seq)); |
1045 | rtx val = gen_call_value_osf_tlsgd (r0, tga, seq); | |
1046 | insn = emit_call_insn (val); | |
1047 | RTL_CONST_CALL_P (insn) = 1; | |
1048 | use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16); | |
5f7b9df8 | 1049 | |
8793a4a1 | 1050 | insn = get_insns (); |
1051 | end_sequence (); | |
5f7b9df8 | 1052 | |
8793a4a1 | 1053 | emit_libcall_block (insn, dest, r0, x); |
1054 | return dest; | |
1055 | } | |
5f7b9df8 | 1056 | |
1057 | case TLS_MODEL_LOCAL_DYNAMIC: | |
8793a4a1 | 1058 | { |
1059 | start_sequence (); | |
5f7b9df8 | 1060 | |
8793a4a1 | 1061 | r0 = gen_rtx_REG (Pmode, 0); |
1062 | r16 = gen_rtx_REG (Pmode, 16); | |
1063 | tga = get_tls_get_addr (); | |
1064 | scratch = gen_reg_rtx (Pmode); | |
1065 | seq = GEN_INT (alpha_next_sequence_number++); | |
5f7b9df8 | 1066 | |
8793a4a1 | 1067 | emit_insn (gen_movdi_er_tlsldm (r16, pic_offset_table_rtx, seq)); |
1068 | rtx val = gen_call_value_osf_tlsldm (r0, tga, seq); | |
1069 | insn = emit_call_insn (val); | |
1070 | RTL_CONST_CALL_P (insn) = 1; | |
1071 | use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16); | |
5f7b9df8 | 1072 | |
8793a4a1 | 1073 | insn = get_insns (); |
1074 | end_sequence (); | |
5f7b9df8 | 1075 | |
8793a4a1 | 1076 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), |
1077 | UNSPEC_TLSLDM_CALL); | |
1078 | emit_libcall_block (insn, scratch, r0, eqv); | |
5f7b9df8 | 1079 | |
8793a4a1 | 1080 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPREL); |
1081 | eqv = gen_rtx_CONST (Pmode, eqv); | |
5f7b9df8 | 1082 | |
8793a4a1 | 1083 | if (alpha_tls_size == 64) |
1084 | { | |
1085 | dest = gen_reg_rtx (Pmode); | |
1086 | emit_insn (gen_rtx_SET (dest, eqv)); | |
1087 | emit_insn (gen_adddi3 (dest, dest, scratch)); | |
1088 | return dest; | |
1089 | } | |
1090 | if (alpha_tls_size == 32) | |
1091 | { | |
1092 | rtx temp = gen_rtx_HIGH (Pmode, eqv); | |
1093 | temp = gen_rtx_PLUS (Pmode, scratch, temp); | |
1094 | scratch = gen_reg_rtx (Pmode); | |
1095 | emit_insn (gen_rtx_SET (scratch, temp)); | |
1096 | } | |
1097 | return gen_rtx_LO_SUM (Pmode, scratch, eqv); | |
1098 | } | |
5f7b9df8 | 1099 | |
1100 | case TLS_MODEL_INITIAL_EXEC: | |
1101 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL); | |
1102 | eqv = gen_rtx_CONST (Pmode, eqv); | |
1103 | tp = gen_reg_rtx (Pmode); | |
1104 | scratch = gen_reg_rtx (Pmode); | |
1105 | dest = gen_reg_rtx (Pmode); | |
1106 | ||
badaa04c | 1107 | emit_insn (gen_get_thread_pointerdi (tp)); |
d1f9b275 | 1108 | emit_insn (gen_rtx_SET (scratch, eqv)); |
5f7b9df8 | 1109 | emit_insn (gen_adddi3 (dest, tp, scratch)); |
1110 | return dest; | |
1111 | ||
1112 | case TLS_MODEL_LOCAL_EXEC: | |
1113 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL); | |
1114 | eqv = gen_rtx_CONST (Pmode, eqv); | |
1115 | tp = gen_reg_rtx (Pmode); | |
1116 | ||
badaa04c | 1117 | emit_insn (gen_get_thread_pointerdi (tp)); |
5f7b9df8 | 1118 | if (alpha_tls_size == 32) |
1119 | { | |
8793a4a1 | 1120 | rtx temp = gen_rtx_HIGH (Pmode, eqv); |
1121 | temp = gen_rtx_PLUS (Pmode, tp, temp); | |
5f7b9df8 | 1122 | tp = gen_reg_rtx (Pmode); |
8793a4a1 | 1123 | emit_insn (gen_rtx_SET (tp, temp)); |
5f7b9df8 | 1124 | } |
1125 | return gen_rtx_LO_SUM (Pmode, tp, eqv); | |
dda53cd5 | 1126 | |
1127 | default: | |
1128 | gcc_unreachable (); | |
5f7b9df8 | 1129 | } |
1130 | ||
8afb6db4 | 1131 | if (local_symbolic_operand (x, Pmode)) |
1132 | { | |
1133 | if (small_symbolic_operand (x, Pmode)) | |
f5a60074 | 1134 | return x; |
8afb6db4 | 1135 | else |
1136 | { | |
e1ba4a27 | 1137 | if (can_create_pseudo_p ()) |
f5a60074 | 1138 | scratch = gen_reg_rtx (Pmode); |
d1f9b275 | 1139 | emit_insn (gen_rtx_SET (scratch, gen_rtx_HIGH (Pmode, x))); |
f5a60074 | 1140 | return gen_rtx_LO_SUM (Pmode, scratch, x); |
8afb6db4 | 1141 | } |
5dcb037d | 1142 | } |
1f0ce6a6 | 1143 | } |
1144 | ||
0d50f0b7 | 1145 | return NULL; |
1146 | ||
1147 | split_addend: | |
1148 | { | |
f5a60074 | 1149 | HOST_WIDE_INT low, high; |
1150 | ||
1151 | low = ((addend & 0xffff) ^ 0x8000) - 0x8000; | |
1152 | addend -= low; | |
1153 | high = ((addend & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
1154 | addend -= high; | |
1155 | ||
1156 | if (addend) | |
1157 | x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (addend), | |
e1ba4a27 | 1158 | (!can_create_pseudo_p () ? scratch : NULL_RTX), |
f5a60074 | 1159 | 1, OPTAB_LIB_WIDEN); |
1160 | if (high) | |
1161 | x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (high), | |
e1ba4a27 | 1162 | (!can_create_pseudo_p () ? scratch : NULL_RTX), |
f5a60074 | 1163 | 1, OPTAB_LIB_WIDEN); |
1164 | ||
29c05e22 | 1165 | return plus_constant (Pmode, x, low); |
0d50f0b7 | 1166 | } |
1167 | } | |
1168 | ||
41e3a0c7 | 1169 | |
1170 | /* Try machine-dependent ways of modifying an illegitimate address | |
1171 | to be legitimate. Return X or the new, valid address. */ | |
1172 | ||
1173 | static rtx | |
1174 | alpha_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, | |
3754d046 | 1175 | machine_mode mode) |
41e3a0c7 | 1176 | { |
1177 | rtx new_x = alpha_legitimize_address_1 (x, NULL_RTX, mode); | |
1178 | return new_x ? new_x : x; | |
1179 | } | |
1180 | ||
649bdf00 | 1181 | /* Return true if ADDR has an effect that depends on the machine mode it |
1182 | is used for. On the Alpha this is true only for the unaligned modes. | |
1183 | We can simplify the test since we know that the address must be valid. */ | |
1184 | ||
1185 | static bool | |
4e27ffd0 | 1186 | alpha_mode_dependent_address_p (const_rtx addr, |
1187 | addr_space_t as ATTRIBUTE_UNUSED) | |
649bdf00 | 1188 | { |
1189 | return GET_CODE (addr) == AND; | |
1190 | } | |
1191 | ||
c0da4391 | 1192 | /* Primarily this is required for TLS symbols, but given that our move |
1193 | patterns *ought* to be able to handle any symbol at any time, we | |
1194 | should never be spilling symbolic operands to the constant pool, ever. */ | |
1195 | ||
1196 | static bool | |
3754d046 | 1197 | alpha_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) |
c0da4391 | 1198 | { |
1199 | enum rtx_code code = GET_CODE (x); | |
1200 | return code == SYMBOL_REF || code == LABEL_REF || code == CONST; | |
1201 | } | |
1202 | ||
805e22b2 | 1203 | /* We do not allow indirect calls to be optimized into sibling calls, nor |
9bdcc1e5 | 1204 | can we allow a call to a function with a different GP to be optimized |
1205 | into a sibcall. */ | |
1206 | ||
805e22b2 | 1207 | static bool |
92643d95 | 1208 | alpha_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) |
805e22b2 | 1209 | { |
9bdcc1e5 | 1210 | /* Can't do indirect tail calls, since we don't know if the target |
1211 | uses the same GP. */ | |
1212 | if (!decl) | |
1213 | return false; | |
1214 | ||
1215 | /* Otherwise, we can make a tail call if the target function shares | |
1216 | the same GP. */ | |
1217 | return decl_has_samegp (decl); | |
805e22b2 | 1218 | } |
1219 | ||
c0fe2f4a | 1220 | bool |
1221 | some_small_symbolic_operand_int (rtx x) | |
367e2ab3 | 1222 | { |
c0fe2f4a | 1223 | subrtx_var_iterator::array_type array; |
1224 | FOR_EACH_SUBRTX_VAR (iter, array, x, ALL) | |
1225 | { | |
1226 | rtx x = *iter; | |
1227 | /* Don't re-split. */ | |
1228 | if (GET_CODE (x) == LO_SUM) | |
1229 | iter.skip_subrtxes (); | |
1230 | else if (small_symbolic_operand (x, Pmode)) | |
1231 | return true; | |
1232 | } | |
1233 | return false; | |
f5a60074 | 1234 | } |
1235 | ||
92643d95 | 1236 | rtx |
1237 | split_small_symbolic_operand (rtx x) | |
1238 | { | |
1239 | x = copy_insn (x); | |
97a30fee | 1240 | subrtx_ptr_iterator::array_type array; |
1241 | FOR_EACH_SUBRTX_PTR (iter, array, &x, ALL) | |
1242 | { | |
1243 | rtx *ptr = *iter; | |
1244 | rtx x = *ptr; | |
1245 | /* Don't re-split. */ | |
1246 | if (GET_CODE (x) == LO_SUM) | |
1247 | iter.skip_subrtxes (); | |
1248 | else if (small_symbolic_operand (x, Pmode)) | |
1249 | { | |
1250 | *ptr = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, x); | |
1251 | iter.skip_subrtxes (); | |
1252 | } | |
1253 | } | |
92643d95 | 1254 | return x; |
1255 | } | |
1256 | ||
2f58af60 | 1257 | /* Indicate that INSN cannot be duplicated. This is true for any insn |
1258 | that we've marked with gpdisp relocs, since those have to stay in | |
1259 | 1-1 correspondence with one another. | |
1260 | ||
5910bb95 | 1261 | Technically we could copy them if we could set up a mapping from one |
2f58af60 | 1262 | sequence number to another, across the set of insns to be duplicated. |
1263 | This seems overly complicated and error-prone since interblock motion | |
b55f2ed8 | 1264 | from sched-ebb could move one of the pair of insns to a different block. |
1265 | ||
1266 | Also cannot allow jsr insns to be duplicated. If they throw exceptions, | |
1267 | then they'll be in a different block from their ldgp. Which could lead | |
1268 | the bb reorder code to think that it would be ok to copy just the block | |
1269 | containing the call and branch to the block containing the ldgp. */ | |
2f58af60 | 1270 | |
1271 | static bool | |
18282db0 | 1272 | alpha_cannot_copy_insn_p (rtx_insn *insn) |
2f58af60 | 1273 | { |
2f58af60 | 1274 | if (!reload_completed || !TARGET_EXPLICIT_RELOCS) |
1275 | return false; | |
b55f2ed8 | 1276 | if (recog_memoized (insn) >= 0) |
1277 | return get_attr_cannot_copy (insn); | |
1278 | else | |
2f58af60 | 1279 | return false; |
2f58af60 | 1280 | } |
1281 | ||
9e7454d0 | 1282 | |
0d50f0b7 | 1283 | /* Try a machine-dependent way of reloading an illegitimate address |
1284 | operand. If we find one, push the reload and return the new rtx. */ | |
9e7454d0 | 1285 | |
0d50f0b7 | 1286 | rtx |
92643d95 | 1287 | alpha_legitimize_reload_address (rtx x, |
3754d046 | 1288 | machine_mode mode ATTRIBUTE_UNUSED, |
92643d95 | 1289 | int opnum, int type, |
1290 | int ind_levels ATTRIBUTE_UNUSED) | |
0d50f0b7 | 1291 | { |
1292 | /* We must recognize output that we have already generated ourselves. */ | |
1293 | if (GET_CODE (x) == PLUS | |
1294 | && GET_CODE (XEXP (x, 0)) == PLUS | |
c933fb42 | 1295 | && REG_P (XEXP (XEXP (x, 0), 0)) |
1296 | && CONST_INT_P (XEXP (XEXP (x, 0), 1)) | |
1297 | && CONST_INT_P (XEXP (x, 1))) | |
0d50f0b7 | 1298 | { |
1299 | push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, | |
1300 | BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, | |
0a48089c | 1301 | opnum, (enum reload_type) type); |
0d50f0b7 | 1302 | return x; |
1303 | } | |
1304 | ||
1305 | /* We wish to handle large displacements off a base register by | |
1306 | splitting the addend across an ldah and the mem insn. This | |
1307 | cuts number of extra insns needed from 3 to 1. */ | |
1308 | if (GET_CODE (x) == PLUS | |
c933fb42 | 1309 | && REG_P (XEXP (x, 0)) |
0d50f0b7 | 1310 | && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER |
1311 | && REGNO_OK_FOR_BASE_P (REGNO (XEXP (x, 0))) | |
7bc95bfb | 1312 | && CONST_INT_P (XEXP (x, 1))) |
0d50f0b7 | 1313 | { |
1314 | HOST_WIDE_INT val = INTVAL (XEXP (x, 1)); | |
1315 | HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000; | |
1316 | HOST_WIDE_INT high | |
1317 | = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
1318 | ||
1319 | /* Check for 32-bit overflow. */ | |
1320 | if (high + low != val) | |
1321 | return NULL_RTX; | |
1322 | ||
1323 | /* Reload the high part into a base reg; leave the low part | |
1324 | in the mem directly. */ | |
1325 | x = gen_rtx_PLUS (GET_MODE (x), | |
1326 | gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0), | |
1327 | GEN_INT (high)), | |
1328 | GEN_INT (low)); | |
1329 | ||
1330 | push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, | |
1331 | BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, | |
0a48089c | 1332 | opnum, (enum reload_type) type); |
0d50f0b7 | 1333 | return x; |
1334 | } | |
1335 | ||
1336 | return NULL_RTX; | |
1337 | } | |
1338 | \f | |
8647dea5 | 1339 | /* Return the cost of moving between registers of various classes. Moving |
1340 | between FLOAT_REGS and anything else except float regs is expensive. | |
1341 | In fact, we make it quite expensive because we really don't want to | |
1342 | do these moves unless it is clearly worth it. Optimizations may | |
1343 | reduce the impact of not being able to allocate a pseudo to a | |
1344 | hard register. */ | |
1345 | ||
1346 | static int | |
1347 | alpha_register_move_cost (machine_mode /*mode*/, | |
1348 | reg_class_t from, reg_class_t to) | |
1349 | { | |
1350 | if ((from == FLOAT_REGS) == (to == FLOAT_REGS)) | |
1351 | return 2; | |
1352 | ||
1353 | if (TARGET_FIX) | |
1354 | return (from == FLOAT_REGS) ? 6 : 8; | |
1355 | ||
1356 | return 4 + 2 * alpha_memory_latency; | |
1357 | } | |
1358 | ||
1359 | /* Return the cost of moving data of MODE from a register to | |
1360 | or from memory. On the Alpha, bump this up a bit. */ | |
1361 | ||
1362 | static int | |
1363 | alpha_memory_move_cost (machine_mode /*mode*/, reg_class_t /*regclass*/, | |
1364 | bool /*in*/) | |
1365 | { | |
1366 | return 2 * alpha_memory_latency; | |
1367 | } | |
1368 | ||
fab7adbf | 1369 | /* Compute a (partial) cost for rtx X. Return true if the complete |
1370 | cost has been computed, and false if subexpressions should be | |
1371 | scanned. In either case, *TOTAL contains the cost result. */ | |
1372 | ||
1373 | static bool | |
5ae4887d | 1374 | alpha_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno, int *total, |
f529eb25 | 1375 | bool speed) |
fab7adbf | 1376 | { |
5ae4887d | 1377 | int code = GET_CODE (x); |
fab7adbf | 1378 | bool float_mode_p = FLOAT_MODE_P (mode); |
d7cf2331 | 1379 | const struct alpha_rtx_cost_data *cost_data; |
1380 | ||
f529eb25 | 1381 | if (!speed) |
d7cf2331 | 1382 | cost_data = &alpha_rtx_cost_size; |
1383 | else | |
fb64edde | 1384 | cost_data = &alpha_rtx_cost_data[alpha_tune]; |
fab7adbf | 1385 | |
1386 | switch (code) | |
1387 | { | |
d7cf2331 | 1388 | case CONST_INT: |
fab7adbf | 1389 | /* If this is an 8-bit constant, return zero since it can be used |
1390 | nearly anywhere with no cost. If it is a valid operand for an | |
1391 | ADD or AND, likewise return 0 if we know it will be used in that | |
1392 | context. Otherwise, return 2 since it might be used there later. | |
1393 | All other constants take at least two insns. */ | |
fab7adbf | 1394 | if (INTVAL (x) >= 0 && INTVAL (x) < 256) |
1395 | { | |
1396 | *total = 0; | |
1397 | return true; | |
1398 | } | |
8e262b5e | 1399 | /* FALLTHRU */ |
fab7adbf | 1400 | |
1401 | case CONST_DOUBLE: | |
5c5c1f00 | 1402 | case CONST_WIDE_INT: |
fab7adbf | 1403 | if (x == CONST0_RTX (mode)) |
1404 | *total = 0; | |
1405 | else if ((outer_code == PLUS && add_operand (x, VOIDmode)) | |
1406 | || (outer_code == AND && and_operand (x, VOIDmode))) | |
1407 | *total = 0; | |
1408 | else if (add_operand (x, VOIDmode) || and_operand (x, VOIDmode)) | |
1409 | *total = 2; | |
1410 | else | |
1411 | *total = COSTS_N_INSNS (2); | |
1412 | return true; | |
9e7454d0 | 1413 | |
fab7adbf | 1414 | case CONST: |
1415 | case SYMBOL_REF: | |
1416 | case LABEL_REF: | |
1417 | if (TARGET_EXPLICIT_RELOCS && small_symbolic_operand (x, VOIDmode)) | |
1418 | *total = COSTS_N_INSNS (outer_code != MEM); | |
1419 | else if (TARGET_EXPLICIT_RELOCS && local_symbolic_operand (x, VOIDmode)) | |
1420 | *total = COSTS_N_INSNS (1 + (outer_code != MEM)); | |
1421 | else if (tls_symbolic_operand_type (x)) | |
1422 | /* Estimate of cost for call_pal rduniq. */ | |
d7cf2331 | 1423 | /* ??? How many insns do we emit here? More than one... */ |
fab7adbf | 1424 | *total = COSTS_N_INSNS (15); |
1425 | else | |
1426 | /* Otherwise we do a load from the GOT. */ | |
f529eb25 | 1427 | *total = COSTS_N_INSNS (!speed ? 1 : alpha_memory_latency); |
fab7adbf | 1428 | return true; |
9e7454d0 | 1429 | |
91bc47b0 | 1430 | case HIGH: |
1431 | /* This is effectively an add_operand. */ | |
1432 | *total = 2; | |
1433 | return true; | |
1434 | ||
fab7adbf | 1435 | case PLUS: |
1436 | case MINUS: | |
1437 | if (float_mode_p) | |
d7cf2331 | 1438 | *total = cost_data->fp_add; |
42bbca40 | 1439 | else if (GET_CODE (XEXP (x, 0)) == ASHIFT |
1440 | && const23_operand (XEXP (XEXP (x, 0), 1), VOIDmode)) | |
fab7adbf | 1441 | { |
5ae4887d | 1442 | *total = (rtx_cost (XEXP (XEXP (x, 0), 0), mode, |
20d892d1 | 1443 | (enum rtx_code) outer_code, opno, speed) |
5ae4887d | 1444 | + rtx_cost (XEXP (x, 1), mode, |
20d892d1 | 1445 | (enum rtx_code) outer_code, opno, speed) |
0a48089c | 1446 | + COSTS_N_INSNS (1)); |
fab7adbf | 1447 | return true; |
1448 | } | |
1449 | return false; | |
1450 | ||
1451 | case MULT: | |
1452 | if (float_mode_p) | |
d7cf2331 | 1453 | *total = cost_data->fp_mult; |
fab7adbf | 1454 | else if (mode == DImode) |
d7cf2331 | 1455 | *total = cost_data->int_mult_di; |
fab7adbf | 1456 | else |
d7cf2331 | 1457 | *total = cost_data->int_mult_si; |
fab7adbf | 1458 | return false; |
1459 | ||
1460 | case ASHIFT: | |
c933fb42 | 1461 | if (CONST_INT_P (XEXP (x, 1)) |
fab7adbf | 1462 | && INTVAL (XEXP (x, 1)) <= 3) |
1463 | { | |
1464 | *total = COSTS_N_INSNS (1); | |
1465 | return false; | |
1466 | } | |
8e262b5e | 1467 | /* FALLTHRU */ |
fab7adbf | 1468 | |
1469 | case ASHIFTRT: | |
1470 | case LSHIFTRT: | |
d7cf2331 | 1471 | *total = cost_data->int_shift; |
fab7adbf | 1472 | return false; |
1473 | ||
1474 | case IF_THEN_ELSE: | |
1475 | if (float_mode_p) | |
d7cf2331 | 1476 | *total = cost_data->fp_add; |
fab7adbf | 1477 | else |
d7cf2331 | 1478 | *total = cost_data->int_cmov; |
fab7adbf | 1479 | return false; |
1480 | ||
1481 | case DIV: | |
1482 | case UDIV: | |
1483 | case MOD: | |
1484 | case UMOD: | |
1485 | if (!float_mode_p) | |
d7cf2331 | 1486 | *total = cost_data->int_div; |
fab7adbf | 1487 | else if (mode == SFmode) |
d7cf2331 | 1488 | *total = cost_data->fp_div_sf; |
fab7adbf | 1489 | else |
d7cf2331 | 1490 | *total = cost_data->fp_div_df; |
fab7adbf | 1491 | return false; |
1492 | ||
1493 | case MEM: | |
f529eb25 | 1494 | *total = COSTS_N_INSNS (!speed ? 1 : alpha_memory_latency); |
fab7adbf | 1495 | return true; |
1496 | ||
1497 | case NEG: | |
1498 | if (! float_mode_p) | |
1499 | { | |
1500 | *total = COSTS_N_INSNS (1); | |
1501 | return false; | |
1502 | } | |
8e262b5e | 1503 | /* FALLTHRU */ |
fab7adbf | 1504 | |
1505 | case ABS: | |
1506 | if (! float_mode_p) | |
1507 | { | |
d7cf2331 | 1508 | *total = COSTS_N_INSNS (1) + cost_data->int_cmov; |
fab7adbf | 1509 | return false; |
1510 | } | |
8e262b5e | 1511 | /* FALLTHRU */ |
fab7adbf | 1512 | |
1513 | case FLOAT: | |
1514 | case UNSIGNED_FLOAT: | |
1515 | case FIX: | |
1516 | case UNSIGNED_FIX: | |
fab7adbf | 1517 | case FLOAT_TRUNCATE: |
d7cf2331 | 1518 | *total = cost_data->fp_add; |
fab7adbf | 1519 | return false; |
1520 | ||
5fc4edde | 1521 | case FLOAT_EXTEND: |
c933fb42 | 1522 | if (MEM_P (XEXP (x, 0))) |
5fc4edde | 1523 | *total = 0; |
1524 | else | |
1525 | *total = cost_data->fp_add; | |
1526 | return false; | |
1527 | ||
fab7adbf | 1528 | default: |
1529 | return false; | |
1530 | } | |
1531 | } | |
1532 | \f | |
bf2a98b3 | 1533 | /* REF is an alignable memory location. Place an aligned SImode |
1534 | reference into *PALIGNED_MEM and the number of bits to shift into | |
a99a652b | 1535 | *PBITNUM. SCRATCH is a free register for use in reloading out |
1536 | of range stack slots. */ | |
bf2a98b3 | 1537 | |
1538 | void | |
92643d95 | 1539 | get_aligned_mem (rtx ref, rtx *paligned_mem, rtx *pbitnum) |
bf2a98b3 | 1540 | { |
1541 | rtx base; | |
a3fed3d2 | 1542 | HOST_WIDE_INT disp, offset; |
bf2a98b3 | 1543 | |
c933fb42 | 1544 | gcc_assert (MEM_P (ref)); |
bf2a98b3 | 1545 | |
b4e5c0d9 | 1546 | if (reload_in_progress) |
a99a652b | 1547 | { |
cc215844 | 1548 | base = find_replacement (&XEXP (ref, 0)); |
4d10b463 | 1549 | gcc_assert (memory_address_p (GET_MODE (ref), base)); |
a99a652b | 1550 | } |
bf2a98b3 | 1551 | else |
4d10b463 | 1552 | base = XEXP (ref, 0); |
bf2a98b3 | 1553 | |
1554 | if (GET_CODE (base) == PLUS) | |
a3fed3d2 | 1555 | disp = INTVAL (XEXP (base, 1)), base = XEXP (base, 0); |
1556 | else | |
1557 | disp = 0; | |
1558 | ||
1559 | /* Find the byte offset within an aligned word. If the memory itself is | |
1560 | claimed to be aligned, believe it. Otherwise, aligned_memory_operand | |
1561 | will have examined the base register and determined it is aligned, and | |
1562 | thus displacements from it are naturally alignable. */ | |
1563 | if (MEM_ALIGN (ref) >= 32) | |
1564 | offset = 0; | |
1565 | else | |
1566 | offset = disp & 3; | |
bf2a98b3 | 1567 | |
5e46378b | 1568 | /* The location should not cross aligned word boundary. */ |
1569 | gcc_assert (offset + GET_MODE_SIZE (GET_MODE (ref)) | |
1570 | <= GET_MODE_SIZE (SImode)); | |
1571 | ||
a3fed3d2 | 1572 | /* Access the entire aligned word. */ |
1573 | *paligned_mem = widen_memory_access (ref, SImode, -offset); | |
bf2a98b3 | 1574 | |
a3fed3d2 | 1575 | /* Convert the byte offset within the word to a bit offset. */ |
9bab4302 | 1576 | offset *= BITS_PER_UNIT; |
a3fed3d2 | 1577 | *pbitnum = GEN_INT (offset); |
bf2a98b3 | 1578 | } |
1579 | ||
9e7454d0 | 1580 | /* Similar, but just get the address. Handle the two reload cases. |
b044f41c | 1581 | Add EXTRA_OFFSET to the address we return. */ |
bf2a98b3 | 1582 | |
1583 | rtx | |
0934d969 | 1584 | get_unaligned_address (rtx ref) |
bf2a98b3 | 1585 | { |
1586 | rtx base; | |
1587 | HOST_WIDE_INT offset = 0; | |
1588 | ||
c933fb42 | 1589 | gcc_assert (MEM_P (ref)); |
bf2a98b3 | 1590 | |
b4e5c0d9 | 1591 | if (reload_in_progress) |
a99a652b | 1592 | { |
a99a652b | 1593 | base = find_replacement (&XEXP (ref, 0)); |
4d10b463 | 1594 | gcc_assert (memory_address_p (GET_MODE (ref), base)); |
a99a652b | 1595 | } |
bf2a98b3 | 1596 | else |
4d10b463 | 1597 | base = XEXP (ref, 0); |
bf2a98b3 | 1598 | |
1599 | if (GET_CODE (base) == PLUS) | |
1600 | offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0); | |
1601 | ||
29c05e22 | 1602 | return plus_constant (Pmode, base, offset); |
0934d969 | 1603 | } |
1604 | ||
1605 | /* Compute a value X, such that X & 7 == (ADDR + OFS) & 7. | |
1606 | X is always returned in a register. */ | |
1607 | ||
1608 | rtx | |
1609 | get_unaligned_offset (rtx addr, HOST_WIDE_INT ofs) | |
1610 | { | |
1611 | if (GET_CODE (addr) == PLUS) | |
1612 | { | |
1613 | ofs += INTVAL (XEXP (addr, 1)); | |
1614 | addr = XEXP (addr, 0); | |
1615 | } | |
1616 | ||
1617 | return expand_simple_binop (Pmode, PLUS, addr, GEN_INT (ofs & 7), | |
1618 | NULL_RTX, 1, OPTAB_LIB_WIDEN); | |
bf2a98b3 | 1619 | } |
14f7bc98 | 1620 | |
f5a60074 | 1621 | /* On the Alpha, all (non-symbolic) constants except zero go into |
9e7454d0 | 1622 | a floating-point register via memory. Note that we cannot |
8deb3959 | 1623 | return anything that is not a subset of RCLASS, and that some |
f5a60074 | 1624 | symbolic constants cannot be dropped to memory. */ |
1625 | ||
1626 | enum reg_class | |
8deb3959 | 1627 | alpha_preferred_reload_class(rtx x, enum reg_class rclass) |
f5a60074 | 1628 | { |
1629 | /* Zero is present in any register class. */ | |
1630 | if (x == CONST0_RTX (GET_MODE (x))) | |
8deb3959 | 1631 | return rclass; |
f5a60074 | 1632 | |
1633 | /* These sorts of constants we can easily drop to memory. */ | |
7bc95bfb | 1634 | if (CONST_SCALAR_INT_P (x) |
1635 | || CONST_DOUBLE_P (x) | |
91bc47b0 | 1636 | || GET_CODE (x) == CONST_VECTOR) |
f5a60074 | 1637 | { |
8deb3959 | 1638 | if (rclass == FLOAT_REGS) |
f5a60074 | 1639 | return NO_REGS; |
8deb3959 | 1640 | if (rclass == ALL_REGS) |
f5a60074 | 1641 | return GENERAL_REGS; |
8deb3959 | 1642 | return rclass; |
f5a60074 | 1643 | } |
1644 | ||
1645 | /* All other kinds of constants should not (and in the case of HIGH | |
1646 | cannot) be dropped to memory -- instead we use a GENERAL_REGS | |
1647 | secondary reload. */ | |
1648 | if (CONSTANT_P (x)) | |
8deb3959 | 1649 | return (rclass == ALL_REGS ? GENERAL_REGS : rclass); |
f5a60074 | 1650 | |
8deb3959 | 1651 | return rclass; |
f5a60074 | 1652 | } |
1653 | ||
0d96cd2b | 1654 | /* Inform reload about cases where moving X with a mode MODE to a register in |
8deb3959 | 1655 | RCLASS requires an extra scratch or immediate register. Return the class |
0d96cd2b | 1656 | needed for the immediate register. */ |
14f7bc98 | 1657 | |
964229b7 | 1658 | static reg_class_t |
1659 | alpha_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, | |
3754d046 | 1660 | machine_mode mode, secondary_reload_info *sri) |
14f7bc98 | 1661 | { |
964229b7 | 1662 | enum reg_class rclass = (enum reg_class) rclass_i; |
1663 | ||
0d96cd2b | 1664 | /* Loading and storing HImode or QImode values to and from memory |
1665 | usually requires a scratch register. */ | |
1666 | if (!TARGET_BWX && (mode == QImode || mode == HImode || mode == CQImode)) | |
d2494d49 | 1667 | { |
0d96cd2b | 1668 | if (any_memory_operand (x, mode)) |
d2494d49 | 1669 | { |
0d96cd2b | 1670 | if (in_p) |
1671 | { | |
1672 | if (!aligned_memory_operand (x, mode)) | |
6b531606 | 1673 | sri->icode = direct_optab_handler (reload_in_optab, mode); |
0d96cd2b | 1674 | } |
1675 | else | |
6b531606 | 1676 | sri->icode = direct_optab_handler (reload_out_optab, mode); |
0d96cd2b | 1677 | return NO_REGS; |
d2494d49 | 1678 | } |
1679 | } | |
14f7bc98 | 1680 | |
0d96cd2b | 1681 | /* We also cannot do integral arithmetic into FP regs, as might result |
1682 | from register elimination into a DImode fp register. */ | |
8deb3959 | 1683 | if (rclass == FLOAT_REGS) |
14f7bc98 | 1684 | { |
0d96cd2b | 1685 | if (MEM_P (x) && GET_CODE (XEXP (x, 0)) == AND) |
14f7bc98 | 1686 | return GENERAL_REGS; |
0d96cd2b | 1687 | if (in_p && INTEGRAL_MODE_P (mode) |
1688 | && !MEM_P (x) && !REG_P (x) && !CONST_INT_P (x)) | |
14f7bc98 | 1689 | return GENERAL_REGS; |
1690 | } | |
1691 | ||
1692 | return NO_REGS; | |
1693 | } | |
1041f930 | 1694 | |
c836e75b | 1695 | /* Implement TARGET_SECONDARY_MEMORY_NEEDED. |
1696 | ||
1697 | If we are copying between general and FP registers, we need a memory | |
1698 | location unless the FIX extension is available. */ | |
1699 | ||
1700 | static bool | |
1701 | alpha_secondary_memory_needed (machine_mode, reg_class_t class1, | |
1702 | reg_class_t class2) | |
1703 | { | |
1704 | return (!TARGET_FIX | |
1705 | && ((class1 == FLOAT_REGS && class2 != FLOAT_REGS) | |
1706 | || (class2 == FLOAT_REGS && class1 != FLOAT_REGS))); | |
1707 | } | |
1708 | ||
1041f930 | 1709 | /* Implement TARGET_SECONDARY_MEMORY_NEEDED_MODE. If MODE is |
1710 | floating-point, use it. Otherwise, widen to a word like the default. | |
1711 | This is needed because we always store integers in FP registers in | |
1712 | quadword format. This whole area is very tricky! */ | |
1713 | ||
1714 | static machine_mode | |
1715 | alpha_secondary_memory_needed_mode (machine_mode mode) | |
1716 | { | |
1717 | if (GET_MODE_CLASS (mode) == MODE_FLOAT) | |
1718 | return mode; | |
1719 | if (GET_MODE_SIZE (mode) >= 4) | |
1720 | return mode; | |
1721 | return mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (mode), 0).require (); | |
1722 | } | |
bf2a98b3 | 1723 | \f |
7ca8bc48 | 1724 | /* Given SEQ, which is an INSN list, look for any MEMs in either |
31d3e01c | 1725 | a SET_DEST or a SET_SRC and copy the in-struct, unchanging, and |
1726 | volatile flags from REF into each of the MEMs found. If REF is not | |
1727 | a MEM, don't do anything. */ | |
bf2a98b3 | 1728 | |
1729 | void | |
7ca8bc48 | 1730 | alpha_set_memflags (rtx seq, rtx ref) |
bf2a98b3 | 1731 | { |
91a55c11 | 1732 | rtx_insn *insn; |
849674a3 | 1733 | |
7ca8bc48 | 1734 | if (!MEM_P (ref)) |
bf2a98b3 | 1735 | return; |
1736 | ||
9e7454d0 | 1737 | /* This is only called from alpha.md, after having had something |
849674a3 | 1738 | generated from one of the insn patterns. So if everything is |
1739 | zero, the pattern is already up-to-date. */ | |
b04fab2a | 1740 | if (!MEM_VOLATILE_P (ref) |
b04fab2a | 1741 | && !MEM_NOTRAP_P (ref) |
1742 | && !MEM_READONLY_P (ref)) | |
849674a3 | 1743 | return; |
1744 | ||
70b88ec2 | 1745 | subrtx_var_iterator::array_type array; |
91a55c11 | 1746 | for (insn = as_a <rtx_insn *> (seq); insn; insn = NEXT_INSN (insn)) |
7ca8bc48 | 1747 | if (INSN_P (insn)) |
70b88ec2 | 1748 | FOR_EACH_SUBRTX_VAR (iter, array, PATTERN (insn), NONCONST) |
1749 | { | |
1750 | rtx x = *iter; | |
1751 | if (MEM_P (x)) | |
1752 | { | |
1753 | MEM_VOLATILE_P (x) = MEM_VOLATILE_P (ref); | |
1754 | MEM_NOTRAP_P (x) = MEM_NOTRAP_P (ref); | |
1755 | MEM_READONLY_P (x) = MEM_READONLY_P (ref); | |
1756 | /* Sadly, we cannot use alias sets because the extra | |
1757 | aliasing produced by the AND interferes. Given that | |
1758 | two-byte quantities are the only thing we would be | |
1759 | able to differentiate anyway, there does not seem to | |
1760 | be any point in convoluting the early out of the | |
1761 | alias check. */ | |
1762 | iter.skip_subrtxes (); | |
1763 | } | |
1764 | } | |
7ca8bc48 | 1765 | else |
1766 | gcc_unreachable (); | |
bf2a98b3 | 1767 | } |
1768 | \f | |
3754d046 | 1769 | static rtx alpha_emit_set_const (rtx, machine_mode, HOST_WIDE_INT, |
91bc47b0 | 1770 | int, bool); |
1771 | ||
1772 | /* Internal routine for alpha_emit_set_const to check for N or below insns. | |
1773 | If NO_OUTPUT is true, then we only check to see if N insns are possible, | |
1774 | and return pc_rtx if successful. */ | |
6f86cb15 | 1775 | |
1776 | static rtx | |
3754d046 | 1777 | alpha_emit_set_const_1 (rtx target, machine_mode mode, |
91bc47b0 | 1778 | HOST_WIDE_INT c, int n, bool no_output) |
bf2a98b3 | 1779 | { |
8deb3959 | 1780 | HOST_WIDE_INT new_const; |
bf2a98b3 | 1781 | int i, bits; |
ea5db00c | 1782 | /* Use a pseudo if highly optimizing and still generating RTL. */ |
1783 | rtx subtarget | |
e1ba4a27 | 1784 | = (flag_expensive_optimizations && can_create_pseudo_p () ? 0 : target); |
301416af | 1785 | rtx temp, insn; |
bf2a98b3 | 1786 | |
bf2a98b3 | 1787 | /* If this is a sign-extended 32-bit constant, we can do this in at most |
a2d7211e | 1788 | three insns, so do it if we have enough insns left. */ |
bf2a98b3 | 1789 | |
a2d7211e | 1790 | if (c >> 31 == -1 || c >> 31 == 0) |
bf2a98b3 | 1791 | { |
bdb19034 | 1792 | HOST_WIDE_INT low = ((c & 0xffff) ^ 0x8000) - 0x8000; |
bf2a98b3 | 1793 | HOST_WIDE_INT tmp1 = c - low; |
bdb19034 | 1794 | HOST_WIDE_INT high = (((tmp1 >> 16) & 0xffff) ^ 0x8000) - 0x8000; |
bf2a98b3 | 1795 | HOST_WIDE_INT extra = 0; |
1796 | ||
81d03ebd | 1797 | /* If HIGH will be interpreted as negative but the constant is |
1798 | positive, we must adjust it to do two ldha insns. */ | |
1799 | ||
1800 | if ((high & 0x8000) != 0 && c >= 0) | |
bf2a98b3 | 1801 | { |
1802 | extra = 0x4000; | |
1803 | tmp1 -= 0x40000000; | |
1804 | high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); | |
1805 | } | |
1806 | ||
1807 | if (c == low || (low == 0 && extra == 0)) | |
3bc2043a | 1808 | { |
1809 | /* We used to use copy_to_suggested_reg (GEN_INT (c), target, mode) | |
1810 | but that meant that we can't handle INT_MIN on 32-bit machines | |
9e7454d0 | 1811 | (like NT/Alpha), because we recurse indefinitely through |
3bc2043a | 1812 | emit_move_insn to gen_movdi. So instead, since we know exactly |
1813 | what we want, create it explicitly. */ | |
1814 | ||
91bc47b0 | 1815 | if (no_output) |
1816 | return pc_rtx; | |
3bc2043a | 1817 | if (target == NULL) |
1818 | target = gen_reg_rtx (mode); | |
d1f9b275 | 1819 | emit_insn (gen_rtx_SET (target, GEN_INT (c))); |
3bc2043a | 1820 | return target; |
1821 | } | |
6f86cb15 | 1822 | else if (n >= 2 + (extra != 0)) |
bf2a98b3 | 1823 | { |
91bc47b0 | 1824 | if (no_output) |
1825 | return pc_rtx; | |
e1ba4a27 | 1826 | if (!can_create_pseudo_p ()) |
5b952578 | 1827 | { |
d1f9b275 | 1828 | emit_insn (gen_rtx_SET (target, GEN_INT (high << 16))); |
5b952578 | 1829 | temp = target; |
1830 | } | |
1831 | else | |
1832 | temp = copy_to_suggested_reg (GEN_INT (high << 16), | |
1833 | subtarget, mode); | |
ea5db00c | 1834 | |
301416af | 1835 | /* As of 2002-02-23, addsi3 is only available when not optimizing. |
1836 | This means that if we go through expand_binop, we'll try to | |
1837 | generate extensions, etc, which will require new pseudos, which | |
1838 | will fail during some split phases. The SImode add patterns | |
1839 | still exist, but are not named. So build the insns by hand. */ | |
1840 | ||
bf2a98b3 | 1841 | if (extra != 0) |
301416af | 1842 | { |
1843 | if (! subtarget) | |
1844 | subtarget = gen_reg_rtx (mode); | |
1845 | insn = gen_rtx_PLUS (mode, temp, GEN_INT (extra << 16)); | |
d1f9b275 | 1846 | insn = gen_rtx_SET (subtarget, insn); |
301416af | 1847 | emit_insn (insn); |
b8585446 | 1848 | temp = subtarget; |
301416af | 1849 | } |
bf2a98b3 | 1850 | |
301416af | 1851 | if (target == NULL) |
1852 | target = gen_reg_rtx (mode); | |
1853 | insn = gen_rtx_PLUS (mode, temp, GEN_INT (low)); | |
d1f9b275 | 1854 | insn = gen_rtx_SET (target, insn); |
301416af | 1855 | emit_insn (insn); |
1856 | return target; | |
bf2a98b3 | 1857 | } |
1858 | } | |
1859 | ||
dacd345b | 1860 | /* If we couldn't do it that way, try some other methods. But if we have |
07014ed9 | 1861 | no instructions left, don't bother. Likewise, if this is SImode and |
1862 | we can't make pseudos, we can't do anything since the expand_binop | |
1863 | and expand_unop calls will widen and try to make pseudos. */ | |
bf2a98b3 | 1864 | |
e1ba4a27 | 1865 | if (n == 1 || (mode == SImode && !can_create_pseudo_p ())) |
bf2a98b3 | 1866 | return 0; |
1867 | ||
dacd345b | 1868 | /* Next, see if we can load a related constant and then shift and possibly |
bf2a98b3 | 1869 | negate it to get the constant we want. Try this once each increasing |
1870 | numbers of insns. */ | |
1871 | ||
1872 | for (i = 1; i < n; i++) | |
1873 | { | |
bdb19034 | 1874 | /* First, see if minus some low bits, we've an easy load of |
1875 | high bits. */ | |
1876 | ||
8deb3959 | 1877 | new_const = ((c & 0xffff) ^ 0x8000) - 0x8000; |
1878 | if (new_const != 0) | |
91bc47b0 | 1879 | { |
8deb3959 | 1880 | temp = alpha_emit_set_const (subtarget, mode, c - new_const, i, no_output); |
91bc47b0 | 1881 | if (temp) |
1882 | { | |
1883 | if (no_output) | |
1884 | return temp; | |
8deb3959 | 1885 | return expand_binop (mode, add_optab, temp, GEN_INT (new_const), |
91bc47b0 | 1886 | target, 0, OPTAB_WIDEN); |
1887 | } | |
1888 | } | |
bdb19034 | 1889 | |
1890 | /* Next try complementing. */ | |
91bc47b0 | 1891 | temp = alpha_emit_set_const (subtarget, mode, ~c, i, no_output); |
1892 | if (temp) | |
1893 | { | |
1894 | if (no_output) | |
1895 | return temp; | |
1896 | return expand_unop (mode, one_cmpl_optab, temp, target, 0); | |
1897 | } | |
bf2a98b3 | 1898 | |
ea5db00c | 1899 | /* Next try to form a constant and do a left shift. We can do this |
bf2a98b3 | 1900 | if some low-order bits are zero; the exact_log2 call below tells |
1901 | us that information. The bits we are shifting out could be any | |
1902 | value, but here we'll just try the 0- and sign-extended forms of | |
1903 | the constant. To try to increase the chance of having the same | |
1904 | constant in more than one insn, start at the highest number of | |
1905 | bits to shift, but try all possibilities in case a ZAPNOT will | |
1906 | be useful. */ | |
1907 | ||
91bc47b0 | 1908 | bits = exact_log2 (c & -c); |
1909 | if (bits > 0) | |
bf2a98b3 | 1910 | for (; bits > 0; bits--) |
91bc47b0 | 1911 | { |
8deb3959 | 1912 | new_const = c >> bits; |
1913 | temp = alpha_emit_set_const (subtarget, mode, new_const, i, no_output); | |
91bc47b0 | 1914 | if (!temp && c < 0) |
1915 | { | |
8deb3959 | 1916 | new_const = (unsigned HOST_WIDE_INT)c >> bits; |
1917 | temp = alpha_emit_set_const (subtarget, mode, new_const, | |
91bc47b0 | 1918 | i, no_output); |
1919 | } | |
1920 | if (temp) | |
1921 | { | |
1922 | if (no_output) | |
1923 | return temp; | |
1924 | return expand_binop (mode, ashl_optab, temp, GEN_INT (bits), | |
1925 | target, 0, OPTAB_WIDEN); | |
1926 | } | |
1927 | } | |
bf2a98b3 | 1928 | |
1929 | /* Now try high-order zero bits. Here we try the shifted-in bits as | |
066efb8d | 1930 | all zero and all ones. Be careful to avoid shifting outside the |
1931 | mode and to avoid shifting outside the host wide int size. */ | |
bf2a98b3 | 1932 | |
91bc47b0 | 1933 | bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) |
a2d7211e | 1934 | - floor_log2 (c) - 1); |
91bc47b0 | 1935 | if (bits > 0) |
bf2a98b3 | 1936 | for (; bits > 0; bits--) |
91bc47b0 | 1937 | { |
8deb3959 | 1938 | new_const = c << bits; |
1939 | temp = alpha_emit_set_const (subtarget, mode, new_const, i, no_output); | |
91bc47b0 | 1940 | if (!temp) |
1941 | { | |
a2d7211e | 1942 | new_const = (c << bits) | ((HOST_WIDE_INT_1U << bits) - 1); |
8deb3959 | 1943 | temp = alpha_emit_set_const (subtarget, mode, new_const, |
91bc47b0 | 1944 | i, no_output); |
1945 | } | |
1946 | if (temp) | |
1947 | { | |
1948 | if (no_output) | |
1949 | return temp; | |
1950 | return expand_binop (mode, lshr_optab, temp, GEN_INT (bits), | |
1951 | target, 1, OPTAB_WIDEN); | |
1952 | } | |
1953 | } | |
bf2a98b3 | 1954 | |
1955 | /* Now try high-order 1 bits. We get that with a sign-extension. | |
066efb8d | 1956 | But one bit isn't enough here. Be careful to avoid shifting outside |
65abff06 | 1957 | the mode and to avoid shifting outside the host wide int size. */ |
9caef960 | 1958 | |
91bc47b0 | 1959 | bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) |
1960 | - floor_log2 (~ c) - 2); | |
1961 | if (bits > 0) | |
bf2a98b3 | 1962 | for (; bits > 0; bits--) |
91bc47b0 | 1963 | { |
8deb3959 | 1964 | new_const = c << bits; |
1965 | temp = alpha_emit_set_const (subtarget, mode, new_const, i, no_output); | |
91bc47b0 | 1966 | if (!temp) |
1967 | { | |
a2d7211e | 1968 | new_const = (c << bits) | ((HOST_WIDE_INT_1U << bits) - 1); |
8deb3959 | 1969 | temp = alpha_emit_set_const (subtarget, mode, new_const, |
91bc47b0 | 1970 | i, no_output); |
1971 | } | |
1972 | if (temp) | |
1973 | { | |
1974 | if (no_output) | |
1975 | return temp; | |
1976 | return expand_binop (mode, ashr_optab, temp, GEN_INT (bits), | |
1977 | target, 0, OPTAB_WIDEN); | |
1978 | } | |
1979 | } | |
bf2a98b3 | 1980 | } |
1981 | ||
bdb19034 | 1982 | /* Finally, see if can load a value into the target that is the same as the |
1983 | constant except that all bytes that are 0 are changed to be 0xff. If we | |
1984 | can, then we can do a ZAPNOT to obtain the desired constant. */ | |
1985 | ||
8deb3959 | 1986 | new_const = c; |
bdb19034 | 1987 | for (i = 0; i < 64; i += 8) |
8deb3959 | 1988 | if ((new_const & ((HOST_WIDE_INT) 0xff << i)) == 0) |
1989 | new_const |= (HOST_WIDE_INT) 0xff << i; | |
e52799e9 | 1990 | |
bdb19034 | 1991 | /* We are only called for SImode and DImode. If this is SImode, ensure that |
1992 | we are sign extended to a full word. */ | |
1993 | ||
1994 | if (mode == SImode) | |
8deb3959 | 1995 | new_const = ((new_const & 0xffffffff) ^ 0x80000000) - 0x80000000; |
bdb19034 | 1996 | |
8deb3959 | 1997 | if (new_const != c) |
91bc47b0 | 1998 | { |
8deb3959 | 1999 | temp = alpha_emit_set_const (subtarget, mode, new_const, n - 1, no_output); |
91bc47b0 | 2000 | if (temp) |
2001 | { | |
2002 | if (no_output) | |
2003 | return temp; | |
8deb3959 | 2004 | return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new_const), |
91bc47b0 | 2005 | target, 0, OPTAB_WIDEN); |
2006 | } | |
2007 | } | |
e52799e9 | 2008 | |
bf2a98b3 | 2009 | return 0; |
2010 | } | |
996a379d | 2011 | |
92643d95 | 2012 | /* Try to output insns to set TARGET equal to the constant C if it can be |
2013 | done in less than N insns. Do all computations in MODE. Returns the place | |
2014 | where the output has been placed if it can be done and the insns have been | |
2015 | emitted. If it would take more than N insns, zero is returned and no | |
2016 | insns and emitted. */ | |
2017 | ||
91bc47b0 | 2018 | static rtx |
3754d046 | 2019 | alpha_emit_set_const (rtx target, machine_mode mode, |
91bc47b0 | 2020 | HOST_WIDE_INT c, int n, bool no_output) |
92643d95 | 2021 | { |
3754d046 | 2022 | machine_mode orig_mode = mode; |
92643d95 | 2023 | rtx orig_target = target; |
91bc47b0 | 2024 | rtx result = 0; |
92643d95 | 2025 | int i; |
2026 | ||
2027 | /* If we can't make any pseudos, TARGET is an SImode hard register, we | |
2028 | can't load this constant in one insn, do this in DImode. */ | |
e1ba4a27 | 2029 | if (!can_create_pseudo_p () && mode == SImode |
c933fb42 | 2030 | && REG_P (target) && REGNO (target) < FIRST_PSEUDO_REGISTER) |
92643d95 | 2031 | { |
91bc47b0 | 2032 | result = alpha_emit_set_const_1 (target, mode, c, 1, no_output); |
2033 | if (result) | |
2034 | return result; | |
2035 | ||
2036 | target = no_output ? NULL : gen_lowpart (DImode, target); | |
2037 | mode = DImode; | |
2038 | } | |
2039 | else if (mode == V8QImode || mode == V4HImode || mode == V2SImode) | |
2040 | { | |
2041 | target = no_output ? NULL : gen_lowpart (DImode, target); | |
92643d95 | 2042 | mode = DImode; |
2043 | } | |
2044 | ||
2045 | /* Try 1 insn, then 2, then up to N. */ | |
2046 | for (i = 1; i <= n; i++) | |
2047 | { | |
91bc47b0 | 2048 | result = alpha_emit_set_const_1 (target, mode, c, i, no_output); |
92643d95 | 2049 | if (result) |
2050 | { | |
7f0256ea | 2051 | rtx_insn *insn; |
2052 | rtx set; | |
91bc47b0 | 2053 | |
2054 | if (no_output) | |
2055 | return result; | |
2056 | ||
2057 | insn = get_last_insn (); | |
2058 | set = single_set (insn); | |
92643d95 | 2059 | if (! CONSTANT_P (SET_SRC (set))) |
2060 | set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c)); | |
2061 | break; | |
2062 | } | |
2063 | } | |
2064 | ||
2065 | /* Allow for the case where we changed the mode of TARGET. */ | |
91bc47b0 | 2066 | if (result) |
2067 | { | |
2068 | if (result == target) | |
2069 | result = orig_target; | |
2070 | else if (mode != orig_mode) | |
2071 | result = gen_lowpart (orig_mode, result); | |
2072 | } | |
92643d95 | 2073 | |
2074 | return result; | |
2075 | } | |
2076 | ||
2612f626 | 2077 | /* Having failed to find a 3 insn sequence in alpha_emit_set_const, |
2078 | fall back to a straight forward decomposition. We do this to avoid | |
2079 | exponential run times encountered when looking for longer sequences | |
2080 | with alpha_emit_set_const. */ | |
2081 | ||
91bc47b0 | 2082 | static rtx |
debb7e7a | 2083 | alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1) |
2612f626 | 2084 | { |
2612f626 | 2085 | HOST_WIDE_INT d1, d2, d3, d4; |
2612f626 | 2086 | |
2087 | /* Decompose the entire word */ | |
a2d7211e | 2088 | |
af792316 | 2089 | d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000; |
2090 | c1 -= d1; | |
2091 | d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
2092 | c1 = (c1 - d2) >> 32; | |
2093 | d3 = ((c1 & 0xffff) ^ 0x8000) - 0x8000; | |
2094 | c1 -= d3; | |
2095 | d4 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
4d10b463 | 2096 | gcc_assert (c1 == d4); |
2612f626 | 2097 | |
2098 | /* Construct the high word */ | |
af792316 | 2099 | if (d4) |
2100 | { | |
2101 | emit_move_insn (target, GEN_INT (d4)); | |
2102 | if (d3) | |
2103 | emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d3))); | |
2104 | } | |
2612f626 | 2105 | else |
af792316 | 2106 | emit_move_insn (target, GEN_INT (d3)); |
2612f626 | 2107 | |
2108 | /* Shift it into place */ | |
af792316 | 2109 | emit_move_insn (target, gen_rtx_ASHIFT (DImode, target, GEN_INT (32))); |
2612f626 | 2110 | |
af792316 | 2111 | /* Add in the low bits. */ |
2112 | if (d2) | |
2113 | emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d2))); | |
2114 | if (d1) | |
2115 | emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d1))); | |
2612f626 | 2116 | |
af792316 | 2117 | return target; |
2612f626 | 2118 | } |
2612f626 | 2119 | |
316e4f71 | 2120 | /* Given an integral CONST_INT or CONST_VECTOR, return the low 64 bits. */ |
91bc47b0 | 2121 | |
debb7e7a | 2122 | static HOST_WIDE_INT |
2123 | alpha_extract_integer (rtx x) | |
91bc47b0 | 2124 | { |
91bc47b0 | 2125 | if (GET_CODE (x) == CONST_VECTOR) |
2126 | x = simplify_subreg (DImode, x, GET_MODE (x), 0); | |
2127 | ||
316e4f71 | 2128 | gcc_assert (CONST_INT_P (x)); |
2129 | ||
2130 | return INTVAL (x); | |
91bc47b0 | 2131 | } |
2132 | ||
ca316360 | 2133 | /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for which |
2134 | we are willing to load the value into a register via a move pattern. | |
91bc47b0 | 2135 | Normally this is all symbolic constants, integral constants that |
2136 | take three or fewer instructions, and floating-point zero. */ | |
2137 | ||
2138 | bool | |
3754d046 | 2139 | alpha_legitimate_constant_p (machine_mode mode, rtx x) |
91bc47b0 | 2140 | { |
debb7e7a | 2141 | HOST_WIDE_INT i0; |
91bc47b0 | 2142 | |
2143 | switch (GET_CODE (x)) | |
2144 | { | |
91bc47b0 | 2145 | case LABEL_REF: |
91bc47b0 | 2146 | case HIGH: |
2147 | return true; | |
2148 | ||
75645350 | 2149 | case CONST: |
2150 | if (GET_CODE (XEXP (x, 0)) == PLUS | |
7bc95bfb | 2151 | && CONST_INT_P (XEXP (XEXP (x, 0), 1))) |
75645350 | 2152 | x = XEXP (XEXP (x, 0), 0); |
2153 | else | |
2154 | return true; | |
2155 | ||
2156 | if (GET_CODE (x) != SYMBOL_REF) | |
2157 | return true; | |
75645350 | 2158 | /* FALLTHRU */ |
2159 | ||
b5c0ec3d | 2160 | case SYMBOL_REF: |
2161 | /* TLS symbols are never valid. */ | |
2162 | return SYMBOL_REF_TLS_MODEL (x) == 0; | |
2163 | ||
5c5c1f00 | 2164 | case CONST_WIDE_INT: |
316e4f71 | 2165 | if (TARGET_BUILD_CONSTANTS) |
2166 | return true; | |
91bc47b0 | 2167 | if (x == CONST0_RTX (mode)) |
2168 | return true; | |
316e4f71 | 2169 | mode = DImode; |
2170 | gcc_assert (CONST_WIDE_INT_NUNITS (x) == 2); | |
2171 | i0 = CONST_WIDE_INT_ELT (x, 1); | |
2172 | if (alpha_emit_set_const_1 (NULL_RTX, mode, i0, 3, true) == NULL) | |
2173 | return false; | |
2174 | i0 = CONST_WIDE_INT_ELT (x, 0); | |
91bc47b0 | 2175 | goto do_integer; |
2176 | ||
5c5c1f00 | 2177 | case CONST_DOUBLE: |
2178 | if (x == CONST0_RTX (mode)) | |
2179 | return true; | |
2180 | return false; | |
2181 | ||
91bc47b0 | 2182 | case CONST_VECTOR: |
2183 | if (x == CONST0_RTX (mode)) | |
2184 | return true; | |
2185 | if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT) | |
2186 | return false; | |
2187 | if (GET_MODE_SIZE (mode) != 8) | |
2188 | return false; | |
316e4f71 | 2189 | /* FALLTHRU */ |
91bc47b0 | 2190 | |
2191 | case CONST_INT: | |
91bc47b0 | 2192 | if (TARGET_BUILD_CONSTANTS) |
2193 | return true; | |
debb7e7a | 2194 | i0 = alpha_extract_integer (x); |
316e4f71 | 2195 | do_integer: |
2196 | return alpha_emit_set_const_1 (NULL_RTX, mode, i0, 3, true) != NULL; | |
91bc47b0 | 2197 | |
2198 | default: | |
2199 | return false; | |
2200 | } | |
2201 | } | |
2202 | ||
2203 | /* Operand 1 is known to be a constant, and should require more than one | |
2204 | instruction to load. Emit that multi-part load. */ | |
2205 | ||
2206 | bool | |
3754d046 | 2207 | alpha_split_const_mov (machine_mode mode, rtx *operands) |
91bc47b0 | 2208 | { |
debb7e7a | 2209 | HOST_WIDE_INT i0; |
91bc47b0 | 2210 | rtx temp = NULL_RTX; |
2211 | ||
debb7e7a | 2212 | i0 = alpha_extract_integer (operands[1]); |
91bc47b0 | 2213 | |
a2d7211e | 2214 | temp = alpha_emit_set_const (operands[0], mode, i0, 3, false); |
91bc47b0 | 2215 | |
2216 | if (!temp && TARGET_BUILD_CONSTANTS) | |
debb7e7a | 2217 | temp = alpha_emit_set_long_const (operands[0], i0); |
91bc47b0 | 2218 | |
2219 | if (temp) | |
2220 | { | |
2221 | if (!rtx_equal_p (operands[0], temp)) | |
2222 | emit_move_insn (operands[0], temp); | |
2223 | return true; | |
2224 | } | |
2225 | ||
2226 | return false; | |
2227 | } | |
2228 | ||
cb6e3ae1 | 2229 | /* Expand a move instruction; return true if all work is done. |
2230 | We don't handle non-bwx subword loads here. */ | |
2231 | ||
2232 | bool | |
3754d046 | 2233 | alpha_expand_mov (machine_mode mode, rtx *operands) |
cb6e3ae1 | 2234 | { |
f8fff44e | 2235 | rtx tmp; |
2236 | ||
cb6e3ae1 | 2237 | /* If the output is not a register, the input must be. */ |
c933fb42 | 2238 | if (MEM_P (operands[0]) |
cb6e3ae1 | 2239 | && ! reg_or_0_operand (operands[1], mode)) |
2240 | operands[1] = force_reg (mode, operands[1]); | |
2241 | ||
f5a60074 | 2242 | /* Allow legitimize_address to perform some simplifications. */ |
62e050c6 | 2243 | if (mode == Pmode && symbolic_operand (operands[1], mode)) |
1f0ce6a6 | 2244 | { |
41e3a0c7 | 2245 | tmp = alpha_legitimize_address_1 (operands[1], operands[0], mode); |
f5a60074 | 2246 | if (tmp) |
5dcb037d | 2247 | { |
5f7b9df8 | 2248 | if (tmp == operands[0]) |
2249 | return true; | |
f5a60074 | 2250 | operands[1] = tmp; |
8afb6db4 | 2251 | return false; |
2252 | } | |
1f0ce6a6 | 2253 | } |
2254 | ||
cb6e3ae1 | 2255 | /* Early out for non-constants and valid constants. */ |
2256 | if (! CONSTANT_P (operands[1]) || input_operand (operands[1], mode)) | |
2257 | return false; | |
2258 | ||
2259 | /* Split large integers. */ | |
c933fb42 | 2260 | if (CONST_INT_P (operands[1]) |
91bc47b0 | 2261 | || GET_CODE (operands[1]) == CONST_VECTOR) |
cb6e3ae1 | 2262 | { |
91bc47b0 | 2263 | if (alpha_split_const_mov (mode, operands)) |
2264 | return true; | |
cb6e3ae1 | 2265 | } |
2266 | ||
2267 | /* Otherwise we've nothing left but to drop the thing to memory. */ | |
f8fff44e | 2268 | tmp = force_const_mem (mode, operands[1]); |
2269 | ||
2270 | if (tmp == NULL_RTX) | |
2271 | return false; | |
2272 | ||
cb6e3ae1 | 2273 | if (reload_in_progress) |
2274 | { | |
f8fff44e | 2275 | emit_move_insn (operands[0], XEXP (tmp, 0)); |
2276 | operands[1] = replace_equiv_address (tmp, operands[0]); | |
cb6e3ae1 | 2277 | } |
2278 | else | |
f8fff44e | 2279 | operands[1] = validize_mem (tmp); |
cb6e3ae1 | 2280 | return false; |
2281 | } | |
2282 | ||
2283 | /* Expand a non-bwx QImode or HImode move instruction; | |
2284 | return true if all work is done. */ | |
2285 | ||
2286 | bool | |
3754d046 | 2287 | alpha_expand_mov_nobwx (machine_mode mode, rtx *operands) |
cb6e3ae1 | 2288 | { |
0d96cd2b | 2289 | rtx seq; |
2290 | ||
cb6e3ae1 | 2291 | /* If the output is not a register, the input must be. */ |
0d96cd2b | 2292 | if (MEM_P (operands[0])) |
cb6e3ae1 | 2293 | operands[1] = force_reg (mode, operands[1]); |
2294 | ||
2295 | /* Handle four memory cases, unaligned and aligned for either the input | |
2296 | or the output. The only case where we can be called during reload is | |
2297 | for aligned loads; all other cases require temporaries. */ | |
2298 | ||
0d96cd2b | 2299 | if (any_memory_operand (operands[1], mode)) |
cb6e3ae1 | 2300 | { |
2301 | if (aligned_memory_operand (operands[1], mode)) | |
2302 | { | |
2303 | if (reload_in_progress) | |
2304 | { | |
0d96cd2b | 2305 | if (mode == QImode) |
2306 | seq = gen_reload_inqi_aligned (operands[0], operands[1]); | |
2307 | else | |
2308 | seq = gen_reload_inhi_aligned (operands[0], operands[1]); | |
2309 | emit_insn (seq); | |
cb6e3ae1 | 2310 | } |
2311 | else | |
2312 | { | |
2313 | rtx aligned_mem, bitnum; | |
2314 | rtx scratch = gen_reg_rtx (SImode); | |
d67e1866 | 2315 | rtx subtarget; |
2316 | bool copyout; | |
cb6e3ae1 | 2317 | |
2318 | get_aligned_mem (operands[1], &aligned_mem, &bitnum); | |
2319 | ||
d67e1866 | 2320 | subtarget = operands[0]; |
c933fb42 | 2321 | if (REG_P (subtarget)) |
d67e1866 | 2322 | subtarget = gen_lowpart (DImode, subtarget), copyout = false; |
2323 | else | |
2324 | subtarget = gen_reg_rtx (DImode), copyout = true; | |
2325 | ||
0d96cd2b | 2326 | if (mode == QImode) |
2327 | seq = gen_aligned_loadqi (subtarget, aligned_mem, | |
2328 | bitnum, scratch); | |
2329 | else | |
2330 | seq = gen_aligned_loadhi (subtarget, aligned_mem, | |
2331 | bitnum, scratch); | |
2332 | emit_insn (seq); | |
d67e1866 | 2333 | |
2334 | if (copyout) | |
2335 | emit_move_insn (operands[0], gen_lowpart (mode, subtarget)); | |
cb6e3ae1 | 2336 | } |
2337 | } | |
2338 | else | |
2339 | { | |
2340 | /* Don't pass these as parameters since that makes the generated | |
2341 | code depend on parameter evaluation order which will cause | |
2342 | bootstrap failures. */ | |
2343 | ||
0d96cd2b | 2344 | rtx temp1, temp2, subtarget, ua; |
d67e1866 | 2345 | bool copyout; |
2346 | ||
2347 | temp1 = gen_reg_rtx (DImode); | |
2348 | temp2 = gen_reg_rtx (DImode); | |
cb6e3ae1 | 2349 | |
d67e1866 | 2350 | subtarget = operands[0]; |
c933fb42 | 2351 | if (REG_P (subtarget)) |
d67e1866 | 2352 | subtarget = gen_lowpart (DImode, subtarget), copyout = false; |
2353 | else | |
2354 | subtarget = gen_reg_rtx (DImode), copyout = true; | |
2355 | ||
0d96cd2b | 2356 | ua = get_unaligned_address (operands[1]); |
2357 | if (mode == QImode) | |
2358 | seq = gen_unaligned_loadqi (subtarget, ua, temp1, temp2); | |
2359 | else | |
2360 | seq = gen_unaligned_loadhi (subtarget, ua, temp1, temp2); | |
2361 | ||
cb6e3ae1 | 2362 | alpha_set_memflags (seq, operands[1]); |
2363 | emit_insn (seq); | |
d67e1866 | 2364 | |
2365 | if (copyout) | |
2366 | emit_move_insn (operands[0], gen_lowpart (mode, subtarget)); | |
cb6e3ae1 | 2367 | } |
2368 | return true; | |
2369 | } | |
2370 | ||
0d96cd2b | 2371 | if (any_memory_operand (operands[0], mode)) |
cb6e3ae1 | 2372 | { |
2373 | if (aligned_memory_operand (operands[0], mode)) | |
2374 | { | |
2375 | rtx aligned_mem, bitnum; | |
2376 | rtx temp1 = gen_reg_rtx (SImode); | |
2377 | rtx temp2 = gen_reg_rtx (SImode); | |
2378 | ||
2379 | get_aligned_mem (operands[0], &aligned_mem, &bitnum); | |
2380 | ||
2381 | emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum, | |
2382 | temp1, temp2)); | |
2383 | } | |
2384 | else | |
2385 | { | |
2386 | rtx temp1 = gen_reg_rtx (DImode); | |
2387 | rtx temp2 = gen_reg_rtx (DImode); | |
2388 | rtx temp3 = gen_reg_rtx (DImode); | |
0d96cd2b | 2389 | rtx ua = get_unaligned_address (operands[0]); |
2390 | ||
2391 | if (mode == QImode) | |
2392 | seq = gen_unaligned_storeqi (ua, operands[1], temp1, temp2, temp3); | |
2393 | else | |
2394 | seq = gen_unaligned_storehi (ua, operands[1], temp1, temp2, temp3); | |
cb6e3ae1 | 2395 | |
2396 | alpha_set_memflags (seq, operands[0]); | |
2397 | emit_insn (seq); | |
2398 | } | |
2399 | return true; | |
2400 | } | |
2401 | ||
2402 | return false; | |
2403 | } | |
2404 | ||
a31688d7 | 2405 | /* Implement the movmisalign patterns. One of the operands is a memory |
84846cff | 2406 | that is not naturally aligned. Emit instructions to load it. */ |
a31688d7 | 2407 | |
2408 | void | |
3754d046 | 2409 | alpha_expand_movmisalign (machine_mode mode, rtx *operands) |
a31688d7 | 2410 | { |
2411 | /* Honor misaligned loads, for those we promised to do so. */ | |
2412 | if (MEM_P (operands[1])) | |
2413 | { | |
2414 | rtx tmp; | |
2415 | ||
2416 | if (register_operand (operands[0], mode)) | |
2417 | tmp = operands[0]; | |
2418 | else | |
2419 | tmp = gen_reg_rtx (mode); | |
2420 | ||
2421 | alpha_expand_unaligned_load (tmp, operands[1], 8, 0, 0); | |
2422 | if (tmp != operands[0]) | |
2423 | emit_move_insn (operands[0], tmp); | |
2424 | } | |
2425 | else if (MEM_P (operands[0])) | |
2426 | { | |
2427 | if (!reg_or_0_operand (operands[1], mode)) | |
2428 | operands[1] = force_reg (mode, operands[1]); | |
2429 | alpha_expand_unaligned_store (operands[0], operands[1], 8, 0); | |
2430 | } | |
2431 | else | |
2432 | gcc_unreachable (); | |
2433 | } | |
2434 | ||
2a42ba09 | 2435 | /* Generate an unsigned DImode to FP conversion. This is the same code |
2436 | optabs would emit if we didn't have TFmode patterns. | |
2437 | ||
2438 | For SFmode, this is the only construction I've found that can pass | |
2439 | gcc.c-torture/execute/ieee/rbug.c. No scenario that uses DFmode | |
2440 | intermediates will work, because you'll get intermediate rounding | |
2441 | that ruins the end result. Some of this could be fixed by turning | |
2442 | on round-to-positive-infinity, but that requires diddling the fpsr, | |
2443 | which kills performance. I tried turning this around and converting | |
2444 | to a negative number, so that I could turn on /m, but either I did | |
2445 | it wrong or there's something else cause I wound up with the exact | |
2446 | same single-bit error. There is a branch-less form of this same code: | |
2447 | ||
2448 | srl $16,1,$1 | |
2449 | and $16,1,$2 | |
2450 | cmplt $16,0,$3 | |
2451 | or $1,$2,$2 | |
2452 | cmovge $16,$16,$2 | |
2453 | itoft $3,$f10 | |
2454 | itoft $2,$f11 | |
2455 | cvtqs $f11,$f11 | |
2456 | adds $f11,$f11,$f0 | |
2457 | fcmoveq $f10,$f11,$f0 | |
2458 | ||
2459 | I'm not using it because it's the same number of instructions as | |
2460 | this branch-full form, and it has more serialized long latency | |
2461 | instructions on the critical path. | |
2462 | ||
2463 | For DFmode, we can avoid rounding errors by breaking up the word | |
2464 | into two pieces, converting them separately, and adding them back: | |
2465 | ||
2466 | LC0: .long 0,0x5f800000 | |
2467 | ||
2468 | itoft $16,$f11 | |
2469 | lda $2,LC0 | |
093c0196 | 2470 | cmplt $16,0,$1 |
2a42ba09 | 2471 | cpyse $f11,$f31,$f10 |
2472 | cpyse $f31,$f11,$f11 | |
2473 | s4addq $1,$2,$1 | |
2474 | lds $f12,0($1) | |
2475 | cvtqt $f10,$f10 | |
2476 | cvtqt $f11,$f11 | |
2477 | addt $f12,$f10,$f0 | |
2478 | addt $f0,$f11,$f0 | |
2479 | ||
2480 | This doesn't seem to be a clear-cut win over the optabs form. | |
2481 | It probably all depends on the distribution of numbers being | |
2482 | converted -- in the optabs form, all but high-bit-set has a | |
2483 | much lower minimum execution time. */ | |
2484 | ||
2485 | void | |
92643d95 | 2486 | alpha_emit_floatuns (rtx operands[2]) |
2a42ba09 | 2487 | { |
2488 | rtx neglab, donelab, i0, i1, f0, in, out; | |
3754d046 | 2489 | machine_mode mode; |
2a42ba09 | 2490 | |
2491 | out = operands[0]; | |
8e2025b4 | 2492 | in = force_reg (DImode, operands[1]); |
2a42ba09 | 2493 | mode = GET_MODE (out); |
2494 | neglab = gen_label_rtx (); | |
2495 | donelab = gen_label_rtx (); | |
2496 | i0 = gen_reg_rtx (DImode); | |
2497 | i1 = gen_reg_rtx (DImode); | |
2498 | f0 = gen_reg_rtx (mode); | |
2499 | ||
7e69f45b | 2500 | emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab); |
2a42ba09 | 2501 | |
d1f9b275 | 2502 | emit_insn (gen_rtx_SET (out, gen_rtx_FLOAT (mode, in))); |
2a42ba09 | 2503 | emit_jump_insn (gen_jump (donelab)); |
093c0196 | 2504 | emit_barrier (); |
2a42ba09 | 2505 | |
2506 | emit_label (neglab); | |
2507 | ||
2508 | emit_insn (gen_lshrdi3 (i0, in, const1_rtx)); | |
2509 | emit_insn (gen_anddi3 (i1, in, const1_rtx)); | |
2510 | emit_insn (gen_iordi3 (i0, i0, i1)); | |
d1f9b275 | 2511 | emit_insn (gen_rtx_SET (f0, gen_rtx_FLOAT (mode, i0))); |
2512 | emit_insn (gen_rtx_SET (out, gen_rtx_PLUS (mode, f0, f0))); | |
2a42ba09 | 2513 | |
2514 | emit_label (donelab); | |
2515 | } | |
2516 | ||
3a2a3a7f | 2517 | /* Generate the comparison for a conditional branch. */ |
2518 | ||
74f4459c | 2519 | void |
3754d046 | 2520 | alpha_emit_conditional_branch (rtx operands[], machine_mode cmp_mode) |
3a2a3a7f | 2521 | { |
2522 | enum rtx_code cmp_code, branch_code; | |
3754d046 | 2523 | machine_mode branch_mode = VOIDmode; |
74f4459c | 2524 | enum rtx_code code = GET_CODE (operands[0]); |
2525 | rtx op0 = operands[1], op1 = operands[2]; | |
3a2a3a7f | 2526 | rtx tem; |
2527 | ||
74f4459c | 2528 | if (cmp_mode == TFmode) |
915c336f | 2529 | { |
8c3428a6 | 2530 | op0 = alpha_emit_xfloating_compare (&code, op0, op1); |
915c336f | 2531 | op1 = const0_rtx; |
74f4459c | 2532 | cmp_mode = DImode; |
915c336f | 2533 | } |
2534 | ||
3a2a3a7f | 2535 | /* The general case: fold the comparison code to the types of compares |
2536 | that we have, choosing the branch as necessary. */ | |
2537 | switch (code) | |
2538 | { | |
2539 | case EQ: case LE: case LT: case LEU: case LTU: | |
a4110d9a | 2540 | case UNORDERED: |
c4d3c065 | 2541 | /* We have these compares. */ |
3a2a3a7f | 2542 | cmp_code = code, branch_code = NE; |
2543 | break; | |
2544 | ||
2545 | case NE: | |
a4110d9a | 2546 | case ORDERED: |
65abff06 | 2547 | /* These must be reversed. */ |
a4110d9a | 2548 | cmp_code = reverse_condition (code), branch_code = EQ; |
3a2a3a7f | 2549 | break; |
2550 | ||
2551 | case GE: case GT: case GEU: case GTU: | |
2552 | /* For FP, we swap them, for INT, we reverse them. */ | |
74f4459c | 2553 | if (cmp_mode == DFmode) |
3a2a3a7f | 2554 | { |
2555 | cmp_code = swap_condition (code); | |
2556 | branch_code = NE; | |
612bd519 | 2557 | std::swap (op0, op1); |
3a2a3a7f | 2558 | } |
2559 | else | |
2560 | { | |
2561 | cmp_code = reverse_condition (code); | |
2562 | branch_code = EQ; | |
2563 | } | |
2564 | break; | |
2565 | ||
2566 | default: | |
4d10b463 | 2567 | gcc_unreachable (); |
3a2a3a7f | 2568 | } |
2569 | ||
74f4459c | 2570 | if (cmp_mode == DFmode) |
3a2a3a7f | 2571 | { |
70ce4162 | 2572 | if (flag_unsafe_math_optimizations && cmp_code != UNORDERED) |
3a2a3a7f | 2573 | { |
2574 | /* When we are not as concerned about non-finite values, and we | |
2575 | are comparing against zero, we can branch directly. */ | |
2576 | if (op1 == CONST0_RTX (DFmode)) | |
21f1e711 | 2577 | cmp_code = UNKNOWN, branch_code = code; |
3a2a3a7f | 2578 | else if (op0 == CONST0_RTX (DFmode)) |
2579 | { | |
2580 | /* Undo the swap we probably did just above. */ | |
612bd519 | 2581 | std::swap (op0, op1); |
4899654e | 2582 | branch_code = swap_condition (cmp_code); |
21f1e711 | 2583 | cmp_code = UNKNOWN; |
3a2a3a7f | 2584 | } |
2585 | } | |
2586 | else | |
2587 | { | |
d30e015b | 2588 | /* ??? We mark the branch mode to be CCmode to prevent the |
9e7454d0 | 2589 | compare and branch from being combined, since the compare |
3a2a3a7f | 2590 | insn follows IEEE rules that the branch does not. */ |
2591 | branch_mode = CCmode; | |
2592 | } | |
2593 | } | |
2594 | else | |
2595 | { | |
3a2a3a7f | 2596 | /* The following optimizations are only for signed compares. */ |
2597 | if (code != LEU && code != LTU && code != GEU && code != GTU) | |
2598 | { | |
2599 | /* Whee. Compare and branch against 0 directly. */ | |
2600 | if (op1 == const0_rtx) | |
21f1e711 | 2601 | cmp_code = UNKNOWN, branch_code = code; |
3a2a3a7f | 2602 | |
3a2f3420 | 2603 | /* If the constants doesn't fit into an immediate, but can |
2604 | be generated by lda/ldah, we adjust the argument and | |
2605 | compare against zero, so we can use beq/bne directly. */ | |
62350d6c | 2606 | /* ??? Don't do this when comparing against symbols, otherwise |
2607 | we'll reduce (&x == 0x1234) to (&x-0x1234 == 0), which will | |
2608 | be declared false out of hand (at least for non-weak). */ | |
c933fb42 | 2609 | else if (CONST_INT_P (op1) |
62350d6c | 2610 | && (code == EQ || code == NE) |
2611 | && !(symbolic_operand (op0, VOIDmode) | |
c933fb42 | 2612 | || (REG_P (op0) && REG_POINTER (op0)))) |
3a2a3a7f | 2613 | { |
1dffd068 | 2614 | rtx n_op1 = GEN_INT (-INTVAL (op1)); |
2615 | ||
2616 | if (! satisfies_constraint_I (op1) | |
2617 | && (satisfies_constraint_K (n_op1) | |
2618 | || satisfies_constraint_L (n_op1))) | |
2619 | cmp_code = PLUS, branch_code = code, op1 = n_op1; | |
3a2a3a7f | 2620 | } |
2621 | } | |
3a2a3a7f | 2622 | |
d74ce6fa | 2623 | if (!reg_or_0_operand (op0, DImode)) |
2624 | op0 = force_reg (DImode, op0); | |
2625 | if (cmp_code != PLUS && !reg_or_8bit_operand (op1, DImode)) | |
2626 | op1 = force_reg (DImode, op1); | |
2627 | } | |
3a2a3a7f | 2628 | |
2629 | /* Emit an initial compare instruction, if necessary. */ | |
2630 | tem = op0; | |
21f1e711 | 2631 | if (cmp_code != UNKNOWN) |
3a2a3a7f | 2632 | { |
2633 | tem = gen_reg_rtx (cmp_mode); | |
2634 | emit_move_insn (tem, gen_rtx_fmt_ee (cmp_code, cmp_mode, op0, op1)); | |
2635 | } | |
2636 | ||
74f4459c | 2637 | /* Emit the branch instruction. */ |
d1f9b275 | 2638 | tem = gen_rtx_SET (pc_rtx, |
74f4459c | 2639 | gen_rtx_IF_THEN_ELSE (VOIDmode, |
2640 | gen_rtx_fmt_ee (branch_code, | |
2641 | branch_mode, tem, | |
2642 | CONST0_RTX (cmp_mode)), | |
2643 | gen_rtx_LABEL_REF (VOIDmode, | |
2644 | operands[3]), | |
2645 | pc_rtx)); | |
2646 | emit_jump_insn (tem); | |
3a2a3a7f | 2647 | } |
2648 | ||
d74ce6fa | 2649 | /* Certain simplifications can be done to make invalid setcc operations |
2650 | valid. Return the final comparison, or NULL if we can't work. */ | |
2651 | ||
74f4459c | 2652 | bool |
3754d046 | 2653 | alpha_emit_setcc (rtx operands[], machine_mode cmp_mode) |
d74ce6fa | 2654 | { |
2655 | enum rtx_code cmp_code; | |
74f4459c | 2656 | enum rtx_code code = GET_CODE (operands[1]); |
2657 | rtx op0 = operands[2], op1 = operands[3]; | |
d74ce6fa | 2658 | rtx tmp; |
2659 | ||
74f4459c | 2660 | if (cmp_mode == TFmode) |
d74ce6fa | 2661 | { |
8c3428a6 | 2662 | op0 = alpha_emit_xfloating_compare (&code, op0, op1); |
d74ce6fa | 2663 | op1 = const0_rtx; |
74f4459c | 2664 | cmp_mode = DImode; |
d74ce6fa | 2665 | } |
2666 | ||
74f4459c | 2667 | if (cmp_mode == DFmode && !TARGET_FIX) |
2668 | return 0; | |
d74ce6fa | 2669 | |
2670 | /* The general case: fold the comparison code to the types of compares | |
2671 | that we have, choosing the branch as necessary. */ | |
2672 | ||
21f1e711 | 2673 | cmp_code = UNKNOWN; |
d74ce6fa | 2674 | switch (code) |
2675 | { | |
2676 | case EQ: case LE: case LT: case LEU: case LTU: | |
2677 | case UNORDERED: | |
2678 | /* We have these compares. */ | |
74f4459c | 2679 | if (cmp_mode == DFmode) |
d74ce6fa | 2680 | cmp_code = code, code = NE; |
2681 | break; | |
2682 | ||
2683 | case NE: | |
74f4459c | 2684 | if (cmp_mode == DImode && op1 == const0_rtx) |
d74ce6fa | 2685 | break; |
8e262b5e | 2686 | /* FALLTHRU */ |
d74ce6fa | 2687 | |
2688 | case ORDERED: | |
2689 | cmp_code = reverse_condition (code); | |
2690 | code = EQ; | |
2691 | break; | |
2692 | ||
2693 | case GE: case GT: case GEU: case GTU: | |
75b3314a | 2694 | /* These normally need swapping, but for integer zero we have |
bc882521 | 2695 | special patterns that recognize swapped operands. */ |
74f4459c | 2696 | if (cmp_mode == DImode && op1 == const0_rtx) |
bc882521 | 2697 | break; |
d74ce6fa | 2698 | code = swap_condition (code); |
74f4459c | 2699 | if (cmp_mode == DFmode) |
d74ce6fa | 2700 | cmp_code = code, code = NE; |
612bd519 | 2701 | std::swap (op0, op1); |
d74ce6fa | 2702 | break; |
2703 | ||
2704 | default: | |
4d10b463 | 2705 | gcc_unreachable (); |
d74ce6fa | 2706 | } |
2707 | ||
74f4459c | 2708 | if (cmp_mode == DImode) |
d74ce6fa | 2709 | { |
bc882521 | 2710 | if (!register_operand (op0, DImode)) |
d74ce6fa | 2711 | op0 = force_reg (DImode, op0); |
2712 | if (!reg_or_8bit_operand (op1, DImode)) | |
2713 | op1 = force_reg (DImode, op1); | |
2714 | } | |
2715 | ||
2716 | /* Emit an initial compare instruction, if necessary. */ | |
21f1e711 | 2717 | if (cmp_code != UNKNOWN) |
d74ce6fa | 2718 | { |
74f4459c | 2719 | tmp = gen_reg_rtx (cmp_mode); |
d1f9b275 | 2720 | emit_insn (gen_rtx_SET (tmp, gen_rtx_fmt_ee (cmp_code, cmp_mode, |
2721 | op0, op1))); | |
d74ce6fa | 2722 | |
eb0e7e5d | 2723 | op0 = cmp_mode != DImode ? gen_lowpart (DImode, tmp) : tmp; |
d74ce6fa | 2724 | op1 = const0_rtx; |
2725 | } | |
2726 | ||
74f4459c | 2727 | /* Emit the setcc instruction. */ |
d1f9b275 | 2728 | emit_insn (gen_rtx_SET (operands[0], gen_rtx_fmt_ee (code, DImode, |
2729 | op0, op1))); | |
74f4459c | 2730 | return true; |
d74ce6fa | 2731 | } |
2732 | ||
3a2a3a7f | 2733 | |
996a379d | 2734 | /* Rewrite a comparison against zero CMP of the form |
2735 | (CODE (cc0) (const_int 0)) so it can be written validly in | |
2736 | a conditional move (if_then_else CMP ...). | |
e3e08e7f | 2737 | If both of the operands that set cc0 are nonzero we must emit |
996a379d | 2738 | an insn to perform the compare (it can't be done within |
65abff06 | 2739 | the conditional move). */ |
92643d95 | 2740 | |
996a379d | 2741 | rtx |
3754d046 | 2742 | alpha_emit_conditional_move (rtx cmp, machine_mode mode) |
996a379d | 2743 | { |
23be97c5 | 2744 | enum rtx_code code = GET_CODE (cmp); |
c60bc286 | 2745 | enum rtx_code cmov_code = NE; |
74f4459c | 2746 | rtx op0 = XEXP (cmp, 0); |
2747 | rtx op1 = XEXP (cmp, 1); | |
3754d046 | 2748 | machine_mode cmp_mode |
23be97c5 | 2749 | = (GET_MODE (op0) == VOIDmode ? DImode : GET_MODE (op0)); |
3754d046 | 2750 | machine_mode cmov_mode = VOIDmode; |
7f3be425 | 2751 | int local_fast_math = flag_unsafe_math_optimizations; |
23be97c5 | 2752 | rtx tem; |
996a379d | 2753 | |
a717c371 | 2754 | if (cmp_mode == TFmode) |
2755 | { | |
2756 | op0 = alpha_emit_xfloating_compare (&code, op0, op1); | |
2757 | op1 = const0_rtx; | |
2758 | cmp_mode = DImode; | |
2759 | } | |
2760 | ||
74f4459c | 2761 | gcc_assert (cmp_mode == DFmode || cmp_mode == DImode); |
b18b881f | 2762 | |
74f4459c | 2763 | if (FLOAT_MODE_P (cmp_mode) != FLOAT_MODE_P (mode)) |
d6cc9868 | 2764 | { |
2765 | enum rtx_code cmp_code; | |
2766 | ||
2767 | if (! TARGET_FIX) | |
2768 | return 0; | |
2769 | ||
2770 | /* If we have fp<->int register move instructions, do a cmov by | |
2771 | performing the comparison in fp registers, and move the | |
e3e08e7f | 2772 | zero/nonzero value to integer registers, where we can then |
d6cc9868 | 2773 | use a normal cmov, or vice-versa. */ |
2774 | ||
2775 | switch (code) | |
2776 | { | |
2777 | case EQ: case LE: case LT: case LEU: case LTU: | |
c4d3c065 | 2778 | case UNORDERED: |
d6cc9868 | 2779 | /* We have these compares. */ |
2780 | cmp_code = code, code = NE; | |
2781 | break; | |
2782 | ||
2783 | case NE: | |
c4d3c065 | 2784 | case ORDERED: |
2785 | /* These must be reversed. */ | |
2786 | cmp_code = reverse_condition (code), code = EQ; | |
d6cc9868 | 2787 | break; |
2788 | ||
2789 | case GE: case GT: case GEU: case GTU: | |
75b3314a | 2790 | /* These normally need swapping, but for integer zero we have |
2791 | special patterns that recognize swapped operands. */ | |
74f4459c | 2792 | if (cmp_mode == DImode && op1 == const0_rtx) |
88f8f2a2 | 2793 | cmp_code = code, code = NE; |
2794 | else | |
2795 | { | |
2796 | cmp_code = swap_condition (code); | |
2797 | code = NE; | |
612bd519 | 2798 | std::swap (op0, op1); |
88f8f2a2 | 2799 | } |
d6cc9868 | 2800 | break; |
2801 | ||
2802 | default: | |
4d10b463 | 2803 | gcc_unreachable (); |
d6cc9868 | 2804 | } |
2805 | ||
c4d3c065 | 2806 | if (cmp_mode == DImode) |
2807 | { | |
2808 | if (!reg_or_0_operand (op0, DImode)) | |
2809 | op0 = force_reg (DImode, op0); | |
2810 | if (!reg_or_8bit_operand (op1, DImode)) | |
2811 | op1 = force_reg (DImode, op1); | |
2812 | } | |
2813 | ||
74f4459c | 2814 | tem = gen_reg_rtx (cmp_mode); |
d1f9b275 | 2815 | emit_insn (gen_rtx_SET (tem, gen_rtx_fmt_ee (cmp_code, cmp_mode, |
2816 | op0, op1))); | |
d6cc9868 | 2817 | |
1e0295b9 | 2818 | cmp_mode = cmp_mode == DImode ? E_DFmode : E_DImode; |
74f4459c | 2819 | op0 = gen_lowpart (cmp_mode, tem); |
2820 | op1 = CONST0_RTX (cmp_mode); | |
5da2e28f | 2821 | cmp = gen_rtx_fmt_ee (code, VOIDmode, op0, op1); |
d6cc9868 | 2822 | local_fast_math = 1; |
2823 | } | |
996a379d | 2824 | |
c4d3c065 | 2825 | if (cmp_mode == DImode) |
2826 | { | |
2827 | if (!reg_or_0_operand (op0, DImode)) | |
2828 | op0 = force_reg (DImode, op0); | |
2829 | if (!reg_or_8bit_operand (op1, DImode)) | |
2830 | op1 = force_reg (DImode, op1); | |
2831 | } | |
2832 | ||
996a379d | 2833 | /* We may be able to use a conditional move directly. |
65abff06 | 2834 | This avoids emitting spurious compares. */ |
2a42ba09 | 2835 | if (signed_comparison_operator (cmp, VOIDmode) |
74f4459c | 2836 | && (cmp_mode == DImode || local_fast_math) |
23be97c5 | 2837 | && (op0 == CONST0_RTX (cmp_mode) || op1 == CONST0_RTX (cmp_mode))) |
941522d6 | 2838 | return gen_rtx_fmt_ee (code, VOIDmode, op0, op1); |
996a379d | 2839 | |
3029ee00 | 2840 | /* We can't put the comparison inside the conditional move; |
996a379d | 2841 | emit a compare instruction and put that inside the |
23be97c5 | 2842 | conditional move. Make sure we emit only comparisons we have; |
2843 | swap or reverse as necessary. */ | |
996a379d | 2844 | |
e1ba4a27 | 2845 | if (!can_create_pseudo_p ()) |
3029ee00 | 2846 | return NULL_RTX; |
2847 | ||
996a379d | 2848 | switch (code) |
2849 | { | |
23be97c5 | 2850 | case EQ: case LE: case LT: case LEU: case LTU: |
c4d3c065 | 2851 | case UNORDERED: |
23be97c5 | 2852 | /* We have these compares: */ |
996a379d | 2853 | break; |
23be97c5 | 2854 | |
996a379d | 2855 | case NE: |
c4d3c065 | 2856 | case ORDERED: |
2857 | /* These must be reversed. */ | |
23be97c5 | 2858 | code = reverse_condition (code); |
c60bc286 | 2859 | cmov_code = EQ; |
996a379d | 2860 | break; |
23be97c5 | 2861 | |
2862 | case GE: case GT: case GEU: case GTU: | |
cf1f9f8b | 2863 | /* These normally need swapping, but for integer zero we have |
2864 | special patterns that recognize swapped operands. */ | |
2865 | if (cmp_mode == DImode && op1 == const0_rtx) | |
2866 | break; | |
2867 | code = swap_condition (code); | |
612bd519 | 2868 | std::swap (op0, op1); |
996a379d | 2869 | break; |
23be97c5 | 2870 | |
996a379d | 2871 | default: |
4d10b463 | 2872 | gcc_unreachable (); |
996a379d | 2873 | } |
2874 | ||
74f4459c | 2875 | if (cmp_mode == DImode) |
d74ce6fa | 2876 | { |
2877 | if (!reg_or_0_operand (op0, DImode)) | |
2878 | op0 = force_reg (DImode, op0); | |
2879 | if (!reg_or_8bit_operand (op1, DImode)) | |
2880 | op1 = force_reg (DImode, op1); | |
2881 | } | |
2882 | ||
b9b4428b | 2883 | /* ??? We mark the branch mode to be CCmode to prevent the compare |
3a2a3a7f | 2884 | and cmov from being combined, since the compare insn follows IEEE |
2885 | rules that the cmov does not. */ | |
74f4459c | 2886 | if (cmp_mode == DFmode && !local_fast_math) |
3a2a3a7f | 2887 | cmov_mode = CCmode; |
2888 | ||
74f4459c | 2889 | tem = gen_reg_rtx (cmp_mode); |
2890 | emit_move_insn (tem, gen_rtx_fmt_ee (code, cmp_mode, op0, op1)); | |
2891 | return gen_rtx_fmt_ee (cmov_code, cmov_mode, tem, CONST0_RTX (cmp_mode)); | |
996a379d | 2892 | } |
bbf31a61 | 2893 | |
2894 | /* Simplify a conditional move of two constants into a setcc with | |
2895 | arithmetic. This is done with a splitter since combine would | |
2896 | just undo the work if done during code generation. It also catches | |
2897 | cases we wouldn't have before cse. */ | |
2898 | ||
2899 | int | |
92643d95 | 2900 | alpha_split_conditional_move (enum rtx_code code, rtx dest, rtx cond, |
2901 | rtx t_rtx, rtx f_rtx) | |
bbf31a61 | 2902 | { |
2903 | HOST_WIDE_INT t, f, diff; | |
3754d046 | 2904 | machine_mode mode; |
bbf31a61 | 2905 | rtx target, subtarget, tmp; |
2906 | ||
2907 | mode = GET_MODE (dest); | |
2908 | t = INTVAL (t_rtx); | |
2909 | f = INTVAL (f_rtx); | |
2910 | diff = t - f; | |
2911 | ||
2912 | if (((code == NE || code == EQ) && diff < 0) | |
2913 | || (code == GE || code == GT)) | |
2914 | { | |
2915 | code = reverse_condition (code); | |
3ffb2c20 | 2916 | std::swap (t, f); |
2917 | diff = -diff; | |
bbf31a61 | 2918 | } |
2919 | ||
2920 | subtarget = target = dest; | |
2921 | if (mode != DImode) | |
2922 | { | |
2923 | target = gen_lowpart (DImode, dest); | |
e1ba4a27 | 2924 | if (can_create_pseudo_p ()) |
bbf31a61 | 2925 | subtarget = gen_reg_rtx (DImode); |
2926 | else | |
2927 | subtarget = target; | |
2928 | } | |
64656695 | 2929 | /* Below, we must be careful to use copy_rtx on target and subtarget |
2930 | in intermediate insns, as they may be a subreg rtx, which may not | |
2931 | be shared. */ | |
bbf31a61 | 2932 | |
2933 | if (f == 0 && exact_log2 (diff) > 0 | |
8d232dc7 | 2934 | /* On EV6, we've got enough shifters to make non-arithmetic shifts |
bbf31a61 | 2935 | viable over a longer latency cmove. On EV5, the E0 slot is a |
65abff06 | 2936 | scarce resource, and on EV4 shift has the same latency as a cmove. */ |
fb64edde | 2937 | && (diff <= 8 || alpha_tune == PROCESSOR_EV6)) |
bbf31a61 | 2938 | { |
2939 | tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx); | |
d1f9b275 | 2940 | emit_insn (gen_rtx_SET (copy_rtx (subtarget), tmp)); |
bbf31a61 | 2941 | |
64656695 | 2942 | tmp = gen_rtx_ASHIFT (DImode, copy_rtx (subtarget), |
2943 | GEN_INT (exact_log2 (t))); | |
d1f9b275 | 2944 | emit_insn (gen_rtx_SET (target, tmp)); |
bbf31a61 | 2945 | } |
2946 | else if (f == 0 && t == -1) | |
2947 | { | |
2948 | tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx); | |
d1f9b275 | 2949 | emit_insn (gen_rtx_SET (copy_rtx (subtarget), tmp)); |
bbf31a61 | 2950 | |
64656695 | 2951 | emit_insn (gen_negdi2 (target, copy_rtx (subtarget))); |
bbf31a61 | 2952 | } |
2953 | else if (diff == 1 || diff == 4 || diff == 8) | |
2954 | { | |
2955 | rtx add_op; | |
2956 | ||
2957 | tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx); | |
d1f9b275 | 2958 | emit_insn (gen_rtx_SET (copy_rtx (subtarget), tmp)); |
bbf31a61 | 2959 | |
2960 | if (diff == 1) | |
64656695 | 2961 | emit_insn (gen_adddi3 (target, copy_rtx (subtarget), GEN_INT (f))); |
bbf31a61 | 2962 | else |
2963 | { | |
2964 | add_op = GEN_INT (f); | |
2965 | if (sext_add_operand (add_op, mode)) | |
2966 | { | |
42bbca40 | 2967 | tmp = gen_rtx_ASHIFT (DImode, copy_rtx (subtarget), |
2968 | GEN_INT (exact_log2 (diff))); | |
bbf31a61 | 2969 | tmp = gen_rtx_PLUS (DImode, tmp, add_op); |
d1f9b275 | 2970 | emit_insn (gen_rtx_SET (target, tmp)); |
bbf31a61 | 2971 | } |
2972 | else | |
2973 | return 0; | |
2974 | } | |
2975 | } | |
2976 | else | |
2977 | return 0; | |
2978 | ||
2979 | return 1; | |
2980 | } | |
34377880 | 2981 | \f |
915c336f | 2982 | /* Look up the function X_floating library function name for the |
2983 | given operation. */ | |
2984 | ||
fb1e4f4a | 2985 | struct GTY(()) xfloating_op |
2d7c492e | 2986 | { |
2987 | const enum rtx_code code; | |
7035b2ab | 2988 | const char *const GTY((skip)) osf_func; |
2989 | const char *const GTY((skip)) vms_func; | |
2d7c492e | 2990 | rtx libcall; |
2991 | }; | |
2992 | ||
9e7454d0 | 2993 | static GTY(()) struct xfloating_op xfloating_ops[] = |
2d7c492e | 2994 | { |
2995 | { PLUS, "_OtsAddX", "OTS$ADD_X", 0 }, | |
2996 | { MINUS, "_OtsSubX", "OTS$SUB_X", 0 }, | |
2997 | { MULT, "_OtsMulX", "OTS$MUL_X", 0 }, | |
2998 | { DIV, "_OtsDivX", "OTS$DIV_X", 0 }, | |
2999 | { EQ, "_OtsEqlX", "OTS$EQL_X", 0 }, | |
3000 | { NE, "_OtsNeqX", "OTS$NEQ_X", 0 }, | |
3001 | { LT, "_OtsLssX", "OTS$LSS_X", 0 }, | |
3002 | { LE, "_OtsLeqX", "OTS$LEQ_X", 0 }, | |
3003 | { GT, "_OtsGtrX", "OTS$GTR_X", 0 }, | |
3004 | { GE, "_OtsGeqX", "OTS$GEQ_X", 0 }, | |
3005 | { FIX, "_OtsCvtXQ", "OTS$CVTXQ", 0 }, | |
3006 | { FLOAT, "_OtsCvtQX", "OTS$CVTQX", 0 }, | |
3007 | { UNSIGNED_FLOAT, "_OtsCvtQUX", "OTS$CVTQUX", 0 }, | |
3008 | { FLOAT_EXTEND, "_OtsConvertFloatTX", "OTS$CVT_FLOAT_T_X", 0 }, | |
3009 | { FLOAT_TRUNCATE, "_OtsConvertFloatXT", "OTS$CVT_FLOAT_X_T", 0 } | |
3010 | }; | |
3011 | ||
3012 | static GTY(()) struct xfloating_op vax_cvt_ops[] = | |
3013 | { | |
3014 | { FLOAT_EXTEND, "_OtsConvertFloatGX", "OTS$CVT_FLOAT_G_X", 0 }, | |
3015 | { FLOAT_TRUNCATE, "_OtsConvertFloatXG", "OTS$CVT_FLOAT_X_G", 0 } | |
3016 | }; | |
3017 | ||
3018 | static rtx | |
92643d95 | 3019 | alpha_lookup_xfloating_lib_func (enum rtx_code code) |
915c336f | 3020 | { |
2d7c492e | 3021 | struct xfloating_op *ops = xfloating_ops; |
3022 | long n = ARRAY_SIZE (xfloating_ops); | |
915c336f | 3023 | long i; |
3024 | ||
8c3428a6 | 3025 | gcc_assert (TARGET_HAS_XFLOATING_LIBS); |
3026 | ||
2d7c492e | 3027 | /* How irritating. Nothing to key off for the main table. */ |
3028 | if (TARGET_FLOAT_VAX && (code == FLOAT_EXTEND || code == FLOAT_TRUNCATE)) | |
915c336f | 3029 | { |
2d7c492e | 3030 | ops = vax_cvt_ops; |
3031 | n = ARRAY_SIZE (vax_cvt_ops); | |
915c336f | 3032 | } |
3033 | ||
2d7c492e | 3034 | for (i = 0; i < n; ++i, ++ops) |
3035 | if (ops->code == code) | |
3036 | { | |
3037 | rtx func = ops->libcall; | |
3038 | if (!func) | |
3039 | { | |
3040 | func = init_one_libfunc (TARGET_ABI_OPEN_VMS | |
3041 | ? ops->vms_func : ops->osf_func); | |
3042 | ops->libcall = func; | |
3043 | } | |
3044 | return func; | |
3045 | } | |
915c336f | 3046 | |
4d10b463 | 3047 | gcc_unreachable (); |
915c336f | 3048 | } |
3049 | ||
3050 | /* Most X_floating operations take the rounding mode as an argument. | |
3051 | Compute that here. */ | |
3052 | ||
3053 | static int | |
92643d95 | 3054 | alpha_compute_xfloating_mode_arg (enum rtx_code code, |
3055 | enum alpha_fp_rounding_mode round) | |
915c336f | 3056 | { |
3057 | int mode; | |
3058 | ||
3059 | switch (round) | |
3060 | { | |
3061 | case ALPHA_FPRM_NORM: | |
3062 | mode = 2; | |
3063 | break; | |
3064 | case ALPHA_FPRM_MINF: | |
3065 | mode = 1; | |
3066 | break; | |
3067 | case ALPHA_FPRM_CHOP: | |
3068 | mode = 0; | |
3069 | break; | |
3070 | case ALPHA_FPRM_DYN: | |
3071 | mode = 4; | |
3072 | break; | |
3073 | default: | |
4d10b463 | 3074 | gcc_unreachable (); |
915c336f | 3075 | |
3076 | /* XXX For reference, round to +inf is mode = 3. */ | |
3077 | } | |
3078 | ||
3079 | if (code == FLOAT_TRUNCATE && alpha_fptm == ALPHA_FPTM_N) | |
3080 | mode |= 0x10000; | |
3081 | ||
3082 | return mode; | |
3083 | } | |
3084 | ||
3085 | /* Emit an X_floating library function call. | |
3086 | ||
3087 | Note that these functions do not follow normal calling conventions: | |
3088 | TFmode arguments are passed in two integer registers (as opposed to | |
9e7454d0 | 3089 | indirect); TFmode return values appear in R16+R17. |
915c336f | 3090 | |
2d7c492e | 3091 | FUNC is the function to call. |
915c336f | 3092 | TARGET is where the output belongs. |
3093 | OPERANDS are the inputs. | |
3094 | NOPERANDS is the count of inputs. | |
3095 | EQUIV is the expression equivalent for the function. | |
3096 | */ | |
3097 | ||
3098 | static void | |
2d7c492e | 3099 | alpha_emit_xfloating_libcall (rtx func, rtx target, rtx operands[], |
92643d95 | 3100 | int noperands, rtx equiv) |
915c336f | 3101 | { |
8793a4a1 | 3102 | rtx usage = NULL_RTX, reg; |
915c336f | 3103 | int regno = 16, i; |
3104 | ||
3105 | start_sequence (); | |
3106 | ||
3107 | for (i = 0; i < noperands; ++i) | |
3108 | { | |
3109 | switch (GET_MODE (operands[i])) | |
3110 | { | |
916ace94 | 3111 | case E_TFmode: |
915c336f | 3112 | reg = gen_rtx_REG (TFmode, regno); |
3113 | regno += 2; | |
3114 | break; | |
3115 | ||
916ace94 | 3116 | case E_DFmode: |
915c336f | 3117 | reg = gen_rtx_REG (DFmode, regno + 32); |
3118 | regno += 1; | |
3119 | break; | |
3120 | ||
916ace94 | 3121 | case E_VOIDmode: |
c933fb42 | 3122 | gcc_assert (CONST_INT_P (operands[i])); |
8e262b5e | 3123 | /* FALLTHRU */ |
916ace94 | 3124 | case E_DImode: |
915c336f | 3125 | reg = gen_rtx_REG (DImode, regno); |
3126 | regno += 1; | |
3127 | break; | |
3128 | ||
3129 | default: | |
4d10b463 | 3130 | gcc_unreachable (); |
915c336f | 3131 | } |
3132 | ||
3133 | emit_move_insn (reg, operands[i]); | |
f2606961 | 3134 | use_reg (&usage, reg); |
915c336f | 3135 | } |
3136 | ||
3137 | switch (GET_MODE (target)) | |
3138 | { | |
916ace94 | 3139 | case E_TFmode: |
915c336f | 3140 | reg = gen_rtx_REG (TFmode, 16); |
3141 | break; | |
916ace94 | 3142 | case E_DFmode: |
915c336f | 3143 | reg = gen_rtx_REG (DFmode, 32); |
3144 | break; | |
916ace94 | 3145 | case E_DImode: |
915c336f | 3146 | reg = gen_rtx_REG (DImode, 0); |
3147 | break; | |
3148 | default: | |
4d10b463 | 3149 | gcc_unreachable (); |
915c336f | 3150 | } |
3151 | ||
8793a4a1 | 3152 | rtx mem = gen_rtx_MEM (QImode, func); |
3153 | rtx_insn *tmp = emit_call_insn (gen_call_value (reg, mem, const0_rtx, | |
3154 | const0_rtx, const0_rtx)); | |
915c336f | 3155 | CALL_INSN_FUNCTION_USAGE (tmp) = usage; |
9c2a0c05 | 3156 | RTL_CONST_CALL_P (tmp) = 1; |
915c336f | 3157 | |
3158 | tmp = get_insns (); | |
3159 | end_sequence (); | |
3160 | ||
3161 | emit_libcall_block (tmp, target, reg, equiv); | |
3162 | } | |
3163 | ||
3164 | /* Emit an X_floating library function call for arithmetic (+,-,*,/). */ | |
3165 | ||
3166 | void | |
92643d95 | 3167 | alpha_emit_xfloating_arith (enum rtx_code code, rtx operands[]) |
915c336f | 3168 | { |
2d7c492e | 3169 | rtx func; |
915c336f | 3170 | int mode; |
b90b6519 | 3171 | rtx out_operands[3]; |
915c336f | 3172 | |
3173 | func = alpha_lookup_xfloating_lib_func (code); | |
3174 | mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm); | |
3175 | ||
b90b6519 | 3176 | out_operands[0] = operands[1]; |
3177 | out_operands[1] = operands[2]; | |
3178 | out_operands[2] = GEN_INT (mode); | |
9e7454d0 | 3179 | alpha_emit_xfloating_libcall (func, operands[0], out_operands, 3, |
915c336f | 3180 | gen_rtx_fmt_ee (code, TFmode, operands[1], |
3181 | operands[2])); | |
3182 | } | |
3183 | ||
3184 | /* Emit an X_floating library function call for a comparison. */ | |
3185 | ||
3186 | static rtx | |
8c3428a6 | 3187 | alpha_emit_xfloating_compare (enum rtx_code *pcode, rtx op0, rtx op1) |
915c336f | 3188 | { |
8c3428a6 | 3189 | enum rtx_code cmp_code, res_code; |
e8e27646 | 3190 | rtx func, out, operands[2], note; |
915c336f | 3191 | |
8c3428a6 | 3192 | /* X_floating library comparison functions return |
3193 | -1 unordered | |
3194 | 0 false | |
3195 | 1 true | |
3196 | Convert the compare against the raw return value. */ | |
3197 | ||
3198 | cmp_code = *pcode; | |
3199 | switch (cmp_code) | |
3200 | { | |
3201 | case UNORDERED: | |
3202 | cmp_code = EQ; | |
3203 | res_code = LT; | |
3204 | break; | |
3205 | case ORDERED: | |
3206 | cmp_code = EQ; | |
3207 | res_code = GE; | |
3208 | break; | |
3209 | case NE: | |
3210 | res_code = NE; | |
3211 | break; | |
3212 | case EQ: | |
3213 | case LT: | |
3214 | case GT: | |
3215 | case LE: | |
3216 | case GE: | |
3217 | res_code = GT; | |
3218 | break; | |
3219 | default: | |
3220 | gcc_unreachable (); | |
3221 | } | |
3222 | *pcode = res_code; | |
3223 | ||
3224 | func = alpha_lookup_xfloating_lib_func (cmp_code); | |
915c336f | 3225 | |
3226 | operands[0] = op0; | |
3227 | operands[1] = op1; | |
3228 | out = gen_reg_rtx (DImode); | |
3229 | ||
8ebff8a4 | 3230 | /* What's actually returned is -1,0,1, not a proper boolean value. */ |
ad94304e | 3231 | note = gen_rtx_fmt_ee (cmp_code, VOIDmode, op0, op1); |
3232 | note = gen_rtx_UNSPEC (DImode, gen_rtvec (1, note), UNSPEC_XFLT_COMPARE); | |
e8e27646 | 3233 | alpha_emit_xfloating_libcall (func, out, operands, 2, note); |
915c336f | 3234 | |
3235 | return out; | |
3236 | } | |
3237 | ||
3238 | /* Emit an X_floating library function call for a conversion. */ | |
3239 | ||
3240 | void | |
caf6f044 | 3241 | alpha_emit_xfloating_cvt (enum rtx_code orig_code, rtx operands[]) |
915c336f | 3242 | { |
3243 | int noperands = 1, mode; | |
b90b6519 | 3244 | rtx out_operands[2]; |
2d7c492e | 3245 | rtx func; |
caf6f044 | 3246 | enum rtx_code code = orig_code; |
3247 | ||
3248 | if (code == UNSIGNED_FIX) | |
3249 | code = FIX; | |
915c336f | 3250 | |
3251 | func = alpha_lookup_xfloating_lib_func (code); | |
3252 | ||
b90b6519 | 3253 | out_operands[0] = operands[1]; |
3254 | ||
915c336f | 3255 | switch (code) |
3256 | { | |
3257 | case FIX: | |
3258 | mode = alpha_compute_xfloating_mode_arg (code, ALPHA_FPRM_CHOP); | |
b90b6519 | 3259 | out_operands[1] = GEN_INT (mode); |
8581412d | 3260 | noperands = 2; |
915c336f | 3261 | break; |
3262 | case FLOAT_TRUNCATE: | |
3263 | mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm); | |
b90b6519 | 3264 | out_operands[1] = GEN_INT (mode); |
8581412d | 3265 | noperands = 2; |
915c336f | 3266 | break; |
3267 | default: | |
3268 | break; | |
3269 | } | |
3270 | ||
b90b6519 | 3271 | alpha_emit_xfloating_libcall (func, operands[0], out_operands, noperands, |
caf6f044 | 3272 | gen_rtx_fmt_e (orig_code, |
3273 | GET_MODE (operands[0]), | |
915c336f | 3274 | operands[1])); |
3275 | } | |
3420680b | 3276 | |
10c77d2b | 3277 | /* Split a TImode or TFmode move from OP[1] to OP[0] into a pair of |
3278 | DImode moves from OP[2,3] to OP[0,1]. If FIXUP_OVERLAP is true, | |
3279 | guarantee that the sequence | |
3280 | set (OP[0] OP[2]) | |
3281 | set (OP[1] OP[3]) | |
3282 | is valid. Naturally, output operand ordering is little-endian. | |
3283 | This is used by *movtf_internal and *movti_internal. */ | |
3284 | ||
3420680b | 3285 | void |
3754d046 | 3286 | alpha_split_tmode_pair (rtx operands[4], machine_mode mode, |
10c77d2b | 3287 | bool fixup_overlap) |
3420680b | 3288 | { |
4d10b463 | 3289 | switch (GET_CODE (operands[1])) |
3420680b | 3290 | { |
4d10b463 | 3291 | case REG: |
3420680b | 3292 | operands[3] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1); |
3293 | operands[2] = gen_rtx_REG (DImode, REGNO (operands[1])); | |
4d10b463 | 3294 | break; |
3295 | ||
3296 | case MEM: | |
e513d163 | 3297 | operands[3] = adjust_address (operands[1], DImode, 8); |
3298 | operands[2] = adjust_address (operands[1], DImode, 0); | |
4d10b463 | 3299 | break; |
3300 | ||
7bc95bfb | 3301 | CASE_CONST_SCALAR_INT: |
e4a93d80 | 3302 | case CONST_DOUBLE: |
10c77d2b | 3303 | gcc_assert (operands[1] == CONST0_RTX (mode)); |
4d10b463 | 3304 | operands[2] = operands[3] = const0_rtx; |
3305 | break; | |
3306 | ||
3307 | default: | |
3308 | gcc_unreachable (); | |
3420680b | 3309 | } |
3420680b | 3310 | |
4d10b463 | 3311 | switch (GET_CODE (operands[0])) |
3420680b | 3312 | { |
4d10b463 | 3313 | case REG: |
3420680b | 3314 | operands[1] = gen_rtx_REG (DImode, REGNO (operands[0]) + 1); |
3315 | operands[0] = gen_rtx_REG (DImode, REGNO (operands[0])); | |
4d10b463 | 3316 | break; |
3317 | ||
3318 | case MEM: | |
e513d163 | 3319 | operands[1] = adjust_address (operands[0], DImode, 8); |
3320 | operands[0] = adjust_address (operands[0], DImode, 0); | |
4d10b463 | 3321 | break; |
3322 | ||
3323 | default: | |
3324 | gcc_unreachable (); | |
3420680b | 3325 | } |
10c77d2b | 3326 | |
3327 | if (fixup_overlap && reg_overlap_mentioned_p (operands[0], operands[3])) | |
3328 | { | |
612bd519 | 3329 | std::swap (operands[0], operands[1]); |
3330 | std::swap (operands[2], operands[3]); | |
10c77d2b | 3331 | } |
3420680b | 3332 | } |
2267ca84 | 3333 | |
9e7454d0 | 3334 | /* Implement negtf2 or abstf2. Op0 is destination, op1 is source, |
3335 | op2 is a register containing the sign bit, operation is the | |
2267ca84 | 3336 | logical operation to be performed. */ |
3337 | ||
3338 | void | |
92643d95 | 3339 | alpha_split_tfmode_frobsign (rtx operands[3], rtx (*operation) (rtx, rtx, rtx)) |
2267ca84 | 3340 | { |
3341 | rtx high_bit = operands[2]; | |
3342 | rtx scratch; | |
3343 | int move; | |
3344 | ||
10c77d2b | 3345 | alpha_split_tmode_pair (operands, TFmode, false); |
2267ca84 | 3346 | |
e3e08e7f | 3347 | /* Detect three flavors of operand overlap. */ |
2267ca84 | 3348 | move = 1; |
3349 | if (rtx_equal_p (operands[0], operands[2])) | |
3350 | move = 0; | |
3351 | else if (rtx_equal_p (operands[1], operands[2])) | |
3352 | { | |
3353 | if (rtx_equal_p (operands[0], high_bit)) | |
3354 | move = 2; | |
3355 | else | |
3356 | move = -1; | |
3357 | } | |
3358 | ||
3359 | if (move < 0) | |
3360 | emit_move_insn (operands[0], operands[2]); | |
3361 | ||
3362 | /* ??? If the destination overlaps both source tf and high_bit, then | |
3363 | assume source tf is dead in its entirety and use the other half | |
3364 | for a scratch register. Otherwise "scratch" is just the proper | |
3365 | destination register. */ | |
3366 | scratch = operands[move < 2 ? 1 : 3]; | |
3367 | ||
3368 | emit_insn ((*operation) (scratch, high_bit, operands[3])); | |
3369 | ||
3370 | if (move > 0) | |
3371 | { | |
3372 | emit_move_insn (operands[0], operands[2]); | |
3373 | if (move > 1) | |
3374 | emit_move_insn (operands[1], scratch); | |
3375 | } | |
3376 | } | |
915c336f | 3377 | \f |
34377880 | 3378 | /* Use ext[wlq][lh] as the Architecture Handbook describes for extracting |
3379 | unaligned data: | |
3380 | ||
3381 | unsigned: signed: | |
3382 | word: ldq_u r1,X(r11) ldq_u r1,X(r11) | |
3383 | ldq_u r2,X+1(r11) ldq_u r2,X+1(r11) | |
3384 | lda r3,X(r11) lda r3,X+2(r11) | |
3385 | extwl r1,r3,r1 extql r1,r3,r1 | |
3386 | extwh r2,r3,r2 extqh r2,r3,r2 | |
3387 | or r1.r2.r1 or r1,r2,r1 | |
3388 | sra r1,48,r1 | |
3389 | ||
3390 | long: ldq_u r1,X(r11) ldq_u r1,X(r11) | |
3391 | ldq_u r2,X+3(r11) ldq_u r2,X+3(r11) | |
3392 | lda r3,X(r11) lda r3,X(r11) | |
3393 | extll r1,r3,r1 extll r1,r3,r1 | |
3394 | extlh r2,r3,r2 extlh r2,r3,r2 | |
3395 | or r1.r2.r1 addl r1,r2,r1 | |
3396 | ||
3397 | quad: ldq_u r1,X(r11) | |
3398 | ldq_u r2,X+7(r11) | |
3399 | lda r3,X(r11) | |
3400 | extql r1,r3,r1 | |
3401 | extqh r2,r3,r2 | |
3402 | or r1.r2.r1 | |
3403 | */ | |
3404 | ||
3405 | void | |
92643d95 | 3406 | alpha_expand_unaligned_load (rtx tgt, rtx mem, HOST_WIDE_INT size, |
3407 | HOST_WIDE_INT ofs, int sign) | |
34377880 | 3408 | { |
1f0ce6a6 | 3409 | rtx meml, memh, addr, extl, exth, tmp, mema; |
3754d046 | 3410 | machine_mode mode; |
34377880 | 3411 | |
9467fa25 | 3412 | if (TARGET_BWX && size == 2) |
3413 | { | |
b83bea6c | 3414 | meml = adjust_address (mem, QImode, ofs); |
3415 | memh = adjust_address (mem, QImode, ofs+1); | |
9467fa25 | 3416 | extl = gen_reg_rtx (DImode); |
3417 | exth = gen_reg_rtx (DImode); | |
3418 | emit_insn (gen_zero_extendqidi2 (extl, meml)); | |
3419 | emit_insn (gen_zero_extendqidi2 (exth, memh)); | |
3420 | exth = expand_simple_binop (DImode, ASHIFT, exth, GEN_INT (8), | |
3421 | NULL, 1, OPTAB_LIB_WIDEN); | |
3422 | addr = expand_simple_binop (DImode, IOR, extl, exth, | |
3423 | NULL, 1, OPTAB_LIB_WIDEN); | |
3424 | ||
3425 | if (sign && GET_MODE (tgt) != HImode) | |
3426 | { | |
3427 | addr = gen_lowpart (HImode, addr); | |
3428 | emit_insn (gen_extend_insn (tgt, addr, GET_MODE (tgt), HImode, 0)); | |
3429 | } | |
3430 | else | |
3431 | { | |
3432 | if (GET_MODE (tgt) != DImode) | |
3433 | addr = gen_lowpart (GET_MODE (tgt), addr); | |
3434 | emit_move_insn (tgt, addr); | |
3435 | } | |
3436 | return; | |
3437 | } | |
3438 | ||
34377880 | 3439 | meml = gen_reg_rtx (DImode); |
3440 | memh = gen_reg_rtx (DImode); | |
3441 | addr = gen_reg_rtx (DImode); | |
3442 | extl = gen_reg_rtx (DImode); | |
3443 | exth = gen_reg_rtx (DImode); | |
3444 | ||
1f0ce6a6 | 3445 | mema = XEXP (mem, 0); |
3446 | if (GET_CODE (mema) == LO_SUM) | |
3447 | mema = force_reg (Pmode, mema); | |
3448 | ||
3024e9f8 | 3449 | /* AND addresses cannot be in any alias set, since they may implicitly |
9e7454d0 | 3450 | alias surrounding code. Ideally we'd have some alias set that |
3024e9f8 | 3451 | covered all types except those with alignment 8 or higher. */ |
3452 | ||
3453 | tmp = change_address (mem, DImode, | |
9e7454d0 | 3454 | gen_rtx_AND (DImode, |
29c05e22 | 3455 | plus_constant (DImode, mema, ofs), |
3024e9f8 | 3456 | GEN_INT (-8))); |
ab6ab77e | 3457 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3458 | emit_move_insn (meml, tmp); |
3459 | ||
3460 | tmp = change_address (mem, DImode, | |
9e7454d0 | 3461 | gen_rtx_AND (DImode, |
29c05e22 | 3462 | plus_constant (DImode, mema, |
3463 | ofs + size - 1), | |
3024e9f8 | 3464 | GEN_INT (-8))); |
ab6ab77e | 3465 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3466 | emit_move_insn (memh, tmp); |
34377880 | 3467 | |
9bab4302 | 3468 | if (sign && size == 2) |
34377880 | 3469 | { |
29c05e22 | 3470 | emit_move_insn (addr, plus_constant (Pmode, mema, ofs+2)); |
34377880 | 3471 | |
7a20d8cd | 3472 | emit_insn (gen_extql (extl, meml, addr)); |
9bab4302 | 3473 | emit_insn (gen_extqh (exth, memh, addr)); |
34377880 | 3474 | |
ba4a7733 | 3475 | /* We must use tgt here for the target. Alpha-vms port fails if we use |
3476 | addr for the target, because addr is marked as a pointer and combine | |
85c36fd1 | 3477 | knows that pointers are always sign-extended 32-bit values. */ |
ba4a7733 | 3478 | addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN); |
9e7454d0 | 3479 | addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (48), |
2cc46ade | 3480 | addr, 1, OPTAB_WIDEN); |
34377880 | 3481 | } |
2cc46ade | 3482 | else |
34377880 | 3483 | { |
29c05e22 | 3484 | emit_move_insn (addr, plus_constant (Pmode, mema, ofs)); |
9bab4302 | 3485 | emit_insn (gen_extxl (extl, meml, GEN_INT (size*8), addr)); |
3486 | switch ((int) size) | |
9caef960 | 3487 | { |
9bab4302 | 3488 | case 2: |
3489 | emit_insn (gen_extwh (exth, memh, addr)); | |
3490 | mode = HImode; | |
3491 | break; | |
9bab4302 | 3492 | case 4: |
3493 | emit_insn (gen_extlh (exth, memh, addr)); | |
3494 | mode = SImode; | |
3495 | break; | |
9bab4302 | 3496 | case 8: |
3497 | emit_insn (gen_extqh (exth, memh, addr)); | |
3498 | mode = DImode; | |
3499 | break; | |
9bab4302 | 3500 | default: |
3501 | gcc_unreachable (); | |
2cc46ade | 3502 | } |
3503 | ||
3504 | addr = expand_binop (mode, ior_optab, gen_lowpart (mode, extl), | |
3505 | gen_lowpart (mode, exth), gen_lowpart (mode, tgt), | |
3506 | sign, OPTAB_WIDEN); | |
34377880 | 3507 | } |
3508 | ||
2cc46ade | 3509 | if (addr != tgt) |
9467fa25 | 3510 | emit_move_insn (tgt, gen_lowpart (GET_MODE (tgt), addr)); |
34377880 | 3511 | } |
3512 | ||
3513 | /* Similarly, use ins and msk instructions to perform unaligned stores. */ | |
3514 | ||
3515 | void | |
92643d95 | 3516 | alpha_expand_unaligned_store (rtx dst, rtx src, |
3517 | HOST_WIDE_INT size, HOST_WIDE_INT ofs) | |
34377880 | 3518 | { |
1f0ce6a6 | 3519 | rtx dstl, dsth, addr, insl, insh, meml, memh, dsta; |
9e7454d0 | 3520 | |
9467fa25 | 3521 | if (TARGET_BWX && size == 2) |
3522 | { | |
3523 | if (src != const0_rtx) | |
3524 | { | |
3525 | dstl = gen_lowpart (QImode, src); | |
3526 | dsth = expand_simple_binop (DImode, LSHIFTRT, src, GEN_INT (8), | |
3527 | NULL, 1, OPTAB_LIB_WIDEN); | |
3528 | dsth = gen_lowpart (QImode, dsth); | |
3529 | } | |
3530 | else | |
3531 | dstl = dsth = const0_rtx; | |
3532 | ||
b83bea6c | 3533 | meml = adjust_address (dst, QImode, ofs); |
3534 | memh = adjust_address (dst, QImode, ofs+1); | |
9467fa25 | 3535 | |
3536 | emit_move_insn (meml, dstl); | |
3537 | emit_move_insn (memh, dsth); | |
3538 | return; | |
3539 | } | |
3540 | ||
34377880 | 3541 | dstl = gen_reg_rtx (DImode); |
3542 | dsth = gen_reg_rtx (DImode); | |
3543 | insl = gen_reg_rtx (DImode); | |
3544 | insh = gen_reg_rtx (DImode); | |
3545 | ||
1f0ce6a6 | 3546 | dsta = XEXP (dst, 0); |
3547 | if (GET_CODE (dsta) == LO_SUM) | |
3548 | dsta = force_reg (Pmode, dsta); | |
3549 | ||
3024e9f8 | 3550 | /* AND addresses cannot be in any alias set, since they may implicitly |
9e7454d0 | 3551 | alias surrounding code. Ideally we'd have some alias set that |
3024e9f8 | 3552 | covered all types except those with alignment 8 or higher. */ |
3553 | ||
34377880 | 3554 | meml = change_address (dst, DImode, |
9e7454d0 | 3555 | gen_rtx_AND (DImode, |
29c05e22 | 3556 | plus_constant (DImode, dsta, ofs), |
941522d6 | 3557 | GEN_INT (-8))); |
ab6ab77e | 3558 | set_mem_alias_set (meml, 0); |
3024e9f8 | 3559 | |
34377880 | 3560 | memh = change_address (dst, DImode, |
9e7454d0 | 3561 | gen_rtx_AND (DImode, |
29c05e22 | 3562 | plus_constant (DImode, dsta, |
3563 | ofs + size - 1), | |
941522d6 | 3564 | GEN_INT (-8))); |
ab6ab77e | 3565 | set_mem_alias_set (memh, 0); |
34377880 | 3566 | |
3567 | emit_move_insn (dsth, memh); | |
3568 | emit_move_insn (dstl, meml); | |
9caef960 | 3569 | |
29c05e22 | 3570 | addr = copy_addr_to_reg (plus_constant (Pmode, dsta, ofs)); |
9bab4302 | 3571 | |
3572 | if (src != CONST0_RTX (GET_MODE (src))) | |
3573 | { | |
3574 | emit_insn (gen_insxh (insh, gen_lowpart (DImode, src), | |
3575 | GEN_INT (size*8), addr)); | |
34377880 | 3576 | |
29768226 | 3577 | switch ((int) size) |
34377880 | 3578 | { |
3579 | case 2: | |
9bab4302 | 3580 | emit_insn (gen_inswl (insl, gen_lowpart (HImode, src), addr)); |
34377880 | 3581 | break; |
3582 | case 4: | |
9bab4302 | 3583 | emit_insn (gen_insll (insl, gen_lowpart (SImode, src), addr)); |
3584 | break; | |
ae4cd3a5 | 3585 | case 8: |
9bab4302 | 3586 | emit_insn (gen_insql (insl, gen_lowpart (DImode, src), addr)); |
34377880 | 3587 | break; |
9bab4302 | 3588 | default: |
3589 | gcc_unreachable (); | |
34377880 | 3590 | } |
3591 | } | |
9caef960 | 3592 | |
9bab4302 | 3593 | emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr)); |
9caef960 | 3594 | |
9bab4302 | 3595 | switch ((int) size) |
3596 | { | |
3597 | case 2: | |
7a20d8cd | 3598 | emit_insn (gen_mskwl (dstl, dstl, addr)); |
9bab4302 | 3599 | break; |
3600 | case 4: | |
7a20d8cd | 3601 | emit_insn (gen_mskll (dstl, dstl, addr)); |
3602 | break; | |
9bab4302 | 3603 | case 8: |
7a20d8cd | 3604 | emit_insn (gen_mskql (dstl, dstl, addr)); |
9bab4302 | 3605 | break; |
3606 | default: | |
3607 | gcc_unreachable (); | |
34377880 | 3608 | } |
3609 | ||
b739144f | 3610 | if (src != CONST0_RTX (GET_MODE (src))) |
34377880 | 3611 | { |
2cc46ade | 3612 | dsth = expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN); |
3613 | dstl = expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN); | |
34377880 | 3614 | } |
9e7454d0 | 3615 | |
9bab4302 | 3616 | /* Must store high before low for degenerate case of aligned. */ |
3617 | emit_move_insn (memh, dsth); | |
3618 | emit_move_insn (meml, dstl); | |
34377880 | 3619 | } |
3620 | ||
2cc46ade | 3621 | /* The block move code tries to maximize speed by separating loads and |
3622 | stores at the expense of register pressure: we load all of the data | |
3623 | before we store it back out. There are two secondary effects worth | |
3624 | mentioning, that this speeds copying to/from aligned and unaligned | |
3625 | buffers, and that it makes the code significantly easier to write. */ | |
34377880 | 3626 | |
2cc46ade | 3627 | #define MAX_MOVE_WORDS 8 |
3628 | ||
3629 | /* Load an integral number of consecutive unaligned quadwords. */ | |
34377880 | 3630 | |
3631 | static void | |
92643d95 | 3632 | alpha_expand_unaligned_load_words (rtx *out_regs, rtx smem, |
3633 | HOST_WIDE_INT words, HOST_WIDE_INT ofs) | |
34377880 | 3634 | { |
3635 | rtx const im8 = GEN_INT (-8); | |
2cc46ade | 3636 | rtx ext_tmps[MAX_MOVE_WORDS], data_regs[MAX_MOVE_WORDS+1]; |
1f0ce6a6 | 3637 | rtx sreg, areg, tmp, smema; |
34377880 | 3638 | HOST_WIDE_INT i; |
3639 | ||
1f0ce6a6 | 3640 | smema = XEXP (smem, 0); |
3641 | if (GET_CODE (smema) == LO_SUM) | |
3642 | smema = force_reg (Pmode, smema); | |
3643 | ||
34377880 | 3644 | /* Generate all the tmp registers we need. */ |
3645 | for (i = 0; i < words; ++i) | |
2cc46ade | 3646 | { |
3647 | data_regs[i] = out_regs[i]; | |
3648 | ext_tmps[i] = gen_reg_rtx (DImode); | |
3649 | } | |
3650 | data_regs[words] = gen_reg_rtx (DImode); | |
3651 | ||
3652 | if (ofs != 0) | |
e513d163 | 3653 | smem = adjust_address (smem, GET_MODE (smem), ofs); |
9e7454d0 | 3654 | |
34377880 | 3655 | /* Load up all of the source data. */ |
3656 | for (i = 0; i < words; ++i) | |
3657 | { | |
3024e9f8 | 3658 | tmp = change_address (smem, DImode, |
3659 | gen_rtx_AND (DImode, | |
29c05e22 | 3660 | plus_constant (DImode, smema, 8*i), |
3024e9f8 | 3661 | im8)); |
ab6ab77e | 3662 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3663 | emit_move_insn (data_regs[i], tmp); |
34377880 | 3664 | } |
3024e9f8 | 3665 | |
3666 | tmp = change_address (smem, DImode, | |
3667 | gen_rtx_AND (DImode, | |
29c05e22 | 3668 | plus_constant (DImode, smema, |
3669 | 8*words - 1), | |
3024e9f8 | 3670 | im8)); |
ab6ab77e | 3671 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3672 | emit_move_insn (data_regs[words], tmp); |
34377880 | 3673 | |
3674 | /* Extract the half-word fragments. Unfortunately DEC decided to make | |
9e7454d0 | 3675 | extxh with offset zero a noop instead of zeroing the register, so |
34377880 | 3676 | we must take care of that edge condition ourselves with cmov. */ |
3677 | ||
1f0ce6a6 | 3678 | sreg = copy_addr_to_reg (smema); |
9e7454d0 | 3679 | areg = expand_binop (DImode, and_optab, sreg, GEN_INT (7), NULL, |
2cc46ade | 3680 | 1, OPTAB_WIDEN); |
34377880 | 3681 | for (i = 0; i < words; ++i) |
3682 | { | |
7a20d8cd | 3683 | emit_insn (gen_extql (data_regs[i], data_regs[i], sreg)); |
9bab4302 | 3684 | emit_insn (gen_extqh (ext_tmps[i], data_regs[i+1], sreg)); |
d1f9b275 | 3685 | emit_insn (gen_rtx_SET (ext_tmps[i], |
941522d6 | 3686 | gen_rtx_IF_THEN_ELSE (DImode, |
2cc46ade | 3687 | gen_rtx_EQ (DImode, areg, |
3688 | const0_rtx), | |
941522d6 | 3689 | const0_rtx, ext_tmps[i]))); |
34377880 | 3690 | } |
3691 | ||
3692 | /* Merge the half-words into whole words. */ | |
3693 | for (i = 0; i < words; ++i) | |
3694 | { | |
2cc46ade | 3695 | out_regs[i] = expand_binop (DImode, ior_optab, data_regs[i], |
3696 | ext_tmps[i], data_regs[i], 1, OPTAB_WIDEN); | |
34377880 | 3697 | } |
3698 | } | |
3699 | ||
3700 | /* Store an integral number of consecutive unaligned quadwords. DATA_REGS | |
3701 | may be NULL to store zeros. */ | |
3702 | ||
3703 | static void | |
92643d95 | 3704 | alpha_expand_unaligned_store_words (rtx *data_regs, rtx dmem, |
3705 | HOST_WIDE_INT words, HOST_WIDE_INT ofs) | |
34377880 | 3706 | { |
3707 | rtx const im8 = GEN_INT (-8); | |
34377880 | 3708 | rtx ins_tmps[MAX_MOVE_WORDS]; |
2cc46ade | 3709 | rtx st_tmp_1, st_tmp_2, dreg; |
1f0ce6a6 | 3710 | rtx st_addr_1, st_addr_2, dmema; |
34377880 | 3711 | HOST_WIDE_INT i; |
3712 | ||
1f0ce6a6 | 3713 | dmema = XEXP (dmem, 0); |
3714 | if (GET_CODE (dmema) == LO_SUM) | |
3715 | dmema = force_reg (Pmode, dmema); | |
3716 | ||
34377880 | 3717 | /* Generate all the tmp registers we need. */ |
3718 | if (data_regs != NULL) | |
3719 | for (i = 0; i < words; ++i) | |
3720 | ins_tmps[i] = gen_reg_rtx(DImode); | |
3721 | st_tmp_1 = gen_reg_rtx(DImode); | |
3722 | st_tmp_2 = gen_reg_rtx(DImode); | |
9e7454d0 | 3723 | |
2cc46ade | 3724 | if (ofs != 0) |
e513d163 | 3725 | dmem = adjust_address (dmem, GET_MODE (dmem), ofs); |
2cc46ade | 3726 | |
3727 | st_addr_2 = change_address (dmem, DImode, | |
941522d6 | 3728 | gen_rtx_AND (DImode, |
29c05e22 | 3729 | plus_constant (DImode, dmema, |
3730 | words*8 - 1), | |
3731 | im8)); | |
ab6ab77e | 3732 | set_mem_alias_set (st_addr_2, 0); |
3024e9f8 | 3733 | |
2cc46ade | 3734 | st_addr_1 = change_address (dmem, DImode, |
1f0ce6a6 | 3735 | gen_rtx_AND (DImode, dmema, im8)); |
ab6ab77e | 3736 | set_mem_alias_set (st_addr_1, 0); |
34377880 | 3737 | |
3738 | /* Load up the destination end bits. */ | |
3739 | emit_move_insn (st_tmp_2, st_addr_2); | |
3740 | emit_move_insn (st_tmp_1, st_addr_1); | |
3741 | ||
3742 | /* Shift the input data into place. */ | |
1f0ce6a6 | 3743 | dreg = copy_addr_to_reg (dmema); |
34377880 | 3744 | if (data_regs != NULL) |
3745 | { | |
3746 | for (i = words-1; i >= 0; --i) | |
3747 | { | |
7a20d8cd | 3748 | emit_insn (gen_insqh (ins_tmps[i], data_regs[i], dreg)); |
9bab4302 | 3749 | emit_insn (gen_insql (data_regs[i], data_regs[i], dreg)); |
34377880 | 3750 | } |
34377880 | 3751 | for (i = words-1; i > 0; --i) |
3752 | { | |
2cc46ade | 3753 | ins_tmps[i-1] = expand_binop (DImode, ior_optab, data_regs[i], |
3754 | ins_tmps[i-1], ins_tmps[i-1], 1, | |
3755 | OPTAB_WIDEN); | |
34377880 | 3756 | } |
3757 | } | |
3758 | ||
3759 | /* Split and merge the ends with the destination data. */ | |
7a20d8cd | 3760 | emit_insn (gen_mskqh (st_tmp_2, st_tmp_2, dreg)); |
3761 | emit_insn (gen_mskql (st_tmp_1, st_tmp_1, dreg)); | |
34377880 | 3762 | |
3763 | if (data_regs != NULL) | |
3764 | { | |
2cc46ade | 3765 | st_tmp_2 = expand_binop (DImode, ior_optab, st_tmp_2, ins_tmps[words-1], |
3766 | st_tmp_2, 1, OPTAB_WIDEN); | |
3767 | st_tmp_1 = expand_binop (DImode, ior_optab, st_tmp_1, data_regs[0], | |
3768 | st_tmp_1, 1, OPTAB_WIDEN); | |
34377880 | 3769 | } |
3770 | ||
3771 | /* Store it all. */ | |
9bab4302 | 3772 | emit_move_insn (st_addr_2, st_tmp_2); |
34377880 | 3773 | for (i = words-1; i > 0; --i) |
3774 | { | |
3024e9f8 | 3775 | rtx tmp = change_address (dmem, DImode, |
3776 | gen_rtx_AND (DImode, | |
29c05e22 | 3777 | plus_constant (DImode, |
3778 | dmema, i*8), | |
3024e9f8 | 3779 | im8)); |
ab6ab77e | 3780 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3781 | emit_move_insn (tmp, data_regs ? ins_tmps[i-1] : const0_rtx); |
34377880 | 3782 | } |
9bab4302 | 3783 | emit_move_insn (st_addr_1, st_tmp_1); |
34377880 | 3784 | } |
3785 | ||
3786 | ||
3787 | /* Expand string/block move operations. | |
3788 | ||
3789 | operands[0] is the pointer to the destination. | |
3790 | operands[1] is the pointer to the source. | |
3791 | operands[2] is the number of bytes to move. | |
3792 | operands[3] is the alignment. */ | |
3793 | ||
3794 | int | |
92643d95 | 3795 | alpha_expand_block_move (rtx operands[]) |
34377880 | 3796 | { |
3797 | rtx bytes_rtx = operands[2]; | |
3798 | rtx align_rtx = operands[3]; | |
d94b545b | 3799 | HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx); |
a9aaae37 | 3800 | HOST_WIDE_INT bytes = orig_bytes; |
3801 | HOST_WIDE_INT src_align = INTVAL (align_rtx) * BITS_PER_UNIT; | |
3802 | HOST_WIDE_INT dst_align = src_align; | |
80909c64 | 3803 | rtx orig_src = operands[1]; |
3804 | rtx orig_dst = operands[0]; | |
3805 | rtx data_regs[2 * MAX_MOVE_WORDS + 16]; | |
2cc46ade | 3806 | rtx tmp; |
1f0ce6a6 | 3807 | unsigned int i, words, ofs, nregs = 0; |
9e7454d0 | 3808 | |
80909c64 | 3809 | if (orig_bytes <= 0) |
34377880 | 3810 | return 1; |
a9aaae37 | 3811 | else if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD) |
34377880 | 3812 | return 0; |
3813 | ||
2cc46ade | 3814 | /* Look for additional alignment information from recorded register info. */ |
3815 | ||
3816 | tmp = XEXP (orig_src, 0); | |
c933fb42 | 3817 | if (REG_P (tmp)) |
80909c64 | 3818 | src_align = MAX (src_align, REGNO_POINTER_ALIGN (REGNO (tmp))); |
2cc46ade | 3819 | else if (GET_CODE (tmp) == PLUS |
c933fb42 | 3820 | && REG_P (XEXP (tmp, 0)) |
3821 | && CONST_INT_P (XEXP (tmp, 1))) | |
2cc46ade | 3822 | { |
80909c64 | 3823 | unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); |
3824 | unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); | |
2cc46ade | 3825 | |
3826 | if (a > src_align) | |
3827 | { | |
80909c64 | 3828 | if (a >= 64 && c % 8 == 0) |
3829 | src_align = 64; | |
3830 | else if (a >= 32 && c % 4 == 0) | |
3831 | src_align = 32; | |
3832 | else if (a >= 16 && c % 2 == 0) | |
3833 | src_align = 16; | |
2cc46ade | 3834 | } |
3835 | } | |
9e7454d0 | 3836 | |
2cc46ade | 3837 | tmp = XEXP (orig_dst, 0); |
c933fb42 | 3838 | if (REG_P (tmp)) |
80909c64 | 3839 | dst_align = MAX (dst_align, REGNO_POINTER_ALIGN (REGNO (tmp))); |
2cc46ade | 3840 | else if (GET_CODE (tmp) == PLUS |
c933fb42 | 3841 | && REG_P (XEXP (tmp, 0)) |
3842 | && CONST_INT_P (XEXP (tmp, 1))) | |
2cc46ade | 3843 | { |
80909c64 | 3844 | unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); |
3845 | unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); | |
2cc46ade | 3846 | |
3847 | if (a > dst_align) | |
3848 | { | |
80909c64 | 3849 | if (a >= 64 && c % 8 == 0) |
3850 | dst_align = 64; | |
3851 | else if (a >= 32 && c % 4 == 0) | |
3852 | dst_align = 32; | |
3853 | else if (a >= 16 && c % 2 == 0) | |
3854 | dst_align = 16; | |
2cc46ade | 3855 | } |
3856 | } | |
3857 | ||
2cc46ade | 3858 | ofs = 0; |
80909c64 | 3859 | if (src_align >= 64 && bytes >= 8) |
34377880 | 3860 | { |
3861 | words = bytes / 8; | |
3862 | ||
34377880 | 3863 | for (i = 0; i < words; ++i) |
27d0c333 | 3864 | data_regs[nregs + i] = gen_reg_rtx (DImode); |
34377880 | 3865 | |
34377880 | 3866 | for (i = 0; i < words; ++i) |
80909c64 | 3867 | emit_move_insn (data_regs[nregs + i], |
e513d163 | 3868 | adjust_address (orig_src, DImode, ofs + i * 8)); |
34377880 | 3869 | |
2cc46ade | 3870 | nregs += words; |
34377880 | 3871 | bytes -= words * 8; |
7597afe9 | 3872 | ofs += words * 8; |
34377880 | 3873 | } |
80909c64 | 3874 | |
3875 | if (src_align >= 32 && bytes >= 4) | |
34377880 | 3876 | { |
3877 | words = bytes / 4; | |
3878 | ||
34377880 | 3879 | for (i = 0; i < words; ++i) |
27d0c333 | 3880 | data_regs[nregs + i] = gen_reg_rtx (SImode); |
34377880 | 3881 | |
34377880 | 3882 | for (i = 0; i < words; ++i) |
80909c64 | 3883 | emit_move_insn (data_regs[nregs + i], |
537ffcfc | 3884 | adjust_address (orig_src, SImode, ofs + i * 4)); |
34377880 | 3885 | |
2cc46ade | 3886 | nregs += words; |
34377880 | 3887 | bytes -= words * 4; |
7597afe9 | 3888 | ofs += words * 4; |
34377880 | 3889 | } |
80909c64 | 3890 | |
a9aaae37 | 3891 | if (bytes >= 8) |
34377880 | 3892 | { |
3893 | words = bytes / 8; | |
3894 | ||
34377880 | 3895 | for (i = 0; i < words+1; ++i) |
27d0c333 | 3896 | data_regs[nregs + i] = gen_reg_rtx (DImode); |
34377880 | 3897 | |
b47268cf | 3898 | alpha_expand_unaligned_load_words (data_regs + nregs, orig_src, |
3899 | words, ofs); | |
34377880 | 3900 | |
2cc46ade | 3901 | nregs += words; |
34377880 | 3902 | bytes -= words * 8; |
7597afe9 | 3903 | ofs += words * 8; |
34377880 | 3904 | } |
80909c64 | 3905 | |
80909c64 | 3906 | if (! TARGET_BWX && bytes >= 4) |
34377880 | 3907 | { |
2cc46ade | 3908 | data_regs[nregs++] = tmp = gen_reg_rtx (SImode); |
34377880 | 3909 | alpha_expand_unaligned_load (tmp, orig_src, 4, ofs, 0); |
34377880 | 3910 | bytes -= 4; |
3911 | ofs += 4; | |
3912 | } | |
80909c64 | 3913 | |
34377880 | 3914 | if (bytes >= 2) |
3915 | { | |
80909c64 | 3916 | if (src_align >= 16) |
34377880 | 3917 | { |
3918 | do { | |
2cc46ade | 3919 | data_regs[nregs++] = tmp = gen_reg_rtx (HImode); |
e513d163 | 3920 | emit_move_insn (tmp, adjust_address (orig_src, HImode, ofs)); |
34377880 | 3921 | bytes -= 2; |
3922 | ofs += 2; | |
3923 | } while (bytes >= 2); | |
3924 | } | |
80909c64 | 3925 | else if (! TARGET_BWX) |
34377880 | 3926 | { |
2cc46ade | 3927 | data_regs[nregs++] = tmp = gen_reg_rtx (HImode); |
34377880 | 3928 | alpha_expand_unaligned_load (tmp, orig_src, 2, ofs, 0); |
34377880 | 3929 | bytes -= 2; |
3930 | ofs += 2; | |
3931 | } | |
3932 | } | |
80909c64 | 3933 | |
34377880 | 3934 | while (bytes > 0) |
3935 | { | |
2cc46ade | 3936 | data_regs[nregs++] = tmp = gen_reg_rtx (QImode); |
e513d163 | 3937 | emit_move_insn (tmp, adjust_address (orig_src, QImode, ofs)); |
34377880 | 3938 | bytes -= 1; |
3939 | ofs += 1; | |
3940 | } | |
80909c64 | 3941 | |
4d10b463 | 3942 | gcc_assert (nregs <= ARRAY_SIZE (data_regs)); |
2cc46ade | 3943 | |
80909c64 | 3944 | /* Now save it back out again. */ |
2cc46ade | 3945 | |
3946 | i = 0, ofs = 0; | |
3947 | ||
2cc46ade | 3948 | /* Write out the data in whatever chunks reading the source allowed. */ |
80909c64 | 3949 | if (dst_align >= 64) |
2cc46ade | 3950 | { |
3951 | while (i < nregs && GET_MODE (data_regs[i]) == DImode) | |
3952 | { | |
e513d163 | 3953 | emit_move_insn (adjust_address (orig_dst, DImode, ofs), |
2cc46ade | 3954 | data_regs[i]); |
3955 | ofs += 8; | |
3956 | i++; | |
3957 | } | |
3958 | } | |
80909c64 | 3959 | |
3960 | if (dst_align >= 32) | |
2cc46ade | 3961 | { |
3962 | /* If the source has remaining DImode regs, write them out in | |
3963 | two pieces. */ | |
3964 | while (i < nregs && GET_MODE (data_regs[i]) == DImode) | |
3965 | { | |
3966 | tmp = expand_binop (DImode, lshr_optab, data_regs[i], GEN_INT (32), | |
3967 | NULL_RTX, 1, OPTAB_WIDEN); | |
3968 | ||
e513d163 | 3969 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), |
2cc46ade | 3970 | gen_lowpart (SImode, data_regs[i])); |
e513d163 | 3971 | emit_move_insn (adjust_address (orig_dst, SImode, ofs + 4), |
2cc46ade | 3972 | gen_lowpart (SImode, tmp)); |
3973 | ofs += 8; | |
3974 | i++; | |
3975 | } | |
3976 | ||
3977 | while (i < nregs && GET_MODE (data_regs[i]) == SImode) | |
3978 | { | |
e513d163 | 3979 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), |
2cc46ade | 3980 | data_regs[i]); |
3981 | ofs += 4; | |
3982 | i++; | |
3983 | } | |
3984 | } | |
80909c64 | 3985 | |
2cc46ade | 3986 | if (i < nregs && GET_MODE (data_regs[i]) == DImode) |
3987 | { | |
3988 | /* Write out a remaining block of words using unaligned methods. */ | |
3989 | ||
80909c64 | 3990 | for (words = 1; i + words < nregs; words++) |
3991 | if (GET_MODE (data_regs[i + words]) != DImode) | |
2cc46ade | 3992 | break; |
3993 | ||
3994 | if (words == 1) | |
3995 | alpha_expand_unaligned_store (orig_dst, data_regs[i], 8, ofs); | |
3996 | else | |
80909c64 | 3997 | alpha_expand_unaligned_store_words (data_regs + i, orig_dst, |
3998 | words, ofs); | |
9e7454d0 | 3999 | |
2cc46ade | 4000 | i += words; |
4001 | ofs += words * 8; | |
4002 | } | |
4003 | ||
4004 | /* Due to the above, this won't be aligned. */ | |
4005 | /* ??? If we have more than one of these, consider constructing full | |
4006 | words in registers and using alpha_expand_unaligned_store_words. */ | |
4007 | while (i < nregs && GET_MODE (data_regs[i]) == SImode) | |
4008 | { | |
4009 | alpha_expand_unaligned_store (orig_dst, data_regs[i], 4, ofs); | |
4010 | ofs += 4; | |
4011 | i++; | |
4012 | } | |
4013 | ||
80909c64 | 4014 | if (dst_align >= 16) |
2cc46ade | 4015 | while (i < nregs && GET_MODE (data_regs[i]) == HImode) |
4016 | { | |
e513d163 | 4017 | emit_move_insn (adjust_address (orig_dst, HImode, ofs), data_regs[i]); |
2cc46ade | 4018 | i++; |
4019 | ofs += 2; | |
4020 | } | |
4021 | else | |
4022 | while (i < nregs && GET_MODE (data_regs[i]) == HImode) | |
4023 | { | |
4024 | alpha_expand_unaligned_store (orig_dst, data_regs[i], 2, ofs); | |
4025 | i++; | |
4026 | ofs += 2; | |
4027 | } | |
80909c64 | 4028 | |
4d10b463 | 4029 | /* The remainder must be byte copies. */ |
4030 | while (i < nregs) | |
2cc46ade | 4031 | { |
4d10b463 | 4032 | gcc_assert (GET_MODE (data_regs[i]) == QImode); |
e513d163 | 4033 | emit_move_insn (adjust_address (orig_dst, QImode, ofs), data_regs[i]); |
2cc46ade | 4034 | i++; |
4035 | ofs += 1; | |
4036 | } | |
80909c64 | 4037 | |
34377880 | 4038 | return 1; |
4039 | } | |
4040 | ||
4041 | int | |
92643d95 | 4042 | alpha_expand_block_clear (rtx operands[]) |
34377880 | 4043 | { |
4044 | rtx bytes_rtx = operands[1]; | |
7a3e5564 | 4045 | rtx align_rtx = operands[3]; |
80909c64 | 4046 | HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx); |
a9aaae37 | 4047 | HOST_WIDE_INT bytes = orig_bytes; |
4048 | HOST_WIDE_INT align = INTVAL (align_rtx) * BITS_PER_UNIT; | |
4049 | HOST_WIDE_INT alignofs = 0; | |
80909c64 | 4050 | rtx orig_dst = operands[0]; |
2cc46ade | 4051 | rtx tmp; |
a9aaae37 | 4052 | int i, words, ofs = 0; |
9e7454d0 | 4053 | |
80909c64 | 4054 | if (orig_bytes <= 0) |
34377880 | 4055 | return 1; |
a9aaae37 | 4056 | if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD) |
34377880 | 4057 | return 0; |
4058 | ||
2cc46ade | 4059 | /* Look for stricter alignment. */ |
2cc46ade | 4060 | tmp = XEXP (orig_dst, 0); |
c933fb42 | 4061 | if (REG_P (tmp)) |
80909c64 | 4062 | align = MAX (align, REGNO_POINTER_ALIGN (REGNO (tmp))); |
2cc46ade | 4063 | else if (GET_CODE (tmp) == PLUS |
c933fb42 | 4064 | && REG_P (XEXP (tmp, 0)) |
4065 | && CONST_INT_P (XEXP (tmp, 1))) | |
2cc46ade | 4066 | { |
a9aaae37 | 4067 | HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); |
4068 | int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); | |
2cc46ade | 4069 | |
4070 | if (a > align) | |
4071 | { | |
a9aaae37 | 4072 | if (a >= 64) |
4073 | align = a, alignofs = 8 - c % 8; | |
4074 | else if (a >= 32) | |
4075 | align = a, alignofs = 4 - c % 4; | |
4076 | else if (a >= 16) | |
4077 | align = a, alignofs = 2 - c % 2; | |
2cc46ade | 4078 | } |
4079 | } | |
4080 | ||
a9aaae37 | 4081 | /* Handle an unaligned prefix first. */ |
4082 | ||
4083 | if (alignofs > 0) | |
4084 | { | |
a9aaae37 | 4085 | /* Given that alignofs is bounded by align, the only time BWX could |
4086 | generate three stores is for a 7 byte fill. Prefer two individual | |
4087 | stores over a load/mask/store sequence. */ | |
4088 | if ((!TARGET_BWX || alignofs == 7) | |
4089 | && align >= 32 | |
4090 | && !(alignofs == 4 && bytes >= 4)) | |
4091 | { | |
3754d046 | 4092 | machine_mode mode = (align >= 64 ? DImode : SImode); |
a9aaae37 | 4093 | int inv_alignofs = (align >= 64 ? 8 : 4) - alignofs; |
4094 | rtx mem, tmp; | |
4095 | HOST_WIDE_INT mask; | |
4096 | ||
e513d163 | 4097 | mem = adjust_address (orig_dst, mode, ofs - inv_alignofs); |
ab6ab77e | 4098 | set_mem_alias_set (mem, 0); |
a9aaae37 | 4099 | |
8d11ad8c | 4100 | mask = ~(HOST_WIDE_INT_M1U << (inv_alignofs * 8)); |
a9aaae37 | 4101 | if (bytes < alignofs) |
4102 | { | |
8d11ad8c | 4103 | mask |= HOST_WIDE_INT_M1U << ((inv_alignofs + bytes) * 8); |
a9aaae37 | 4104 | ofs += bytes; |
4105 | bytes = 0; | |
4106 | } | |
4107 | else | |
4108 | { | |
4109 | bytes -= alignofs; | |
4110 | ofs += alignofs; | |
4111 | } | |
4112 | alignofs = 0; | |
4113 | ||
4114 | tmp = expand_binop (mode, and_optab, mem, GEN_INT (mask), | |
4115 | NULL_RTX, 1, OPTAB_WIDEN); | |
4116 | ||
4117 | emit_move_insn (mem, tmp); | |
4118 | } | |
a9aaae37 | 4119 | |
4120 | if (TARGET_BWX && (alignofs & 1) && bytes >= 1) | |
4121 | { | |
e513d163 | 4122 | emit_move_insn (adjust_address (orig_dst, QImode, ofs), const0_rtx); |
a9aaae37 | 4123 | bytes -= 1; |
4124 | ofs += 1; | |
4125 | alignofs -= 1; | |
4126 | } | |
4127 | if (TARGET_BWX && align >= 16 && (alignofs & 3) == 2 && bytes >= 2) | |
4128 | { | |
e513d163 | 4129 | emit_move_insn (adjust_address (orig_dst, HImode, ofs), const0_rtx); |
a9aaae37 | 4130 | bytes -= 2; |
4131 | ofs += 2; | |
4132 | alignofs -= 2; | |
4133 | } | |
4134 | if (alignofs == 4 && bytes >= 4) | |
4135 | { | |
e513d163 | 4136 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx); |
a9aaae37 | 4137 | bytes -= 4; |
4138 | ofs += 4; | |
4139 | alignofs = 0; | |
4140 | } | |
4141 | ||
4142 | /* If we've not used the extra lead alignment information by now, | |
4143 | we won't be able to. Downgrade align to match what's left over. */ | |
4144 | if (alignofs > 0) | |
4145 | { | |
4146 | alignofs = alignofs & -alignofs; | |
4147 | align = MIN (align, alignofs * BITS_PER_UNIT); | |
4148 | } | |
4149 | } | |
4150 | ||
4151 | /* Handle a block of contiguous long-words. */ | |
34377880 | 4152 | |
80909c64 | 4153 | if (align >= 64 && bytes >= 8) |
34377880 | 4154 | { |
4155 | words = bytes / 8; | |
4156 | ||
4157 | for (i = 0; i < words; ++i) | |
1f0ce6a6 | 4158 | emit_move_insn (adjust_address (orig_dst, DImode, ofs + i * 8), |
e513d163 | 4159 | const0_rtx); |
34377880 | 4160 | |
4161 | bytes -= words * 8; | |
7597afe9 | 4162 | ofs += words * 8; |
34377880 | 4163 | } |
80909c64 | 4164 | |
a9aaae37 | 4165 | /* If the block is large and appropriately aligned, emit a single |
4166 | store followed by a sequence of stq_u insns. */ | |
4167 | ||
4168 | if (align >= 32 && bytes > 16) | |
4169 | { | |
1f0ce6a6 | 4170 | rtx orig_dsta; |
4171 | ||
e513d163 | 4172 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx); |
a9aaae37 | 4173 | bytes -= 4; |
4174 | ofs += 4; | |
4175 | ||
1f0ce6a6 | 4176 | orig_dsta = XEXP (orig_dst, 0); |
4177 | if (GET_CODE (orig_dsta) == LO_SUM) | |
4178 | orig_dsta = force_reg (Pmode, orig_dsta); | |
4179 | ||
a9aaae37 | 4180 | words = bytes / 8; |
4181 | for (i = 0; i < words; ++i) | |
4182 | { | |
ab6ab77e | 4183 | rtx mem |
4184 | = change_address (orig_dst, DImode, | |
4185 | gen_rtx_AND (DImode, | |
29c05e22 | 4186 | plus_constant (DImode, orig_dsta, |
4187 | ofs + i*8), | |
ab6ab77e | 4188 | GEN_INT (-8))); |
4189 | set_mem_alias_set (mem, 0); | |
a9aaae37 | 4190 | emit_move_insn (mem, const0_rtx); |
4191 | } | |
4192 | ||
4193 | /* Depending on the alignment, the first stq_u may have overlapped | |
4194 | with the initial stl, which means that the last stq_u didn't | |
4195 | write as much as it would appear. Leave those questionable bytes | |
4196 | unaccounted for. */ | |
4197 | bytes -= words * 8 - 4; | |
4198 | ofs += words * 8 - 4; | |
4199 | } | |
4200 | ||
4201 | /* Handle a smaller block of aligned words. */ | |
4202 | ||
4203 | if ((align >= 64 && bytes == 4) | |
4204 | || (align == 32 && bytes >= 4)) | |
34377880 | 4205 | { |
4206 | words = bytes / 4; | |
4207 | ||
4208 | for (i = 0; i < words; ++i) | |
e513d163 | 4209 | emit_move_insn (adjust_address (orig_dst, SImode, ofs + i * 4), |
80909c64 | 4210 | const0_rtx); |
34377880 | 4211 | |
4212 | bytes -= words * 4; | |
7597afe9 | 4213 | ofs += words * 4; |
34377880 | 4214 | } |
80909c64 | 4215 | |
a9aaae37 | 4216 | /* An unaligned block uses stq_u stores for as many as possible. */ |
4217 | ||
4218 | if (bytes >= 8) | |
34377880 | 4219 | { |
4220 | words = bytes / 8; | |
4221 | ||
7597afe9 | 4222 | alpha_expand_unaligned_store_words (NULL, orig_dst, words, ofs); |
34377880 | 4223 | |
4224 | bytes -= words * 8; | |
7597afe9 | 4225 | ofs += words * 8; |
34377880 | 4226 | } |
4227 | ||
a9aaae37 | 4228 | /* Next clean up any trailing pieces. */ |
34377880 | 4229 | |
a9aaae37 | 4230 | /* Count the number of bits in BYTES for which aligned stores could |
4231 | be emitted. */ | |
4232 | words = 0; | |
4233 | for (i = (TARGET_BWX ? 1 : 4); i * BITS_PER_UNIT <= align ; i <<= 1) | |
4234 | if (bytes & i) | |
4235 | words += 1; | |
4236 | ||
4237 | /* If we have appropriate alignment (and it wouldn't take too many | |
4238 | instructions otherwise), mask out the bytes we need. */ | |
4239 | if (TARGET_BWX ? words > 2 : bytes > 0) | |
4240 | { | |
4241 | if (align >= 64) | |
4242 | { | |
4243 | rtx mem, tmp; | |
4244 | HOST_WIDE_INT mask; | |
4245 | ||
e513d163 | 4246 | mem = adjust_address (orig_dst, DImode, ofs); |
ab6ab77e | 4247 | set_mem_alias_set (mem, 0); |
a9aaae37 | 4248 | |
8d11ad8c | 4249 | mask = HOST_WIDE_INT_M1U << (bytes * 8); |
a9aaae37 | 4250 | |
4251 | tmp = expand_binop (DImode, and_optab, mem, GEN_INT (mask), | |
4252 | NULL_RTX, 1, OPTAB_WIDEN); | |
4253 | ||
4254 | emit_move_insn (mem, tmp); | |
4255 | return 1; | |
4256 | } | |
4257 | else if (align >= 32 && bytes < 4) | |
4258 | { | |
4259 | rtx mem, tmp; | |
4260 | HOST_WIDE_INT mask; | |
4261 | ||
e513d163 | 4262 | mem = adjust_address (orig_dst, SImode, ofs); |
ab6ab77e | 4263 | set_mem_alias_set (mem, 0); |
a9aaae37 | 4264 | |
8d11ad8c | 4265 | mask = HOST_WIDE_INT_M1U << (bytes * 8); |
a9aaae37 | 4266 | |
4267 | tmp = expand_binop (SImode, and_optab, mem, GEN_INT (mask), | |
4268 | NULL_RTX, 1, OPTAB_WIDEN); | |
4269 | ||
4270 | emit_move_insn (mem, tmp); | |
4271 | return 1; | |
4272 | } | |
34377880 | 4273 | } |
80909c64 | 4274 | |
34377880 | 4275 | if (!TARGET_BWX && bytes >= 4) |
4276 | { | |
4277 | alpha_expand_unaligned_store (orig_dst, const0_rtx, 4, ofs); | |
4278 | bytes -= 4; | |
4279 | ofs += 4; | |
4280 | } | |
80909c64 | 4281 | |
34377880 | 4282 | if (bytes >= 2) |
4283 | { | |
80909c64 | 4284 | if (align >= 16) |
34377880 | 4285 | { |
4286 | do { | |
e513d163 | 4287 | emit_move_insn (adjust_address (orig_dst, HImode, ofs), |
34377880 | 4288 | const0_rtx); |
4289 | bytes -= 2; | |
4290 | ofs += 2; | |
4291 | } while (bytes >= 2); | |
4292 | } | |
80909c64 | 4293 | else if (! TARGET_BWX) |
34377880 | 4294 | { |
4295 | alpha_expand_unaligned_store (orig_dst, const0_rtx, 2, ofs); | |
4296 | bytes -= 2; | |
4297 | ofs += 2; | |
4298 | } | |
4299 | } | |
80909c64 | 4300 | |
34377880 | 4301 | while (bytes > 0) |
4302 | { | |
e513d163 | 4303 | emit_move_insn (adjust_address (orig_dst, QImode, ofs), const0_rtx); |
34377880 | 4304 | bytes -= 1; |
4305 | ofs += 1; | |
4306 | } | |
4307 | ||
4308 | return 1; | |
4309 | } | |
f2cc13dc | 4310 | |
4311 | /* Returns a mask so that zap(x, value) == x & mask. */ | |
4312 | ||
4313 | rtx | |
92643d95 | 4314 | alpha_expand_zap_mask (HOST_WIDE_INT value) |
f2cc13dc | 4315 | { |
4316 | rtx result; | |
4317 | int i; | |
a2d7211e | 4318 | HOST_WIDE_INT mask = 0; |
f2cc13dc | 4319 | |
a2d7211e | 4320 | for (i = 7; i >= 0; --i) |
f2cc13dc | 4321 | { |
a2d7211e | 4322 | mask <<= 8; |
4323 | if (!((value >> i) & 1)) | |
4324 | mask |= 0xff; | |
f2cc13dc | 4325 | } |
f2cc13dc | 4326 | |
a2d7211e | 4327 | result = gen_int_mode (mask, DImode); |
f2cc13dc | 4328 | return result; |
4329 | } | |
4330 | ||
4331 | void | |
92643d95 | 4332 | alpha_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx), |
3754d046 | 4333 | machine_mode mode, |
92643d95 | 4334 | rtx op0, rtx op1, rtx op2) |
f2cc13dc | 4335 | { |
4336 | op0 = gen_lowpart (mode, op0); | |
4337 | ||
4338 | if (op1 == const0_rtx) | |
4339 | op1 = CONST0_RTX (mode); | |
4340 | else | |
4341 | op1 = gen_lowpart (mode, op1); | |
ae4cd3a5 | 4342 | |
4343 | if (op2 == const0_rtx) | |
f2cc13dc | 4344 | op2 = CONST0_RTX (mode); |
4345 | else | |
4346 | op2 = gen_lowpart (mode, op2); | |
4347 | ||
4348 | emit_insn ((*gen) (op0, op1, op2)); | |
4349 | } | |
f155876e | 4350 | |
032caa7b | 4351 | /* A subroutine of the atomic operation splitters. Jump to LABEL if |
4352 | COND is true. Mark the jump as unlikely to be taken. */ | |
4353 | ||
4354 | static void | |
4355 | emit_unlikely_jump (rtx cond, rtx label) | |
4356 | { | |
753de566 | 4357 | rtx x = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, label, pc_rtx); |
4358 | rtx_insn *insn = emit_jump_insn (gen_rtx_SET (pc_rtx, x)); | |
61cb1816 | 4359 | add_reg_br_prob_note (insn, profile_probability::very_unlikely ()); |
032caa7b | 4360 | } |
4361 | ||
4362 | /* A subroutine of the atomic operation splitters. Emit a load-locked | |
4363 | instruction in MODE. */ | |
4364 | ||
4365 | static void | |
3754d046 | 4366 | emit_load_locked (machine_mode mode, rtx reg, rtx mem) |
032caa7b | 4367 | { |
4368 | rtx (*fn) (rtx, rtx) = NULL; | |
4369 | if (mode == SImode) | |
4370 | fn = gen_load_locked_si; | |
4371 | else if (mode == DImode) | |
4372 | fn = gen_load_locked_di; | |
4373 | emit_insn (fn (reg, mem)); | |
4374 | } | |
4375 | ||
4376 | /* A subroutine of the atomic operation splitters. Emit a store-conditional | |
4377 | instruction in MODE. */ | |
4378 | ||
4379 | static void | |
3754d046 | 4380 | emit_store_conditional (machine_mode mode, rtx res, rtx mem, rtx val) |
032caa7b | 4381 | { |
4382 | rtx (*fn) (rtx, rtx, rtx) = NULL; | |
4383 | if (mode == SImode) | |
4384 | fn = gen_store_conditional_si; | |
4385 | else if (mode == DImode) | |
4386 | fn = gen_store_conditional_di; | |
4387 | emit_insn (fn (res, mem, val)); | |
4388 | } | |
4389 | ||
51c750d8 | 4390 | /* Subroutines of the atomic operation splitters. Emit barriers |
4391 | as needed for the memory MODEL. */ | |
4392 | ||
4393 | static void | |
4394 | alpha_pre_atomic_barrier (enum memmodel model) | |
4395 | { | |
30c3c442 | 4396 | if (need_atomic_barrier_p (model, true)) |
4397 | emit_insn (gen_memory_barrier ()); | |
51c750d8 | 4398 | } |
4399 | ||
4400 | static void | |
4401 | alpha_post_atomic_barrier (enum memmodel model) | |
4402 | { | |
30c3c442 | 4403 | if (need_atomic_barrier_p (model, false)) |
4404 | emit_insn (gen_memory_barrier ()); | |
51c750d8 | 4405 | } |
4406 | ||
596d3184 | 4407 | /* A subroutine of the atomic operation splitters. Emit an insxl |
4408 | instruction in MODE. */ | |
4409 | ||
4410 | static rtx | |
3754d046 | 4411 | emit_insxl (machine_mode mode, rtx op1, rtx op2) |
596d3184 | 4412 | { |
4413 | rtx ret = gen_reg_rtx (DImode); | |
4414 | rtx (*fn) (rtx, rtx, rtx); | |
4415 | ||
7a20d8cd | 4416 | switch (mode) |
4417 | { | |
916ace94 | 4418 | case E_QImode: |
7a20d8cd | 4419 | fn = gen_insbl; |
4420 | break; | |
916ace94 | 4421 | case E_HImode: |
7a20d8cd | 4422 | fn = gen_inswl; |
4423 | break; | |
916ace94 | 4424 | case E_SImode: |
7a20d8cd | 4425 | fn = gen_insll; |
4426 | break; | |
916ace94 | 4427 | case E_DImode: |
7a20d8cd | 4428 | fn = gen_insql; |
4429 | break; | |
4430 | default: | |
4431 | gcc_unreachable (); | |
4432 | } | |
9bab4302 | 4433 | |
9a6f4ddd | 4434 | op1 = force_reg (mode, op1); |
596d3184 | 4435 | emit_insn (fn (ret, op1, op2)); |
4436 | ||
4437 | return ret; | |
4438 | } | |
4439 | ||
85694bac | 4440 | /* Expand an atomic fetch-and-operate pattern. CODE is the binary operation |
f155876e | 4441 | to perform. MEM is the memory on which to operate. VAL is the second |
4442 | operand of the binary operator. BEFORE and AFTER are optional locations to | |
4443 | return the value of MEM either before of after the operation. SCRATCH is | |
4444 | a scratch register. */ | |
4445 | ||
4446 | void | |
51c750d8 | 4447 | alpha_split_atomic_op (enum rtx_code code, rtx mem, rtx val, rtx before, |
4448 | rtx after, rtx scratch, enum memmodel model) | |
f155876e | 4449 | { |
3754d046 | 4450 | machine_mode mode = GET_MODE (mem); |
032caa7b | 4451 | rtx label, x, cond = gen_rtx_REG (DImode, REGNO (scratch)); |
f155876e | 4452 | |
51c750d8 | 4453 | alpha_pre_atomic_barrier (model); |
f155876e | 4454 | |
4455 | label = gen_label_rtx (); | |
4456 | emit_label (label); | |
4457 | label = gen_rtx_LABEL_REF (DImode, label); | |
4458 | ||
4459 | if (before == NULL) | |
4460 | before = scratch; | |
032caa7b | 4461 | emit_load_locked (mode, before, mem); |
f155876e | 4462 | |
4463 | if (code == NOT) | |
6f7e6aa3 | 4464 | { |
4465 | x = gen_rtx_AND (mode, before, val); | |
d1f9b275 | 4466 | emit_insn (gen_rtx_SET (val, x)); |
6f7e6aa3 | 4467 | |
4468 | x = gen_rtx_NOT (mode, val); | |
4469 | } | |
f155876e | 4470 | else |
4471 | x = gen_rtx_fmt_ee (code, mode, before, val); | |
f155876e | 4472 | if (after) |
d1f9b275 | 4473 | emit_insn (gen_rtx_SET (after, copy_rtx (x))); |
4474 | emit_insn (gen_rtx_SET (scratch, x)); | |
f155876e | 4475 | |
032caa7b | 4476 | emit_store_conditional (mode, cond, mem, scratch); |
4477 | ||
4478 | x = gen_rtx_EQ (DImode, cond, const0_rtx); | |
4479 | emit_unlikely_jump (x, label); | |
4480 | ||
51c750d8 | 4481 | alpha_post_atomic_barrier (model); |
032caa7b | 4482 | } |
4483 | ||
4484 | /* Expand a compare and swap operation. */ | |
4485 | ||
4486 | void | |
51c750d8 | 4487 | alpha_split_compare_and_swap (rtx operands[]) |
032caa7b | 4488 | { |
51c750d8 | 4489 | rtx cond, retval, mem, oldval, newval; |
4490 | bool is_weak; | |
4491 | enum memmodel mod_s, mod_f; | |
3754d046 | 4492 | machine_mode mode; |
51c750d8 | 4493 | rtx label1, label2, x; |
4494 | ||
4495 | cond = operands[0]; | |
4496 | retval = operands[1]; | |
4497 | mem = operands[2]; | |
4498 | oldval = operands[3]; | |
4499 | newval = operands[4]; | |
4500 | is_weak = (operands[5] != const0_rtx); | |
a372f7ca | 4501 | mod_s = memmodel_from_int (INTVAL (operands[6])); |
4502 | mod_f = memmodel_from_int (INTVAL (operands[7])); | |
51c750d8 | 4503 | mode = GET_MODE (mem); |
4504 | ||
4505 | alpha_pre_atomic_barrier (mod_s); | |
4506 | ||
4507 | label1 = NULL_RTX; | |
4508 | if (!is_weak) | |
4509 | { | |
4510 | label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); | |
4511 | emit_label (XEXP (label1, 0)); | |
4512 | } | |
032caa7b | 4513 | label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); |
032caa7b | 4514 | |
4515 | emit_load_locked (mode, retval, mem); | |
4516 | ||
4517 | x = gen_lowpart (DImode, retval); | |
4518 | if (oldval == const0_rtx) | |
51c750d8 | 4519 | { |
4520 | emit_move_insn (cond, const0_rtx); | |
4521 | x = gen_rtx_NE (DImode, x, const0_rtx); | |
4522 | } | |
f155876e | 4523 | else |
032caa7b | 4524 | { |
4525 | x = gen_rtx_EQ (DImode, x, oldval); | |
d1f9b275 | 4526 | emit_insn (gen_rtx_SET (cond, x)); |
032caa7b | 4527 | x = gen_rtx_EQ (DImode, cond, const0_rtx); |
4528 | } | |
4529 | emit_unlikely_jump (x, label2); | |
4530 | ||
51c750d8 | 4531 | emit_move_insn (cond, newval); |
4532 | emit_store_conditional (mode, cond, mem, gen_lowpart (mode, cond)); | |
f155876e | 4533 | |
51c750d8 | 4534 | if (!is_weak) |
4535 | { | |
4536 | x = gen_rtx_EQ (DImode, cond, const0_rtx); | |
4537 | emit_unlikely_jump (x, label1); | |
4538 | } | |
4539 | ||
a372f7ca | 4540 | if (!is_mm_relaxed (mod_f)) |
51c750d8 | 4541 | emit_label (XEXP (label2, 0)); |
4542 | ||
4543 | alpha_post_atomic_barrier (mod_s); | |
032caa7b | 4544 | |
a372f7ca | 4545 | if (is_mm_relaxed (mod_f)) |
51c750d8 | 4546 | emit_label (XEXP (label2, 0)); |
032caa7b | 4547 | } |
4548 | ||
596d3184 | 4549 | void |
51c750d8 | 4550 | alpha_expand_compare_and_swap_12 (rtx operands[]) |
596d3184 | 4551 | { |
51c750d8 | 4552 | rtx cond, dst, mem, oldval, newval, is_weak, mod_s, mod_f; |
3754d046 | 4553 | machine_mode mode; |
596d3184 | 4554 | rtx addr, align, wdst; |
51c750d8 | 4555 | rtx (*gen) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx); |
4556 | ||
4557 | cond = operands[0]; | |
4558 | dst = operands[1]; | |
4559 | mem = operands[2]; | |
4560 | oldval = operands[3]; | |
4561 | newval = operands[4]; | |
4562 | is_weak = operands[5]; | |
4563 | mod_s = operands[6]; | |
4564 | mod_f = operands[7]; | |
4565 | mode = GET_MODE (mem); | |
4566 | ||
4567 | /* We forced the address into a register via mem_noofs_operand. */ | |
4568 | addr = XEXP (mem, 0); | |
4569 | gcc_assert (register_operand (addr, DImode)); | |
596d3184 | 4570 | |
596d3184 | 4571 | align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8), |
4572 | NULL_RTX, 1, OPTAB_DIRECT); | |
4573 | ||
4574 | oldval = convert_modes (DImode, mode, oldval, 1); | |
51c750d8 | 4575 | |
4576 | if (newval != const0_rtx) | |
4577 | newval = emit_insxl (mode, newval, addr); | |
596d3184 | 4578 | |
4579 | wdst = gen_reg_rtx (DImode); | |
4580 | if (mode == QImode) | |
51c750d8 | 4581 | gen = gen_atomic_compare_and_swapqi_1; |
596d3184 | 4582 | else |
51c750d8 | 4583 | gen = gen_atomic_compare_and_swaphi_1; |
4584 | emit_insn (gen (cond, wdst, mem, oldval, newval, align, | |
4585 | is_weak, mod_s, mod_f)); | |
596d3184 | 4586 | |
4587 | emit_move_insn (dst, gen_lowpart (mode, wdst)); | |
4588 | } | |
4589 | ||
4590 | void | |
51c750d8 | 4591 | alpha_split_compare_and_swap_12 (rtx operands[]) |
596d3184 | 4592 | { |
51c750d8 | 4593 | rtx cond, dest, orig_mem, oldval, newval, align, scratch; |
3754d046 | 4594 | machine_mode mode; |
51c750d8 | 4595 | bool is_weak; |
4596 | enum memmodel mod_s, mod_f; | |
4597 | rtx label1, label2, mem, addr, width, mask, x; | |
4598 | ||
4599 | cond = operands[0]; | |
4600 | dest = operands[1]; | |
4601 | orig_mem = operands[2]; | |
4602 | oldval = operands[3]; | |
4603 | newval = operands[4]; | |
4604 | align = operands[5]; | |
4605 | is_weak = (operands[6] != const0_rtx); | |
a372f7ca | 4606 | mod_s = memmodel_from_int (INTVAL (operands[7])); |
4607 | mod_f = memmodel_from_int (INTVAL (operands[8])); | |
51c750d8 | 4608 | scratch = operands[9]; |
4609 | mode = GET_MODE (orig_mem); | |
4610 | addr = XEXP (orig_mem, 0); | |
596d3184 | 4611 | |
4612 | mem = gen_rtx_MEM (DImode, align); | |
51c750d8 | 4613 | MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (orig_mem); |
02891b92 | 4614 | if (MEM_ALIAS_SET (orig_mem) == ALIAS_SET_MEMORY_BARRIER) |
4615 | set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER); | |
596d3184 | 4616 | |
51c750d8 | 4617 | alpha_pre_atomic_barrier (mod_s); |
4618 | ||
4619 | label1 = NULL_RTX; | |
4620 | if (!is_weak) | |
4621 | { | |
4622 | label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); | |
4623 | emit_label (XEXP (label1, 0)); | |
4624 | } | |
596d3184 | 4625 | label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); |
596d3184 | 4626 | |
4627 | emit_load_locked (DImode, scratch, mem); | |
4628 | ||
4629 | width = GEN_INT (GET_MODE_BITSIZE (mode)); | |
4630 | mask = GEN_INT (mode == QImode ? 0xff : 0xffff); | |
9bab4302 | 4631 | emit_insn (gen_extxl (dest, scratch, width, addr)); |
596d3184 | 4632 | |
4633 | if (oldval == const0_rtx) | |
51c750d8 | 4634 | { |
4635 | emit_move_insn (cond, const0_rtx); | |
4636 | x = gen_rtx_NE (DImode, dest, const0_rtx); | |
4637 | } | |
596d3184 | 4638 | else |
4639 | { | |
4640 | x = gen_rtx_EQ (DImode, dest, oldval); | |
d1f9b275 | 4641 | emit_insn (gen_rtx_SET (cond, x)); |
596d3184 | 4642 | x = gen_rtx_EQ (DImode, cond, const0_rtx); |
4643 | } | |
4644 | emit_unlikely_jump (x, label2); | |
4645 | ||
51c750d8 | 4646 | emit_insn (gen_mskxl (cond, scratch, mask, addr)); |
596d3184 | 4647 | |
51c750d8 | 4648 | if (newval != const0_rtx) |
4649 | emit_insn (gen_iordi3 (cond, cond, newval)); | |
596d3184 | 4650 | |
51c750d8 | 4651 | emit_store_conditional (DImode, cond, mem, cond); |
596d3184 | 4652 | |
51c750d8 | 4653 | if (!is_weak) |
4654 | { | |
4655 | x = gen_rtx_EQ (DImode, cond, const0_rtx); | |
4656 | emit_unlikely_jump (x, label1); | |
4657 | } | |
4658 | ||
a372f7ca | 4659 | if (!is_mm_relaxed (mod_f)) |
51c750d8 | 4660 | emit_label (XEXP (label2, 0)); |
4661 | ||
4662 | alpha_post_atomic_barrier (mod_s); | |
4663 | ||
a372f7ca | 4664 | if (is_mm_relaxed (mod_f)) |
51c750d8 | 4665 | emit_label (XEXP (label2, 0)); |
596d3184 | 4666 | } |
4667 | ||
032caa7b | 4668 | /* Expand an atomic exchange operation. */ |
4669 | ||
4670 | void | |
51c750d8 | 4671 | alpha_split_atomic_exchange (rtx operands[]) |
032caa7b | 4672 | { |
51c750d8 | 4673 | rtx retval, mem, val, scratch; |
4674 | enum memmodel model; | |
3754d046 | 4675 | machine_mode mode; |
51c750d8 | 4676 | rtx label, x, cond; |
4677 | ||
4678 | retval = operands[0]; | |
4679 | mem = operands[1]; | |
4680 | val = operands[2]; | |
4681 | model = (enum memmodel) INTVAL (operands[3]); | |
4682 | scratch = operands[4]; | |
4683 | mode = GET_MODE (mem); | |
4684 | cond = gen_lowpart (DImode, scratch); | |
4685 | ||
4686 | alpha_pre_atomic_barrier (model); | |
f155876e | 4687 | |
032caa7b | 4688 | label = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); |
4689 | emit_label (XEXP (label, 0)); | |
4690 | ||
4691 | emit_load_locked (mode, retval, mem); | |
4692 | emit_move_insn (scratch, val); | |
4693 | emit_store_conditional (mode, cond, mem, scratch); | |
4694 | ||
4695 | x = gen_rtx_EQ (DImode, cond, const0_rtx); | |
4696 | emit_unlikely_jump (x, label); | |
a15b4a3c | 4697 | |
51c750d8 | 4698 | alpha_post_atomic_barrier (model); |
f155876e | 4699 | } |
596d3184 | 4700 | |
4701 | void | |
51c750d8 | 4702 | alpha_expand_atomic_exchange_12 (rtx operands[]) |
596d3184 | 4703 | { |
51c750d8 | 4704 | rtx dst, mem, val, model; |
3754d046 | 4705 | machine_mode mode; |
596d3184 | 4706 | rtx addr, align, wdst; |
51c750d8 | 4707 | rtx (*gen) (rtx, rtx, rtx, rtx, rtx); |
596d3184 | 4708 | |
51c750d8 | 4709 | dst = operands[0]; |
4710 | mem = operands[1]; | |
4711 | val = operands[2]; | |
4712 | model = operands[3]; | |
4713 | mode = GET_MODE (mem); | |
4714 | ||
4715 | /* We forced the address into a register via mem_noofs_operand. */ | |
4716 | addr = XEXP (mem, 0); | |
4717 | gcc_assert (register_operand (addr, DImode)); | |
596d3184 | 4718 | |
596d3184 | 4719 | align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8), |
4720 | NULL_RTX, 1, OPTAB_DIRECT); | |
4721 | ||
4722 | /* Insert val into the correct byte location within the word. */ | |
51c750d8 | 4723 | if (val != const0_rtx) |
4724 | val = emit_insxl (mode, val, addr); | |
596d3184 | 4725 | |
4726 | wdst = gen_reg_rtx (DImode); | |
4727 | if (mode == QImode) | |
51c750d8 | 4728 | gen = gen_atomic_exchangeqi_1; |
596d3184 | 4729 | else |
51c750d8 | 4730 | gen = gen_atomic_exchangehi_1; |
4731 | emit_insn (gen (wdst, mem, val, align, model)); | |
596d3184 | 4732 | |
4733 | emit_move_insn (dst, gen_lowpart (mode, wdst)); | |
4734 | } | |
4735 | ||
4736 | void | |
51c750d8 | 4737 | alpha_split_atomic_exchange_12 (rtx operands[]) |
596d3184 | 4738 | { |
51c750d8 | 4739 | rtx dest, orig_mem, addr, val, align, scratch; |
596d3184 | 4740 | rtx label, mem, width, mask, x; |
3754d046 | 4741 | machine_mode mode; |
51c750d8 | 4742 | enum memmodel model; |
4743 | ||
4744 | dest = operands[0]; | |
4745 | orig_mem = operands[1]; | |
4746 | val = operands[2]; | |
4747 | align = operands[3]; | |
4748 | model = (enum memmodel) INTVAL (operands[4]); | |
4749 | scratch = operands[5]; | |
4750 | mode = GET_MODE (orig_mem); | |
4751 | addr = XEXP (orig_mem, 0); | |
596d3184 | 4752 | |
4753 | mem = gen_rtx_MEM (DImode, align); | |
51c750d8 | 4754 | MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (orig_mem); |
02891b92 | 4755 | if (MEM_ALIAS_SET (orig_mem) == ALIAS_SET_MEMORY_BARRIER) |
4756 | set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER); | |
51c750d8 | 4757 | |
4758 | alpha_pre_atomic_barrier (model); | |
596d3184 | 4759 | |
596d3184 | 4760 | label = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); |
4761 | emit_label (XEXP (label, 0)); | |
4762 | ||
4763 | emit_load_locked (DImode, scratch, mem); | |
4764 | ||
4765 | width = GEN_INT (GET_MODE_BITSIZE (mode)); | |
4766 | mask = GEN_INT (mode == QImode ? 0xff : 0xffff); | |
9bab4302 | 4767 | emit_insn (gen_extxl (dest, scratch, width, addr)); |
4768 | emit_insn (gen_mskxl (scratch, scratch, mask, addr)); | |
51c750d8 | 4769 | if (val != const0_rtx) |
4770 | emit_insn (gen_iordi3 (scratch, scratch, val)); | |
596d3184 | 4771 | |
4772 | emit_store_conditional (DImode, scratch, mem, scratch); | |
4773 | ||
4774 | x = gen_rtx_EQ (DImode, scratch, const0_rtx); | |
4775 | emit_unlikely_jump (x, label); | |
a15b4a3c | 4776 | |
51c750d8 | 4777 | alpha_post_atomic_barrier (model); |
596d3184 | 4778 | } |
bf2a98b3 | 4779 | \f |
4780 | /* Adjust the cost of a scheduling dependency. Return the new cost of | |
4781 | a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ | |
4782 | ||
747af5e7 | 4783 | static int |
99f52c2b | 4784 | alpha_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost, |
4785 | unsigned int) | |
bf2a98b3 | 4786 | { |
f5e8a4bc | 4787 | enum attr_type dep_insn_type; |
bf2a98b3 | 4788 | |
4789 | /* If the dependence is an anti-dependence, there is no cost. For an | |
4790 | output dependence, there is sometimes a cost, but it doesn't seem | |
4791 | worth handling those few cases. */ | |
99f52c2b | 4792 | if (dep_type != 0) |
7eb0c947 | 4793 | return cost; |
bf2a98b3 | 4794 | |
d2832bd8 | 4795 | /* If we can't recognize the insns, we can't really do anything. */ |
4796 | if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0) | |
4797 | return cost; | |
4798 | ||
d2832bd8 | 4799 | dep_insn_type = get_attr_type (dep_insn); |
4800 | ||
07c1a295 | 4801 | /* Bring in the user-defined memory latency. */ |
e7a69d05 | 4802 | if (dep_insn_type == TYPE_ILD |
4803 | || dep_insn_type == TYPE_FLD | |
4804 | || dep_insn_type == TYPE_LDSYM) | |
07c1a295 | 4805 | cost += alpha_memory_latency-1; |
4806 | ||
7eb0c947 | 4807 | /* Everything else handled in DFA bypasses now. */ |
3680ac41 | 4808 | |
bf2a98b3 | 4809 | return cost; |
4810 | } | |
747af5e7 | 4811 | |
7eb0c947 | 4812 | /* The number of instructions that can be issued per cycle. */ |
4813 | ||
747af5e7 | 4814 | static int |
92643d95 | 4815 | alpha_issue_rate (void) |
747af5e7 | 4816 | { |
fb64edde | 4817 | return (alpha_tune == PROCESSOR_EV4 ? 2 : 4); |
747af5e7 | 4818 | } |
4819 | ||
7eb0c947 | 4820 | /* How many alternative schedules to try. This should be as wide as the |
4821 | scheduling freedom in the DFA, but no wider. Making this value too | |
4822 | large results extra work for the scheduler. | |
4823 | ||
4824 | For EV4, loads can be issued to either IB0 or IB1, thus we have 2 | |
4825 | alternative schedules. For EV5, we can choose between E0/E1 and | |
8d232dc7 | 4826 | FA/FM. For EV6, an arithmetic insn can be issued to U0/U1/L0/L1. */ |
7eb0c947 | 4827 | |
4828 | static int | |
92643d95 | 4829 | alpha_multipass_dfa_lookahead (void) |
7eb0c947 | 4830 | { |
fb64edde | 4831 | return (alpha_tune == PROCESSOR_EV6 ? 4 : 2); |
7eb0c947 | 4832 | } |
0c0464e6 | 4833 | \f |
5f7b9df8 | 4834 | /* Machine-specific function data. */ |
4835 | ||
5ce94904 | 4836 | struct GTY(()) alpha_links; |
4837 | ||
fb1e4f4a | 4838 | struct GTY(()) machine_function |
5f7b9df8 | 4839 | { |
126b6848 | 4840 | /* For flag_reorder_blocks_and_partition. */ |
842ae815 | 4841 | rtx gp_save_rtx; |
50f36bdb | 4842 | |
4843 | /* For VMS condition handlers. */ | |
5ce94904 | 4844 | bool uses_condition_handler; |
4845 | ||
4846 | /* Linkage entries. */ | |
ee34b0e4 | 4847 | hash_map<nofree_string_hash, alpha_links *> *links; |
5f7b9df8 | 4848 | }; |
4849 | ||
1f3233d1 | 4850 | /* How to allocate a 'struct machine_function'. */ |
9caef960 | 4851 | |
1f3233d1 | 4852 | static struct machine_function * |
92643d95 | 4853 | alpha_init_machine_status (void) |
9caef960 | 4854 | { |
25a27413 | 4855 | return ggc_cleared_alloc<machine_function> (); |
9caef960 | 4856 | } |
9caef960 | 4857 | |
50f36bdb | 4858 | /* Support for frame based VMS condition handlers. */ |
4859 | ||
4860 | /* A VMS condition handler may be established for a function with a call to | |
4861 | __builtin_establish_vms_condition_handler, and cancelled with a call to | |
4862 | __builtin_revert_vms_condition_handler. | |
4863 | ||
4864 | The VMS Condition Handling Facility knows about the existence of a handler | |
4865 | from the procedure descriptor .handler field. As the VMS native compilers, | |
4866 | we store the user specified handler's address at a fixed location in the | |
4867 | stack frame and point the procedure descriptor at a common wrapper which | |
4868 | fetches the real handler's address and issues an indirect call. | |
4869 | ||
4870 | The indirection wrapper is "__gcc_shell_handler", provided by libgcc. | |
4871 | ||
4872 | We force the procedure kind to PT_STACK, and the fixed frame location is | |
4873 | fp+8, just before the register save area. We use the handler_data field in | |
4874 | the procedure descriptor to state the fp offset at which the installed | |
4875 | handler address can be found. */ | |
4876 | ||
4877 | #define VMS_COND_HANDLER_FP_OFFSET 8 | |
4878 | ||
4879 | /* Expand code to store the currently installed user VMS condition handler | |
4880 | into TARGET and install HANDLER as the new condition handler. */ | |
4881 | ||
4882 | void | |
4883 | alpha_expand_builtin_establish_vms_condition_handler (rtx target, rtx handler) | |
4884 | { | |
29c05e22 | 4885 | rtx handler_slot_address = plus_constant (Pmode, hard_frame_pointer_rtx, |
4886 | VMS_COND_HANDLER_FP_OFFSET); | |
50f36bdb | 4887 | |
4888 | rtx handler_slot | |
4889 | = gen_rtx_MEM (DImode, handler_slot_address); | |
4890 | ||
4891 | emit_move_insn (target, handler_slot); | |
4892 | emit_move_insn (handler_slot, handler); | |
4893 | ||
4894 | /* Notify the start/prologue/epilogue emitters that the condition handler | |
4895 | slot is needed. In addition to reserving the slot space, this will force | |
4896 | the procedure kind to PT_STACK so ensure that the hard_frame_pointer_rtx | |
4897 | use above is correct. */ | |
4898 | cfun->machine->uses_condition_handler = true; | |
4899 | } | |
4900 | ||
4901 | /* Expand code to store the current VMS condition handler into TARGET and | |
4902 | nullify it. */ | |
4903 | ||
4904 | void | |
4905 | alpha_expand_builtin_revert_vms_condition_handler (rtx target) | |
4906 | { | |
4907 | /* We implement this by establishing a null condition handler, with the tiny | |
4908 | side effect of setting uses_condition_handler. This is a little bit | |
4909 | pessimistic if no actual builtin_establish call is ever issued, which is | |
4910 | not a real problem and expected never to happen anyway. */ | |
4911 | ||
4912 | alpha_expand_builtin_establish_vms_condition_handler (target, const0_rtx); | |
4913 | } | |
4914 | ||
0c0464e6 | 4915 | /* Functions to save and restore alpha_return_addr_rtx. */ |
4916 | ||
0c0464e6 | 4917 | /* Start the ball rolling with RETURN_ADDR_RTX. */ |
4918 | ||
4919 | rtx | |
92643d95 | 4920 | alpha_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) |
0c0464e6 | 4921 | { |
0c0464e6 | 4922 | if (count != 0) |
4923 | return const0_rtx; | |
4924 | ||
0f37b7a2 | 4925 | return get_hard_reg_initial_val (Pmode, REG_RA); |
0c0464e6 | 4926 | } |
4927 | ||
a221313c | 4928 | /* Return or create a memory slot containing the gp value for the current |
66561750 | 4929 | function. Needed only if TARGET_LD_BUGGY_LDGP. */ |
4930 | ||
4931 | rtx | |
92643d95 | 4932 | alpha_gp_save_rtx (void) |
66561750 | 4933 | { |
7f0256ea | 4934 | rtx_insn *seq; |
4935 | rtx m = cfun->machine->gp_save_rtx; | |
a221313c | 4936 | |
4937 | if (m == NULL) | |
4938 | { | |
4939 | start_sequence (); | |
4940 | ||
4941 | m = assign_stack_local (DImode, UNITS_PER_WORD, BITS_PER_WORD); | |
4942 | m = validize_mem (m); | |
4943 | emit_move_insn (m, pic_offset_table_rtx); | |
4944 | ||
4945 | seq = get_insns (); | |
4946 | end_sequence (); | |
8a1586ba | 4947 | |
4948 | /* We used to simply emit the sequence after entry_of_function. | |
4949 | However this breaks the CFG if the first instruction in the | |
4950 | first block is not the NOTE_INSN_BASIC_BLOCK, for example a | |
4951 | label. Emit the sequence properly on the edge. We are only | |
4952 | invoked from dw2_build_landing_pads and finish_eh_generation | |
4953 | will call commit_edge_insertions thanks to a kludge. */ | |
34154e27 | 4954 | insert_insn_on_edge (seq, |
4955 | single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))); | |
a221313c | 4956 | |
4957 | cfun->machine->gp_save_rtx = m; | |
4958 | } | |
4959 | ||
4960 | return m; | |
66561750 | 4961 | } |
4962 | ||
0d25d8c2 | 4963 | static void |
4964 | alpha_instantiate_decls (void) | |
4965 | { | |
4966 | if (cfun->machine->gp_save_rtx != NULL_RTX) | |
4967 | instantiate_decl_rtl (cfun->machine->gp_save_rtx); | |
4968 | } | |
4969 | ||
0c0464e6 | 4970 | static int |
92643d95 | 4971 | alpha_ra_ever_killed (void) |
0c0464e6 | 4972 | { |
7f0256ea | 4973 | rtx_insn *top; |
5a965225 | 4974 | |
0f37b7a2 | 4975 | if (!has_hard_reg_initial_val (Pmode, REG_RA)) |
3072d30e | 4976 | return (int)df_regs_ever_live_p (REG_RA); |
0c0464e6 | 4977 | |
5a965225 | 4978 | push_topmost_sequence (); |
4979 | top = get_insns (); | |
4980 | pop_topmost_sequence (); | |
4981 | ||
311f821c | 4982 | return reg_set_between_p (gen_rtx_REG (Pmode, REG_RA), top, NULL); |
0c0464e6 | 4983 | } |
4984 | ||
bf2a98b3 | 4985 | \f |
6fec94c5 | 4986 | /* Return the trap mode suffix applicable to the current |
65abff06 | 4987 | instruction, or NULL. */ |
bf2a98b3 | 4988 | |
6fec94c5 | 4989 | static const char * |
92643d95 | 4990 | get_trap_mode_suffix (void) |
bf2a98b3 | 4991 | { |
6fec94c5 | 4992 | enum attr_trap_suffix s = get_attr_trap_suffix (current_output_insn); |
bf2a98b3 | 4993 | |
6fec94c5 | 4994 | switch (s) |
bf2a98b3 | 4995 | { |
6fec94c5 | 4996 | case TRAP_SUFFIX_NONE: |
4997 | return NULL; | |
c4622276 | 4998 | |
6fec94c5 | 4999 | case TRAP_SUFFIX_SU: |
bc16f0c1 | 5000 | if (alpha_fptm >= ALPHA_FPTM_SU) |
6fec94c5 | 5001 | return "su"; |
5002 | return NULL; | |
c4622276 | 5003 | |
6fec94c5 | 5004 | case TRAP_SUFFIX_SUI: |
5005 | if (alpha_fptm >= ALPHA_FPTM_SUI) | |
5006 | return "sui"; | |
5007 | return NULL; | |
5008 | ||
5009 | case TRAP_SUFFIX_V_SV: | |
39344852 | 5010 | switch (alpha_fptm) |
5011 | { | |
5012 | case ALPHA_FPTM_N: | |
6fec94c5 | 5013 | return NULL; |
39344852 | 5014 | case ALPHA_FPTM_U: |
6fec94c5 | 5015 | return "v"; |
39344852 | 5016 | case ALPHA_FPTM_SU: |
5017 | case ALPHA_FPTM_SUI: | |
6fec94c5 | 5018 | return "sv"; |
4d10b463 | 5019 | default: |
5020 | gcc_unreachable (); | |
39344852 | 5021 | } |
39344852 | 5022 | |
6fec94c5 | 5023 | case TRAP_SUFFIX_V_SV_SVI: |
b5ea3193 | 5024 | switch (alpha_fptm) |
5025 | { | |
5026 | case ALPHA_FPTM_N: | |
6fec94c5 | 5027 | return NULL; |
b5ea3193 | 5028 | case ALPHA_FPTM_U: |
6fec94c5 | 5029 | return "v"; |
b5ea3193 | 5030 | case ALPHA_FPTM_SU: |
6fec94c5 | 5031 | return "sv"; |
b5ea3193 | 5032 | case ALPHA_FPTM_SUI: |
6fec94c5 | 5033 | return "svi"; |
4d10b463 | 5034 | default: |
5035 | gcc_unreachable (); | |
b5ea3193 | 5036 | } |
5037 | break; | |
5038 | ||
6fec94c5 | 5039 | case TRAP_SUFFIX_U_SU_SUI: |
c4622276 | 5040 | switch (alpha_fptm) |
5041 | { | |
5042 | case ALPHA_FPTM_N: | |
6fec94c5 | 5043 | return NULL; |
c4622276 | 5044 | case ALPHA_FPTM_U: |
6fec94c5 | 5045 | return "u"; |
c4622276 | 5046 | case ALPHA_FPTM_SU: |
6fec94c5 | 5047 | return "su"; |
c4622276 | 5048 | case ALPHA_FPTM_SUI: |
6fec94c5 | 5049 | return "sui"; |
4d10b463 | 5050 | default: |
5051 | gcc_unreachable (); | |
c4622276 | 5052 | } |
5053 | break; | |
4d10b463 | 5054 | |
5055 | default: | |
5056 | gcc_unreachable (); | |
6fec94c5 | 5057 | } |
4d10b463 | 5058 | gcc_unreachable (); |
6fec94c5 | 5059 | } |
c4622276 | 5060 | |
6fec94c5 | 5061 | /* Return the rounding mode suffix applicable to the current |
65abff06 | 5062 | instruction, or NULL. */ |
6fec94c5 | 5063 | |
5064 | static const char * | |
92643d95 | 5065 | get_round_mode_suffix (void) |
6fec94c5 | 5066 | { |
5067 | enum attr_round_suffix s = get_attr_round_suffix (current_output_insn); | |
5068 | ||
5069 | switch (s) | |
5070 | { | |
5071 | case ROUND_SUFFIX_NONE: | |
5072 | return NULL; | |
5073 | case ROUND_SUFFIX_NORMAL: | |
5074 | switch (alpha_fprm) | |
c4622276 | 5075 | { |
6fec94c5 | 5076 | case ALPHA_FPRM_NORM: |
5077 | return NULL; | |
9e7454d0 | 5078 | case ALPHA_FPRM_MINF: |
6fec94c5 | 5079 | return "m"; |
5080 | case ALPHA_FPRM_CHOP: | |
5081 | return "c"; | |
5082 | case ALPHA_FPRM_DYN: | |
5083 | return "d"; | |
4d10b463 | 5084 | default: |
5085 | gcc_unreachable (); | |
c4622276 | 5086 | } |
5087 | break; | |
5088 | ||
6fec94c5 | 5089 | case ROUND_SUFFIX_C: |
5090 | return "c"; | |
4d10b463 | 5091 | |
5092 | default: | |
5093 | gcc_unreachable (); | |
6fec94c5 | 5094 | } |
4d10b463 | 5095 | gcc_unreachable (); |
6fec94c5 | 5096 | } |
5097 | ||
a2ea1410 | 5098 | /* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */ |
6fec94c5 | 5099 | |
a2ea1410 | 5100 | static bool |
5101 | alpha_print_operand_punct_valid_p (unsigned char code) | |
5102 | { | |
5103 | return (code == '/' || code == ',' || code == '-' || code == '~' | |
5104 | || code == '#' || code == '*' || code == '&'); | |
5105 | } | |
5106 | ||
5107 | /* Implement TARGET_PRINT_OPERAND. The alpha-specific | |
5108 | operand codes are documented below. */ | |
5109 | ||
5110 | static void | |
5111 | alpha_print_operand (FILE *file, rtx x, int code) | |
6fec94c5 | 5112 | { |
5113 | int i; | |
5114 | ||
5115 | switch (code) | |
5116 | { | |
5117 | case '~': | |
5118 | /* Print the assembler name of the current function. */ | |
5119 | assemble_name (file, alpha_fnname); | |
5120 | break; | |
5121 | ||
5f7b9df8 | 5122 | case '&': |
3677652f | 5123 | if (const char *name = get_some_local_dynamic_name ()) |
5124 | assemble_name (file, name); | |
5125 | else | |
5126 | output_operand_lossage ("'%%&' used without any " | |
5127 | "local dynamic TLS references"); | |
5f7b9df8 | 5128 | break; |
5129 | ||
6fec94c5 | 5130 | case '/': |
a2ea1410 | 5131 | /* Generates the instruction suffix. The TRAP_SUFFIX and ROUND_SUFFIX |
5132 | attributes are examined to determine what is appropriate. */ | |
6fec94c5 | 5133 | { |
5134 | const char *trap = get_trap_mode_suffix (); | |
5135 | const char *round = get_round_mode_suffix (); | |
5136 | ||
5137 | if (trap || round) | |
48a5030b | 5138 | fprintf (file, "/%s%s", (trap ? trap : ""), (round ? round : "")); |
6fec94c5 | 5139 | break; |
5140 | } | |
5141 | ||
8df4a58b | 5142 | case ',': |
a2ea1410 | 5143 | /* Generates single precision suffix for floating point |
5144 | instructions (s for IEEE, f for VAX). */ | |
6fec94c5 | 5145 | fputc ((TARGET_FLOAT_VAX ? 'f' : 's'), file); |
8df4a58b | 5146 | break; |
5147 | ||
5148 | case '-': | |
a2ea1410 | 5149 | /* Generates double precision suffix for floating point |
5150 | instructions (t for IEEE, g for VAX). */ | |
6fec94c5 | 5151 | fputc ((TARGET_FLOAT_VAX ? 'g' : 't'), file); |
8df4a58b | 5152 | break; |
5153 | ||
1f0ce6a6 | 5154 | case '#': |
5155 | if (alpha_this_literal_sequence_number == 0) | |
5156 | alpha_this_literal_sequence_number = alpha_next_sequence_number++; | |
5157 | fprintf (file, "%d", alpha_this_literal_sequence_number); | |
5158 | break; | |
5159 | ||
5160 | case '*': | |
5161 | if (alpha_this_gpdisp_sequence_number == 0) | |
5162 | alpha_this_gpdisp_sequence_number = alpha_next_sequence_number++; | |
5163 | fprintf (file, "%d", alpha_this_gpdisp_sequence_number); | |
5164 | break; | |
5165 | ||
ad2ed779 | 5166 | case 'J': |
5f7b9df8 | 5167 | { |
5168 | const char *lituse; | |
5169 | ||
5170 | if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD_CALL) | |
5171 | { | |
5172 | x = XVECEXP (x, 0, 0); | |
5173 | lituse = "lituse_tlsgd"; | |
5174 | } | |
5175 | else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSLDM_CALL) | |
5176 | { | |
5177 | x = XVECEXP (x, 0, 0); | |
5178 | lituse = "lituse_tlsldm"; | |
5179 | } | |
c933fb42 | 5180 | else if (CONST_INT_P (x)) |
5f7b9df8 | 5181 | lituse = "lituse_jsr"; |
5182 | else | |
5183 | { | |
5184 | output_operand_lossage ("invalid %%J value"); | |
5185 | break; | |
5186 | } | |
5187 | ||
5188 | if (x != const0_rtx) | |
5189 | fprintf (file, "\t\t!%s!%d", lituse, (int) INTVAL (x)); | |
5190 | } | |
ad2ed779 | 5191 | break; |
5192 | ||
592222c2 | 5193 | case 'j': |
5194 | { | |
5195 | const char *lituse; | |
5196 | ||
5197 | #ifdef HAVE_AS_JSRDIRECT_RELOCS | |
5198 | lituse = "lituse_jsrdirect"; | |
5199 | #else | |
5200 | lituse = "lituse_jsr"; | |
5201 | #endif | |
5202 | ||
5203 | gcc_assert (INTVAL (x) != 0); | |
5204 | fprintf (file, "\t\t!%s!%d", lituse, (int) INTVAL (x)); | |
5205 | } | |
5206 | break; | |
bf2a98b3 | 5207 | case 'r': |
5208 | /* If this operand is the constant zero, write it as "$31". */ | |
c933fb42 | 5209 | if (REG_P (x)) |
bf2a98b3 | 5210 | fprintf (file, "%s", reg_names[REGNO (x)]); |
5211 | else if (x == CONST0_RTX (GET_MODE (x))) | |
5212 | fprintf (file, "$31"); | |
5213 | else | |
5214 | output_operand_lossage ("invalid %%r value"); | |
bf2a98b3 | 5215 | break; |
5216 | ||
5217 | case 'R': | |
5218 | /* Similar, but for floating-point. */ | |
c933fb42 | 5219 | if (REG_P (x)) |
bf2a98b3 | 5220 | fprintf (file, "%s", reg_names[REGNO (x)]); |
5221 | else if (x == CONST0_RTX (GET_MODE (x))) | |
5222 | fprintf (file, "$f31"); | |
5223 | else | |
5224 | output_operand_lossage ("invalid %%R value"); | |
bf2a98b3 | 5225 | break; |
5226 | ||
5227 | case 'N': | |
5228 | /* Write the 1's complement of a constant. */ | |
c933fb42 | 5229 | if (!CONST_INT_P (x)) |
bf2a98b3 | 5230 | output_operand_lossage ("invalid %%N value"); |
5231 | ||
61a63ca5 | 5232 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INTVAL (x)); |
bf2a98b3 | 5233 | break; |
5234 | ||
5235 | case 'P': | |
5236 | /* Write 1 << C, for a constant C. */ | |
c933fb42 | 5237 | if (!CONST_INT_P (x)) |
bf2a98b3 | 5238 | output_operand_lossage ("invalid %%P value"); |
5239 | ||
a2d7211e | 5240 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, HOST_WIDE_INT_1 << INTVAL (x)); |
bf2a98b3 | 5241 | break; |
5242 | ||
5243 | case 'h': | |
5244 | /* Write the high-order 16 bits of a constant, sign-extended. */ | |
c933fb42 | 5245 | if (!CONST_INT_P (x)) |
bf2a98b3 | 5246 | output_operand_lossage ("invalid %%h value"); |
5247 | ||
61a63ca5 | 5248 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) >> 16); |
bf2a98b3 | 5249 | break; |
5250 | ||
5251 | case 'L': | |
5252 | /* Write the low-order 16 bits of a constant, sign-extended. */ | |
c933fb42 | 5253 | if (!CONST_INT_P (x)) |
bf2a98b3 | 5254 | output_operand_lossage ("invalid %%L value"); |
5255 | ||
61a63ca5 | 5256 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, |
5257 | (INTVAL (x) & 0xffff) - 2 * (INTVAL (x) & 0x8000)); | |
bf2a98b3 | 5258 | break; |
5259 | ||
5260 | case 'm': | |
5261 | /* Write mask for ZAP insn. */ | |
5c5c1f00 | 5262 | if (CONST_INT_P (x)) |
bf2a98b3 | 5263 | { |
5264 | HOST_WIDE_INT mask = 0, value = INTVAL (x); | |
5265 | ||
5266 | for (i = 0; i < 8; i++, value >>= 8) | |
5267 | if (value & 0xff) | |
5268 | mask |= (1 << i); | |
5269 | ||
61a63ca5 | 5270 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask); |
bf2a98b3 | 5271 | } |
5272 | else | |
5273 | output_operand_lossage ("invalid %%m value"); | |
5274 | break; | |
5275 | ||
5276 | case 'M': | |
34377880 | 5277 | /* 'b', 'w', 'l', or 'q' as the value of the constant. */ |
7bc95bfb | 5278 | if (!mode_width_operand (x, VOIDmode)) |
bf2a98b3 | 5279 | output_operand_lossage ("invalid %%M value"); |
5280 | ||
5281 | fprintf (file, "%s", | |
34377880 | 5282 | (INTVAL (x) == 8 ? "b" |
5283 | : INTVAL (x) == 16 ? "w" | |
5284 | : INTVAL (x) == 32 ? "l" | |
5285 | : "q")); | |
bf2a98b3 | 5286 | break; |
5287 | ||
5288 | case 'U': | |
5289 | /* Similar, except do it from the mask. */ | |
c933fb42 | 5290 | if (CONST_INT_P (x)) |
ae4cd3a5 | 5291 | { |
5292 | HOST_WIDE_INT value = INTVAL (x); | |
5293 | ||
5294 | if (value == 0xff) | |
5295 | { | |
5296 | fputc ('b', file); | |
5297 | break; | |
5298 | } | |
5299 | if (value == 0xffff) | |
5300 | { | |
5301 | fputc ('w', file); | |
5302 | break; | |
5303 | } | |
5304 | if (value == 0xffffffff) | |
5305 | { | |
5306 | fputc ('l', file); | |
5307 | break; | |
5308 | } | |
5309 | if (value == -1) | |
5310 | { | |
5311 | fputc ('q', file); | |
5312 | break; | |
5313 | } | |
5314 | } | |
a2d7211e | 5315 | |
ae4cd3a5 | 5316 | output_operand_lossage ("invalid %%U value"); |
bf2a98b3 | 5317 | break; |
5318 | ||
5319 | case 's': | |
9bab4302 | 5320 | /* Write the constant value divided by 8. */ |
c933fb42 | 5321 | if (!CONST_INT_P (x) |
9bab4302 | 5322 | || (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 |
9caef960 | 5323 | || (INTVAL (x) & 7) != 0) |
bf2a98b3 | 5324 | output_operand_lossage ("invalid %%s value"); |
5325 | ||
9bab4302 | 5326 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) / 8); |
bf2a98b3 | 5327 | break; |
5328 | ||
62dc3582 | 5329 | case 'C': case 'D': case 'c': case 'd': |
bf2a98b3 | 5330 | /* Write out comparison name. */ |
62dc3582 | 5331 | { |
5332 | enum rtx_code c = GET_CODE (x); | |
5333 | ||
6720e96c | 5334 | if (!COMPARISON_P (x)) |
62dc3582 | 5335 | output_operand_lossage ("invalid %%C value"); |
5336 | ||
f3d263a7 | 5337 | else if (code == 'D') |
62dc3582 | 5338 | c = reverse_condition (c); |
5339 | else if (code == 'c') | |
5340 | c = swap_condition (c); | |
5341 | else if (code == 'd') | |
5342 | c = swap_condition (reverse_condition (c)); | |
5343 | ||
5344 | if (c == LEU) | |
5345 | fprintf (file, "ule"); | |
5346 | else if (c == LTU) | |
5347 | fprintf (file, "ult"); | |
a4110d9a | 5348 | else if (c == UNORDERED) |
5349 | fprintf (file, "un"); | |
62dc3582 | 5350 | else |
5351 | fprintf (file, "%s", GET_RTX_NAME (c)); | |
5352 | } | |
8ad50a44 | 5353 | break; |
5354 | ||
bf2a98b3 | 5355 | case 'E': |
5356 | /* Write the divide or modulus operator. */ | |
5357 | switch (GET_CODE (x)) | |
5358 | { | |
5359 | case DIV: | |
5360 | fprintf (file, "div%s", GET_MODE (x) == SImode ? "l" : "q"); | |
5361 | break; | |
5362 | case UDIV: | |
5363 | fprintf (file, "div%su", GET_MODE (x) == SImode ? "l" : "q"); | |
5364 | break; | |
5365 | case MOD: | |
5366 | fprintf (file, "rem%s", GET_MODE (x) == SImode ? "l" : "q"); | |
5367 | break; | |
5368 | case UMOD: | |
5369 | fprintf (file, "rem%su", GET_MODE (x) == SImode ? "l" : "q"); | |
5370 | break; | |
5371 | default: | |
5372 | output_operand_lossage ("invalid %%E value"); | |
5373 | break; | |
5374 | } | |
5375 | break; | |
5376 | ||
bf2a98b3 | 5377 | case 'A': |
5378 | /* Write "_u" for unaligned access. */ | |
c933fb42 | 5379 | if (MEM_P (x) && GET_CODE (XEXP (x, 0)) == AND) |
bf2a98b3 | 5380 | fprintf (file, "_u"); |
5381 | break; | |
5382 | ||
5383 | case 0: | |
c933fb42 | 5384 | if (REG_P (x)) |
bf2a98b3 | 5385 | fprintf (file, "%s", reg_names[REGNO (x)]); |
c933fb42 | 5386 | else if (MEM_P (x)) |
3c047fe9 | 5387 | output_address (GET_MODE (x), XEXP (x, 0)); |
5f7b9df8 | 5388 | else if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC) |
5389 | { | |
5390 | switch (XINT (XEXP (x, 0), 1)) | |
5391 | { | |
5392 | case UNSPEC_DTPREL: | |
5393 | case UNSPEC_TPREL: | |
5394 | output_addr_const (file, XVECEXP (XEXP (x, 0), 0, 0)); | |
5395 | break; | |
5396 | default: | |
5397 | output_operand_lossage ("unknown relocation unspec"); | |
5398 | break; | |
5399 | } | |
5400 | } | |
bf2a98b3 | 5401 | else |
5402 | output_addr_const (file, x); | |
5403 | break; | |
5404 | ||
5405 | default: | |
5406 | output_operand_lossage ("invalid %%xn code"); | |
5407 | } | |
5408 | } | |
6e0fe99e | 5409 | |
a2ea1410 | 5410 | /* Implement TARGET_PRINT_OPERAND_ADDRESS. */ |
5411 | ||
5412 | static void | |
5413 | alpha_print_operand_address (FILE *file, machine_mode /*mode*/, rtx addr) | |
6e0fe99e | 5414 | { |
a3e39a24 | 5415 | int basereg = 31; |
6e0fe99e | 5416 | HOST_WIDE_INT offset = 0; |
5417 | ||
5418 | if (GET_CODE (addr) == AND) | |
5419 | addr = XEXP (addr, 0); | |
6e0fe99e | 5420 | |
a3e39a24 | 5421 | if (GET_CODE (addr) == PLUS |
c933fb42 | 5422 | && CONST_INT_P (XEXP (addr, 1))) |
6e0fe99e | 5423 | { |
5424 | offset = INTVAL (XEXP (addr, 1)); | |
a3e39a24 | 5425 | addr = XEXP (addr, 0); |
6e0fe99e | 5426 | } |
1f0ce6a6 | 5427 | |
5428 | if (GET_CODE (addr) == LO_SUM) | |
5429 | { | |
5f7b9df8 | 5430 | const char *reloc16, *reloclo; |
5431 | rtx op1 = XEXP (addr, 1); | |
5432 | ||
5433 | if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1, 0)) == UNSPEC) | |
5434 | { | |
5435 | op1 = XEXP (op1, 0); | |
5436 | switch (XINT (op1, 1)) | |
5437 | { | |
5438 | case UNSPEC_DTPREL: | |
5439 | reloc16 = NULL; | |
5440 | reloclo = (alpha_tls_size == 16 ? "dtprel" : "dtprello"); | |
5441 | break; | |
5442 | case UNSPEC_TPREL: | |
5443 | reloc16 = NULL; | |
5444 | reloclo = (alpha_tls_size == 16 ? "tprel" : "tprello"); | |
5445 | break; | |
5446 | default: | |
5447 | output_operand_lossage ("unknown relocation unspec"); | |
5448 | return; | |
5449 | } | |
5450 | ||
5451 | output_addr_const (file, XVECEXP (op1, 0, 0)); | |
5452 | } | |
5453 | else | |
5454 | { | |
5455 | reloc16 = "gprel"; | |
5456 | reloclo = "gprellow"; | |
5457 | output_addr_const (file, op1); | |
5458 | } | |
5459 | ||
1f0ce6a6 | 5460 | if (offset) |
4840a03a | 5461 | fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset); |
9e7454d0 | 5462 | |
1f0ce6a6 | 5463 | addr = XEXP (addr, 0); |
4d10b463 | 5464 | switch (GET_CODE (addr)) |
5465 | { | |
5466 | case REG: | |
5467 | basereg = REGNO (addr); | |
5468 | break; | |
5469 | ||
5470 | case SUBREG: | |
5471 | basereg = subreg_regno (addr); | |
5472 | break; | |
5473 | ||
5474 | default: | |
5475 | gcc_unreachable (); | |
5476 | } | |
5dcb037d | 5477 | |
5478 | fprintf (file, "($%d)\t\t!%s", basereg, | |
5f7b9df8 | 5479 | (basereg == 29 ? reloc16 : reloclo)); |
1f0ce6a6 | 5480 | return; |
5481 | } | |
5482 | ||
4d10b463 | 5483 | switch (GET_CODE (addr)) |
5484 | { | |
5485 | case REG: | |
5486 | basereg = REGNO (addr); | |
5487 | break; | |
5488 | ||
5489 | case SUBREG: | |
5490 | basereg = subreg_regno (addr); | |
5491 | break; | |
5492 | ||
5493 | case CONST_INT: | |
5494 | offset = INTVAL (addr); | |
5495 | break; | |
cf73d31f | 5496 | |
4d10b463 | 5497 | case SYMBOL_REF: |
90449b57 | 5498 | gcc_assert(TARGET_ABI_OPEN_VMS || this_is_asm_operands); |
cf73d31f | 5499 | fprintf (file, "%s", XSTR (addr, 0)); |
5500 | return; | |
4d10b463 | 5501 | |
5502 | case CONST: | |
90449b57 | 5503 | gcc_assert(TARGET_ABI_OPEN_VMS || this_is_asm_operands); |
4d10b463 | 5504 | gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS |
5505 | && GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF); | |
6433714e | 5506 | fprintf (file, "%s+" HOST_WIDE_INT_PRINT_DEC, |
cf73d31f | 5507 | XSTR (XEXP (XEXP (addr, 0), 0), 0), |
5508 | INTVAL (XEXP (XEXP (addr, 0), 1))); | |
5509 | return; | |
90449b57 | 5510 | |
4d10b463 | 5511 | default: |
90449b57 | 5512 | output_operand_lossage ("invalid operand address"); |
5513 | return; | |
4d10b463 | 5514 | } |
6e0fe99e | 5515 | |
4840a03a | 5516 | fprintf (file, HOST_WIDE_INT_PRINT_DEC "($%d)", offset, basereg); |
6e0fe99e | 5517 | } |
bf2a98b3 | 5518 | \f |
9e042f31 | 5519 | /* Emit RTL insns to initialize the variable parts of a trampoline at |
7bcbe23a | 5520 | M_TRAMP. FNDECL is target function's decl. CHAIN_VALUE is an rtx |
5521 | for the static chain value for the function. */ | |
96297568 | 5522 | |
7bcbe23a | 5523 | static void |
5524 | alpha_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) | |
9e042f31 | 5525 | { |
7bcbe23a | 5526 | rtx fnaddr, mem, word1, word2; |
5527 | ||
5528 | fnaddr = XEXP (DECL_RTL (fndecl), 0); | |
9e042f31 | 5529 | |
17683b9f | 5530 | #ifdef POINTERS_EXTEND_UNSIGNED |
7bcbe23a | 5531 | fnaddr = convert_memory_address (Pmode, fnaddr); |
5532 | chain_value = convert_memory_address (Pmode, chain_value); | |
17683b9f | 5533 | #endif |
5534 | ||
d2f33c43 | 5535 | if (TARGET_ABI_OPEN_VMS) |
5536 | { | |
d2f33c43 | 5537 | const char *fnname; |
5538 | char *trname; | |
5539 | ||
5540 | /* Construct the name of the trampoline entry point. */ | |
5541 | fnname = XSTR (fnaddr, 0); | |
5542 | trname = (char *) alloca (strlen (fnname) + 5); | |
5543 | strcpy (trname, fnname); | |
5544 | strcat (trname, "..tr"); | |
7bcbe23a | 5545 | fnname = ggc_alloc_string (trname, strlen (trname) + 1); |
5546 | word2 = gen_rtx_SYMBOL_REF (Pmode, fnname); | |
d2f33c43 | 5547 | |
5548 | /* Trampoline (or "bounded") procedure descriptor is constructed from | |
5549 | the function's procedure descriptor with certain fields zeroed IAW | |
5550 | the VMS calling standard. This is stored in the first quadword. */ | |
7bcbe23a | 5551 | word1 = force_reg (DImode, gen_const_mem (DImode, fnaddr)); |
3ea24468 | 5552 | word1 = expand_and (DImode, word1, |
1fa4dd5c | 5553 | GEN_INT (HOST_WIDE_INT_C (0xffff0fff0000fff0)), |
5554 | NULL); | |
d2f33c43 | 5555 | } |
7bcbe23a | 5556 | else |
5557 | { | |
5558 | /* These 4 instructions are: | |
5559 | ldq $1,24($27) | |
5560 | ldq $27,16($27) | |
5561 | jmp $31,($27),0 | |
5562 | nop | |
5563 | We don't bother setting the HINT field of the jump; the nop | |
5564 | is merely there for padding. */ | |
1fa4dd5c | 5565 | word1 = GEN_INT (HOST_WIDE_INT_C (0xa77b0010a43b0018)); |
5566 | word2 = GEN_INT (HOST_WIDE_INT_C (0x47ff041f6bfb0000)); | |
7bcbe23a | 5567 | } |
5568 | ||
5569 | /* Store the first two words, as computed above. */ | |
5570 | mem = adjust_address (m_tramp, DImode, 0); | |
5571 | emit_move_insn (mem, word1); | |
5572 | mem = adjust_address (m_tramp, DImode, 8); | |
5573 | emit_move_insn (mem, word2); | |
5574 | ||
5575 | /* Store function address and static chain value. */ | |
5576 | mem = adjust_address (m_tramp, Pmode, 16); | |
5577 | emit_move_insn (mem, fnaddr); | |
5578 | mem = adjust_address (m_tramp, Pmode, 24); | |
5579 | emit_move_insn (mem, chain_value); | |
d2f33c43 | 5580 | |
4505d022 | 5581 | if (TARGET_ABI_OSF) |
7bcbe23a | 5582 | { |
5583 | emit_insn (gen_imb ()); | |
a6f06169 | 5584 | #ifdef HAVE_ENABLE_EXECUTE_STACK |
7bcbe23a | 5585 | emit_library_call (init_one_libfunc ("__enable_execute_stack"), |
9e9e5c15 | 5586 | LCT_NORMAL, VOIDmode, XEXP (m_tramp, 0), Pmode); |
9e042f31 | 5587 | #endif |
7bcbe23a | 5588 | } |
9e042f31 | 5589 | } |
5590 | \f | |
915c336f | 5591 | /* Determine where to put an argument to a function. |
5592 | Value is zero to push the argument on the stack, | |
5593 | or a hard register in which to store the argument. | |
5594 | ||
5595 | MODE is the argument's machine mode. | |
5596 | TYPE is the data type of the argument (as a tree). | |
5597 | This is null for libcalls where that information may | |
5598 | not be available. | |
5599 | CUM is a variable of type CUMULATIVE_ARGS which gives info about | |
5600 | the preceding args and about the function being called. | |
5601 | NAMED is nonzero if this argument is a named parameter | |
5602 | (otherwise it is an extra parameter matching an ellipsis). | |
5603 | ||
5604 | On Alpha the first 6 words of args are normally in registers | |
5605 | and the rest are pushed. */ | |
5606 | ||
54ea4630 | 5607 | static rtx |
3754d046 | 5608 | alpha_function_arg (cumulative_args_t cum_v, machine_mode mode, |
54ea4630 | 5609 | const_tree type, bool named ATTRIBUTE_UNUSED) |
915c336f | 5610 | { |
39cba157 | 5611 | CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); |
915c336f | 5612 | int basereg; |
57e47080 | 5613 | int num_args; |
915c336f | 5614 | |
a685f5d8 | 5615 | /* Don't get confused and pass small structures in FP registers. */ |
5616 | if (type && AGGREGATE_TYPE_P (type)) | |
9caef960 | 5617 | basereg = 16; |
a685f5d8 | 5618 | else |
5619 | { | |
92d40bc4 | 5620 | /* With alpha_split_complex_arg, we shouldn't see any raw complex |
a685f5d8 | 5621 | values here. */ |
1d674b45 | 5622 | gcc_checking_assert (!COMPLEX_MODE_P (mode)); |
a685f5d8 | 5623 | |
5624 | /* Set up defaults for FP operands passed in FP registers, and | |
5625 | integral operands passed in integer registers. */ | |
5626 | if (TARGET_FPREGS && GET_MODE_CLASS (mode) == MODE_FLOAT) | |
5627 | basereg = 32 + 16; | |
5628 | else | |
5629 | basereg = 16; | |
5630 | } | |
9caef960 | 5631 | |
5632 | /* ??? Irritatingly, the definition of CUMULATIVE_ARGS is different for | |
54ea4630 | 5633 | the two platforms, so we can't avoid conditional compilation. */ |
1467e953 | 5634 | #if TARGET_ABI_OPEN_VMS |
9caef960 | 5635 | { |
5636 | if (mode == VOIDmode) | |
b50190db | 5637 | return alpha_arg_info_reg_val (*cum); |
1467e953 | 5638 | |
54ea4630 | 5639 | num_args = cum->num_args; |
0336f0f0 | 5640 | if (num_args >= 6 |
5641 | || targetm.calls.must_pass_in_stack (mode, type)) | |
9caef960 | 5642 | return NULL_RTX; |
5643 | } | |
a685f5d8 | 5644 | #elif TARGET_ABI_OSF |
9caef960 | 5645 | { |
54ea4630 | 5646 | if (*cum >= 6) |
9caef960 | 5647 | return NULL_RTX; |
54ea4630 | 5648 | num_args = *cum; |
9caef960 | 5649 | |
5650 | /* VOID is passed as a special flag for "last argument". */ | |
5651 | if (type == void_type_node) | |
5652 | basereg = 16; | |
0336f0f0 | 5653 | else if (targetm.calls.must_pass_in_stack (mode, type)) |
9caef960 | 5654 | return NULL_RTX; |
9caef960 | 5655 | } |
a685f5d8 | 5656 | #else |
5657 | #error Unhandled ABI | |
5658 | #endif | |
915c336f | 5659 | |
57e47080 | 5660 | return gen_rtx_REG (mode, num_args + basereg); |
915c336f | 5661 | } |
5662 | ||
54ea4630 | 5663 | /* Update the data in CUM to advance over an argument |
5664 | of mode MODE and data type TYPE. | |
5665 | (TYPE is null for libcalls where that information may not be available.) */ | |
5666 | ||
5667 | static void | |
3754d046 | 5668 | alpha_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, |
302d2812 | 5669 | const_tree type, bool named ATTRIBUTE_UNUSED) |
54ea4630 | 5670 | { |
39cba157 | 5671 | CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); |
54ea4630 | 5672 | bool onstack = targetm.calls.must_pass_in_stack (mode, type); |
9deca143 | 5673 | int increment = onstack ? 6 : ALPHA_ARG_SIZE (mode, type); |
54ea4630 | 5674 | |
5675 | #if TARGET_ABI_OSF | |
5676 | *cum += increment; | |
5677 | #else | |
5678 | if (!onstack && cum->num_args < 6) | |
5679 | cum->atypes[cum->num_args] = alpha_arg_type (mode); | |
5680 | cum->num_args += increment; | |
5681 | #endif | |
5682 | } | |
5683 | ||
f054eb3c | 5684 | static int |
39cba157 | 5685 | alpha_arg_partial_bytes (cumulative_args_t cum_v, |
3754d046 | 5686 | machine_mode mode ATTRIBUTE_UNUSED, |
f054eb3c | 5687 | tree type ATTRIBUTE_UNUSED, |
5688 | bool named ATTRIBUTE_UNUSED) | |
5689 | { | |
5690 | int words = 0; | |
39cba157 | 5691 | CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED = get_cumulative_args (cum_v); |
f054eb3c | 5692 | |
5693 | #if TARGET_ABI_OPEN_VMS | |
5694 | if (cum->num_args < 6 | |
9deca143 | 5695 | && 6 < cum->num_args + ALPHA_ARG_SIZE (mode, type)) |
5c5b637a | 5696 | words = 6 - cum->num_args; |
f054eb3c | 5697 | #elif TARGET_ABI_OSF |
9deca143 | 5698 | if (*cum < 6 && 6 < *cum + ALPHA_ARG_SIZE (mode, type)) |
f054eb3c | 5699 | words = 6 - *cum; |
5700 | #else | |
5701 | #error Unhandled ABI | |
5702 | #endif | |
5703 | ||
5704 | return words * UNITS_PER_WORD; | |
5705 | } | |
5706 | ||
5707 | ||
a685f5d8 | 5708 | /* Return true if TYPE must be returned in memory, instead of in registers. */ |
5709 | ||
dd9f3024 | 5710 | static bool |
fb80456a | 5711 | alpha_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) |
a685f5d8 | 5712 | { |
3754d046 | 5713 | machine_mode mode = VOIDmode; |
a685f5d8 | 5714 | int size; |
5715 | ||
5716 | if (type) | |
5717 | { | |
5718 | mode = TYPE_MODE (type); | |
5719 | ||
cfdbb1f5 | 5720 | /* All aggregates are returned in memory, except on OpenVMS where |
5721 | records that fit 64 bits should be returned by immediate value | |
5722 | as required by section 3.8.7.1 of the OpenVMS Calling Standard. */ | |
5723 | if (TARGET_ABI_OPEN_VMS | |
5724 | && TREE_CODE (type) != ARRAY_TYPE | |
5725 | && (unsigned HOST_WIDE_INT) int_size_in_bytes(type) <= 8) | |
5726 | return false; | |
5727 | ||
a685f5d8 | 5728 | if (AGGREGATE_TYPE_P (type)) |
5729 | return true; | |
5730 | } | |
5731 | ||
5732 | size = GET_MODE_SIZE (mode); | |
5733 | switch (GET_MODE_CLASS (mode)) | |
5734 | { | |
5735 | case MODE_VECTOR_FLOAT: | |
5736 | /* Pass all float vectors in memory, like an aggregate. */ | |
5737 | return true; | |
5738 | ||
5739 | case MODE_COMPLEX_FLOAT: | |
5740 | /* We judge complex floats on the size of their element, | |
5741 | not the size of the whole type. */ | |
5742 | size = GET_MODE_UNIT_SIZE (mode); | |
5743 | break; | |
5744 | ||
5745 | case MODE_INT: | |
5746 | case MODE_FLOAT: | |
5747 | case MODE_COMPLEX_INT: | |
5748 | case MODE_VECTOR_INT: | |
5749 | break; | |
5750 | ||
5751 | default: | |
9e7454d0 | 5752 | /* ??? We get called on all sorts of random stuff from |
4d10b463 | 5753 | aggregate_value_p. We must return something, but it's not |
5754 | clear what's safe to return. Pretend it's a struct I | |
5755 | guess. */ | |
a685f5d8 | 5756 | return true; |
5757 | } | |
5758 | ||
5759 | /* Otherwise types must fit in one register. */ | |
5760 | return size > UNITS_PER_WORD; | |
5761 | } | |
5762 | ||
b981d932 | 5763 | /* Return true if TYPE should be passed by invisible reference. */ |
5764 | ||
5765 | static bool | |
39cba157 | 5766 | alpha_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED, |
3754d046 | 5767 | machine_mode mode, |
fb80456a | 5768 | const_tree type ATTRIBUTE_UNUSED, |
f9e3d239 | 5769 | bool named) |
b981d932 | 5770 | { |
f9e3d239 | 5771 | /* Pass float and _Complex float variable arguments by reference. |
5772 | This avoids 64-bit store from a FP register to a pretend args save area | |
5773 | and subsequent 32-bit load from the saved location to a FP register. | |
5774 | ||
5775 | Note that 32-bit loads and stores to/from a FP register on alpha reorder | |
5776 | bits to form a canonical 64-bit value in the FP register. This fact | |
5777 | invalidates compiler assumption that 32-bit FP value lives in the lower | |
5778 | 32-bits of the passed 64-bit FP value, so loading the 32-bit value from | |
5779 | the stored 64-bit location using 32-bit FP load is invalid on alpha. | |
5780 | ||
5781 | This introduces sort of ABI incompatibility, but until _Float32 was | |
5782 | introduced, C-family languages promoted 32-bit float variable arg to | |
5783 | a 64-bit double, and it was not allowed to pass float as a varible | |
5784 | argument. Passing _Complex float as a variable argument never | |
5785 | worked on alpha. Thus, we have no backward compatibility issues | |
5786 | to worry about, and passing unpromoted _Float32 and _Complex float | |
5787 | as a variable argument will actually work in the future. */ | |
5788 | ||
5789 | if (mode == SFmode || mode == SCmode) | |
5790 | return !named; | |
5791 | ||
b981d932 | 5792 | return mode == TFmode || mode == TCmode; |
5793 | } | |
5794 | ||
a685f5d8 | 5795 | /* Define how to find the value returned by a function. VALTYPE is the |
5796 | data type of the value (as a tree). If the precise function being | |
5797 | called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0. | |
5798 | MODE is set instead of VALTYPE for libcalls. | |
5799 | ||
5800 | On Alpha the value is found in $0 for integer functions and | |
5801 | $f0 for floating-point functions. */ | |
5802 | ||
8647dea5 | 5803 | static rtx |
5804 | alpha_function_value_1 (const_tree valtype, const_tree func ATTRIBUTE_UNUSED, | |
5805 | machine_mode mode) | |
a685f5d8 | 5806 | { |
f5e8a4bc | 5807 | unsigned int regnum, dummy ATTRIBUTE_UNUSED; |
8deb3959 | 5808 | enum mode_class mclass; |
a685f5d8 | 5809 | |
4d10b463 | 5810 | gcc_assert (!valtype || !alpha_return_in_memory (valtype, func)); |
a685f5d8 | 5811 | |
5812 | if (valtype) | |
5813 | mode = TYPE_MODE (valtype); | |
5814 | ||
8deb3959 | 5815 | mclass = GET_MODE_CLASS (mode); |
5816 | switch (mclass) | |
a685f5d8 | 5817 | { |
5818 | case MODE_INT: | |
cfdbb1f5 | 5819 | /* Do the same thing as PROMOTE_MODE except for libcalls on VMS, |
5820 | where we have them returning both SImode and DImode. */ | |
5821 | if (!(TARGET_ABI_OPEN_VMS && valtype && AGGREGATE_TYPE_P (valtype))) | |
5822 | PROMOTE_MODE (mode, dummy, valtype); | |
8e262b5e | 5823 | /* FALLTHRU */ |
a685f5d8 | 5824 | |
5825 | case MODE_COMPLEX_INT: | |
5826 | case MODE_VECTOR_INT: | |
5827 | regnum = 0; | |
5828 | break; | |
5829 | ||
5830 | case MODE_FLOAT: | |
5831 | regnum = 32; | |
5832 | break; | |
5833 | ||
5834 | case MODE_COMPLEX_FLOAT: | |
5835 | { | |
3754d046 | 5836 | machine_mode cmode = GET_MODE_INNER (mode); |
a685f5d8 | 5837 | |
5838 | return gen_rtx_PARALLEL | |
5839 | (VOIDmode, | |
5840 | gen_rtvec (2, | |
5841 | gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 32), | |
bcd9bd66 | 5842 | const0_rtx), |
a685f5d8 | 5843 | gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 33), |
5844 | GEN_INT (GET_MODE_SIZE (cmode))))); | |
5845 | } | |
5846 | ||
cfdbb1f5 | 5847 | case MODE_RANDOM: |
5848 | /* We should only reach here for BLKmode on VMS. */ | |
5849 | gcc_assert (TARGET_ABI_OPEN_VMS && mode == BLKmode); | |
5850 | regnum = 0; | |
5851 | break; | |
5852 | ||
a685f5d8 | 5853 | default: |
4d10b463 | 5854 | gcc_unreachable (); |
a685f5d8 | 5855 | } |
5856 | ||
5857 | return gen_rtx_REG (mode, regnum); | |
5858 | } | |
5859 | ||
8647dea5 | 5860 | /* Implement TARGET_FUNCTION_VALUE. */ |
5861 | ||
5862 | static rtx | |
5863 | alpha_function_value (const_tree valtype, const_tree fn_decl_or_type, | |
5864 | bool /*outgoing*/) | |
5865 | { | |
5866 | return alpha_function_value_1 (valtype, fn_decl_or_type, VOIDmode); | |
5867 | } | |
5868 | ||
5869 | /* Implement TARGET_LIBCALL_VALUE. */ | |
5870 | ||
5871 | static rtx | |
5872 | alpha_libcall_value (machine_mode mode, const_rtx /*fun*/) | |
5873 | { | |
5874 | return alpha_function_value_1 (NULL_TREE, NULL_TREE, mode); | |
5875 | } | |
5876 | ||
5877 | /* Implement TARGET_FUNCTION_VALUE_REGNO_P. | |
5878 | ||
5879 | On the Alpha, $0 $1 and $f0 $f1 are the only register thus used. */ | |
5880 | ||
5881 | static bool | |
5882 | alpha_function_value_regno_p (const unsigned int regno) | |
5883 | { | |
5884 | return (regno == 0 || regno == 1 || regno == 32 || regno == 33); | |
5885 | } | |
5886 | ||
9e7454d0 | 5887 | /* TCmode complex values are passed by invisible reference. We |
92d40bc4 | 5888 | should not split these values. */ |
5889 | ||
5890 | static bool | |
a9f1838b | 5891 | alpha_split_complex_arg (const_tree type) |
92d40bc4 | 5892 | { |
5893 | return TYPE_MODE (type) != TCmode; | |
5894 | } | |
5895 | ||
2e15d750 | 5896 | static tree |
5897 | alpha_build_builtin_va_list (void) | |
bf2a98b3 | 5898 | { |
7ba21c9f | 5899 | tree base, ofs, space, record, type_decl; |
bf2a98b3 | 5900 | |
04d75965 | 5901 | if (TARGET_ABI_OPEN_VMS) |
e7aabeab | 5902 | return ptr_type_node; |
5903 | ||
a1f71e15 | 5904 | record = (*lang_hooks.types.make_type) (RECORD_TYPE); |
54e46243 | 5905 | type_decl = build_decl (BUILTINS_LOCATION, |
5906 | TYPE_DECL, get_identifier ("__va_list_tag"), record); | |
bc907808 | 5907 | TYPE_STUB_DECL (record) = type_decl; |
0054fd98 | 5908 | TYPE_NAME (record) = type_decl; |
5909 | ||
e7aabeab | 5910 | /* C++? SET_IS_AGGR_TYPE (record, 1); */ |
bf2a98b3 | 5911 | |
7ba21c9f | 5912 | /* Dummy field to prevent alignment warnings. */ |
54e46243 | 5913 | space = build_decl (BUILTINS_LOCATION, |
5914 | FIELD_DECL, NULL_TREE, integer_type_node); | |
7ba21c9f | 5915 | DECL_FIELD_CONTEXT (space) = record; |
5916 | DECL_ARTIFICIAL (space) = 1; | |
5917 | DECL_IGNORED_P (space) = 1; | |
5918 | ||
54e46243 | 5919 | ofs = build_decl (BUILTINS_LOCATION, |
5920 | FIELD_DECL, get_identifier ("__offset"), | |
e7aabeab | 5921 | integer_type_node); |
5922 | DECL_FIELD_CONTEXT (ofs) = record; | |
1767a056 | 5923 | DECL_CHAIN (ofs) = space; |
fc4c89ed | 5924 | |
54e46243 | 5925 | base = build_decl (BUILTINS_LOCATION, |
5926 | FIELD_DECL, get_identifier ("__base"), | |
e7aabeab | 5927 | ptr_type_node); |
5928 | DECL_FIELD_CONTEXT (base) = record; | |
1767a056 | 5929 | DECL_CHAIN (base) = ofs; |
fc4c89ed | 5930 | |
e7aabeab | 5931 | TYPE_FIELDS (record) = base; |
5932 | layout_type (record); | |
5933 | ||
a6c787e5 | 5934 | va_list_gpr_counter_field = ofs; |
e7aabeab | 5935 | return record; |
5936 | } | |
5937 | ||
7955d282 | 5938 | #if TARGET_ABI_OSF |
a6c787e5 | 5939 | /* Helper function for alpha_stdarg_optimize_hook. Skip over casts |
5940 | and constant additions. */ | |
5941 | ||
42acab1c | 5942 | static gimple * |
a6c787e5 | 5943 | va_list_skip_additions (tree lhs) |
5944 | { | |
42acab1c | 5945 | gimple *stmt; |
a6c787e5 | 5946 | |
5947 | for (;;) | |
5948 | { | |
94c0325b | 5949 | enum tree_code code; |
5950 | ||
a6c787e5 | 5951 | stmt = SSA_NAME_DEF_STMT (lhs); |
5952 | ||
94c0325b | 5953 | if (gimple_code (stmt) == GIMPLE_PHI) |
a6c787e5 | 5954 | return stmt; |
5955 | ||
94c0325b | 5956 | if (!is_gimple_assign (stmt) |
5957 | || gimple_assign_lhs (stmt) != lhs) | |
5958 | return NULL; | |
a6c787e5 | 5959 | |
94c0325b | 5960 | if (TREE_CODE (gimple_assign_rhs1 (stmt)) != SSA_NAME) |
5961 | return stmt; | |
5962 | code = gimple_assign_rhs_code (stmt); | |
5963 | if (!CONVERT_EXPR_CODE_P (code) | |
5964 | && ((code != PLUS_EXPR && code != POINTER_PLUS_EXPR) | |
5965 | || TREE_CODE (gimple_assign_rhs2 (stmt)) != INTEGER_CST | |
cd4547bf | 5966 | || !tree_fits_uhwi_p (gimple_assign_rhs2 (stmt)))) |
94c0325b | 5967 | return stmt; |
a6c787e5 | 5968 | |
94c0325b | 5969 | lhs = gimple_assign_rhs1 (stmt); |
a6c787e5 | 5970 | } |
5971 | } | |
5972 | ||
5973 | /* Check if LHS = RHS statement is | |
5974 | LHS = *(ap.__base + ap.__offset + cst) | |
5975 | or | |
5976 | LHS = *(ap.__base | |
5977 | + ((ap.__offset + cst <= 47) | |
5978 | ? ap.__offset + cst - 48 : ap.__offset + cst) + cst2). | |
5979 | If the former, indicate that GPR registers are needed, | |
5980 | if the latter, indicate that FPR registers are needed. | |
adde8f91 | 5981 | |
5982 | Also look for LHS = (*ptr).field, where ptr is one of the forms | |
5983 | listed above. | |
5984 | ||
a6c787e5 | 5985 | On alpha, cfun->va_list_gpr_size is used as size of the needed |
adde8f91 | 5986 | regs and cfun->va_list_fpr_size is a bitmask, bit 0 set if GPR |
5987 | registers are needed and bit 1 set if FPR registers are needed. | |
5988 | Return true if va_list references should not be scanned for the | |
5989 | current statement. */ | |
a6c787e5 | 5990 | |
5991 | static bool | |
42acab1c | 5992 | alpha_stdarg_optimize_hook (struct stdarg_info *si, const gimple *stmt) |
a6c787e5 | 5993 | { |
94c0325b | 5994 | tree base, offset, rhs; |
a6c787e5 | 5995 | int offset_arg = 1; |
42acab1c | 5996 | gimple *base_stmt; |
a6c787e5 | 5997 | |
94c0325b | 5998 | if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) |
5999 | != GIMPLE_SINGLE_RHS) | |
6000 | return false; | |
6001 | ||
6002 | rhs = gimple_assign_rhs1 (stmt); | |
adde8f91 | 6003 | while (handled_component_p (rhs)) |
6004 | rhs = TREE_OPERAND (rhs, 0); | |
182cf5a9 | 6005 | if (TREE_CODE (rhs) != MEM_REF |
a6c787e5 | 6006 | || TREE_CODE (TREE_OPERAND (rhs, 0)) != SSA_NAME) |
6007 | return false; | |
6008 | ||
94c0325b | 6009 | stmt = va_list_skip_additions (TREE_OPERAND (rhs, 0)); |
6010 | if (stmt == NULL | |
6011 | || !is_gimple_assign (stmt) | |
6012 | || gimple_assign_rhs_code (stmt) != POINTER_PLUS_EXPR) | |
a6c787e5 | 6013 | return false; |
6014 | ||
94c0325b | 6015 | base = gimple_assign_rhs1 (stmt); |
a6c787e5 | 6016 | if (TREE_CODE (base) == SSA_NAME) |
94c0325b | 6017 | { |
6018 | base_stmt = va_list_skip_additions (base); | |
6019 | if (base_stmt | |
6020 | && is_gimple_assign (base_stmt) | |
6021 | && gimple_assign_rhs_code (base_stmt) == COMPONENT_REF) | |
6022 | base = gimple_assign_rhs1 (base_stmt); | |
6023 | } | |
a6c787e5 | 6024 | |
6025 | if (TREE_CODE (base) != COMPONENT_REF | |
6026 | || TREE_OPERAND (base, 1) != TYPE_FIELDS (va_list_type_node)) | |
6027 | { | |
94c0325b | 6028 | base = gimple_assign_rhs2 (stmt); |
a6c787e5 | 6029 | if (TREE_CODE (base) == SSA_NAME) |
94c0325b | 6030 | { |
6031 | base_stmt = va_list_skip_additions (base); | |
6032 | if (base_stmt | |
6033 | && is_gimple_assign (base_stmt) | |
6034 | && gimple_assign_rhs_code (base_stmt) == COMPONENT_REF) | |
6035 | base = gimple_assign_rhs1 (base_stmt); | |
6036 | } | |
a6c787e5 | 6037 | |
6038 | if (TREE_CODE (base) != COMPONENT_REF | |
6039 | || TREE_OPERAND (base, 1) != TYPE_FIELDS (va_list_type_node)) | |
6040 | return false; | |
6041 | ||
6042 | offset_arg = 0; | |
6043 | } | |
6044 | ||
6045 | base = get_base_address (base); | |
6046 | if (TREE_CODE (base) != VAR_DECL | |
72952522 | 6047 | || !bitmap_bit_p (si->va_list_vars, DECL_UID (base) + num_ssa_names)) |
a6c787e5 | 6048 | return false; |
6049 | ||
94c0325b | 6050 | offset = gimple_op (stmt, 1 + offset_arg); |
a6c787e5 | 6051 | if (TREE_CODE (offset) == SSA_NAME) |
a6c787e5 | 6052 | { |
42acab1c | 6053 | gimple *offset_stmt = va_list_skip_additions (offset); |
a6c787e5 | 6054 | |
94c0325b | 6055 | if (offset_stmt |
6056 | && gimple_code (offset_stmt) == GIMPLE_PHI) | |
a6c787e5 | 6057 | { |
94c0325b | 6058 | HOST_WIDE_INT sub; |
42acab1c | 6059 | gimple *arg1_stmt, *arg2_stmt; |
94c0325b | 6060 | tree arg1, arg2; |
6061 | enum tree_code code1, code2; | |
a6c787e5 | 6062 | |
94c0325b | 6063 | if (gimple_phi_num_args (offset_stmt) != 2) |
7955d282 | 6064 | goto escapes; |
a6c787e5 | 6065 | |
94c0325b | 6066 | arg1_stmt |
6067 | = va_list_skip_additions (gimple_phi_arg_def (offset_stmt, 0)); | |
6068 | arg2_stmt | |
6069 | = va_list_skip_additions (gimple_phi_arg_def (offset_stmt, 1)); | |
6070 | if (arg1_stmt == NULL | |
6071 | || !is_gimple_assign (arg1_stmt) | |
6072 | || arg2_stmt == NULL | |
6073 | || !is_gimple_assign (arg2_stmt)) | |
6074 | goto escapes; | |
a6c787e5 | 6075 | |
94c0325b | 6076 | code1 = gimple_assign_rhs_code (arg1_stmt); |
6077 | code2 = gimple_assign_rhs_code (arg2_stmt); | |
6078 | if (code1 == COMPONENT_REF | |
6079 | && (code2 == MINUS_EXPR || code2 == PLUS_EXPR)) | |
6080 | /* Do nothing. */; | |
6081 | else if (code2 == COMPONENT_REF | |
6082 | && (code1 == MINUS_EXPR || code1 == PLUS_EXPR)) | |
6083 | { | |
3ffb2c20 | 6084 | std::swap (arg1_stmt, arg2_stmt); |
94c0325b | 6085 | code2 = code1; |
94c0325b | 6086 | } |
6087 | else | |
6088 | goto escapes; | |
7955d282 | 6089 | |
35ec552a | 6090 | if (!tree_fits_shwi_p (gimple_assign_rhs2 (arg2_stmt))) |
94c0325b | 6091 | goto escapes; |
7955d282 | 6092 | |
fcb97e84 | 6093 | sub = tree_to_shwi (gimple_assign_rhs2 (arg2_stmt)); |
94c0325b | 6094 | if (code2 == MINUS_EXPR) |
6095 | sub = -sub; | |
6096 | if (sub < -48 || sub > -32) | |
6097 | goto escapes; | |
a6c787e5 | 6098 | |
94c0325b | 6099 | arg1 = gimple_assign_rhs1 (arg1_stmt); |
6100 | arg2 = gimple_assign_rhs1 (arg2_stmt); | |
6101 | if (TREE_CODE (arg2) == SSA_NAME) | |
6102 | { | |
6103 | arg2_stmt = va_list_skip_additions (arg2); | |
6104 | if (arg2_stmt == NULL | |
6105 | || !is_gimple_assign (arg2_stmt) | |
6106 | || gimple_assign_rhs_code (arg2_stmt) != COMPONENT_REF) | |
6107 | goto escapes; | |
6108 | arg2 = gimple_assign_rhs1 (arg2_stmt); | |
6109 | } | |
6110 | if (arg1 != arg2) | |
6111 | goto escapes; | |
6112 | ||
6113 | if (TREE_CODE (arg1) != COMPONENT_REF | |
6114 | || TREE_OPERAND (arg1, 1) != va_list_gpr_counter_field | |
6115 | || get_base_address (arg1) != base) | |
6116 | goto escapes; | |
6117 | ||
6118 | /* Need floating point regs. */ | |
6119 | cfun->va_list_fpr_size |= 2; | |
6120 | return false; | |
6121 | } | |
6122 | if (offset_stmt | |
6123 | && is_gimple_assign (offset_stmt) | |
6124 | && gimple_assign_rhs_code (offset_stmt) == COMPONENT_REF) | |
6125 | offset = gimple_assign_rhs1 (offset_stmt); | |
6126 | } | |
6127 | if (TREE_CODE (offset) != COMPONENT_REF | |
6128 | || TREE_OPERAND (offset, 1) != va_list_gpr_counter_field | |
6129 | || get_base_address (offset) != base) | |
a6c787e5 | 6130 | goto escapes; |
6131 | else | |
6132 | /* Need general regs. */ | |
6133 | cfun->va_list_fpr_size |= 1; | |
6134 | return false; | |
6135 | ||
6136 | escapes: | |
6137 | si->va_list_escapes = true; | |
6138 | return false; | |
6139 | } | |
7955d282 | 6140 | #endif |
a6c787e5 | 6141 | |
4310aa50 | 6142 | /* Perform any needed actions needed for a function that is receiving a |
dd9f3024 | 6143 | variable number of arguments. */ |
4310aa50 | 6144 | |
dd9f3024 | 6145 | static void |
3754d046 | 6146 | alpha_setup_incoming_varargs (cumulative_args_t pcum, machine_mode mode, |
2dc656b7 | 6147 | tree type, int *pretend_size, int no_rtl) |
dd9f3024 | 6148 | { |
39cba157 | 6149 | CUMULATIVE_ARGS cum = *get_cumulative_args (pcum); |
2dc656b7 | 6150 | |
6151 | /* Skip the current argument. */ | |
39cba157 | 6152 | targetm.calls.function_arg_advance (pack_cumulative_args (&cum), mode, type, |
6153 | true); | |
2dc656b7 | 6154 | |
04d75965 | 6155 | #if TARGET_ABI_OPEN_VMS |
dd9f3024 | 6156 | /* For VMS, we allocate space for all 6 arg registers plus a count. |
4310aa50 | 6157 | |
dd9f3024 | 6158 | However, if NO registers need to be saved, don't allocate any space. |
6159 | This is not only because we won't need the space, but because AP | |
6160 | includes the current_pretend_args_size and we don't want to mess up | |
6161 | any ap-relative addresses already made. */ | |
2dc656b7 | 6162 | if (cum.num_args < 6) |
dd9f3024 | 6163 | { |
6164 | if (!no_rtl) | |
6165 | { | |
6166 | emit_move_insn (gen_rtx_REG (DImode, 1), virtual_incoming_args_rtx); | |
6167 | emit_insn (gen_arg_home ()); | |
6168 | } | |
6169 | *pretend_size = 7 * UNITS_PER_WORD; | |
6170 | } | |
6171 | #else | |
6172 | /* On OSF/1 and friends, we allocate space for all 12 arg registers, but | |
6173 | only push those that are remaining. However, if NO registers need to | |
6174 | be saved, don't allocate any space. This is not only because we won't | |
6175 | need the space, but because AP includes the current_pretend_args_size | |
6176 | and we don't want to mess up any ap-relative addresses already made. | |
6177 | ||
6178 | If we are not to use the floating-point registers, save the integer | |
6179 | registers where we would put the floating-point registers. This is | |
6180 | not the most efficient way to implement varargs with just one register | |
6181 | class, but it isn't worth doing anything more efficient in this rare | |
6182 | case. */ | |
4310aa50 | 6183 | if (cum >= 6) |
6184 | return; | |
6185 | ||
6186 | if (!no_rtl) | |
6187 | { | |
32c2fdea | 6188 | int count; |
6189 | alias_set_type set = get_varargs_alias_set (); | |
4310aa50 | 6190 | rtx tmp; |
6191 | ||
7955d282 | 6192 | count = cfun->va_list_gpr_size / UNITS_PER_WORD; |
6193 | if (count > 6 - cum) | |
6194 | count = 6 - cum; | |
4310aa50 | 6195 | |
7955d282 | 6196 | /* Detect whether integer registers or floating-point registers |
6197 | are needed by the detected va_arg statements. See above for | |
6198 | how these values are computed. Note that the "escape" value | |
6199 | is VA_LIST_MAX_FPR_SIZE, which is 255, which has both of | |
6200 | these bits set. */ | |
6201 | gcc_assert ((VA_LIST_MAX_FPR_SIZE & 3) == 3); | |
6202 | ||
6203 | if (cfun->va_list_fpr_size & 1) | |
6204 | { | |
6205 | tmp = gen_rtx_MEM (BLKmode, | |
29c05e22 | 6206 | plus_constant (Pmode, virtual_incoming_args_rtx, |
7955d282 | 6207 | (cum + 6) * UNITS_PER_WORD)); |
ae2dd339 | 6208 | MEM_NOTRAP_P (tmp) = 1; |
7955d282 | 6209 | set_mem_alias_set (tmp, set); |
6210 | move_block_from_reg (16 + cum, tmp, count); | |
6211 | } | |
6212 | ||
6213 | if (cfun->va_list_fpr_size & 2) | |
6214 | { | |
6215 | tmp = gen_rtx_MEM (BLKmode, | |
29c05e22 | 6216 | plus_constant (Pmode, virtual_incoming_args_rtx, |
7955d282 | 6217 | cum * UNITS_PER_WORD)); |
ae2dd339 | 6218 | MEM_NOTRAP_P (tmp) = 1; |
7955d282 | 6219 | set_mem_alias_set (tmp, set); |
6220 | move_block_from_reg (16 + cum + TARGET_FPREGS*32, tmp, count); | |
6221 | } | |
6222 | } | |
4310aa50 | 6223 | *pretend_size = 12 * UNITS_PER_WORD; |
f6940372 | 6224 | #endif |
dd9f3024 | 6225 | } |
4310aa50 | 6226 | |
8a58ed0a | 6227 | static void |
92643d95 | 6228 | alpha_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) |
e7aabeab | 6229 | { |
6230 | HOST_WIDE_INT offset; | |
6231 | tree t, offset_field, base_field; | |
fc4c89ed | 6232 | |
80909c64 | 6233 | if (TREE_CODE (TREE_TYPE (valist)) == ERROR_MARK) |
6234 | return; | |
6235 | ||
6644435d | 6236 | /* For Unix, TARGET_SETUP_INCOMING_VARARGS moves the starting address base |
e7aabeab | 6237 | up by 48, storing fp arg registers in the first 48 bytes, and the |
6238 | integer arg registers in the next 48 bytes. This is only done, | |
6239 | however, if any integer registers need to be stored. | |
6240 | ||
6241 | If no integer registers need be stored, then we must subtract 48 | |
6242 | in order to account for the integer arg registers which are counted | |
4310aa50 | 6243 | in argsize above, but which are not actually stored on the stack. |
6244 | Must further be careful here about structures straddling the last | |
9e7454d0 | 6245 | integer argument register; that futzes with pretend_args_size, |
4310aa50 | 6246 | which changes the meaning of AP. */ |
e7aabeab | 6247 | |
2dc656b7 | 6248 | if (NUM_ARGS < 6) |
fc264da3 | 6249 | offset = TARGET_ABI_OPEN_VMS ? UNITS_PER_WORD : 6 * UNITS_PER_WORD; |
8df4a58b | 6250 | else |
abe32cce | 6251 | offset = -6 * UNITS_PER_WORD + crtl->args.pretend_args_size; |
e7aabeab | 6252 | |
fc264da3 | 6253 | if (TARGET_ABI_OPEN_VMS) |
6254 | { | |
cfdbb1f5 | 6255 | t = make_tree (ptr_type_node, virtual_incoming_args_rtx); |
2cc66f2a | 6256 | t = fold_build_pointer_plus_hwi (t, offset + NUM_ARGS * UNITS_PER_WORD); |
cfdbb1f5 | 6257 | t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t); |
fc264da3 | 6258 | TREE_SIDE_EFFECTS (t) = 1; |
fc264da3 | 6259 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); |
6260 | } | |
6261 | else | |
6262 | { | |
6263 | base_field = TYPE_FIELDS (TREE_TYPE (valist)); | |
1767a056 | 6264 | offset_field = DECL_CHAIN (base_field); |
fc264da3 | 6265 | |
ed03eadb | 6266 | base_field = build3 (COMPONENT_REF, TREE_TYPE (base_field), |
6267 | valist, base_field, NULL_TREE); | |
6268 | offset_field = build3 (COMPONENT_REF, TREE_TYPE (offset_field), | |
6269 | valist, offset_field, NULL_TREE); | |
fc264da3 | 6270 | |
6271 | t = make_tree (ptr_type_node, virtual_incoming_args_rtx); | |
2cc66f2a | 6272 | t = fold_build_pointer_plus_hwi (t, offset); |
75a70cf9 | 6273 | t = build2 (MODIFY_EXPR, TREE_TYPE (base_field), base_field, t); |
fc264da3 | 6274 | TREE_SIDE_EFFECTS (t) = 1; |
6275 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
6276 | ||
7016c612 | 6277 | t = build_int_cst (NULL_TREE, NUM_ARGS * UNITS_PER_WORD); |
75a70cf9 | 6278 | t = build2 (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, t); |
fc264da3 | 6279 | TREE_SIDE_EFFECTS (t) = 1; |
6280 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
6281 | } | |
e7aabeab | 6282 | } |
6283 | ||
de8f9b94 | 6284 | static tree |
94c0325b | 6285 | alpha_gimplify_va_arg_1 (tree type, tree base, tree offset, |
75a70cf9 | 6286 | gimple_seq *pre_p) |
de8f9b94 | 6287 | { |
94c0325b | 6288 | tree type_size, ptr_type, addend, t, addr; |
6289 | gimple_seq internal_post; | |
de8f9b94 | 6290 | |
de8f9b94 | 6291 | /* If the type could not be passed in registers, skip the block |
6292 | reserved for the registers. */ | |
0336f0f0 | 6293 | if (targetm.calls.must_pass_in_stack (TYPE_MODE (type), type)) |
de8f9b94 | 6294 | { |
7016c612 | 6295 | t = build_int_cst (TREE_TYPE (offset), 6*8); |
75a70cf9 | 6296 | gimplify_assign (offset, |
6297 | build2 (MAX_EXPR, TREE_TYPE (offset), offset, t), | |
6298 | pre_p); | |
de8f9b94 | 6299 | } |
6300 | ||
6301 | addend = offset; | |
bd746187 | 6302 | ptr_type = build_pointer_type_for_mode (type, ptr_mode, true); |
de8f9b94 | 6303 | |
2cd7bb84 | 6304 | if (TREE_CODE (type) == COMPLEX_TYPE) |
de8f9b94 | 6305 | { |
6306 | tree real_part, imag_part, real_temp; | |
6307 | ||
c7b3f103 | 6308 | real_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, |
6309 | offset, pre_p); | |
6310 | ||
6311 | /* Copy the value into a new temporary, lest the formal temporary | |
de8f9b94 | 6312 | be reused out from under us. */ |
c7b3f103 | 6313 | real_temp = get_initialized_tmp_var (real_part, pre_p, NULL); |
de8f9b94 | 6314 | |
c7b3f103 | 6315 | imag_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, |
6316 | offset, pre_p); | |
de8f9b94 | 6317 | |
ed03eadb | 6318 | return build2 (COMPLEX_EXPR, type, real_temp, imag_part); |
de8f9b94 | 6319 | } |
6320 | else if (TREE_CODE (type) == REAL_TYPE) | |
6321 | { | |
6322 | tree fpaddend, cond, fourtyeight; | |
6323 | ||
7016c612 | 6324 | fourtyeight = build_int_cst (TREE_TYPE (addend), 6*8); |
ed03eadb | 6325 | fpaddend = fold_build2 (MINUS_EXPR, TREE_TYPE (addend), |
6326 | addend, fourtyeight); | |
6327 | cond = fold_build2 (LT_EXPR, boolean_type_node, addend, fourtyeight); | |
6328 | addend = fold_build3 (COND_EXPR, TREE_TYPE (addend), cond, | |
6329 | fpaddend, addend); | |
de8f9b94 | 6330 | } |
6331 | ||
6332 | /* Build the final address and force that value into a temporary. */ | |
2cc66f2a | 6333 | addr = fold_build_pointer_plus (fold_convert (ptr_type, base), addend); |
c7b3f103 | 6334 | internal_post = NULL; |
6335 | gimplify_expr (&addr, pre_p, &internal_post, is_gimple_val, fb_rvalue); | |
94c0325b | 6336 | gimple_seq_add_seq (pre_p, internal_post); |
de8f9b94 | 6337 | |
6338 | /* Update the offset field. */ | |
c7b3f103 | 6339 | type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type)); |
6340 | if (type_size == NULL || TREE_OVERFLOW (type_size)) | |
6341 | t = size_zero_node; | |
6342 | else | |
6343 | { | |
6344 | t = size_binop (PLUS_EXPR, type_size, size_int (7)); | |
6345 | t = size_binop (TRUNC_DIV_EXPR, t, size_int (8)); | |
6346 | t = size_binop (MULT_EXPR, t, size_int (8)); | |
6347 | } | |
6348 | t = fold_convert (TREE_TYPE (offset), t); | |
75a70cf9 | 6349 | gimplify_assign (offset, build2 (PLUS_EXPR, TREE_TYPE (offset), offset, t), |
6350 | pre_p); | |
de8f9b94 | 6351 | |
063f5fdd | 6352 | return build_va_arg_indirect_ref (addr); |
de8f9b94 | 6353 | } |
6354 | ||
e0eca1fa | 6355 | static tree |
75a70cf9 | 6356 | alpha_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, |
6357 | gimple_seq *post_p) | |
de8f9b94 | 6358 | { |
e0eca1fa | 6359 | tree offset_field, base_field, offset, base, t, r; |
2cd7bb84 | 6360 | bool indirect; |
de8f9b94 | 6361 | |
04d75965 | 6362 | if (TARGET_ABI_OPEN_VMS) |
e0eca1fa | 6363 | return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); |
de8f9b94 | 6364 | |
6365 | base_field = TYPE_FIELDS (va_list_type_node); | |
1767a056 | 6366 | offset_field = DECL_CHAIN (base_field); |
ed03eadb | 6367 | base_field = build3 (COMPONENT_REF, TREE_TYPE (base_field), |
6368 | valist, base_field, NULL_TREE); | |
6369 | offset_field = build3 (COMPONENT_REF, TREE_TYPE (offset_field), | |
6370 | valist, offset_field, NULL_TREE); | |
de8f9b94 | 6371 | |
c7b3f103 | 6372 | /* Pull the fields of the structure out into temporaries. Since we never |
6373 | modify the base field, we can use a formal temporary. Sign-extend the | |
6374 | offset field so that it's the proper width for pointer arithmetic. */ | |
6375 | base = get_formal_tmp_var (base_field, pre_p); | |
de8f9b94 | 6376 | |
a51edb4c | 6377 | t = fold_convert (build_nonstandard_integer_type (64, 0), offset_field); |
c7b3f103 | 6378 | offset = get_initialized_tmp_var (t, pre_p, NULL); |
de8f9b94 | 6379 | |
2cd7bb84 | 6380 | indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false); |
6381 | if (indirect) | |
bd746187 | 6382 | type = build_pointer_type_for_mode (type, ptr_mode, true); |
2cd7bb84 | 6383 | |
de8f9b94 | 6384 | /* Find the value. Note that this will be a stable indirection, or |
6385 | a composite of stable indirections in the case of complex. */ | |
c7b3f103 | 6386 | r = alpha_gimplify_va_arg_1 (type, base, offset, pre_p); |
de8f9b94 | 6387 | |
6388 | /* Stuff the offset temporary back into its field. */ | |
94c0325b | 6389 | gimplify_assign (unshare_expr (offset_field), |
75a70cf9 | 6390 | fold_convert (TREE_TYPE (offset_field), offset), pre_p); |
e0eca1fa | 6391 | |
2cd7bb84 | 6392 | if (indirect) |
063f5fdd | 6393 | r = build_va_arg_indirect_ref (r); |
2cd7bb84 | 6394 | |
e0eca1fa | 6395 | return r; |
de8f9b94 | 6396 | } |
bf2a98b3 | 6397 | \f |
f2cc13dc | 6398 | /* Builtins. */ |
6399 | ||
6400 | enum alpha_builtin | |
6401 | { | |
6402 | ALPHA_BUILTIN_CMPBGE, | |
ae4cd3a5 | 6403 | ALPHA_BUILTIN_EXTBL, |
6404 | ALPHA_BUILTIN_EXTWL, | |
6405 | ALPHA_BUILTIN_EXTLL, | |
f2cc13dc | 6406 | ALPHA_BUILTIN_EXTQL, |
ae4cd3a5 | 6407 | ALPHA_BUILTIN_EXTWH, |
6408 | ALPHA_BUILTIN_EXTLH, | |
f2cc13dc | 6409 | ALPHA_BUILTIN_EXTQH, |
ae4cd3a5 | 6410 | ALPHA_BUILTIN_INSBL, |
6411 | ALPHA_BUILTIN_INSWL, | |
6412 | ALPHA_BUILTIN_INSLL, | |
6413 | ALPHA_BUILTIN_INSQL, | |
6414 | ALPHA_BUILTIN_INSWH, | |
6415 | ALPHA_BUILTIN_INSLH, | |
6416 | ALPHA_BUILTIN_INSQH, | |
6417 | ALPHA_BUILTIN_MSKBL, | |
6418 | ALPHA_BUILTIN_MSKWL, | |
6419 | ALPHA_BUILTIN_MSKLL, | |
6420 | ALPHA_BUILTIN_MSKQL, | |
6421 | ALPHA_BUILTIN_MSKWH, | |
6422 | ALPHA_BUILTIN_MSKLH, | |
6423 | ALPHA_BUILTIN_MSKQH, | |
6424 | ALPHA_BUILTIN_UMULH, | |
f2cc13dc | 6425 | ALPHA_BUILTIN_ZAP, |
6426 | ALPHA_BUILTIN_ZAPNOT, | |
6427 | ALPHA_BUILTIN_AMASK, | |
6428 | ALPHA_BUILTIN_IMPLVER, | |
6429 | ALPHA_BUILTIN_RPCC, | |
50f36bdb | 6430 | ALPHA_BUILTIN_ESTABLISH_VMS_CONDITION_HANDLER, |
6431 | ALPHA_BUILTIN_REVERT_VMS_CONDITION_HANDLER, | |
f2cc13dc | 6432 | |
6433 | /* TARGET_MAX */ | |
6434 | ALPHA_BUILTIN_MINUB8, | |
6435 | ALPHA_BUILTIN_MINSB8, | |
6436 | ALPHA_BUILTIN_MINUW4, | |
6437 | ALPHA_BUILTIN_MINSW4, | |
6438 | ALPHA_BUILTIN_MAXUB8, | |
6439 | ALPHA_BUILTIN_MAXSB8, | |
6440 | ALPHA_BUILTIN_MAXUW4, | |
6441 | ALPHA_BUILTIN_MAXSW4, | |
6442 | ALPHA_BUILTIN_PERR, | |
6443 | ALPHA_BUILTIN_PKLB, | |
6444 | ALPHA_BUILTIN_PKWB, | |
6445 | ALPHA_BUILTIN_UNPKBL, | |
6446 | ALPHA_BUILTIN_UNPKBW, | |
6447 | ||
ae4cd3a5 | 6448 | /* TARGET_CIX */ |
6449 | ALPHA_BUILTIN_CTTZ, | |
6450 | ALPHA_BUILTIN_CTLZ, | |
6451 | ALPHA_BUILTIN_CTPOP, | |
6452 | ||
f2cc13dc | 6453 | ALPHA_BUILTIN_max |
6454 | }; | |
6455 | ||
ff8e23a2 | 6456 | static enum insn_code const code_for_builtin[ALPHA_BUILTIN_max] = { |
ae4cd3a5 | 6457 | CODE_FOR_builtin_cmpbge, |
9bab4302 | 6458 | CODE_FOR_extbl, |
6459 | CODE_FOR_extwl, | |
6460 | CODE_FOR_extll, | |
6461 | CODE_FOR_extql, | |
6462 | CODE_FOR_extwh, | |
6463 | CODE_FOR_extlh, | |
6464 | CODE_FOR_extqh, | |
ae4cd3a5 | 6465 | CODE_FOR_builtin_insbl, |
6466 | CODE_FOR_builtin_inswl, | |
6467 | CODE_FOR_builtin_insll, | |
9bab4302 | 6468 | CODE_FOR_insql, |
6469 | CODE_FOR_inswh, | |
6470 | CODE_FOR_inslh, | |
6471 | CODE_FOR_insqh, | |
6472 | CODE_FOR_mskbl, | |
6473 | CODE_FOR_mskwl, | |
6474 | CODE_FOR_mskll, | |
6475 | CODE_FOR_mskql, | |
6476 | CODE_FOR_mskwh, | |
6477 | CODE_FOR_msklh, | |
6478 | CODE_FOR_mskqh, | |
ae4cd3a5 | 6479 | CODE_FOR_umuldi3_highpart, |
6480 | CODE_FOR_builtin_zap, | |
6481 | CODE_FOR_builtin_zapnot, | |
6482 | CODE_FOR_builtin_amask, | |
6483 | CODE_FOR_builtin_implver, | |
6484 | CODE_FOR_builtin_rpcc, | |
50f36bdb | 6485 | CODE_FOR_builtin_establish_vms_condition_handler, |
6486 | CODE_FOR_builtin_revert_vms_condition_handler, | |
ae4cd3a5 | 6487 | |
6488 | /* TARGET_MAX */ | |
6489 | CODE_FOR_builtin_minub8, | |
6490 | CODE_FOR_builtin_minsb8, | |
6491 | CODE_FOR_builtin_minuw4, | |
6492 | CODE_FOR_builtin_minsw4, | |
6493 | CODE_FOR_builtin_maxub8, | |
6494 | CODE_FOR_builtin_maxsb8, | |
6495 | CODE_FOR_builtin_maxuw4, | |
6496 | CODE_FOR_builtin_maxsw4, | |
6497 | CODE_FOR_builtin_perr, | |
6498 | CODE_FOR_builtin_pklb, | |
6499 | CODE_FOR_builtin_pkwb, | |
6500 | CODE_FOR_builtin_unpkbl, | |
6501 | CODE_FOR_builtin_unpkbw, | |
6502 | ||
6503 | /* TARGET_CIX */ | |
849c7bc6 | 6504 | CODE_FOR_ctzdi2, |
6505 | CODE_FOR_clzdi2, | |
6506 | CODE_FOR_popcountdi2 | |
ae4cd3a5 | 6507 | }; |
6508 | ||
f2cc13dc | 6509 | struct alpha_builtin_def |
6510 | { | |
6511 | const char *name; | |
6512 | enum alpha_builtin code; | |
6513 | unsigned int target_mask; | |
849c7bc6 | 6514 | bool is_const; |
f2cc13dc | 6515 | }; |
6516 | ||
6517 | static struct alpha_builtin_def const zero_arg_builtins[] = { | |
849c7bc6 | 6518 | { "__builtin_alpha_implver", ALPHA_BUILTIN_IMPLVER, 0, true }, |
6519 | { "__builtin_alpha_rpcc", ALPHA_BUILTIN_RPCC, 0, false } | |
f2cc13dc | 6520 | }; |
6521 | ||
6522 | static struct alpha_builtin_def const one_arg_builtins[] = { | |
849c7bc6 | 6523 | { "__builtin_alpha_amask", ALPHA_BUILTIN_AMASK, 0, true }, |
6524 | { "__builtin_alpha_pklb", ALPHA_BUILTIN_PKLB, MASK_MAX, true }, | |
6525 | { "__builtin_alpha_pkwb", ALPHA_BUILTIN_PKWB, MASK_MAX, true }, | |
6526 | { "__builtin_alpha_unpkbl", ALPHA_BUILTIN_UNPKBL, MASK_MAX, true }, | |
6527 | { "__builtin_alpha_unpkbw", ALPHA_BUILTIN_UNPKBW, MASK_MAX, true }, | |
6528 | { "__builtin_alpha_cttz", ALPHA_BUILTIN_CTTZ, MASK_CIX, true }, | |
6529 | { "__builtin_alpha_ctlz", ALPHA_BUILTIN_CTLZ, MASK_CIX, true }, | |
6530 | { "__builtin_alpha_ctpop", ALPHA_BUILTIN_CTPOP, MASK_CIX, true } | |
f2cc13dc | 6531 | }; |
6532 | ||
6533 | static struct alpha_builtin_def const two_arg_builtins[] = { | |
849c7bc6 | 6534 | { "__builtin_alpha_cmpbge", ALPHA_BUILTIN_CMPBGE, 0, true }, |
6535 | { "__builtin_alpha_extbl", ALPHA_BUILTIN_EXTBL, 0, true }, | |
6536 | { "__builtin_alpha_extwl", ALPHA_BUILTIN_EXTWL, 0, true }, | |
6537 | { "__builtin_alpha_extll", ALPHA_BUILTIN_EXTLL, 0, true }, | |
6538 | { "__builtin_alpha_extql", ALPHA_BUILTIN_EXTQL, 0, true }, | |
6539 | { "__builtin_alpha_extwh", ALPHA_BUILTIN_EXTWH, 0, true }, | |
6540 | { "__builtin_alpha_extlh", ALPHA_BUILTIN_EXTLH, 0, true }, | |
6541 | { "__builtin_alpha_extqh", ALPHA_BUILTIN_EXTQH, 0, true }, | |
6542 | { "__builtin_alpha_insbl", ALPHA_BUILTIN_INSBL, 0, true }, | |
6543 | { "__builtin_alpha_inswl", ALPHA_BUILTIN_INSWL, 0, true }, | |
6544 | { "__builtin_alpha_insll", ALPHA_BUILTIN_INSLL, 0, true }, | |
6545 | { "__builtin_alpha_insql", ALPHA_BUILTIN_INSQL, 0, true }, | |
6546 | { "__builtin_alpha_inswh", ALPHA_BUILTIN_INSWH, 0, true }, | |
6547 | { "__builtin_alpha_inslh", ALPHA_BUILTIN_INSLH, 0, true }, | |
6548 | { "__builtin_alpha_insqh", ALPHA_BUILTIN_INSQH, 0, true }, | |
6549 | { "__builtin_alpha_mskbl", ALPHA_BUILTIN_MSKBL, 0, true }, | |
6550 | { "__builtin_alpha_mskwl", ALPHA_BUILTIN_MSKWL, 0, true }, | |
6551 | { "__builtin_alpha_mskll", ALPHA_BUILTIN_MSKLL, 0, true }, | |
6552 | { "__builtin_alpha_mskql", ALPHA_BUILTIN_MSKQL, 0, true }, | |
6553 | { "__builtin_alpha_mskwh", ALPHA_BUILTIN_MSKWH, 0, true }, | |
6554 | { "__builtin_alpha_msklh", ALPHA_BUILTIN_MSKLH, 0, true }, | |
6555 | { "__builtin_alpha_mskqh", ALPHA_BUILTIN_MSKQH, 0, true }, | |
6556 | { "__builtin_alpha_umulh", ALPHA_BUILTIN_UMULH, 0, true }, | |
6557 | { "__builtin_alpha_zap", ALPHA_BUILTIN_ZAP, 0, true }, | |
6558 | { "__builtin_alpha_zapnot", ALPHA_BUILTIN_ZAPNOT, 0, true }, | |
6559 | { "__builtin_alpha_minub8", ALPHA_BUILTIN_MINUB8, MASK_MAX, true }, | |
6560 | { "__builtin_alpha_minsb8", ALPHA_BUILTIN_MINSB8, MASK_MAX, true }, | |
6561 | { "__builtin_alpha_minuw4", ALPHA_BUILTIN_MINUW4, MASK_MAX, true }, | |
6562 | { "__builtin_alpha_minsw4", ALPHA_BUILTIN_MINSW4, MASK_MAX, true }, | |
6563 | { "__builtin_alpha_maxub8", ALPHA_BUILTIN_MAXUB8, MASK_MAX, true }, | |
6564 | { "__builtin_alpha_maxsb8", ALPHA_BUILTIN_MAXSB8, MASK_MAX, true }, | |
6565 | { "__builtin_alpha_maxuw4", ALPHA_BUILTIN_MAXUW4, MASK_MAX, true }, | |
6566 | { "__builtin_alpha_maxsw4", ALPHA_BUILTIN_MAXSW4, MASK_MAX, true }, | |
6567 | { "__builtin_alpha_perr", ALPHA_BUILTIN_PERR, MASK_MAX, true } | |
f2cc13dc | 6568 | }; |
6569 | ||
21c2a8b2 | 6570 | static GTY(()) tree alpha_dimode_u; |
849c7bc6 | 6571 | static GTY(()) tree alpha_v8qi_u; |
6572 | static GTY(()) tree alpha_v8qi_s; | |
6573 | static GTY(()) tree alpha_v4hi_u; | |
6574 | static GTY(()) tree alpha_v4hi_s; | |
6575 | ||
bad4fb18 | 6576 | static GTY(()) tree alpha_builtins[(int) ALPHA_BUILTIN_max]; |
6577 | ||
6578 | /* Return the alpha builtin for CODE. */ | |
6579 | ||
6580 | static tree | |
6581 | alpha_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) | |
6582 | { | |
6583 | if (code >= ALPHA_BUILTIN_max) | |
6584 | return error_mark_node; | |
6585 | return alpha_builtins[code]; | |
6586 | } | |
6587 | ||
6588 | /* Helper function of alpha_init_builtins. Add the built-in specified | |
6589 | by NAME, TYPE, CODE, and ECF. */ | |
6590 | ||
6591 | static void | |
6592 | alpha_builtin_function (const char *name, tree ftype, | |
6593 | enum alpha_builtin code, unsigned ecf) | |
6594 | { | |
6595 | tree decl = add_builtin_function (name, ftype, (int) code, | |
6596 | BUILT_IN_MD, NULL, NULL_TREE); | |
6597 | ||
6598 | if (ecf & ECF_CONST) | |
6599 | TREE_READONLY (decl) = 1; | |
6600 | if (ecf & ECF_NOTHROW) | |
6601 | TREE_NOTHROW (decl) = 1; | |
6602 | ||
6603 | alpha_builtins [(int) code] = decl; | |
6604 | } | |
6605 | ||
b657e73a | 6606 | /* Helper function of alpha_init_builtins. Add the COUNT built-in |
6607 | functions pointed to by P, with function type FTYPE. */ | |
6608 | ||
6609 | static void | |
6610 | alpha_add_builtins (const struct alpha_builtin_def *p, size_t count, | |
6611 | tree ftype) | |
6612 | { | |
b657e73a | 6613 | size_t i; |
6614 | ||
6615 | for (i = 0; i < count; ++i, ++p) | |
6616 | if ((target_flags & p->target_mask) == p->target_mask) | |
bad4fb18 | 6617 | alpha_builtin_function (p->name, ftype, p->code, |
6618 | (p->is_const ? ECF_CONST : 0) | ECF_NOTHROW); | |
b657e73a | 6619 | } |
6620 | ||
f2cc13dc | 6621 | static void |
92643d95 | 6622 | alpha_init_builtins (void) |
f2cc13dc | 6623 | { |
bad4fb18 | 6624 | tree ftype; |
f2cc13dc | 6625 | |
21c2a8b2 | 6626 | alpha_dimode_u = lang_hooks.types.type_for_mode (DImode, 1); |
6627 | alpha_v8qi_u = build_vector_type (unsigned_intQI_type_node, 8); | |
6628 | alpha_v8qi_s = build_vector_type (intQI_type_node, 8); | |
6629 | alpha_v4hi_u = build_vector_type (unsigned_intHI_type_node, 4); | |
6630 | alpha_v4hi_s = build_vector_type (intHI_type_node, 4); | |
e2dc233c | 6631 | |
21c2a8b2 | 6632 | ftype = build_function_type_list (alpha_dimode_u, NULL_TREE); |
6633 | alpha_add_builtins (zero_arg_builtins, ARRAY_SIZE (zero_arg_builtins), ftype); | |
f2cc13dc | 6634 | |
21c2a8b2 | 6635 | ftype = build_function_type_list (alpha_dimode_u, alpha_dimode_u, NULL_TREE); |
6636 | alpha_add_builtins (one_arg_builtins, ARRAY_SIZE (one_arg_builtins), ftype); | |
f2cc13dc | 6637 | |
21c2a8b2 | 6638 | ftype = build_function_type_list (alpha_dimode_u, alpha_dimode_u, |
6639 | alpha_dimode_u, NULL_TREE); | |
6640 | alpha_add_builtins (two_arg_builtins, ARRAY_SIZE (two_arg_builtins), ftype); | |
938e069b | 6641 | |
50f36bdb | 6642 | if (TARGET_ABI_OPEN_VMS) |
6643 | { | |
6644 | ftype = build_function_type_list (ptr_type_node, ptr_type_node, | |
6645 | NULL_TREE); | |
bad4fb18 | 6646 | alpha_builtin_function ("__builtin_establish_vms_condition_handler", |
6647 | ftype, | |
6648 | ALPHA_BUILTIN_ESTABLISH_VMS_CONDITION_HANDLER, | |
6649 | 0); | |
50f36bdb | 6650 | |
6651 | ftype = build_function_type_list (ptr_type_node, void_type_node, | |
6652 | NULL_TREE); | |
bad4fb18 | 6653 | alpha_builtin_function ("__builtin_revert_vms_condition_handler", ftype, |
6654 | ALPHA_BUILTIN_REVERT_VMS_CONDITION_HANDLER, 0); | |
ded97e77 | 6655 | |
6656 | vms_patch_builtins (); | |
50f36bdb | 6657 | } |
f2cc13dc | 6658 | } |
6659 | ||
6660 | /* Expand an expression EXP that calls a built-in function, | |
6661 | with result going to TARGET if that's convenient | |
6662 | (and in mode MODE if that's convenient). | |
6663 | SUBTARGET may be used as the target for computing one of EXP's operands. | |
6664 | IGNORE is nonzero if the value is to be ignored. */ | |
6665 | ||
6666 | static rtx | |
92643d95 | 6667 | alpha_expand_builtin (tree exp, rtx target, |
6668 | rtx subtarget ATTRIBUTE_UNUSED, | |
3754d046 | 6669 | machine_mode mode ATTRIBUTE_UNUSED, |
92643d95 | 6670 | int ignore ATTRIBUTE_UNUSED) |
f2cc13dc | 6671 | { |
f2cc13dc | 6672 | #define MAX_ARGS 2 |
6673 | ||
c2f47e15 | 6674 | tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); |
f2cc13dc | 6675 | unsigned int fcode = DECL_FUNCTION_CODE (fndecl); |
c2f47e15 | 6676 | tree arg; |
6677 | call_expr_arg_iterator iter; | |
f2cc13dc | 6678 | enum insn_code icode; |
6679 | rtx op[MAX_ARGS], pat; | |
6680 | int arity; | |
938e069b | 6681 | bool nonvoid; |
f2cc13dc | 6682 | |
6683 | if (fcode >= ALPHA_BUILTIN_max) | |
6684 | internal_error ("bad builtin fcode"); | |
6685 | icode = code_for_builtin[fcode]; | |
6686 | if (icode == 0) | |
6687 | internal_error ("bad builtin fcode"); | |
6688 | ||
938e069b | 6689 | nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; |
6690 | ||
c2f47e15 | 6691 | arity = 0; |
6692 | FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) | |
f2cc13dc | 6693 | { |
6694 | const struct insn_operand_data *insn_op; | |
6695 | ||
f2cc13dc | 6696 | if (arg == error_mark_node) |
6697 | return NULL_RTX; | |
6698 | if (arity > MAX_ARGS) | |
6699 | return NULL_RTX; | |
6700 | ||
938e069b | 6701 | insn_op = &insn_data[icode].operand[arity + nonvoid]; |
6702 | ||
0a48089c | 6703 | op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL); |
f2cc13dc | 6704 | |
f2cc13dc | 6705 | if (!(*insn_op->predicate) (op[arity], insn_op->mode)) |
6706 | op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]); | |
c2f47e15 | 6707 | arity++; |
f2cc13dc | 6708 | } |
6709 | ||
938e069b | 6710 | if (nonvoid) |
6711 | { | |
3754d046 | 6712 | machine_mode tmode = insn_data[icode].operand[0].mode; |
938e069b | 6713 | if (!target |
6714 | || GET_MODE (target) != tmode | |
6715 | || !(*insn_data[icode].operand[0].predicate) (target, tmode)) | |
6716 | target = gen_reg_rtx (tmode); | |
6717 | } | |
f2cc13dc | 6718 | |
6719 | switch (arity) | |
6720 | { | |
6721 | case 0: | |
6722 | pat = GEN_FCN (icode) (target); | |
6723 | break; | |
6724 | case 1: | |
938e069b | 6725 | if (nonvoid) |
6726 | pat = GEN_FCN (icode) (target, op[0]); | |
6727 | else | |
6728 | pat = GEN_FCN (icode) (op[0]); | |
f2cc13dc | 6729 | break; |
6730 | case 2: | |
6731 | pat = GEN_FCN (icode) (target, op[0], op[1]); | |
6732 | break; | |
6733 | default: | |
4d10b463 | 6734 | gcc_unreachable (); |
f2cc13dc | 6735 | } |
6736 | if (!pat) | |
6737 | return NULL_RTX; | |
6738 | emit_insn (pat); | |
6739 | ||
938e069b | 6740 | if (nonvoid) |
6741 | return target; | |
6742 | else | |
6743 | return const0_rtx; | |
f2cc13dc | 6744 | } |
849c7bc6 | 6745 | |
849c7bc6 | 6746 | /* Fold the builtin for the CMPBGE instruction. This is a vector comparison |
85c36fd1 | 6747 | with an 8-bit output vector. OPINT contains the integer operands; bit N |
849c7bc6 | 6748 | of OP_CONST is set if OPINT[N] is valid. */ |
6749 | ||
6750 | static tree | |
6751 | alpha_fold_builtin_cmpbge (unsigned HOST_WIDE_INT opint[], long op_const) | |
6752 | { | |
6753 | if (op_const == 3) | |
6754 | { | |
6755 | int i, val; | |
6756 | for (i = 0, val = 0; i < 8; ++i) | |
6757 | { | |
6758 | unsigned HOST_WIDE_INT c0 = (opint[0] >> (i * 8)) & 0xff; | |
6759 | unsigned HOST_WIDE_INT c1 = (opint[1] >> (i * 8)) & 0xff; | |
6760 | if (c0 >= c1) | |
6761 | val |= 1 << i; | |
6762 | } | |
21c2a8b2 | 6763 | return build_int_cst (alpha_dimode_u, val); |
849c7bc6 | 6764 | } |
3def9653 | 6765 | else if (op_const == 2 && opint[1] == 0) |
21c2a8b2 | 6766 | return build_int_cst (alpha_dimode_u, 0xff); |
849c7bc6 | 6767 | return NULL; |
6768 | } | |
6769 | ||
6770 | /* Fold the builtin for the ZAPNOT instruction. This is essentially a | |
6771 | specialized form of an AND operation. Other byte manipulation instructions | |
6772 | are defined in terms of this instruction, so this is also used as a | |
6773 | subroutine for other builtins. | |
6774 | ||
6775 | OP contains the tree operands; OPINT contains the extracted integer values. | |
6776 | Bit N of OP_CONST it set if OPINT[N] is valid. OP may be null if only | |
6777 | OPINT may be considered. */ | |
6778 | ||
6779 | static tree | |
6780 | alpha_fold_builtin_zapnot (tree *op, unsigned HOST_WIDE_INT opint[], | |
6781 | long op_const) | |
6782 | { | |
6783 | if (op_const & 2) | |
6784 | { | |
6785 | unsigned HOST_WIDE_INT mask = 0; | |
6786 | int i; | |
6787 | ||
6788 | for (i = 0; i < 8; ++i) | |
6789 | if ((opint[1] >> i) & 1) | |
6790 | mask |= (unsigned HOST_WIDE_INT)0xff << (i * 8); | |
6791 | ||
6792 | if (op_const & 1) | |
21c2a8b2 | 6793 | return build_int_cst (alpha_dimode_u, opint[0] & mask); |
849c7bc6 | 6794 | |
6795 | if (op) | |
21c2a8b2 | 6796 | return fold_build2 (BIT_AND_EXPR, alpha_dimode_u, op[0], |
6797 | build_int_cst (alpha_dimode_u, mask)); | |
849c7bc6 | 6798 | } |
6799 | else if ((op_const & 1) && opint[0] == 0) | |
21c2a8b2 | 6800 | return build_int_cst (alpha_dimode_u, 0); |
849c7bc6 | 6801 | return NULL; |
6802 | } | |
6803 | ||
6804 | /* Fold the builtins for the EXT family of instructions. */ | |
6805 | ||
6806 | static tree | |
6807 | alpha_fold_builtin_extxx (tree op[], unsigned HOST_WIDE_INT opint[], | |
6808 | long op_const, unsigned HOST_WIDE_INT bytemask, | |
6809 | bool is_high) | |
6810 | { | |
6811 | long zap_const = 2; | |
6812 | tree *zap_op = NULL; | |
6813 | ||
6814 | if (op_const & 2) | |
6815 | { | |
6816 | unsigned HOST_WIDE_INT loc; | |
6817 | ||
6818 | loc = opint[1] & 7; | |
9bab4302 | 6819 | loc *= BITS_PER_UNIT; |
849c7bc6 | 6820 | |
6821 | if (loc != 0) | |
6822 | { | |
6823 | if (op_const & 1) | |
6824 | { | |
6825 | unsigned HOST_WIDE_INT temp = opint[0]; | |
6826 | if (is_high) | |
6827 | temp <<= loc; | |
6828 | else | |
6829 | temp >>= loc; | |
6830 | opint[0] = temp; | |
6831 | zap_const = 3; | |
6832 | } | |
6833 | } | |
6834 | else | |
6835 | zap_op = op; | |
6836 | } | |
6837 | ||
6838 | opint[1] = bytemask; | |
6839 | return alpha_fold_builtin_zapnot (zap_op, opint, zap_const); | |
6840 | } | |
6841 | ||
6842 | /* Fold the builtins for the INS family of instructions. */ | |
6843 | ||
6844 | static tree | |
6845 | alpha_fold_builtin_insxx (tree op[], unsigned HOST_WIDE_INT opint[], | |
6846 | long op_const, unsigned HOST_WIDE_INT bytemask, | |
6847 | bool is_high) | |
6848 | { | |
6849 | if ((op_const & 1) && opint[0] == 0) | |
21c2a8b2 | 6850 | return build_int_cst (alpha_dimode_u, 0); |
849c7bc6 | 6851 | |
6852 | if (op_const & 2) | |
6853 | { | |
6854 | unsigned HOST_WIDE_INT temp, loc, byteloc; | |
6855 | tree *zap_op = NULL; | |
6856 | ||
6857 | loc = opint[1] & 7; | |
849c7bc6 | 6858 | bytemask <<= loc; |
6859 | ||
6860 | temp = opint[0]; | |
6861 | if (is_high) | |
6862 | { | |
6863 | byteloc = (64 - (loc * 8)) & 0x3f; | |
6864 | if (byteloc == 0) | |
6865 | zap_op = op; | |
6866 | else | |
6867 | temp >>= byteloc; | |
6868 | bytemask >>= 8; | |
6869 | } | |
6870 | else | |
6871 | { | |
6872 | byteloc = loc * 8; | |
6873 | if (byteloc == 0) | |
6874 | zap_op = op; | |
6875 | else | |
6876 | temp <<= byteloc; | |
6877 | } | |
6878 | ||
6879 | opint[0] = temp; | |
6880 | opint[1] = bytemask; | |
6881 | return alpha_fold_builtin_zapnot (zap_op, opint, op_const); | |
6882 | } | |
6883 | ||
6884 | return NULL; | |
6885 | } | |
6886 | ||
6887 | static tree | |
6888 | alpha_fold_builtin_mskxx (tree op[], unsigned HOST_WIDE_INT opint[], | |
6889 | long op_const, unsigned HOST_WIDE_INT bytemask, | |
6890 | bool is_high) | |
6891 | { | |
6892 | if (op_const & 2) | |
6893 | { | |
6894 | unsigned HOST_WIDE_INT loc; | |
6895 | ||
6896 | loc = opint[1] & 7; | |
849c7bc6 | 6897 | bytemask <<= loc; |
6898 | ||
6899 | if (is_high) | |
6900 | bytemask >>= 8; | |
6901 | ||
6902 | opint[1] = bytemask ^ 0xff; | |
6903 | } | |
6904 | ||
6905 | return alpha_fold_builtin_zapnot (op, opint, op_const); | |
6906 | } | |
6907 | ||
849c7bc6 | 6908 | static tree |
6909 | alpha_fold_vector_minmax (enum tree_code code, tree op[], tree vtype) | |
6910 | { | |
6911 | tree op0 = fold_convert (vtype, op[0]); | |
6912 | tree op1 = fold_convert (vtype, op[1]); | |
b3da1868 | 6913 | tree val = fold_build2 (code, vtype, op0, op1); |
21c2a8b2 | 6914 | return fold_build1 (VIEW_CONVERT_EXPR, alpha_dimode_u, val); |
849c7bc6 | 6915 | } |
6916 | ||
6917 | static tree | |
6918 | alpha_fold_builtin_perr (unsigned HOST_WIDE_INT opint[], long op_const) | |
6919 | { | |
6920 | unsigned HOST_WIDE_INT temp = 0; | |
6921 | int i; | |
6922 | ||
6923 | if (op_const != 3) | |
6924 | return NULL; | |
6925 | ||
6926 | for (i = 0; i < 8; ++i) | |
6927 | { | |
6928 | unsigned HOST_WIDE_INT a = (opint[0] >> (i * 8)) & 0xff; | |
6929 | unsigned HOST_WIDE_INT b = (opint[1] >> (i * 8)) & 0xff; | |
6930 | if (a >= b) | |
6931 | temp += a - b; | |
6932 | else | |
6933 | temp += b - a; | |
6934 | } | |
6935 | ||
21c2a8b2 | 6936 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6937 | } |
6938 | ||
6939 | static tree | |
6940 | alpha_fold_builtin_pklb (unsigned HOST_WIDE_INT opint[], long op_const) | |
6941 | { | |
6942 | unsigned HOST_WIDE_INT temp; | |
6943 | ||
6944 | if (op_const == 0) | |
6945 | return NULL; | |
6946 | ||
6947 | temp = opint[0] & 0xff; | |
6948 | temp |= (opint[0] >> 24) & 0xff00; | |
6949 | ||
21c2a8b2 | 6950 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6951 | } |
6952 | ||
6953 | static tree | |
6954 | alpha_fold_builtin_pkwb (unsigned HOST_WIDE_INT opint[], long op_const) | |
6955 | { | |
6956 | unsigned HOST_WIDE_INT temp; | |
6957 | ||
6958 | if (op_const == 0) | |
6959 | return NULL; | |
6960 | ||
6961 | temp = opint[0] & 0xff; | |
6962 | temp |= (opint[0] >> 8) & 0xff00; | |
6963 | temp |= (opint[0] >> 16) & 0xff0000; | |
6964 | temp |= (opint[0] >> 24) & 0xff000000; | |
6965 | ||
21c2a8b2 | 6966 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6967 | } |
6968 | ||
6969 | static tree | |
6970 | alpha_fold_builtin_unpkbl (unsigned HOST_WIDE_INT opint[], long op_const) | |
6971 | { | |
6972 | unsigned HOST_WIDE_INT temp; | |
6973 | ||
6974 | if (op_const == 0) | |
6975 | return NULL; | |
6976 | ||
6977 | temp = opint[0] & 0xff; | |
6978 | temp |= (opint[0] & 0xff00) << 24; | |
6979 | ||
21c2a8b2 | 6980 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6981 | } |
6982 | ||
6983 | static tree | |
6984 | alpha_fold_builtin_unpkbw (unsigned HOST_WIDE_INT opint[], long op_const) | |
6985 | { | |
6986 | unsigned HOST_WIDE_INT temp; | |
6987 | ||
6988 | if (op_const == 0) | |
6989 | return NULL; | |
6990 | ||
6991 | temp = opint[0] & 0xff; | |
6992 | temp |= (opint[0] & 0x0000ff00) << 8; | |
6993 | temp |= (opint[0] & 0x00ff0000) << 16; | |
6994 | temp |= (opint[0] & 0xff000000) << 24; | |
6995 | ||
21c2a8b2 | 6996 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6997 | } |
6998 | ||
6999 | static tree | |
7000 | alpha_fold_builtin_cttz (unsigned HOST_WIDE_INT opint[], long op_const) | |
7001 | { | |
7002 | unsigned HOST_WIDE_INT temp; | |
7003 | ||
7004 | if (op_const == 0) | |
7005 | return NULL; | |
7006 | ||
7007 | if (opint[0] == 0) | |
7008 | temp = 64; | |
7009 | else | |
7010 | temp = exact_log2 (opint[0] & -opint[0]); | |
7011 | ||
21c2a8b2 | 7012 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 7013 | } |
7014 | ||
7015 | static tree | |
7016 | alpha_fold_builtin_ctlz (unsigned HOST_WIDE_INT opint[], long op_const) | |
7017 | { | |
7018 | unsigned HOST_WIDE_INT temp; | |
7019 | ||
7020 | if (op_const == 0) | |
7021 | return NULL; | |
7022 | ||
7023 | if (opint[0] == 0) | |
7024 | temp = 64; | |
7025 | else | |
7026 | temp = 64 - floor_log2 (opint[0]) - 1; | |
7027 | ||
21c2a8b2 | 7028 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 7029 | } |
7030 | ||
7031 | static tree | |
7032 | alpha_fold_builtin_ctpop (unsigned HOST_WIDE_INT opint[], long op_const) | |
7033 | { | |
7034 | unsigned HOST_WIDE_INT temp, op; | |
7035 | ||
7036 | if (op_const == 0) | |
7037 | return NULL; | |
7038 | ||
7039 | op = opint[0]; | |
7040 | temp = 0; | |
7041 | while (op) | |
7042 | temp++, op &= op - 1; | |
7043 | ||
21c2a8b2 | 7044 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 7045 | } |
7046 | ||
7047 | /* Fold one of our builtin functions. */ | |
7048 | ||
7049 | static tree | |
97d67146 | 7050 | alpha_fold_builtin (tree fndecl, int n_args, tree *op, |
7051 | bool ignore ATTRIBUTE_UNUSED) | |
849c7bc6 | 7052 | { |
849c7bc6 | 7053 | unsigned HOST_WIDE_INT opint[MAX_ARGS]; |
432093e5 | 7054 | long op_const = 0; |
97d67146 | 7055 | int i; |
849c7bc6 | 7056 | |
21c2a8b2 | 7057 | if (n_args > MAX_ARGS) |
97d67146 | 7058 | return NULL; |
7059 | ||
7060 | for (i = 0; i < n_args; i++) | |
849c7bc6 | 7061 | { |
97d67146 | 7062 | tree arg = op[i]; |
849c7bc6 | 7063 | if (arg == error_mark_node) |
7064 | return NULL; | |
849c7bc6 | 7065 | |
97d67146 | 7066 | opint[i] = 0; |
849c7bc6 | 7067 | if (TREE_CODE (arg) == INTEGER_CST) |
7068 | { | |
97d67146 | 7069 | op_const |= 1L << i; |
7070 | opint[i] = int_cst_value (arg); | |
849c7bc6 | 7071 | } |
7072 | } | |
7073 | ||
7074 | switch (DECL_FUNCTION_CODE (fndecl)) | |
7075 | { | |
7076 | case ALPHA_BUILTIN_CMPBGE: | |
7077 | return alpha_fold_builtin_cmpbge (opint, op_const); | |
7078 | ||
7079 | case ALPHA_BUILTIN_EXTBL: | |
7080 | return alpha_fold_builtin_extxx (op, opint, op_const, 0x01, false); | |
7081 | case ALPHA_BUILTIN_EXTWL: | |
7082 | return alpha_fold_builtin_extxx (op, opint, op_const, 0x03, false); | |
7083 | case ALPHA_BUILTIN_EXTLL: | |
7084 | return alpha_fold_builtin_extxx (op, opint, op_const, 0x0f, false); | |
7085 | case ALPHA_BUILTIN_EXTQL: | |
7086 | return alpha_fold_builtin_extxx (op, opint, op_const, 0xff, false); | |
7087 | case ALPHA_BUILTIN_EXTWH: | |
7088 | return alpha_fold_builtin_extxx (op, opint, op_const, 0x03, true); | |
7089 | case ALPHA_BUILTIN_EXTLH: | |
7090 | return alpha_fold_builtin_extxx (op, opint, op_const, 0x0f, true); | |
7091 | case ALPHA_BUILTIN_EXTQH: | |
7092 | return alpha_fold_builtin_extxx (op, opint, op_const, 0xff, true); | |
7093 | ||
7094 | case ALPHA_BUILTIN_INSBL: | |
7095 | return alpha_fold_builtin_insxx (op, opint, op_const, 0x01, false); | |
7096 | case ALPHA_BUILTIN_INSWL: | |
7097 | return alpha_fold_builtin_insxx (op, opint, op_const, 0x03, false); | |
7098 | case ALPHA_BUILTIN_INSLL: | |
7099 | return alpha_fold_builtin_insxx (op, opint, op_const, 0x0f, false); | |
7100 | case ALPHA_BUILTIN_INSQL: | |
7101 | return alpha_fold_builtin_insxx (op, opint, op_const, 0xff, false); | |
7102 | case ALPHA_BUILTIN_INSWH: | |
7103 | return alpha_fold_builtin_insxx (op, opint, op_const, 0x03, true); | |
7104 | case ALPHA_BUILTIN_INSLH: | |
7105 | return alpha_fold_builtin_insxx (op, opint, op_const, 0x0f, true); | |
7106 | case ALPHA_BUILTIN_INSQH: | |
7107 | return alpha_fold_builtin_insxx (op, opint, op_const, 0xff, true); | |
7108 | ||
7109 | case ALPHA_BUILTIN_MSKBL: | |
7110 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0x01, false); | |
7111 | case ALPHA_BUILTIN_MSKWL: | |
7112 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0x03, false); | |
7113 | case ALPHA_BUILTIN_MSKLL: | |
7114 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0x0f, false); | |
7115 | case ALPHA_BUILTIN_MSKQL: | |
7116 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0xff, false); | |
7117 | case ALPHA_BUILTIN_MSKWH: | |
7118 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0x03, true); | |
7119 | case ALPHA_BUILTIN_MSKLH: | |
7120 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0x0f, true); | |
7121 | case ALPHA_BUILTIN_MSKQH: | |
7122 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0xff, true); | |
7123 | ||
849c7bc6 | 7124 | case ALPHA_BUILTIN_ZAP: |
7125 | opint[1] ^= 0xff; | |
7126 | /* FALLTHRU */ | |
7127 | case ALPHA_BUILTIN_ZAPNOT: | |
7128 | return alpha_fold_builtin_zapnot (op, opint, op_const); | |
7129 | ||
7130 | case ALPHA_BUILTIN_MINUB8: | |
7131 | return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v8qi_u); | |
7132 | case ALPHA_BUILTIN_MINSB8: | |
7133 | return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v8qi_s); | |
7134 | case ALPHA_BUILTIN_MINUW4: | |
7135 | return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v4hi_u); | |
7136 | case ALPHA_BUILTIN_MINSW4: | |
7137 | return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v4hi_s); | |
7138 | case ALPHA_BUILTIN_MAXUB8: | |
7139 | return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v8qi_u); | |
7140 | case ALPHA_BUILTIN_MAXSB8: | |
7141 | return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v8qi_s); | |
7142 | case ALPHA_BUILTIN_MAXUW4: | |
7143 | return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v4hi_u); | |
7144 | case ALPHA_BUILTIN_MAXSW4: | |
7145 | return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v4hi_s); | |
7146 | ||
7147 | case ALPHA_BUILTIN_PERR: | |
7148 | return alpha_fold_builtin_perr (opint, op_const); | |
7149 | case ALPHA_BUILTIN_PKLB: | |
7150 | return alpha_fold_builtin_pklb (opint, op_const); | |
7151 | case ALPHA_BUILTIN_PKWB: | |
7152 | return alpha_fold_builtin_pkwb (opint, op_const); | |
7153 | case ALPHA_BUILTIN_UNPKBL: | |
7154 | return alpha_fold_builtin_unpkbl (opint, op_const); | |
7155 | case ALPHA_BUILTIN_UNPKBW: | |
7156 | return alpha_fold_builtin_unpkbw (opint, op_const); | |
7157 | ||
7158 | case ALPHA_BUILTIN_CTTZ: | |
7159 | return alpha_fold_builtin_cttz (opint, op_const); | |
7160 | case ALPHA_BUILTIN_CTLZ: | |
7161 | return alpha_fold_builtin_ctlz (opint, op_const); | |
7162 | case ALPHA_BUILTIN_CTPOP: | |
7163 | return alpha_fold_builtin_ctpop (opint, op_const); | |
7164 | ||
7165 | case ALPHA_BUILTIN_AMASK: | |
7166 | case ALPHA_BUILTIN_IMPLVER: | |
7167 | case ALPHA_BUILTIN_RPCC: | |
849c7bc6 | 7168 | /* None of these are foldable at compile-time. */ |
7169 | default: | |
7170 | return NULL; | |
7171 | } | |
7172 | } | |
e3825818 | 7173 | |
7174 | bool | |
7175 | alpha_gimple_fold_builtin (gimple_stmt_iterator *gsi) | |
7176 | { | |
7177 | bool changed = false; | |
42acab1c | 7178 | gimple *stmt = gsi_stmt (*gsi); |
e3825818 | 7179 | tree call = gimple_call_fn (stmt); |
42acab1c | 7180 | gimple *new_stmt = NULL; |
e3825818 | 7181 | |
7182 | if (call) | |
7183 | { | |
7184 | tree fndecl = gimple_call_fndecl (stmt); | |
7185 | ||
7186 | if (fndecl) | |
7187 | { | |
7188 | tree arg0, arg1; | |
7189 | ||
7190 | switch (DECL_FUNCTION_CODE (fndecl)) | |
7191 | { | |
7192 | case ALPHA_BUILTIN_UMULH: | |
7193 | arg0 = gimple_call_arg (stmt, 0); | |
7194 | arg1 = gimple_call_arg (stmt, 1); | |
7195 | ||
84d842ae | 7196 | new_stmt = gimple_build_assign (gimple_call_lhs (stmt), |
7197 | MULT_HIGHPART_EXPR, arg0, arg1); | |
e3825818 | 7198 | break; |
7199 | default: | |
7200 | break; | |
7201 | } | |
7202 | } | |
7203 | } | |
7204 | ||
7205 | if (new_stmt) | |
7206 | { | |
7207 | gsi_replace (gsi, new_stmt, true); | |
7208 | changed = true; | |
7209 | } | |
7210 | ||
7211 | return changed; | |
7212 | } | |
f2cc13dc | 7213 | \f |
bf2a98b3 | 7214 | /* This page contains routines that are used to determine what the function |
7215 | prologue and epilogue code will do and write them out. */ | |
7216 | ||
7217 | /* Compute the size of the save area in the stack. */ | |
7218 | ||
8df4a58b | 7219 | /* These variables are used for communication between the following functions. |
7220 | They indicate various things about the current function being compiled | |
7221 | that are used to tell what kind of prologue, epilogue and procedure | |
efee20da | 7222 | descriptor to generate. */ |
8df4a58b | 7223 | |
7224 | /* Nonzero if we need a stack procedure. */ | |
b19d7ab1 | 7225 | enum alpha_procedure_types {PT_NULL = 0, PT_REGISTER = 1, PT_STACK = 2}; |
7226 | static enum alpha_procedure_types alpha_procedure_type; | |
8df4a58b | 7227 | |
7228 | /* Register number (either FP or SP) that is used to unwind the frame. */ | |
b9a5aa8e | 7229 | static int vms_unwind_regno; |
8df4a58b | 7230 | |
7231 | /* Register number used to save FP. We need not have one for RA since | |
7232 | we don't modify it for register procedures. This is only defined | |
7233 | for register frame procedures. */ | |
b9a5aa8e | 7234 | static int vms_save_fp_regno; |
8df4a58b | 7235 | |
7236 | /* Register number used to reference objects off our PV. */ | |
b9a5aa8e | 7237 | static int vms_base_regno; |
8df4a58b | 7238 | |
2cf1388a | 7239 | /* Compute register masks for saved registers. */ |
8df4a58b | 7240 | |
7241 | static void | |
92643d95 | 7242 | alpha_sa_mask (unsigned long *imaskP, unsigned long *fmaskP) |
8df4a58b | 7243 | { |
7244 | unsigned long imask = 0; | |
7245 | unsigned long fmask = 0; | |
1f0ce6a6 | 7246 | unsigned int i; |
8df4a58b | 7247 | |
eaa112a0 | 7248 | /* When outputting a thunk, we don't have valid register life info, |
7249 | but assemble_start_function wants to output .frame and .mask | |
7250 | directives. */ | |
9247818a | 7251 | if (cfun->is_thunk) |
2cf1388a | 7252 | { |
961d6ddd | 7253 | *imaskP = 0; |
7254 | *fmaskP = 0; | |
7255 | return; | |
7256 | } | |
8df4a58b | 7257 | |
b19d7ab1 | 7258 | if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK) |
df7d0d23 | 7259 | imask |= (1UL << HARD_FRAME_POINTER_REGNUM); |
8df4a58b | 7260 | |
961d6ddd | 7261 | /* One for every register we have to save. */ |
7262 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
7263 | if (! fixed_regs[i] && ! call_used_regs[i] | |
04d75965 | 7264 | && df_regs_ever_live_p (i) && i != REG_RA) |
961d6ddd | 7265 | { |
7266 | if (i < 32) | |
df7d0d23 | 7267 | imask |= (1UL << i); |
961d6ddd | 7268 | else |
df7d0d23 | 7269 | fmask |= (1UL << (i - 32)); |
961d6ddd | 7270 | } |
7271 | ||
7272 | /* We need to restore these for the handler. */ | |
18d50ae6 | 7273 | if (crtl->calls_eh_return) |
c49ad9ef | 7274 | { |
7275 | for (i = 0; ; ++i) | |
7276 | { | |
7277 | unsigned regno = EH_RETURN_DATA_REGNO (i); | |
7278 | if (regno == INVALID_REGNUM) | |
7279 | break; | |
7280 | imask |= 1UL << regno; | |
7281 | } | |
c49ad9ef | 7282 | } |
9e7454d0 | 7283 | |
961d6ddd | 7284 | /* If any register spilled, then spill the return address also. */ |
7285 | /* ??? This is required by the Digital stack unwind specification | |
7286 | and isn't needed if we're doing Dwarf2 unwinding. */ | |
7287 | if (imask || fmask || alpha_ra_ever_killed ()) | |
df7d0d23 | 7288 | imask |= (1UL << REG_RA); |
b9a5aa8e | 7289 | |
8df4a58b | 7290 | *imaskP = imask; |
7291 | *fmaskP = fmask; | |
8df4a58b | 7292 | } |
7293 | ||
7294 | int | |
92643d95 | 7295 | alpha_sa_size (void) |
8df4a58b | 7296 | { |
5aae9d06 | 7297 | unsigned long mask[2]; |
8df4a58b | 7298 | int sa_size = 0; |
5aae9d06 | 7299 | int i, j; |
8df4a58b | 7300 | |
5aae9d06 | 7301 | alpha_sa_mask (&mask[0], &mask[1]); |
7302 | ||
04d75965 | 7303 | for (j = 0; j < 2; ++j) |
7304 | for (i = 0; i < 32; ++i) | |
7305 | if ((mask[j] >> i) & 1) | |
7306 | sa_size++; | |
9caef960 | 7307 | |
04d75965 | 7308 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7309 | { |
d3832055 | 7310 | /* Start with a stack procedure if we make any calls (REG_RA used), or |
7311 | need a frame pointer, with a register procedure if we otherwise need | |
7312 | at least a slot, and with a null procedure in other cases. */ | |
7313 | if ((mask[0] >> REG_RA) & 1 || frame_pointer_needed) | |
b19d7ab1 | 7314 | alpha_procedure_type = PT_STACK; |
7315 | else if (get_frame_size() != 0) | |
7316 | alpha_procedure_type = PT_REGISTER; | |
7317 | else | |
7318 | alpha_procedure_type = PT_NULL; | |
5aae9d06 | 7319 | |
2ab60bb1 | 7320 | /* Don't reserve space for saving FP & RA yet. Do that later after we've |
5aae9d06 | 7321 | made the final decision on stack procedure vs register procedure. */ |
b19d7ab1 | 7322 | if (alpha_procedure_type == PT_STACK) |
2ab60bb1 | 7323 | sa_size -= 2; |
b9a5aa8e | 7324 | |
7325 | /* Decide whether to refer to objects off our PV via FP or PV. | |
7326 | If we need FP for something else or if we receive a nonlocal | |
7327 | goto (which expects PV to contain the value), we must use PV. | |
7328 | Otherwise, start by assuming we can use FP. */ | |
b19d7ab1 | 7329 | |
7330 | vms_base_regno | |
7331 | = (frame_pointer_needed | |
18d50ae6 | 7332 | || cfun->has_nonlocal_label |
b19d7ab1 | 7333 | || alpha_procedure_type == PT_STACK |
abe32cce | 7334 | || crtl->outgoing_args_size) |
b19d7ab1 | 7335 | ? REG_PV : HARD_FRAME_POINTER_REGNUM; |
b9a5aa8e | 7336 | |
7337 | /* If we want to copy PV into FP, we need to find some register | |
7338 | in which to save FP. */ | |
7339 | ||
7340 | vms_save_fp_regno = -1; | |
7341 | if (vms_base_regno == HARD_FRAME_POINTER_REGNUM) | |
7342 | for (i = 0; i < 32; i++) | |
3072d30e | 7343 | if (! fixed_regs[i] && call_used_regs[i] && ! df_regs_ever_live_p (i)) |
b9a5aa8e | 7344 | vms_save_fp_regno = i; |
7345 | ||
50f36bdb | 7346 | /* A VMS condition handler requires a stack procedure in our |
7347 | implementation. (not required by the calling standard). */ | |
7348 | if ((vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER) | |
7349 | || cfun->machine->uses_condition_handler) | |
b19d7ab1 | 7350 | vms_base_regno = REG_PV, alpha_procedure_type = PT_STACK; |
7351 | else if (alpha_procedure_type == PT_NULL) | |
7352 | vms_base_regno = REG_PV; | |
b9a5aa8e | 7353 | |
7354 | /* Stack unwinding should be done via FP unless we use it for PV. */ | |
7355 | vms_unwind_regno = (vms_base_regno == REG_PV | |
7356 | ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); | |
7357 | ||
50f36bdb | 7358 | /* If this is a stack procedure, allow space for saving FP, RA and |
7359 | a condition handler slot if needed. */ | |
b19d7ab1 | 7360 | if (alpha_procedure_type == PT_STACK) |
50f36bdb | 7361 | sa_size += 2 + cfun->machine->uses_condition_handler; |
b9a5aa8e | 7362 | } |
7363 | else | |
7364 | { | |
b9a5aa8e | 7365 | /* Our size must be even (multiple of 16 bytes). */ |
7366 | if (sa_size & 1) | |
7367 | sa_size++; | |
7368 | } | |
8df4a58b | 7369 | |
7370 | return sa_size * 8; | |
7371 | } | |
7372 | ||
4310aa50 | 7373 | /* Define the offset between two registers, one to be eliminated, |
7374 | and the other its replacement, at the start of a routine. */ | |
7375 | ||
7376 | HOST_WIDE_INT | |
92643d95 | 7377 | alpha_initial_elimination_offset (unsigned int from, |
7378 | unsigned int to ATTRIBUTE_UNUSED) | |
4310aa50 | 7379 | { |
7380 | HOST_WIDE_INT ret; | |
7381 | ||
7382 | ret = alpha_sa_size (); | |
abe32cce | 7383 | ret += ALPHA_ROUND (crtl->outgoing_args_size); |
4310aa50 | 7384 | |
4d10b463 | 7385 | switch (from) |
7386 | { | |
7387 | case FRAME_POINTER_REGNUM: | |
7388 | break; | |
7389 | ||
7390 | case ARG_POINTER_REGNUM: | |
7391 | ret += (ALPHA_ROUND (get_frame_size () | |
abe32cce | 7392 | + crtl->args.pretend_args_size) |
7393 | - crtl->args.pretend_args_size); | |
4d10b463 | 7394 | break; |
7395 | ||
7396 | default: | |
7397 | gcc_unreachable (); | |
7398 | } | |
4310aa50 | 7399 | |
7400 | return ret; | |
7401 | } | |
7402 | ||
d3832055 | 7403 | #if TARGET_ABI_OPEN_VMS |
7404 | ||
cd90919d | 7405 | /* Worker function for TARGET_CAN_ELIMINATE. */ |
7406 | ||
7407 | static bool | |
7408 | alpha_vms_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) | |
8df4a58b | 7409 | { |
d3832055 | 7410 | /* We need the alpha_procedure_type to decide. Evaluate it now. */ |
8df4a58b | 7411 | alpha_sa_size (); |
d3832055 | 7412 | |
7413 | switch (alpha_procedure_type) | |
7414 | { | |
7415 | case PT_NULL: | |
7416 | /* NULL procedures have no frame of their own and we only | |
7417 | know how to resolve from the current stack pointer. */ | |
7418 | return to == STACK_POINTER_REGNUM; | |
7419 | ||
7420 | case PT_REGISTER: | |
7421 | case PT_STACK: | |
7422 | /* We always eliminate except to the stack pointer if there is no | |
7423 | usable frame pointer at hand. */ | |
7424 | return (to != STACK_POINTER_REGNUM | |
7425 | || vms_unwind_regno != HARD_FRAME_POINTER_REGNUM); | |
7426 | } | |
7427 | ||
7428 | gcc_unreachable (); | |
8df4a58b | 7429 | } |
7430 | ||
d3832055 | 7431 | /* FROM is to be eliminated for TO. Return the offset so that TO+offset |
7432 | designates the same location as FROM. */ | |
7433 | ||
7434 | HOST_WIDE_INT | |
7435 | alpha_vms_initial_elimination_offset (unsigned int from, unsigned int to) | |
7436 | { | |
7437 | /* The only possible attempts we ever expect are ARG or FRAME_PTR to | |
7438 | HARD_FRAME or STACK_PTR. We need the alpha_procedure_type to decide | |
7439 | on the proper computations and will need the register save area size | |
7440 | in most cases. */ | |
7441 | ||
7442 | HOST_WIDE_INT sa_size = alpha_sa_size (); | |
7443 | ||
7444 | /* PT_NULL procedures have no frame of their own and we only allow | |
7445 | elimination to the stack pointer. This is the argument pointer and we | |
7446 | resolve the soft frame pointer to that as well. */ | |
7447 | ||
7448 | if (alpha_procedure_type == PT_NULL) | |
7449 | return 0; | |
7450 | ||
7451 | /* For a PT_STACK procedure the frame layout looks as follows | |
7452 | ||
7453 | -----> decreasing addresses | |
7454 | ||
7455 | < size rounded up to 16 | likewise > | |
7456 | --------------#------------------------------+++--------------+++-------# | |
7457 | incoming args # pretended args | "frame" | regs sa | PV | outgoing args # | |
7458 | --------------#---------------------------------------------------------# | |
7459 | ^ ^ ^ ^ | |
7460 | ARG_PTR FRAME_PTR HARD_FRAME_PTR STACK_PTR | |
7461 | ||
7462 | ||
7463 | PT_REGISTER procedures are similar in that they may have a frame of their | |
7464 | own. They have no regs-sa/pv/outgoing-args area. | |
7465 | ||
7466 | We first compute offset to HARD_FRAME_PTR, then add what we need to get | |
7467 | to STACK_PTR if need be. */ | |
7468 | ||
7469 | { | |
7470 | HOST_WIDE_INT offset; | |
7471 | HOST_WIDE_INT pv_save_size = alpha_procedure_type == PT_STACK ? 8 : 0; | |
7472 | ||
7473 | switch (from) | |
7474 | { | |
7475 | case FRAME_POINTER_REGNUM: | |
7476 | offset = ALPHA_ROUND (sa_size + pv_save_size); | |
7477 | break; | |
7478 | case ARG_POINTER_REGNUM: | |
7479 | offset = (ALPHA_ROUND (sa_size + pv_save_size | |
7480 | + get_frame_size () | |
7481 | + crtl->args.pretend_args_size) | |
7482 | - crtl->args.pretend_args_size); | |
7483 | break; | |
7484 | default: | |
7485 | gcc_unreachable (); | |
7486 | } | |
7487 | ||
7488 | if (to == STACK_POINTER_REGNUM) | |
7489 | offset += ALPHA_ROUND (crtl->outgoing_args_size); | |
7490 | ||
7491 | return offset; | |
7492 | } | |
8df4a58b | 7493 | } |
7494 | ||
00dca3d4 | 7495 | #define COMMON_OBJECT "common_object" |
7496 | ||
7497 | static tree | |
7498 | common_object_handler (tree *node, tree name ATTRIBUTE_UNUSED, | |
7499 | tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, | |
7500 | bool *no_add_attrs ATTRIBUTE_UNUSED) | |
7501 | { | |
7502 | tree decl = *node; | |
7503 | gcc_assert (DECL_P (decl)); | |
7504 | ||
7505 | DECL_COMMON (decl) = 1; | |
7506 | return NULL_TREE; | |
7507 | } | |
2d280039 | 7508 | |
cd819d2f | 7509 | static const struct attribute_spec vms_attribute_table[] = |
bf2a98b3 | 7510 | { |
672bc44d | 7511 | /* { name, min_len, max_len, decl_req, type_req, fn_type_req, |
7512 | affects_type_identity, handler, exclude } */ | |
7513 | { COMMON_OBJECT, 0, 1, true, false, false, false, common_object_handler, | |
dab0e385 | 7514 | NULL }, |
672bc44d | 7515 | { NULL, 0, 0, false, false, false, false, NULL, NULL } |
e3c541f0 | 7516 | }; |
bf2a98b3 | 7517 | |
00dca3d4 | 7518 | void |
7519 | vms_output_aligned_decl_common(FILE *file, tree decl, const char *name, | |
7520 | unsigned HOST_WIDE_INT size, | |
7521 | unsigned int align) | |
7522 | { | |
7523 | tree attr = DECL_ATTRIBUTES (decl); | |
7524 | fprintf (file, "%s", COMMON_ASM_OP); | |
7525 | assemble_name (file, name); | |
7526 | fprintf (file, "," HOST_WIDE_INT_PRINT_UNSIGNED, size); | |
7527 | /* ??? Unlike on OSF/1, the alignment factor is not in log units. */ | |
7528 | fprintf (file, ",%u", align / BITS_PER_UNIT); | |
7529 | if (attr) | |
7530 | { | |
7531 | attr = lookup_attribute (COMMON_OBJECT, attr); | |
7532 | if (attr) | |
7533 | fprintf (file, ",%s", | |
7534 | IDENTIFIER_POINTER (TREE_VALUE (TREE_VALUE (attr)))); | |
7535 | } | |
7536 | fputc ('\n', file); | |
7537 | } | |
7538 | ||
7539 | #undef COMMON_OBJECT | |
7540 | ||
2d280039 | 7541 | #endif |
7542 | ||
fe508bee | 7543 | bool |
92643d95 | 7544 | alpha_find_lo_sum_using_gp (rtx insn) |
a3859c0f | 7545 | { |
fe508bee | 7546 | subrtx_iterator::array_type array; |
7547 | FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST) | |
7548 | { | |
7549 | const_rtx x = *iter; | |
7550 | if (GET_CODE (x) == LO_SUM && XEXP (x, 0) == pic_offset_table_rtx) | |
7551 | return true; | |
7552 | } | |
7553 | return false; | |
1f0ce6a6 | 7554 | } |
7555 | ||
b9a5aa8e | 7556 | static int |
92643d95 | 7557 | alpha_does_function_need_gp (void) |
b9a5aa8e | 7558 | { |
7f0256ea | 7559 | rtx_insn *insn; |
bf2a98b3 | 7560 | |
9caef960 | 7561 | /* The GP being variable is an OSF abi thing. */ |
7562 | if (! TARGET_ABI_OSF) | |
b9a5aa8e | 7563 | return 0; |
bf2a98b3 | 7564 | |
008fdc59 | 7565 | /* We need the gp to load the address of __mcount. */ |
18d50ae6 | 7566 | if (TARGET_PROFILING_NEEDS_GP && crtl->profile) |
b9a5aa8e | 7567 | return 1; |
0e0a0e7a | 7568 | |
008fdc59 | 7569 | /* The code emitted by alpha_output_mi_thunk_osf uses the gp. */ |
9247818a | 7570 | if (cfun->is_thunk) |
2cf1388a | 7571 | return 1; |
2cf1388a | 7572 | |
008fdc59 | 7573 | /* The nonlocal receiver pattern assumes that the gp is valid for |
7574 | the nested function. Reasonable because it's almost always set | |
7575 | correctly already. For the cases where that's wrong, make sure | |
7576 | the nested function loads its gp on entry. */ | |
18d50ae6 | 7577 | if (crtl->has_nonlocal_goto) |
008fdc59 | 7578 | return 1; |
7579 | ||
9e7454d0 | 7580 | /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first. |
b9a5aa8e | 7581 | Even if we are a static function, we still need to do this in case |
7582 | our address is taken and passed to something like qsort. */ | |
bf2a98b3 | 7583 | |
b9a5aa8e | 7584 | push_topmost_sequence (); |
7585 | insn = get_insns (); | |
7586 | pop_topmost_sequence (); | |
8df4a58b | 7587 | |
b9a5aa8e | 7588 | for (; insn; insn = NEXT_INSN (insn)) |
30608852 | 7589 | if (NONDEBUG_INSN_P (insn) |
b9a5aa8e | 7590 | && GET_CODE (PATTERN (insn)) != USE |
a3859c0f | 7591 | && GET_CODE (PATTERN (insn)) != CLOBBER |
7592 | && get_attr_usegp (insn)) | |
7593 | return 1; | |
bf2a98b3 | 7594 | |
b9a5aa8e | 7595 | return 0; |
bf2a98b3 | 7596 | } |
7597 | ||
7d73bc2a | 7598 | \f |
5a965225 | 7599 | /* Helper function to set RTX_FRAME_RELATED_P on instructions, including |
7600 | sequences. */ | |
7601 | ||
7f0256ea | 7602 | static rtx_insn * |
92643d95 | 7603 | set_frame_related_p (void) |
5a965225 | 7604 | { |
7f0256ea | 7605 | rtx_insn *seq = get_insns (); |
7606 | rtx_insn *insn; | |
31d3e01c | 7607 | |
5a965225 | 7608 | end_sequence (); |
7609 | ||
31d3e01c | 7610 | if (!seq) |
7f0256ea | 7611 | return NULL; |
31d3e01c | 7612 | |
7613 | if (INSN_P (seq)) | |
5a965225 | 7614 | { |
31d3e01c | 7615 | insn = seq; |
7616 | while (insn != NULL_RTX) | |
7617 | { | |
7618 | RTX_FRAME_RELATED_P (insn) = 1; | |
7619 | insn = NEXT_INSN (insn); | |
7620 | } | |
7621 | seq = emit_insn (seq); | |
5a965225 | 7622 | } |
7623 | else | |
7624 | { | |
7625 | seq = emit_insn (seq); | |
7626 | RTX_FRAME_RELATED_P (seq) = 1; | |
5a965225 | 7627 | } |
31d3e01c | 7628 | return seq; |
5a965225 | 7629 | } |
7630 | ||
7631 | #define FRP(exp) (start_sequence (), exp, set_frame_related_p ()) | |
7632 | ||
fb0de38e | 7633 | /* Generates a store with the proper unwind info attached. VALUE is |
183f1993 | 7634 | stored at BASE_REG+BASE_OFS. If FRAME_BIAS is nonzero, then BASE_REG |
fb0de38e | 7635 | contains SP+FRAME_BIAS, and that is the unwind info that should be |
7636 | generated. If FRAME_REG != VALUE, then VALUE is being stored on | |
7637 | behalf of FRAME_REG, and FRAME_REG should be present in the unwind. */ | |
7638 | ||
7639 | static void | |
7640 | emit_frame_store_1 (rtx value, rtx base_reg, HOST_WIDE_INT frame_bias, | |
7641 | HOST_WIDE_INT base_ofs, rtx frame_reg) | |
7642 | { | |
7f0256ea | 7643 | rtx addr, mem; |
7644 | rtx_insn *insn; | |
fb0de38e | 7645 | |
29c05e22 | 7646 | addr = plus_constant (Pmode, base_reg, base_ofs); |
656e2b9d | 7647 | mem = gen_frame_mem (DImode, addr); |
fb0de38e | 7648 | |
7649 | insn = emit_move_insn (mem, value); | |
7650 | RTX_FRAME_RELATED_P (insn) = 1; | |
7651 | ||
7652 | if (frame_bias || value != frame_reg) | |
7653 | { | |
7654 | if (frame_bias) | |
7655 | { | |
29c05e22 | 7656 | addr = plus_constant (Pmode, stack_pointer_rtx, |
7657 | frame_bias + base_ofs); | |
fb0de38e | 7658 | mem = gen_rtx_MEM (DImode, addr); |
7659 | } | |
7660 | ||
0a48089c | 7661 | add_reg_note (insn, REG_FRAME_RELATED_EXPR, |
d1f9b275 | 7662 | gen_rtx_SET (mem, frame_reg)); |
fb0de38e | 7663 | } |
7664 | } | |
7665 | ||
7666 | static void | |
7667 | emit_frame_store (unsigned int regno, rtx base_reg, | |
7668 | HOST_WIDE_INT frame_bias, HOST_WIDE_INT base_ofs) | |
7669 | { | |
7670 | rtx reg = gen_rtx_REG (DImode, regno); | |
7671 | emit_frame_store_1 (reg, base_reg, frame_bias, base_ofs, reg); | |
7672 | } | |
7673 | ||
990495a7 | 7674 | /* Compute the frame size. SIZE is the size of the "naked" frame |
7675 | and SA_SIZE is the size of the register save area. */ | |
7676 | ||
7677 | static HOST_WIDE_INT | |
7678 | compute_frame_size (HOST_WIDE_INT size, HOST_WIDE_INT sa_size) | |
7679 | { | |
7680 | if (TARGET_ABI_OPEN_VMS) | |
7681 | return ALPHA_ROUND (sa_size | |
7682 | + (alpha_procedure_type == PT_STACK ? 8 : 0) | |
7683 | + size | |
7684 | + crtl->args.pretend_args_size); | |
990495a7 | 7685 | else |
7686 | return ALPHA_ROUND (crtl->outgoing_args_size) | |
7687 | + sa_size | |
7688 | + ALPHA_ROUND (size | |
7689 | + crtl->args.pretend_args_size); | |
7690 | } | |
7691 | ||
bf2a98b3 | 7692 | /* Write function prologue. */ |
7693 | ||
8df4a58b | 7694 | /* On vms we have two kinds of functions: |
7695 | ||
7696 | - stack frame (PROC_STACK) | |
7697 | these are 'normal' functions with local vars and which are | |
7698 | calling other functions | |
7699 | - register frame (PROC_REGISTER) | |
7700 | keeps all data in registers, needs no stack | |
7701 | ||
7702 | We must pass this to the assembler so it can generate the | |
7703 | proper pdsc (procedure descriptor) | |
7704 | This is done with the '.pdesc' command. | |
7705 | ||
b9a5aa8e | 7706 | On not-vms, we don't really differentiate between the two, as we can |
7707 | simply allocate stack without saving registers. */ | |
8df4a58b | 7708 | |
7709 | void | |
92643d95 | 7710 | alpha_expand_prologue (void) |
8df4a58b | 7711 | { |
b9a5aa8e | 7712 | /* Registers to save. */ |
8df4a58b | 7713 | unsigned long imask = 0; |
7714 | unsigned long fmask = 0; | |
7715 | /* Stack space needed for pushing registers clobbered by us. */ | |
04d75965 | 7716 | HOST_WIDE_INT sa_size, sa_bias; |
8df4a58b | 7717 | /* Complete stack size needed. */ |
7718 | HOST_WIDE_INT frame_size; | |
e1f9b4f8 | 7719 | /* Probed stack size; it additionally includes the size of |
7720 | the "reserve region" if any. */ | |
7721 | HOST_WIDE_INT probed_size; | |
8df4a58b | 7722 | /* Offset from base reg to register save area. */ |
b9a5aa8e | 7723 | HOST_WIDE_INT reg_offset; |
fb0de38e | 7724 | rtx sa_reg; |
8df4a58b | 7725 | int i; |
7726 | ||
7727 | sa_size = alpha_sa_size (); | |
990495a7 | 7728 | frame_size = compute_frame_size (get_frame_size (), sa_size); |
8df4a58b | 7729 | |
8c0dd614 | 7730 | if (flag_stack_usage_info) |
990495a7 | 7731 | current_function_static_stack_size = frame_size; |
8df4a58b | 7732 | |
1467e953 | 7733 | if (TARGET_ABI_OPEN_VMS) |
50f36bdb | 7734 | reg_offset = 8 + 8 * cfun->machine->uses_condition_handler; |
b9a5aa8e | 7735 | else |
abe32cce | 7736 | reg_offset = ALPHA_ROUND (crtl->outgoing_args_size); |
8df4a58b | 7737 | |
b9a5aa8e | 7738 | alpha_sa_mask (&imask, &fmask); |
8df4a58b | 7739 | |
a314eb5e | 7740 | /* Emit an insn to reload GP, if needed. */ |
1467e953 | 7741 | if (TARGET_ABI_OSF) |
a314eb5e | 7742 | { |
7743 | alpha_function_needs_gp = alpha_does_function_need_gp (); | |
7744 | if (alpha_function_needs_gp) | |
7745 | emit_insn (gen_prologue_ldgp ()); | |
7746 | } | |
7747 | ||
30dceb30 | 7748 | /* TARGET_PROFILING_NEEDS_GP actually implies that we need to insert |
7749 | the call to mcount ourselves, rather than having the linker do it | |
7750 | magically in response to -pg. Since _mcount has special linkage, | |
7751 | don't represent the call as a call. */ | |
18d50ae6 | 7752 | if (TARGET_PROFILING_NEEDS_GP && crtl->profile) |
30dceb30 | 7753 | emit_insn (gen_prologue_mcount ()); |
9caef960 | 7754 | |
8df4a58b | 7755 | /* Adjust the stack by the frame size. If the frame size is > 4096 |
7756 | bytes, we need to be sure we probe somewhere in the first and last | |
7757 | 4096 bytes (we can probably get away without the latter test) and | |
7758 | every 8192 bytes in between. If the frame size is > 32768, we | |
7759 | do this in a loop. Otherwise, we generate the explicit probe | |
9e7454d0 | 7760 | instructions. |
8df4a58b | 7761 | |
7762 | Note that we are only allowed to adjust sp once in the prologue. */ | |
7763 | ||
e1f9b4f8 | 7764 | probed_size = frame_size; |
1e81f1d8 | 7765 | if (flag_stack_check || flag_stack_clash_protection) |
f21f2061 | 7766 | probed_size += get_stack_check_protect (); |
e1f9b4f8 | 7767 | |
7768 | if (probed_size <= 32768) | |
8df4a58b | 7769 | { |
e1f9b4f8 | 7770 | if (probed_size > 4096) |
8df4a58b | 7771 | { |
baf8b2cc | 7772 | int probed; |
8df4a58b | 7773 | |
e1f9b4f8 | 7774 | for (probed = 4096; probed < probed_size; probed += 8192) |
b4a8fe79 | 7775 | emit_insn (gen_stack_probe_internal (GEN_INT (-probed))); |
8df4a58b | 7776 | |
e1f9b4f8 | 7777 | /* We only have to do this probe if we aren't saving registers or |
7778 | if we are probing beyond the frame because of -fstack-check. */ | |
7779 | if ((sa_size == 0 && probed_size > probed - 4096) | |
1e81f1d8 | 7780 | || flag_stack_check || flag_stack_clash_protection) |
b4a8fe79 | 7781 | emit_insn (gen_stack_probe_internal (GEN_INT (-probed_size))); |
8df4a58b | 7782 | } |
7783 | ||
7784 | if (frame_size != 0) | |
205b281f | 7785 | FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, |
04d75965 | 7786 | GEN_INT (-frame_size)))); |
8df4a58b | 7787 | } |
7788 | else | |
7789 | { | |
b9a5aa8e | 7790 | /* Here we generate code to set R22 to SP + 4096 and set R23 to the |
8df4a58b | 7791 | number of 8192 byte blocks to probe. We then probe each block |
7792 | in the loop and then set SP to the proper location. If the | |
7793 | amount remaining is > 4096, we have to do one more probe if we | |
e1f9b4f8 | 7794 | are not saving any registers or if we are probing beyond the |
7795 | frame because of -fstack-check. */ | |
8df4a58b | 7796 | |
e1f9b4f8 | 7797 | HOST_WIDE_INT blocks = (probed_size + 4096) / 8192; |
7798 | HOST_WIDE_INT leftover = probed_size + 4096 - blocks * 8192; | |
b9a5aa8e | 7799 | rtx ptr = gen_rtx_REG (DImode, 22); |
7800 | rtx count = gen_rtx_REG (DImode, 23); | |
cd28cb76 | 7801 | rtx seq; |
8df4a58b | 7802 | |
b9a5aa8e | 7803 | emit_move_insn (count, GEN_INT (blocks)); |
04d75965 | 7804 | emit_insn (gen_adddi3 (ptr, stack_pointer_rtx, GEN_INT (4096))); |
8df4a58b | 7805 | |
b9a5aa8e | 7806 | /* Because of the difficulty in emitting a new basic block this |
7807 | late in the compilation, generate the loop as a single insn. */ | |
7808 | emit_insn (gen_prologue_stack_probe_loop (count, ptr)); | |
8df4a58b | 7809 | |
1e81f1d8 | 7810 | if ((leftover > 4096 && sa_size == 0) |
7811 | || flag_stack_check || flag_stack_clash_protection) | |
b9a5aa8e | 7812 | { |
29c05e22 | 7813 | rtx last = gen_rtx_MEM (DImode, |
7814 | plus_constant (Pmode, ptr, -leftover)); | |
b9a5aa8e | 7815 | MEM_VOLATILE_P (last) = 1; |
7816 | emit_move_insn (last, const0_rtx); | |
7817 | } | |
8df4a58b | 7818 | |
1e81f1d8 | 7819 | if (flag_stack_check || flag_stack_clash_protection) |
f88f2646 | 7820 | { |
1b803a4f | 7821 | /* If -fstack-check is specified we have to load the entire |
7822 | constant into a register and subtract from the sp in one go, | |
7823 | because the probed stack size is not equal to the frame size. */ | |
f88f2646 | 7824 | HOST_WIDE_INT lo, hi; |
05bea6dd | 7825 | lo = ((frame_size & 0xffff) ^ 0x8000) - 0x8000; |
7826 | hi = frame_size - lo; | |
5a965225 | 7827 | |
cd28cb76 | 7828 | emit_move_insn (ptr, GEN_INT (hi)); |
df9e12ce | 7829 | emit_insn (gen_adddi3 (ptr, ptr, GEN_INT (lo))); |
cd28cb76 | 7830 | seq = emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, |
7831 | ptr)); | |
f88f2646 | 7832 | } |
7833 | else | |
7834 | { | |
f88f2646 | 7835 | seq = emit_insn (gen_adddi3 (stack_pointer_rtx, ptr, |
7836 | GEN_INT (-leftover))); | |
f88f2646 | 7837 | } |
cd28cb76 | 7838 | |
7839 | /* This alternative is special, because the DWARF code cannot | |
7840 | possibly intuit through the loop above. So we invent this | |
7841 | note it looks at instead. */ | |
7842 | RTX_FRAME_RELATED_P (seq) = 1; | |
0a48089c | 7843 | add_reg_note (seq, REG_FRAME_RELATED_EXPR, |
d1f9b275 | 7844 | gen_rtx_SET (stack_pointer_rtx, |
29c05e22 | 7845 | plus_constant (Pmode, stack_pointer_rtx, |
04d75965 | 7846 | -frame_size))); |
8df4a58b | 7847 | } |
7848 | ||
04d75965 | 7849 | /* Cope with very large offsets to the register save area. */ |
7850 | sa_bias = 0; | |
7851 | sa_reg = stack_pointer_rtx; | |
7852 | if (reg_offset + sa_size > 0x8000) | |
8df4a58b | 7853 | { |
04d75965 | 7854 | int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000; |
7855 | rtx sa_bias_rtx; | |
8df4a58b | 7856 | |
04d75965 | 7857 | if (low + sa_size <= 0x8000) |
7858 | sa_bias = reg_offset - low, reg_offset = low; | |
7859 | else | |
7860 | sa_bias = reg_offset, reg_offset = 0; | |
9e7454d0 | 7861 | |
04d75965 | 7862 | sa_reg = gen_rtx_REG (DImode, 24); |
7863 | sa_bias_rtx = GEN_INT (sa_bias); | |
8df4a58b | 7864 | |
04d75965 | 7865 | if (add_operand (sa_bias_rtx, DImode)) |
7866 | emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, sa_bias_rtx)); | |
7867 | else | |
9caef960 | 7868 | { |
04d75965 | 7869 | emit_move_insn (sa_reg, sa_bias_rtx); |
7870 | emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, sa_reg)); | |
9caef960 | 7871 | } |
04d75965 | 7872 | } |
8df4a58b | 7873 | |
04d75965 | 7874 | /* Save regs in stack order. Beginning with VMS PV. */ |
7875 | if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK) | |
7876 | emit_frame_store (REG_PV, stack_pointer_rtx, 0, 0); | |
8df4a58b | 7877 | |
04d75965 | 7878 | /* Save register RA next. */ |
7879 | if (imask & (1UL << REG_RA)) | |
9caef960 | 7880 | { |
04d75965 | 7881 | emit_frame_store (REG_RA, sa_reg, sa_bias, reg_offset); |
7882 | imask &= ~(1UL << REG_RA); | |
7883 | reg_offset += 8; | |
9caef960 | 7884 | } |
8df4a58b | 7885 | |
04d75965 | 7886 | /* Now save any other registers required to be saved. */ |
7887 | for (i = 0; i < 31; i++) | |
7888 | if (imask & (1UL << i)) | |
7889 | { | |
7890 | emit_frame_store (i, sa_reg, sa_bias, reg_offset); | |
7891 | reg_offset += 8; | |
7892 | } | |
7893 | ||
7894 | for (i = 0; i < 31; i++) | |
7895 | if (fmask & (1UL << i)) | |
7896 | { | |
7897 | emit_frame_store (i+32, sa_reg, sa_bias, reg_offset); | |
7898 | reg_offset += 8; | |
7899 | } | |
7900 | ||
1467e953 | 7901 | if (TARGET_ABI_OPEN_VMS) |
8df4a58b | 7902 | { |
d30e4246 | 7903 | /* Register frame procedures save the fp. */ |
b19d7ab1 | 7904 | if (alpha_procedure_type == PT_REGISTER) |
d30e4246 | 7905 | { |
7f0256ea | 7906 | rtx_insn *insn = |
7907 | emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno), | |
7908 | hard_frame_pointer_rtx); | |
d30e4246 | 7909 | add_reg_note (insn, REG_CFA_REGISTER, NULL); |
7910 | RTX_FRAME_RELATED_P (insn) = 1; | |
7911 | } | |
8df4a58b | 7912 | |
b19d7ab1 | 7913 | if (alpha_procedure_type != PT_NULL && vms_base_regno != REG_PV) |
6d50e356 | 7914 | emit_insn (gen_force_movdi (gen_rtx_REG (DImode, vms_base_regno), |
7915 | gen_rtx_REG (DImode, REG_PV))); | |
8df4a58b | 7916 | |
b19d7ab1 | 7917 | if (alpha_procedure_type != PT_NULL |
7918 | && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM) | |
205b281f | 7919 | FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); |
8df4a58b | 7920 | |
b9a5aa8e | 7921 | /* If we have to allocate space for outgoing args, do it now. */ |
abe32cce | 7922 | if (crtl->outgoing_args_size != 0) |
81a5b286 | 7923 | { |
7f0256ea | 7924 | rtx_insn *seq |
9e7454d0 | 7925 | = emit_move_insn (stack_pointer_rtx, |
81a5b286 | 7926 | plus_constant |
29c05e22 | 7927 | (Pmode, hard_frame_pointer_rtx, |
81a5b286 | 7928 | - (ALPHA_ROUND |
abe32cce | 7929 | (crtl->outgoing_args_size)))); |
9e7454d0 | 7930 | |
81a5b286 | 7931 | /* Only set FRAME_RELATED_P on the stack adjustment we just emitted |
7932 | if ! frame_pointer_needed. Setting the bit will change the CFA | |
7933 | computation rule to use sp again, which would be wrong if we had | |
7934 | frame_pointer_needed, as this means sp might move unpredictably | |
7935 | later on. | |
7936 | ||
7937 | Also, note that | |
7938 | frame_pointer_needed | |
7939 | => vms_unwind_regno == HARD_FRAME_POINTER_REGNUM | |
7940 | and | |
abe32cce | 7941 | crtl->outgoing_args_size != 0 |
81a5b286 | 7942 | => alpha_procedure_type != PT_NULL, |
7943 | ||
7944 | so when we are not setting the bit here, we are guaranteed to | |
5910bb95 | 7945 | have emitted an FRP frame pointer update just before. */ |
81a5b286 | 7946 | RTX_FRAME_RELATED_P (seq) = ! frame_pointer_needed; |
7947 | } | |
b9a5aa8e | 7948 | } |
04d75965 | 7949 | else |
b9a5aa8e | 7950 | { |
7951 | /* If we need a frame pointer, set it from the stack pointer. */ | |
7952 | if (frame_pointer_needed) | |
7953 | { | |
7954 | if (TARGET_CAN_FAULT_IN_PROLOGUE) | |
5a965225 | 7955 | FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); |
8df4a58b | 7956 | else |
205b281f | 7957 | /* This must always be the last instruction in the |
7958 | prologue, thus we emit a special move + clobber. */ | |
5a965225 | 7959 | FRP (emit_insn (gen_init_fp (hard_frame_pointer_rtx, |
7960 | stack_pointer_rtx, sa_reg))); | |
8df4a58b | 7961 | } |
8df4a58b | 7962 | } |
7963 | ||
b9a5aa8e | 7964 | /* The ABIs for VMS and OSF/1 say that while we can schedule insns into |
7965 | the prologue, for exception handling reasons, we cannot do this for | |
7966 | any insn that might fault. We could prevent this for mems with a | |
7967 | (clobber:BLK (scratch)), but this doesn't work for fp insns. So we | |
7968 | have to prevent all such scheduling with a blockage. | |
8df4a58b | 7969 | |
9e7454d0 | 7970 | Linux, on the other hand, never bothered to implement OSF/1's |
b9a5aa8e | 7971 | exception handling, and so doesn't care about such things. Anyone |
7972 | planning to use dwarf2 frame-unwind info can also omit the blockage. */ | |
8df4a58b | 7973 | |
b9a5aa8e | 7974 | if (! TARGET_CAN_FAULT_IN_PROLOGUE) |
7975 | emit_insn (gen_blockage ()); | |
1fce2e8a | 7976 | } |
7977 | ||
e3b8b697 | 7978 | /* Count the number of .file directives, so that .loc is up to date. */ |
d0de818d | 7979 | int num_source_filenames = 0; |
e3b8b697 | 7980 | |
2cf1388a | 7981 | /* Output the textual info surrounding the prologue. */ |
8df4a58b | 7982 | |
b9a5aa8e | 7983 | void |
92643d95 | 7984 | alpha_start_function (FILE *file, const char *fnname, |
7985 | tree decl ATTRIBUTE_UNUSED) | |
0c0464e6 | 7986 | { |
b9a5aa8e | 7987 | unsigned long imask = 0; |
7988 | unsigned long fmask = 0; | |
7989 | /* Stack space needed for pushing registers clobbered by us. */ | |
7990 | HOST_WIDE_INT sa_size; | |
7991 | /* Complete stack size needed. */ | |
f9e9d81d | 7992 | unsigned HOST_WIDE_INT frame_size; |
126b6848 | 7993 | /* The maximum debuggable frame size. */ |
7994 | unsigned HOST_WIDE_INT max_frame_size = 1UL << 31; | |
b9a5aa8e | 7995 | /* Offset from base reg to register save area. */ |
7996 | HOST_WIDE_INT reg_offset; | |
2cf1388a | 7997 | char *entry_label = (char *) alloca (strlen (fnname) + 6); |
d2f33c43 | 7998 | char *tramp_label = (char *) alloca (strlen (fnname) + 6); |
b9a5aa8e | 7999 | int i; |
0c0464e6 | 8000 | |
1f697db5 | 8001 | #if TARGET_ABI_OPEN_VMS |
784576c7 | 8002 | vms_start_function (fnname); |
1f697db5 | 8003 | #endif |
8004 | ||
a314eb5e | 8005 | alpha_fnname = fnname; |
b9a5aa8e | 8006 | sa_size = alpha_sa_size (); |
990495a7 | 8007 | frame_size = compute_frame_size (get_frame_size (), sa_size); |
0c0464e6 | 8008 | |
1467e953 | 8009 | if (TARGET_ABI_OPEN_VMS) |
50f36bdb | 8010 | reg_offset = 8 + 8 * cfun->machine->uses_condition_handler; |
b9a5aa8e | 8011 | else |
abe32cce | 8012 | reg_offset = ALPHA_ROUND (crtl->outgoing_args_size); |
0c0464e6 | 8013 | |
b9a5aa8e | 8014 | alpha_sa_mask (&imask, &fmask); |
bf2a98b3 | 8015 | |
b9a5aa8e | 8016 | /* Issue function start and label. */ |
04d75965 | 8017 | if (TARGET_ABI_OPEN_VMS || !flag_inhibit_size_directive) |
f1fe649e | 8018 | { |
b9a5aa8e | 8019 | fputs ("\t.ent ", file); |
2cf1388a | 8020 | assemble_name (file, fnname); |
b9a5aa8e | 8021 | putc ('\n', file); |
a314eb5e | 8022 | |
8023 | /* If the function needs GP, we'll write the "..ng" label there. | |
8024 | Otherwise, do it here. */ | |
961d6ddd | 8025 | if (TARGET_ABI_OSF |
8026 | && ! alpha_function_needs_gp | |
9247818a | 8027 | && ! cfun->is_thunk) |
a314eb5e | 8028 | { |
8029 | putc ('$', file); | |
8030 | assemble_name (file, fnname); | |
8031 | fputs ("..ng:\n", file); | |
8032 | } | |
f1fe649e | 8033 | } |
d2f33c43 | 8034 | /* Nested functions on VMS that are potentially called via trampoline |
8035 | get a special transfer entry point that loads the called functions | |
8036 | procedure descriptor and static chain. */ | |
8037 | if (TARGET_ABI_OPEN_VMS | |
8038 | && !TREE_PUBLIC (decl) | |
8039 | && DECL_CONTEXT (decl) | |
d8f99b92 | 8040 | && !TYPE_P (DECL_CONTEXT (decl)) |
8041 | && TREE_CODE (DECL_CONTEXT (decl)) != TRANSLATION_UNIT_DECL) | |
d2f33c43 | 8042 | { |
8043 | strcpy (tramp_label, fnname); | |
8044 | strcat (tramp_label, "..tr"); | |
8045 | ASM_OUTPUT_LABEL (file, tramp_label); | |
8046 | fprintf (file, "\tldq $1,24($27)\n"); | |
8047 | fprintf (file, "\tldq $27,16($27)\n"); | |
8048 | } | |
449b7f2d | 8049 | |
2cf1388a | 8050 | strcpy (entry_label, fnname); |
1467e953 | 8051 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 8052 | strcat (entry_label, "..en"); |
9caef960 | 8053 | |
b9a5aa8e | 8054 | ASM_OUTPUT_LABEL (file, entry_label); |
8055 | inside_function = TRUE; | |
449b7f2d | 8056 | |
1467e953 | 8057 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 8058 | fprintf (file, "\t.base $%d\n", vms_base_regno); |
bf2a98b3 | 8059 | |
4505d022 | 8060 | if (TARGET_ABI_OSF |
8061 | && TARGET_IEEE_CONFORMANT | |
b9a5aa8e | 8062 | && !flag_inhibit_size_directive) |
9c0e5703 | 8063 | { |
b9a5aa8e | 8064 | /* Set flags in procedure descriptor to request IEEE-conformant |
8065 | math-library routines. The value we set it to is PDSC_EXC_IEEE | |
65abff06 | 8066 | (/usr/include/pdsc.h). */ |
b9a5aa8e | 8067 | fputs ("\t.eflag 48\n", file); |
9c0e5703 | 8068 | } |
bf2a98b3 | 8069 | |
b9a5aa8e | 8070 | /* Set up offsets to alpha virtual arg/local debugging pointer. */ |
abe32cce | 8071 | alpha_auto_offset = -frame_size + crtl->args.pretend_args_size; |
b9a5aa8e | 8072 | alpha_arg_offset = -frame_size + 48; |
cb015df5 | 8073 | |
b9a5aa8e | 8074 | /* Describe our frame. If the frame size is larger than an integer, |
8075 | print it as zero to avoid an assembler error. We won't be | |
8076 | properly describing such a frame, but that's the best we can do. */ | |
04d75965 | 8077 | if (TARGET_ABI_OPEN_VMS) |
4840a03a | 8078 | fprintf (file, "\t.frame $%d," HOST_WIDE_INT_PRINT_DEC ",$26," |
8079 | HOST_WIDE_INT_PRINT_DEC "\n", | |
8080 | vms_unwind_regno, | |
8081 | frame_size >= (1UL << 31) ? 0 : frame_size, | |
8082 | reg_offset); | |
b9a5aa8e | 8083 | else if (!flag_inhibit_size_directive) |
4840a03a | 8084 | fprintf (file, "\t.frame $%d," HOST_WIDE_INT_PRINT_DEC ",$26,%d\n", |
8085 | (frame_pointer_needed | |
8086 | ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM), | |
6dbdfeeb | 8087 | frame_size >= max_frame_size ? 0 : frame_size, |
abe32cce | 8088 | crtl->args.pretend_args_size); |
15d5236f | 8089 | |
b9a5aa8e | 8090 | /* Describe which registers were spilled. */ |
04d75965 | 8091 | if (TARGET_ABI_OPEN_VMS) |
15d5236f | 8092 | { |
b9a5aa8e | 8093 | if (imask) |
9caef960 | 8094 | /* ??? Does VMS care if mask contains ra? The old code didn't |
b9a5aa8e | 8095 | set it, so I don't here. */ |
df7d0d23 | 8096 | fprintf (file, "\t.mask 0x%lx,0\n", imask & ~(1UL << REG_RA)); |
b9a5aa8e | 8097 | if (fmask) |
769ea120 | 8098 | fprintf (file, "\t.fmask 0x%lx,0\n", fmask); |
b19d7ab1 | 8099 | if (alpha_procedure_type == PT_REGISTER) |
b9a5aa8e | 8100 | fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno); |
8101 | } | |
8102 | else if (!flag_inhibit_size_directive) | |
8103 | { | |
8104 | if (imask) | |
15d5236f | 8105 | { |
4840a03a | 8106 | fprintf (file, "\t.mask 0x%lx," HOST_WIDE_INT_PRINT_DEC "\n", imask, |
6dbdfeeb | 8107 | frame_size >= max_frame_size ? 0 : reg_offset - frame_size); |
b9a5aa8e | 8108 | |
8109 | for (i = 0; i < 32; ++i) | |
df7d0d23 | 8110 | if (imask & (1UL << i)) |
b9a5aa8e | 8111 | reg_offset += 8; |
15d5236f | 8112 | } |
b9a5aa8e | 8113 | |
8114 | if (fmask) | |
4840a03a | 8115 | fprintf (file, "\t.fmask 0x%lx," HOST_WIDE_INT_PRINT_DEC "\n", fmask, |
6dbdfeeb | 8116 | frame_size >= max_frame_size ? 0 : reg_offset - frame_size); |
bf2a98b3 | 8117 | } |
8118 | ||
1467e953 | 8119 | #if TARGET_ABI_OPEN_VMS |
50f36bdb | 8120 | /* If a user condition handler has been installed at some point, emit |
8121 | the procedure descriptor bits to point the Condition Handling Facility | |
8122 | at the indirection wrapper, and state the fp offset at which the user | |
8123 | handler may be found. */ | |
8124 | if (cfun->machine->uses_condition_handler) | |
8125 | { | |
8126 | fprintf (file, "\t.handler __gcc_shell_handler\n"); | |
8127 | fprintf (file, "\t.handler_data %d\n", VMS_COND_HANDLER_FP_OFFSET); | |
8128 | } | |
8129 | ||
5ce94904 | 8130 | #ifdef TARGET_VMS_CRASH_DEBUG |
8131 | /* Support of minimal traceback info. */ | |
2f14b1f9 | 8132 | switch_to_section (readonly_data_section); |
b9a5aa8e | 8133 | fprintf (file, "\t.align 3\n"); |
2cf1388a | 8134 | assemble_name (file, fnname); fputs ("..na:\n", file); |
b9a5aa8e | 8135 | fputs ("\t.ascii \"", file); |
2cf1388a | 8136 | assemble_name (file, fnname); |
b9a5aa8e | 8137 | fputs ("\\0\"\n", file); |
2f14b1f9 | 8138 | switch_to_section (text_section); |
b9a5aa8e | 8139 | #endif |
5ce94904 | 8140 | #endif /* TARGET_ABI_OPEN_VMS */ |
b9a5aa8e | 8141 | } |
bf2a98b3 | 8142 | |
b9a5aa8e | 8143 | /* Emit the .prologue note at the scheduled end of the prologue. */ |
16b3392b | 8144 | |
85ae73e8 | 8145 | static void |
92643d95 | 8146 | alpha_output_function_end_prologue (FILE *file) |
b9a5aa8e | 8147 | { |
04d75965 | 8148 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 8149 | fputs ("\t.prologue\n", file); |
b9a5aa8e | 8150 | else if (!flag_inhibit_size_directive) |
961d6ddd | 8151 | fprintf (file, "\t.prologue %d\n", |
9247818a | 8152 | alpha_function_needs_gp || cfun->is_thunk); |
bf2a98b3 | 8153 | } |
8154 | ||
8155 | /* Write function epilogue. */ | |
8156 | ||
8157 | void | |
92643d95 | 8158 | alpha_expand_epilogue (void) |
bf2a98b3 | 8159 | { |
b9a5aa8e | 8160 | /* Registers to save. */ |
8161 | unsigned long imask = 0; | |
8162 | unsigned long fmask = 0; | |
8163 | /* Stack space needed for pushing registers clobbered by us. */ | |
8164 | HOST_WIDE_INT sa_size; | |
8165 | /* Complete stack size needed. */ | |
8166 | HOST_WIDE_INT frame_size; | |
8167 | /* Offset from base reg to register save area. */ | |
8168 | HOST_WIDE_INT reg_offset; | |
8169 | int fp_is_frame_pointer, fp_offset; | |
8170 | rtx sa_reg, sa_reg_exp = NULL; | |
d30e4246 | 8171 | rtx sp_adj1, sp_adj2, mem, reg, insn; |
11016d99 | 8172 | rtx eh_ofs; |
d30e4246 | 8173 | rtx cfa_restores = NULL_RTX; |
bf2a98b3 | 8174 | int i; |
8175 | ||
b9a5aa8e | 8176 | sa_size = alpha_sa_size (); |
990495a7 | 8177 | frame_size = compute_frame_size (get_frame_size (), sa_size); |
bf2a98b3 | 8178 | |
1467e953 | 8179 | if (TARGET_ABI_OPEN_VMS) |
b19d7ab1 | 8180 | { |
8181 | if (alpha_procedure_type == PT_STACK) | |
50f36bdb | 8182 | reg_offset = 8 + 8 * cfun->machine->uses_condition_handler; |
b19d7ab1 | 8183 | else |
8184 | reg_offset = 0; | |
8185 | } | |
b9a5aa8e | 8186 | else |
abe32cce | 8187 | reg_offset = ALPHA_ROUND (crtl->outgoing_args_size); |
b9a5aa8e | 8188 | |
8189 | alpha_sa_mask (&imask, &fmask); | |
8190 | ||
b19d7ab1 | 8191 | fp_is_frame_pointer |
4505d022 | 8192 | = (TARGET_ABI_OPEN_VMS |
8193 | ? alpha_procedure_type == PT_STACK | |
8194 | : frame_pointer_needed); | |
29768226 | 8195 | fp_offset = 0; |
8196 | sa_reg = stack_pointer_rtx; | |
b9a5aa8e | 8197 | |
18d50ae6 | 8198 | if (crtl->calls_eh_return) |
c92c328f | 8199 | eh_ofs = EH_RETURN_STACKADJ_RTX; |
8200 | else | |
8201 | eh_ofs = NULL_RTX; | |
8202 | ||
04d75965 | 8203 | if (sa_size) |
b9a5aa8e | 8204 | { |
8205 | /* If we have a frame pointer, restore SP from it. */ | |
4505d022 | 8206 | if (TARGET_ABI_OPEN_VMS |
8207 | ? vms_unwind_regno == HARD_FRAME_POINTER_REGNUM | |
8208 | : frame_pointer_needed) | |
d30e4246 | 8209 | emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); |
15d5236f | 8210 | |
b9a5aa8e | 8211 | /* Cope with very large offsets to the register save area. */ |
b9a5aa8e | 8212 | if (reg_offset + sa_size > 0x8000) |
bf2a98b3 | 8213 | { |
b9a5aa8e | 8214 | int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000; |
8215 | HOST_WIDE_INT bias; | |
8216 | ||
8217 | if (low + sa_size <= 0x8000) | |
8218 | bias = reg_offset - low, reg_offset = low; | |
9e7454d0 | 8219 | else |
b9a5aa8e | 8220 | bias = reg_offset, reg_offset = 0; |
8221 | ||
8222 | sa_reg = gen_rtx_REG (DImode, 22); | |
29c05e22 | 8223 | sa_reg_exp = plus_constant (Pmode, stack_pointer_rtx, bias); |
b9a5aa8e | 8224 | |
d30e4246 | 8225 | emit_move_insn (sa_reg, sa_reg_exp); |
bf2a98b3 | 8226 | } |
9e7454d0 | 8227 | |
65abff06 | 8228 | /* Restore registers in order, excepting a true frame pointer. */ |
bf2a98b3 | 8229 | |
29c05e22 | 8230 | mem = gen_frame_mem (DImode, plus_constant (Pmode, sa_reg, reg_offset)); |
d30e4246 | 8231 | reg = gen_rtx_REG (DImode, REG_RA); |
8232 | emit_move_insn (reg, mem); | |
8233 | cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores); | |
c92c328f | 8234 | |
b9a5aa8e | 8235 | reg_offset += 8; |
df7d0d23 | 8236 | imask &= ~(1UL << REG_RA); |
16b3392b | 8237 | |
c49ad9ef | 8238 | for (i = 0; i < 31; ++i) |
df7d0d23 | 8239 | if (imask & (1UL << i)) |
bf2a98b3 | 8240 | { |
b9a5aa8e | 8241 | if (i == HARD_FRAME_POINTER_REGNUM && fp_is_frame_pointer) |
16b3392b | 8242 | fp_offset = reg_offset; |
8243 | else | |
b9a5aa8e | 8244 | { |
656e2b9d | 8245 | mem = gen_frame_mem (DImode, |
29c05e22 | 8246 | plus_constant (Pmode, sa_reg, |
8247 | reg_offset)); | |
d30e4246 | 8248 | reg = gen_rtx_REG (DImode, i); |
8249 | emit_move_insn (reg, mem); | |
8250 | cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, | |
8251 | cfa_restores); | |
b9a5aa8e | 8252 | } |
bf2a98b3 | 8253 | reg_offset += 8; |
8254 | } | |
8255 | ||
c49ad9ef | 8256 | for (i = 0; i < 31; ++i) |
df7d0d23 | 8257 | if (fmask & (1UL << i)) |
bf2a98b3 | 8258 | { |
29c05e22 | 8259 | mem = gen_frame_mem (DFmode, plus_constant (Pmode, sa_reg, |
8260 | reg_offset)); | |
d30e4246 | 8261 | reg = gen_rtx_REG (DFmode, i+32); |
8262 | emit_move_insn (reg, mem); | |
8263 | cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores); | |
bf2a98b3 | 8264 | reg_offset += 8; |
8265 | } | |
b9a5aa8e | 8266 | } |
bf2a98b3 | 8267 | |
11016d99 | 8268 | if (frame_size || eh_ofs) |
b9a5aa8e | 8269 | { |
ec37ccb4 | 8270 | sp_adj1 = stack_pointer_rtx; |
8271 | ||
11016d99 | 8272 | if (eh_ofs) |
ec37ccb4 | 8273 | { |
8274 | sp_adj1 = gen_rtx_REG (DImode, 23); | |
8275 | emit_move_insn (sp_adj1, | |
11016d99 | 8276 | gen_rtx_PLUS (Pmode, stack_pointer_rtx, eh_ofs)); |
ec37ccb4 | 8277 | } |
8278 | ||
b9a5aa8e | 8279 | /* If the stack size is large, begin computation into a temporary |
8280 | register so as not to interfere with a potential fp restore, | |
8281 | which must be consecutive with an SP restore. */ | |
04d75965 | 8282 | if (frame_size < 32768 && !cfun->calls_alloca) |
ec37ccb4 | 8283 | sp_adj2 = GEN_INT (frame_size); |
b9a5aa8e | 8284 | else if (frame_size < 0x40007fffL) |
8285 | { | |
8286 | int low = ((frame_size & 0xffff) ^ 0x8000) - 0x8000; | |
8287 | ||
29c05e22 | 8288 | sp_adj2 = plus_constant (Pmode, sp_adj1, frame_size - low); |
b9a5aa8e | 8289 | if (sa_reg_exp && rtx_equal_p (sa_reg_exp, sp_adj2)) |
8290 | sp_adj1 = sa_reg; | |
8291 | else | |
8292 | { | |
8293 | sp_adj1 = gen_rtx_REG (DImode, 23); | |
d30e4246 | 8294 | emit_move_insn (sp_adj1, sp_adj2); |
b9a5aa8e | 8295 | } |
8296 | sp_adj2 = GEN_INT (low); | |
8297 | } | |
0e0a0e7a | 8298 | else |
b9a5aa8e | 8299 | { |
ec37ccb4 | 8300 | rtx tmp = gen_rtx_REG (DImode, 23); |
d30e4246 | 8301 | sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, 3, false); |
ec37ccb4 | 8302 | if (!sp_adj2) |
b9a5aa8e | 8303 | { |
8304 | /* We can't drop new things to memory this late, afaik, | |
8305 | so build it up by pieces. */ | |
debb7e7a | 8306 | sp_adj2 = alpha_emit_set_long_const (tmp, frame_size); |
4d10b463 | 8307 | gcc_assert (sp_adj2); |
b9a5aa8e | 8308 | } |
b9a5aa8e | 8309 | } |
bf2a98b3 | 8310 | |
b9a5aa8e | 8311 | /* From now on, things must be in order. So emit blockages. */ |
8312 | ||
8313 | /* Restore the frame pointer. */ | |
04d75965 | 8314 | if (fp_is_frame_pointer) |
b9a5aa8e | 8315 | { |
8316 | emit_insn (gen_blockage ()); | |
29c05e22 | 8317 | mem = gen_frame_mem (DImode, plus_constant (Pmode, sa_reg, |
8318 | fp_offset)); | |
d30e4246 | 8319 | emit_move_insn (hard_frame_pointer_rtx, mem); |
8320 | cfa_restores = alloc_reg_note (REG_CFA_RESTORE, | |
8321 | hard_frame_pointer_rtx, cfa_restores); | |
b9a5aa8e | 8322 | } |
1467e953 | 8323 | else if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 8324 | { |
8325 | emit_insn (gen_blockage ()); | |
d30e4246 | 8326 | emit_move_insn (hard_frame_pointer_rtx, |
8327 | gen_rtx_REG (DImode, vms_save_fp_regno)); | |
8328 | cfa_restores = alloc_reg_note (REG_CFA_RESTORE, | |
8329 | hard_frame_pointer_rtx, cfa_restores); | |
b9a5aa8e | 8330 | } |
8331 | ||
8332 | /* Restore the stack pointer. */ | |
8333 | emit_insn (gen_blockage ()); | |
9caef960 | 8334 | if (sp_adj2 == const0_rtx) |
d30e4246 | 8335 | insn = emit_move_insn (stack_pointer_rtx, sp_adj1); |
9caef960 | 8336 | else |
d30e4246 | 8337 | insn = emit_move_insn (stack_pointer_rtx, |
8338 | gen_rtx_PLUS (DImode, sp_adj1, sp_adj2)); | |
8339 | REG_NOTES (insn) = cfa_restores; | |
8340 | add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx); | |
8341 | RTX_FRAME_RELATED_P (insn) = 1; | |
b9a5aa8e | 8342 | } |
9e7454d0 | 8343 | else |
b9a5aa8e | 8344 | { |
d30e4246 | 8345 | gcc_assert (cfa_restores == NULL); |
8346 | ||
b19d7ab1 | 8347 | if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_REGISTER) |
b9a5aa8e | 8348 | { |
8349 | emit_insn (gen_blockage ()); | |
d30e4246 | 8350 | insn = emit_move_insn (hard_frame_pointer_rtx, |
8351 | gen_rtx_REG (DImode, vms_save_fp_regno)); | |
8352 | add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx); | |
8353 | RTX_FRAME_RELATED_P (insn) = 1; | |
b9a5aa8e | 8354 | } |
bf2a98b3 | 8355 | } |
b9a5aa8e | 8356 | } |
cf73d31f | 8357 | \f |
b9a5aa8e | 8358 | /* Output the rest of the textual info surrounding the epilogue. */ |
8359 | ||
8360 | void | |
92643d95 | 8361 | alpha_end_function (FILE *file, const char *fnname, tree decl ATTRIBUTE_UNUSED) |
b9a5aa8e | 8362 | { |
7f0256ea | 8363 | rtx_insn *insn; |
32a8f747 | 8364 | |
8365 | /* We output a nop after noreturn calls at the very end of the function to | |
8366 | ensure that the return address always remains in the caller's code range, | |
8367 | as not doing so might confuse unwinding engines. */ | |
8368 | insn = get_last_insn (); | |
8369 | if (!INSN_P (insn)) | |
8370 | insn = prev_active_insn (insn); | |
937fc2f7 | 8371 | if (insn && CALL_P (insn)) |
32a8f747 | 8372 | output_asm_insn (get_insn_template (CODE_FOR_nop, NULL), NULL); |
8373 | ||
04b0d94a | 8374 | #if TARGET_ABI_OPEN_VMS |
5ce94904 | 8375 | /* Write the linkage entries. */ |
8376 | alpha_write_linkage (file, fnname); | |
04b0d94a | 8377 | #endif |
8378 | ||
bf2a98b3 | 8379 | /* End the function. */ |
38021748 | 8380 | if (TARGET_ABI_OPEN_VMS |
8381 | || !flag_inhibit_size_directive) | |
f1fe649e | 8382 | { |
b9a5aa8e | 8383 | fputs ("\t.end ", file); |
2cf1388a | 8384 | assemble_name (file, fnname); |
b9a5aa8e | 8385 | putc ('\n', file); |
f1fe649e | 8386 | } |
449b7f2d | 8387 | inside_function = FALSE; |
bf2a98b3 | 8388 | } |
961d6ddd | 8389 | |
6988553d | 8390 | #if TARGET_ABI_OSF |
8391 | /* Emit a tail call to FUNCTION after adjusting THIS by DELTA. | |
961d6ddd | 8392 | |
8393 | In order to avoid the hordes of differences between generated code | |
8394 | with and without TARGET_EXPLICIT_RELOCS, and to avoid duplicating | |
8395 | lots of code loading up large constants, generate rtl and emit it | |
8396 | instead of going straight to text. | |
8397 | ||
8398 | Not sure why this idea hasn't been explored before... */ | |
8399 | ||
6988553d | 8400 | static void |
92643d95 | 8401 | alpha_output_mi_thunk_osf (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, |
8402 | HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, | |
8403 | tree function) | |
961d6ddd | 8404 | { |
8405 | HOST_WIDE_INT hi, lo; | |
7f0256ea | 8406 | rtx this_rtx, funexp; |
8407 | rtx_insn *insn; | |
961d6ddd | 8408 | |
8409 | /* We always require a valid GP. */ | |
8410 | emit_insn (gen_prologue_ldgp ()); | |
31b97e8f | 8411 | emit_note (NOTE_INSN_PROLOGUE_END); |
961d6ddd | 8412 | |
8413 | /* Find the "this" pointer. If the function returns a structure, | |
8414 | the structure return pointer is in $16. */ | |
45550790 | 8415 | if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) |
8deb3959 | 8416 | this_rtx = gen_rtx_REG (Pmode, 17); |
961d6ddd | 8417 | else |
8deb3959 | 8418 | this_rtx = gen_rtx_REG (Pmode, 16); |
961d6ddd | 8419 | |
8420 | /* Add DELTA. When possible we use ldah+lda. Otherwise load the | |
8421 | entire constant for the add. */ | |
8422 | lo = ((delta & 0xffff) ^ 0x8000) - 0x8000; | |
8423 | hi = (((delta - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
8424 | if (hi + lo == delta) | |
8425 | { | |
8426 | if (hi) | |
8deb3959 | 8427 | emit_insn (gen_adddi3 (this_rtx, this_rtx, GEN_INT (hi))); |
961d6ddd | 8428 | if (lo) |
8deb3959 | 8429 | emit_insn (gen_adddi3 (this_rtx, this_rtx, GEN_INT (lo))); |
961d6ddd | 8430 | } |
8431 | else | |
8432 | { | |
debb7e7a | 8433 | rtx tmp = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 0), delta); |
8deb3959 | 8434 | emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp)); |
961d6ddd | 8435 | } |
8436 | ||
a19ec9da | 8437 | /* Add a delta stored in the vtable at VCALL_OFFSET. */ |
8438 | if (vcall_offset) | |
8439 | { | |
8440 | rtx tmp, tmp2; | |
8441 | ||
8442 | tmp = gen_rtx_REG (Pmode, 0); | |
8deb3959 | 8443 | emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx)); |
a19ec9da | 8444 | |
8445 | lo = ((vcall_offset & 0xffff) ^ 0x8000) - 0x8000; | |
8446 | hi = (((vcall_offset - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
8447 | if (hi + lo == vcall_offset) | |
8448 | { | |
8449 | if (hi) | |
8450 | emit_insn (gen_adddi3 (tmp, tmp, GEN_INT (hi))); | |
8451 | } | |
8452 | else | |
8453 | { | |
8454 | tmp2 = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 1), | |
debb7e7a | 8455 | vcall_offset); |
a19ec9da | 8456 | emit_insn (gen_adddi3 (tmp, tmp, tmp2)); |
8457 | lo = 0; | |
8458 | } | |
8459 | if (lo) | |
8460 | tmp2 = gen_rtx_PLUS (Pmode, tmp, GEN_INT (lo)); | |
8461 | else | |
8462 | tmp2 = tmp; | |
8463 | emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp2)); | |
8464 | ||
8deb3959 | 8465 | emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp)); |
a19ec9da | 8466 | } |
8467 | ||
961d6ddd | 8468 | /* Generate a tail call to the target function. */ |
8469 | if (! TREE_USED (function)) | |
8470 | { | |
8471 | assemble_external (function); | |
8472 | TREE_USED (function) = 1; | |
8473 | } | |
8474 | funexp = XEXP (DECL_RTL (function), 0); | |
8475 | funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); | |
8476 | insn = emit_call_insn (gen_sibcall (funexp, const0_rtx)); | |
8477 | SIBLING_CALL_P (insn) = 1; | |
8478 | ||
8479 | /* Run just enough of rest_of_compilation to get the insns emitted. | |
8480 | There's not really enough bulk here to make other passes such as | |
8481 | instruction scheduling worth while. Note that use_thunk calls | |
8482 | assemble_start_function and assemble_end_function. */ | |
8483 | insn = get_insns (); | |
8484 | shorten_branches (insn); | |
8485 | final_start_function (insn, file, 1); | |
4bf029b0 | 8486 | final (insn, file, 1); |
961d6ddd | 8487 | final_end_function (); |
8488 | } | |
6988553d | 8489 | #endif /* TARGET_ABI_OSF */ |
449b7f2d | 8490 | \f |
8491 | /* Debugging support. */ | |
8492 | ||
8493 | #include "gstab.h" | |
8494 | ||
449b7f2d | 8495 | /* Name of the file containing the current function. */ |
8496 | ||
ace75b22 | 8497 | static const char *current_function_file = ""; |
449b7f2d | 8498 | |
8499 | /* Offsets to alpha virtual arg/local debugging pointers. */ | |
8500 | ||
8501 | long alpha_arg_offset; | |
8502 | long alpha_auto_offset; | |
8503 | \f | |
8504 | /* Emit a new filename to a stream. */ | |
8505 | ||
8506 | void | |
92643d95 | 8507 | alpha_output_filename (FILE *stream, const char *name) |
449b7f2d | 8508 | { |
8509 | static int first_time = TRUE; | |
449b7f2d | 8510 | |
8511 | if (first_time) | |
8512 | { | |
8513 | first_time = FALSE; | |
8514 | ++num_source_filenames; | |
8515 | current_function_file = name; | |
8516 | fprintf (stream, "\t.file\t%d ", num_source_filenames); | |
8517 | output_quoted_string (stream, name); | |
8518 | fprintf (stream, "\n"); | |
449b7f2d | 8519 | } |
8520 | ||
449b7f2d | 8521 | else if (name != current_function_file |
be3797c1 | 8522 | && strcmp (name, current_function_file) != 0) |
449b7f2d | 8523 | { |
48a5030b | 8524 | ++num_source_filenames; |
8525 | current_function_file = name; | |
8526 | fprintf (stream, "\t.file\t%d ", num_source_filenames); | |
449b7f2d | 8527 | |
8528 | output_quoted_string (stream, name); | |
8529 | fprintf (stream, "\n"); | |
8530 | } | |
8531 | } | |
c4622276 | 8532 | \f |
8533 | /* Structure to show the current status of registers and memory. */ | |
8534 | ||
8535 | struct shadow_summary | |
8536 | { | |
8537 | struct { | |
495c4a78 | 8538 | unsigned int i : 31; /* Mask of int regs */ |
8539 | unsigned int fp : 31; /* Mask of fp regs */ | |
8540 | unsigned int mem : 1; /* mem == imem | fpmem */ | |
c4622276 | 8541 | } used, defd; |
8542 | }; | |
8543 | ||
8544 | /* Summary the effects of expression X on the machine. Update SUM, a pointer | |
8545 | to the summary structure. SET is nonzero if the insn is setting the | |
8546 | object, otherwise zero. */ | |
8547 | ||
8548 | static void | |
92643d95 | 8549 | summarize_insn (rtx x, struct shadow_summary *sum, int set) |
c4622276 | 8550 | { |
d2ca078f | 8551 | const char *format_ptr; |
c4622276 | 8552 | int i, j; |
8553 | ||
8554 | if (x == 0) | |
8555 | return; | |
8556 | ||
8557 | switch (GET_CODE (x)) | |
8558 | { | |
8559 | /* ??? Note that this case would be incorrect if the Alpha had a | |
8560 | ZERO_EXTRACT in SET_DEST. */ | |
8561 | case SET: | |
8562 | summarize_insn (SET_SRC (x), sum, 0); | |
8563 | summarize_insn (SET_DEST (x), sum, 1); | |
8564 | break; | |
8565 | ||
8566 | case CLOBBER: | |
8567 | summarize_insn (XEXP (x, 0), sum, 1); | |
8568 | break; | |
8569 | ||
8570 | case USE: | |
8571 | summarize_insn (XEXP (x, 0), sum, 0); | |
8572 | break; | |
8573 | ||
a886cc41 | 8574 | case ASM_OPERANDS: |
8575 | for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--) | |
8576 | summarize_insn (ASM_OPERANDS_INPUT (x, i), sum, 0); | |
8577 | break; | |
8578 | ||
c4622276 | 8579 | case PARALLEL: |
3a5dbb5e | 8580 | for (i = XVECLEN (x, 0) - 1; i >= 0; i--) |
c4622276 | 8581 | summarize_insn (XVECEXP (x, 0, i), sum, 0); |
8582 | break; | |
8583 | ||
a886cc41 | 8584 | case SUBREG: |
b9a5aa8e | 8585 | summarize_insn (SUBREG_REG (x), sum, 0); |
8586 | break; | |
a886cc41 | 8587 | |
c4622276 | 8588 | case REG: |
8589 | { | |
8590 | int regno = REGNO (x); | |
f3d263a7 | 8591 | unsigned long mask = ((unsigned long) 1) << (regno % 32); |
c4622276 | 8592 | |
8593 | if (regno == 31 || regno == 63) | |
8594 | break; | |
8595 | ||
8596 | if (set) | |
8597 | { | |
8598 | if (regno < 32) | |
8599 | sum->defd.i |= mask; | |
8600 | else | |
8601 | sum->defd.fp |= mask; | |
8602 | } | |
8603 | else | |
8604 | { | |
8605 | if (regno < 32) | |
8606 | sum->used.i |= mask; | |
8607 | else | |
8608 | sum->used.fp |= mask; | |
8609 | } | |
8610 | } | |
8611 | break; | |
8612 | ||
8613 | case MEM: | |
8614 | if (set) | |
8615 | sum->defd.mem = 1; | |
8616 | else | |
8617 | sum->used.mem = 1; | |
8618 | ||
8619 | /* Find the regs used in memory address computation: */ | |
8620 | summarize_insn (XEXP (x, 0), sum, 0); | |
8621 | break; | |
8622 | ||
5c5c1f00 | 8623 | case CONST_INT: case CONST_WIDE_INT: case CONST_DOUBLE: |
8624 | case SYMBOL_REF: case LABEL_REF: case CONST: | |
5bdbf614 | 8625 | case SCRATCH: case ASM_INPUT: |
2d710b28 | 8626 | break; |
8627 | ||
c4622276 | 8628 | /* Handle common unary and binary ops for efficiency. */ |
8629 | case COMPARE: case PLUS: case MINUS: case MULT: case DIV: | |
8630 | case MOD: case UDIV: case UMOD: case AND: case IOR: | |
8631 | case XOR: case ASHIFT: case ROTATE: case ASHIFTRT: case LSHIFTRT: | |
8632 | case ROTATERT: case SMIN: case SMAX: case UMIN: case UMAX: | |
8633 | case NE: case EQ: case GE: case GT: case LE: | |
8634 | case LT: case GEU: case GTU: case LEU: case LTU: | |
8635 | summarize_insn (XEXP (x, 0), sum, 0); | |
8636 | summarize_insn (XEXP (x, 1), sum, 0); | |
8637 | break; | |
8638 | ||
8639 | case NEG: case NOT: case SIGN_EXTEND: case ZERO_EXTEND: | |
8640 | case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: case FLOAT: | |
8641 | case FIX: case UNSIGNED_FLOAT: case UNSIGNED_FIX: case ABS: | |
9e7454d0 | 8642 | case SQRT: case FFS: |
c4622276 | 8643 | summarize_insn (XEXP (x, 0), sum, 0); |
8644 | break; | |
8645 | ||
8646 | default: | |
8647 | format_ptr = GET_RTX_FORMAT (GET_CODE (x)); | |
3a5dbb5e | 8648 | for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) |
cada32d3 | 8649 | switch (format_ptr[i]) |
c4622276 | 8650 | { |
8651 | case 'e': | |
8652 | summarize_insn (XEXP (x, i), sum, 0); | |
8653 | break; | |
8654 | ||
8655 | case 'E': | |
3a5dbb5e | 8656 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) |
c4622276 | 8657 | summarize_insn (XVECEXP (x, i, j), sum, 0); |
8658 | break; | |
8659 | ||
1dc5f36f | 8660 | case 'i': |
8661 | break; | |
8662 | ||
c4622276 | 8663 | default: |
4d10b463 | 8664 | gcc_unreachable (); |
c4622276 | 8665 | } |
8666 | } | |
8667 | } | |
c4622276 | 8668 | |
b9a5aa8e | 8669 | /* Ensure a sufficient number of `trapb' insns are in the code when |
8670 | the user requests code with a trap precision of functions or | |
8671 | instructions. | |
8672 | ||
8673 | In naive mode, when the user requests a trap-precision of | |
8674 | "instruction", a trapb is needed after every instruction that may | |
8675 | generate a trap. This ensures that the code is resumption safe but | |
8676 | it is also slow. | |
8677 | ||
8678 | When optimizations are turned on, we delay issuing a trapb as long | |
8679 | as possible. In this context, a trap shadow is the sequence of | |
8680 | instructions that starts with a (potentially) trap generating | |
8681 | instruction and extends to the next trapb or call_pal instruction | |
8682 | (but GCC never generates call_pal by itself). We can delay (and | |
8683 | therefore sometimes omit) a trapb subject to the following | |
8684 | conditions: | |
8685 | ||
8686 | (a) On entry to the trap shadow, if any Alpha register or memory | |
8687 | location contains a value that is used as an operand value by some | |
8688 | instruction in the trap shadow (live on entry), then no instruction | |
8689 | in the trap shadow may modify the register or memory location. | |
8690 | ||
8691 | (b) Within the trap shadow, the computation of the base register | |
8692 | for a memory load or store instruction may not involve using the | |
8693 | result of an instruction that might generate an UNPREDICTABLE | |
8694 | result. | |
8695 | ||
8696 | (c) Within the trap shadow, no register may be used more than once | |
8697 | as a destination register. (This is to make life easier for the | |
8698 | trap-handler.) | |
c4622276 | 8699 | |
18adf4f6 | 8700 | (d) The trap shadow may not include any branch instructions. */ |
c4622276 | 8701 | |
18adf4f6 | 8702 | static void |
92643d95 | 8703 | alpha_handle_trap_shadows (void) |
c4622276 | 8704 | { |
18adf4f6 | 8705 | struct shadow_summary shadow; |
8706 | int trap_pending, exception_nesting; | |
91a55c11 | 8707 | rtx_insn *i, *n; |
c4622276 | 8708 | |
18adf4f6 | 8709 | trap_pending = 0; |
8710 | exception_nesting = 0; | |
8711 | shadow.used.i = 0; | |
8712 | shadow.used.fp = 0; | |
8713 | shadow.used.mem = 0; | |
8714 | shadow.defd = shadow.used; | |
9e7454d0 | 8715 | |
2efea8c0 | 8716 | for (i = get_insns (); i ; i = NEXT_INSN (i)) |
18adf4f6 | 8717 | { |
c933fb42 | 8718 | if (NOTE_P (i)) |
18adf4f6 | 8719 | { |
ad4583d9 | 8720 | switch (NOTE_KIND (i)) |
18adf4f6 | 8721 | { |
8722 | case NOTE_INSN_EH_REGION_BEG: | |
8723 | exception_nesting++; | |
8724 | if (trap_pending) | |
8725 | goto close_shadow; | |
8726 | break; | |
8727 | ||
8728 | case NOTE_INSN_EH_REGION_END: | |
8729 | exception_nesting--; | |
8730 | if (trap_pending) | |
8731 | goto close_shadow; | |
8732 | break; | |
8733 | ||
8734 | case NOTE_INSN_EPILOGUE_BEG: | |
8735 | if (trap_pending && alpha_tp >= ALPHA_TP_FUNC) | |
8736 | goto close_shadow; | |
8737 | break; | |
8738 | } | |
8739 | } | |
8740 | else if (trap_pending) | |
8741 | { | |
8742 | if (alpha_tp == ALPHA_TP_FUNC) | |
8743 | { | |
c933fb42 | 8744 | if (JUMP_P (i) |
18adf4f6 | 8745 | && GET_CODE (PATTERN (i)) == RETURN) |
8746 | goto close_shadow; | |
8747 | } | |
8748 | else if (alpha_tp == ALPHA_TP_INSN) | |
8749 | { | |
8750 | if (optimize > 0) | |
8751 | { | |
8752 | struct shadow_summary sum; | |
8753 | ||
8754 | sum.used.i = 0; | |
8755 | sum.used.fp = 0; | |
8756 | sum.used.mem = 0; | |
a886cc41 | 8757 | sum.defd = sum.used; |
18adf4f6 | 8758 | |
8759 | switch (GET_CODE (i)) | |
8760 | { | |
8761 | case INSN: | |
4d10b463 | 8762 | /* Annoyingly, get_attr_trap will die on these. */ |
fad0a39b | 8763 | if (GET_CODE (PATTERN (i)) == USE |
8764 | || GET_CODE (PATTERN (i)) == CLOBBER) | |
18adf4f6 | 8765 | break; |
8766 | ||
8767 | summarize_insn (PATTERN (i), &sum, 0); | |
8768 | ||
8769 | if ((sum.defd.i & shadow.defd.i) | |
8770 | || (sum.defd.fp & shadow.defd.fp)) | |
8771 | { | |
8772 | /* (c) would be violated */ | |
8773 | goto close_shadow; | |
8774 | } | |
8775 | ||
8776 | /* Combine shadow with summary of current insn: */ | |
8777 | shadow.used.i |= sum.used.i; | |
8778 | shadow.used.fp |= sum.used.fp; | |
8779 | shadow.used.mem |= sum.used.mem; | |
8780 | shadow.defd.i |= sum.defd.i; | |
8781 | shadow.defd.fp |= sum.defd.fp; | |
8782 | shadow.defd.mem |= sum.defd.mem; | |
8783 | ||
8784 | if ((sum.defd.i & shadow.used.i) | |
8785 | || (sum.defd.fp & shadow.used.fp) | |
8786 | || (sum.defd.mem & shadow.used.mem)) | |
8787 | { | |
8788 | /* (a) would be violated (also takes care of (b)) */ | |
4d10b463 | 8789 | gcc_assert (get_attr_trap (i) != TRAP_YES |
8790 | || (!(sum.defd.i & sum.used.i) | |
8791 | && !(sum.defd.fp & sum.used.fp))); | |
18adf4f6 | 8792 | |
8793 | goto close_shadow; | |
8794 | } | |
8795 | break; | |
8796 | ||
acaaf650 | 8797 | case BARRIER: |
8798 | /* __builtin_unreachable can expand to no code at all, | |
8799 | leaving (barrier) RTXes in the instruction stream. */ | |
8800 | goto close_shadow_notrapb; | |
8801 | ||
18adf4f6 | 8802 | case JUMP_INSN: |
8803 | case CALL_INSN: | |
8804 | case CODE_LABEL: | |
8805 | goto close_shadow; | |
8806 | ||
8807 | default: | |
4d10b463 | 8808 | gcc_unreachable (); |
18adf4f6 | 8809 | } |
8810 | } | |
8811 | else | |
8812 | { | |
8813 | close_shadow: | |
b9b4428b | 8814 | n = emit_insn_before (gen_trapb (), i); |
8815 | PUT_MODE (n, TImode); | |
8816 | PUT_MODE (i, TImode); | |
acaaf650 | 8817 | close_shadow_notrapb: |
18adf4f6 | 8818 | trap_pending = 0; |
8819 | shadow.used.i = 0; | |
8820 | shadow.used.fp = 0; | |
8821 | shadow.used.mem = 0; | |
8822 | shadow.defd = shadow.used; | |
8823 | } | |
8824 | } | |
8825 | } | |
c4622276 | 8826 | |
609d4083 | 8827 | if ((exception_nesting > 0 || alpha_tp >= ALPHA_TP_FUNC) |
c933fb42 | 8828 | && NONJUMP_INSN_P (i) |
609d4083 | 8829 | && GET_CODE (PATTERN (i)) != USE |
8830 | && GET_CODE (PATTERN (i)) != CLOBBER | |
8831 | && get_attr_trap (i) == TRAP_YES) | |
8832 | { | |
8833 | if (optimize && !trap_pending) | |
8834 | summarize_insn (PATTERN (i), &shadow, 0); | |
8835 | trap_pending = 1; | |
8836 | } | |
c4622276 | 8837 | } |
8838 | } | |
b9b4428b | 8839 | \f |
b9b4428b | 8840 | /* Alpha can only issue instruction groups simultaneously if they are |
5910bb95 | 8841 | suitably aligned. This is very processor-specific. */ |
07770f18 | 8842 | /* There are a number of entries in alphaev4_insn_pipe and alphaev5_insn_pipe |
8843 | that are marked "fake". These instructions do not exist on that target, | |
8844 | but it is possible to see these insns with deranged combinations of | |
8845 | command-line options, such as "-mtune=ev4 -mmax". Instead of aborting, | |
8846 | choose a result at random. */ | |
b9b4428b | 8847 | |
849674a3 | 8848 | enum alphaev4_pipe { |
8849 | EV4_STOP = 0, | |
8850 | EV4_IB0 = 1, | |
8851 | EV4_IB1 = 2, | |
8852 | EV4_IBX = 4 | |
8853 | }; | |
8854 | ||
b9b4428b | 8855 | enum alphaev5_pipe { |
8856 | EV5_STOP = 0, | |
8857 | EV5_NONE = 1, | |
8858 | EV5_E01 = 2, | |
8859 | EV5_E0 = 4, | |
8860 | EV5_E1 = 8, | |
8861 | EV5_FAM = 16, | |
8862 | EV5_FA = 32, | |
8863 | EV5_FM = 64 | |
8864 | }; | |
8865 | ||
849674a3 | 8866 | static enum alphaev4_pipe |
7f0256ea | 8867 | alphaev4_insn_pipe (rtx_insn *insn) |
849674a3 | 8868 | { |
8869 | if (recog_memoized (insn) < 0) | |
8870 | return EV4_STOP; | |
8871 | if (get_attr_length (insn) != 4) | |
8872 | return EV4_STOP; | |
8873 | ||
8874 | switch (get_attr_type (insn)) | |
8875 | { | |
8876 | case TYPE_ILD: | |
f155876e | 8877 | case TYPE_LDSYM: |
849674a3 | 8878 | case TYPE_FLD: |
f155876e | 8879 | case TYPE_LD_L: |
849674a3 | 8880 | return EV4_IBX; |
8881 | ||
849674a3 | 8882 | case TYPE_IADD: |
8883 | case TYPE_ILOG: | |
8884 | case TYPE_ICMOV: | |
8885 | case TYPE_ICMP: | |
849674a3 | 8886 | case TYPE_FST: |
8887 | case TYPE_SHIFT: | |
8888 | case TYPE_IMUL: | |
8889 | case TYPE_FBR: | |
07770f18 | 8890 | case TYPE_MVI: /* fake */ |
849674a3 | 8891 | return EV4_IB0; |
8892 | ||
f155876e | 8893 | case TYPE_IST: |
849674a3 | 8894 | case TYPE_MISC: |
8895 | case TYPE_IBR: | |
8896 | case TYPE_JSR: | |
1050b77e | 8897 | case TYPE_CALLPAL: |
849674a3 | 8898 | case TYPE_FCPYS: |
8899 | case TYPE_FCMOV: | |
8900 | case TYPE_FADD: | |
8901 | case TYPE_FDIV: | |
8902 | case TYPE_FMUL: | |
f155876e | 8903 | case TYPE_ST_C: |
8904 | case TYPE_MB: | |
07770f18 | 8905 | case TYPE_FSQRT: /* fake */ |
8906 | case TYPE_FTOI: /* fake */ | |
8907 | case TYPE_ITOF: /* fake */ | |
849674a3 | 8908 | return EV4_IB1; |
8909 | ||
8910 | default: | |
4d10b463 | 8911 | gcc_unreachable (); |
849674a3 | 8912 | } |
8913 | } | |
8914 | ||
b9b4428b | 8915 | static enum alphaev5_pipe |
7f0256ea | 8916 | alphaev5_insn_pipe (rtx_insn *insn) |
b9b4428b | 8917 | { |
8918 | if (recog_memoized (insn) < 0) | |
8919 | return EV5_STOP; | |
8920 | if (get_attr_length (insn) != 4) | |
8921 | return EV5_STOP; | |
8922 | ||
8923 | switch (get_attr_type (insn)) | |
8924 | { | |
8925 | case TYPE_ILD: | |
8926 | case TYPE_FLD: | |
8927 | case TYPE_LDSYM: | |
8928 | case TYPE_IADD: | |
8929 | case TYPE_ILOG: | |
8930 | case TYPE_ICMOV: | |
8931 | case TYPE_ICMP: | |
8932 | return EV5_E01; | |
8933 | ||
8934 | case TYPE_IST: | |
8935 | case TYPE_FST: | |
8936 | case TYPE_SHIFT: | |
8937 | case TYPE_IMUL: | |
8938 | case TYPE_MISC: | |
8939 | case TYPE_MVI: | |
f155876e | 8940 | case TYPE_LD_L: |
8941 | case TYPE_ST_C: | |
8942 | case TYPE_MB: | |
07770f18 | 8943 | case TYPE_FTOI: /* fake */ |
8944 | case TYPE_ITOF: /* fake */ | |
b9b4428b | 8945 | return EV5_E0; |
8946 | ||
8947 | case TYPE_IBR: | |
8948 | case TYPE_JSR: | |
1050b77e | 8949 | case TYPE_CALLPAL: |
b9b4428b | 8950 | return EV5_E1; |
8951 | ||
8952 | case TYPE_FCPYS: | |
8953 | return EV5_FAM; | |
8954 | ||
8955 | case TYPE_FBR: | |
8956 | case TYPE_FCMOV: | |
8957 | case TYPE_FADD: | |
8958 | case TYPE_FDIV: | |
07770f18 | 8959 | case TYPE_FSQRT: /* fake */ |
b9b4428b | 8960 | return EV5_FA; |
8961 | ||
8962 | case TYPE_FMUL: | |
8963 | return EV5_FM; | |
ddca68f8 | 8964 | |
8965 | default: | |
4d10b463 | 8966 | gcc_unreachable (); |
b9b4428b | 8967 | } |
b9b4428b | 8968 | } |
8969 | ||
9e7454d0 | 8970 | /* IN_USE is a mask of the slots currently filled within the insn group. |
849674a3 | 8971 | The mask bits come from alphaev4_pipe above. If EV4_IBX is set, then |
9e7454d0 | 8972 | the insn in EV4_IB0 can be swapped by the hardware into EV4_IB1. |
849674a3 | 8973 | |
8974 | LEN is, of course, the length of the group in bytes. */ | |
8975 | ||
7f0256ea | 8976 | static rtx_insn * |
8977 | alphaev4_next_group (rtx_insn *insn, int *pin_use, int *plen) | |
849674a3 | 8978 | { |
8979 | int len, in_use; | |
8980 | ||
8981 | len = in_use = 0; | |
8982 | ||
9204e736 | 8983 | if (! INSN_P (insn) |
849674a3 | 8984 | || GET_CODE (PATTERN (insn)) == CLOBBER |
8985 | || GET_CODE (PATTERN (insn)) == USE) | |
8986 | goto next_and_done; | |
8987 | ||
8988 | while (1) | |
8989 | { | |
8990 | enum alphaev4_pipe pipe; | |
8991 | ||
8992 | pipe = alphaev4_insn_pipe (insn); | |
8993 | switch (pipe) | |
8994 | { | |
8995 | case EV4_STOP: | |
8996 | /* Force complex instructions to start new groups. */ | |
8997 | if (in_use) | |
8998 | goto done; | |
8999 | ||
20833d12 | 9000 | /* If this is a completely unrecognized insn, it's an asm. |
849674a3 | 9001 | We don't know how long it is, so record length as -1 to |
9002 | signal a needed realignment. */ | |
9003 | if (recog_memoized (insn) < 0) | |
9004 | len = -1; | |
9005 | else | |
9006 | len = get_attr_length (insn); | |
9007 | goto next_and_done; | |
9008 | ||
9009 | case EV4_IBX: | |
9010 | if (in_use & EV4_IB0) | |
9011 | { | |
9012 | if (in_use & EV4_IB1) | |
9013 | goto done; | |
9014 | in_use |= EV4_IB1; | |
9015 | } | |
9016 | else | |
9017 | in_use |= EV4_IB0 | EV4_IBX; | |
9018 | break; | |
9019 | ||
9020 | case EV4_IB0: | |
9021 | if (in_use & EV4_IB0) | |
9022 | { | |
9023 | if (!(in_use & EV4_IBX) || (in_use & EV4_IB1)) | |
9024 | goto done; | |
9025 | in_use |= EV4_IB1; | |
9026 | } | |
9027 | in_use |= EV4_IB0; | |
9028 | break; | |
9029 | ||
9030 | case EV4_IB1: | |
9031 | if (in_use & EV4_IB1) | |
9032 | goto done; | |
9033 | in_use |= EV4_IB1; | |
9034 | break; | |
9035 | ||
9036 | default: | |
4d10b463 | 9037 | gcc_unreachable (); |
849674a3 | 9038 | } |
9039 | len += 4; | |
9e7454d0 | 9040 | |
849674a3 | 9041 | /* Haifa doesn't do well scheduling branches. */ |
c933fb42 | 9042 | if (JUMP_P (insn)) |
849674a3 | 9043 | goto next_and_done; |
9044 | ||
9045 | next: | |
9046 | insn = next_nonnote_insn (insn); | |
9047 | ||
9204e736 | 9048 | if (!insn || ! INSN_P (insn)) |
849674a3 | 9049 | goto done; |
9050 | ||
9051 | /* Let Haifa tell us where it thinks insn group boundaries are. */ | |
9052 | if (GET_MODE (insn) == TImode) | |
9053 | goto done; | |
9054 | ||
9055 | if (GET_CODE (insn) == CLOBBER || GET_CODE (insn) == USE) | |
9056 | goto next; | |
9057 | } | |
9058 | ||
9059 | next_and_done: | |
9060 | insn = next_nonnote_insn (insn); | |
9061 | ||
9062 | done: | |
9063 | *plen = len; | |
9064 | *pin_use = in_use; | |
9065 | return insn; | |
9066 | } | |
9067 | ||
9e7454d0 | 9068 | /* IN_USE is a mask of the slots currently filled within the insn group. |
849674a3 | 9069 | The mask bits come from alphaev5_pipe above. If EV5_E01 is set, then |
9e7454d0 | 9070 | the insn in EV5_E0 can be swapped by the hardware into EV5_E1. |
b9b4428b | 9071 | |
9072 | LEN is, of course, the length of the group in bytes. */ | |
9073 | ||
7f0256ea | 9074 | static rtx_insn * |
9075 | alphaev5_next_group (rtx_insn *insn, int *pin_use, int *plen) | |
b9b4428b | 9076 | { |
9077 | int len, in_use; | |
9078 | ||
9079 | len = in_use = 0; | |
9080 | ||
9204e736 | 9081 | if (! INSN_P (insn) |
ddca68f8 | 9082 | || GET_CODE (PATTERN (insn)) == CLOBBER |
9083 | || GET_CODE (PATTERN (insn)) == USE) | |
9084 | goto next_and_done; | |
b9b4428b | 9085 | |
ddca68f8 | 9086 | while (1) |
b9b4428b | 9087 | { |
9088 | enum alphaev5_pipe pipe; | |
b9b4428b | 9089 | |
9090 | pipe = alphaev5_insn_pipe (insn); | |
9091 | switch (pipe) | |
9092 | { | |
9093 | case EV5_STOP: | |
9094 | /* Force complex instructions to start new groups. */ | |
9095 | if (in_use) | |
9096 | goto done; | |
9097 | ||
20833d12 | 9098 | /* If this is a completely unrecognized insn, it's an asm. |
b9b4428b | 9099 | We don't know how long it is, so record length as -1 to |
9100 | signal a needed realignment. */ | |
9101 | if (recog_memoized (insn) < 0) | |
9102 | len = -1; | |
9103 | else | |
9104 | len = get_attr_length (insn); | |
ddca68f8 | 9105 | goto next_and_done; |
b9b4428b | 9106 | |
4d10b463 | 9107 | /* ??? Most of the places below, we would like to assert never |
9108 | happen, as it would indicate an error either in Haifa, or | |
9109 | in the scheduling description. Unfortunately, Haifa never | |
9110 | schedules the last instruction of the BB, so we don't have | |
9111 | an accurate TI bit to go off. */ | |
b9b4428b | 9112 | case EV5_E01: |
9113 | if (in_use & EV5_E0) | |
9114 | { | |
9115 | if (in_use & EV5_E1) | |
9116 | goto done; | |
9117 | in_use |= EV5_E1; | |
9118 | } | |
9119 | else | |
9120 | in_use |= EV5_E0 | EV5_E01; | |
9121 | break; | |
9122 | ||
9123 | case EV5_E0: | |
9124 | if (in_use & EV5_E0) | |
9125 | { | |
849674a3 | 9126 | if (!(in_use & EV5_E01) || (in_use & EV5_E1)) |
b9b4428b | 9127 | goto done; |
9128 | in_use |= EV5_E1; | |
9129 | } | |
9130 | in_use |= EV5_E0; | |
9131 | break; | |
9132 | ||
9133 | case EV5_E1: | |
9134 | if (in_use & EV5_E1) | |
9135 | goto done; | |
9136 | in_use |= EV5_E1; | |
9137 | break; | |
9138 | ||
9139 | case EV5_FAM: | |
9140 | if (in_use & EV5_FA) | |
9141 | { | |
9142 | if (in_use & EV5_FM) | |
9143 | goto done; | |
9144 | in_use |= EV5_FM; | |
9145 | } | |
9146 | else | |
9147 | in_use |= EV5_FA | EV5_FAM; | |
9148 | break; | |
9149 | ||
9150 | case EV5_FA: | |
9151 | if (in_use & EV5_FA) | |
9152 | goto done; | |
9153 | in_use |= EV5_FA; | |
9154 | break; | |
9155 | ||
9156 | case EV5_FM: | |
9157 | if (in_use & EV5_FM) | |
9158 | goto done; | |
9159 | in_use |= EV5_FM; | |
9160 | break; | |
9161 | ||
9162 | case EV5_NONE: | |
9163 | break; | |
9164 | ||
9165 | default: | |
4d10b463 | 9166 | gcc_unreachable (); |
b9b4428b | 9167 | } |
9168 | len += 4; | |
9e7454d0 | 9169 | |
b9b4428b | 9170 | /* Haifa doesn't do well scheduling branches. */ |
9171 | /* ??? If this is predicted not-taken, slotting continues, except | |
9172 | that no more IBR, FBR, or JSR insns may be slotted. */ | |
c933fb42 | 9173 | if (JUMP_P (insn)) |
ddca68f8 | 9174 | goto next_and_done; |
b9b4428b | 9175 | |
ddca68f8 | 9176 | next: |
b9b4428b | 9177 | insn = next_nonnote_insn (insn); |
9178 | ||
9204e736 | 9179 | if (!insn || ! INSN_P (insn)) |
b9b4428b | 9180 | goto done; |
f9137da0 | 9181 | |
b9b4428b | 9182 | /* Let Haifa tell us where it thinks insn group boundaries are. */ |
9183 | if (GET_MODE (insn) == TImode) | |
9184 | goto done; | |
9185 | ||
ddca68f8 | 9186 | if (GET_CODE (insn) == CLOBBER || GET_CODE (insn) == USE) |
9187 | goto next; | |
b9b4428b | 9188 | } |
ddca68f8 | 9189 | |
9190 | next_and_done: | |
9191 | insn = next_nonnote_insn (insn); | |
b9b4428b | 9192 | |
9193 | done: | |
9194 | *plen = len; | |
9195 | *pin_use = in_use; | |
9196 | return insn; | |
b9b4428b | 9197 | } |
9198 | ||
849674a3 | 9199 | static rtx |
92643d95 | 9200 | alphaev4_next_nop (int *pin_use) |
849674a3 | 9201 | { |
9202 | int in_use = *pin_use; | |
9203 | rtx nop; | |
9204 | ||
9205 | if (!(in_use & EV4_IB0)) | |
9206 | { | |
9207 | in_use |= EV4_IB0; | |
9208 | nop = gen_nop (); | |
9209 | } | |
9210 | else if ((in_use & (EV4_IBX|EV4_IB1)) == EV4_IBX) | |
9211 | { | |
9212 | in_use |= EV4_IB1; | |
9213 | nop = gen_nop (); | |
9214 | } | |
9215 | else if (TARGET_FP && !(in_use & EV4_IB1)) | |
9216 | { | |
9217 | in_use |= EV4_IB1; | |
9218 | nop = gen_fnop (); | |
9219 | } | |
9220 | else | |
9221 | nop = gen_unop (); | |
9222 | ||
9223 | *pin_use = in_use; | |
9224 | return nop; | |
9225 | } | |
9226 | ||
9227 | static rtx | |
92643d95 | 9228 | alphaev5_next_nop (int *pin_use) |
849674a3 | 9229 | { |
9230 | int in_use = *pin_use; | |
9231 | rtx nop; | |
9232 | ||
9233 | if (!(in_use & EV5_E1)) | |
9234 | { | |
9235 | in_use |= EV5_E1; | |
9236 | nop = gen_nop (); | |
9237 | } | |
9238 | else if (TARGET_FP && !(in_use & EV5_FA)) | |
9239 | { | |
9240 | in_use |= EV5_FA; | |
9241 | nop = gen_fnop (); | |
9242 | } | |
9243 | else if (TARGET_FP && !(in_use & EV5_FM)) | |
9244 | { | |
9245 | in_use |= EV5_FM; | |
9246 | nop = gen_fnop (); | |
9247 | } | |
9248 | else | |
9249 | nop = gen_unop (); | |
9250 | ||
9251 | *pin_use = in_use; | |
9252 | return nop; | |
9253 | } | |
9254 | ||
9255 | /* The instruction group alignment main loop. */ | |
9256 | ||
b9b4428b | 9257 | static void |
b80c91bc | 9258 | alpha_align_insns_1 (unsigned int max_align, |
7f0256ea | 9259 | rtx_insn *(*next_group) (rtx_insn *, int *, int *), |
b80c91bc | 9260 | rtx (*next_nop) (int *)) |
b9b4428b | 9261 | { |
9262 | /* ALIGN is the known alignment for the insn group. */ | |
b53f315c | 9263 | unsigned int align; |
b9b4428b | 9264 | /* OFS is the offset of the current insn in the insn group. */ |
9265 | int ofs; | |
fd1ace94 | 9266 | int prev_in_use, in_use, len, ldgp; |
7f0256ea | 9267 | rtx_insn *i, *next; |
b9b4428b | 9268 | |
9269 | /* Let shorten branches care for assigning alignments to code labels. */ | |
2efea8c0 | 9270 | shorten_branches (get_insns ()); |
b9b4428b | 9271 | |
6fceef7a | 9272 | unsigned int option_alignment = align_functions.levels[0].get_value (); |
6848a0ae | 9273 | if (option_alignment < 4) |
d815ce59 | 9274 | align = 4; |
6848a0ae | 9275 | else if ((unsigned int) option_alignment < max_align) |
9276 | align = option_alignment; | |
d815ce59 | 9277 | else |
9278 | align = max_align; | |
e2c8a34a | 9279 | |
b9b4428b | 9280 | ofs = prev_in_use = 0; |
2efea8c0 | 9281 | i = get_insns (); |
c933fb42 | 9282 | if (NOTE_P (i)) |
b9b4428b | 9283 | i = next_nonnote_insn (i); |
9284 | ||
fd1ace94 | 9285 | ldgp = alpha_function_needs_gp ? 8 : 0; |
9286 | ||
b9b4428b | 9287 | while (i) |
9288 | { | |
b53f315c | 9289 | next = (*next_group) (i, &in_use, &len); |
b9b4428b | 9290 | |
9291 | /* When we see a label, resync alignment etc. */ | |
c933fb42 | 9292 | if (LABEL_P (i)) |
b9b4428b | 9293 | { |
6fceef7a | 9294 | unsigned int new_align |
9295 | = label_to_alignment (i).levels[0].get_value (); | |
b53f315c | 9296 | |
b9b4428b | 9297 | if (new_align >= align) |
9298 | { | |
849674a3 | 9299 | align = new_align < max_align ? new_align : max_align; |
b9b4428b | 9300 | ofs = 0; |
9301 | } | |
b53f315c | 9302 | |
b9b4428b | 9303 | else if (ofs & (new_align-1)) |
9304 | ofs = (ofs | (new_align-1)) + 1; | |
4d10b463 | 9305 | gcc_assert (!len); |
b9b4428b | 9306 | } |
9307 | ||
9308 | /* Handle complex instructions special. */ | |
9309 | else if (in_use == 0) | |
9310 | { | |
9311 | /* Asms will have length < 0. This is a signal that we have | |
9312 | lost alignment knowledge. Assume, however, that the asm | |
9313 | will not mis-align instructions. */ | |
9314 | if (len < 0) | |
9315 | { | |
9316 | ofs = 0; | |
9317 | align = 4; | |
9318 | len = 0; | |
9319 | } | |
9320 | } | |
9321 | ||
9322 | /* If the known alignment is smaller than the recognized insn group, | |
9323 | realign the output. */ | |
1f0ce6a6 | 9324 | else if ((int) align < len) |
b9b4428b | 9325 | { |
b53f315c | 9326 | unsigned int new_log_align = len > 8 ? 4 : 3; |
7f0256ea | 9327 | rtx_insn *prev, *where; |
b9b4428b | 9328 | |
943a1b57 | 9329 | where = prev = prev_nonnote_insn (i); |
c933fb42 | 9330 | if (!where || !LABEL_P (where)) |
b9b4428b | 9331 | where = i; |
9332 | ||
943a1b57 | 9333 | /* Can't realign between a call and its gp reload. */ |
9334 | if (! (TARGET_EXPLICIT_RELOCS | |
c933fb42 | 9335 | && prev && CALL_P (prev))) |
943a1b57 | 9336 | { |
9337 | emit_insn_before (gen_realign (GEN_INT (new_log_align)), where); | |
9338 | align = 1 << new_log_align; | |
9339 | ofs = 0; | |
9340 | } | |
b9b4428b | 9341 | } |
9342 | ||
fd1ace94 | 9343 | /* We may not insert padding inside the initial ldgp sequence. */ |
9344 | else if (ldgp > 0) | |
9345 | ldgp -= len; | |
9346 | ||
b9b4428b | 9347 | /* If the group won't fit in the same INT16 as the previous, |
9348 | we need to add padding to keep the group together. Rather | |
9349 | than simply leaving the insn filling to the assembler, we | |
9350 | can make use of the knowledge of what sorts of instructions | |
9351 | were issued in the previous group to make sure that all of | |
9352 | the added nops are really free. */ | |
1f0ce6a6 | 9353 | else if (ofs + len > (int) align) |
b9b4428b | 9354 | { |
9355 | int nop_count = (align - ofs) / 4; | |
7f0256ea | 9356 | rtx_insn *where; |
b9b4428b | 9357 | |
efee20da | 9358 | /* Insert nops before labels, branches, and calls to truly merge |
943a1b57 | 9359 | the execution of the nops with the previous instruction group. */ |
b9b4428b | 9360 | where = prev_nonnote_insn (i); |
849674a3 | 9361 | if (where) |
b9b4428b | 9362 | { |
c933fb42 | 9363 | if (LABEL_P (where)) |
b9b4428b | 9364 | { |
7f0256ea | 9365 | rtx_insn *where2 = prev_nonnote_insn (where); |
c933fb42 | 9366 | if (where2 && JUMP_P (where2)) |
849674a3 | 9367 | where = where2; |
b9b4428b | 9368 | } |
c933fb42 | 9369 | else if (NONJUMP_INSN_P (where)) |
849674a3 | 9370 | where = i; |
b9b4428b | 9371 | } |
849674a3 | 9372 | else |
9373 | where = i; | |
9374 | ||
9e7454d0 | 9375 | do |
849674a3 | 9376 | emit_insn_before ((*next_nop)(&prev_in_use), where); |
b9b4428b | 9377 | while (--nop_count); |
9378 | ofs = 0; | |
9379 | } | |
9380 | ||
9381 | ofs = (ofs + len) & (align - 1); | |
9382 | prev_in_use = in_use; | |
9383 | i = next; | |
9384 | } | |
9385 | } | |
a27deefc | 9386 | |
b80c91bc | 9387 | static void |
9388 | alpha_align_insns (void) | |
9389 | { | |
9390 | if (alpha_tune == PROCESSOR_EV4) | |
9391 | alpha_align_insns_1 (8, alphaev4_next_group, alphaev4_next_nop); | |
9392 | else if (alpha_tune == PROCESSOR_EV5) | |
9393 | alpha_align_insns_1 (16, alphaev5_next_group, alphaev5_next_nop); | |
9394 | else | |
9395 | gcc_unreachable (); | |
9396 | } | |
9397 | ||
0578f206 | 9398 | /* Insert an unop between sibcall or noreturn function call and GP load. */ |
a27deefc | 9399 | |
9400 | static void | |
0578f206 | 9401 | alpha_pad_function_end (void) |
a27deefc | 9402 | { |
7f0256ea | 9403 | rtx_insn *insn, *next; |
a27deefc | 9404 | |
9405 | for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) | |
9406 | { | |
60f629bc | 9407 | if (!CALL_P (insn) |
9408 | || !(SIBLING_CALL_P (insn) | |
9409 | || find_reg_note (insn, REG_NORETURN, NULL_RTX))) | |
a27deefc | 9410 | continue; |
9411 | ||
9412 | next = next_active_insn (insn); | |
a27deefc | 9413 | if (next) |
9414 | { | |
9415 | rtx pat = PATTERN (next); | |
9416 | ||
9417 | if (GET_CODE (pat) == SET | |
9418 | && GET_CODE (SET_SRC (pat)) == UNSPEC_VOLATILE | |
9419 | && XINT (SET_SRC (pat), 1) == UNSPECV_LDGP1) | |
9420 | emit_insn_after (gen_unop (), insn); | |
9421 | } | |
9422 | } | |
9423 | } | |
b9b4428b | 9424 | \f |
35a3065a | 9425 | /* Machine dependent reorg pass. */ |
18adf4f6 | 9426 | |
2efea8c0 | 9427 | static void |
92643d95 | 9428 | alpha_reorg (void) |
18adf4f6 | 9429 | { |
0578f206 | 9430 | /* Workaround for a linker error that triggers when an exception |
9431 | handler immediatelly follows a sibcall or a noreturn function. | |
9432 | ||
9433 | In the sibcall case: | |
9434 | ||
9435 | The instruction stream from an object file: | |
9436 | ||
9437 | 1d8: 00 00 fb 6b jmp (t12) | |
9438 | 1dc: 00 00 ba 27 ldah gp,0(ra) | |
9439 | 1e0: 00 00 bd 23 lda gp,0(gp) | |
9440 | 1e4: 00 00 7d a7 ldq t12,0(gp) | |
9441 | 1e8: 00 40 5b 6b jsr ra,(t12),1ec <__funcZ+0x1ec> | |
9442 | ||
9443 | was converted in the final link pass to: | |
9444 | ||
9445 | 12003aa88: 67 fa ff c3 br 120039428 <...> | |
9446 | 12003aa8c: 00 00 fe 2f unop | |
9447 | 12003aa90: 00 00 fe 2f unop | |
9448 | 12003aa94: 48 83 7d a7 ldq t12,-31928(gp) | |
9449 | 12003aa98: 00 40 5b 6b jsr ra,(t12),12003aa9c <__func+0x1ec> | |
9450 | ||
9451 | And in the noreturn case: | |
a27deefc | 9452 | |
9453 | The instruction stream from an object file: | |
9454 | ||
9455 | 54: 00 40 5b 6b jsr ra,(t12),58 <__func+0x58> | |
9456 | 58: 00 00 ba 27 ldah gp,0(ra) | |
9457 | 5c: 00 00 bd 23 lda gp,0(gp) | |
9458 | 60: 00 00 7d a7 ldq t12,0(gp) | |
9459 | 64: 00 40 5b 6b jsr ra,(t12),68 <__func+0x68> | |
9460 | ||
9461 | was converted in the final link pass to: | |
9462 | ||
9463 | fdb24: a0 03 40 d3 bsr ra,fe9a8 <_called_func+0x8> | |
9464 | fdb28: 00 00 fe 2f unop | |
9465 | fdb2c: 00 00 fe 2f unop | |
9466 | fdb30: 30 82 7d a7 ldq t12,-32208(gp) | |
9467 | fdb34: 00 40 5b 6b jsr ra,(t12),fdb38 <__func+0x68> | |
9468 | ||
9469 | GP load instructions were wrongly cleared by the linker relaxation | |
9470 | pass. This workaround prevents removal of GP loads by inserting | |
0578f206 | 9471 | an unop instruction between a sibcall or noreturn function call and |
a27deefc | 9472 | exception handler prologue. */ |
9473 | ||
9474 | if (current_function_has_exception_handlers ()) | |
0578f206 | 9475 | alpha_pad_function_end (); |
d60df0a8 | 9476 | |
9477 | /* CALL_PAL that implements trap insn, updates program counter to point | |
9478 | after the insn. In case trap is the last insn in the function, | |
9479 | emit NOP to guarantee that PC remains inside function boundaries. | |
9480 | This workaround is needed to get reliable backtraces. */ | |
9481 | ||
9482 | rtx_insn *insn = prev_active_insn (get_last_insn ()); | |
9483 | ||
9484 | if (insn && NONJUMP_INSN_P (insn)) | |
9485 | { | |
9486 | rtx pat = PATTERN (insn); | |
9487 | if (GET_CODE (pat) == PARALLEL) | |
9488 | { | |
9489 | rtx vec = XVECEXP (pat, 0, 0); | |
9490 | if (GET_CODE (vec) == TRAP_IF | |
9491 | && XEXP (vec, 0) == const1_rtx) | |
9492 | emit_insn_after (gen_unop (), insn); | |
9493 | } | |
9494 | } | |
18adf4f6 | 9495 | } |
18adf4f6 | 9496 | \f |
92c473b8 | 9497 | static void |
9498 | alpha_file_start (void) | |
9499 | { | |
9500 | default_file_start (); | |
92c473b8 | 9501 | |
9502 | fputs ("\t.set noreorder\n", asm_out_file); | |
9503 | fputs ("\t.set volatile\n", asm_out_file); | |
4505d022 | 9504 | if (TARGET_ABI_OSF) |
92c473b8 | 9505 | fputs ("\t.set noat\n", asm_out_file); |
9506 | if (TARGET_EXPLICIT_RELOCS) | |
9507 | fputs ("\t.set nomacro\n", asm_out_file); | |
9508 | if (TARGET_SUPPORT_ARCH | TARGET_BWX | TARGET_MAX | TARGET_FIX | TARGET_CIX) | |
fb64edde | 9509 | { |
9510 | const char *arch; | |
9511 | ||
9512 | if (alpha_cpu == PROCESSOR_EV6 || TARGET_FIX || TARGET_CIX) | |
9513 | arch = "ev6"; | |
9514 | else if (TARGET_MAX) | |
9515 | arch = "pca56"; | |
9516 | else if (TARGET_BWX) | |
9517 | arch = "ev56"; | |
9518 | else if (alpha_cpu == PROCESSOR_EV5) | |
9519 | arch = "ev5"; | |
9520 | else | |
9521 | arch = "ev4"; | |
9522 | ||
9523 | fprintf (asm_out_file, "\t.arch %s\n", arch); | |
9524 | } | |
92c473b8 | 9525 | } |
92c473b8 | 9526 | |
4e151b05 | 9527 | /* Since we don't have a .dynbss section, we should not allow global |
9528 | relocations in the .rodata section. */ | |
9529 | ||
9530 | static int | |
9531 | alpha_elf_reloc_rw_mask (void) | |
9532 | { | |
9533 | return flag_pic ? 3 : 2; | |
9534 | } | |
bbfbe351 | 9535 | |
2f14b1f9 | 9536 | /* Return a section for X. The only special thing we do here is to |
9537 | honor small data. */ | |
bbfbe351 | 9538 | |
2f14b1f9 | 9539 | static section * |
3754d046 | 9540 | alpha_elf_select_rtx_section (machine_mode mode, rtx x, |
92643d95 | 9541 | unsigned HOST_WIDE_INT align) |
bbfbe351 | 9542 | { |
9543 | if (TARGET_SMALL_DATA && GET_MODE_SIZE (mode) <= g_switch_value) | |
5910bb95 | 9544 | /* ??? Consider using mergeable sdata sections. */ |
2f14b1f9 | 9545 | return sdata_section; |
bbfbe351 | 9546 | else |
2f14b1f9 | 9547 | return default_elf_select_rtx_section (mode, x, align); |
bbfbe351 | 9548 | } |
9549 | ||
cc2af183 | 9550 | static unsigned int |
9551 | alpha_elf_section_type_flags (tree decl, const char *name, int reloc) | |
9552 | { | |
9553 | unsigned int flags = 0; | |
9554 | ||
9555 | if (strcmp (name, ".sdata") == 0 | |
9556 | || strncmp (name, ".sdata.", 7) == 0 | |
9557 | || strncmp (name, ".gnu.linkonce.s.", 16) == 0 | |
9558 | || strcmp (name, ".sbss") == 0 | |
9559 | || strncmp (name, ".sbss.", 6) == 0 | |
9560 | || strncmp (name, ".gnu.linkonce.sb.", 17) == 0) | |
9561 | flags = SECTION_SMALL; | |
9562 | ||
9563 | flags |= default_section_type_flags (decl, name, reloc); | |
9564 | return flags; | |
9565 | } | |
bbfbe351 | 9566 | \f |
9de382d9 | 9567 | /* Structure to collect function names for final output in link section. */ |
9568 | /* Note that items marked with GTY can't be ifdef'ed out. */ | |
573aba85 | 9569 | |
5ce94904 | 9570 | enum reloc_kind |
9571 | { | |
9572 | KIND_LINKAGE, | |
9573 | KIND_CODEADDR | |
9574 | }; | |
573aba85 | 9575 | |
fb1e4f4a | 9576 | struct GTY(()) alpha_links |
573aba85 | 9577 | { |
5ce94904 | 9578 | rtx func; |
573aba85 | 9579 | rtx linkage; |
9de382d9 | 9580 | enum reloc_kind rkind; |
9581 | }; | |
9582 | ||
1467e953 | 9583 | #if TARGET_ABI_OPEN_VMS |
8df4a58b | 9584 | |
0dbd1c74 | 9585 | /* Return the VMS argument type corresponding to MODE. */ |
8df4a58b | 9586 | |
0dbd1c74 | 9587 | enum avms_arg_type |
3754d046 | 9588 | alpha_arg_type (machine_mode mode) |
0dbd1c74 | 9589 | { |
9590 | switch (mode) | |
8df4a58b | 9591 | { |
916ace94 | 9592 | case E_SFmode: |
0dbd1c74 | 9593 | return TARGET_FLOAT_VAX ? FF : FS; |
916ace94 | 9594 | case E_DFmode: |
0dbd1c74 | 9595 | return TARGET_FLOAT_VAX ? FD : FT; |
9596 | default: | |
9597 | return I64; | |
8df4a58b | 9598 | } |
0dbd1c74 | 9599 | } |
8df4a58b | 9600 | |
0dbd1c74 | 9601 | /* Return an rtx for an integer representing the VMS Argument Information |
9602 | register value. */ | |
8df4a58b | 9603 | |
1dd6c958 | 9604 | rtx |
92643d95 | 9605 | alpha_arg_info_reg_val (CUMULATIVE_ARGS cum) |
0dbd1c74 | 9606 | { |
9607 | unsigned HOST_WIDE_INT regval = cum.num_args; | |
9608 | int i; | |
8df4a58b | 9609 | |
0dbd1c74 | 9610 | for (i = 0; i < 6; i++) |
9611 | regval |= ((int) cum.atypes[i]) << (i * 3 + 8); | |
8df4a58b | 9612 | |
0dbd1c74 | 9613 | return GEN_INT (regval); |
9614 | } | |
9615 | \f | |
8df4a58b | 9616 | |
c45d3ddf | 9617 | /* Return a SYMBOL_REF representing the reference to the .linkage entry |
9618 | of function FUNC built for calls made from CFUNDECL. LFLAG is 1 if | |
9619 | this is the reference to the linkage pointer value, 0 if this is the | |
9620 | reference to the function entry value. RFLAG is 1 if this a reduced | |
9621 | reference (code address only), 0 if this is a full reference. */ | |
9622 | ||
cf73d31f | 9623 | rtx |
5ce94904 | 9624 | alpha_use_linkage (rtx func, bool lflag, bool rflag) |
cf73d31f | 9625 | { |
5ce94904 | 9626 | struct alpha_links *al = NULL; |
c45d3ddf | 9627 | const char *name = XSTR (func, 0); |
cf73d31f | 9628 | |
5ce94904 | 9629 | if (cfun->machine->links) |
cf73d31f | 9630 | { |
cf73d31f | 9631 | /* Is this name already defined? */ |
1ddffe86 | 9632 | alpha_links **slot = cfun->machine->links->get (name); |
d4786b13 | 9633 | if (slot) |
9634 | al = *slot; | |
cf73d31f | 9635 | } |
9636 | else | |
d4786b13 | 9637 | cfun->machine->links |
ee34b0e4 | 9638 | = hash_map<nofree_string_hash, alpha_links *>::create_ggc (64); |
cf73d31f | 9639 | |
5ce94904 | 9640 | if (al == NULL) |
cf73d31f | 9641 | { |
5ce94904 | 9642 | size_t buf_len; |
cf73d31f | 9643 | char *linksym; |
47544e52 | 9644 | tree id; |
cf73d31f | 9645 | |
9646 | if (name[0] == '*') | |
9647 | name++; | |
9648 | ||
47544e52 | 9649 | /* Follow transparent alias, as this is used for CRTL translations. */ |
9650 | id = maybe_get_identifier (name); | |
9651 | if (id) | |
9652 | { | |
9653 | while (IDENTIFIER_TRANSPARENT_ALIAS (id)) | |
9654 | id = TREE_CHAIN (id); | |
9655 | name = IDENTIFIER_POINTER (id); | |
9656 | } | |
9657 | ||
5ce94904 | 9658 | buf_len = strlen (name) + 8 + 9; |
9659 | linksym = (char *) alloca (buf_len); | |
9660 | snprintf (linksym, buf_len, "$%d..%s..lk", cfun->funcdef_no, name); | |
cf73d31f | 9661 | |
25a27413 | 9662 | al = ggc_alloc<alpha_links> (); |
5ce94904 | 9663 | al->func = func; |
9664 | al->linkage = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (linksym)); | |
cf73d31f | 9665 | |
d4786b13 | 9666 | cfun->machine->links->put (ggc_strdup (name), al); |
cf73d31f | 9667 | } |
9668 | ||
5ce94904 | 9669 | al->rkind = rflag ? KIND_CODEADDR : KIND_LINKAGE; |
9e7454d0 | 9670 | |
cf73d31f | 9671 | if (lflag) |
29c05e22 | 9672 | return gen_rtx_MEM (Pmode, plus_constant (Pmode, al->linkage, 8)); |
cf73d31f | 9673 | else |
9674 | return al->linkage; | |
9675 | } | |
9676 | ||
57e47080 | 9677 | static int |
1ddffe86 | 9678 | alpha_write_one_linkage (const char *name, alpha_links *link, FILE *stream) |
57e47080 | 9679 | { |
5ce94904 | 9680 | ASM_OUTPUT_INTERNAL_LABEL (stream, XSTR (link->linkage, 0)); |
cf73d31f | 9681 | if (link->rkind == KIND_CODEADDR) |
57e47080 | 9682 | { |
5ce94904 | 9683 | /* External and used, request code address. */ |
47544e52 | 9684 | fprintf (stream, "\t.code_address "); |
57e47080 | 9685 | } |
9686 | else | |
9687 | { | |
5ce94904 | 9688 | if (!SYMBOL_REF_EXTERNAL_P (link->func) |
9689 | && SYMBOL_REF_LOCAL_P (link->func)) | |
cf73d31f | 9690 | { |
5ce94904 | 9691 | /* Locally defined, build linkage pair. */ |
cf73d31f | 9692 | fprintf (stream, "\t.quad %s..en\n", name); |
47544e52 | 9693 | fprintf (stream, "\t.quad "); |
cf73d31f | 9694 | } |
9695 | else | |
9696 | { | |
5ce94904 | 9697 | /* External, request linkage pair. */ |
47544e52 | 9698 | fprintf (stream, "\t.linkage "); |
cf73d31f | 9699 | } |
57e47080 | 9700 | } |
47544e52 | 9701 | assemble_name (stream, name); |
9702 | fputs ("\n", stream); | |
57e47080 | 9703 | |
9704 | return 0; | |
9705 | } | |
8df4a58b | 9706 | |
cf73d31f | 9707 | static void |
5ce94904 | 9708 | alpha_write_linkage (FILE *stream, const char *funname) |
8df4a58b | 9709 | { |
2f14b1f9 | 9710 | fprintf (stream, "\t.link\n"); |
cf73d31f | 9711 | fprintf (stream, "\t.align 3\n"); |
2f14b1f9 | 9712 | in_section = NULL; |
9713 | ||
5ce94904 | 9714 | #ifdef TARGET_VMS_CRASH_DEBUG |
cf73d31f | 9715 | fputs ("\t.name ", stream); |
9716 | assemble_name (stream, funname); | |
9717 | fputs ("..na\n", stream); | |
5ce94904 | 9718 | #endif |
9719 | ||
cf73d31f | 9720 | ASM_OUTPUT_LABEL (stream, funname); |
9721 | fprintf (stream, "\t.pdesc "); | |
9722 | assemble_name (stream, funname); | |
9723 | fprintf (stream, "..en,%s\n", | |
9724 | alpha_procedure_type == PT_STACK ? "stack" | |
9725 | : alpha_procedure_type == PT_REGISTER ? "reg" : "null"); | |
9726 | ||
5ce94904 | 9727 | if (cfun->machine->links) |
c64a8830 | 9728 | { |
ee34b0e4 | 9729 | hash_map<nofree_string_hash, alpha_links *>::iterator iter |
d4786b13 | 9730 | = cfun->machine->links->begin (); |
9731 | for (; iter != cfun->machine->links->end (); ++iter) | |
9732 | alpha_write_one_linkage ((*iter).first, (*iter).second, stream); | |
c64a8830 | 9733 | } |
8df4a58b | 9734 | } |
9735 | ||
2cb4ac60 | 9736 | /* Switch to an arbitrary section NAME with attributes as specified |
9737 | by FLAGS. ALIGN specifies any known alignment requirements for | |
9738 | the section; 0 if the default should be used. */ | |
9739 | ||
9740 | static void | |
537cd941 | 9741 | vms_asm_named_section (const char *name, unsigned int flags, |
9742 | tree decl ATTRIBUTE_UNUSED) | |
2cb4ac60 | 9743 | { |
c64a8830 | 9744 | fputc ('\n', asm_out_file); |
9745 | fprintf (asm_out_file, ".section\t%s", name); | |
2cb4ac60 | 9746 | |
c64a8830 | 9747 | if (flags & SECTION_DEBUG) |
9748 | fprintf (asm_out_file, ",NOWRT"); | |
9749 | ||
9750 | fputc ('\n', asm_out_file); | |
2cb4ac60 | 9751 | } |
9752 | ||
01d15dc5 | 9753 | /* Record an element in the table of global constructors. SYMBOL is |
9754 | a SYMBOL_REF of the function to be called; PRIORITY is a number | |
9e7454d0 | 9755 | between 0 and MAX_INIT_PRIORITY. |
01d15dc5 | 9756 | |
9757 | Differs from default_ctors_section_asm_out_constructor in that the | |
9758 | width of the .ctors entry is always 64 bits, rather than the 32 bits | |
9759 | used by a normal pointer. */ | |
9760 | ||
9761 | static void | |
92643d95 | 9762 | vms_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED) |
01d15dc5 | 9763 | { |
2f14b1f9 | 9764 | switch_to_section (ctors_section); |
09d688ff | 9765 | assemble_align (BITS_PER_WORD); |
9766 | assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1); | |
01d15dc5 | 9767 | } |
9768 | ||
9769 | static void | |
92643d95 | 9770 | vms_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED) |
01d15dc5 | 9771 | { |
2f14b1f9 | 9772 | switch_to_section (dtors_section); |
09d688ff | 9773 | assemble_align (BITS_PER_WORD); |
9774 | assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1); | |
01d15dc5 | 9775 | } |
8df4a58b | 9776 | #else |
cf73d31f | 9777 | rtx |
c45d3ddf | 9778 | alpha_use_linkage (rtx func ATTRIBUTE_UNUSED, |
5ce94904 | 9779 | bool lflag ATTRIBUTE_UNUSED, |
9780 | bool rflag ATTRIBUTE_UNUSED) | |
cf73d31f | 9781 | { |
9782 | return NULL_RTX; | |
9783 | } | |
9784 | ||
1467e953 | 9785 | #endif /* TARGET_ABI_OPEN_VMS */ |
9caef960 | 9786 | \f |
f2f543a3 | 9787 | static void |
9788 | alpha_init_libfuncs (void) | |
9789 | { | |
04d75965 | 9790 | if (TARGET_ABI_OPEN_VMS) |
f2f543a3 | 9791 | { |
9792 | /* Use the VMS runtime library functions for division and | |
9793 | remainder. */ | |
9794 | set_optab_libfunc (sdiv_optab, SImode, "OTS$DIV_I"); | |
9795 | set_optab_libfunc (sdiv_optab, DImode, "OTS$DIV_L"); | |
9796 | set_optab_libfunc (udiv_optab, SImode, "OTS$DIV_UI"); | |
9797 | set_optab_libfunc (udiv_optab, DImode, "OTS$DIV_UL"); | |
9798 | set_optab_libfunc (smod_optab, SImode, "OTS$REM_I"); | |
9799 | set_optab_libfunc (smod_optab, DImode, "OTS$REM_L"); | |
9800 | set_optab_libfunc (umod_optab, SImode, "OTS$REM_UI"); | |
9801 | set_optab_libfunc (umod_optab, DImode, "OTS$REM_UL"); | |
2db66e7c | 9802 | #ifdef MEM_LIBFUNCS_INIT |
9803 | MEM_LIBFUNCS_INIT; | |
9804 | #endif | |
f2f543a3 | 9805 | } |
9806 | } | |
9807 | ||
b2d7ede1 | 9808 | /* On the Alpha, we use this to disable the floating-point registers |
9809 | when they don't exist. */ | |
9810 | ||
9811 | static void | |
9812 | alpha_conditional_register_usage (void) | |
9813 | { | |
9814 | int i; | |
9815 | if (! TARGET_FPREGS) | |
9816 | for (i = 32; i < 63; i++) | |
9817 | fixed_regs[i] = call_used_regs[i] = 1; | |
9818 | } | |
d5065e6e | 9819 | |
9820 | /* Canonicalize a comparison from one we don't have to one we do have. */ | |
9821 | ||
9822 | static void | |
9823 | alpha_canonicalize_comparison (int *code, rtx *op0, rtx *op1, | |
9824 | bool op0_preserve_value) | |
9825 | { | |
9826 | if (!op0_preserve_value | |
9827 | && (*code == GE || *code == GT || *code == GEU || *code == GTU) | |
9828 | && (REG_P (*op1) || *op1 == const0_rtx)) | |
9829 | { | |
3ffb2c20 | 9830 | std::swap (*op0, *op1); |
d5065e6e | 9831 | *code = (int)swap_condition ((enum rtx_code)*code); |
9832 | } | |
9833 | ||
9834 | if ((*code == LT || *code == LTU) | |
9835 | && CONST_INT_P (*op1) && INTVAL (*op1) == 256) | |
9836 | { | |
9837 | *code = *code == LT ? LE : LEU; | |
9838 | *op1 = GEN_INT (255); | |
9839 | } | |
9840 | } | |
175a5f5f | 9841 | |
9842 | /* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV. */ | |
9843 | ||
9844 | static void | |
9845 | alpha_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) | |
9846 | { | |
9847 | const unsigned HOST_WIDE_INT SWCR_STATUS_MASK = (0x3fUL << 17); | |
9848 | ||
9849 | tree fenv_var, get_fpscr, set_fpscr, mask, ld_fenv, masked_fenv; | |
9850 | tree new_fenv_var, reload_fenv, restore_fnenv; | |
9851 | tree update_call, atomic_feraiseexcept, hold_fnclex; | |
9852 | ||
9853 | /* Assume OSF/1 compatible interfaces. */ | |
9854 | if (!TARGET_ABI_OSF) | |
9855 | return; | |
9856 | ||
9857 | /* Generate the equivalent of : | |
9858 | unsigned long fenv_var; | |
9859 | fenv_var = __ieee_get_fp_control (); | |
9860 | ||
9861 | unsigned long masked_fenv; | |
9862 | masked_fenv = fenv_var & mask; | |
9863 | ||
9864 | __ieee_set_fp_control (masked_fenv); */ | |
9865 | ||
8757cf79 | 9866 | fenv_var = create_tmp_var_raw (long_unsigned_type_node); |
175a5f5f | 9867 | get_fpscr |
9868 | = build_fn_decl ("__ieee_get_fp_control", | |
9869 | build_function_type_list (long_unsigned_type_node, NULL)); | |
9870 | set_fpscr | |
9871 | = build_fn_decl ("__ieee_set_fp_control", | |
9872 | build_function_type_list (void_type_node, NULL)); | |
9873 | mask = build_int_cst (long_unsigned_type_node, ~SWCR_STATUS_MASK); | |
9874 | ld_fenv = build2 (MODIFY_EXPR, long_unsigned_type_node, | |
9875 | fenv_var, build_call_expr (get_fpscr, 0)); | |
9876 | masked_fenv = build2 (BIT_AND_EXPR, long_unsigned_type_node, fenv_var, mask); | |
9877 | hold_fnclex = build_call_expr (set_fpscr, 1, masked_fenv); | |
9878 | *hold = build2 (COMPOUND_EXPR, void_type_node, | |
9879 | build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv), | |
9880 | hold_fnclex); | |
9881 | ||
9882 | /* Store the value of masked_fenv to clear the exceptions: | |
9883 | __ieee_set_fp_control (masked_fenv); */ | |
9884 | ||
9885 | *clear = build_call_expr (set_fpscr, 1, masked_fenv); | |
9886 | ||
9887 | /* Generate the equivalent of : | |
9888 | unsigned long new_fenv_var; | |
9889 | new_fenv_var = __ieee_get_fp_control (); | |
9890 | ||
9891 | __ieee_set_fp_control (fenv_var); | |
9892 | ||
9893 | __atomic_feraiseexcept (new_fenv_var); */ | |
9894 | ||
8757cf79 | 9895 | new_fenv_var = create_tmp_var_raw (long_unsigned_type_node); |
175a5f5f | 9896 | reload_fenv = build2 (MODIFY_EXPR, long_unsigned_type_node, new_fenv_var, |
9897 | build_call_expr (get_fpscr, 0)); | |
9898 | restore_fnenv = build_call_expr (set_fpscr, 1, fenv_var); | |
9899 | atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT); | |
9900 | update_call | |
9901 | = build_call_expr (atomic_feraiseexcept, 1, | |
9902 | fold_convert (integer_type_node, new_fenv_var)); | |
9903 | *update = build2 (COMPOUND_EXPR, void_type_node, | |
9904 | build2 (COMPOUND_EXPR, void_type_node, | |
9905 | reload_fenv, restore_fnenv), update_call); | |
9906 | } | |
b395382f | 9907 | |
9908 | /* Implement TARGET_HARD_REGNO_MODE_OK. On Alpha, the integer registers | |
9909 | can hold any mode. The floating-point registers can hold 64-bit | |
9910 | integers as well, but not smaller values. */ | |
9911 | ||
9912 | static bool | |
9913 | alpha_hard_regno_mode_ok (unsigned int regno, machine_mode mode) | |
9914 | { | |
9915 | if (IN_RANGE (regno, 32, 62)) | |
9916 | return (mode == SFmode | |
9917 | || mode == DFmode | |
9918 | || mode == DImode | |
9919 | || mode == SCmode | |
9920 | || mode == DCmode); | |
9921 | return true; | |
9922 | } | |
5f6dcf1a | 9923 | |
9924 | /* Implement TARGET_MODES_TIEABLE_P. This asymmetric test is true when | |
9925 | MODE1 could be put in an FP register but MODE2 could not. */ | |
9926 | ||
9927 | static bool | |
9928 | alpha_modes_tieable_p (machine_mode mode1, machine_mode mode2) | |
9929 | { | |
9930 | return (alpha_hard_regno_mode_ok (32, mode1) | |
9931 | ? alpha_hard_regno_mode_ok (32, mode2) | |
9932 | : true); | |
9933 | } | |
b56a9dbc | 9934 | |
9935 | /* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ | |
9936 | ||
9937 | static bool | |
9938 | alpha_can_change_mode_class (machine_mode from, machine_mode to, | |
9939 | reg_class_t rclass) | |
9940 | { | |
9941 | return (GET_MODE_SIZE (from) == GET_MODE_SIZE (to) | |
9942 | || !reg_classes_intersect_p (FLOAT_REGS, rclass)); | |
9943 | } | |
92643d95 | 9944 | \f |
9945 | /* Initialize the GCC target structure. */ | |
9946 | #if TARGET_ABI_OPEN_VMS | |
9947 | # undef TARGET_ATTRIBUTE_TABLE | |
9948 | # define TARGET_ATTRIBUTE_TABLE vms_attribute_table | |
cd90919d | 9949 | # undef TARGET_CAN_ELIMINATE |
9950 | # define TARGET_CAN_ELIMINATE alpha_vms_can_eliminate | |
92643d95 | 9951 | #endif |
9952 | ||
9953 | #undef TARGET_IN_SMALL_DATA_P | |
9954 | #define TARGET_IN_SMALL_DATA_P alpha_in_small_data_p | |
9955 | ||
92643d95 | 9956 | #undef TARGET_ASM_ALIGNED_HI_OP |
9957 | #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" | |
9958 | #undef TARGET_ASM_ALIGNED_DI_OP | |
9959 | #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" | |
9960 | ||
9961 | /* Default unaligned ops are provided for ELF systems. To get unaligned | |
9962 | data for non-ELF systems, we have to turn off auto alignment. */ | |
48a5030b | 9963 | #if TARGET_ABI_OPEN_VMS |
92643d95 | 9964 | #undef TARGET_ASM_UNALIGNED_HI_OP |
9965 | #define TARGET_ASM_UNALIGNED_HI_OP "\t.align 0\n\t.word\t" | |
9966 | #undef TARGET_ASM_UNALIGNED_SI_OP | |
9967 | #define TARGET_ASM_UNALIGNED_SI_OP "\t.align 0\n\t.long\t" | |
9968 | #undef TARGET_ASM_UNALIGNED_DI_OP | |
9969 | #define TARGET_ASM_UNALIGNED_DI_OP "\t.align 0\n\t.quad\t" | |
9970 | #endif | |
9971 | ||
4e151b05 | 9972 | #undef TARGET_ASM_RELOC_RW_MASK |
9973 | #define TARGET_ASM_RELOC_RW_MASK alpha_elf_reloc_rw_mask | |
92643d95 | 9974 | #undef TARGET_ASM_SELECT_RTX_SECTION |
9975 | #define TARGET_ASM_SELECT_RTX_SECTION alpha_elf_select_rtx_section | |
cc2af183 | 9976 | #undef TARGET_SECTION_TYPE_FLAGS |
9977 | #define TARGET_SECTION_TYPE_FLAGS alpha_elf_section_type_flags | |
92643d95 | 9978 | |
9979 | #undef TARGET_ASM_FUNCTION_END_PROLOGUE | |
9980 | #define TARGET_ASM_FUNCTION_END_PROLOGUE alpha_output_function_end_prologue | |
9981 | ||
f2f543a3 | 9982 | #undef TARGET_INIT_LIBFUNCS |
9983 | #define TARGET_INIT_LIBFUNCS alpha_init_libfuncs | |
9984 | ||
41e3a0c7 | 9985 | #undef TARGET_LEGITIMIZE_ADDRESS |
9986 | #define TARGET_LEGITIMIZE_ADDRESS alpha_legitimize_address | |
649bdf00 | 9987 | #undef TARGET_MODE_DEPENDENT_ADDRESS_P |
9988 | #define TARGET_MODE_DEPENDENT_ADDRESS_P alpha_mode_dependent_address_p | |
41e3a0c7 | 9989 | |
92c473b8 | 9990 | #undef TARGET_ASM_FILE_START |
9991 | #define TARGET_ASM_FILE_START alpha_file_start | |
92c473b8 | 9992 | |
92643d95 | 9993 | #undef TARGET_SCHED_ADJUST_COST |
9994 | #define TARGET_SCHED_ADJUST_COST alpha_adjust_cost | |
9995 | #undef TARGET_SCHED_ISSUE_RATE | |
9996 | #define TARGET_SCHED_ISSUE_RATE alpha_issue_rate | |
92643d95 | 9997 | #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD |
9998 | #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \ | |
9999 | alpha_multipass_dfa_lookahead | |
10000 | ||
10001 | #undef TARGET_HAVE_TLS | |
10002 | #define TARGET_HAVE_TLS HAVE_AS_TLS | |
10003 | ||
bad4fb18 | 10004 | #undef TARGET_BUILTIN_DECL |
10005 | #define TARGET_BUILTIN_DECL alpha_builtin_decl | |
92643d95 | 10006 | #undef TARGET_INIT_BUILTINS |
10007 | #define TARGET_INIT_BUILTINS alpha_init_builtins | |
10008 | #undef TARGET_EXPAND_BUILTIN | |
10009 | #define TARGET_EXPAND_BUILTIN alpha_expand_builtin | |
849c7bc6 | 10010 | #undef TARGET_FOLD_BUILTIN |
10011 | #define TARGET_FOLD_BUILTIN alpha_fold_builtin | |
e3825818 | 10012 | #undef TARGET_GIMPLE_FOLD_BUILTIN |
10013 | #define TARGET_GIMPLE_FOLD_BUILTIN alpha_gimple_fold_builtin | |
92643d95 | 10014 | |
10015 | #undef TARGET_FUNCTION_OK_FOR_SIBCALL | |
10016 | #define TARGET_FUNCTION_OK_FOR_SIBCALL alpha_function_ok_for_sibcall | |
10017 | #undef TARGET_CANNOT_COPY_INSN_P | |
10018 | #define TARGET_CANNOT_COPY_INSN_P alpha_cannot_copy_insn_p | |
ca316360 | 10019 | #undef TARGET_LEGITIMATE_CONSTANT_P |
10020 | #define TARGET_LEGITIMATE_CONSTANT_P alpha_legitimate_constant_p | |
c0da4391 | 10021 | #undef TARGET_CANNOT_FORCE_CONST_MEM |
10022 | #define TARGET_CANNOT_FORCE_CONST_MEM alpha_cannot_force_const_mem | |
92643d95 | 10023 | |
10024 | #if TARGET_ABI_OSF | |
10025 | #undef TARGET_ASM_OUTPUT_MI_THUNK | |
10026 | #define TARGET_ASM_OUTPUT_MI_THUNK alpha_output_mi_thunk_osf | |
10027 | #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK | |
a9f1838b | 10028 | #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true |
7955d282 | 10029 | #undef TARGET_STDARG_OPTIMIZE_HOOK |
10030 | #define TARGET_STDARG_OPTIMIZE_HOOK alpha_stdarg_optimize_hook | |
92643d95 | 10031 | #endif |
10032 | ||
a2ea1410 | 10033 | #undef TARGET_PRINT_OPERAND |
10034 | #define TARGET_PRINT_OPERAND alpha_print_operand | |
10035 | #undef TARGET_PRINT_OPERAND_ADDRESS | |
10036 | #define TARGET_PRINT_OPERAND_ADDRESS alpha_print_operand_address | |
10037 | #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P | |
10038 | #define TARGET_PRINT_OPERAND_PUNCT_VALID_P alpha_print_operand_punct_valid_p | |
10039 | ||
c2ec39b5 | 10040 | /* Use 16-bits anchor. */ |
10041 | #undef TARGET_MIN_ANCHOR_OFFSET | |
10042 | #define TARGET_MIN_ANCHOR_OFFSET -0x7fff - 1 | |
10043 | #undef TARGET_MAX_ANCHOR_OFFSET | |
10044 | #define TARGET_MAX_ANCHOR_OFFSET 0x7fff | |
10045 | #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P | |
10046 | #define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true | |
10047 | ||
8647dea5 | 10048 | #undef TARGET_REGISTER_MOVE_COST |
10049 | #define TARGET_REGISTER_MOVE_COST alpha_register_move_cost | |
10050 | #undef TARGET_MEMORY_MOVE_COST | |
10051 | #define TARGET_MEMORY_MOVE_COST alpha_memory_move_cost | |
92643d95 | 10052 | #undef TARGET_RTX_COSTS |
10053 | #define TARGET_RTX_COSTS alpha_rtx_costs | |
10054 | #undef TARGET_ADDRESS_COST | |
d9c5e5f4 | 10055 | #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0 |
92643d95 | 10056 | |
10057 | #undef TARGET_MACHINE_DEPENDENT_REORG | |
10058 | #define TARGET_MACHINE_DEPENDENT_REORG alpha_reorg | |
10059 | ||
3b2411a8 | 10060 | #undef TARGET_PROMOTE_FUNCTION_MODE |
10061 | #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote | |
dd9f3024 | 10062 | #undef TARGET_PROMOTE_PROTOTYPES |
fb80456a | 10063 | #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false |
8647dea5 | 10064 | |
10065 | #undef TARGET_FUNCTION_VALUE | |
10066 | #define TARGET_FUNCTION_VALUE alpha_function_value | |
10067 | #undef TARGET_LIBCALL_VALUE | |
10068 | #define TARGET_LIBCALL_VALUE alpha_libcall_value | |
10069 | #undef TARGET_FUNCTION_VALUE_REGNO_P | |
10070 | #define TARGET_FUNCTION_VALUE_REGNO_P alpha_function_value_regno_p | |
dd9f3024 | 10071 | #undef TARGET_RETURN_IN_MEMORY |
10072 | #define TARGET_RETURN_IN_MEMORY alpha_return_in_memory | |
b981d932 | 10073 | #undef TARGET_PASS_BY_REFERENCE |
10074 | #define TARGET_PASS_BY_REFERENCE alpha_pass_by_reference | |
dd9f3024 | 10075 | #undef TARGET_SETUP_INCOMING_VARARGS |
10076 | #define TARGET_SETUP_INCOMING_VARARGS alpha_setup_incoming_varargs | |
10077 | #undef TARGET_STRICT_ARGUMENT_NAMING | |
10078 | #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true | |
10079 | #undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED | |
10080 | #define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true | |
92d40bc4 | 10081 | #undef TARGET_SPLIT_COMPLEX_ARG |
10082 | #define TARGET_SPLIT_COMPLEX_ARG alpha_split_complex_arg | |
de8f9b94 | 10083 | #undef TARGET_GIMPLIFY_VA_ARG_EXPR |
10084 | #define TARGET_GIMPLIFY_VA_ARG_EXPR alpha_gimplify_va_arg | |
f054eb3c | 10085 | #undef TARGET_ARG_PARTIAL_BYTES |
10086 | #define TARGET_ARG_PARTIAL_BYTES alpha_arg_partial_bytes | |
54ea4630 | 10087 | #undef TARGET_FUNCTION_ARG |
10088 | #define TARGET_FUNCTION_ARG alpha_function_arg | |
10089 | #undef TARGET_FUNCTION_ARG_ADVANCE | |
10090 | #define TARGET_FUNCTION_ARG_ADVANCE alpha_function_arg_advance | |
7bcbe23a | 10091 | #undef TARGET_TRAMPOLINE_INIT |
10092 | #define TARGET_TRAMPOLINE_INIT alpha_trampoline_init | |
b2aef146 | 10093 | |
0d25d8c2 | 10094 | #undef TARGET_INSTANTIATE_DECLS |
10095 | #define TARGET_INSTANTIATE_DECLS alpha_instantiate_decls | |
10096 | ||
0d96cd2b | 10097 | #undef TARGET_SECONDARY_RELOAD |
10098 | #define TARGET_SECONDARY_RELOAD alpha_secondary_reload | |
c836e75b | 10099 | #undef TARGET_SECONDARY_MEMORY_NEEDED |
10100 | #define TARGET_SECONDARY_MEMORY_NEEDED alpha_secondary_memory_needed | |
1041f930 | 10101 | #undef TARGET_SECONDARY_MEMORY_NEEDED_MODE |
10102 | #define TARGET_SECONDARY_MEMORY_NEEDED_MODE alpha_secondary_memory_needed_mode | |
0d96cd2b | 10103 | |
b2aef146 | 10104 | #undef TARGET_SCALAR_MODE_SUPPORTED_P |
10105 | #define TARGET_SCALAR_MODE_SUPPORTED_P alpha_scalar_mode_supported_p | |
9e7454d0 | 10106 | #undef TARGET_VECTOR_MODE_SUPPORTED_P |
10107 | #define TARGET_VECTOR_MODE_SUPPORTED_P alpha_vector_mode_supported_p | |
dd9f3024 | 10108 | |
2e15d750 | 10109 | #undef TARGET_BUILD_BUILTIN_VA_LIST |
10110 | #define TARGET_BUILD_BUILTIN_VA_LIST alpha_build_builtin_va_list | |
10111 | ||
8a58ed0a | 10112 | #undef TARGET_EXPAND_BUILTIN_VA_START |
10113 | #define TARGET_EXPAND_BUILTIN_VA_START alpha_va_start | |
10114 | ||
4c834714 | 10115 | #undef TARGET_OPTION_OVERRIDE |
10116 | #define TARGET_OPTION_OVERRIDE alpha_option_override | |
10117 | ||
3032a4ea | 10118 | #undef TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE |
10119 | #define TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE \ | |
10120 | alpha_override_options_after_change | |
10121 | ||
4257b08a | 10122 | #ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING |
eddcdde1 | 10123 | #undef TARGET_MANGLE_TYPE |
10124 | #define TARGET_MANGLE_TYPE alpha_mangle_type | |
4257b08a | 10125 | #endif |
10126 | ||
e46fbef5 | 10127 | #undef TARGET_LRA_P |
10128 | #define TARGET_LRA_P hook_bool_void_false | |
10129 | ||
fd50b071 | 10130 | #undef TARGET_LEGITIMATE_ADDRESS_P |
10131 | #define TARGET_LEGITIMATE_ADDRESS_P alpha_legitimate_address_p | |
10132 | ||
b2d7ede1 | 10133 | #undef TARGET_CONDITIONAL_REGISTER_USAGE |
10134 | #define TARGET_CONDITIONAL_REGISTER_USAGE alpha_conditional_register_usage | |
10135 | ||
d5065e6e | 10136 | #undef TARGET_CANONICALIZE_COMPARISON |
10137 | #define TARGET_CANONICALIZE_COMPARISON alpha_canonicalize_comparison | |
10138 | ||
175a5f5f | 10139 | #undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV |
10140 | #define TARGET_ATOMIC_ASSIGN_EXPAND_FENV alpha_atomic_assign_expand_fenv | |
10141 | ||
b395382f | 10142 | #undef TARGET_HARD_REGNO_MODE_OK |
10143 | #define TARGET_HARD_REGNO_MODE_OK alpha_hard_regno_mode_ok | |
10144 | ||
5f6dcf1a | 10145 | #undef TARGET_MODES_TIEABLE_P |
10146 | #define TARGET_MODES_TIEABLE_P alpha_modes_tieable_p | |
10147 | ||
b56a9dbc | 10148 | #undef TARGET_CAN_CHANGE_MODE_CLASS |
10149 | #define TARGET_CAN_CHANGE_MODE_CLASS alpha_can_change_mode_class | |
10150 | ||
92643d95 | 10151 | struct gcc_target targetm = TARGET_INITIALIZER; |
10152 | ||
10153 | \f | |
1f3233d1 | 10154 | #include "gt-alpha.h" |