]>
Commit | Line | Data |
---|---|---|
bf2a98b3 | 1 | /* Subroutines used for code generation on the DEC Alpha. |
d353bf18 | 2 | Copyright (C) 1992-2015 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 | ||
bf2a98b3 | 22 | #include "config.h" |
769ea120 | 23 | #include "system.h" |
805e22b2 | 24 | #include "coretypes.h" |
25 | #include "tm.h" | |
bf2a98b3 | 26 | #include "rtl.h" |
b20a8bb4 | 27 | #include "alias.h" |
28 | #include "symtab.h" | |
d8fc4d0b | 29 | #include "tree.h" |
b20a8bb4 | 30 | #include "fold-const.h" |
9ed99284 | 31 | #include "stor-layout.h" |
32 | #include "calls.h" | |
33 | #include "varasm.h" | |
bf2a98b3 | 34 | #include "regs.h" |
35 | #include "hard-reg-set.h" | |
bf2a98b3 | 36 | #include "insn-config.h" |
37 | #include "conditions.h" | |
bf2a98b3 | 38 | #include "output.h" |
39 | #include "insn-attr.h" | |
40 | #include "flags.h" | |
41 | #include "recog.h" | |
d53441c8 | 42 | #include "function.h" |
d53441c8 | 43 | #include "expmed.h" |
44 | #include "dojump.h" | |
45 | #include "explow.h" | |
46 | #include "emit-rtl.h" | |
47 | #include "stmt.h" | |
bf2a98b3 | 48 | #include "expr.h" |
34517c64 | 49 | #include "insn-codes.h" |
d8fc4d0b | 50 | #include "optabs.h" |
51 | #include "reload.h" | |
bf2a98b3 | 52 | #include "obstack.h" |
0c0464e6 | 53 | #include "except.h" |
0b205f4c | 54 | #include "diagnostic-core.h" |
0d50f0b7 | 55 | #include "tm_p.h" |
a767736d | 56 | #include "target.h" |
57 | #include "target-def.h" | |
218e3e4e | 58 | #include "common/common-target.h" |
961d6ddd | 59 | #include "debug.h" |
a1f71e15 | 60 | #include "langhooks.h" |
94ea8568 | 61 | #include "predict.h" |
62 | #include "dominance.h" | |
63 | #include "cfg.h" | |
64 | #include "cfgrtl.h" | |
65 | #include "cfganal.h" | |
66 | #include "lcm.h" | |
67 | #include "cfgbuild.h" | |
68 | #include "cfgcleanup.h" | |
bc61cadb | 69 | #include "basic-block.h" |
70 | #include "tree-ssa-alias.h" | |
71 | #include "internal-fn.h" | |
72 | #include "gimple-fold.h" | |
73 | #include "tree-eh.h" | |
74 | #include "gimple-expr.h" | |
e795d6e1 | 75 | #include "gimple.h" |
b80c91bc | 76 | #include "tree-pass.h" |
77 | #include "context.h" | |
78 | #include "pass_manager.h" | |
e3825818 | 79 | #include "gimple-iterator.h" |
a8783bee | 80 | #include "gimplify.h" |
dd9784d4 | 81 | #include "gimple-ssa.h" |
9ed99284 | 82 | #include "stringpool.h" |
16660726 | 83 | #include "tree-ssanames.h" |
a6c787e5 | 84 | #include "tree-stdarg.h" |
1dffd068 | 85 | #include "tm-constrs.h" |
3072d30e | 86 | #include "df.h" |
2db66e7c | 87 | #include "libfuncs.h" |
fba5dd52 | 88 | #include "opts.h" |
56317318 | 89 | #include "params.h" |
f7715905 | 90 | #include "builtins.h" |
97a30fee | 91 | #include "rtl-iter.h" |
0c0464e6 | 92 | |
65abff06 | 93 | /* Specify which cpu to schedule for. */ |
fb64edde | 94 | enum processor_type alpha_tune; |
0c0464e6 | 95 | |
fb64edde | 96 | /* Which cpu we're generating code for. */ |
f141a8b4 | 97 | enum processor_type alpha_cpu; |
fb64edde | 98 | |
9e7454d0 | 99 | static const char * const alpha_cpu_name[] = |
07c1a295 | 100 | { |
101 | "ev4", "ev5", "ev6" | |
102 | }; | |
0c5845b3 | 103 | |
c4622276 | 104 | /* Specify how accurate floating-point traps need to be. */ |
105 | ||
106 | enum alpha_trap_precision alpha_tp; | |
107 | ||
108 | /* Specify the floating-point rounding mode. */ | |
109 | ||
110 | enum alpha_fp_rounding_mode alpha_fprm; | |
111 | ||
112 | /* Specify which things cause traps. */ | |
113 | ||
114 | enum alpha_fp_trap_mode alpha_fptm; | |
115 | ||
e3e08e7f | 116 | /* Nonzero if inside of a function, because the Alpha asm can't |
449b7f2d | 117 | handle .files inside of functions. */ |
118 | ||
119 | static int inside_function = FALSE; | |
120 | ||
07c1a295 | 121 | /* The number of cycles of latency we should assume on memory reads. */ |
122 | ||
123 | int alpha_memory_latency = 3; | |
124 | ||
b9a5aa8e | 125 | /* Whether the function needs the GP. */ |
126 | ||
127 | static int alpha_function_needs_gp; | |
128 | ||
a314eb5e | 129 | /* The assembler name of the current function. */ |
130 | ||
131 | static const char *alpha_fnname; | |
132 | ||
1f0ce6a6 | 133 | /* The next explicit relocation sequence number. */ |
9de382d9 | 134 | extern GTY(()) int alpha_next_sequence_number; |
1f0ce6a6 | 135 | int alpha_next_sequence_number = 1; |
136 | ||
137 | /* The literal and gpdisp sequence numbers for this insn, as printed | |
138 | by %# and %* respectively. */ | |
9de382d9 | 139 | extern GTY(()) int alpha_this_literal_sequence_number; |
140 | extern GTY(()) int alpha_this_gpdisp_sequence_number; | |
1f0ce6a6 | 141 | int alpha_this_literal_sequence_number; |
142 | int alpha_this_gpdisp_sequence_number; | |
143 | ||
fab7adbf | 144 | /* Costs of various operations on the different architectures. */ |
145 | ||
146 | struct alpha_rtx_cost_data | |
147 | { | |
148 | unsigned char fp_add; | |
149 | unsigned char fp_mult; | |
150 | unsigned char fp_div_sf; | |
151 | unsigned char fp_div_df; | |
152 | unsigned char int_mult_si; | |
153 | unsigned char int_mult_di; | |
154 | unsigned char int_shift; | |
155 | unsigned char int_cmov; | |
d7cf2331 | 156 | unsigned short int_div; |
fab7adbf | 157 | }; |
158 | ||
159 | static struct alpha_rtx_cost_data const alpha_rtx_cost_data[PROCESSOR_MAX] = | |
160 | { | |
161 | { /* EV4 */ | |
162 | COSTS_N_INSNS (6), /* fp_add */ | |
163 | COSTS_N_INSNS (6), /* fp_mult */ | |
164 | COSTS_N_INSNS (34), /* fp_div_sf */ | |
165 | COSTS_N_INSNS (63), /* fp_div_df */ | |
166 | COSTS_N_INSNS (23), /* int_mult_si */ | |
167 | COSTS_N_INSNS (23), /* int_mult_di */ | |
168 | COSTS_N_INSNS (2), /* int_shift */ | |
169 | COSTS_N_INSNS (2), /* int_cmov */ | |
f6777b0a | 170 | COSTS_N_INSNS (97), /* int_div */ |
fab7adbf | 171 | }, |
172 | { /* EV5 */ | |
173 | COSTS_N_INSNS (4), /* fp_add */ | |
174 | COSTS_N_INSNS (4), /* fp_mult */ | |
175 | COSTS_N_INSNS (15), /* fp_div_sf */ | |
176 | COSTS_N_INSNS (22), /* fp_div_df */ | |
177 | COSTS_N_INSNS (8), /* int_mult_si */ | |
178 | COSTS_N_INSNS (12), /* int_mult_di */ | |
179 | COSTS_N_INSNS (1) + 1, /* int_shift */ | |
180 | COSTS_N_INSNS (1), /* int_cmov */ | |
f6777b0a | 181 | COSTS_N_INSNS (83), /* int_div */ |
fab7adbf | 182 | }, |
183 | { /* EV6 */ | |
184 | COSTS_N_INSNS (4), /* fp_add */ | |
185 | COSTS_N_INSNS (4), /* fp_mult */ | |
186 | COSTS_N_INSNS (12), /* fp_div_sf */ | |
187 | COSTS_N_INSNS (15), /* fp_div_df */ | |
188 | COSTS_N_INSNS (7), /* int_mult_si */ | |
189 | COSTS_N_INSNS (7), /* int_mult_di */ | |
190 | COSTS_N_INSNS (1), /* int_shift */ | |
191 | COSTS_N_INSNS (2), /* int_cmov */ | |
f6777b0a | 192 | COSTS_N_INSNS (86), /* int_div */ |
fab7adbf | 193 | }, |
194 | }; | |
195 | ||
d7cf2331 | 196 | /* Similar but tuned for code size instead of execution latency. The |
197 | extra +N is fractional cost tuning based on latency. It's used to | |
198 | encourage use of cheaper insns like shift, but only if there's just | |
199 | one of them. */ | |
200 | ||
201 | static struct alpha_rtx_cost_data const alpha_rtx_cost_size = | |
202 | { | |
203 | COSTS_N_INSNS (1), /* fp_add */ | |
204 | COSTS_N_INSNS (1), /* fp_mult */ | |
205 | COSTS_N_INSNS (1), /* fp_div_sf */ | |
206 | COSTS_N_INSNS (1) + 1, /* fp_div_df */ | |
207 | COSTS_N_INSNS (1) + 1, /* int_mult_si */ | |
208 | COSTS_N_INSNS (1) + 2, /* int_mult_di */ | |
209 | COSTS_N_INSNS (1), /* int_shift */ | |
210 | COSTS_N_INSNS (1), /* int_cmov */ | |
211 | COSTS_N_INSNS (6), /* int_div */ | |
212 | }; | |
213 | ||
0dbd1c74 | 214 | /* Get the number of args of a function in one of two ways. */ |
04d75965 | 215 | #if TARGET_ABI_OPEN_VMS |
abe32cce | 216 | #define NUM_ARGS crtl->args.info.num_args |
0dbd1c74 | 217 | #else |
abe32cce | 218 | #define NUM_ARGS crtl->args.info |
0dbd1c74 | 219 | #endif |
d2832bd8 | 220 | |
d2832bd8 | 221 | #define REG_PV 27 |
222 | #define REG_RA 26 | |
f2cc13dc | 223 | |
92643d95 | 224 | /* Declarations of static functions. */ |
225 | static struct machine_function *alpha_init_machine_status (void); | |
8c3428a6 | 226 | static rtx alpha_emit_xfloating_compare (enum rtx_code *, rtx, rtx); |
b80c91bc | 227 | static void alpha_handle_trap_shadows (void); |
228 | static void alpha_align_insns (void); | |
3032a4ea | 229 | static void alpha_override_options_after_change (void); |
805e22b2 | 230 | |
92643d95 | 231 | #if TARGET_ABI_OPEN_VMS |
5ce94904 | 232 | static void alpha_write_linkage (FILE *, const char *); |
3754d046 | 233 | static bool vms_valid_pointer_mode (machine_mode); |
044f30d8 | 234 | #else |
235 | #define vms_patch_builtins() gcc_unreachable() | |
6988553d | 236 | #endif |
a767736d | 237 | \f |
b80c91bc | 238 | static unsigned int |
239 | rest_of_handle_trap_shadows (void) | |
240 | { | |
241 | alpha_handle_trap_shadows (); | |
242 | return 0; | |
243 | } | |
244 | ||
245 | namespace { | |
246 | ||
247 | const pass_data pass_data_handle_trap_shadows = | |
248 | { | |
249 | RTL_PASS, | |
250 | "trap_shadows", /* name */ | |
251 | OPTGROUP_NONE, /* optinfo_flags */ | |
252 | TV_NONE, /* tv_id */ | |
253 | 0, /* properties_required */ | |
254 | 0, /* properties_provided */ | |
255 | 0, /* properties_destroyed */ | |
256 | 0, /* todo_flags_start */ | |
257 | TODO_df_finish, /* todo_flags_finish */ | |
258 | }; | |
259 | ||
260 | class pass_handle_trap_shadows : public rtl_opt_pass | |
261 | { | |
262 | public: | |
263 | pass_handle_trap_shadows(gcc::context *ctxt) | |
264 | : rtl_opt_pass(pass_data_handle_trap_shadows, ctxt) | |
265 | {} | |
266 | ||
267 | /* opt_pass methods: */ | |
268 | virtual bool gate (function *) | |
269 | { | |
270 | return alpha_tp != ALPHA_TP_PROG || flag_exceptions; | |
271 | } | |
272 | ||
273 | virtual unsigned int execute (function *) | |
274 | { | |
275 | return rest_of_handle_trap_shadows (); | |
276 | } | |
277 | ||
278 | }; // class pass_handle_trap_shadows | |
279 | ||
280 | } // anon namespace | |
281 | ||
282 | rtl_opt_pass * | |
283 | make_pass_handle_trap_shadows (gcc::context *ctxt) | |
284 | { | |
285 | return new pass_handle_trap_shadows (ctxt); | |
286 | } | |
287 | ||
288 | static unsigned int | |
289 | rest_of_align_insns (void) | |
290 | { | |
291 | alpha_align_insns (); | |
292 | return 0; | |
293 | } | |
294 | ||
295 | namespace { | |
296 | ||
297 | const pass_data pass_data_align_insns = | |
298 | { | |
299 | RTL_PASS, | |
300 | "align_insns", /* name */ | |
301 | OPTGROUP_NONE, /* optinfo_flags */ | |
302 | TV_NONE, /* tv_id */ | |
303 | 0, /* properties_required */ | |
304 | 0, /* properties_provided */ | |
305 | 0, /* properties_destroyed */ | |
306 | 0, /* todo_flags_start */ | |
307 | TODO_df_finish, /* todo_flags_finish */ | |
308 | }; | |
309 | ||
310 | class pass_align_insns : public rtl_opt_pass | |
311 | { | |
312 | public: | |
313 | pass_align_insns(gcc::context *ctxt) | |
314 | : rtl_opt_pass(pass_data_align_insns, ctxt) | |
315 | {} | |
316 | ||
317 | /* opt_pass methods: */ | |
318 | virtual bool gate (function *) | |
319 | { | |
320 | /* Due to the number of extra trapb insns, don't bother fixing up | |
321 | alignment when trap precision is instruction. Moreover, we can | |
322 | only do our job when sched2 is run. */ | |
323 | return ((alpha_tune == PROCESSOR_EV4 | |
324 | || alpha_tune == PROCESSOR_EV5) | |
325 | && optimize && !optimize_size | |
326 | && alpha_tp != ALPHA_TP_INSN | |
327 | && flag_schedule_insns_after_reload); | |
328 | } | |
329 | ||
330 | virtual unsigned int execute (function *) | |
331 | { | |
332 | return rest_of_align_insns (); | |
333 | } | |
334 | ||
335 | }; // class pass_align_insns | |
336 | ||
337 | } // anon namespace | |
338 | ||
339 | rtl_opt_pass * | |
340 | make_pass_align_insns (gcc::context *ctxt) | |
341 | { | |
342 | return new pass_align_insns (ctxt); | |
343 | } | |
344 | ||
4257b08a | 345 | #ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING |
eddcdde1 | 346 | /* Implement TARGET_MANGLE_TYPE. */ |
4257b08a | 347 | |
348 | static const char * | |
a9f1838b | 349 | alpha_mangle_type (const_tree type) |
4257b08a | 350 | { |
351 | if (TYPE_MAIN_VARIANT (type) == long_double_type_node | |
352 | && TARGET_LONG_DOUBLE_128) | |
353 | return "g"; | |
354 | ||
355 | /* For all other types, use normal C++ mangling. */ | |
356 | return NULL; | |
357 | } | |
358 | #endif | |
359 | ||
65abff06 | 360 | /* Parse target option strings. */ |
c4622276 | 361 | |
4c834714 | 362 | static void |
363 | alpha_option_override (void) | |
c4622276 | 364 | { |
e99c3a1d | 365 | static const struct cpu_table { |
366 | const char *const name; | |
367 | const enum processor_type processor; | |
368 | const int flags; | |
56317318 | 369 | const unsigned short line_size; /* in bytes */ |
370 | const unsigned short l1_size; /* in kb. */ | |
371 | const unsigned short l2_size; /* in kb. */ | |
27de1488 | 372 | } cpu_table[] = { |
56317318 | 373 | /* EV4/LCA45 had 8k L1 caches; EV45 had 16k L1 caches. |
374 | EV4/EV45 had 128k to 16M 32-byte direct Bcache. LCA45 | |
375 | had 64k to 8M 8-byte direct Bcache. */ | |
376 | { "ev4", PROCESSOR_EV4, 0, 32, 8, 8*1024 }, | |
377 | { "21064", PROCESSOR_EV4, 0, 32, 8, 8*1024 }, | |
378 | { "ev45", PROCESSOR_EV4, 0, 32, 16, 16*1024 }, | |
379 | ||
380 | /* EV5 or EV56 had 8k 32 byte L1, 96k 32 or 64 byte L2, | |
381 | and 1M to 16M 64 byte L3 (not modeled). | |
382 | PCA56 had 16k 64-byte cache; PCA57 had 32k Icache. | |
383 | PCA56 had 8k 64-byte cache; PCA57 had 16k Dcache. */ | |
384 | { "ev5", PROCESSOR_EV5, 0, 32, 8, 96 }, | |
385 | { "21164", PROCESSOR_EV5, 0, 32, 8, 96 }, | |
386 | { "ev56", PROCESSOR_EV5, MASK_BWX, 32, 8, 96 }, | |
387 | { "21164a", PROCESSOR_EV5, MASK_BWX, 32, 8, 96 }, | |
388 | { "pca56", PROCESSOR_EV5, MASK_BWX|MASK_MAX, 64, 16, 4*1024 }, | |
389 | { "21164PC",PROCESSOR_EV5, MASK_BWX|MASK_MAX, 64, 16, 4*1024 }, | |
390 | { "21164pc",PROCESSOR_EV5, MASK_BWX|MASK_MAX, 64, 16, 4*1024 }, | |
391 | ||
392 | /* EV6 had 64k 64 byte L1, 1M to 16M Bcache. */ | |
393 | { "ev6", PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX, 64, 64, 16*1024 }, | |
394 | { "21264", PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX, 64, 64, 16*1024 }, | |
395 | { "ev67", PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX|MASK_CIX, | |
396 | 64, 64, 16*1024 }, | |
397 | { "21264a", PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX|MASK_CIX, | |
398 | 64, 64, 16*1024 } | |
27de1488 | 399 | }; |
9e7454d0 | 400 | |
b80c91bc | 401 | opt_pass *pass_handle_trap_shadows = make_pass_handle_trap_shadows (g); |
33c6d8ad | 402 | struct register_pass_info handle_trap_shadows_info |
b80c91bc | 403 | = { pass_handle_trap_shadows, "eh_ranges", |
404 | 1, PASS_POS_INSERT_AFTER | |
405 | }; | |
406 | ||
407 | opt_pass *pass_align_insns = make_pass_align_insns (g); | |
33c6d8ad | 408 | struct register_pass_info align_insns_info |
b80c91bc | 409 | = { pass_align_insns, "shorten", |
410 | 1, PASS_POS_INSERT_BEFORE | |
411 | }; | |
412 | ||
afba4ec8 | 413 | int const ct_size = ARRAY_SIZE (cpu_table); |
56317318 | 414 | int line_size = 0, l1_size = 0, l2_size = 0; |
fb64edde | 415 | int i; |
416 | ||
4c834714 | 417 | #ifdef SUBTARGET_OVERRIDE_OPTIONS |
418 | SUBTARGET_OVERRIDE_OPTIONS; | |
419 | #endif | |
420 | ||
669cf718 | 421 | /* Default to full IEEE compliance mode for Go language. */ |
422 | if (strcmp (lang_hooks.name, "GNU Go") == 0 | |
423 | && !(target_flags_explicit & MASK_IEEE)) | |
424 | target_flags |= MASK_IEEE; | |
425 | ||
04d75965 | 426 | alpha_fprm = ALPHA_FPRM_NORM; |
c4622276 | 427 | alpha_tp = ALPHA_TP_PROG; |
c4622276 | 428 | alpha_fptm = ALPHA_FPTM_N; |
429 | ||
430 | if (TARGET_IEEE) | |
431 | { | |
04d75965 | 432 | alpha_tp = ALPHA_TP_INSN; |
433 | alpha_fptm = ALPHA_FPTM_SU; | |
c4622276 | 434 | } |
c4622276 | 435 | if (TARGET_IEEE_WITH_INEXACT) |
436 | { | |
04d75965 | 437 | alpha_tp = ALPHA_TP_INSN; |
438 | alpha_fptm = ALPHA_FPTM_SUI; | |
c4622276 | 439 | } |
440 | ||
441 | if (alpha_tp_string) | |
264f7d8c | 442 | { |
443 | if (! strcmp (alpha_tp_string, "p")) | |
c4622276 | 444 | alpha_tp = ALPHA_TP_PROG; |
264f7d8c | 445 | else if (! strcmp (alpha_tp_string, "f")) |
c4622276 | 446 | alpha_tp = ALPHA_TP_FUNC; |
264f7d8c | 447 | else if (! strcmp (alpha_tp_string, "i")) |
c4622276 | 448 | alpha_tp = ALPHA_TP_INSN; |
264f7d8c | 449 | else |
1e5fcbe2 | 450 | error ("bad value %qs for -mtrap-precision switch", alpha_tp_string); |
264f7d8c | 451 | } |
c4622276 | 452 | |
453 | if (alpha_fprm_string) | |
264f7d8c | 454 | { |
455 | if (! strcmp (alpha_fprm_string, "n")) | |
c4622276 | 456 | alpha_fprm = ALPHA_FPRM_NORM; |
264f7d8c | 457 | else if (! strcmp (alpha_fprm_string, "m")) |
c4622276 | 458 | alpha_fprm = ALPHA_FPRM_MINF; |
264f7d8c | 459 | else if (! strcmp (alpha_fprm_string, "c")) |
c4622276 | 460 | alpha_fprm = ALPHA_FPRM_CHOP; |
264f7d8c | 461 | else if (! strcmp (alpha_fprm_string,"d")) |
c4622276 | 462 | alpha_fprm = ALPHA_FPRM_DYN; |
264f7d8c | 463 | else |
1e5fcbe2 | 464 | error ("bad value %qs for -mfp-rounding-mode switch", |
c4622276 | 465 | alpha_fprm_string); |
264f7d8c | 466 | } |
c4622276 | 467 | |
468 | if (alpha_fptm_string) | |
264f7d8c | 469 | { |
470 | if (strcmp (alpha_fptm_string, "n") == 0) | |
471 | alpha_fptm = ALPHA_FPTM_N; | |
472 | else if (strcmp (alpha_fptm_string, "u") == 0) | |
473 | alpha_fptm = ALPHA_FPTM_U; | |
474 | else if (strcmp (alpha_fptm_string, "su") == 0) | |
475 | alpha_fptm = ALPHA_FPTM_SU; | |
476 | else if (strcmp (alpha_fptm_string, "sui") == 0) | |
477 | alpha_fptm = ALPHA_FPTM_SUI; | |
478 | else | |
1e5fcbe2 | 479 | error ("bad value %qs for -mfp-trap-mode switch", alpha_fptm_string); |
264f7d8c | 480 | } |
c4622276 | 481 | |
cbd8ec27 | 482 | if (alpha_cpu_string) |
483 | { | |
afba4ec8 | 484 | for (i = 0; i < ct_size; i++) |
27de1488 | 485 | if (! strcmp (alpha_cpu_string, cpu_table [i].name)) |
486 | { | |
56317318 | 487 | alpha_tune = alpha_cpu = cpu_table[i].processor; |
488 | line_size = cpu_table[i].line_size; | |
489 | l1_size = cpu_table[i].l1_size; | |
490 | l2_size = cpu_table[i].l2_size; | |
fb64edde | 491 | target_flags &= ~ (MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX); |
56317318 | 492 | target_flags |= cpu_table[i].flags; |
27de1488 | 493 | break; |
494 | } | |
afba4ec8 | 495 | if (i == ct_size) |
1e5fcbe2 | 496 | error ("bad value %qs for -mcpu switch", alpha_cpu_string); |
cbd8ec27 | 497 | } |
498 | ||
27de1488 | 499 | if (alpha_tune_string) |
500 | { | |
afba4ec8 | 501 | for (i = 0; i < ct_size; i++) |
27de1488 | 502 | if (! strcmp (alpha_tune_string, cpu_table [i].name)) |
503 | { | |
56317318 | 504 | alpha_tune = cpu_table[i].processor; |
505 | line_size = cpu_table[i].line_size; | |
506 | l1_size = cpu_table[i].l1_size; | |
507 | l2_size = cpu_table[i].l2_size; | |
27de1488 | 508 | break; |
509 | } | |
afba4ec8 | 510 | if (i == ct_size) |
89b3c92a | 511 | error ("bad value %qs for -mtune switch", alpha_tune_string); |
27de1488 | 512 | } |
513 | ||
56317318 | 514 | if (line_size) |
515 | maybe_set_param_value (PARAM_L1_CACHE_LINE_SIZE, line_size, | |
516 | global_options.x_param_values, | |
517 | global_options_set.x_param_values); | |
518 | if (l1_size) | |
519 | maybe_set_param_value (PARAM_L1_CACHE_SIZE, l1_size, | |
520 | global_options.x_param_values, | |
521 | global_options_set.x_param_values); | |
522 | if (l2_size) | |
523 | maybe_set_param_value (PARAM_L2_CACHE_SIZE, l2_size, | |
524 | global_options.x_param_values, | |
525 | global_options_set.x_param_values); | |
526 | ||
65abff06 | 527 | /* Do some sanity checks on the above options. */ |
c4622276 | 528 | |
264f7d8c | 529 | if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI) |
fb64edde | 530 | && alpha_tp != ALPHA_TP_INSN && alpha_cpu != PROCESSOR_EV6) |
c4622276 | 531 | { |
c3ceba8e | 532 | warning (0, "fp software completion requires -mtrap-precision=i"); |
c4622276 | 533 | alpha_tp = ALPHA_TP_INSN; |
534 | } | |
8df4a58b | 535 | |
fb64edde | 536 | if (alpha_cpu == PROCESSOR_EV6) |
bc16f0c1 | 537 | { |
538 | /* Except for EV6 pass 1 (not released), we always have precise | |
539 | arithmetic traps. Which means we can do software completion | |
540 | without minding trap shadows. */ | |
541 | alpha_tp = ALPHA_TP_PROG; | |
542 | } | |
543 | ||
8df4a58b | 544 | if (TARGET_FLOAT_VAX) |
545 | { | |
546 | if (alpha_fprm == ALPHA_FPRM_MINF || alpha_fprm == ALPHA_FPRM_DYN) | |
547 | { | |
c3ceba8e | 548 | warning (0, "rounding mode not supported for VAX floats"); |
8df4a58b | 549 | alpha_fprm = ALPHA_FPRM_NORM; |
550 | } | |
551 | if (alpha_fptm == ALPHA_FPTM_SUI) | |
552 | { | |
c3ceba8e | 553 | warning (0, "trap mode not supported for VAX floats"); |
8df4a58b | 554 | alpha_fptm = ALPHA_FPTM_SU; |
555 | } | |
ef76af46 | 556 | if (target_flags_explicit & MASK_LONG_DOUBLE_128) |
c3ceba8e | 557 | warning (0, "128-bit long double not supported for VAX floats"); |
ef76af46 | 558 | target_flags &= ~MASK_LONG_DOUBLE_128; |
8df4a58b | 559 | } |
07c1a295 | 560 | |
561 | { | |
562 | char *end; | |
563 | int lat; | |
564 | ||
565 | if (!alpha_mlat_string) | |
566 | alpha_mlat_string = "L1"; | |
567 | ||
14184418 | 568 | if (ISDIGIT ((unsigned char)alpha_mlat_string[0]) |
07c1a295 | 569 | && (lat = strtol (alpha_mlat_string, &end, 10), *end == '\0')) |
570 | ; | |
571 | else if ((alpha_mlat_string[0] == 'L' || alpha_mlat_string[0] == 'l') | |
14184418 | 572 | && ISDIGIT ((unsigned char)alpha_mlat_string[1]) |
07c1a295 | 573 | && alpha_mlat_string[2] == '\0') |
574 | { | |
9e7454d0 | 575 | static int const cache_latency[][4] = |
07c1a295 | 576 | { |
577 | { 3, 30, -1 }, /* ev4 -- Bcache is a guess */ | |
578 | { 2, 12, 38 }, /* ev5 -- Bcache from PC164 LMbench numbers */ | |
65abff06 | 579 | { 3, 12, 30 }, /* ev6 -- Bcache from DS20 LMbench. */ |
07c1a295 | 580 | }; |
581 | ||
582 | lat = alpha_mlat_string[1] - '0'; | |
fb64edde | 583 | if (lat <= 0 || lat > 3 || cache_latency[alpha_tune][lat-1] == -1) |
07c1a295 | 584 | { |
c3ceba8e | 585 | warning (0, "L%d cache latency unknown for %s", |
fb64edde | 586 | lat, alpha_cpu_name[alpha_tune]); |
07c1a295 | 587 | lat = 3; |
588 | } | |
589 | else | |
fb64edde | 590 | lat = cache_latency[alpha_tune][lat-1]; |
07c1a295 | 591 | } |
592 | else if (! strcmp (alpha_mlat_string, "main")) | |
593 | { | |
594 | /* Most current memories have about 370ns latency. This is | |
595 | a reasonable guess for a fast cpu. */ | |
596 | lat = 150; | |
597 | } | |
598 | else | |
599 | { | |
c3ceba8e | 600 | warning (0, "bad value %qs for -mmemory-latency", alpha_mlat_string); |
07c1a295 | 601 | lat = 3; |
602 | } | |
603 | ||
604 | alpha_memory_latency = lat; | |
605 | } | |
a9fa9190 | 606 | |
607 | /* Default the definition of "small data" to 8 bytes. */ | |
13a54dd9 | 608 | if (!global_options_set.x_g_switch_value) |
a9fa9190 | 609 | g_switch_value = 8; |
849674a3 | 610 | |
5dcb037d | 611 | /* Infer TARGET_SMALL_DATA from -fpic/-fPIC. */ |
612 | if (flag_pic == 1) | |
613 | target_flags |= MASK_SMALL_DATA; | |
614 | else if (flag_pic == 2) | |
615 | target_flags &= ~MASK_SMALL_DATA; | |
616 | ||
3032a4ea | 617 | alpha_override_options_after_change (); |
0ea5169b | 618 | |
9caef960 | 619 | /* Register variables and functions with the garbage collector. */ |
620 | ||
9caef960 | 621 | /* Set up function hooks. */ |
622 | init_machine_status = alpha_init_machine_status; | |
1268285a | 623 | |
624 | /* Tell the compiler when we're using VAX floating point. */ | |
625 | if (TARGET_FLOAT_VAX) | |
626 | { | |
0021bea9 | 627 | REAL_MODE_FORMAT (SFmode) = &vax_f_format; |
628 | REAL_MODE_FORMAT (DFmode) = &vax_g_format; | |
629 | REAL_MODE_FORMAT (TFmode) = NULL; | |
1268285a | 630 | } |
2dde0cc6 | 631 | |
632 | #ifdef TARGET_DEFAULT_LONG_DOUBLE_128 | |
633 | if (!(target_flags_explicit & MASK_LONG_DOUBLE_128)) | |
634 | target_flags |= MASK_LONG_DOUBLE_128; | |
635 | #endif | |
b80c91bc | 636 | |
637 | /* This needs to be done at start up. It's convenient to do it here. */ | |
638 | register_pass (&handle_trap_shadows_info); | |
639 | register_pass (&align_insns_info); | |
c4622276 | 640 | } |
3032a4ea | 641 | |
642 | /* Implement targetm.override_options_after_change. */ | |
643 | ||
644 | static void | |
645 | alpha_override_options_after_change (void) | |
646 | { | |
647 | /* Align labels and loops for optimal branching. */ | |
648 | /* ??? Kludge these by not doing anything if we don't optimize. */ | |
649 | if (optimize > 0) | |
650 | { | |
651 | if (align_loops <= 0) | |
652 | align_loops = 16; | |
653 | if (align_jumps <= 0) | |
654 | align_jumps = 16; | |
655 | } | |
656 | if (align_functions <= 0) | |
657 | align_functions = 16; | |
658 | } | |
c4622276 | 659 | \f |
bf2a98b3 | 660 | /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */ |
661 | ||
662 | int | |
92643d95 | 663 | zap_mask (HOST_WIDE_INT value) |
bf2a98b3 | 664 | { |
665 | int i; | |
666 | ||
667 | for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; | |
668 | i++, value >>= 8) | |
669 | if ((value & 0xff) != 0 && (value & 0xff) != 0xff) | |
670 | return 0; | |
671 | ||
672 | return 1; | |
673 | } | |
674 | ||
9e7454d0 | 675 | /* Return true if OP is valid for a particular TLS relocation. |
41421c64 | 676 | We are already guaranteed that OP is a CONST. */ |
bf2a98b3 | 677 | |
678 | int | |
41421c64 | 679 | tls_symbolic_operand_1 (rtx op, int size, int unspec) |
bf2a98b3 | 680 | { |
5f7b9df8 | 681 | op = XEXP (op, 0); |
682 | ||
683 | if (GET_CODE (op) != UNSPEC || XINT (op, 1) != unspec) | |
684 | return 0; | |
685 | op = XVECEXP (op, 0, 0); | |
686 | ||
687 | if (GET_CODE (op) != SYMBOL_REF) | |
688 | return 0; | |
5f7b9df8 | 689 | |
09a1f342 | 690 | switch (SYMBOL_REF_TLS_MODEL (op)) |
9bdcc1e5 | 691 | { |
09a1f342 | 692 | case TLS_MODEL_LOCAL_DYNAMIC: |
ea284d73 | 693 | return unspec == UNSPEC_DTPREL && size == alpha_tls_size; |
09a1f342 | 694 | case TLS_MODEL_INITIAL_EXEC: |
9bdcc1e5 | 695 | return unspec == UNSPEC_TPREL && size == 64; |
09a1f342 | 696 | case TLS_MODEL_LOCAL_EXEC: |
ea284d73 | 697 | return unspec == UNSPEC_TPREL && size == alpha_tls_size; |
9bdcc1e5 | 698 | default: |
4d10b463 | 699 | gcc_unreachable (); |
9bdcc1e5 | 700 | } |
5f7b9df8 | 701 | } |
702 | ||
41421c64 | 703 | /* Used by aligned_memory_operand and unaligned_memory_operand to |
704 | resolve what reload is going to do with OP if it's a register. */ | |
bbf31a61 | 705 | |
41421c64 | 706 | rtx |
707 | resolve_reload_operand (rtx op) | |
bf2a98b3 | 708 | { |
cc215844 | 709 | if (reload_in_progress) |
bf2a98b3 | 710 | { |
cc215844 | 711 | rtx tmp = op; |
712 | if (GET_CODE (tmp) == SUBREG) | |
713 | tmp = SUBREG_REG (tmp); | |
c933fb42 | 714 | if (REG_P (tmp) |
cc215844 | 715 | && REGNO (tmp) >= FIRST_PSEUDO_REGISTER) |
716 | { | |
1c654ff1 | 717 | op = reg_equiv_memory_loc (REGNO (tmp)); |
cc215844 | 718 | if (op == 0) |
719 | return 0; | |
720 | } | |
bf2a98b3 | 721 | } |
41421c64 | 722 | return op; |
14f7bc98 | 723 | } |
724 | ||
b2aef146 | 725 | /* The scalar modes supported differs from the default check-what-c-supports |
726 | version in that sometimes TFmode is available even when long double | |
04d75965 | 727 | indicates only DFmode. */ |
b2aef146 | 728 | |
729 | static bool | |
3754d046 | 730 | alpha_scalar_mode_supported_p (machine_mode mode) |
b2aef146 | 731 | { |
732 | switch (mode) | |
733 | { | |
734 | case QImode: | |
735 | case HImode: | |
736 | case SImode: | |
737 | case DImode: | |
738 | case TImode: /* via optabs.c */ | |
739 | return true; | |
740 | ||
741 | case SFmode: | |
742 | case DFmode: | |
743 | return true; | |
744 | ||
745 | case TFmode: | |
746 | return TARGET_HAS_XFLOATING_LIBS; | |
747 | ||
748 | default: | |
749 | return false; | |
750 | } | |
751 | } | |
752 | ||
753 | /* Alpha implements a couple of integer vector mode operations when | |
b739144f | 754 | TARGET_MAX is enabled. We do not check TARGET_MAX here, however, |
755 | which allows the vectorizer to operate on e.g. move instructions, | |
756 | or when expand_vector_operations can do something useful. */ | |
b2aef146 | 757 | |
9e7454d0 | 758 | static bool |
3754d046 | 759 | alpha_vector_mode_supported_p (machine_mode mode) |
9e7454d0 | 760 | { |
b739144f | 761 | return mode == V8QImode || mode == V4HImode || mode == V2SImode; |
9e7454d0 | 762 | } |
763 | ||
550e415f | 764 | /* Return 1 if this function can directly return via $26. */ |
765 | ||
766 | int | |
92643d95 | 767 | direct_return (void) |
550e415f | 768 | { |
4505d022 | 769 | return (TARGET_ABI_OSF |
1467e953 | 770 | && reload_completed |
771 | && alpha_sa_size () == 0 | |
550e415f | 772 | && get_frame_size () == 0 |
abe32cce | 773 | && crtl->outgoing_args_size == 0 |
774 | && crtl->args.pretend_args_size == 0); | |
550e415f | 775 | } |
ecb98d40 | 776 | |
5f7b9df8 | 777 | /* Return the TLS model to use for SYMBOL. */ |
778 | ||
779 | static enum tls_model | |
92643d95 | 780 | tls_symbolic_operand_type (rtx symbol) |
5f7b9df8 | 781 | { |
09a1f342 | 782 | enum tls_model model; |
5f7b9df8 | 783 | |
784 | if (GET_CODE (symbol) != SYMBOL_REF) | |
afba4ec8 | 785 | return TLS_MODEL_NONE; |
09a1f342 | 786 | model = SYMBOL_REF_TLS_MODEL (symbol); |
5f7b9df8 | 787 | |
09a1f342 | 788 | /* Local-exec with a 64-bit size is the same code as initial-exec. */ |
789 | if (model == TLS_MODEL_LOCAL_EXEC && alpha_tls_size == 64) | |
790 | model = TLS_MODEL_INITIAL_EXEC; | |
5f7b9df8 | 791 | |
09a1f342 | 792 | return model; |
5f7b9df8 | 793 | } |
14f7bc98 | 794 | \f |
9bdcc1e5 | 795 | /* Return true if the function DECL will share the same GP as any |
796 | function in the current unit of translation. */ | |
797 | ||
798 | static bool | |
a9f1838b | 799 | decl_has_samegp (const_tree decl) |
9bdcc1e5 | 800 | { |
801 | /* Functions that are not local can be overridden, and thus may | |
802 | not share the same gp. */ | |
803 | if (!(*targetm.binds_local_p) (decl)) | |
804 | return false; | |
805 | ||
806 | /* If -msmall-data is in effect, assume that there is only one GP | |
807 | for the module, and so any local symbol has this property. We | |
808 | need explicit relocations to be able to enforce this for symbols | |
809 | not defined in this unit of translation, however. */ | |
810 | if (TARGET_EXPLICIT_RELOCS && TARGET_SMALL_DATA) | |
811 | return true; | |
812 | ||
813 | /* Functions that are not external are defined in this UoT. */ | |
cf1d67e3 | 814 | /* ??? Irritatingly, static functions not yet emitted are still |
815 | marked "external". Apply this to non-static functions only. */ | |
816 | return !TREE_PUBLIC (decl) || !DECL_EXTERNAL (decl); | |
9bdcc1e5 | 817 | } |
818 | ||
52470889 | 819 | /* Return true if EXP should be placed in the small data section. */ |
820 | ||
821 | static bool | |
a9f1838b | 822 | alpha_in_small_data_p (const_tree exp) |
52470889 | 823 | { |
0aad4cd2 | 824 | /* We want to merge strings, so we never consider them small data. */ |
825 | if (TREE_CODE (exp) == STRING_CST) | |
826 | return false; | |
827 | ||
6ac09a46 | 828 | /* Functions are never in the small data area. Duh. */ |
829 | if (TREE_CODE (exp) == FUNCTION_DECL) | |
830 | return false; | |
831 | ||
6ca5d410 | 832 | /* COMMON symbols are never small data. */ |
833 | if (TREE_CODE (exp) == VAR_DECL && DECL_COMMON (exp)) | |
834 | return false; | |
835 | ||
52470889 | 836 | if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) |
837 | { | |
738a6bda | 838 | const char *section = DECL_SECTION_NAME (exp); |
52470889 | 839 | if (strcmp (section, ".sdata") == 0 |
840 | || strcmp (section, ".sbss") == 0) | |
841 | return true; | |
842 | } | |
843 | else | |
844 | { | |
845 | HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); | |
846 | ||
847 | /* If this is an incomplete type with size 0, then we can't put it | |
848 | in sdata because it might be too big when completed. */ | |
13a54dd9 | 849 | if (size > 0 && size <= g_switch_value) |
52470889 | 850 | return true; |
851 | } | |
852 | ||
853 | return false; | |
854 | } | |
855 | ||
cf73d31f | 856 | #if TARGET_ABI_OPEN_VMS |
656ad977 | 857 | static bool |
3754d046 | 858 | vms_valid_pointer_mode (machine_mode mode) |
656ad977 | 859 | { |
860 | return (mode == SImode || mode == DImode); | |
861 | } | |
862 | ||
cf73d31f | 863 | static bool |
92643d95 | 864 | alpha_linkage_symbol_p (const char *symname) |
cf73d31f | 865 | { |
866 | int symlen = strlen (symname); | |
867 | ||
868 | if (symlen > 4) | |
869 | return strcmp (&symname [symlen - 4], "..lk") == 0; | |
870 | ||
871 | return false; | |
872 | } | |
873 | ||
874 | #define LINKAGE_SYMBOL_REF_P(X) \ | |
875 | ((GET_CODE (X) == SYMBOL_REF \ | |
876 | && alpha_linkage_symbol_p (XSTR (X, 0))) \ | |
877 | || (GET_CODE (X) == CONST \ | |
878 | && GET_CODE (XEXP (X, 0)) == PLUS \ | |
879 | && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF \ | |
880 | && alpha_linkage_symbol_p (XSTR (XEXP (XEXP (X, 0), 0), 0)))) | |
881 | #endif | |
882 | ||
24b3c0ed | 883 | /* legitimate_address_p recognizes an RTL expression that is a valid |
884 | memory address for an instruction. The MODE argument is the | |
885 | machine mode for the MEM expression that wants to use this address. | |
886 | ||
887 | For Alpha, we have either a constant address or the sum of a | |
888 | register and a constant address, or just a register. For DImode, | |
889 | any of those forms can be surrounded with an AND that clear the | |
890 | low-order three bits; this is an "unaligned" access. */ | |
891 | ||
fd50b071 | 892 | static bool |
3754d046 | 893 | alpha_legitimate_address_p (machine_mode mode, rtx x, bool strict) |
24b3c0ed | 894 | { |
895 | /* If this is an ldq_u type address, discard the outer AND. */ | |
896 | if (mode == DImode | |
897 | && GET_CODE (x) == AND | |
c933fb42 | 898 | && CONST_INT_P (XEXP (x, 1)) |
24b3c0ed | 899 | && INTVAL (XEXP (x, 1)) == -8) |
900 | x = XEXP (x, 0); | |
901 | ||
902 | /* Discard non-paradoxical subregs. */ | |
903 | if (GET_CODE (x) == SUBREG | |
904 | && (GET_MODE_SIZE (GET_MODE (x)) | |
905 | < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) | |
906 | x = SUBREG_REG (x); | |
907 | ||
908 | /* Unadorned general registers are valid. */ | |
909 | if (REG_P (x) | |
910 | && (strict | |
911 | ? STRICT_REG_OK_FOR_BASE_P (x) | |
912 | : NONSTRICT_REG_OK_FOR_BASE_P (x))) | |
913 | return true; | |
914 | ||
915 | /* Constant addresses (i.e. +/- 32k) are valid. */ | |
916 | if (CONSTANT_ADDRESS_P (x)) | |
917 | return true; | |
918 | ||
cf73d31f | 919 | #if TARGET_ABI_OPEN_VMS |
920 | if (LINKAGE_SYMBOL_REF_P (x)) | |
921 | return true; | |
922 | #endif | |
923 | ||
24b3c0ed | 924 | /* Register plus a small constant offset is valid. */ |
925 | if (GET_CODE (x) == PLUS) | |
926 | { | |
927 | rtx ofs = XEXP (x, 1); | |
928 | x = XEXP (x, 0); | |
929 | ||
930 | /* Discard non-paradoxical subregs. */ | |
931 | if (GET_CODE (x) == SUBREG | |
932 | && (GET_MODE_SIZE (GET_MODE (x)) | |
933 | < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) | |
934 | x = SUBREG_REG (x); | |
935 | ||
936 | if (REG_P (x)) | |
937 | { | |
938 | if (! strict | |
939 | && NONSTRICT_REG_OK_FP_BASE_P (x) | |
c933fb42 | 940 | && CONST_INT_P (ofs)) |
24b3c0ed | 941 | return true; |
942 | if ((strict | |
943 | ? STRICT_REG_OK_FOR_BASE_P (x) | |
944 | : NONSTRICT_REG_OK_FOR_BASE_P (x)) | |
945 | && CONSTANT_ADDRESS_P (ofs)) | |
946 | return true; | |
947 | } | |
24b3c0ed | 948 | } |
949 | ||
d6c48eee | 950 | /* If we're managing explicit relocations, LO_SUM is valid, as are small |
951 | data symbols. Avoid explicit relocations of modes larger than word | |
952 | mode since i.e. $LC0+8($1) can fold around +/- 32k offset. */ | |
953 | else if (TARGET_EXPLICIT_RELOCS | |
954 | && GET_MODE_SIZE (mode) <= UNITS_PER_WORD) | |
1f0ce6a6 | 955 | { |
f5a60074 | 956 | if (small_symbolic_operand (x, Pmode)) |
1f0ce6a6 | 957 | return true; |
f5a60074 | 958 | |
959 | if (GET_CODE (x) == LO_SUM) | |
960 | { | |
961 | rtx ofs = XEXP (x, 1); | |
962 | x = XEXP (x, 0); | |
963 | ||
964 | /* Discard non-paradoxical subregs. */ | |
965 | if (GET_CODE (x) == SUBREG | |
966 | && (GET_MODE_SIZE (GET_MODE (x)) | |
967 | < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) | |
968 | x = SUBREG_REG (x); | |
969 | ||
970 | /* Must have a valid base register. */ | |
971 | if (! (REG_P (x) | |
972 | && (strict | |
973 | ? STRICT_REG_OK_FOR_BASE_P (x) | |
974 | : NONSTRICT_REG_OK_FOR_BASE_P (x)))) | |
975 | return false; | |
976 | ||
977 | /* The symbol must be local. */ | |
5f7b9df8 | 978 | if (local_symbolic_operand (ofs, Pmode) |
979 | || dtp32_symbolic_operand (ofs, Pmode) | |
980 | || tp32_symbolic_operand (ofs, Pmode)) | |
f5a60074 | 981 | return true; |
982 | } | |
1f0ce6a6 | 983 | } |
984 | ||
24b3c0ed | 985 | return false; |
986 | } | |
987 | ||
09a1f342 | 988 | /* Build the SYMBOL_REF for __tls_get_addr. */ |
989 | ||
990 | static GTY(()) rtx tls_get_addr_libfunc; | |
991 | ||
992 | static rtx | |
92643d95 | 993 | get_tls_get_addr (void) |
09a1f342 | 994 | { |
995 | if (!tls_get_addr_libfunc) | |
996 | tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr"); | |
997 | return tls_get_addr_libfunc; | |
998 | } | |
999 | ||
0d50f0b7 | 1000 | /* Try machine-dependent ways of modifying an illegitimate address |
1001 | to be legitimate. If we find one, return the new, valid address. */ | |
1002 | ||
41e3a0c7 | 1003 | static rtx |
3754d046 | 1004 | alpha_legitimize_address_1 (rtx x, rtx scratch, machine_mode mode) |
0d50f0b7 | 1005 | { |
1006 | HOST_WIDE_INT addend; | |
1007 | ||
1008 | /* If the address is (plus reg const_int) and the CONST_INT is not a | |
1009 | valid offset, compute the high part of the constant and add it to | |
1010 | the register. Then our address is (plus temp low-part-const). */ | |
1011 | if (GET_CODE (x) == PLUS | |
c933fb42 | 1012 | && REG_P (XEXP (x, 0)) |
1013 | && CONST_INT_P (XEXP (x, 1)) | |
0d50f0b7 | 1014 | && ! CONSTANT_ADDRESS_P (XEXP (x, 1))) |
1015 | { | |
1016 | addend = INTVAL (XEXP (x, 1)); | |
1017 | x = XEXP (x, 0); | |
1018 | goto split_addend; | |
1019 | } | |
1020 | ||
1021 | /* If the address is (const (plus FOO const_int)), find the low-order | |
1022 | part of the CONST_INT. Then load FOO plus any high-order part of the | |
1023 | CONST_INT into a register. Our address is (plus reg low-part-const). | |
1024 | This is done to reduce the number of GOT entries. */ | |
e1ba4a27 | 1025 | if (can_create_pseudo_p () |
f5a60074 | 1026 | && GET_CODE (x) == CONST |
0d50f0b7 | 1027 | && GET_CODE (XEXP (x, 0)) == PLUS |
c933fb42 | 1028 | && CONST_INT_P (XEXP (XEXP (x, 0), 1))) |
0d50f0b7 | 1029 | { |
1030 | addend = INTVAL (XEXP (XEXP (x, 0), 1)); | |
1031 | x = force_reg (Pmode, XEXP (XEXP (x, 0), 0)); | |
1032 | goto split_addend; | |
1033 | } | |
1034 | ||
1035 | /* If we have a (plus reg const), emit the load as in (2), then add | |
1036 | the two registers, and finally generate (plus reg low-part-const) as | |
1037 | our address. */ | |
e1ba4a27 | 1038 | if (can_create_pseudo_p () |
f5a60074 | 1039 | && GET_CODE (x) == PLUS |
c933fb42 | 1040 | && REG_P (XEXP (x, 0)) |
0d50f0b7 | 1041 | && GET_CODE (XEXP (x, 1)) == CONST |
1042 | && GET_CODE (XEXP (XEXP (x, 1), 0)) == PLUS | |
c933fb42 | 1043 | && CONST_INT_P (XEXP (XEXP (XEXP (x, 1), 0), 1))) |
0d50f0b7 | 1044 | { |
1045 | addend = INTVAL (XEXP (XEXP (XEXP (x, 1), 0), 1)); | |
1046 | x = expand_simple_binop (Pmode, PLUS, XEXP (x, 0), | |
1047 | XEXP (XEXP (XEXP (x, 1), 0), 0), | |
1048 | NULL_RTX, 1, OPTAB_LIB_WIDEN); | |
1049 | goto split_addend; | |
1050 | } | |
1051 | ||
d6c48eee | 1052 | /* If this is a local symbol, split the address into HIGH/LO_SUM parts. |
1053 | Avoid modes larger than word mode since i.e. $LC0+8($1) can fold | |
1054 | around +/- 32k offset. */ | |
1055 | if (TARGET_EXPLICIT_RELOCS | |
1056 | && GET_MODE_SIZE (mode) <= UNITS_PER_WORD | |
1057 | && symbolic_operand (x, Pmode)) | |
1f0ce6a6 | 1058 | { |
5f7b9df8 | 1059 | rtx r0, r16, eqv, tga, tp, insn, dest, seq; |
1060 | ||
1061 | switch (tls_symbolic_operand_type (x)) | |
1062 | { | |
dda53cd5 | 1063 | case TLS_MODEL_NONE: |
1064 | break; | |
1065 | ||
5f7b9df8 | 1066 | case TLS_MODEL_GLOBAL_DYNAMIC: |
1067 | start_sequence (); | |
1068 | ||
1069 | r0 = gen_rtx_REG (Pmode, 0); | |
1070 | r16 = gen_rtx_REG (Pmode, 16); | |
09a1f342 | 1071 | tga = get_tls_get_addr (); |
5f7b9df8 | 1072 | dest = gen_reg_rtx (Pmode); |
1073 | seq = GEN_INT (alpha_next_sequence_number++); | |
9e7454d0 | 1074 | |
5f7b9df8 | 1075 | emit_insn (gen_movdi_er_tlsgd (r16, pic_offset_table_rtx, x, seq)); |
1076 | insn = gen_call_value_osf_tlsgd (r0, tga, seq); | |
1077 | insn = emit_call_insn (insn); | |
9c2a0c05 | 1078 | RTL_CONST_CALL_P (insn) = 1; |
5f7b9df8 | 1079 | use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16); |
1080 | ||
1081 | insn = get_insns (); | |
1082 | end_sequence (); | |
1083 | ||
1084 | emit_libcall_block (insn, dest, r0, x); | |
1085 | return dest; | |
1086 | ||
1087 | case TLS_MODEL_LOCAL_DYNAMIC: | |
1088 | start_sequence (); | |
1089 | ||
1090 | r0 = gen_rtx_REG (Pmode, 0); | |
1091 | r16 = gen_rtx_REG (Pmode, 16); | |
09a1f342 | 1092 | tga = get_tls_get_addr (); |
5f7b9df8 | 1093 | scratch = gen_reg_rtx (Pmode); |
1094 | seq = GEN_INT (alpha_next_sequence_number++); | |
1095 | ||
1096 | emit_insn (gen_movdi_er_tlsldm (r16, pic_offset_table_rtx, seq)); | |
1097 | insn = gen_call_value_osf_tlsldm (r0, tga, seq); | |
1098 | insn = emit_call_insn (insn); | |
9c2a0c05 | 1099 | RTL_CONST_CALL_P (insn) = 1; |
5f7b9df8 | 1100 | use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16); |
1101 | ||
1102 | insn = get_insns (); | |
1103 | end_sequence (); | |
1104 | ||
1105 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), | |
1106 | UNSPEC_TLSLDM_CALL); | |
1107 | emit_libcall_block (insn, scratch, r0, eqv); | |
1108 | ||
1109 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPREL); | |
1110 | eqv = gen_rtx_CONST (Pmode, eqv); | |
1111 | ||
1112 | if (alpha_tls_size == 64) | |
1113 | { | |
1114 | dest = gen_reg_rtx (Pmode); | |
d1f9b275 | 1115 | emit_insn (gen_rtx_SET (dest, eqv)); |
5f7b9df8 | 1116 | emit_insn (gen_adddi3 (dest, dest, scratch)); |
1117 | return dest; | |
1118 | } | |
1119 | if (alpha_tls_size == 32) | |
1120 | { | |
1121 | insn = gen_rtx_HIGH (Pmode, eqv); | |
1122 | insn = gen_rtx_PLUS (Pmode, scratch, insn); | |
1123 | scratch = gen_reg_rtx (Pmode); | |
d1f9b275 | 1124 | emit_insn (gen_rtx_SET (scratch, insn)); |
5f7b9df8 | 1125 | } |
1126 | return gen_rtx_LO_SUM (Pmode, scratch, eqv); | |
1127 | ||
1128 | case TLS_MODEL_INITIAL_EXEC: | |
1129 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL); | |
1130 | eqv = gen_rtx_CONST (Pmode, eqv); | |
1131 | tp = gen_reg_rtx (Pmode); | |
1132 | scratch = gen_reg_rtx (Pmode); | |
1133 | dest = gen_reg_rtx (Pmode); | |
1134 | ||
badaa04c | 1135 | emit_insn (gen_get_thread_pointerdi (tp)); |
d1f9b275 | 1136 | emit_insn (gen_rtx_SET (scratch, eqv)); |
5f7b9df8 | 1137 | emit_insn (gen_adddi3 (dest, tp, scratch)); |
1138 | return dest; | |
1139 | ||
1140 | case TLS_MODEL_LOCAL_EXEC: | |
1141 | eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL); | |
1142 | eqv = gen_rtx_CONST (Pmode, eqv); | |
1143 | tp = gen_reg_rtx (Pmode); | |
1144 | ||
badaa04c | 1145 | emit_insn (gen_get_thread_pointerdi (tp)); |
5f7b9df8 | 1146 | if (alpha_tls_size == 32) |
1147 | { | |
1148 | insn = gen_rtx_HIGH (Pmode, eqv); | |
1149 | insn = gen_rtx_PLUS (Pmode, tp, insn); | |
1150 | tp = gen_reg_rtx (Pmode); | |
d1f9b275 | 1151 | emit_insn (gen_rtx_SET (tp, insn)); |
5f7b9df8 | 1152 | } |
1153 | return gen_rtx_LO_SUM (Pmode, tp, eqv); | |
dda53cd5 | 1154 | |
1155 | default: | |
1156 | gcc_unreachable (); | |
5f7b9df8 | 1157 | } |
1158 | ||
8afb6db4 | 1159 | if (local_symbolic_operand (x, Pmode)) |
1160 | { | |
1161 | if (small_symbolic_operand (x, Pmode)) | |
f5a60074 | 1162 | return x; |
8afb6db4 | 1163 | else |
1164 | { | |
e1ba4a27 | 1165 | if (can_create_pseudo_p ()) |
f5a60074 | 1166 | scratch = gen_reg_rtx (Pmode); |
d1f9b275 | 1167 | emit_insn (gen_rtx_SET (scratch, gen_rtx_HIGH (Pmode, x))); |
f5a60074 | 1168 | return gen_rtx_LO_SUM (Pmode, scratch, x); |
8afb6db4 | 1169 | } |
5dcb037d | 1170 | } |
1f0ce6a6 | 1171 | } |
1172 | ||
0d50f0b7 | 1173 | return NULL; |
1174 | ||
1175 | split_addend: | |
1176 | { | |
f5a60074 | 1177 | HOST_WIDE_INT low, high; |
1178 | ||
1179 | low = ((addend & 0xffff) ^ 0x8000) - 0x8000; | |
1180 | addend -= low; | |
1181 | high = ((addend & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
1182 | addend -= high; | |
1183 | ||
1184 | if (addend) | |
1185 | x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (addend), | |
e1ba4a27 | 1186 | (!can_create_pseudo_p () ? scratch : NULL_RTX), |
f5a60074 | 1187 | 1, OPTAB_LIB_WIDEN); |
1188 | if (high) | |
1189 | x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (high), | |
e1ba4a27 | 1190 | (!can_create_pseudo_p () ? scratch : NULL_RTX), |
f5a60074 | 1191 | 1, OPTAB_LIB_WIDEN); |
1192 | ||
29c05e22 | 1193 | return plus_constant (Pmode, x, low); |
0d50f0b7 | 1194 | } |
1195 | } | |
1196 | ||
41e3a0c7 | 1197 | |
1198 | /* Try machine-dependent ways of modifying an illegitimate address | |
1199 | to be legitimate. Return X or the new, valid address. */ | |
1200 | ||
1201 | static rtx | |
1202 | alpha_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, | |
3754d046 | 1203 | machine_mode mode) |
41e3a0c7 | 1204 | { |
1205 | rtx new_x = alpha_legitimize_address_1 (x, NULL_RTX, mode); | |
1206 | return new_x ? new_x : x; | |
1207 | } | |
1208 | ||
649bdf00 | 1209 | /* Return true if ADDR has an effect that depends on the machine mode it |
1210 | is used for. On the Alpha this is true only for the unaligned modes. | |
1211 | We can simplify the test since we know that the address must be valid. */ | |
1212 | ||
1213 | static bool | |
4e27ffd0 | 1214 | alpha_mode_dependent_address_p (const_rtx addr, |
1215 | addr_space_t as ATTRIBUTE_UNUSED) | |
649bdf00 | 1216 | { |
1217 | return GET_CODE (addr) == AND; | |
1218 | } | |
1219 | ||
c0da4391 | 1220 | /* Primarily this is required for TLS symbols, but given that our move |
1221 | patterns *ought* to be able to handle any symbol at any time, we | |
1222 | should never be spilling symbolic operands to the constant pool, ever. */ | |
1223 | ||
1224 | static bool | |
3754d046 | 1225 | alpha_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) |
c0da4391 | 1226 | { |
1227 | enum rtx_code code = GET_CODE (x); | |
1228 | return code == SYMBOL_REF || code == LABEL_REF || code == CONST; | |
1229 | } | |
1230 | ||
805e22b2 | 1231 | /* We do not allow indirect calls to be optimized into sibling calls, nor |
9bdcc1e5 | 1232 | can we allow a call to a function with a different GP to be optimized |
1233 | into a sibcall. */ | |
1234 | ||
805e22b2 | 1235 | static bool |
92643d95 | 1236 | alpha_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) |
805e22b2 | 1237 | { |
9bdcc1e5 | 1238 | /* Can't do indirect tail calls, since we don't know if the target |
1239 | uses the same GP. */ | |
1240 | if (!decl) | |
1241 | return false; | |
1242 | ||
1243 | /* Otherwise, we can make a tail call if the target function shares | |
1244 | the same GP. */ | |
1245 | return decl_has_samegp (decl); | |
805e22b2 | 1246 | } |
1247 | ||
c0fe2f4a | 1248 | bool |
1249 | some_small_symbolic_operand_int (rtx x) | |
367e2ab3 | 1250 | { |
c0fe2f4a | 1251 | subrtx_var_iterator::array_type array; |
1252 | FOR_EACH_SUBRTX_VAR (iter, array, x, ALL) | |
1253 | { | |
1254 | rtx x = *iter; | |
1255 | /* Don't re-split. */ | |
1256 | if (GET_CODE (x) == LO_SUM) | |
1257 | iter.skip_subrtxes (); | |
1258 | else if (small_symbolic_operand (x, Pmode)) | |
1259 | return true; | |
1260 | } | |
1261 | return false; | |
f5a60074 | 1262 | } |
1263 | ||
92643d95 | 1264 | rtx |
1265 | split_small_symbolic_operand (rtx x) | |
1266 | { | |
1267 | x = copy_insn (x); | |
97a30fee | 1268 | subrtx_ptr_iterator::array_type array; |
1269 | FOR_EACH_SUBRTX_PTR (iter, array, &x, ALL) | |
1270 | { | |
1271 | rtx *ptr = *iter; | |
1272 | rtx x = *ptr; | |
1273 | /* Don't re-split. */ | |
1274 | if (GET_CODE (x) == LO_SUM) | |
1275 | iter.skip_subrtxes (); | |
1276 | else if (small_symbolic_operand (x, Pmode)) | |
1277 | { | |
1278 | *ptr = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, x); | |
1279 | iter.skip_subrtxes (); | |
1280 | } | |
1281 | } | |
92643d95 | 1282 | return x; |
1283 | } | |
1284 | ||
2f58af60 | 1285 | /* Indicate that INSN cannot be duplicated. This is true for any insn |
1286 | that we've marked with gpdisp relocs, since those have to stay in | |
1287 | 1-1 correspondence with one another. | |
1288 | ||
5910bb95 | 1289 | Technically we could copy them if we could set up a mapping from one |
2f58af60 | 1290 | sequence number to another, across the set of insns to be duplicated. |
1291 | This seems overly complicated and error-prone since interblock motion | |
b55f2ed8 | 1292 | from sched-ebb could move one of the pair of insns to a different block. |
1293 | ||
1294 | Also cannot allow jsr insns to be duplicated. If they throw exceptions, | |
1295 | then they'll be in a different block from their ldgp. Which could lead | |
1296 | the bb reorder code to think that it would be ok to copy just the block | |
1297 | containing the call and branch to the block containing the ldgp. */ | |
2f58af60 | 1298 | |
1299 | static bool | |
18282db0 | 1300 | alpha_cannot_copy_insn_p (rtx_insn *insn) |
2f58af60 | 1301 | { |
2f58af60 | 1302 | if (!reload_completed || !TARGET_EXPLICIT_RELOCS) |
1303 | return false; | |
b55f2ed8 | 1304 | if (recog_memoized (insn) >= 0) |
1305 | return get_attr_cannot_copy (insn); | |
1306 | else | |
2f58af60 | 1307 | return false; |
2f58af60 | 1308 | } |
1309 | ||
9e7454d0 | 1310 | |
0d50f0b7 | 1311 | /* Try a machine-dependent way of reloading an illegitimate address |
1312 | operand. If we find one, push the reload and return the new rtx. */ | |
9e7454d0 | 1313 | |
0d50f0b7 | 1314 | rtx |
92643d95 | 1315 | alpha_legitimize_reload_address (rtx x, |
3754d046 | 1316 | machine_mode mode ATTRIBUTE_UNUSED, |
92643d95 | 1317 | int opnum, int type, |
1318 | int ind_levels ATTRIBUTE_UNUSED) | |
0d50f0b7 | 1319 | { |
1320 | /* We must recognize output that we have already generated ourselves. */ | |
1321 | if (GET_CODE (x) == PLUS | |
1322 | && GET_CODE (XEXP (x, 0)) == PLUS | |
c933fb42 | 1323 | && REG_P (XEXP (XEXP (x, 0), 0)) |
1324 | && CONST_INT_P (XEXP (XEXP (x, 0), 1)) | |
1325 | && CONST_INT_P (XEXP (x, 1))) | |
0d50f0b7 | 1326 | { |
1327 | push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, | |
1328 | BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, | |
0a48089c | 1329 | opnum, (enum reload_type) type); |
0d50f0b7 | 1330 | return x; |
1331 | } | |
1332 | ||
1333 | /* We wish to handle large displacements off a base register by | |
1334 | splitting the addend across an ldah and the mem insn. This | |
1335 | cuts number of extra insns needed from 3 to 1. */ | |
1336 | if (GET_CODE (x) == PLUS | |
c933fb42 | 1337 | && REG_P (XEXP (x, 0)) |
0d50f0b7 | 1338 | && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER |
1339 | && REGNO_OK_FOR_BASE_P (REGNO (XEXP (x, 0))) | |
7bc95bfb | 1340 | && CONST_INT_P (XEXP (x, 1))) |
0d50f0b7 | 1341 | { |
1342 | HOST_WIDE_INT val = INTVAL (XEXP (x, 1)); | |
1343 | HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000; | |
1344 | HOST_WIDE_INT high | |
1345 | = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
1346 | ||
1347 | /* Check for 32-bit overflow. */ | |
1348 | if (high + low != val) | |
1349 | return NULL_RTX; | |
1350 | ||
1351 | /* Reload the high part into a base reg; leave the low part | |
1352 | in the mem directly. */ | |
1353 | x = gen_rtx_PLUS (GET_MODE (x), | |
1354 | gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0), | |
1355 | GEN_INT (high)), | |
1356 | GEN_INT (low)); | |
1357 | ||
1358 | push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, | |
1359 | BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, | |
0a48089c | 1360 | opnum, (enum reload_type) type); |
0d50f0b7 | 1361 | return x; |
1362 | } | |
1363 | ||
1364 | return NULL_RTX; | |
1365 | } | |
1366 | \f | |
fab7adbf | 1367 | /* Compute a (partial) cost for rtx X. Return true if the complete |
1368 | cost has been computed, and false if subexpressions should be | |
1369 | scanned. In either case, *TOTAL contains the cost result. */ | |
1370 | ||
1371 | static bool | |
20d892d1 | 1372 | alpha_rtx_costs (rtx x, int code, int outer_code, int opno, int *total, |
f529eb25 | 1373 | bool speed) |
fab7adbf | 1374 | { |
3754d046 | 1375 | machine_mode mode = GET_MODE (x); |
fab7adbf | 1376 | bool float_mode_p = FLOAT_MODE_P (mode); |
d7cf2331 | 1377 | const struct alpha_rtx_cost_data *cost_data; |
1378 | ||
f529eb25 | 1379 | if (!speed) |
d7cf2331 | 1380 | cost_data = &alpha_rtx_cost_size; |
1381 | else | |
fb64edde | 1382 | cost_data = &alpha_rtx_cost_data[alpha_tune]; |
fab7adbf | 1383 | |
1384 | switch (code) | |
1385 | { | |
d7cf2331 | 1386 | case CONST_INT: |
fab7adbf | 1387 | /* If this is an 8-bit constant, return zero since it can be used |
1388 | nearly anywhere with no cost. If it is a valid operand for an | |
1389 | ADD or AND, likewise return 0 if we know it will be used in that | |
1390 | context. Otherwise, return 2 since it might be used there later. | |
1391 | All other constants take at least two insns. */ | |
fab7adbf | 1392 | if (INTVAL (x) >= 0 && INTVAL (x) < 256) |
1393 | { | |
1394 | *total = 0; | |
1395 | return true; | |
1396 | } | |
8e262b5e | 1397 | /* FALLTHRU */ |
fab7adbf | 1398 | |
1399 | case CONST_DOUBLE: | |
5c5c1f00 | 1400 | case CONST_WIDE_INT: |
fab7adbf | 1401 | if (x == CONST0_RTX (mode)) |
1402 | *total = 0; | |
1403 | else if ((outer_code == PLUS && add_operand (x, VOIDmode)) | |
1404 | || (outer_code == AND && and_operand (x, VOIDmode))) | |
1405 | *total = 0; | |
1406 | else if (add_operand (x, VOIDmode) || and_operand (x, VOIDmode)) | |
1407 | *total = 2; | |
1408 | else | |
1409 | *total = COSTS_N_INSNS (2); | |
1410 | return true; | |
9e7454d0 | 1411 | |
fab7adbf | 1412 | case CONST: |
1413 | case SYMBOL_REF: | |
1414 | case LABEL_REF: | |
1415 | if (TARGET_EXPLICIT_RELOCS && small_symbolic_operand (x, VOIDmode)) | |
1416 | *total = COSTS_N_INSNS (outer_code != MEM); | |
1417 | else if (TARGET_EXPLICIT_RELOCS && local_symbolic_operand (x, VOIDmode)) | |
1418 | *total = COSTS_N_INSNS (1 + (outer_code != MEM)); | |
1419 | else if (tls_symbolic_operand_type (x)) | |
1420 | /* Estimate of cost for call_pal rduniq. */ | |
d7cf2331 | 1421 | /* ??? How many insns do we emit here? More than one... */ |
fab7adbf | 1422 | *total = COSTS_N_INSNS (15); |
1423 | else | |
1424 | /* Otherwise we do a load from the GOT. */ | |
f529eb25 | 1425 | *total = COSTS_N_INSNS (!speed ? 1 : alpha_memory_latency); |
fab7adbf | 1426 | return true; |
9e7454d0 | 1427 | |
91bc47b0 | 1428 | case HIGH: |
1429 | /* This is effectively an add_operand. */ | |
1430 | *total = 2; | |
1431 | return true; | |
1432 | ||
fab7adbf | 1433 | case PLUS: |
1434 | case MINUS: | |
1435 | if (float_mode_p) | |
d7cf2331 | 1436 | *total = cost_data->fp_add; |
fab7adbf | 1437 | else if (GET_CODE (XEXP (x, 0)) == MULT |
1438 | && const48_operand (XEXP (XEXP (x, 0), 1), VOIDmode)) | |
1439 | { | |
0a48089c | 1440 | *total = (rtx_cost (XEXP (XEXP (x, 0), 0), |
20d892d1 | 1441 | (enum rtx_code) outer_code, opno, speed) |
0a48089c | 1442 | + rtx_cost (XEXP (x, 1), |
20d892d1 | 1443 | (enum rtx_code) outer_code, opno, speed) |
0a48089c | 1444 | + COSTS_N_INSNS (1)); |
fab7adbf | 1445 | return true; |
1446 | } | |
1447 | return false; | |
1448 | ||
1449 | case MULT: | |
1450 | if (float_mode_p) | |
d7cf2331 | 1451 | *total = cost_data->fp_mult; |
fab7adbf | 1452 | else if (mode == DImode) |
d7cf2331 | 1453 | *total = cost_data->int_mult_di; |
fab7adbf | 1454 | else |
d7cf2331 | 1455 | *total = cost_data->int_mult_si; |
fab7adbf | 1456 | return false; |
1457 | ||
1458 | case ASHIFT: | |
c933fb42 | 1459 | if (CONST_INT_P (XEXP (x, 1)) |
fab7adbf | 1460 | && INTVAL (XEXP (x, 1)) <= 3) |
1461 | { | |
1462 | *total = COSTS_N_INSNS (1); | |
1463 | return false; | |
1464 | } | |
8e262b5e | 1465 | /* FALLTHRU */ |
fab7adbf | 1466 | |
1467 | case ASHIFTRT: | |
1468 | case LSHIFTRT: | |
d7cf2331 | 1469 | *total = cost_data->int_shift; |
fab7adbf | 1470 | return false; |
1471 | ||
1472 | case IF_THEN_ELSE: | |
1473 | if (float_mode_p) | |
d7cf2331 | 1474 | *total = cost_data->fp_add; |
fab7adbf | 1475 | else |
d7cf2331 | 1476 | *total = cost_data->int_cmov; |
fab7adbf | 1477 | return false; |
1478 | ||
1479 | case DIV: | |
1480 | case UDIV: | |
1481 | case MOD: | |
1482 | case UMOD: | |
1483 | if (!float_mode_p) | |
d7cf2331 | 1484 | *total = cost_data->int_div; |
fab7adbf | 1485 | else if (mode == SFmode) |
d7cf2331 | 1486 | *total = cost_data->fp_div_sf; |
fab7adbf | 1487 | else |
d7cf2331 | 1488 | *total = cost_data->fp_div_df; |
fab7adbf | 1489 | return false; |
1490 | ||
1491 | case MEM: | |
f529eb25 | 1492 | *total = COSTS_N_INSNS (!speed ? 1 : alpha_memory_latency); |
fab7adbf | 1493 | return true; |
1494 | ||
1495 | case NEG: | |
1496 | if (! float_mode_p) | |
1497 | { | |
1498 | *total = COSTS_N_INSNS (1); | |
1499 | return false; | |
1500 | } | |
8e262b5e | 1501 | /* FALLTHRU */ |
fab7adbf | 1502 | |
1503 | case ABS: | |
1504 | if (! float_mode_p) | |
1505 | { | |
d7cf2331 | 1506 | *total = COSTS_N_INSNS (1) + cost_data->int_cmov; |
fab7adbf | 1507 | return false; |
1508 | } | |
8e262b5e | 1509 | /* FALLTHRU */ |
fab7adbf | 1510 | |
1511 | case FLOAT: | |
1512 | case UNSIGNED_FLOAT: | |
1513 | case FIX: | |
1514 | case UNSIGNED_FIX: | |
fab7adbf | 1515 | case FLOAT_TRUNCATE: |
d7cf2331 | 1516 | *total = cost_data->fp_add; |
fab7adbf | 1517 | return false; |
1518 | ||
5fc4edde | 1519 | case FLOAT_EXTEND: |
c933fb42 | 1520 | if (MEM_P (XEXP (x, 0))) |
5fc4edde | 1521 | *total = 0; |
1522 | else | |
1523 | *total = cost_data->fp_add; | |
1524 | return false; | |
1525 | ||
fab7adbf | 1526 | default: |
1527 | return false; | |
1528 | } | |
1529 | } | |
1530 | \f | |
bf2a98b3 | 1531 | /* REF is an alignable memory location. Place an aligned SImode |
1532 | reference into *PALIGNED_MEM and the number of bits to shift into | |
a99a652b | 1533 | *PBITNUM. SCRATCH is a free register for use in reloading out |
1534 | of range stack slots. */ | |
bf2a98b3 | 1535 | |
1536 | void | |
92643d95 | 1537 | get_aligned_mem (rtx ref, rtx *paligned_mem, rtx *pbitnum) |
bf2a98b3 | 1538 | { |
1539 | rtx base; | |
a3fed3d2 | 1540 | HOST_WIDE_INT disp, offset; |
bf2a98b3 | 1541 | |
c933fb42 | 1542 | gcc_assert (MEM_P (ref)); |
bf2a98b3 | 1543 | |
b4e5c0d9 | 1544 | if (reload_in_progress) |
a99a652b | 1545 | { |
cc215844 | 1546 | base = find_replacement (&XEXP (ref, 0)); |
4d10b463 | 1547 | gcc_assert (memory_address_p (GET_MODE (ref), base)); |
a99a652b | 1548 | } |
bf2a98b3 | 1549 | else |
4d10b463 | 1550 | base = XEXP (ref, 0); |
bf2a98b3 | 1551 | |
1552 | if (GET_CODE (base) == PLUS) | |
a3fed3d2 | 1553 | disp = INTVAL (XEXP (base, 1)), base = XEXP (base, 0); |
1554 | else | |
1555 | disp = 0; | |
1556 | ||
1557 | /* Find the byte offset within an aligned word. If the memory itself is | |
1558 | claimed to be aligned, believe it. Otherwise, aligned_memory_operand | |
1559 | will have examined the base register and determined it is aligned, and | |
1560 | thus displacements from it are naturally alignable. */ | |
1561 | if (MEM_ALIGN (ref) >= 32) | |
1562 | offset = 0; | |
1563 | else | |
1564 | offset = disp & 3; | |
bf2a98b3 | 1565 | |
5e46378b | 1566 | /* The location should not cross aligned word boundary. */ |
1567 | gcc_assert (offset + GET_MODE_SIZE (GET_MODE (ref)) | |
1568 | <= GET_MODE_SIZE (SImode)); | |
1569 | ||
a3fed3d2 | 1570 | /* Access the entire aligned word. */ |
1571 | *paligned_mem = widen_memory_access (ref, SImode, -offset); | |
bf2a98b3 | 1572 | |
a3fed3d2 | 1573 | /* Convert the byte offset within the word to a bit offset. */ |
9bab4302 | 1574 | offset *= BITS_PER_UNIT; |
a3fed3d2 | 1575 | *pbitnum = GEN_INT (offset); |
bf2a98b3 | 1576 | } |
1577 | ||
9e7454d0 | 1578 | /* Similar, but just get the address. Handle the two reload cases. |
b044f41c | 1579 | Add EXTRA_OFFSET to the address we return. */ |
bf2a98b3 | 1580 | |
1581 | rtx | |
0934d969 | 1582 | get_unaligned_address (rtx ref) |
bf2a98b3 | 1583 | { |
1584 | rtx base; | |
1585 | HOST_WIDE_INT offset = 0; | |
1586 | ||
c933fb42 | 1587 | gcc_assert (MEM_P (ref)); |
bf2a98b3 | 1588 | |
b4e5c0d9 | 1589 | if (reload_in_progress) |
a99a652b | 1590 | { |
a99a652b | 1591 | base = find_replacement (&XEXP (ref, 0)); |
4d10b463 | 1592 | gcc_assert (memory_address_p (GET_MODE (ref), base)); |
a99a652b | 1593 | } |
bf2a98b3 | 1594 | else |
4d10b463 | 1595 | base = XEXP (ref, 0); |
bf2a98b3 | 1596 | |
1597 | if (GET_CODE (base) == PLUS) | |
1598 | offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0); | |
1599 | ||
29c05e22 | 1600 | return plus_constant (Pmode, base, offset); |
0934d969 | 1601 | } |
1602 | ||
1603 | /* Compute a value X, such that X & 7 == (ADDR + OFS) & 7. | |
1604 | X is always returned in a register. */ | |
1605 | ||
1606 | rtx | |
1607 | get_unaligned_offset (rtx addr, HOST_WIDE_INT ofs) | |
1608 | { | |
1609 | if (GET_CODE (addr) == PLUS) | |
1610 | { | |
1611 | ofs += INTVAL (XEXP (addr, 1)); | |
1612 | addr = XEXP (addr, 0); | |
1613 | } | |
1614 | ||
1615 | return expand_simple_binop (Pmode, PLUS, addr, GEN_INT (ofs & 7), | |
1616 | NULL_RTX, 1, OPTAB_LIB_WIDEN); | |
bf2a98b3 | 1617 | } |
14f7bc98 | 1618 | |
f5a60074 | 1619 | /* On the Alpha, all (non-symbolic) constants except zero go into |
9e7454d0 | 1620 | a floating-point register via memory. Note that we cannot |
8deb3959 | 1621 | return anything that is not a subset of RCLASS, and that some |
f5a60074 | 1622 | symbolic constants cannot be dropped to memory. */ |
1623 | ||
1624 | enum reg_class | |
8deb3959 | 1625 | alpha_preferred_reload_class(rtx x, enum reg_class rclass) |
f5a60074 | 1626 | { |
1627 | /* Zero is present in any register class. */ | |
1628 | if (x == CONST0_RTX (GET_MODE (x))) | |
8deb3959 | 1629 | return rclass; |
f5a60074 | 1630 | |
1631 | /* These sorts of constants we can easily drop to memory. */ | |
7bc95bfb | 1632 | if (CONST_SCALAR_INT_P (x) |
1633 | || CONST_DOUBLE_P (x) | |
91bc47b0 | 1634 | || GET_CODE (x) == CONST_VECTOR) |
f5a60074 | 1635 | { |
8deb3959 | 1636 | if (rclass == FLOAT_REGS) |
f5a60074 | 1637 | return NO_REGS; |
8deb3959 | 1638 | if (rclass == ALL_REGS) |
f5a60074 | 1639 | return GENERAL_REGS; |
8deb3959 | 1640 | return rclass; |
f5a60074 | 1641 | } |
1642 | ||
1643 | /* All other kinds of constants should not (and in the case of HIGH | |
1644 | cannot) be dropped to memory -- instead we use a GENERAL_REGS | |
1645 | secondary reload. */ | |
1646 | if (CONSTANT_P (x)) | |
8deb3959 | 1647 | return (rclass == ALL_REGS ? GENERAL_REGS : rclass); |
f5a60074 | 1648 | |
8deb3959 | 1649 | return rclass; |
f5a60074 | 1650 | } |
1651 | ||
0d96cd2b | 1652 | /* Inform reload about cases where moving X with a mode MODE to a register in |
8deb3959 | 1653 | RCLASS requires an extra scratch or immediate register. Return the class |
0d96cd2b | 1654 | needed for the immediate register. */ |
14f7bc98 | 1655 | |
964229b7 | 1656 | static reg_class_t |
1657 | alpha_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, | |
3754d046 | 1658 | machine_mode mode, secondary_reload_info *sri) |
14f7bc98 | 1659 | { |
964229b7 | 1660 | enum reg_class rclass = (enum reg_class) rclass_i; |
1661 | ||
0d96cd2b | 1662 | /* Loading and storing HImode or QImode values to and from memory |
1663 | usually requires a scratch register. */ | |
1664 | if (!TARGET_BWX && (mode == QImode || mode == HImode || mode == CQImode)) | |
d2494d49 | 1665 | { |
0d96cd2b | 1666 | if (any_memory_operand (x, mode)) |
d2494d49 | 1667 | { |
0d96cd2b | 1668 | if (in_p) |
1669 | { | |
1670 | if (!aligned_memory_operand (x, mode)) | |
6b531606 | 1671 | sri->icode = direct_optab_handler (reload_in_optab, mode); |
0d96cd2b | 1672 | } |
1673 | else | |
6b531606 | 1674 | sri->icode = direct_optab_handler (reload_out_optab, mode); |
0d96cd2b | 1675 | return NO_REGS; |
d2494d49 | 1676 | } |
1677 | } | |
14f7bc98 | 1678 | |
0d96cd2b | 1679 | /* We also cannot do integral arithmetic into FP regs, as might result |
1680 | from register elimination into a DImode fp register. */ | |
8deb3959 | 1681 | if (rclass == FLOAT_REGS) |
14f7bc98 | 1682 | { |
0d96cd2b | 1683 | if (MEM_P (x) && GET_CODE (XEXP (x, 0)) == AND) |
14f7bc98 | 1684 | return GENERAL_REGS; |
0d96cd2b | 1685 | if (in_p && INTEGRAL_MODE_P (mode) |
1686 | && !MEM_P (x) && !REG_P (x) && !CONST_INT_P (x)) | |
14f7bc98 | 1687 | return GENERAL_REGS; |
1688 | } | |
1689 | ||
1690 | return NO_REGS; | |
1691 | } | |
bf2a98b3 | 1692 | \f |
7ca8bc48 | 1693 | /* Given SEQ, which is an INSN list, look for any MEMs in either |
31d3e01c | 1694 | a SET_DEST or a SET_SRC and copy the in-struct, unchanging, and |
1695 | volatile flags from REF into each of the MEMs found. If REF is not | |
1696 | a MEM, don't do anything. */ | |
bf2a98b3 | 1697 | |
1698 | void | |
7ca8bc48 | 1699 | alpha_set_memflags (rtx seq, rtx ref) |
bf2a98b3 | 1700 | { |
91a55c11 | 1701 | rtx_insn *insn; |
849674a3 | 1702 | |
7ca8bc48 | 1703 | if (!MEM_P (ref)) |
bf2a98b3 | 1704 | return; |
1705 | ||
9e7454d0 | 1706 | /* This is only called from alpha.md, after having had something |
849674a3 | 1707 | generated from one of the insn patterns. So if everything is |
1708 | zero, the pattern is already up-to-date. */ | |
b04fab2a | 1709 | if (!MEM_VOLATILE_P (ref) |
b04fab2a | 1710 | && !MEM_NOTRAP_P (ref) |
1711 | && !MEM_READONLY_P (ref)) | |
849674a3 | 1712 | return; |
1713 | ||
70b88ec2 | 1714 | subrtx_var_iterator::array_type array; |
91a55c11 | 1715 | for (insn = as_a <rtx_insn *> (seq); insn; insn = NEXT_INSN (insn)) |
7ca8bc48 | 1716 | if (INSN_P (insn)) |
70b88ec2 | 1717 | FOR_EACH_SUBRTX_VAR (iter, array, PATTERN (insn), NONCONST) |
1718 | { | |
1719 | rtx x = *iter; | |
1720 | if (MEM_P (x)) | |
1721 | { | |
1722 | MEM_VOLATILE_P (x) = MEM_VOLATILE_P (ref); | |
1723 | MEM_NOTRAP_P (x) = MEM_NOTRAP_P (ref); | |
1724 | MEM_READONLY_P (x) = MEM_READONLY_P (ref); | |
1725 | /* Sadly, we cannot use alias sets because the extra | |
1726 | aliasing produced by the AND interferes. Given that | |
1727 | two-byte quantities are the only thing we would be | |
1728 | able to differentiate anyway, there does not seem to | |
1729 | be any point in convoluting the early out of the | |
1730 | alias check. */ | |
1731 | iter.skip_subrtxes (); | |
1732 | } | |
1733 | } | |
7ca8bc48 | 1734 | else |
1735 | gcc_unreachable (); | |
bf2a98b3 | 1736 | } |
1737 | \f | |
3754d046 | 1738 | static rtx alpha_emit_set_const (rtx, machine_mode, HOST_WIDE_INT, |
91bc47b0 | 1739 | int, bool); |
1740 | ||
1741 | /* Internal routine for alpha_emit_set_const to check for N or below insns. | |
1742 | If NO_OUTPUT is true, then we only check to see if N insns are possible, | |
1743 | and return pc_rtx if successful. */ | |
6f86cb15 | 1744 | |
1745 | static rtx | |
3754d046 | 1746 | alpha_emit_set_const_1 (rtx target, machine_mode mode, |
91bc47b0 | 1747 | HOST_WIDE_INT c, int n, bool no_output) |
bf2a98b3 | 1748 | { |
8deb3959 | 1749 | HOST_WIDE_INT new_const; |
bf2a98b3 | 1750 | int i, bits; |
ea5db00c | 1751 | /* Use a pseudo if highly optimizing and still generating RTL. */ |
1752 | rtx subtarget | |
e1ba4a27 | 1753 | = (flag_expensive_optimizations && can_create_pseudo_p () ? 0 : target); |
301416af | 1754 | rtx temp, insn; |
bf2a98b3 | 1755 | |
bf2a98b3 | 1756 | /* If this is a sign-extended 32-bit constant, we can do this in at most |
a2d7211e | 1757 | three insns, so do it if we have enough insns left. */ |
bf2a98b3 | 1758 | |
a2d7211e | 1759 | if (c >> 31 == -1 || c >> 31 == 0) |
bf2a98b3 | 1760 | { |
bdb19034 | 1761 | HOST_WIDE_INT low = ((c & 0xffff) ^ 0x8000) - 0x8000; |
bf2a98b3 | 1762 | HOST_WIDE_INT tmp1 = c - low; |
bdb19034 | 1763 | HOST_WIDE_INT high = (((tmp1 >> 16) & 0xffff) ^ 0x8000) - 0x8000; |
bf2a98b3 | 1764 | HOST_WIDE_INT extra = 0; |
1765 | ||
81d03ebd | 1766 | /* If HIGH will be interpreted as negative but the constant is |
1767 | positive, we must adjust it to do two ldha insns. */ | |
1768 | ||
1769 | if ((high & 0x8000) != 0 && c >= 0) | |
bf2a98b3 | 1770 | { |
1771 | extra = 0x4000; | |
1772 | tmp1 -= 0x40000000; | |
1773 | high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); | |
1774 | } | |
1775 | ||
1776 | if (c == low || (low == 0 && extra == 0)) | |
3bc2043a | 1777 | { |
1778 | /* We used to use copy_to_suggested_reg (GEN_INT (c), target, mode) | |
1779 | but that meant that we can't handle INT_MIN on 32-bit machines | |
9e7454d0 | 1780 | (like NT/Alpha), because we recurse indefinitely through |
3bc2043a | 1781 | emit_move_insn to gen_movdi. So instead, since we know exactly |
1782 | what we want, create it explicitly. */ | |
1783 | ||
91bc47b0 | 1784 | if (no_output) |
1785 | return pc_rtx; | |
3bc2043a | 1786 | if (target == NULL) |
1787 | target = gen_reg_rtx (mode); | |
d1f9b275 | 1788 | emit_insn (gen_rtx_SET (target, GEN_INT (c))); |
3bc2043a | 1789 | return target; |
1790 | } | |
6f86cb15 | 1791 | else if (n >= 2 + (extra != 0)) |
bf2a98b3 | 1792 | { |
91bc47b0 | 1793 | if (no_output) |
1794 | return pc_rtx; | |
e1ba4a27 | 1795 | if (!can_create_pseudo_p ()) |
5b952578 | 1796 | { |
d1f9b275 | 1797 | emit_insn (gen_rtx_SET (target, GEN_INT (high << 16))); |
5b952578 | 1798 | temp = target; |
1799 | } | |
1800 | else | |
1801 | temp = copy_to_suggested_reg (GEN_INT (high << 16), | |
1802 | subtarget, mode); | |
ea5db00c | 1803 | |
301416af | 1804 | /* As of 2002-02-23, addsi3 is only available when not optimizing. |
1805 | This means that if we go through expand_binop, we'll try to | |
1806 | generate extensions, etc, which will require new pseudos, which | |
1807 | will fail during some split phases. The SImode add patterns | |
1808 | still exist, but are not named. So build the insns by hand. */ | |
1809 | ||
bf2a98b3 | 1810 | if (extra != 0) |
301416af | 1811 | { |
1812 | if (! subtarget) | |
1813 | subtarget = gen_reg_rtx (mode); | |
1814 | insn = gen_rtx_PLUS (mode, temp, GEN_INT (extra << 16)); | |
d1f9b275 | 1815 | insn = gen_rtx_SET (subtarget, insn); |
301416af | 1816 | emit_insn (insn); |
b8585446 | 1817 | temp = subtarget; |
301416af | 1818 | } |
bf2a98b3 | 1819 | |
301416af | 1820 | if (target == NULL) |
1821 | target = gen_reg_rtx (mode); | |
1822 | insn = gen_rtx_PLUS (mode, temp, GEN_INT (low)); | |
d1f9b275 | 1823 | insn = gen_rtx_SET (target, insn); |
301416af | 1824 | emit_insn (insn); |
1825 | return target; | |
bf2a98b3 | 1826 | } |
1827 | } | |
1828 | ||
dacd345b | 1829 | /* If we couldn't do it that way, try some other methods. But if we have |
07014ed9 | 1830 | no instructions left, don't bother. Likewise, if this is SImode and |
1831 | we can't make pseudos, we can't do anything since the expand_binop | |
1832 | and expand_unop calls will widen and try to make pseudos. */ | |
bf2a98b3 | 1833 | |
e1ba4a27 | 1834 | if (n == 1 || (mode == SImode && !can_create_pseudo_p ())) |
bf2a98b3 | 1835 | return 0; |
1836 | ||
dacd345b | 1837 | /* Next, see if we can load a related constant and then shift and possibly |
bf2a98b3 | 1838 | negate it to get the constant we want. Try this once each increasing |
1839 | numbers of insns. */ | |
1840 | ||
1841 | for (i = 1; i < n; i++) | |
1842 | { | |
bdb19034 | 1843 | /* First, see if minus some low bits, we've an easy load of |
1844 | high bits. */ | |
1845 | ||
8deb3959 | 1846 | new_const = ((c & 0xffff) ^ 0x8000) - 0x8000; |
1847 | if (new_const != 0) | |
91bc47b0 | 1848 | { |
8deb3959 | 1849 | temp = alpha_emit_set_const (subtarget, mode, c - new_const, i, no_output); |
91bc47b0 | 1850 | if (temp) |
1851 | { | |
1852 | if (no_output) | |
1853 | return temp; | |
8deb3959 | 1854 | return expand_binop (mode, add_optab, temp, GEN_INT (new_const), |
91bc47b0 | 1855 | target, 0, OPTAB_WIDEN); |
1856 | } | |
1857 | } | |
bdb19034 | 1858 | |
1859 | /* Next try complementing. */ | |
91bc47b0 | 1860 | temp = alpha_emit_set_const (subtarget, mode, ~c, i, no_output); |
1861 | if (temp) | |
1862 | { | |
1863 | if (no_output) | |
1864 | return temp; | |
1865 | return expand_unop (mode, one_cmpl_optab, temp, target, 0); | |
1866 | } | |
bf2a98b3 | 1867 | |
ea5db00c | 1868 | /* Next try to form a constant and do a left shift. We can do this |
bf2a98b3 | 1869 | if some low-order bits are zero; the exact_log2 call below tells |
1870 | us that information. The bits we are shifting out could be any | |
1871 | value, but here we'll just try the 0- and sign-extended forms of | |
1872 | the constant. To try to increase the chance of having the same | |
1873 | constant in more than one insn, start at the highest number of | |
1874 | bits to shift, but try all possibilities in case a ZAPNOT will | |
1875 | be useful. */ | |
1876 | ||
91bc47b0 | 1877 | bits = exact_log2 (c & -c); |
1878 | if (bits > 0) | |
bf2a98b3 | 1879 | for (; bits > 0; bits--) |
91bc47b0 | 1880 | { |
8deb3959 | 1881 | new_const = c >> bits; |
1882 | temp = alpha_emit_set_const (subtarget, mode, new_const, i, no_output); | |
91bc47b0 | 1883 | if (!temp && c < 0) |
1884 | { | |
8deb3959 | 1885 | new_const = (unsigned HOST_WIDE_INT)c >> bits; |
1886 | temp = alpha_emit_set_const (subtarget, mode, new_const, | |
91bc47b0 | 1887 | i, no_output); |
1888 | } | |
1889 | if (temp) | |
1890 | { | |
1891 | if (no_output) | |
1892 | return temp; | |
1893 | return expand_binop (mode, ashl_optab, temp, GEN_INT (bits), | |
1894 | target, 0, OPTAB_WIDEN); | |
1895 | } | |
1896 | } | |
bf2a98b3 | 1897 | |
1898 | /* Now try high-order zero bits. Here we try the shifted-in bits as | |
066efb8d | 1899 | all zero and all ones. Be careful to avoid shifting outside the |
1900 | mode and to avoid shifting outside the host wide int size. */ | |
bf2a98b3 | 1901 | |
91bc47b0 | 1902 | bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) |
a2d7211e | 1903 | - floor_log2 (c) - 1); |
91bc47b0 | 1904 | if (bits > 0) |
bf2a98b3 | 1905 | for (; bits > 0; bits--) |
91bc47b0 | 1906 | { |
8deb3959 | 1907 | new_const = c << bits; |
1908 | temp = alpha_emit_set_const (subtarget, mode, new_const, i, no_output); | |
91bc47b0 | 1909 | if (!temp) |
1910 | { | |
a2d7211e | 1911 | new_const = (c << bits) | ((HOST_WIDE_INT_1U << bits) - 1); |
8deb3959 | 1912 | temp = alpha_emit_set_const (subtarget, mode, new_const, |
91bc47b0 | 1913 | i, no_output); |
1914 | } | |
1915 | if (temp) | |
1916 | { | |
1917 | if (no_output) | |
1918 | return temp; | |
1919 | return expand_binop (mode, lshr_optab, temp, GEN_INT (bits), | |
1920 | target, 1, OPTAB_WIDEN); | |
1921 | } | |
1922 | } | |
bf2a98b3 | 1923 | |
1924 | /* Now try high-order 1 bits. We get that with a sign-extension. | |
066efb8d | 1925 | But one bit isn't enough here. Be careful to avoid shifting outside |
65abff06 | 1926 | the mode and to avoid shifting outside the host wide int size. */ |
9caef960 | 1927 | |
91bc47b0 | 1928 | bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8) |
1929 | - floor_log2 (~ c) - 2); | |
1930 | if (bits > 0) | |
bf2a98b3 | 1931 | for (; bits > 0; bits--) |
91bc47b0 | 1932 | { |
8deb3959 | 1933 | new_const = c << bits; |
1934 | temp = alpha_emit_set_const (subtarget, mode, new_const, i, no_output); | |
91bc47b0 | 1935 | if (!temp) |
1936 | { | |
a2d7211e | 1937 | new_const = (c << bits) | ((HOST_WIDE_INT_1U << bits) - 1); |
8deb3959 | 1938 | temp = alpha_emit_set_const (subtarget, mode, new_const, |
91bc47b0 | 1939 | i, no_output); |
1940 | } | |
1941 | if (temp) | |
1942 | { | |
1943 | if (no_output) | |
1944 | return temp; | |
1945 | return expand_binop (mode, ashr_optab, temp, GEN_INT (bits), | |
1946 | target, 0, OPTAB_WIDEN); | |
1947 | } | |
1948 | } | |
bf2a98b3 | 1949 | } |
1950 | ||
bdb19034 | 1951 | /* Finally, see if can load a value into the target that is the same as the |
1952 | constant except that all bytes that are 0 are changed to be 0xff. If we | |
1953 | can, then we can do a ZAPNOT to obtain the desired constant. */ | |
1954 | ||
8deb3959 | 1955 | new_const = c; |
bdb19034 | 1956 | for (i = 0; i < 64; i += 8) |
8deb3959 | 1957 | if ((new_const & ((HOST_WIDE_INT) 0xff << i)) == 0) |
1958 | new_const |= (HOST_WIDE_INT) 0xff << i; | |
e52799e9 | 1959 | |
bdb19034 | 1960 | /* We are only called for SImode and DImode. If this is SImode, ensure that |
1961 | we are sign extended to a full word. */ | |
1962 | ||
1963 | if (mode == SImode) | |
8deb3959 | 1964 | new_const = ((new_const & 0xffffffff) ^ 0x80000000) - 0x80000000; |
bdb19034 | 1965 | |
8deb3959 | 1966 | if (new_const != c) |
91bc47b0 | 1967 | { |
8deb3959 | 1968 | temp = alpha_emit_set_const (subtarget, mode, new_const, n - 1, no_output); |
91bc47b0 | 1969 | if (temp) |
1970 | { | |
1971 | if (no_output) | |
1972 | return temp; | |
8deb3959 | 1973 | return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new_const), |
91bc47b0 | 1974 | target, 0, OPTAB_WIDEN); |
1975 | } | |
1976 | } | |
e52799e9 | 1977 | |
bf2a98b3 | 1978 | return 0; |
1979 | } | |
996a379d | 1980 | |
92643d95 | 1981 | /* Try to output insns to set TARGET equal to the constant C if it can be |
1982 | done in less than N insns. Do all computations in MODE. Returns the place | |
1983 | where the output has been placed if it can be done and the insns have been | |
1984 | emitted. If it would take more than N insns, zero is returned and no | |
1985 | insns and emitted. */ | |
1986 | ||
91bc47b0 | 1987 | static rtx |
3754d046 | 1988 | alpha_emit_set_const (rtx target, machine_mode mode, |
91bc47b0 | 1989 | HOST_WIDE_INT c, int n, bool no_output) |
92643d95 | 1990 | { |
3754d046 | 1991 | machine_mode orig_mode = mode; |
92643d95 | 1992 | rtx orig_target = target; |
91bc47b0 | 1993 | rtx result = 0; |
92643d95 | 1994 | int i; |
1995 | ||
1996 | /* If we can't make any pseudos, TARGET is an SImode hard register, we | |
1997 | can't load this constant in one insn, do this in DImode. */ | |
e1ba4a27 | 1998 | if (!can_create_pseudo_p () && mode == SImode |
c933fb42 | 1999 | && REG_P (target) && REGNO (target) < FIRST_PSEUDO_REGISTER) |
92643d95 | 2000 | { |
91bc47b0 | 2001 | result = alpha_emit_set_const_1 (target, mode, c, 1, no_output); |
2002 | if (result) | |
2003 | return result; | |
2004 | ||
2005 | target = no_output ? NULL : gen_lowpart (DImode, target); | |
2006 | mode = DImode; | |
2007 | } | |
2008 | else if (mode == V8QImode || mode == V4HImode || mode == V2SImode) | |
2009 | { | |
2010 | target = no_output ? NULL : gen_lowpart (DImode, target); | |
92643d95 | 2011 | mode = DImode; |
2012 | } | |
2013 | ||
2014 | /* Try 1 insn, then 2, then up to N. */ | |
2015 | for (i = 1; i <= n; i++) | |
2016 | { | |
91bc47b0 | 2017 | result = alpha_emit_set_const_1 (target, mode, c, i, no_output); |
92643d95 | 2018 | if (result) |
2019 | { | |
7f0256ea | 2020 | rtx_insn *insn; |
2021 | rtx set; | |
91bc47b0 | 2022 | |
2023 | if (no_output) | |
2024 | return result; | |
2025 | ||
2026 | insn = get_last_insn (); | |
2027 | set = single_set (insn); | |
92643d95 | 2028 | if (! CONSTANT_P (SET_SRC (set))) |
2029 | set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c)); | |
2030 | break; | |
2031 | } | |
2032 | } | |
2033 | ||
2034 | /* Allow for the case where we changed the mode of TARGET. */ | |
91bc47b0 | 2035 | if (result) |
2036 | { | |
2037 | if (result == target) | |
2038 | result = orig_target; | |
2039 | else if (mode != orig_mode) | |
2040 | result = gen_lowpart (orig_mode, result); | |
2041 | } | |
92643d95 | 2042 | |
2043 | return result; | |
2044 | } | |
2045 | ||
2612f626 | 2046 | /* Having failed to find a 3 insn sequence in alpha_emit_set_const, |
2047 | fall back to a straight forward decomposition. We do this to avoid | |
2048 | exponential run times encountered when looking for longer sequences | |
2049 | with alpha_emit_set_const. */ | |
2050 | ||
91bc47b0 | 2051 | static rtx |
debb7e7a | 2052 | alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1) |
2612f626 | 2053 | { |
2612f626 | 2054 | HOST_WIDE_INT d1, d2, d3, d4; |
2612f626 | 2055 | |
2056 | /* Decompose the entire word */ | |
a2d7211e | 2057 | |
af792316 | 2058 | d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000; |
2059 | c1 -= d1; | |
2060 | d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
2061 | c1 = (c1 - d2) >> 32; | |
2062 | d3 = ((c1 & 0xffff) ^ 0x8000) - 0x8000; | |
2063 | c1 -= d3; | |
2064 | d4 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
4d10b463 | 2065 | gcc_assert (c1 == d4); |
2612f626 | 2066 | |
2067 | /* Construct the high word */ | |
af792316 | 2068 | if (d4) |
2069 | { | |
2070 | emit_move_insn (target, GEN_INT (d4)); | |
2071 | if (d3) | |
2072 | emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d3))); | |
2073 | } | |
2612f626 | 2074 | else |
af792316 | 2075 | emit_move_insn (target, GEN_INT (d3)); |
2612f626 | 2076 | |
2077 | /* Shift it into place */ | |
af792316 | 2078 | emit_move_insn (target, gen_rtx_ASHIFT (DImode, target, GEN_INT (32))); |
2612f626 | 2079 | |
af792316 | 2080 | /* Add in the low bits. */ |
2081 | if (d2) | |
2082 | emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d2))); | |
2083 | if (d1) | |
2084 | emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d1))); | |
2612f626 | 2085 | |
af792316 | 2086 | return target; |
2612f626 | 2087 | } |
2612f626 | 2088 | |
316e4f71 | 2089 | /* Given an integral CONST_INT or CONST_VECTOR, return the low 64 bits. */ |
91bc47b0 | 2090 | |
debb7e7a | 2091 | static HOST_WIDE_INT |
2092 | alpha_extract_integer (rtx x) | |
91bc47b0 | 2093 | { |
91bc47b0 | 2094 | if (GET_CODE (x) == CONST_VECTOR) |
2095 | x = simplify_subreg (DImode, x, GET_MODE (x), 0); | |
2096 | ||
316e4f71 | 2097 | gcc_assert (CONST_INT_P (x)); |
2098 | ||
2099 | return INTVAL (x); | |
91bc47b0 | 2100 | } |
2101 | ||
ca316360 | 2102 | /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for which |
2103 | we are willing to load the value into a register via a move pattern. | |
91bc47b0 | 2104 | Normally this is all symbolic constants, integral constants that |
2105 | take three or fewer instructions, and floating-point zero. */ | |
2106 | ||
2107 | bool | |
3754d046 | 2108 | alpha_legitimate_constant_p (machine_mode mode, rtx x) |
91bc47b0 | 2109 | { |
debb7e7a | 2110 | HOST_WIDE_INT i0; |
91bc47b0 | 2111 | |
2112 | switch (GET_CODE (x)) | |
2113 | { | |
91bc47b0 | 2114 | case LABEL_REF: |
91bc47b0 | 2115 | case HIGH: |
2116 | return true; | |
2117 | ||
75645350 | 2118 | case CONST: |
2119 | if (GET_CODE (XEXP (x, 0)) == PLUS | |
7bc95bfb | 2120 | && CONST_INT_P (XEXP (XEXP (x, 0), 1))) |
75645350 | 2121 | x = XEXP (XEXP (x, 0), 0); |
2122 | else | |
2123 | return true; | |
2124 | ||
2125 | if (GET_CODE (x) != SYMBOL_REF) | |
2126 | return true; | |
75645350 | 2127 | /* FALLTHRU */ |
2128 | ||
b5c0ec3d | 2129 | case SYMBOL_REF: |
2130 | /* TLS symbols are never valid. */ | |
2131 | return SYMBOL_REF_TLS_MODEL (x) == 0; | |
2132 | ||
5c5c1f00 | 2133 | case CONST_WIDE_INT: |
316e4f71 | 2134 | if (TARGET_BUILD_CONSTANTS) |
2135 | return true; | |
91bc47b0 | 2136 | if (x == CONST0_RTX (mode)) |
2137 | return true; | |
316e4f71 | 2138 | mode = DImode; |
2139 | gcc_assert (CONST_WIDE_INT_NUNITS (x) == 2); | |
2140 | i0 = CONST_WIDE_INT_ELT (x, 1); | |
2141 | if (alpha_emit_set_const_1 (NULL_RTX, mode, i0, 3, true) == NULL) | |
2142 | return false; | |
2143 | i0 = CONST_WIDE_INT_ELT (x, 0); | |
91bc47b0 | 2144 | goto do_integer; |
2145 | ||
5c5c1f00 | 2146 | case CONST_DOUBLE: |
2147 | if (x == CONST0_RTX (mode)) | |
2148 | return true; | |
2149 | return false; | |
2150 | ||
91bc47b0 | 2151 | case CONST_VECTOR: |
2152 | if (x == CONST0_RTX (mode)) | |
2153 | return true; | |
2154 | if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT) | |
2155 | return false; | |
2156 | if (GET_MODE_SIZE (mode) != 8) | |
2157 | return false; | |
316e4f71 | 2158 | /* FALLTHRU */ |
91bc47b0 | 2159 | |
2160 | case CONST_INT: | |
91bc47b0 | 2161 | if (TARGET_BUILD_CONSTANTS) |
2162 | return true; | |
debb7e7a | 2163 | i0 = alpha_extract_integer (x); |
316e4f71 | 2164 | do_integer: |
2165 | return alpha_emit_set_const_1 (NULL_RTX, mode, i0, 3, true) != NULL; | |
91bc47b0 | 2166 | |
2167 | default: | |
2168 | return false; | |
2169 | } | |
2170 | } | |
2171 | ||
2172 | /* Operand 1 is known to be a constant, and should require more than one | |
2173 | instruction to load. Emit that multi-part load. */ | |
2174 | ||
2175 | bool | |
3754d046 | 2176 | alpha_split_const_mov (machine_mode mode, rtx *operands) |
91bc47b0 | 2177 | { |
debb7e7a | 2178 | HOST_WIDE_INT i0; |
91bc47b0 | 2179 | rtx temp = NULL_RTX; |
2180 | ||
debb7e7a | 2181 | i0 = alpha_extract_integer (operands[1]); |
91bc47b0 | 2182 | |
a2d7211e | 2183 | temp = alpha_emit_set_const (operands[0], mode, i0, 3, false); |
91bc47b0 | 2184 | |
2185 | if (!temp && TARGET_BUILD_CONSTANTS) | |
debb7e7a | 2186 | temp = alpha_emit_set_long_const (operands[0], i0); |
91bc47b0 | 2187 | |
2188 | if (temp) | |
2189 | { | |
2190 | if (!rtx_equal_p (operands[0], temp)) | |
2191 | emit_move_insn (operands[0], temp); | |
2192 | return true; | |
2193 | } | |
2194 | ||
2195 | return false; | |
2196 | } | |
2197 | ||
cb6e3ae1 | 2198 | /* Expand a move instruction; return true if all work is done. |
2199 | We don't handle non-bwx subword loads here. */ | |
2200 | ||
2201 | bool | |
3754d046 | 2202 | alpha_expand_mov (machine_mode mode, rtx *operands) |
cb6e3ae1 | 2203 | { |
f8fff44e | 2204 | rtx tmp; |
2205 | ||
cb6e3ae1 | 2206 | /* If the output is not a register, the input must be. */ |
c933fb42 | 2207 | if (MEM_P (operands[0]) |
cb6e3ae1 | 2208 | && ! reg_or_0_operand (operands[1], mode)) |
2209 | operands[1] = force_reg (mode, operands[1]); | |
2210 | ||
f5a60074 | 2211 | /* Allow legitimize_address to perform some simplifications. */ |
62e050c6 | 2212 | if (mode == Pmode && symbolic_operand (operands[1], mode)) |
1f0ce6a6 | 2213 | { |
41e3a0c7 | 2214 | tmp = alpha_legitimize_address_1 (operands[1], operands[0], mode); |
f5a60074 | 2215 | if (tmp) |
5dcb037d | 2216 | { |
5f7b9df8 | 2217 | if (tmp == operands[0]) |
2218 | return true; | |
f5a60074 | 2219 | operands[1] = tmp; |
8afb6db4 | 2220 | return false; |
2221 | } | |
1f0ce6a6 | 2222 | } |
2223 | ||
cb6e3ae1 | 2224 | /* Early out for non-constants and valid constants. */ |
2225 | if (! CONSTANT_P (operands[1]) || input_operand (operands[1], mode)) | |
2226 | return false; | |
2227 | ||
2228 | /* Split large integers. */ | |
c933fb42 | 2229 | if (CONST_INT_P (operands[1]) |
91bc47b0 | 2230 | || GET_CODE (operands[1]) == CONST_VECTOR) |
cb6e3ae1 | 2231 | { |
91bc47b0 | 2232 | if (alpha_split_const_mov (mode, operands)) |
2233 | return true; | |
cb6e3ae1 | 2234 | } |
2235 | ||
2236 | /* Otherwise we've nothing left but to drop the thing to memory. */ | |
f8fff44e | 2237 | tmp = force_const_mem (mode, operands[1]); |
2238 | ||
2239 | if (tmp == NULL_RTX) | |
2240 | return false; | |
2241 | ||
cb6e3ae1 | 2242 | if (reload_in_progress) |
2243 | { | |
f8fff44e | 2244 | emit_move_insn (operands[0], XEXP (tmp, 0)); |
2245 | operands[1] = replace_equiv_address (tmp, operands[0]); | |
cb6e3ae1 | 2246 | } |
2247 | else | |
f8fff44e | 2248 | operands[1] = validize_mem (tmp); |
cb6e3ae1 | 2249 | return false; |
2250 | } | |
2251 | ||
2252 | /* Expand a non-bwx QImode or HImode move instruction; | |
2253 | return true if all work is done. */ | |
2254 | ||
2255 | bool | |
3754d046 | 2256 | alpha_expand_mov_nobwx (machine_mode mode, rtx *operands) |
cb6e3ae1 | 2257 | { |
0d96cd2b | 2258 | rtx seq; |
2259 | ||
cb6e3ae1 | 2260 | /* If the output is not a register, the input must be. */ |
0d96cd2b | 2261 | if (MEM_P (operands[0])) |
cb6e3ae1 | 2262 | operands[1] = force_reg (mode, operands[1]); |
2263 | ||
2264 | /* Handle four memory cases, unaligned and aligned for either the input | |
2265 | or the output. The only case where we can be called during reload is | |
2266 | for aligned loads; all other cases require temporaries. */ | |
2267 | ||
0d96cd2b | 2268 | if (any_memory_operand (operands[1], mode)) |
cb6e3ae1 | 2269 | { |
2270 | if (aligned_memory_operand (operands[1], mode)) | |
2271 | { | |
2272 | if (reload_in_progress) | |
2273 | { | |
0d96cd2b | 2274 | if (mode == QImode) |
2275 | seq = gen_reload_inqi_aligned (operands[0], operands[1]); | |
2276 | else | |
2277 | seq = gen_reload_inhi_aligned (operands[0], operands[1]); | |
2278 | emit_insn (seq); | |
cb6e3ae1 | 2279 | } |
2280 | else | |
2281 | { | |
2282 | rtx aligned_mem, bitnum; | |
2283 | rtx scratch = gen_reg_rtx (SImode); | |
d67e1866 | 2284 | rtx subtarget; |
2285 | bool copyout; | |
cb6e3ae1 | 2286 | |
2287 | get_aligned_mem (operands[1], &aligned_mem, &bitnum); | |
2288 | ||
d67e1866 | 2289 | subtarget = operands[0]; |
c933fb42 | 2290 | if (REG_P (subtarget)) |
d67e1866 | 2291 | subtarget = gen_lowpart (DImode, subtarget), copyout = false; |
2292 | else | |
2293 | subtarget = gen_reg_rtx (DImode), copyout = true; | |
2294 | ||
0d96cd2b | 2295 | if (mode == QImode) |
2296 | seq = gen_aligned_loadqi (subtarget, aligned_mem, | |
2297 | bitnum, scratch); | |
2298 | else | |
2299 | seq = gen_aligned_loadhi (subtarget, aligned_mem, | |
2300 | bitnum, scratch); | |
2301 | emit_insn (seq); | |
d67e1866 | 2302 | |
2303 | if (copyout) | |
2304 | emit_move_insn (operands[0], gen_lowpart (mode, subtarget)); | |
cb6e3ae1 | 2305 | } |
2306 | } | |
2307 | else | |
2308 | { | |
2309 | /* Don't pass these as parameters since that makes the generated | |
2310 | code depend on parameter evaluation order which will cause | |
2311 | bootstrap failures. */ | |
2312 | ||
0d96cd2b | 2313 | rtx temp1, temp2, subtarget, ua; |
d67e1866 | 2314 | bool copyout; |
2315 | ||
2316 | temp1 = gen_reg_rtx (DImode); | |
2317 | temp2 = gen_reg_rtx (DImode); | |
cb6e3ae1 | 2318 | |
d67e1866 | 2319 | subtarget = operands[0]; |
c933fb42 | 2320 | if (REG_P (subtarget)) |
d67e1866 | 2321 | subtarget = gen_lowpart (DImode, subtarget), copyout = false; |
2322 | else | |
2323 | subtarget = gen_reg_rtx (DImode), copyout = true; | |
2324 | ||
0d96cd2b | 2325 | ua = get_unaligned_address (operands[1]); |
2326 | if (mode == QImode) | |
2327 | seq = gen_unaligned_loadqi (subtarget, ua, temp1, temp2); | |
2328 | else | |
2329 | seq = gen_unaligned_loadhi (subtarget, ua, temp1, temp2); | |
2330 | ||
cb6e3ae1 | 2331 | alpha_set_memflags (seq, operands[1]); |
2332 | emit_insn (seq); | |
d67e1866 | 2333 | |
2334 | if (copyout) | |
2335 | emit_move_insn (operands[0], gen_lowpart (mode, subtarget)); | |
cb6e3ae1 | 2336 | } |
2337 | return true; | |
2338 | } | |
2339 | ||
0d96cd2b | 2340 | if (any_memory_operand (operands[0], mode)) |
cb6e3ae1 | 2341 | { |
2342 | if (aligned_memory_operand (operands[0], mode)) | |
2343 | { | |
2344 | rtx aligned_mem, bitnum; | |
2345 | rtx temp1 = gen_reg_rtx (SImode); | |
2346 | rtx temp2 = gen_reg_rtx (SImode); | |
2347 | ||
2348 | get_aligned_mem (operands[0], &aligned_mem, &bitnum); | |
2349 | ||
2350 | emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum, | |
2351 | temp1, temp2)); | |
2352 | } | |
2353 | else | |
2354 | { | |
2355 | rtx temp1 = gen_reg_rtx (DImode); | |
2356 | rtx temp2 = gen_reg_rtx (DImode); | |
2357 | rtx temp3 = gen_reg_rtx (DImode); | |
0d96cd2b | 2358 | rtx ua = get_unaligned_address (operands[0]); |
2359 | ||
2360 | if (mode == QImode) | |
2361 | seq = gen_unaligned_storeqi (ua, operands[1], temp1, temp2, temp3); | |
2362 | else | |
2363 | seq = gen_unaligned_storehi (ua, operands[1], temp1, temp2, temp3); | |
cb6e3ae1 | 2364 | |
2365 | alpha_set_memflags (seq, operands[0]); | |
2366 | emit_insn (seq); | |
2367 | } | |
2368 | return true; | |
2369 | } | |
2370 | ||
2371 | return false; | |
2372 | } | |
2373 | ||
a31688d7 | 2374 | /* Implement the movmisalign patterns. One of the operands is a memory |
84846cff | 2375 | that is not naturally aligned. Emit instructions to load it. */ |
a31688d7 | 2376 | |
2377 | void | |
3754d046 | 2378 | alpha_expand_movmisalign (machine_mode mode, rtx *operands) |
a31688d7 | 2379 | { |
2380 | /* Honor misaligned loads, for those we promised to do so. */ | |
2381 | if (MEM_P (operands[1])) | |
2382 | { | |
2383 | rtx tmp; | |
2384 | ||
2385 | if (register_operand (operands[0], mode)) | |
2386 | tmp = operands[0]; | |
2387 | else | |
2388 | tmp = gen_reg_rtx (mode); | |
2389 | ||
2390 | alpha_expand_unaligned_load (tmp, operands[1], 8, 0, 0); | |
2391 | if (tmp != operands[0]) | |
2392 | emit_move_insn (operands[0], tmp); | |
2393 | } | |
2394 | else if (MEM_P (operands[0])) | |
2395 | { | |
2396 | if (!reg_or_0_operand (operands[1], mode)) | |
2397 | operands[1] = force_reg (mode, operands[1]); | |
2398 | alpha_expand_unaligned_store (operands[0], operands[1], 8, 0); | |
2399 | } | |
2400 | else | |
2401 | gcc_unreachable (); | |
2402 | } | |
2403 | ||
2a42ba09 | 2404 | /* Generate an unsigned DImode to FP conversion. This is the same code |
2405 | optabs would emit if we didn't have TFmode patterns. | |
2406 | ||
2407 | For SFmode, this is the only construction I've found that can pass | |
2408 | gcc.c-torture/execute/ieee/rbug.c. No scenario that uses DFmode | |
2409 | intermediates will work, because you'll get intermediate rounding | |
2410 | that ruins the end result. Some of this could be fixed by turning | |
2411 | on round-to-positive-infinity, but that requires diddling the fpsr, | |
2412 | which kills performance. I tried turning this around and converting | |
2413 | to a negative number, so that I could turn on /m, but either I did | |
2414 | it wrong or there's something else cause I wound up with the exact | |
2415 | same single-bit error. There is a branch-less form of this same code: | |
2416 | ||
2417 | srl $16,1,$1 | |
2418 | and $16,1,$2 | |
2419 | cmplt $16,0,$3 | |
2420 | or $1,$2,$2 | |
2421 | cmovge $16,$16,$2 | |
2422 | itoft $3,$f10 | |
2423 | itoft $2,$f11 | |
2424 | cvtqs $f11,$f11 | |
2425 | adds $f11,$f11,$f0 | |
2426 | fcmoveq $f10,$f11,$f0 | |
2427 | ||
2428 | I'm not using it because it's the same number of instructions as | |
2429 | this branch-full form, and it has more serialized long latency | |
2430 | instructions on the critical path. | |
2431 | ||
2432 | For DFmode, we can avoid rounding errors by breaking up the word | |
2433 | into two pieces, converting them separately, and adding them back: | |
2434 | ||
2435 | LC0: .long 0,0x5f800000 | |
2436 | ||
2437 | itoft $16,$f11 | |
2438 | lda $2,LC0 | |
093c0196 | 2439 | cmplt $16,0,$1 |
2a42ba09 | 2440 | cpyse $f11,$f31,$f10 |
2441 | cpyse $f31,$f11,$f11 | |
2442 | s4addq $1,$2,$1 | |
2443 | lds $f12,0($1) | |
2444 | cvtqt $f10,$f10 | |
2445 | cvtqt $f11,$f11 | |
2446 | addt $f12,$f10,$f0 | |
2447 | addt $f0,$f11,$f0 | |
2448 | ||
2449 | This doesn't seem to be a clear-cut win over the optabs form. | |
2450 | It probably all depends on the distribution of numbers being | |
2451 | converted -- in the optabs form, all but high-bit-set has a | |
2452 | much lower minimum execution time. */ | |
2453 | ||
2454 | void | |
92643d95 | 2455 | alpha_emit_floatuns (rtx operands[2]) |
2a42ba09 | 2456 | { |
2457 | rtx neglab, donelab, i0, i1, f0, in, out; | |
3754d046 | 2458 | machine_mode mode; |
2a42ba09 | 2459 | |
2460 | out = operands[0]; | |
8e2025b4 | 2461 | in = force_reg (DImode, operands[1]); |
2a42ba09 | 2462 | mode = GET_MODE (out); |
2463 | neglab = gen_label_rtx (); | |
2464 | donelab = gen_label_rtx (); | |
2465 | i0 = gen_reg_rtx (DImode); | |
2466 | i1 = gen_reg_rtx (DImode); | |
2467 | f0 = gen_reg_rtx (mode); | |
2468 | ||
7e69f45b | 2469 | emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab); |
2a42ba09 | 2470 | |
d1f9b275 | 2471 | emit_insn (gen_rtx_SET (out, gen_rtx_FLOAT (mode, in))); |
2a42ba09 | 2472 | emit_jump_insn (gen_jump (donelab)); |
093c0196 | 2473 | emit_barrier (); |
2a42ba09 | 2474 | |
2475 | emit_label (neglab); | |
2476 | ||
2477 | emit_insn (gen_lshrdi3 (i0, in, const1_rtx)); | |
2478 | emit_insn (gen_anddi3 (i1, in, const1_rtx)); | |
2479 | emit_insn (gen_iordi3 (i0, i0, i1)); | |
d1f9b275 | 2480 | emit_insn (gen_rtx_SET (f0, gen_rtx_FLOAT (mode, i0))); |
2481 | emit_insn (gen_rtx_SET (out, gen_rtx_PLUS (mode, f0, f0))); | |
2a42ba09 | 2482 | |
2483 | emit_label (donelab); | |
2484 | } | |
2485 | ||
3a2a3a7f | 2486 | /* Generate the comparison for a conditional branch. */ |
2487 | ||
74f4459c | 2488 | void |
3754d046 | 2489 | alpha_emit_conditional_branch (rtx operands[], machine_mode cmp_mode) |
3a2a3a7f | 2490 | { |
2491 | enum rtx_code cmp_code, branch_code; | |
3754d046 | 2492 | machine_mode branch_mode = VOIDmode; |
74f4459c | 2493 | enum rtx_code code = GET_CODE (operands[0]); |
2494 | rtx op0 = operands[1], op1 = operands[2]; | |
3a2a3a7f | 2495 | rtx tem; |
2496 | ||
74f4459c | 2497 | if (cmp_mode == TFmode) |
915c336f | 2498 | { |
8c3428a6 | 2499 | op0 = alpha_emit_xfloating_compare (&code, op0, op1); |
915c336f | 2500 | op1 = const0_rtx; |
74f4459c | 2501 | cmp_mode = DImode; |
915c336f | 2502 | } |
2503 | ||
3a2a3a7f | 2504 | /* The general case: fold the comparison code to the types of compares |
2505 | that we have, choosing the branch as necessary. */ | |
2506 | switch (code) | |
2507 | { | |
2508 | case EQ: case LE: case LT: case LEU: case LTU: | |
a4110d9a | 2509 | case UNORDERED: |
c4d3c065 | 2510 | /* We have these compares. */ |
3a2a3a7f | 2511 | cmp_code = code, branch_code = NE; |
2512 | break; | |
2513 | ||
2514 | case NE: | |
a4110d9a | 2515 | case ORDERED: |
65abff06 | 2516 | /* These must be reversed. */ |
a4110d9a | 2517 | cmp_code = reverse_condition (code), branch_code = EQ; |
3a2a3a7f | 2518 | break; |
2519 | ||
2520 | case GE: case GT: case GEU: case GTU: | |
2521 | /* For FP, we swap them, for INT, we reverse them. */ | |
74f4459c | 2522 | if (cmp_mode == DFmode) |
3a2a3a7f | 2523 | { |
2524 | cmp_code = swap_condition (code); | |
2525 | branch_code = NE; | |
612bd519 | 2526 | std::swap (op0, op1); |
3a2a3a7f | 2527 | } |
2528 | else | |
2529 | { | |
2530 | cmp_code = reverse_condition (code); | |
2531 | branch_code = EQ; | |
2532 | } | |
2533 | break; | |
2534 | ||
2535 | default: | |
4d10b463 | 2536 | gcc_unreachable (); |
3a2a3a7f | 2537 | } |
2538 | ||
74f4459c | 2539 | if (cmp_mode == DFmode) |
3a2a3a7f | 2540 | { |
70ce4162 | 2541 | if (flag_unsafe_math_optimizations && cmp_code != UNORDERED) |
3a2a3a7f | 2542 | { |
2543 | /* When we are not as concerned about non-finite values, and we | |
2544 | are comparing against zero, we can branch directly. */ | |
2545 | if (op1 == CONST0_RTX (DFmode)) | |
21f1e711 | 2546 | cmp_code = UNKNOWN, branch_code = code; |
3a2a3a7f | 2547 | else if (op0 == CONST0_RTX (DFmode)) |
2548 | { | |
2549 | /* Undo the swap we probably did just above. */ | |
612bd519 | 2550 | std::swap (op0, op1); |
4899654e | 2551 | branch_code = swap_condition (cmp_code); |
21f1e711 | 2552 | cmp_code = UNKNOWN; |
3a2a3a7f | 2553 | } |
2554 | } | |
2555 | else | |
2556 | { | |
d30e015b | 2557 | /* ??? We mark the branch mode to be CCmode to prevent the |
9e7454d0 | 2558 | compare and branch from being combined, since the compare |
3a2a3a7f | 2559 | insn follows IEEE rules that the branch does not. */ |
2560 | branch_mode = CCmode; | |
2561 | } | |
2562 | } | |
2563 | else | |
2564 | { | |
3a2a3a7f | 2565 | /* The following optimizations are only for signed compares. */ |
2566 | if (code != LEU && code != LTU && code != GEU && code != GTU) | |
2567 | { | |
2568 | /* Whee. Compare and branch against 0 directly. */ | |
2569 | if (op1 == const0_rtx) | |
21f1e711 | 2570 | cmp_code = UNKNOWN, branch_code = code; |
3a2a3a7f | 2571 | |
3a2f3420 | 2572 | /* If the constants doesn't fit into an immediate, but can |
2573 | be generated by lda/ldah, we adjust the argument and | |
2574 | compare against zero, so we can use beq/bne directly. */ | |
62350d6c | 2575 | /* ??? Don't do this when comparing against symbols, otherwise |
2576 | we'll reduce (&x == 0x1234) to (&x-0x1234 == 0), which will | |
2577 | be declared false out of hand (at least for non-weak). */ | |
c933fb42 | 2578 | else if (CONST_INT_P (op1) |
62350d6c | 2579 | && (code == EQ || code == NE) |
2580 | && !(symbolic_operand (op0, VOIDmode) | |
c933fb42 | 2581 | || (REG_P (op0) && REG_POINTER (op0)))) |
3a2a3a7f | 2582 | { |
1dffd068 | 2583 | rtx n_op1 = GEN_INT (-INTVAL (op1)); |
2584 | ||
2585 | if (! satisfies_constraint_I (op1) | |
2586 | && (satisfies_constraint_K (n_op1) | |
2587 | || satisfies_constraint_L (n_op1))) | |
2588 | cmp_code = PLUS, branch_code = code, op1 = n_op1; | |
3a2a3a7f | 2589 | } |
2590 | } | |
3a2a3a7f | 2591 | |
d74ce6fa | 2592 | if (!reg_or_0_operand (op0, DImode)) |
2593 | op0 = force_reg (DImode, op0); | |
2594 | if (cmp_code != PLUS && !reg_or_8bit_operand (op1, DImode)) | |
2595 | op1 = force_reg (DImode, op1); | |
2596 | } | |
3a2a3a7f | 2597 | |
2598 | /* Emit an initial compare instruction, if necessary. */ | |
2599 | tem = op0; | |
21f1e711 | 2600 | if (cmp_code != UNKNOWN) |
3a2a3a7f | 2601 | { |
2602 | tem = gen_reg_rtx (cmp_mode); | |
2603 | emit_move_insn (tem, gen_rtx_fmt_ee (cmp_code, cmp_mode, op0, op1)); | |
2604 | } | |
2605 | ||
74f4459c | 2606 | /* Emit the branch instruction. */ |
d1f9b275 | 2607 | tem = gen_rtx_SET (pc_rtx, |
74f4459c | 2608 | gen_rtx_IF_THEN_ELSE (VOIDmode, |
2609 | gen_rtx_fmt_ee (branch_code, | |
2610 | branch_mode, tem, | |
2611 | CONST0_RTX (cmp_mode)), | |
2612 | gen_rtx_LABEL_REF (VOIDmode, | |
2613 | operands[3]), | |
2614 | pc_rtx)); | |
2615 | emit_jump_insn (tem); | |
3a2a3a7f | 2616 | } |
2617 | ||
d74ce6fa | 2618 | /* Certain simplifications can be done to make invalid setcc operations |
2619 | valid. Return the final comparison, or NULL if we can't work. */ | |
2620 | ||
74f4459c | 2621 | bool |
3754d046 | 2622 | alpha_emit_setcc (rtx operands[], machine_mode cmp_mode) |
d74ce6fa | 2623 | { |
2624 | enum rtx_code cmp_code; | |
74f4459c | 2625 | enum rtx_code code = GET_CODE (operands[1]); |
2626 | rtx op0 = operands[2], op1 = operands[3]; | |
d74ce6fa | 2627 | rtx tmp; |
2628 | ||
74f4459c | 2629 | if (cmp_mode == TFmode) |
d74ce6fa | 2630 | { |
8c3428a6 | 2631 | op0 = alpha_emit_xfloating_compare (&code, op0, op1); |
d74ce6fa | 2632 | op1 = const0_rtx; |
74f4459c | 2633 | cmp_mode = DImode; |
d74ce6fa | 2634 | } |
2635 | ||
74f4459c | 2636 | if (cmp_mode == DFmode && !TARGET_FIX) |
2637 | return 0; | |
d74ce6fa | 2638 | |
2639 | /* The general case: fold the comparison code to the types of compares | |
2640 | that we have, choosing the branch as necessary. */ | |
2641 | ||
21f1e711 | 2642 | cmp_code = UNKNOWN; |
d74ce6fa | 2643 | switch (code) |
2644 | { | |
2645 | case EQ: case LE: case LT: case LEU: case LTU: | |
2646 | case UNORDERED: | |
2647 | /* We have these compares. */ | |
74f4459c | 2648 | if (cmp_mode == DFmode) |
d74ce6fa | 2649 | cmp_code = code, code = NE; |
2650 | break; | |
2651 | ||
2652 | case NE: | |
74f4459c | 2653 | if (cmp_mode == DImode && op1 == const0_rtx) |
d74ce6fa | 2654 | break; |
8e262b5e | 2655 | /* FALLTHRU */ |
d74ce6fa | 2656 | |
2657 | case ORDERED: | |
2658 | cmp_code = reverse_condition (code); | |
2659 | code = EQ; | |
2660 | break; | |
2661 | ||
2662 | case GE: case GT: case GEU: case GTU: | |
75b3314a | 2663 | /* These normally need swapping, but for integer zero we have |
bc882521 | 2664 | special patterns that recognize swapped operands. */ |
74f4459c | 2665 | if (cmp_mode == DImode && op1 == const0_rtx) |
bc882521 | 2666 | break; |
d74ce6fa | 2667 | code = swap_condition (code); |
74f4459c | 2668 | if (cmp_mode == DFmode) |
d74ce6fa | 2669 | cmp_code = code, code = NE; |
612bd519 | 2670 | std::swap (op0, op1); |
d74ce6fa | 2671 | break; |
2672 | ||
2673 | default: | |
4d10b463 | 2674 | gcc_unreachable (); |
d74ce6fa | 2675 | } |
2676 | ||
74f4459c | 2677 | if (cmp_mode == DImode) |
d74ce6fa | 2678 | { |
bc882521 | 2679 | if (!register_operand (op0, DImode)) |
d74ce6fa | 2680 | op0 = force_reg (DImode, op0); |
2681 | if (!reg_or_8bit_operand (op1, DImode)) | |
2682 | op1 = force_reg (DImode, op1); | |
2683 | } | |
2684 | ||
2685 | /* Emit an initial compare instruction, if necessary. */ | |
21f1e711 | 2686 | if (cmp_code != UNKNOWN) |
d74ce6fa | 2687 | { |
74f4459c | 2688 | tmp = gen_reg_rtx (cmp_mode); |
d1f9b275 | 2689 | emit_insn (gen_rtx_SET (tmp, gen_rtx_fmt_ee (cmp_code, cmp_mode, |
2690 | op0, op1))); | |
d74ce6fa | 2691 | |
eb0e7e5d | 2692 | op0 = cmp_mode != DImode ? gen_lowpart (DImode, tmp) : tmp; |
d74ce6fa | 2693 | op1 = const0_rtx; |
2694 | } | |
2695 | ||
74f4459c | 2696 | /* Emit the setcc instruction. */ |
d1f9b275 | 2697 | emit_insn (gen_rtx_SET (operands[0], gen_rtx_fmt_ee (code, DImode, |
2698 | op0, op1))); | |
74f4459c | 2699 | return true; |
d74ce6fa | 2700 | } |
2701 | ||
3a2a3a7f | 2702 | |
996a379d | 2703 | /* Rewrite a comparison against zero CMP of the form |
2704 | (CODE (cc0) (const_int 0)) so it can be written validly in | |
2705 | a conditional move (if_then_else CMP ...). | |
e3e08e7f | 2706 | If both of the operands that set cc0 are nonzero we must emit |
996a379d | 2707 | an insn to perform the compare (it can't be done within |
65abff06 | 2708 | the conditional move). */ |
92643d95 | 2709 | |
996a379d | 2710 | rtx |
3754d046 | 2711 | alpha_emit_conditional_move (rtx cmp, machine_mode mode) |
996a379d | 2712 | { |
23be97c5 | 2713 | enum rtx_code code = GET_CODE (cmp); |
c60bc286 | 2714 | enum rtx_code cmov_code = NE; |
74f4459c | 2715 | rtx op0 = XEXP (cmp, 0); |
2716 | rtx op1 = XEXP (cmp, 1); | |
3754d046 | 2717 | machine_mode cmp_mode |
23be97c5 | 2718 | = (GET_MODE (op0) == VOIDmode ? DImode : GET_MODE (op0)); |
3754d046 | 2719 | machine_mode cmov_mode = VOIDmode; |
7f3be425 | 2720 | int local_fast_math = flag_unsafe_math_optimizations; |
23be97c5 | 2721 | rtx tem; |
996a379d | 2722 | |
a717c371 | 2723 | if (cmp_mode == TFmode) |
2724 | { | |
2725 | op0 = alpha_emit_xfloating_compare (&code, op0, op1); | |
2726 | op1 = const0_rtx; | |
2727 | cmp_mode = DImode; | |
2728 | } | |
2729 | ||
74f4459c | 2730 | gcc_assert (cmp_mode == DFmode || cmp_mode == DImode); |
b18b881f | 2731 | |
74f4459c | 2732 | if (FLOAT_MODE_P (cmp_mode) != FLOAT_MODE_P (mode)) |
d6cc9868 | 2733 | { |
2734 | enum rtx_code cmp_code; | |
2735 | ||
2736 | if (! TARGET_FIX) | |
2737 | return 0; | |
2738 | ||
2739 | /* If we have fp<->int register move instructions, do a cmov by | |
2740 | performing the comparison in fp registers, and move the | |
e3e08e7f | 2741 | zero/nonzero value to integer registers, where we can then |
d6cc9868 | 2742 | use a normal cmov, or vice-versa. */ |
2743 | ||
2744 | switch (code) | |
2745 | { | |
2746 | case EQ: case LE: case LT: case LEU: case LTU: | |
c4d3c065 | 2747 | case UNORDERED: |
d6cc9868 | 2748 | /* We have these compares. */ |
2749 | cmp_code = code, code = NE; | |
2750 | break; | |
2751 | ||
2752 | case NE: | |
c4d3c065 | 2753 | case ORDERED: |
2754 | /* These must be reversed. */ | |
2755 | cmp_code = reverse_condition (code), code = EQ; | |
d6cc9868 | 2756 | break; |
2757 | ||
2758 | case GE: case GT: case GEU: case GTU: | |
75b3314a | 2759 | /* These normally need swapping, but for integer zero we have |
2760 | special patterns that recognize swapped operands. */ | |
74f4459c | 2761 | if (cmp_mode == DImode && op1 == const0_rtx) |
88f8f2a2 | 2762 | cmp_code = code, code = NE; |
2763 | else | |
2764 | { | |
2765 | cmp_code = swap_condition (code); | |
2766 | code = NE; | |
612bd519 | 2767 | std::swap (op0, op1); |
88f8f2a2 | 2768 | } |
d6cc9868 | 2769 | break; |
2770 | ||
2771 | default: | |
4d10b463 | 2772 | gcc_unreachable (); |
d6cc9868 | 2773 | } |
2774 | ||
c4d3c065 | 2775 | if (cmp_mode == DImode) |
2776 | { | |
2777 | if (!reg_or_0_operand (op0, DImode)) | |
2778 | op0 = force_reg (DImode, op0); | |
2779 | if (!reg_or_8bit_operand (op1, DImode)) | |
2780 | op1 = force_reg (DImode, op1); | |
2781 | } | |
2782 | ||
74f4459c | 2783 | tem = gen_reg_rtx (cmp_mode); |
d1f9b275 | 2784 | emit_insn (gen_rtx_SET (tem, gen_rtx_fmt_ee (cmp_code, cmp_mode, |
2785 | op0, op1))); | |
d6cc9868 | 2786 | |
74f4459c | 2787 | cmp_mode = cmp_mode == DImode ? DFmode : DImode; |
2788 | op0 = gen_lowpart (cmp_mode, tem); | |
2789 | op1 = CONST0_RTX (cmp_mode); | |
5da2e28f | 2790 | cmp = gen_rtx_fmt_ee (code, VOIDmode, op0, op1); |
d6cc9868 | 2791 | local_fast_math = 1; |
2792 | } | |
996a379d | 2793 | |
c4d3c065 | 2794 | if (cmp_mode == DImode) |
2795 | { | |
2796 | if (!reg_or_0_operand (op0, DImode)) | |
2797 | op0 = force_reg (DImode, op0); | |
2798 | if (!reg_or_8bit_operand (op1, DImode)) | |
2799 | op1 = force_reg (DImode, op1); | |
2800 | } | |
2801 | ||
996a379d | 2802 | /* We may be able to use a conditional move directly. |
65abff06 | 2803 | This avoids emitting spurious compares. */ |
2a42ba09 | 2804 | if (signed_comparison_operator (cmp, VOIDmode) |
74f4459c | 2805 | && (cmp_mode == DImode || local_fast_math) |
23be97c5 | 2806 | && (op0 == CONST0_RTX (cmp_mode) || op1 == CONST0_RTX (cmp_mode))) |
941522d6 | 2807 | return gen_rtx_fmt_ee (code, VOIDmode, op0, op1); |
996a379d | 2808 | |
3029ee00 | 2809 | /* We can't put the comparison inside the conditional move; |
996a379d | 2810 | emit a compare instruction and put that inside the |
23be97c5 | 2811 | conditional move. Make sure we emit only comparisons we have; |
2812 | swap or reverse as necessary. */ | |
996a379d | 2813 | |
e1ba4a27 | 2814 | if (!can_create_pseudo_p ()) |
3029ee00 | 2815 | return NULL_RTX; |
2816 | ||
996a379d | 2817 | switch (code) |
2818 | { | |
23be97c5 | 2819 | case EQ: case LE: case LT: case LEU: case LTU: |
c4d3c065 | 2820 | case UNORDERED: |
23be97c5 | 2821 | /* We have these compares: */ |
996a379d | 2822 | break; |
23be97c5 | 2823 | |
996a379d | 2824 | case NE: |
c4d3c065 | 2825 | case ORDERED: |
2826 | /* These must be reversed. */ | |
23be97c5 | 2827 | code = reverse_condition (code); |
c60bc286 | 2828 | cmov_code = EQ; |
996a379d | 2829 | break; |
23be97c5 | 2830 | |
2831 | case GE: case GT: case GEU: case GTU: | |
cf1f9f8b | 2832 | /* These normally need swapping, but for integer zero we have |
2833 | special patterns that recognize swapped operands. */ | |
2834 | if (cmp_mode == DImode && op1 == const0_rtx) | |
2835 | break; | |
2836 | code = swap_condition (code); | |
612bd519 | 2837 | std::swap (op0, op1); |
996a379d | 2838 | break; |
23be97c5 | 2839 | |
996a379d | 2840 | default: |
4d10b463 | 2841 | gcc_unreachable (); |
996a379d | 2842 | } |
2843 | ||
74f4459c | 2844 | if (cmp_mode == DImode) |
d74ce6fa | 2845 | { |
2846 | if (!reg_or_0_operand (op0, DImode)) | |
2847 | op0 = force_reg (DImode, op0); | |
2848 | if (!reg_or_8bit_operand (op1, DImode)) | |
2849 | op1 = force_reg (DImode, op1); | |
2850 | } | |
2851 | ||
b9b4428b | 2852 | /* ??? We mark the branch mode to be CCmode to prevent the compare |
3a2a3a7f | 2853 | and cmov from being combined, since the compare insn follows IEEE |
2854 | rules that the cmov does not. */ | |
74f4459c | 2855 | if (cmp_mode == DFmode && !local_fast_math) |
3a2a3a7f | 2856 | cmov_mode = CCmode; |
2857 | ||
74f4459c | 2858 | tem = gen_reg_rtx (cmp_mode); |
2859 | emit_move_insn (tem, gen_rtx_fmt_ee (code, cmp_mode, op0, op1)); | |
2860 | return gen_rtx_fmt_ee (cmov_code, cmov_mode, tem, CONST0_RTX (cmp_mode)); | |
996a379d | 2861 | } |
bbf31a61 | 2862 | |
2863 | /* Simplify a conditional move of two constants into a setcc with | |
2864 | arithmetic. This is done with a splitter since combine would | |
2865 | just undo the work if done during code generation. It also catches | |
2866 | cases we wouldn't have before cse. */ | |
2867 | ||
2868 | int | |
92643d95 | 2869 | alpha_split_conditional_move (enum rtx_code code, rtx dest, rtx cond, |
2870 | rtx t_rtx, rtx f_rtx) | |
bbf31a61 | 2871 | { |
2872 | HOST_WIDE_INT t, f, diff; | |
3754d046 | 2873 | machine_mode mode; |
bbf31a61 | 2874 | rtx target, subtarget, tmp; |
2875 | ||
2876 | mode = GET_MODE (dest); | |
2877 | t = INTVAL (t_rtx); | |
2878 | f = INTVAL (f_rtx); | |
2879 | diff = t - f; | |
2880 | ||
2881 | if (((code == NE || code == EQ) && diff < 0) | |
2882 | || (code == GE || code == GT)) | |
2883 | { | |
2884 | code = reverse_condition (code); | |
2885 | diff = t, t = f, f = diff; | |
2886 | diff = t - f; | |
2887 | } | |
2888 | ||
2889 | subtarget = target = dest; | |
2890 | if (mode != DImode) | |
2891 | { | |
2892 | target = gen_lowpart (DImode, dest); | |
e1ba4a27 | 2893 | if (can_create_pseudo_p ()) |
bbf31a61 | 2894 | subtarget = gen_reg_rtx (DImode); |
2895 | else | |
2896 | subtarget = target; | |
2897 | } | |
64656695 | 2898 | /* Below, we must be careful to use copy_rtx on target and subtarget |
2899 | in intermediate insns, as they may be a subreg rtx, which may not | |
2900 | be shared. */ | |
bbf31a61 | 2901 | |
2902 | if (f == 0 && exact_log2 (diff) > 0 | |
8d232dc7 | 2903 | /* On EV6, we've got enough shifters to make non-arithmetic shifts |
bbf31a61 | 2904 | viable over a longer latency cmove. On EV5, the E0 slot is a |
65abff06 | 2905 | scarce resource, and on EV4 shift has the same latency as a cmove. */ |
fb64edde | 2906 | && (diff <= 8 || alpha_tune == PROCESSOR_EV6)) |
bbf31a61 | 2907 | { |
2908 | tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx); | |
d1f9b275 | 2909 | emit_insn (gen_rtx_SET (copy_rtx (subtarget), tmp)); |
bbf31a61 | 2910 | |
64656695 | 2911 | tmp = gen_rtx_ASHIFT (DImode, copy_rtx (subtarget), |
2912 | GEN_INT (exact_log2 (t))); | |
d1f9b275 | 2913 | emit_insn (gen_rtx_SET (target, tmp)); |
bbf31a61 | 2914 | } |
2915 | else if (f == 0 && t == -1) | |
2916 | { | |
2917 | tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx); | |
d1f9b275 | 2918 | emit_insn (gen_rtx_SET (copy_rtx (subtarget), tmp)); |
bbf31a61 | 2919 | |
64656695 | 2920 | emit_insn (gen_negdi2 (target, copy_rtx (subtarget))); |
bbf31a61 | 2921 | } |
2922 | else if (diff == 1 || diff == 4 || diff == 8) | |
2923 | { | |
2924 | rtx add_op; | |
2925 | ||
2926 | tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx); | |
d1f9b275 | 2927 | emit_insn (gen_rtx_SET (copy_rtx (subtarget), tmp)); |
bbf31a61 | 2928 | |
2929 | if (diff == 1) | |
64656695 | 2930 | emit_insn (gen_adddi3 (target, copy_rtx (subtarget), GEN_INT (f))); |
bbf31a61 | 2931 | else |
2932 | { | |
2933 | add_op = GEN_INT (f); | |
2934 | if (sext_add_operand (add_op, mode)) | |
2935 | { | |
64656695 | 2936 | tmp = gen_rtx_MULT (DImode, copy_rtx (subtarget), |
2937 | GEN_INT (diff)); | |
bbf31a61 | 2938 | tmp = gen_rtx_PLUS (DImode, tmp, add_op); |
d1f9b275 | 2939 | emit_insn (gen_rtx_SET (target, tmp)); |
bbf31a61 | 2940 | } |
2941 | else | |
2942 | return 0; | |
2943 | } | |
2944 | } | |
2945 | else | |
2946 | return 0; | |
2947 | ||
2948 | return 1; | |
2949 | } | |
34377880 | 2950 | \f |
915c336f | 2951 | /* Look up the function X_floating library function name for the |
2952 | given operation. */ | |
2953 | ||
fb1e4f4a | 2954 | struct GTY(()) xfloating_op |
2d7c492e | 2955 | { |
2956 | const enum rtx_code code; | |
7035b2ab | 2957 | const char *const GTY((skip)) osf_func; |
2958 | const char *const GTY((skip)) vms_func; | |
2d7c492e | 2959 | rtx libcall; |
2960 | }; | |
2961 | ||
9e7454d0 | 2962 | static GTY(()) struct xfloating_op xfloating_ops[] = |
2d7c492e | 2963 | { |
2964 | { PLUS, "_OtsAddX", "OTS$ADD_X", 0 }, | |
2965 | { MINUS, "_OtsSubX", "OTS$SUB_X", 0 }, | |
2966 | { MULT, "_OtsMulX", "OTS$MUL_X", 0 }, | |
2967 | { DIV, "_OtsDivX", "OTS$DIV_X", 0 }, | |
2968 | { EQ, "_OtsEqlX", "OTS$EQL_X", 0 }, | |
2969 | { NE, "_OtsNeqX", "OTS$NEQ_X", 0 }, | |
2970 | { LT, "_OtsLssX", "OTS$LSS_X", 0 }, | |
2971 | { LE, "_OtsLeqX", "OTS$LEQ_X", 0 }, | |
2972 | { GT, "_OtsGtrX", "OTS$GTR_X", 0 }, | |
2973 | { GE, "_OtsGeqX", "OTS$GEQ_X", 0 }, | |
2974 | { FIX, "_OtsCvtXQ", "OTS$CVTXQ", 0 }, | |
2975 | { FLOAT, "_OtsCvtQX", "OTS$CVTQX", 0 }, | |
2976 | { UNSIGNED_FLOAT, "_OtsCvtQUX", "OTS$CVTQUX", 0 }, | |
2977 | { FLOAT_EXTEND, "_OtsConvertFloatTX", "OTS$CVT_FLOAT_T_X", 0 }, | |
2978 | { FLOAT_TRUNCATE, "_OtsConvertFloatXT", "OTS$CVT_FLOAT_X_T", 0 } | |
2979 | }; | |
2980 | ||
2981 | static GTY(()) struct xfloating_op vax_cvt_ops[] = | |
2982 | { | |
2983 | { FLOAT_EXTEND, "_OtsConvertFloatGX", "OTS$CVT_FLOAT_G_X", 0 }, | |
2984 | { FLOAT_TRUNCATE, "_OtsConvertFloatXG", "OTS$CVT_FLOAT_X_G", 0 } | |
2985 | }; | |
2986 | ||
2987 | static rtx | |
92643d95 | 2988 | alpha_lookup_xfloating_lib_func (enum rtx_code code) |
915c336f | 2989 | { |
2d7c492e | 2990 | struct xfloating_op *ops = xfloating_ops; |
2991 | long n = ARRAY_SIZE (xfloating_ops); | |
915c336f | 2992 | long i; |
2993 | ||
8c3428a6 | 2994 | gcc_assert (TARGET_HAS_XFLOATING_LIBS); |
2995 | ||
2d7c492e | 2996 | /* How irritating. Nothing to key off for the main table. */ |
2997 | if (TARGET_FLOAT_VAX && (code == FLOAT_EXTEND || code == FLOAT_TRUNCATE)) | |
915c336f | 2998 | { |
2d7c492e | 2999 | ops = vax_cvt_ops; |
3000 | n = ARRAY_SIZE (vax_cvt_ops); | |
915c336f | 3001 | } |
3002 | ||
2d7c492e | 3003 | for (i = 0; i < n; ++i, ++ops) |
3004 | if (ops->code == code) | |
3005 | { | |
3006 | rtx func = ops->libcall; | |
3007 | if (!func) | |
3008 | { | |
3009 | func = init_one_libfunc (TARGET_ABI_OPEN_VMS | |
3010 | ? ops->vms_func : ops->osf_func); | |
3011 | ops->libcall = func; | |
3012 | } | |
3013 | return func; | |
3014 | } | |
915c336f | 3015 | |
4d10b463 | 3016 | gcc_unreachable (); |
915c336f | 3017 | } |
3018 | ||
3019 | /* Most X_floating operations take the rounding mode as an argument. | |
3020 | Compute that here. */ | |
3021 | ||
3022 | static int | |
92643d95 | 3023 | alpha_compute_xfloating_mode_arg (enum rtx_code code, |
3024 | enum alpha_fp_rounding_mode round) | |
915c336f | 3025 | { |
3026 | int mode; | |
3027 | ||
3028 | switch (round) | |
3029 | { | |
3030 | case ALPHA_FPRM_NORM: | |
3031 | mode = 2; | |
3032 | break; | |
3033 | case ALPHA_FPRM_MINF: | |
3034 | mode = 1; | |
3035 | break; | |
3036 | case ALPHA_FPRM_CHOP: | |
3037 | mode = 0; | |
3038 | break; | |
3039 | case ALPHA_FPRM_DYN: | |
3040 | mode = 4; | |
3041 | break; | |
3042 | default: | |
4d10b463 | 3043 | gcc_unreachable (); |
915c336f | 3044 | |
3045 | /* XXX For reference, round to +inf is mode = 3. */ | |
3046 | } | |
3047 | ||
3048 | if (code == FLOAT_TRUNCATE && alpha_fptm == ALPHA_FPTM_N) | |
3049 | mode |= 0x10000; | |
3050 | ||
3051 | return mode; | |
3052 | } | |
3053 | ||
3054 | /* Emit an X_floating library function call. | |
3055 | ||
3056 | Note that these functions do not follow normal calling conventions: | |
3057 | TFmode arguments are passed in two integer registers (as opposed to | |
9e7454d0 | 3058 | indirect); TFmode return values appear in R16+R17. |
915c336f | 3059 | |
2d7c492e | 3060 | FUNC is the function to call. |
915c336f | 3061 | TARGET is where the output belongs. |
3062 | OPERANDS are the inputs. | |
3063 | NOPERANDS is the count of inputs. | |
3064 | EQUIV is the expression equivalent for the function. | |
3065 | */ | |
3066 | ||
3067 | static void | |
2d7c492e | 3068 | alpha_emit_xfloating_libcall (rtx func, rtx target, rtx operands[], |
92643d95 | 3069 | int noperands, rtx equiv) |
915c336f | 3070 | { |
3071 | rtx usage = NULL_RTX, tmp, reg; | |
3072 | int regno = 16, i; | |
3073 | ||
3074 | start_sequence (); | |
3075 | ||
3076 | for (i = 0; i < noperands; ++i) | |
3077 | { | |
3078 | switch (GET_MODE (operands[i])) | |
3079 | { | |
3080 | case TFmode: | |
3081 | reg = gen_rtx_REG (TFmode, regno); | |
3082 | regno += 2; | |
3083 | break; | |
3084 | ||
3085 | case DFmode: | |
3086 | reg = gen_rtx_REG (DFmode, regno + 32); | |
3087 | regno += 1; | |
3088 | break; | |
3089 | ||
3090 | case VOIDmode: | |
c933fb42 | 3091 | gcc_assert (CONST_INT_P (operands[i])); |
8e262b5e | 3092 | /* FALLTHRU */ |
915c336f | 3093 | case DImode: |
3094 | reg = gen_rtx_REG (DImode, regno); | |
3095 | regno += 1; | |
3096 | break; | |
3097 | ||
3098 | default: | |
4d10b463 | 3099 | gcc_unreachable (); |
915c336f | 3100 | } |
3101 | ||
3102 | emit_move_insn (reg, operands[i]); | |
f2606961 | 3103 | use_reg (&usage, reg); |
915c336f | 3104 | } |
3105 | ||
3106 | switch (GET_MODE (target)) | |
3107 | { | |
3108 | case TFmode: | |
3109 | reg = gen_rtx_REG (TFmode, 16); | |
3110 | break; | |
3111 | case DFmode: | |
3112 | reg = gen_rtx_REG (DFmode, 32); | |
3113 | break; | |
3114 | case DImode: | |
3115 | reg = gen_rtx_REG (DImode, 0); | |
3116 | break; | |
3117 | default: | |
4d10b463 | 3118 | gcc_unreachable (); |
915c336f | 3119 | } |
3120 | ||
2d7c492e | 3121 | tmp = gen_rtx_MEM (QImode, func); |
2c6f8e4d | 3122 | tmp = emit_call_insn (GEN_CALL_VALUE (reg, tmp, const0_rtx, |
915c336f | 3123 | const0_rtx, const0_rtx)); |
3124 | CALL_INSN_FUNCTION_USAGE (tmp) = usage; | |
9c2a0c05 | 3125 | RTL_CONST_CALL_P (tmp) = 1; |
915c336f | 3126 | |
3127 | tmp = get_insns (); | |
3128 | end_sequence (); | |
3129 | ||
3130 | emit_libcall_block (tmp, target, reg, equiv); | |
3131 | } | |
3132 | ||
3133 | /* Emit an X_floating library function call for arithmetic (+,-,*,/). */ | |
3134 | ||
3135 | void | |
92643d95 | 3136 | alpha_emit_xfloating_arith (enum rtx_code code, rtx operands[]) |
915c336f | 3137 | { |
2d7c492e | 3138 | rtx func; |
915c336f | 3139 | int mode; |
b90b6519 | 3140 | rtx out_operands[3]; |
915c336f | 3141 | |
3142 | func = alpha_lookup_xfloating_lib_func (code); | |
3143 | mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm); | |
3144 | ||
b90b6519 | 3145 | out_operands[0] = operands[1]; |
3146 | out_operands[1] = operands[2]; | |
3147 | out_operands[2] = GEN_INT (mode); | |
9e7454d0 | 3148 | alpha_emit_xfloating_libcall (func, operands[0], out_operands, 3, |
915c336f | 3149 | gen_rtx_fmt_ee (code, TFmode, operands[1], |
3150 | operands[2])); | |
3151 | } | |
3152 | ||
3153 | /* Emit an X_floating library function call for a comparison. */ | |
3154 | ||
3155 | static rtx | |
8c3428a6 | 3156 | alpha_emit_xfloating_compare (enum rtx_code *pcode, rtx op0, rtx op1) |
915c336f | 3157 | { |
8c3428a6 | 3158 | enum rtx_code cmp_code, res_code; |
e8e27646 | 3159 | rtx func, out, operands[2], note; |
915c336f | 3160 | |
8c3428a6 | 3161 | /* X_floating library comparison functions return |
3162 | -1 unordered | |
3163 | 0 false | |
3164 | 1 true | |
3165 | Convert the compare against the raw return value. */ | |
3166 | ||
3167 | cmp_code = *pcode; | |
3168 | switch (cmp_code) | |
3169 | { | |
3170 | case UNORDERED: | |
3171 | cmp_code = EQ; | |
3172 | res_code = LT; | |
3173 | break; | |
3174 | case ORDERED: | |
3175 | cmp_code = EQ; | |
3176 | res_code = GE; | |
3177 | break; | |
3178 | case NE: | |
3179 | res_code = NE; | |
3180 | break; | |
3181 | case EQ: | |
3182 | case LT: | |
3183 | case GT: | |
3184 | case LE: | |
3185 | case GE: | |
3186 | res_code = GT; | |
3187 | break; | |
3188 | default: | |
3189 | gcc_unreachable (); | |
3190 | } | |
3191 | *pcode = res_code; | |
3192 | ||
3193 | func = alpha_lookup_xfloating_lib_func (cmp_code); | |
915c336f | 3194 | |
3195 | operands[0] = op0; | |
3196 | operands[1] = op1; | |
3197 | out = gen_reg_rtx (DImode); | |
3198 | ||
8ebff8a4 | 3199 | /* What's actually returned is -1,0,1, not a proper boolean value. */ |
ad94304e | 3200 | note = gen_rtx_fmt_ee (cmp_code, VOIDmode, op0, op1); |
3201 | note = gen_rtx_UNSPEC (DImode, gen_rtvec (1, note), UNSPEC_XFLT_COMPARE); | |
e8e27646 | 3202 | alpha_emit_xfloating_libcall (func, out, operands, 2, note); |
915c336f | 3203 | |
3204 | return out; | |
3205 | } | |
3206 | ||
3207 | /* Emit an X_floating library function call for a conversion. */ | |
3208 | ||
3209 | void | |
caf6f044 | 3210 | alpha_emit_xfloating_cvt (enum rtx_code orig_code, rtx operands[]) |
915c336f | 3211 | { |
3212 | int noperands = 1, mode; | |
b90b6519 | 3213 | rtx out_operands[2]; |
2d7c492e | 3214 | rtx func; |
caf6f044 | 3215 | enum rtx_code code = orig_code; |
3216 | ||
3217 | if (code == UNSIGNED_FIX) | |
3218 | code = FIX; | |
915c336f | 3219 | |
3220 | func = alpha_lookup_xfloating_lib_func (code); | |
3221 | ||
b90b6519 | 3222 | out_operands[0] = operands[1]; |
3223 | ||
915c336f | 3224 | switch (code) |
3225 | { | |
3226 | case FIX: | |
3227 | mode = alpha_compute_xfloating_mode_arg (code, ALPHA_FPRM_CHOP); | |
b90b6519 | 3228 | out_operands[1] = GEN_INT (mode); |
8581412d | 3229 | noperands = 2; |
915c336f | 3230 | break; |
3231 | case FLOAT_TRUNCATE: | |
3232 | mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm); | |
b90b6519 | 3233 | out_operands[1] = GEN_INT (mode); |
8581412d | 3234 | noperands = 2; |
915c336f | 3235 | break; |
3236 | default: | |
3237 | break; | |
3238 | } | |
3239 | ||
b90b6519 | 3240 | alpha_emit_xfloating_libcall (func, operands[0], out_operands, noperands, |
caf6f044 | 3241 | gen_rtx_fmt_e (orig_code, |
3242 | GET_MODE (operands[0]), | |
915c336f | 3243 | operands[1])); |
3244 | } | |
3420680b | 3245 | |
10c77d2b | 3246 | /* Split a TImode or TFmode move from OP[1] to OP[0] into a pair of |
3247 | DImode moves from OP[2,3] to OP[0,1]. If FIXUP_OVERLAP is true, | |
3248 | guarantee that the sequence | |
3249 | set (OP[0] OP[2]) | |
3250 | set (OP[1] OP[3]) | |
3251 | is valid. Naturally, output operand ordering is little-endian. | |
3252 | This is used by *movtf_internal and *movti_internal. */ | |
3253 | ||
3420680b | 3254 | void |
3754d046 | 3255 | alpha_split_tmode_pair (rtx operands[4], machine_mode mode, |
10c77d2b | 3256 | bool fixup_overlap) |
3420680b | 3257 | { |
4d10b463 | 3258 | switch (GET_CODE (operands[1])) |
3420680b | 3259 | { |
4d10b463 | 3260 | case REG: |
3420680b | 3261 | operands[3] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1); |
3262 | operands[2] = gen_rtx_REG (DImode, REGNO (operands[1])); | |
4d10b463 | 3263 | break; |
3264 | ||
3265 | case MEM: | |
e513d163 | 3266 | operands[3] = adjust_address (operands[1], DImode, 8); |
3267 | operands[2] = adjust_address (operands[1], DImode, 0); | |
4d10b463 | 3268 | break; |
3269 | ||
7bc95bfb | 3270 | CASE_CONST_SCALAR_INT: |
e4a93d80 | 3271 | case CONST_DOUBLE: |
10c77d2b | 3272 | gcc_assert (operands[1] == CONST0_RTX (mode)); |
4d10b463 | 3273 | operands[2] = operands[3] = const0_rtx; |
3274 | break; | |
3275 | ||
3276 | default: | |
3277 | gcc_unreachable (); | |
3420680b | 3278 | } |
3420680b | 3279 | |
4d10b463 | 3280 | switch (GET_CODE (operands[0])) |
3420680b | 3281 | { |
4d10b463 | 3282 | case REG: |
3420680b | 3283 | operands[1] = gen_rtx_REG (DImode, REGNO (operands[0]) + 1); |
3284 | operands[0] = gen_rtx_REG (DImode, REGNO (operands[0])); | |
4d10b463 | 3285 | break; |
3286 | ||
3287 | case MEM: | |
e513d163 | 3288 | operands[1] = adjust_address (operands[0], DImode, 8); |
3289 | operands[0] = adjust_address (operands[0], DImode, 0); | |
4d10b463 | 3290 | break; |
3291 | ||
3292 | default: | |
3293 | gcc_unreachable (); | |
3420680b | 3294 | } |
10c77d2b | 3295 | |
3296 | if (fixup_overlap && reg_overlap_mentioned_p (operands[0], operands[3])) | |
3297 | { | |
612bd519 | 3298 | std::swap (operands[0], operands[1]); |
3299 | std::swap (operands[2], operands[3]); | |
10c77d2b | 3300 | } |
3420680b | 3301 | } |
2267ca84 | 3302 | |
9e7454d0 | 3303 | /* Implement negtf2 or abstf2. Op0 is destination, op1 is source, |
3304 | op2 is a register containing the sign bit, operation is the | |
2267ca84 | 3305 | logical operation to be performed. */ |
3306 | ||
3307 | void | |
92643d95 | 3308 | alpha_split_tfmode_frobsign (rtx operands[3], rtx (*operation) (rtx, rtx, rtx)) |
2267ca84 | 3309 | { |
3310 | rtx high_bit = operands[2]; | |
3311 | rtx scratch; | |
3312 | int move; | |
3313 | ||
10c77d2b | 3314 | alpha_split_tmode_pair (operands, TFmode, false); |
2267ca84 | 3315 | |
e3e08e7f | 3316 | /* Detect three flavors of operand overlap. */ |
2267ca84 | 3317 | move = 1; |
3318 | if (rtx_equal_p (operands[0], operands[2])) | |
3319 | move = 0; | |
3320 | else if (rtx_equal_p (operands[1], operands[2])) | |
3321 | { | |
3322 | if (rtx_equal_p (operands[0], high_bit)) | |
3323 | move = 2; | |
3324 | else | |
3325 | move = -1; | |
3326 | } | |
3327 | ||
3328 | if (move < 0) | |
3329 | emit_move_insn (operands[0], operands[2]); | |
3330 | ||
3331 | /* ??? If the destination overlaps both source tf and high_bit, then | |
3332 | assume source tf is dead in its entirety and use the other half | |
3333 | for a scratch register. Otherwise "scratch" is just the proper | |
3334 | destination register. */ | |
3335 | scratch = operands[move < 2 ? 1 : 3]; | |
3336 | ||
3337 | emit_insn ((*operation) (scratch, high_bit, operands[3])); | |
3338 | ||
3339 | if (move > 0) | |
3340 | { | |
3341 | emit_move_insn (operands[0], operands[2]); | |
3342 | if (move > 1) | |
3343 | emit_move_insn (operands[1], scratch); | |
3344 | } | |
3345 | } | |
915c336f | 3346 | \f |
34377880 | 3347 | /* Use ext[wlq][lh] as the Architecture Handbook describes for extracting |
3348 | unaligned data: | |
3349 | ||
3350 | unsigned: signed: | |
3351 | word: ldq_u r1,X(r11) ldq_u r1,X(r11) | |
3352 | ldq_u r2,X+1(r11) ldq_u r2,X+1(r11) | |
3353 | lda r3,X(r11) lda r3,X+2(r11) | |
3354 | extwl r1,r3,r1 extql r1,r3,r1 | |
3355 | extwh r2,r3,r2 extqh r2,r3,r2 | |
3356 | or r1.r2.r1 or r1,r2,r1 | |
3357 | sra r1,48,r1 | |
3358 | ||
3359 | long: ldq_u r1,X(r11) ldq_u r1,X(r11) | |
3360 | ldq_u r2,X+3(r11) ldq_u r2,X+3(r11) | |
3361 | lda r3,X(r11) lda r3,X(r11) | |
3362 | extll r1,r3,r1 extll r1,r3,r1 | |
3363 | extlh r2,r3,r2 extlh r2,r3,r2 | |
3364 | or r1.r2.r1 addl r1,r2,r1 | |
3365 | ||
3366 | quad: ldq_u r1,X(r11) | |
3367 | ldq_u r2,X+7(r11) | |
3368 | lda r3,X(r11) | |
3369 | extql r1,r3,r1 | |
3370 | extqh r2,r3,r2 | |
3371 | or r1.r2.r1 | |
3372 | */ | |
3373 | ||
3374 | void | |
92643d95 | 3375 | alpha_expand_unaligned_load (rtx tgt, rtx mem, HOST_WIDE_INT size, |
3376 | HOST_WIDE_INT ofs, int sign) | |
34377880 | 3377 | { |
1f0ce6a6 | 3378 | rtx meml, memh, addr, extl, exth, tmp, mema; |
3754d046 | 3379 | machine_mode mode; |
34377880 | 3380 | |
9467fa25 | 3381 | if (TARGET_BWX && size == 2) |
3382 | { | |
b83bea6c | 3383 | meml = adjust_address (mem, QImode, ofs); |
3384 | memh = adjust_address (mem, QImode, ofs+1); | |
9467fa25 | 3385 | extl = gen_reg_rtx (DImode); |
3386 | exth = gen_reg_rtx (DImode); | |
3387 | emit_insn (gen_zero_extendqidi2 (extl, meml)); | |
3388 | emit_insn (gen_zero_extendqidi2 (exth, memh)); | |
3389 | exth = expand_simple_binop (DImode, ASHIFT, exth, GEN_INT (8), | |
3390 | NULL, 1, OPTAB_LIB_WIDEN); | |
3391 | addr = expand_simple_binop (DImode, IOR, extl, exth, | |
3392 | NULL, 1, OPTAB_LIB_WIDEN); | |
3393 | ||
3394 | if (sign && GET_MODE (tgt) != HImode) | |
3395 | { | |
3396 | addr = gen_lowpart (HImode, addr); | |
3397 | emit_insn (gen_extend_insn (tgt, addr, GET_MODE (tgt), HImode, 0)); | |
3398 | } | |
3399 | else | |
3400 | { | |
3401 | if (GET_MODE (tgt) != DImode) | |
3402 | addr = gen_lowpart (GET_MODE (tgt), addr); | |
3403 | emit_move_insn (tgt, addr); | |
3404 | } | |
3405 | return; | |
3406 | } | |
3407 | ||
34377880 | 3408 | meml = gen_reg_rtx (DImode); |
3409 | memh = gen_reg_rtx (DImode); | |
3410 | addr = gen_reg_rtx (DImode); | |
3411 | extl = gen_reg_rtx (DImode); | |
3412 | exth = gen_reg_rtx (DImode); | |
3413 | ||
1f0ce6a6 | 3414 | mema = XEXP (mem, 0); |
3415 | if (GET_CODE (mema) == LO_SUM) | |
3416 | mema = force_reg (Pmode, mema); | |
3417 | ||
3024e9f8 | 3418 | /* AND addresses cannot be in any alias set, since they may implicitly |
9e7454d0 | 3419 | alias surrounding code. Ideally we'd have some alias set that |
3024e9f8 | 3420 | covered all types except those with alignment 8 or higher. */ |
3421 | ||
3422 | tmp = change_address (mem, DImode, | |
9e7454d0 | 3423 | gen_rtx_AND (DImode, |
29c05e22 | 3424 | plus_constant (DImode, mema, ofs), |
3024e9f8 | 3425 | GEN_INT (-8))); |
ab6ab77e | 3426 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3427 | emit_move_insn (meml, tmp); |
3428 | ||
3429 | tmp = change_address (mem, DImode, | |
9e7454d0 | 3430 | gen_rtx_AND (DImode, |
29c05e22 | 3431 | plus_constant (DImode, mema, |
3432 | ofs + size - 1), | |
3024e9f8 | 3433 | GEN_INT (-8))); |
ab6ab77e | 3434 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3435 | emit_move_insn (memh, tmp); |
34377880 | 3436 | |
9bab4302 | 3437 | if (sign && size == 2) |
34377880 | 3438 | { |
29c05e22 | 3439 | emit_move_insn (addr, plus_constant (Pmode, mema, ofs+2)); |
34377880 | 3440 | |
7a20d8cd | 3441 | emit_insn (gen_extql (extl, meml, addr)); |
9bab4302 | 3442 | emit_insn (gen_extqh (exth, memh, addr)); |
34377880 | 3443 | |
ba4a7733 | 3444 | /* We must use tgt here for the target. Alpha-vms port fails if we use |
3445 | addr for the target, because addr is marked as a pointer and combine | |
85c36fd1 | 3446 | knows that pointers are always sign-extended 32-bit values. */ |
ba4a7733 | 3447 | addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN); |
9e7454d0 | 3448 | addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (48), |
2cc46ade | 3449 | addr, 1, OPTAB_WIDEN); |
34377880 | 3450 | } |
2cc46ade | 3451 | else |
34377880 | 3452 | { |
29c05e22 | 3453 | emit_move_insn (addr, plus_constant (Pmode, mema, ofs)); |
9bab4302 | 3454 | emit_insn (gen_extxl (extl, meml, GEN_INT (size*8), addr)); |
3455 | switch ((int) size) | |
9caef960 | 3456 | { |
9bab4302 | 3457 | case 2: |
3458 | emit_insn (gen_extwh (exth, memh, addr)); | |
3459 | mode = HImode; | |
3460 | break; | |
9bab4302 | 3461 | case 4: |
3462 | emit_insn (gen_extlh (exth, memh, addr)); | |
3463 | mode = SImode; | |
3464 | break; | |
9bab4302 | 3465 | case 8: |
3466 | emit_insn (gen_extqh (exth, memh, addr)); | |
3467 | mode = DImode; | |
3468 | break; | |
9bab4302 | 3469 | default: |
3470 | gcc_unreachable (); | |
2cc46ade | 3471 | } |
3472 | ||
3473 | addr = expand_binop (mode, ior_optab, gen_lowpart (mode, extl), | |
3474 | gen_lowpart (mode, exth), gen_lowpart (mode, tgt), | |
3475 | sign, OPTAB_WIDEN); | |
34377880 | 3476 | } |
3477 | ||
2cc46ade | 3478 | if (addr != tgt) |
9467fa25 | 3479 | emit_move_insn (tgt, gen_lowpart (GET_MODE (tgt), addr)); |
34377880 | 3480 | } |
3481 | ||
3482 | /* Similarly, use ins and msk instructions to perform unaligned stores. */ | |
3483 | ||
3484 | void | |
92643d95 | 3485 | alpha_expand_unaligned_store (rtx dst, rtx src, |
3486 | HOST_WIDE_INT size, HOST_WIDE_INT ofs) | |
34377880 | 3487 | { |
1f0ce6a6 | 3488 | rtx dstl, dsth, addr, insl, insh, meml, memh, dsta; |
9e7454d0 | 3489 | |
9467fa25 | 3490 | if (TARGET_BWX && size == 2) |
3491 | { | |
3492 | if (src != const0_rtx) | |
3493 | { | |
3494 | dstl = gen_lowpart (QImode, src); | |
3495 | dsth = expand_simple_binop (DImode, LSHIFTRT, src, GEN_INT (8), | |
3496 | NULL, 1, OPTAB_LIB_WIDEN); | |
3497 | dsth = gen_lowpart (QImode, dsth); | |
3498 | } | |
3499 | else | |
3500 | dstl = dsth = const0_rtx; | |
3501 | ||
b83bea6c | 3502 | meml = adjust_address (dst, QImode, ofs); |
3503 | memh = adjust_address (dst, QImode, ofs+1); | |
9467fa25 | 3504 | |
3505 | emit_move_insn (meml, dstl); | |
3506 | emit_move_insn (memh, dsth); | |
3507 | return; | |
3508 | } | |
3509 | ||
34377880 | 3510 | dstl = gen_reg_rtx (DImode); |
3511 | dsth = gen_reg_rtx (DImode); | |
3512 | insl = gen_reg_rtx (DImode); | |
3513 | insh = gen_reg_rtx (DImode); | |
3514 | ||
1f0ce6a6 | 3515 | dsta = XEXP (dst, 0); |
3516 | if (GET_CODE (dsta) == LO_SUM) | |
3517 | dsta = force_reg (Pmode, dsta); | |
3518 | ||
3024e9f8 | 3519 | /* AND addresses cannot be in any alias set, since they may implicitly |
9e7454d0 | 3520 | alias surrounding code. Ideally we'd have some alias set that |
3024e9f8 | 3521 | covered all types except those with alignment 8 or higher. */ |
3522 | ||
34377880 | 3523 | meml = change_address (dst, DImode, |
9e7454d0 | 3524 | gen_rtx_AND (DImode, |
29c05e22 | 3525 | plus_constant (DImode, dsta, ofs), |
941522d6 | 3526 | GEN_INT (-8))); |
ab6ab77e | 3527 | set_mem_alias_set (meml, 0); |
3024e9f8 | 3528 | |
34377880 | 3529 | memh = change_address (dst, DImode, |
9e7454d0 | 3530 | gen_rtx_AND (DImode, |
29c05e22 | 3531 | plus_constant (DImode, dsta, |
3532 | ofs + size - 1), | |
941522d6 | 3533 | GEN_INT (-8))); |
ab6ab77e | 3534 | set_mem_alias_set (memh, 0); |
34377880 | 3535 | |
3536 | emit_move_insn (dsth, memh); | |
3537 | emit_move_insn (dstl, meml); | |
9caef960 | 3538 | |
29c05e22 | 3539 | addr = copy_addr_to_reg (plus_constant (Pmode, dsta, ofs)); |
9bab4302 | 3540 | |
3541 | if (src != CONST0_RTX (GET_MODE (src))) | |
3542 | { | |
3543 | emit_insn (gen_insxh (insh, gen_lowpart (DImode, src), | |
3544 | GEN_INT (size*8), addr)); | |
34377880 | 3545 | |
29768226 | 3546 | switch ((int) size) |
34377880 | 3547 | { |
3548 | case 2: | |
9bab4302 | 3549 | emit_insn (gen_inswl (insl, gen_lowpart (HImode, src), addr)); |
34377880 | 3550 | break; |
3551 | case 4: | |
9bab4302 | 3552 | emit_insn (gen_insll (insl, gen_lowpart (SImode, src), addr)); |
3553 | break; | |
ae4cd3a5 | 3554 | case 8: |
9bab4302 | 3555 | emit_insn (gen_insql (insl, gen_lowpart (DImode, src), addr)); |
34377880 | 3556 | break; |
9bab4302 | 3557 | default: |
3558 | gcc_unreachable (); | |
34377880 | 3559 | } |
3560 | } | |
9caef960 | 3561 | |
9bab4302 | 3562 | emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr)); |
9caef960 | 3563 | |
9bab4302 | 3564 | switch ((int) size) |
3565 | { | |
3566 | case 2: | |
7a20d8cd | 3567 | emit_insn (gen_mskwl (dstl, dstl, addr)); |
9bab4302 | 3568 | break; |
3569 | case 4: | |
7a20d8cd | 3570 | emit_insn (gen_mskll (dstl, dstl, addr)); |
3571 | break; | |
9bab4302 | 3572 | case 8: |
7a20d8cd | 3573 | emit_insn (gen_mskql (dstl, dstl, addr)); |
9bab4302 | 3574 | break; |
3575 | default: | |
3576 | gcc_unreachable (); | |
34377880 | 3577 | } |
3578 | ||
b739144f | 3579 | if (src != CONST0_RTX (GET_MODE (src))) |
34377880 | 3580 | { |
2cc46ade | 3581 | dsth = expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN); |
3582 | dstl = expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN); | |
34377880 | 3583 | } |
9e7454d0 | 3584 | |
9bab4302 | 3585 | /* Must store high before low for degenerate case of aligned. */ |
3586 | emit_move_insn (memh, dsth); | |
3587 | emit_move_insn (meml, dstl); | |
34377880 | 3588 | } |
3589 | ||
2cc46ade | 3590 | /* The block move code tries to maximize speed by separating loads and |
3591 | stores at the expense of register pressure: we load all of the data | |
3592 | before we store it back out. There are two secondary effects worth | |
3593 | mentioning, that this speeds copying to/from aligned and unaligned | |
3594 | buffers, and that it makes the code significantly easier to write. */ | |
34377880 | 3595 | |
2cc46ade | 3596 | #define MAX_MOVE_WORDS 8 |
3597 | ||
3598 | /* Load an integral number of consecutive unaligned quadwords. */ | |
34377880 | 3599 | |
3600 | static void | |
92643d95 | 3601 | alpha_expand_unaligned_load_words (rtx *out_regs, rtx smem, |
3602 | HOST_WIDE_INT words, HOST_WIDE_INT ofs) | |
34377880 | 3603 | { |
3604 | rtx const im8 = GEN_INT (-8); | |
2cc46ade | 3605 | rtx ext_tmps[MAX_MOVE_WORDS], data_regs[MAX_MOVE_WORDS+1]; |
1f0ce6a6 | 3606 | rtx sreg, areg, tmp, smema; |
34377880 | 3607 | HOST_WIDE_INT i; |
3608 | ||
1f0ce6a6 | 3609 | smema = XEXP (smem, 0); |
3610 | if (GET_CODE (smema) == LO_SUM) | |
3611 | smema = force_reg (Pmode, smema); | |
3612 | ||
34377880 | 3613 | /* Generate all the tmp registers we need. */ |
3614 | for (i = 0; i < words; ++i) | |
2cc46ade | 3615 | { |
3616 | data_regs[i] = out_regs[i]; | |
3617 | ext_tmps[i] = gen_reg_rtx (DImode); | |
3618 | } | |
3619 | data_regs[words] = gen_reg_rtx (DImode); | |
3620 | ||
3621 | if (ofs != 0) | |
e513d163 | 3622 | smem = adjust_address (smem, GET_MODE (smem), ofs); |
9e7454d0 | 3623 | |
34377880 | 3624 | /* Load up all of the source data. */ |
3625 | for (i = 0; i < words; ++i) | |
3626 | { | |
3024e9f8 | 3627 | tmp = change_address (smem, DImode, |
3628 | gen_rtx_AND (DImode, | |
29c05e22 | 3629 | plus_constant (DImode, smema, 8*i), |
3024e9f8 | 3630 | im8)); |
ab6ab77e | 3631 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3632 | emit_move_insn (data_regs[i], tmp); |
34377880 | 3633 | } |
3024e9f8 | 3634 | |
3635 | tmp = change_address (smem, DImode, | |
3636 | gen_rtx_AND (DImode, | |
29c05e22 | 3637 | plus_constant (DImode, smema, |
3638 | 8*words - 1), | |
3024e9f8 | 3639 | im8)); |
ab6ab77e | 3640 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3641 | emit_move_insn (data_regs[words], tmp); |
34377880 | 3642 | |
3643 | /* Extract the half-word fragments. Unfortunately DEC decided to make | |
9e7454d0 | 3644 | extxh with offset zero a noop instead of zeroing the register, so |
34377880 | 3645 | we must take care of that edge condition ourselves with cmov. */ |
3646 | ||
1f0ce6a6 | 3647 | sreg = copy_addr_to_reg (smema); |
9e7454d0 | 3648 | areg = expand_binop (DImode, and_optab, sreg, GEN_INT (7), NULL, |
2cc46ade | 3649 | 1, OPTAB_WIDEN); |
34377880 | 3650 | for (i = 0; i < words; ++i) |
3651 | { | |
7a20d8cd | 3652 | emit_insn (gen_extql (data_regs[i], data_regs[i], sreg)); |
9bab4302 | 3653 | emit_insn (gen_extqh (ext_tmps[i], data_regs[i+1], sreg)); |
d1f9b275 | 3654 | emit_insn (gen_rtx_SET (ext_tmps[i], |
941522d6 | 3655 | gen_rtx_IF_THEN_ELSE (DImode, |
2cc46ade | 3656 | gen_rtx_EQ (DImode, areg, |
3657 | const0_rtx), | |
941522d6 | 3658 | const0_rtx, ext_tmps[i]))); |
34377880 | 3659 | } |
3660 | ||
3661 | /* Merge the half-words into whole words. */ | |
3662 | for (i = 0; i < words; ++i) | |
3663 | { | |
2cc46ade | 3664 | out_regs[i] = expand_binop (DImode, ior_optab, data_regs[i], |
3665 | ext_tmps[i], data_regs[i], 1, OPTAB_WIDEN); | |
34377880 | 3666 | } |
3667 | } | |
3668 | ||
3669 | /* Store an integral number of consecutive unaligned quadwords. DATA_REGS | |
3670 | may be NULL to store zeros. */ | |
3671 | ||
3672 | static void | |
92643d95 | 3673 | alpha_expand_unaligned_store_words (rtx *data_regs, rtx dmem, |
3674 | HOST_WIDE_INT words, HOST_WIDE_INT ofs) | |
34377880 | 3675 | { |
3676 | rtx const im8 = GEN_INT (-8); | |
34377880 | 3677 | rtx ins_tmps[MAX_MOVE_WORDS]; |
2cc46ade | 3678 | rtx st_tmp_1, st_tmp_2, dreg; |
1f0ce6a6 | 3679 | rtx st_addr_1, st_addr_2, dmema; |
34377880 | 3680 | HOST_WIDE_INT i; |
3681 | ||
1f0ce6a6 | 3682 | dmema = XEXP (dmem, 0); |
3683 | if (GET_CODE (dmema) == LO_SUM) | |
3684 | dmema = force_reg (Pmode, dmema); | |
3685 | ||
34377880 | 3686 | /* Generate all the tmp registers we need. */ |
3687 | if (data_regs != NULL) | |
3688 | for (i = 0; i < words; ++i) | |
3689 | ins_tmps[i] = gen_reg_rtx(DImode); | |
3690 | st_tmp_1 = gen_reg_rtx(DImode); | |
3691 | st_tmp_2 = gen_reg_rtx(DImode); | |
9e7454d0 | 3692 | |
2cc46ade | 3693 | if (ofs != 0) |
e513d163 | 3694 | dmem = adjust_address (dmem, GET_MODE (dmem), ofs); |
2cc46ade | 3695 | |
3696 | st_addr_2 = change_address (dmem, DImode, | |
941522d6 | 3697 | gen_rtx_AND (DImode, |
29c05e22 | 3698 | plus_constant (DImode, dmema, |
3699 | words*8 - 1), | |
3700 | im8)); | |
ab6ab77e | 3701 | set_mem_alias_set (st_addr_2, 0); |
3024e9f8 | 3702 | |
2cc46ade | 3703 | st_addr_1 = change_address (dmem, DImode, |
1f0ce6a6 | 3704 | gen_rtx_AND (DImode, dmema, im8)); |
ab6ab77e | 3705 | set_mem_alias_set (st_addr_1, 0); |
34377880 | 3706 | |
3707 | /* Load up the destination end bits. */ | |
3708 | emit_move_insn (st_tmp_2, st_addr_2); | |
3709 | emit_move_insn (st_tmp_1, st_addr_1); | |
3710 | ||
3711 | /* Shift the input data into place. */ | |
1f0ce6a6 | 3712 | dreg = copy_addr_to_reg (dmema); |
34377880 | 3713 | if (data_regs != NULL) |
3714 | { | |
3715 | for (i = words-1; i >= 0; --i) | |
3716 | { | |
7a20d8cd | 3717 | emit_insn (gen_insqh (ins_tmps[i], data_regs[i], dreg)); |
9bab4302 | 3718 | emit_insn (gen_insql (data_regs[i], data_regs[i], dreg)); |
34377880 | 3719 | } |
34377880 | 3720 | for (i = words-1; i > 0; --i) |
3721 | { | |
2cc46ade | 3722 | ins_tmps[i-1] = expand_binop (DImode, ior_optab, data_regs[i], |
3723 | ins_tmps[i-1], ins_tmps[i-1], 1, | |
3724 | OPTAB_WIDEN); | |
34377880 | 3725 | } |
3726 | } | |
3727 | ||
3728 | /* Split and merge the ends with the destination data. */ | |
7a20d8cd | 3729 | emit_insn (gen_mskqh (st_tmp_2, st_tmp_2, dreg)); |
3730 | emit_insn (gen_mskql (st_tmp_1, st_tmp_1, dreg)); | |
34377880 | 3731 | |
3732 | if (data_regs != NULL) | |
3733 | { | |
2cc46ade | 3734 | st_tmp_2 = expand_binop (DImode, ior_optab, st_tmp_2, ins_tmps[words-1], |
3735 | st_tmp_2, 1, OPTAB_WIDEN); | |
3736 | st_tmp_1 = expand_binop (DImode, ior_optab, st_tmp_1, data_regs[0], | |
3737 | st_tmp_1, 1, OPTAB_WIDEN); | |
34377880 | 3738 | } |
3739 | ||
3740 | /* Store it all. */ | |
9bab4302 | 3741 | emit_move_insn (st_addr_2, st_tmp_2); |
34377880 | 3742 | for (i = words-1; i > 0; --i) |
3743 | { | |
3024e9f8 | 3744 | rtx tmp = change_address (dmem, DImode, |
3745 | gen_rtx_AND (DImode, | |
29c05e22 | 3746 | plus_constant (DImode, |
3747 | dmema, i*8), | |
3024e9f8 | 3748 | im8)); |
ab6ab77e | 3749 | set_mem_alias_set (tmp, 0); |
3024e9f8 | 3750 | emit_move_insn (tmp, data_regs ? ins_tmps[i-1] : const0_rtx); |
34377880 | 3751 | } |
9bab4302 | 3752 | emit_move_insn (st_addr_1, st_tmp_1); |
34377880 | 3753 | } |
3754 | ||
3755 | ||
3756 | /* Expand string/block move operations. | |
3757 | ||
3758 | operands[0] is the pointer to the destination. | |
3759 | operands[1] is the pointer to the source. | |
3760 | operands[2] is the number of bytes to move. | |
3761 | operands[3] is the alignment. */ | |
3762 | ||
3763 | int | |
92643d95 | 3764 | alpha_expand_block_move (rtx operands[]) |
34377880 | 3765 | { |
3766 | rtx bytes_rtx = operands[2]; | |
3767 | rtx align_rtx = operands[3]; | |
d94b545b | 3768 | HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx); |
a9aaae37 | 3769 | HOST_WIDE_INT bytes = orig_bytes; |
3770 | HOST_WIDE_INT src_align = INTVAL (align_rtx) * BITS_PER_UNIT; | |
3771 | HOST_WIDE_INT dst_align = src_align; | |
80909c64 | 3772 | rtx orig_src = operands[1]; |
3773 | rtx orig_dst = operands[0]; | |
3774 | rtx data_regs[2 * MAX_MOVE_WORDS + 16]; | |
2cc46ade | 3775 | rtx tmp; |
1f0ce6a6 | 3776 | unsigned int i, words, ofs, nregs = 0; |
9e7454d0 | 3777 | |
80909c64 | 3778 | if (orig_bytes <= 0) |
34377880 | 3779 | return 1; |
a9aaae37 | 3780 | else if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD) |
34377880 | 3781 | return 0; |
3782 | ||
2cc46ade | 3783 | /* Look for additional alignment information from recorded register info. */ |
3784 | ||
3785 | tmp = XEXP (orig_src, 0); | |
c933fb42 | 3786 | if (REG_P (tmp)) |
80909c64 | 3787 | src_align = MAX (src_align, REGNO_POINTER_ALIGN (REGNO (tmp))); |
2cc46ade | 3788 | else if (GET_CODE (tmp) == PLUS |
c933fb42 | 3789 | && REG_P (XEXP (tmp, 0)) |
3790 | && CONST_INT_P (XEXP (tmp, 1))) | |
2cc46ade | 3791 | { |
80909c64 | 3792 | unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); |
3793 | unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); | |
2cc46ade | 3794 | |
3795 | if (a > src_align) | |
3796 | { | |
80909c64 | 3797 | if (a >= 64 && c % 8 == 0) |
3798 | src_align = 64; | |
3799 | else if (a >= 32 && c % 4 == 0) | |
3800 | src_align = 32; | |
3801 | else if (a >= 16 && c % 2 == 0) | |
3802 | src_align = 16; | |
2cc46ade | 3803 | } |
3804 | } | |
9e7454d0 | 3805 | |
2cc46ade | 3806 | tmp = XEXP (orig_dst, 0); |
c933fb42 | 3807 | if (REG_P (tmp)) |
80909c64 | 3808 | dst_align = MAX (dst_align, REGNO_POINTER_ALIGN (REGNO (tmp))); |
2cc46ade | 3809 | else if (GET_CODE (tmp) == PLUS |
c933fb42 | 3810 | && REG_P (XEXP (tmp, 0)) |
3811 | && CONST_INT_P (XEXP (tmp, 1))) | |
2cc46ade | 3812 | { |
80909c64 | 3813 | unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); |
3814 | unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); | |
2cc46ade | 3815 | |
3816 | if (a > dst_align) | |
3817 | { | |
80909c64 | 3818 | if (a >= 64 && c % 8 == 0) |
3819 | dst_align = 64; | |
3820 | else if (a >= 32 && c % 4 == 0) | |
3821 | dst_align = 32; | |
3822 | else if (a >= 16 && c % 2 == 0) | |
3823 | dst_align = 16; | |
2cc46ade | 3824 | } |
3825 | } | |
3826 | ||
2cc46ade | 3827 | ofs = 0; |
80909c64 | 3828 | if (src_align >= 64 && bytes >= 8) |
34377880 | 3829 | { |
3830 | words = bytes / 8; | |
3831 | ||
34377880 | 3832 | for (i = 0; i < words; ++i) |
27d0c333 | 3833 | data_regs[nregs + i] = gen_reg_rtx (DImode); |
34377880 | 3834 | |
34377880 | 3835 | for (i = 0; i < words; ++i) |
80909c64 | 3836 | emit_move_insn (data_regs[nregs + i], |
e513d163 | 3837 | adjust_address (orig_src, DImode, ofs + i * 8)); |
34377880 | 3838 | |
2cc46ade | 3839 | nregs += words; |
34377880 | 3840 | bytes -= words * 8; |
7597afe9 | 3841 | ofs += words * 8; |
34377880 | 3842 | } |
80909c64 | 3843 | |
3844 | if (src_align >= 32 && bytes >= 4) | |
34377880 | 3845 | { |
3846 | words = bytes / 4; | |
3847 | ||
34377880 | 3848 | for (i = 0; i < words; ++i) |
27d0c333 | 3849 | data_regs[nregs + i] = gen_reg_rtx (SImode); |
34377880 | 3850 | |
34377880 | 3851 | for (i = 0; i < words; ++i) |
80909c64 | 3852 | emit_move_insn (data_regs[nregs + i], |
537ffcfc | 3853 | adjust_address (orig_src, SImode, ofs + i * 4)); |
34377880 | 3854 | |
2cc46ade | 3855 | nregs += words; |
34377880 | 3856 | bytes -= words * 4; |
7597afe9 | 3857 | ofs += words * 4; |
34377880 | 3858 | } |
80909c64 | 3859 | |
a9aaae37 | 3860 | if (bytes >= 8) |
34377880 | 3861 | { |
3862 | words = bytes / 8; | |
3863 | ||
34377880 | 3864 | for (i = 0; i < words+1; ++i) |
27d0c333 | 3865 | data_regs[nregs + i] = gen_reg_rtx (DImode); |
34377880 | 3866 | |
b47268cf | 3867 | alpha_expand_unaligned_load_words (data_regs + nregs, orig_src, |
3868 | words, ofs); | |
34377880 | 3869 | |
2cc46ade | 3870 | nregs += words; |
34377880 | 3871 | bytes -= words * 8; |
7597afe9 | 3872 | ofs += words * 8; |
34377880 | 3873 | } |
80909c64 | 3874 | |
80909c64 | 3875 | if (! TARGET_BWX && bytes >= 4) |
34377880 | 3876 | { |
2cc46ade | 3877 | data_regs[nregs++] = tmp = gen_reg_rtx (SImode); |
34377880 | 3878 | alpha_expand_unaligned_load (tmp, orig_src, 4, ofs, 0); |
34377880 | 3879 | bytes -= 4; |
3880 | ofs += 4; | |
3881 | } | |
80909c64 | 3882 | |
34377880 | 3883 | if (bytes >= 2) |
3884 | { | |
80909c64 | 3885 | if (src_align >= 16) |
34377880 | 3886 | { |
3887 | do { | |
2cc46ade | 3888 | data_regs[nregs++] = tmp = gen_reg_rtx (HImode); |
e513d163 | 3889 | emit_move_insn (tmp, adjust_address (orig_src, HImode, ofs)); |
34377880 | 3890 | bytes -= 2; |
3891 | ofs += 2; | |
3892 | } while (bytes >= 2); | |
3893 | } | |
80909c64 | 3894 | else if (! TARGET_BWX) |
34377880 | 3895 | { |
2cc46ade | 3896 | data_regs[nregs++] = tmp = gen_reg_rtx (HImode); |
34377880 | 3897 | alpha_expand_unaligned_load (tmp, orig_src, 2, ofs, 0); |
34377880 | 3898 | bytes -= 2; |
3899 | ofs += 2; | |
3900 | } | |
3901 | } | |
80909c64 | 3902 | |
34377880 | 3903 | while (bytes > 0) |
3904 | { | |
2cc46ade | 3905 | data_regs[nregs++] = tmp = gen_reg_rtx (QImode); |
e513d163 | 3906 | emit_move_insn (tmp, adjust_address (orig_src, QImode, ofs)); |
34377880 | 3907 | bytes -= 1; |
3908 | ofs += 1; | |
3909 | } | |
80909c64 | 3910 | |
4d10b463 | 3911 | gcc_assert (nregs <= ARRAY_SIZE (data_regs)); |
2cc46ade | 3912 | |
80909c64 | 3913 | /* Now save it back out again. */ |
2cc46ade | 3914 | |
3915 | i = 0, ofs = 0; | |
3916 | ||
2cc46ade | 3917 | /* Write out the data in whatever chunks reading the source allowed. */ |
80909c64 | 3918 | if (dst_align >= 64) |
2cc46ade | 3919 | { |
3920 | while (i < nregs && GET_MODE (data_regs[i]) == DImode) | |
3921 | { | |
e513d163 | 3922 | emit_move_insn (adjust_address (orig_dst, DImode, ofs), |
2cc46ade | 3923 | data_regs[i]); |
3924 | ofs += 8; | |
3925 | i++; | |
3926 | } | |
3927 | } | |
80909c64 | 3928 | |
3929 | if (dst_align >= 32) | |
2cc46ade | 3930 | { |
3931 | /* If the source has remaining DImode regs, write them out in | |
3932 | two pieces. */ | |
3933 | while (i < nregs && GET_MODE (data_regs[i]) == DImode) | |
3934 | { | |
3935 | tmp = expand_binop (DImode, lshr_optab, data_regs[i], GEN_INT (32), | |
3936 | NULL_RTX, 1, OPTAB_WIDEN); | |
3937 | ||
e513d163 | 3938 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), |
2cc46ade | 3939 | gen_lowpart (SImode, data_regs[i])); |
e513d163 | 3940 | emit_move_insn (adjust_address (orig_dst, SImode, ofs + 4), |
2cc46ade | 3941 | gen_lowpart (SImode, tmp)); |
3942 | ofs += 8; | |
3943 | i++; | |
3944 | } | |
3945 | ||
3946 | while (i < nregs && GET_MODE (data_regs[i]) == SImode) | |
3947 | { | |
e513d163 | 3948 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), |
2cc46ade | 3949 | data_regs[i]); |
3950 | ofs += 4; | |
3951 | i++; | |
3952 | } | |
3953 | } | |
80909c64 | 3954 | |
2cc46ade | 3955 | if (i < nregs && GET_MODE (data_regs[i]) == DImode) |
3956 | { | |
3957 | /* Write out a remaining block of words using unaligned methods. */ | |
3958 | ||
80909c64 | 3959 | for (words = 1; i + words < nregs; words++) |
3960 | if (GET_MODE (data_regs[i + words]) != DImode) | |
2cc46ade | 3961 | break; |
3962 | ||
3963 | if (words == 1) | |
3964 | alpha_expand_unaligned_store (orig_dst, data_regs[i], 8, ofs); | |
3965 | else | |
80909c64 | 3966 | alpha_expand_unaligned_store_words (data_regs + i, orig_dst, |
3967 | words, ofs); | |
9e7454d0 | 3968 | |
2cc46ade | 3969 | i += words; |
3970 | ofs += words * 8; | |
3971 | } | |
3972 | ||
3973 | /* Due to the above, this won't be aligned. */ | |
3974 | /* ??? If we have more than one of these, consider constructing full | |
3975 | words in registers and using alpha_expand_unaligned_store_words. */ | |
3976 | while (i < nregs && GET_MODE (data_regs[i]) == SImode) | |
3977 | { | |
3978 | alpha_expand_unaligned_store (orig_dst, data_regs[i], 4, ofs); | |
3979 | ofs += 4; | |
3980 | i++; | |
3981 | } | |
3982 | ||
80909c64 | 3983 | if (dst_align >= 16) |
2cc46ade | 3984 | while (i < nregs && GET_MODE (data_regs[i]) == HImode) |
3985 | { | |
e513d163 | 3986 | emit_move_insn (adjust_address (orig_dst, HImode, ofs), data_regs[i]); |
2cc46ade | 3987 | i++; |
3988 | ofs += 2; | |
3989 | } | |
3990 | else | |
3991 | while (i < nregs && GET_MODE (data_regs[i]) == HImode) | |
3992 | { | |
3993 | alpha_expand_unaligned_store (orig_dst, data_regs[i], 2, ofs); | |
3994 | i++; | |
3995 | ofs += 2; | |
3996 | } | |
80909c64 | 3997 | |
4d10b463 | 3998 | /* The remainder must be byte copies. */ |
3999 | while (i < nregs) | |
2cc46ade | 4000 | { |
4d10b463 | 4001 | gcc_assert (GET_MODE (data_regs[i]) == QImode); |
e513d163 | 4002 | emit_move_insn (adjust_address (orig_dst, QImode, ofs), data_regs[i]); |
2cc46ade | 4003 | i++; |
4004 | ofs += 1; | |
4005 | } | |
80909c64 | 4006 | |
34377880 | 4007 | return 1; |
4008 | } | |
4009 | ||
4010 | int | |
92643d95 | 4011 | alpha_expand_block_clear (rtx operands[]) |
34377880 | 4012 | { |
4013 | rtx bytes_rtx = operands[1]; | |
7a3e5564 | 4014 | rtx align_rtx = operands[3]; |
80909c64 | 4015 | HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx); |
a9aaae37 | 4016 | HOST_WIDE_INT bytes = orig_bytes; |
4017 | HOST_WIDE_INT align = INTVAL (align_rtx) * BITS_PER_UNIT; | |
4018 | HOST_WIDE_INT alignofs = 0; | |
80909c64 | 4019 | rtx orig_dst = operands[0]; |
2cc46ade | 4020 | rtx tmp; |
a9aaae37 | 4021 | int i, words, ofs = 0; |
9e7454d0 | 4022 | |
80909c64 | 4023 | if (orig_bytes <= 0) |
34377880 | 4024 | return 1; |
a9aaae37 | 4025 | if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD) |
34377880 | 4026 | return 0; |
4027 | ||
2cc46ade | 4028 | /* Look for stricter alignment. */ |
2cc46ade | 4029 | tmp = XEXP (orig_dst, 0); |
c933fb42 | 4030 | if (REG_P (tmp)) |
80909c64 | 4031 | align = MAX (align, REGNO_POINTER_ALIGN (REGNO (tmp))); |
2cc46ade | 4032 | else if (GET_CODE (tmp) == PLUS |
c933fb42 | 4033 | && REG_P (XEXP (tmp, 0)) |
4034 | && CONST_INT_P (XEXP (tmp, 1))) | |
2cc46ade | 4035 | { |
a9aaae37 | 4036 | HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1)); |
4037 | int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0))); | |
2cc46ade | 4038 | |
4039 | if (a > align) | |
4040 | { | |
a9aaae37 | 4041 | if (a >= 64) |
4042 | align = a, alignofs = 8 - c % 8; | |
4043 | else if (a >= 32) | |
4044 | align = a, alignofs = 4 - c % 4; | |
4045 | else if (a >= 16) | |
4046 | align = a, alignofs = 2 - c % 2; | |
2cc46ade | 4047 | } |
4048 | } | |
4049 | ||
a9aaae37 | 4050 | /* Handle an unaligned prefix first. */ |
4051 | ||
4052 | if (alignofs > 0) | |
4053 | { | |
a9aaae37 | 4054 | /* Given that alignofs is bounded by align, the only time BWX could |
4055 | generate three stores is for a 7 byte fill. Prefer two individual | |
4056 | stores over a load/mask/store sequence. */ | |
4057 | if ((!TARGET_BWX || alignofs == 7) | |
4058 | && align >= 32 | |
4059 | && !(alignofs == 4 && bytes >= 4)) | |
4060 | { | |
3754d046 | 4061 | machine_mode mode = (align >= 64 ? DImode : SImode); |
a9aaae37 | 4062 | int inv_alignofs = (align >= 64 ? 8 : 4) - alignofs; |
4063 | rtx mem, tmp; | |
4064 | HOST_WIDE_INT mask; | |
4065 | ||
e513d163 | 4066 | mem = adjust_address (orig_dst, mode, ofs - inv_alignofs); |
ab6ab77e | 4067 | set_mem_alias_set (mem, 0); |
a9aaae37 | 4068 | |
4069 | mask = ~(~(HOST_WIDE_INT)0 << (inv_alignofs * 8)); | |
4070 | if (bytes < alignofs) | |
4071 | { | |
4072 | mask |= ~(HOST_WIDE_INT)0 << ((inv_alignofs + bytes) * 8); | |
4073 | ofs += bytes; | |
4074 | bytes = 0; | |
4075 | } | |
4076 | else | |
4077 | { | |
4078 | bytes -= alignofs; | |
4079 | ofs += alignofs; | |
4080 | } | |
4081 | alignofs = 0; | |
4082 | ||
4083 | tmp = expand_binop (mode, and_optab, mem, GEN_INT (mask), | |
4084 | NULL_RTX, 1, OPTAB_WIDEN); | |
4085 | ||
4086 | emit_move_insn (mem, tmp); | |
4087 | } | |
a9aaae37 | 4088 | |
4089 | if (TARGET_BWX && (alignofs & 1) && bytes >= 1) | |
4090 | { | |
e513d163 | 4091 | emit_move_insn (adjust_address (orig_dst, QImode, ofs), const0_rtx); |
a9aaae37 | 4092 | bytes -= 1; |
4093 | ofs += 1; | |
4094 | alignofs -= 1; | |
4095 | } | |
4096 | if (TARGET_BWX && align >= 16 && (alignofs & 3) == 2 && bytes >= 2) | |
4097 | { | |
e513d163 | 4098 | emit_move_insn (adjust_address (orig_dst, HImode, ofs), const0_rtx); |
a9aaae37 | 4099 | bytes -= 2; |
4100 | ofs += 2; | |
4101 | alignofs -= 2; | |
4102 | } | |
4103 | if (alignofs == 4 && bytes >= 4) | |
4104 | { | |
e513d163 | 4105 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx); |
a9aaae37 | 4106 | bytes -= 4; |
4107 | ofs += 4; | |
4108 | alignofs = 0; | |
4109 | } | |
4110 | ||
4111 | /* If we've not used the extra lead alignment information by now, | |
4112 | we won't be able to. Downgrade align to match what's left over. */ | |
4113 | if (alignofs > 0) | |
4114 | { | |
4115 | alignofs = alignofs & -alignofs; | |
4116 | align = MIN (align, alignofs * BITS_PER_UNIT); | |
4117 | } | |
4118 | } | |
4119 | ||
4120 | /* Handle a block of contiguous long-words. */ | |
34377880 | 4121 | |
80909c64 | 4122 | if (align >= 64 && bytes >= 8) |
34377880 | 4123 | { |
4124 | words = bytes / 8; | |
4125 | ||
4126 | for (i = 0; i < words; ++i) | |
1f0ce6a6 | 4127 | emit_move_insn (adjust_address (orig_dst, DImode, ofs + i * 8), |
e513d163 | 4128 | const0_rtx); |
34377880 | 4129 | |
4130 | bytes -= words * 8; | |
7597afe9 | 4131 | ofs += words * 8; |
34377880 | 4132 | } |
80909c64 | 4133 | |
a9aaae37 | 4134 | /* If the block is large and appropriately aligned, emit a single |
4135 | store followed by a sequence of stq_u insns. */ | |
4136 | ||
4137 | if (align >= 32 && bytes > 16) | |
4138 | { | |
1f0ce6a6 | 4139 | rtx orig_dsta; |
4140 | ||
e513d163 | 4141 | emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx); |
a9aaae37 | 4142 | bytes -= 4; |
4143 | ofs += 4; | |
4144 | ||
1f0ce6a6 | 4145 | orig_dsta = XEXP (orig_dst, 0); |
4146 | if (GET_CODE (orig_dsta) == LO_SUM) | |
4147 | orig_dsta = force_reg (Pmode, orig_dsta); | |
4148 | ||
a9aaae37 | 4149 | words = bytes / 8; |
4150 | for (i = 0; i < words; ++i) | |
4151 | { | |
ab6ab77e | 4152 | rtx mem |
4153 | = change_address (orig_dst, DImode, | |
4154 | gen_rtx_AND (DImode, | |
29c05e22 | 4155 | plus_constant (DImode, orig_dsta, |
4156 | ofs + i*8), | |
ab6ab77e | 4157 | GEN_INT (-8))); |
4158 | set_mem_alias_set (mem, 0); | |
a9aaae37 | 4159 | emit_move_insn (mem, const0_rtx); |
4160 | } | |
4161 | ||
4162 | /* Depending on the alignment, the first stq_u may have overlapped | |
4163 | with the initial stl, which means that the last stq_u didn't | |
4164 | write as much as it would appear. Leave those questionable bytes | |
4165 | unaccounted for. */ | |
4166 | bytes -= words * 8 - 4; | |
4167 | ofs += words * 8 - 4; | |
4168 | } | |
4169 | ||
4170 | /* Handle a smaller block of aligned words. */ | |
4171 | ||
4172 | if ((align >= 64 && bytes == 4) | |
4173 | || (align == 32 && bytes >= 4)) | |
34377880 | 4174 | { |
4175 | words = bytes / 4; | |
4176 | ||
4177 | for (i = 0; i < words; ++i) | |
e513d163 | 4178 | emit_move_insn (adjust_address (orig_dst, SImode, ofs + i * 4), |
80909c64 | 4179 | const0_rtx); |
34377880 | 4180 | |
4181 | bytes -= words * 4; | |
7597afe9 | 4182 | ofs += words * 4; |
34377880 | 4183 | } |
80909c64 | 4184 | |
a9aaae37 | 4185 | /* An unaligned block uses stq_u stores for as many as possible. */ |
4186 | ||
4187 | if (bytes >= 8) | |
34377880 | 4188 | { |
4189 | words = bytes / 8; | |
4190 | ||
7597afe9 | 4191 | alpha_expand_unaligned_store_words (NULL, orig_dst, words, ofs); |
34377880 | 4192 | |
4193 | bytes -= words * 8; | |
7597afe9 | 4194 | ofs += words * 8; |
34377880 | 4195 | } |
4196 | ||
a9aaae37 | 4197 | /* Next clean up any trailing pieces. */ |
34377880 | 4198 | |
a9aaae37 | 4199 | /* Count the number of bits in BYTES for which aligned stores could |
4200 | be emitted. */ | |
4201 | words = 0; | |
4202 | for (i = (TARGET_BWX ? 1 : 4); i * BITS_PER_UNIT <= align ; i <<= 1) | |
4203 | if (bytes & i) | |
4204 | words += 1; | |
4205 | ||
4206 | /* If we have appropriate alignment (and it wouldn't take too many | |
4207 | instructions otherwise), mask out the bytes we need. */ | |
4208 | if (TARGET_BWX ? words > 2 : bytes > 0) | |
4209 | { | |
4210 | if (align >= 64) | |
4211 | { | |
4212 | rtx mem, tmp; | |
4213 | HOST_WIDE_INT mask; | |
4214 | ||
e513d163 | 4215 | mem = adjust_address (orig_dst, DImode, ofs); |
ab6ab77e | 4216 | set_mem_alias_set (mem, 0); |
a9aaae37 | 4217 | |
4218 | mask = ~(HOST_WIDE_INT)0 << (bytes * 8); | |
4219 | ||
4220 | tmp = expand_binop (DImode, and_optab, mem, GEN_INT (mask), | |
4221 | NULL_RTX, 1, OPTAB_WIDEN); | |
4222 | ||
4223 | emit_move_insn (mem, tmp); | |
4224 | return 1; | |
4225 | } | |
4226 | else if (align >= 32 && bytes < 4) | |
4227 | { | |
4228 | rtx mem, tmp; | |
4229 | HOST_WIDE_INT mask; | |
4230 | ||
e513d163 | 4231 | mem = adjust_address (orig_dst, SImode, ofs); |
ab6ab77e | 4232 | set_mem_alias_set (mem, 0); |
a9aaae37 | 4233 | |
4234 | mask = ~(HOST_WIDE_INT)0 << (bytes * 8); | |
4235 | ||
4236 | tmp = expand_binop (SImode, and_optab, mem, GEN_INT (mask), | |
4237 | NULL_RTX, 1, OPTAB_WIDEN); | |
4238 | ||
4239 | emit_move_insn (mem, tmp); | |
4240 | return 1; | |
4241 | } | |
34377880 | 4242 | } |
80909c64 | 4243 | |
34377880 | 4244 | if (!TARGET_BWX && bytes >= 4) |
4245 | { | |
4246 | alpha_expand_unaligned_store (orig_dst, const0_rtx, 4, ofs); | |
4247 | bytes -= 4; | |
4248 | ofs += 4; | |
4249 | } | |
80909c64 | 4250 | |
34377880 | 4251 | if (bytes >= 2) |
4252 | { | |
80909c64 | 4253 | if (align >= 16) |
34377880 | 4254 | { |
4255 | do { | |
e513d163 | 4256 | emit_move_insn (adjust_address (orig_dst, HImode, ofs), |
34377880 | 4257 | const0_rtx); |
4258 | bytes -= 2; | |
4259 | ofs += 2; | |
4260 | } while (bytes >= 2); | |
4261 | } | |
80909c64 | 4262 | else if (! TARGET_BWX) |
34377880 | 4263 | { |
4264 | alpha_expand_unaligned_store (orig_dst, const0_rtx, 2, ofs); | |
4265 | bytes -= 2; | |
4266 | ofs += 2; | |
4267 | } | |
4268 | } | |
80909c64 | 4269 | |
34377880 | 4270 | while (bytes > 0) |
4271 | { | |
e513d163 | 4272 | emit_move_insn (adjust_address (orig_dst, QImode, ofs), const0_rtx); |
34377880 | 4273 | bytes -= 1; |
4274 | ofs += 1; | |
4275 | } | |
4276 | ||
4277 | return 1; | |
4278 | } | |
f2cc13dc | 4279 | |
4280 | /* Returns a mask so that zap(x, value) == x & mask. */ | |
4281 | ||
4282 | rtx | |
92643d95 | 4283 | alpha_expand_zap_mask (HOST_WIDE_INT value) |
f2cc13dc | 4284 | { |
4285 | rtx result; | |
4286 | int i; | |
a2d7211e | 4287 | HOST_WIDE_INT mask = 0; |
f2cc13dc | 4288 | |
a2d7211e | 4289 | for (i = 7; i >= 0; --i) |
f2cc13dc | 4290 | { |
a2d7211e | 4291 | mask <<= 8; |
4292 | if (!((value >> i) & 1)) | |
4293 | mask |= 0xff; | |
f2cc13dc | 4294 | } |
f2cc13dc | 4295 | |
a2d7211e | 4296 | result = gen_int_mode (mask, DImode); |
f2cc13dc | 4297 | return result; |
4298 | } | |
4299 | ||
4300 | void | |
92643d95 | 4301 | alpha_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx), |
3754d046 | 4302 | machine_mode mode, |
92643d95 | 4303 | rtx op0, rtx op1, rtx op2) |
f2cc13dc | 4304 | { |
4305 | op0 = gen_lowpart (mode, op0); | |
4306 | ||
4307 | if (op1 == const0_rtx) | |
4308 | op1 = CONST0_RTX (mode); | |
4309 | else | |
4310 | op1 = gen_lowpart (mode, op1); | |
ae4cd3a5 | 4311 | |
4312 | if (op2 == const0_rtx) | |
f2cc13dc | 4313 | op2 = CONST0_RTX (mode); |
4314 | else | |
4315 | op2 = gen_lowpart (mode, op2); | |
4316 | ||
4317 | emit_insn ((*gen) (op0, op1, op2)); | |
4318 | } | |
f155876e | 4319 | |
032caa7b | 4320 | /* A subroutine of the atomic operation splitters. Jump to LABEL if |
4321 | COND is true. Mark the jump as unlikely to be taken. */ | |
4322 | ||
4323 | static void | |
4324 | emit_unlikely_jump (rtx cond, rtx label) | |
4325 | { | |
9eb946de | 4326 | int very_unlikely = REG_BR_PROB_BASE / 100 - 1; |
032caa7b | 4327 | rtx x; |
4328 | ||
4329 | x = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, label, pc_rtx); | |
d1f9b275 | 4330 | x = emit_jump_insn (gen_rtx_SET (pc_rtx, x)); |
9eb946de | 4331 | add_int_reg_note (x, REG_BR_PROB, very_unlikely); |
032caa7b | 4332 | } |
4333 | ||
4334 | /* A subroutine of the atomic operation splitters. Emit a load-locked | |
4335 | instruction in MODE. */ | |
4336 | ||
4337 | static void | |
3754d046 | 4338 | emit_load_locked (machine_mode mode, rtx reg, rtx mem) |
032caa7b | 4339 | { |
4340 | rtx (*fn) (rtx, rtx) = NULL; | |
4341 | if (mode == SImode) | |
4342 | fn = gen_load_locked_si; | |
4343 | else if (mode == DImode) | |
4344 | fn = gen_load_locked_di; | |
4345 | emit_insn (fn (reg, mem)); | |
4346 | } | |
4347 | ||
4348 | /* A subroutine of the atomic operation splitters. Emit a store-conditional | |
4349 | instruction in MODE. */ | |
4350 | ||
4351 | static void | |
3754d046 | 4352 | emit_store_conditional (machine_mode mode, rtx res, rtx mem, rtx val) |
032caa7b | 4353 | { |
4354 | rtx (*fn) (rtx, rtx, rtx) = NULL; | |
4355 | if (mode == SImode) | |
4356 | fn = gen_store_conditional_si; | |
4357 | else if (mode == DImode) | |
4358 | fn = gen_store_conditional_di; | |
4359 | emit_insn (fn (res, mem, val)); | |
4360 | } | |
4361 | ||
51c750d8 | 4362 | /* Subroutines of the atomic operation splitters. Emit barriers |
4363 | as needed for the memory MODEL. */ | |
4364 | ||
4365 | static void | |
4366 | alpha_pre_atomic_barrier (enum memmodel model) | |
4367 | { | |
30c3c442 | 4368 | if (need_atomic_barrier_p (model, true)) |
4369 | emit_insn (gen_memory_barrier ()); | |
51c750d8 | 4370 | } |
4371 | ||
4372 | static void | |
4373 | alpha_post_atomic_barrier (enum memmodel model) | |
4374 | { | |
30c3c442 | 4375 | if (need_atomic_barrier_p (model, false)) |
4376 | emit_insn (gen_memory_barrier ()); | |
51c750d8 | 4377 | } |
4378 | ||
596d3184 | 4379 | /* A subroutine of the atomic operation splitters. Emit an insxl |
4380 | instruction in MODE. */ | |
4381 | ||
4382 | static rtx | |
3754d046 | 4383 | emit_insxl (machine_mode mode, rtx op1, rtx op2) |
596d3184 | 4384 | { |
4385 | rtx ret = gen_reg_rtx (DImode); | |
4386 | rtx (*fn) (rtx, rtx, rtx); | |
4387 | ||
7a20d8cd | 4388 | switch (mode) |
4389 | { | |
4390 | case QImode: | |
4391 | fn = gen_insbl; | |
4392 | break; | |
4393 | case HImode: | |
4394 | fn = gen_inswl; | |
4395 | break; | |
4396 | case SImode: | |
4397 | fn = gen_insll; | |
4398 | break; | |
4399 | case DImode: | |
4400 | fn = gen_insql; | |
4401 | break; | |
4402 | default: | |
4403 | gcc_unreachable (); | |
4404 | } | |
9bab4302 | 4405 | |
9a6f4ddd | 4406 | op1 = force_reg (mode, op1); |
596d3184 | 4407 | emit_insn (fn (ret, op1, op2)); |
4408 | ||
4409 | return ret; | |
4410 | } | |
4411 | ||
85694bac | 4412 | /* Expand an atomic fetch-and-operate pattern. CODE is the binary operation |
f155876e | 4413 | to perform. MEM is the memory on which to operate. VAL is the second |
4414 | operand of the binary operator. BEFORE and AFTER are optional locations to | |
4415 | return the value of MEM either before of after the operation. SCRATCH is | |
4416 | a scratch register. */ | |
4417 | ||
4418 | void | |
51c750d8 | 4419 | alpha_split_atomic_op (enum rtx_code code, rtx mem, rtx val, rtx before, |
4420 | rtx after, rtx scratch, enum memmodel model) | |
f155876e | 4421 | { |
3754d046 | 4422 | machine_mode mode = GET_MODE (mem); |
032caa7b | 4423 | rtx label, x, cond = gen_rtx_REG (DImode, REGNO (scratch)); |
f155876e | 4424 | |
51c750d8 | 4425 | alpha_pre_atomic_barrier (model); |
f155876e | 4426 | |
4427 | label = gen_label_rtx (); | |
4428 | emit_label (label); | |
4429 | label = gen_rtx_LABEL_REF (DImode, label); | |
4430 | ||
4431 | if (before == NULL) | |
4432 | before = scratch; | |
032caa7b | 4433 | emit_load_locked (mode, before, mem); |
f155876e | 4434 | |
4435 | if (code == NOT) | |
6f7e6aa3 | 4436 | { |
4437 | x = gen_rtx_AND (mode, before, val); | |
d1f9b275 | 4438 | emit_insn (gen_rtx_SET (val, x)); |
6f7e6aa3 | 4439 | |
4440 | x = gen_rtx_NOT (mode, val); | |
4441 | } | |
f155876e | 4442 | else |
4443 | x = gen_rtx_fmt_ee (code, mode, before, val); | |
f155876e | 4444 | if (after) |
d1f9b275 | 4445 | emit_insn (gen_rtx_SET (after, copy_rtx (x))); |
4446 | emit_insn (gen_rtx_SET (scratch, x)); | |
f155876e | 4447 | |
032caa7b | 4448 | emit_store_conditional (mode, cond, mem, scratch); |
4449 | ||
4450 | x = gen_rtx_EQ (DImode, cond, const0_rtx); | |
4451 | emit_unlikely_jump (x, label); | |
4452 | ||
51c750d8 | 4453 | alpha_post_atomic_barrier (model); |
032caa7b | 4454 | } |
4455 | ||
4456 | /* Expand a compare and swap operation. */ | |
4457 | ||
4458 | void | |
51c750d8 | 4459 | alpha_split_compare_and_swap (rtx operands[]) |
032caa7b | 4460 | { |
51c750d8 | 4461 | rtx cond, retval, mem, oldval, newval; |
4462 | bool is_weak; | |
4463 | enum memmodel mod_s, mod_f; | |
3754d046 | 4464 | machine_mode mode; |
51c750d8 | 4465 | rtx label1, label2, x; |
4466 | ||
4467 | cond = operands[0]; | |
4468 | retval = operands[1]; | |
4469 | mem = operands[2]; | |
4470 | oldval = operands[3]; | |
4471 | newval = operands[4]; | |
4472 | is_weak = (operands[5] != const0_rtx); | |
a372f7ca | 4473 | mod_s = memmodel_from_int (INTVAL (operands[6])); |
4474 | mod_f = memmodel_from_int (INTVAL (operands[7])); | |
51c750d8 | 4475 | mode = GET_MODE (mem); |
4476 | ||
4477 | alpha_pre_atomic_barrier (mod_s); | |
4478 | ||
4479 | label1 = NULL_RTX; | |
4480 | if (!is_weak) | |
4481 | { | |
4482 | label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); | |
4483 | emit_label (XEXP (label1, 0)); | |
4484 | } | |
032caa7b | 4485 | label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); |
032caa7b | 4486 | |
4487 | emit_load_locked (mode, retval, mem); | |
4488 | ||
4489 | x = gen_lowpart (DImode, retval); | |
4490 | if (oldval == const0_rtx) | |
51c750d8 | 4491 | { |
4492 | emit_move_insn (cond, const0_rtx); | |
4493 | x = gen_rtx_NE (DImode, x, const0_rtx); | |
4494 | } | |
f155876e | 4495 | else |
032caa7b | 4496 | { |
4497 | x = gen_rtx_EQ (DImode, x, oldval); | |
d1f9b275 | 4498 | emit_insn (gen_rtx_SET (cond, x)); |
032caa7b | 4499 | x = gen_rtx_EQ (DImode, cond, const0_rtx); |
4500 | } | |
4501 | emit_unlikely_jump (x, label2); | |
4502 | ||
51c750d8 | 4503 | emit_move_insn (cond, newval); |
4504 | emit_store_conditional (mode, cond, mem, gen_lowpart (mode, cond)); | |
f155876e | 4505 | |
51c750d8 | 4506 | if (!is_weak) |
4507 | { | |
4508 | x = gen_rtx_EQ (DImode, cond, const0_rtx); | |
4509 | emit_unlikely_jump (x, label1); | |
4510 | } | |
4511 | ||
a372f7ca | 4512 | if (!is_mm_relaxed (mod_f)) |
51c750d8 | 4513 | emit_label (XEXP (label2, 0)); |
4514 | ||
4515 | alpha_post_atomic_barrier (mod_s); | |
032caa7b | 4516 | |
a372f7ca | 4517 | if (is_mm_relaxed (mod_f)) |
51c750d8 | 4518 | emit_label (XEXP (label2, 0)); |
032caa7b | 4519 | } |
4520 | ||
596d3184 | 4521 | void |
51c750d8 | 4522 | alpha_expand_compare_and_swap_12 (rtx operands[]) |
596d3184 | 4523 | { |
51c750d8 | 4524 | rtx cond, dst, mem, oldval, newval, is_weak, mod_s, mod_f; |
3754d046 | 4525 | machine_mode mode; |
596d3184 | 4526 | rtx addr, align, wdst; |
51c750d8 | 4527 | rtx (*gen) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx); |
4528 | ||
4529 | cond = operands[0]; | |
4530 | dst = operands[1]; | |
4531 | mem = operands[2]; | |
4532 | oldval = operands[3]; | |
4533 | newval = operands[4]; | |
4534 | is_weak = operands[5]; | |
4535 | mod_s = operands[6]; | |
4536 | mod_f = operands[7]; | |
4537 | mode = GET_MODE (mem); | |
4538 | ||
4539 | /* We forced the address into a register via mem_noofs_operand. */ | |
4540 | addr = XEXP (mem, 0); | |
4541 | gcc_assert (register_operand (addr, DImode)); | |
596d3184 | 4542 | |
596d3184 | 4543 | align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8), |
4544 | NULL_RTX, 1, OPTAB_DIRECT); | |
4545 | ||
4546 | oldval = convert_modes (DImode, mode, oldval, 1); | |
51c750d8 | 4547 | |
4548 | if (newval != const0_rtx) | |
4549 | newval = emit_insxl (mode, newval, addr); | |
596d3184 | 4550 | |
4551 | wdst = gen_reg_rtx (DImode); | |
4552 | if (mode == QImode) | |
51c750d8 | 4553 | gen = gen_atomic_compare_and_swapqi_1; |
596d3184 | 4554 | else |
51c750d8 | 4555 | gen = gen_atomic_compare_and_swaphi_1; |
4556 | emit_insn (gen (cond, wdst, mem, oldval, newval, align, | |
4557 | is_weak, mod_s, mod_f)); | |
596d3184 | 4558 | |
4559 | emit_move_insn (dst, gen_lowpart (mode, wdst)); | |
4560 | } | |
4561 | ||
4562 | void | |
51c750d8 | 4563 | alpha_split_compare_and_swap_12 (rtx operands[]) |
596d3184 | 4564 | { |
51c750d8 | 4565 | rtx cond, dest, orig_mem, oldval, newval, align, scratch; |
3754d046 | 4566 | machine_mode mode; |
51c750d8 | 4567 | bool is_weak; |
4568 | enum memmodel mod_s, mod_f; | |
4569 | rtx label1, label2, mem, addr, width, mask, x; | |
4570 | ||
4571 | cond = operands[0]; | |
4572 | dest = operands[1]; | |
4573 | orig_mem = operands[2]; | |
4574 | oldval = operands[3]; | |
4575 | newval = operands[4]; | |
4576 | align = operands[5]; | |
4577 | is_weak = (operands[6] != const0_rtx); | |
a372f7ca | 4578 | mod_s = memmodel_from_int (INTVAL (operands[7])); |
4579 | mod_f = memmodel_from_int (INTVAL (operands[8])); | |
51c750d8 | 4580 | scratch = operands[9]; |
4581 | mode = GET_MODE (orig_mem); | |
4582 | addr = XEXP (orig_mem, 0); | |
596d3184 | 4583 | |
4584 | mem = gen_rtx_MEM (DImode, align); | |
51c750d8 | 4585 | MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (orig_mem); |
02891b92 | 4586 | if (MEM_ALIAS_SET (orig_mem) == ALIAS_SET_MEMORY_BARRIER) |
4587 | set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER); | |
596d3184 | 4588 | |
51c750d8 | 4589 | alpha_pre_atomic_barrier (mod_s); |
4590 | ||
4591 | label1 = NULL_RTX; | |
4592 | if (!is_weak) | |
4593 | { | |
4594 | label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); | |
4595 | emit_label (XEXP (label1, 0)); | |
4596 | } | |
596d3184 | 4597 | label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); |
596d3184 | 4598 | |
4599 | emit_load_locked (DImode, scratch, mem); | |
4600 | ||
4601 | width = GEN_INT (GET_MODE_BITSIZE (mode)); | |
4602 | mask = GEN_INT (mode == QImode ? 0xff : 0xffff); | |
9bab4302 | 4603 | emit_insn (gen_extxl (dest, scratch, width, addr)); |
596d3184 | 4604 | |
4605 | if (oldval == const0_rtx) | |
51c750d8 | 4606 | { |
4607 | emit_move_insn (cond, const0_rtx); | |
4608 | x = gen_rtx_NE (DImode, dest, const0_rtx); | |
4609 | } | |
596d3184 | 4610 | else |
4611 | { | |
4612 | x = gen_rtx_EQ (DImode, dest, oldval); | |
d1f9b275 | 4613 | emit_insn (gen_rtx_SET (cond, x)); |
596d3184 | 4614 | x = gen_rtx_EQ (DImode, cond, const0_rtx); |
4615 | } | |
4616 | emit_unlikely_jump (x, label2); | |
4617 | ||
51c750d8 | 4618 | emit_insn (gen_mskxl (cond, scratch, mask, addr)); |
596d3184 | 4619 | |
51c750d8 | 4620 | if (newval != const0_rtx) |
4621 | emit_insn (gen_iordi3 (cond, cond, newval)); | |
596d3184 | 4622 | |
51c750d8 | 4623 | emit_store_conditional (DImode, cond, mem, cond); |
596d3184 | 4624 | |
51c750d8 | 4625 | if (!is_weak) |
4626 | { | |
4627 | x = gen_rtx_EQ (DImode, cond, const0_rtx); | |
4628 | emit_unlikely_jump (x, label1); | |
4629 | } | |
4630 | ||
a372f7ca | 4631 | if (!is_mm_relaxed (mod_f)) |
51c750d8 | 4632 | emit_label (XEXP (label2, 0)); |
4633 | ||
4634 | alpha_post_atomic_barrier (mod_s); | |
4635 | ||
a372f7ca | 4636 | if (is_mm_relaxed (mod_f)) |
51c750d8 | 4637 | emit_label (XEXP (label2, 0)); |
596d3184 | 4638 | } |
4639 | ||
032caa7b | 4640 | /* Expand an atomic exchange operation. */ |
4641 | ||
4642 | void | |
51c750d8 | 4643 | alpha_split_atomic_exchange (rtx operands[]) |
032caa7b | 4644 | { |
51c750d8 | 4645 | rtx retval, mem, val, scratch; |
4646 | enum memmodel model; | |
3754d046 | 4647 | machine_mode mode; |
51c750d8 | 4648 | rtx label, x, cond; |
4649 | ||
4650 | retval = operands[0]; | |
4651 | mem = operands[1]; | |
4652 | val = operands[2]; | |
4653 | model = (enum memmodel) INTVAL (operands[3]); | |
4654 | scratch = operands[4]; | |
4655 | mode = GET_MODE (mem); | |
4656 | cond = gen_lowpart (DImode, scratch); | |
4657 | ||
4658 | alpha_pre_atomic_barrier (model); | |
f155876e | 4659 | |
032caa7b | 4660 | label = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); |
4661 | emit_label (XEXP (label, 0)); | |
4662 | ||
4663 | emit_load_locked (mode, retval, mem); | |
4664 | emit_move_insn (scratch, val); | |
4665 | emit_store_conditional (mode, cond, mem, scratch); | |
4666 | ||
4667 | x = gen_rtx_EQ (DImode, cond, const0_rtx); | |
4668 | emit_unlikely_jump (x, label); | |
a15b4a3c | 4669 | |
51c750d8 | 4670 | alpha_post_atomic_barrier (model); |
f155876e | 4671 | } |
596d3184 | 4672 | |
4673 | void | |
51c750d8 | 4674 | alpha_expand_atomic_exchange_12 (rtx operands[]) |
596d3184 | 4675 | { |
51c750d8 | 4676 | rtx dst, mem, val, model; |
3754d046 | 4677 | machine_mode mode; |
596d3184 | 4678 | rtx addr, align, wdst; |
51c750d8 | 4679 | rtx (*gen) (rtx, rtx, rtx, rtx, rtx); |
596d3184 | 4680 | |
51c750d8 | 4681 | dst = operands[0]; |
4682 | mem = operands[1]; | |
4683 | val = operands[2]; | |
4684 | model = operands[3]; | |
4685 | mode = GET_MODE (mem); | |
4686 | ||
4687 | /* We forced the address into a register via mem_noofs_operand. */ | |
4688 | addr = XEXP (mem, 0); | |
4689 | gcc_assert (register_operand (addr, DImode)); | |
596d3184 | 4690 | |
596d3184 | 4691 | align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8), |
4692 | NULL_RTX, 1, OPTAB_DIRECT); | |
4693 | ||
4694 | /* Insert val into the correct byte location within the word. */ | |
51c750d8 | 4695 | if (val != const0_rtx) |
4696 | val = emit_insxl (mode, val, addr); | |
596d3184 | 4697 | |
4698 | wdst = gen_reg_rtx (DImode); | |
4699 | if (mode == QImode) | |
51c750d8 | 4700 | gen = gen_atomic_exchangeqi_1; |
596d3184 | 4701 | else |
51c750d8 | 4702 | gen = gen_atomic_exchangehi_1; |
4703 | emit_insn (gen (wdst, mem, val, align, model)); | |
596d3184 | 4704 | |
4705 | emit_move_insn (dst, gen_lowpart (mode, wdst)); | |
4706 | } | |
4707 | ||
4708 | void | |
51c750d8 | 4709 | alpha_split_atomic_exchange_12 (rtx operands[]) |
596d3184 | 4710 | { |
51c750d8 | 4711 | rtx dest, orig_mem, addr, val, align, scratch; |
596d3184 | 4712 | rtx label, mem, width, mask, x; |
3754d046 | 4713 | machine_mode mode; |
51c750d8 | 4714 | enum memmodel model; |
4715 | ||
4716 | dest = operands[0]; | |
4717 | orig_mem = operands[1]; | |
4718 | val = operands[2]; | |
4719 | align = operands[3]; | |
4720 | model = (enum memmodel) INTVAL (operands[4]); | |
4721 | scratch = operands[5]; | |
4722 | mode = GET_MODE (orig_mem); | |
4723 | addr = XEXP (orig_mem, 0); | |
596d3184 | 4724 | |
4725 | mem = gen_rtx_MEM (DImode, align); | |
51c750d8 | 4726 | MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (orig_mem); |
02891b92 | 4727 | if (MEM_ALIAS_SET (orig_mem) == ALIAS_SET_MEMORY_BARRIER) |
4728 | set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER); | |
51c750d8 | 4729 | |
4730 | alpha_pre_atomic_barrier (model); | |
596d3184 | 4731 | |
596d3184 | 4732 | label = gen_rtx_LABEL_REF (DImode, gen_label_rtx ()); |
4733 | emit_label (XEXP (label, 0)); | |
4734 | ||
4735 | emit_load_locked (DImode, scratch, mem); | |
4736 | ||
4737 | width = GEN_INT (GET_MODE_BITSIZE (mode)); | |
4738 | mask = GEN_INT (mode == QImode ? 0xff : 0xffff); | |
9bab4302 | 4739 | emit_insn (gen_extxl (dest, scratch, width, addr)); |
4740 | emit_insn (gen_mskxl (scratch, scratch, mask, addr)); | |
51c750d8 | 4741 | if (val != const0_rtx) |
4742 | emit_insn (gen_iordi3 (scratch, scratch, val)); | |
596d3184 | 4743 | |
4744 | emit_store_conditional (DImode, scratch, mem, scratch); | |
4745 | ||
4746 | x = gen_rtx_EQ (DImode, scratch, const0_rtx); | |
4747 | emit_unlikely_jump (x, label); | |
a15b4a3c | 4748 | |
51c750d8 | 4749 | alpha_post_atomic_barrier (model); |
596d3184 | 4750 | } |
bf2a98b3 | 4751 | \f |
4752 | /* Adjust the cost of a scheduling dependency. Return the new cost of | |
4753 | a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ | |
4754 | ||
747af5e7 | 4755 | static int |
18282db0 | 4756 | alpha_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, int cost) |
bf2a98b3 | 4757 | { |
f5e8a4bc | 4758 | enum attr_type dep_insn_type; |
bf2a98b3 | 4759 | |
4760 | /* If the dependence is an anti-dependence, there is no cost. For an | |
4761 | output dependence, there is sometimes a cost, but it doesn't seem | |
4762 | worth handling those few cases. */ | |
bf2a98b3 | 4763 | if (REG_NOTE_KIND (link) != 0) |
7eb0c947 | 4764 | return cost; |
bf2a98b3 | 4765 | |
d2832bd8 | 4766 | /* If we can't recognize the insns, we can't really do anything. */ |
4767 | if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0) | |
4768 | return cost; | |
4769 | ||
d2832bd8 | 4770 | dep_insn_type = get_attr_type (dep_insn); |
4771 | ||
07c1a295 | 4772 | /* Bring in the user-defined memory latency. */ |
e7a69d05 | 4773 | if (dep_insn_type == TYPE_ILD |
4774 | || dep_insn_type == TYPE_FLD | |
4775 | || dep_insn_type == TYPE_LDSYM) | |
07c1a295 | 4776 | cost += alpha_memory_latency-1; |
4777 | ||
7eb0c947 | 4778 | /* Everything else handled in DFA bypasses now. */ |
3680ac41 | 4779 | |
bf2a98b3 | 4780 | return cost; |
4781 | } | |
747af5e7 | 4782 | |
7eb0c947 | 4783 | /* The number of instructions that can be issued per cycle. */ |
4784 | ||
747af5e7 | 4785 | static int |
92643d95 | 4786 | alpha_issue_rate (void) |
747af5e7 | 4787 | { |
fb64edde | 4788 | return (alpha_tune == PROCESSOR_EV4 ? 2 : 4); |
747af5e7 | 4789 | } |
4790 | ||
7eb0c947 | 4791 | /* How many alternative schedules to try. This should be as wide as the |
4792 | scheduling freedom in the DFA, but no wider. Making this value too | |
4793 | large results extra work for the scheduler. | |
4794 | ||
4795 | For EV4, loads can be issued to either IB0 or IB1, thus we have 2 | |
4796 | alternative schedules. For EV5, we can choose between E0/E1 and | |
8d232dc7 | 4797 | FA/FM. For EV6, an arithmetic insn can be issued to U0/U1/L0/L1. */ |
7eb0c947 | 4798 | |
4799 | static int | |
92643d95 | 4800 | alpha_multipass_dfa_lookahead (void) |
7eb0c947 | 4801 | { |
fb64edde | 4802 | return (alpha_tune == PROCESSOR_EV6 ? 4 : 2); |
7eb0c947 | 4803 | } |
0c0464e6 | 4804 | \f |
5f7b9df8 | 4805 | /* Machine-specific function data. */ |
4806 | ||
5ce94904 | 4807 | struct GTY(()) alpha_links; |
4808 | ||
d4786b13 | 4809 | struct string_traits : default_hashmap_traits |
4810 | { | |
4811 | static bool equal_keys (const char *const &a, const char *const &b) | |
4812 | { | |
4813 | return strcmp (a, b) == 0; | |
4814 | } | |
4815 | }; | |
4816 | ||
fb1e4f4a | 4817 | struct GTY(()) machine_function |
5f7b9df8 | 4818 | { |
126b6848 | 4819 | /* For flag_reorder_blocks_and_partition. */ |
842ae815 | 4820 | rtx gp_save_rtx; |
50f36bdb | 4821 | |
4822 | /* For VMS condition handlers. */ | |
5ce94904 | 4823 | bool uses_condition_handler; |
4824 | ||
4825 | /* Linkage entries. */ | |
d4786b13 | 4826 | hash_map<const char *, alpha_links *, string_traits> *links; |
5f7b9df8 | 4827 | }; |
4828 | ||
1f3233d1 | 4829 | /* How to allocate a 'struct machine_function'. */ |
9caef960 | 4830 | |
1f3233d1 | 4831 | static struct machine_function * |
92643d95 | 4832 | alpha_init_machine_status (void) |
9caef960 | 4833 | { |
25a27413 | 4834 | return ggc_cleared_alloc<machine_function> (); |
9caef960 | 4835 | } |
9caef960 | 4836 | |
50f36bdb | 4837 | /* Support for frame based VMS condition handlers. */ |
4838 | ||
4839 | /* A VMS condition handler may be established for a function with a call to | |
4840 | __builtin_establish_vms_condition_handler, and cancelled with a call to | |
4841 | __builtin_revert_vms_condition_handler. | |
4842 | ||
4843 | The VMS Condition Handling Facility knows about the existence of a handler | |
4844 | from the procedure descriptor .handler field. As the VMS native compilers, | |
4845 | we store the user specified handler's address at a fixed location in the | |
4846 | stack frame and point the procedure descriptor at a common wrapper which | |
4847 | fetches the real handler's address and issues an indirect call. | |
4848 | ||
4849 | The indirection wrapper is "__gcc_shell_handler", provided by libgcc. | |
4850 | ||
4851 | We force the procedure kind to PT_STACK, and the fixed frame location is | |
4852 | fp+8, just before the register save area. We use the handler_data field in | |
4853 | the procedure descriptor to state the fp offset at which the installed | |
4854 | handler address can be found. */ | |
4855 | ||
4856 | #define VMS_COND_HANDLER_FP_OFFSET 8 | |
4857 | ||
4858 | /* Expand code to store the currently installed user VMS condition handler | |
4859 | into TARGET and install HANDLER as the new condition handler. */ | |
4860 | ||
4861 | void | |
4862 | alpha_expand_builtin_establish_vms_condition_handler (rtx target, rtx handler) | |
4863 | { | |
29c05e22 | 4864 | rtx handler_slot_address = plus_constant (Pmode, hard_frame_pointer_rtx, |
4865 | VMS_COND_HANDLER_FP_OFFSET); | |
50f36bdb | 4866 | |
4867 | rtx handler_slot | |
4868 | = gen_rtx_MEM (DImode, handler_slot_address); | |
4869 | ||
4870 | emit_move_insn (target, handler_slot); | |
4871 | emit_move_insn (handler_slot, handler); | |
4872 | ||
4873 | /* Notify the start/prologue/epilogue emitters that the condition handler | |
4874 | slot is needed. In addition to reserving the slot space, this will force | |
4875 | the procedure kind to PT_STACK so ensure that the hard_frame_pointer_rtx | |
4876 | use above is correct. */ | |
4877 | cfun->machine->uses_condition_handler = true; | |
4878 | } | |
4879 | ||
4880 | /* Expand code to store the current VMS condition handler into TARGET and | |
4881 | nullify it. */ | |
4882 | ||
4883 | void | |
4884 | alpha_expand_builtin_revert_vms_condition_handler (rtx target) | |
4885 | { | |
4886 | /* We implement this by establishing a null condition handler, with the tiny | |
4887 | side effect of setting uses_condition_handler. This is a little bit | |
4888 | pessimistic if no actual builtin_establish call is ever issued, which is | |
4889 | not a real problem and expected never to happen anyway. */ | |
4890 | ||
4891 | alpha_expand_builtin_establish_vms_condition_handler (target, const0_rtx); | |
4892 | } | |
4893 | ||
0c0464e6 | 4894 | /* Functions to save and restore alpha_return_addr_rtx. */ |
4895 | ||
0c0464e6 | 4896 | /* Start the ball rolling with RETURN_ADDR_RTX. */ |
4897 | ||
4898 | rtx | |
92643d95 | 4899 | alpha_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) |
0c0464e6 | 4900 | { |
0c0464e6 | 4901 | if (count != 0) |
4902 | return const0_rtx; | |
4903 | ||
0f37b7a2 | 4904 | return get_hard_reg_initial_val (Pmode, REG_RA); |
0c0464e6 | 4905 | } |
4906 | ||
a221313c | 4907 | /* Return or create a memory slot containing the gp value for the current |
66561750 | 4908 | function. Needed only if TARGET_LD_BUGGY_LDGP. */ |
4909 | ||
4910 | rtx | |
92643d95 | 4911 | alpha_gp_save_rtx (void) |
66561750 | 4912 | { |
7f0256ea | 4913 | rtx_insn *seq; |
4914 | rtx m = cfun->machine->gp_save_rtx; | |
a221313c | 4915 | |
4916 | if (m == NULL) | |
4917 | { | |
4918 | start_sequence (); | |
4919 | ||
4920 | m = assign_stack_local (DImode, UNITS_PER_WORD, BITS_PER_WORD); | |
4921 | m = validize_mem (m); | |
4922 | emit_move_insn (m, pic_offset_table_rtx); | |
4923 | ||
4924 | seq = get_insns (); | |
4925 | end_sequence (); | |
8a1586ba | 4926 | |
4927 | /* We used to simply emit the sequence after entry_of_function. | |
4928 | However this breaks the CFG if the first instruction in the | |
4929 | first block is not the NOTE_INSN_BASIC_BLOCK, for example a | |
4930 | label. Emit the sequence properly on the edge. We are only | |
4931 | invoked from dw2_build_landing_pads and finish_eh_generation | |
4932 | will call commit_edge_insertions thanks to a kludge. */ | |
34154e27 | 4933 | insert_insn_on_edge (seq, |
4934 | single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))); | |
a221313c | 4935 | |
4936 | cfun->machine->gp_save_rtx = m; | |
4937 | } | |
4938 | ||
4939 | return m; | |
66561750 | 4940 | } |
4941 | ||
0d25d8c2 | 4942 | static void |
4943 | alpha_instantiate_decls (void) | |
4944 | { | |
4945 | if (cfun->machine->gp_save_rtx != NULL_RTX) | |
4946 | instantiate_decl_rtl (cfun->machine->gp_save_rtx); | |
4947 | } | |
4948 | ||
0c0464e6 | 4949 | static int |
92643d95 | 4950 | alpha_ra_ever_killed (void) |
0c0464e6 | 4951 | { |
7f0256ea | 4952 | rtx_insn *top; |
5a965225 | 4953 | |
0f37b7a2 | 4954 | if (!has_hard_reg_initial_val (Pmode, REG_RA)) |
3072d30e | 4955 | return (int)df_regs_ever_live_p (REG_RA); |
0c0464e6 | 4956 | |
5a965225 | 4957 | push_topmost_sequence (); |
4958 | top = get_insns (); | |
4959 | pop_topmost_sequence (); | |
4960 | ||
311f821c | 4961 | return reg_set_between_p (gen_rtx_REG (Pmode, REG_RA), top, NULL); |
0c0464e6 | 4962 | } |
4963 | ||
bf2a98b3 | 4964 | \f |
6fec94c5 | 4965 | /* Return the trap mode suffix applicable to the current |
65abff06 | 4966 | instruction, or NULL. */ |
bf2a98b3 | 4967 | |
6fec94c5 | 4968 | static const char * |
92643d95 | 4969 | get_trap_mode_suffix (void) |
bf2a98b3 | 4970 | { |
6fec94c5 | 4971 | enum attr_trap_suffix s = get_attr_trap_suffix (current_output_insn); |
bf2a98b3 | 4972 | |
6fec94c5 | 4973 | switch (s) |
bf2a98b3 | 4974 | { |
6fec94c5 | 4975 | case TRAP_SUFFIX_NONE: |
4976 | return NULL; | |
c4622276 | 4977 | |
6fec94c5 | 4978 | case TRAP_SUFFIX_SU: |
bc16f0c1 | 4979 | if (alpha_fptm >= ALPHA_FPTM_SU) |
6fec94c5 | 4980 | return "su"; |
4981 | return NULL; | |
c4622276 | 4982 | |
6fec94c5 | 4983 | case TRAP_SUFFIX_SUI: |
4984 | if (alpha_fptm >= ALPHA_FPTM_SUI) | |
4985 | return "sui"; | |
4986 | return NULL; | |
4987 | ||
4988 | case TRAP_SUFFIX_V_SV: | |
39344852 | 4989 | switch (alpha_fptm) |
4990 | { | |
4991 | case ALPHA_FPTM_N: | |
6fec94c5 | 4992 | return NULL; |
39344852 | 4993 | case ALPHA_FPTM_U: |
6fec94c5 | 4994 | return "v"; |
39344852 | 4995 | case ALPHA_FPTM_SU: |
4996 | case ALPHA_FPTM_SUI: | |
6fec94c5 | 4997 | return "sv"; |
4d10b463 | 4998 | default: |
4999 | gcc_unreachable (); | |
39344852 | 5000 | } |
39344852 | 5001 | |
6fec94c5 | 5002 | case TRAP_SUFFIX_V_SV_SVI: |
b5ea3193 | 5003 | switch (alpha_fptm) |
5004 | { | |
5005 | case ALPHA_FPTM_N: | |
6fec94c5 | 5006 | return NULL; |
b5ea3193 | 5007 | case ALPHA_FPTM_U: |
6fec94c5 | 5008 | return "v"; |
b5ea3193 | 5009 | case ALPHA_FPTM_SU: |
6fec94c5 | 5010 | return "sv"; |
b5ea3193 | 5011 | case ALPHA_FPTM_SUI: |
6fec94c5 | 5012 | return "svi"; |
4d10b463 | 5013 | default: |
5014 | gcc_unreachable (); | |
b5ea3193 | 5015 | } |
5016 | break; | |
5017 | ||
6fec94c5 | 5018 | case TRAP_SUFFIX_U_SU_SUI: |
c4622276 | 5019 | switch (alpha_fptm) |
5020 | { | |
5021 | case ALPHA_FPTM_N: | |
6fec94c5 | 5022 | return NULL; |
c4622276 | 5023 | case ALPHA_FPTM_U: |
6fec94c5 | 5024 | return "u"; |
c4622276 | 5025 | case ALPHA_FPTM_SU: |
6fec94c5 | 5026 | return "su"; |
c4622276 | 5027 | case ALPHA_FPTM_SUI: |
6fec94c5 | 5028 | return "sui"; |
4d10b463 | 5029 | default: |
5030 | gcc_unreachable (); | |
c4622276 | 5031 | } |
5032 | break; | |
4d10b463 | 5033 | |
5034 | default: | |
5035 | gcc_unreachable (); | |
6fec94c5 | 5036 | } |
4d10b463 | 5037 | gcc_unreachable (); |
6fec94c5 | 5038 | } |
c4622276 | 5039 | |
6fec94c5 | 5040 | /* Return the rounding mode suffix applicable to the current |
65abff06 | 5041 | instruction, or NULL. */ |
6fec94c5 | 5042 | |
5043 | static const char * | |
92643d95 | 5044 | get_round_mode_suffix (void) |
6fec94c5 | 5045 | { |
5046 | enum attr_round_suffix s = get_attr_round_suffix (current_output_insn); | |
5047 | ||
5048 | switch (s) | |
5049 | { | |
5050 | case ROUND_SUFFIX_NONE: | |
5051 | return NULL; | |
5052 | case ROUND_SUFFIX_NORMAL: | |
5053 | switch (alpha_fprm) | |
c4622276 | 5054 | { |
6fec94c5 | 5055 | case ALPHA_FPRM_NORM: |
5056 | return NULL; | |
9e7454d0 | 5057 | case ALPHA_FPRM_MINF: |
6fec94c5 | 5058 | return "m"; |
5059 | case ALPHA_FPRM_CHOP: | |
5060 | return "c"; | |
5061 | case ALPHA_FPRM_DYN: | |
5062 | return "d"; | |
4d10b463 | 5063 | default: |
5064 | gcc_unreachable (); | |
c4622276 | 5065 | } |
5066 | break; | |
5067 | ||
6fec94c5 | 5068 | case ROUND_SUFFIX_C: |
5069 | return "c"; | |
4d10b463 | 5070 | |
5071 | default: | |
5072 | gcc_unreachable (); | |
6fec94c5 | 5073 | } |
4d10b463 | 5074 | gcc_unreachable (); |
6fec94c5 | 5075 | } |
5076 | ||
5077 | /* Print an operand. Recognize special options, documented below. */ | |
5078 | ||
5079 | void | |
92643d95 | 5080 | print_operand (FILE *file, rtx x, int code) |
6fec94c5 | 5081 | { |
5082 | int i; | |
5083 | ||
5084 | switch (code) | |
5085 | { | |
5086 | case '~': | |
5087 | /* Print the assembler name of the current function. */ | |
5088 | assemble_name (file, alpha_fnname); | |
5089 | break; | |
5090 | ||
5f7b9df8 | 5091 | case '&': |
3677652f | 5092 | if (const char *name = get_some_local_dynamic_name ()) |
5093 | assemble_name (file, name); | |
5094 | else | |
5095 | output_operand_lossage ("'%%&' used without any " | |
5096 | "local dynamic TLS references"); | |
5f7b9df8 | 5097 | break; |
5098 | ||
6fec94c5 | 5099 | case '/': |
5100 | { | |
5101 | const char *trap = get_trap_mode_suffix (); | |
5102 | const char *round = get_round_mode_suffix (); | |
5103 | ||
5104 | if (trap || round) | |
48a5030b | 5105 | fprintf (file, "/%s%s", (trap ? trap : ""), (round ? round : "")); |
6fec94c5 | 5106 | break; |
5107 | } | |
5108 | ||
8df4a58b | 5109 | case ',': |
5110 | /* Generates single precision instruction suffix. */ | |
6fec94c5 | 5111 | fputc ((TARGET_FLOAT_VAX ? 'f' : 's'), file); |
8df4a58b | 5112 | break; |
5113 | ||
5114 | case '-': | |
5115 | /* Generates double precision instruction suffix. */ | |
6fec94c5 | 5116 | fputc ((TARGET_FLOAT_VAX ? 'g' : 't'), file); |
8df4a58b | 5117 | break; |
5118 | ||
1f0ce6a6 | 5119 | case '#': |
5120 | if (alpha_this_literal_sequence_number == 0) | |
5121 | alpha_this_literal_sequence_number = alpha_next_sequence_number++; | |
5122 | fprintf (file, "%d", alpha_this_literal_sequence_number); | |
5123 | break; | |
5124 | ||
5125 | case '*': | |
5126 | if (alpha_this_gpdisp_sequence_number == 0) | |
5127 | alpha_this_gpdisp_sequence_number = alpha_next_sequence_number++; | |
5128 | fprintf (file, "%d", alpha_this_gpdisp_sequence_number); | |
5129 | break; | |
5130 | ||
ad2ed779 | 5131 | case 'J': |
5f7b9df8 | 5132 | { |
5133 | const char *lituse; | |
5134 | ||
5135 | if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD_CALL) | |
5136 | { | |
5137 | x = XVECEXP (x, 0, 0); | |
5138 | lituse = "lituse_tlsgd"; | |
5139 | } | |
5140 | else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSLDM_CALL) | |
5141 | { | |
5142 | x = XVECEXP (x, 0, 0); | |
5143 | lituse = "lituse_tlsldm"; | |
5144 | } | |
c933fb42 | 5145 | else if (CONST_INT_P (x)) |
5f7b9df8 | 5146 | lituse = "lituse_jsr"; |
5147 | else | |
5148 | { | |
5149 | output_operand_lossage ("invalid %%J value"); | |
5150 | break; | |
5151 | } | |
5152 | ||
5153 | if (x != const0_rtx) | |
5154 | fprintf (file, "\t\t!%s!%d", lituse, (int) INTVAL (x)); | |
5155 | } | |
ad2ed779 | 5156 | break; |
5157 | ||
592222c2 | 5158 | case 'j': |
5159 | { | |
5160 | const char *lituse; | |
5161 | ||
5162 | #ifdef HAVE_AS_JSRDIRECT_RELOCS | |
5163 | lituse = "lituse_jsrdirect"; | |
5164 | #else | |
5165 | lituse = "lituse_jsr"; | |
5166 | #endif | |
5167 | ||
5168 | gcc_assert (INTVAL (x) != 0); | |
5169 | fprintf (file, "\t\t!%s!%d", lituse, (int) INTVAL (x)); | |
5170 | } | |
5171 | break; | |
bf2a98b3 | 5172 | case 'r': |
5173 | /* If this operand is the constant zero, write it as "$31". */ | |
c933fb42 | 5174 | if (REG_P (x)) |
bf2a98b3 | 5175 | fprintf (file, "%s", reg_names[REGNO (x)]); |
5176 | else if (x == CONST0_RTX (GET_MODE (x))) | |
5177 | fprintf (file, "$31"); | |
5178 | else | |
5179 | output_operand_lossage ("invalid %%r value"); | |
bf2a98b3 | 5180 | break; |
5181 | ||
5182 | case 'R': | |
5183 | /* Similar, but for floating-point. */ | |
c933fb42 | 5184 | if (REG_P (x)) |
bf2a98b3 | 5185 | fprintf (file, "%s", reg_names[REGNO (x)]); |
5186 | else if (x == CONST0_RTX (GET_MODE (x))) | |
5187 | fprintf (file, "$f31"); | |
5188 | else | |
5189 | output_operand_lossage ("invalid %%R value"); | |
bf2a98b3 | 5190 | break; |
5191 | ||
5192 | case 'N': | |
5193 | /* Write the 1's complement of a constant. */ | |
c933fb42 | 5194 | if (!CONST_INT_P (x)) |
bf2a98b3 | 5195 | output_operand_lossage ("invalid %%N value"); |
5196 | ||
61a63ca5 | 5197 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INTVAL (x)); |
bf2a98b3 | 5198 | break; |
5199 | ||
5200 | case 'P': | |
5201 | /* Write 1 << C, for a constant C. */ | |
c933fb42 | 5202 | if (!CONST_INT_P (x)) |
bf2a98b3 | 5203 | output_operand_lossage ("invalid %%P value"); |
5204 | ||
a2d7211e | 5205 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, HOST_WIDE_INT_1 << INTVAL (x)); |
bf2a98b3 | 5206 | break; |
5207 | ||
5208 | case 'h': | |
5209 | /* Write the high-order 16 bits of a constant, sign-extended. */ | |
c933fb42 | 5210 | if (!CONST_INT_P (x)) |
bf2a98b3 | 5211 | output_operand_lossage ("invalid %%h value"); |
5212 | ||
61a63ca5 | 5213 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) >> 16); |
bf2a98b3 | 5214 | break; |
5215 | ||
5216 | case 'L': | |
5217 | /* Write the low-order 16 bits of a constant, sign-extended. */ | |
c933fb42 | 5218 | if (!CONST_INT_P (x)) |
bf2a98b3 | 5219 | output_operand_lossage ("invalid %%L value"); |
5220 | ||
61a63ca5 | 5221 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, |
5222 | (INTVAL (x) & 0xffff) - 2 * (INTVAL (x) & 0x8000)); | |
bf2a98b3 | 5223 | break; |
5224 | ||
5225 | case 'm': | |
5226 | /* Write mask for ZAP insn. */ | |
5c5c1f00 | 5227 | if (CONST_INT_P (x)) |
bf2a98b3 | 5228 | { |
5229 | HOST_WIDE_INT mask = 0, value = INTVAL (x); | |
5230 | ||
5231 | for (i = 0; i < 8; i++, value >>= 8) | |
5232 | if (value & 0xff) | |
5233 | mask |= (1 << i); | |
5234 | ||
61a63ca5 | 5235 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask); |
bf2a98b3 | 5236 | } |
5237 | else | |
5238 | output_operand_lossage ("invalid %%m value"); | |
5239 | break; | |
5240 | ||
5241 | case 'M': | |
34377880 | 5242 | /* 'b', 'w', 'l', or 'q' as the value of the constant. */ |
7bc95bfb | 5243 | if (!mode_width_operand (x, VOIDmode)) |
bf2a98b3 | 5244 | output_operand_lossage ("invalid %%M value"); |
5245 | ||
5246 | fprintf (file, "%s", | |
34377880 | 5247 | (INTVAL (x) == 8 ? "b" |
5248 | : INTVAL (x) == 16 ? "w" | |
5249 | : INTVAL (x) == 32 ? "l" | |
5250 | : "q")); | |
bf2a98b3 | 5251 | break; |
5252 | ||
5253 | case 'U': | |
5254 | /* Similar, except do it from the mask. */ | |
c933fb42 | 5255 | if (CONST_INT_P (x)) |
ae4cd3a5 | 5256 | { |
5257 | HOST_WIDE_INT value = INTVAL (x); | |
5258 | ||
5259 | if (value == 0xff) | |
5260 | { | |
5261 | fputc ('b', file); | |
5262 | break; | |
5263 | } | |
5264 | if (value == 0xffff) | |
5265 | { | |
5266 | fputc ('w', file); | |
5267 | break; | |
5268 | } | |
5269 | if (value == 0xffffffff) | |
5270 | { | |
5271 | fputc ('l', file); | |
5272 | break; | |
5273 | } | |
5274 | if (value == -1) | |
5275 | { | |
5276 | fputc ('q', file); | |
5277 | break; | |
5278 | } | |
5279 | } | |
a2d7211e | 5280 | |
ae4cd3a5 | 5281 | output_operand_lossage ("invalid %%U value"); |
bf2a98b3 | 5282 | break; |
5283 | ||
5284 | case 's': | |
9bab4302 | 5285 | /* Write the constant value divided by 8. */ |
c933fb42 | 5286 | if (!CONST_INT_P (x) |
9bab4302 | 5287 | || (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 |
9caef960 | 5288 | || (INTVAL (x) & 7) != 0) |
bf2a98b3 | 5289 | output_operand_lossage ("invalid %%s value"); |
5290 | ||
9bab4302 | 5291 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) / 8); |
bf2a98b3 | 5292 | break; |
5293 | ||
5294 | case 'S': | |
5295 | /* Same, except compute (64 - c) / 8 */ | |
5296 | ||
c933fb42 | 5297 | if (!CONST_INT_P (x) |
bf2a98b3 | 5298 | && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 |
5299 | && (INTVAL (x) & 7) != 8) | |
5300 | output_operand_lossage ("invalid %%s value"); | |
5301 | ||
61a63ca5 | 5302 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, (64 - INTVAL (x)) / 8); |
bf2a98b3 | 5303 | break; |
5304 | ||
62dc3582 | 5305 | case 'C': case 'D': case 'c': case 'd': |
bf2a98b3 | 5306 | /* Write out comparison name. */ |
62dc3582 | 5307 | { |
5308 | enum rtx_code c = GET_CODE (x); | |
5309 | ||
6720e96c | 5310 | if (!COMPARISON_P (x)) |
62dc3582 | 5311 | output_operand_lossage ("invalid %%C value"); |
5312 | ||
f3d263a7 | 5313 | else if (code == 'D') |
62dc3582 | 5314 | c = reverse_condition (c); |
5315 | else if (code == 'c') | |
5316 | c = swap_condition (c); | |
5317 | else if (code == 'd') | |
5318 | c = swap_condition (reverse_condition (c)); | |
5319 | ||
5320 | if (c == LEU) | |
5321 | fprintf (file, "ule"); | |
5322 | else if (c == LTU) | |
5323 | fprintf (file, "ult"); | |
a4110d9a | 5324 | else if (c == UNORDERED) |
5325 | fprintf (file, "un"); | |
62dc3582 | 5326 | else |
5327 | fprintf (file, "%s", GET_RTX_NAME (c)); | |
5328 | } | |
8ad50a44 | 5329 | break; |
5330 | ||
bf2a98b3 | 5331 | case 'E': |
5332 | /* Write the divide or modulus operator. */ | |
5333 | switch (GET_CODE (x)) | |
5334 | { | |
5335 | case DIV: | |
5336 | fprintf (file, "div%s", GET_MODE (x) == SImode ? "l" : "q"); | |
5337 | break; | |
5338 | case UDIV: | |
5339 | fprintf (file, "div%su", GET_MODE (x) == SImode ? "l" : "q"); | |
5340 | break; | |
5341 | case MOD: | |
5342 | fprintf (file, "rem%s", GET_MODE (x) == SImode ? "l" : "q"); | |
5343 | break; | |
5344 | case UMOD: | |
5345 | fprintf (file, "rem%su", GET_MODE (x) == SImode ? "l" : "q"); | |
5346 | break; | |
5347 | default: | |
5348 | output_operand_lossage ("invalid %%E value"); | |
5349 | break; | |
5350 | } | |
5351 | break; | |
5352 | ||
bf2a98b3 | 5353 | case 'A': |
5354 | /* Write "_u" for unaligned access. */ | |
c933fb42 | 5355 | if (MEM_P (x) && GET_CODE (XEXP (x, 0)) == AND) |
bf2a98b3 | 5356 | fprintf (file, "_u"); |
5357 | break; | |
5358 | ||
5359 | case 0: | |
c933fb42 | 5360 | if (REG_P (x)) |
bf2a98b3 | 5361 | fprintf (file, "%s", reg_names[REGNO (x)]); |
c933fb42 | 5362 | else if (MEM_P (x)) |
bf2a98b3 | 5363 | output_address (XEXP (x, 0)); |
5f7b9df8 | 5364 | else if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC) |
5365 | { | |
5366 | switch (XINT (XEXP (x, 0), 1)) | |
5367 | { | |
5368 | case UNSPEC_DTPREL: | |
5369 | case UNSPEC_TPREL: | |
5370 | output_addr_const (file, XVECEXP (XEXP (x, 0), 0, 0)); | |
5371 | break; | |
5372 | default: | |
5373 | output_operand_lossage ("unknown relocation unspec"); | |
5374 | break; | |
5375 | } | |
5376 | } | |
bf2a98b3 | 5377 | else |
5378 | output_addr_const (file, x); | |
5379 | break; | |
5380 | ||
5381 | default: | |
5382 | output_operand_lossage ("invalid %%xn code"); | |
5383 | } | |
5384 | } | |
6e0fe99e | 5385 | |
5386 | void | |
92643d95 | 5387 | print_operand_address (FILE *file, rtx addr) |
6e0fe99e | 5388 | { |
a3e39a24 | 5389 | int basereg = 31; |
6e0fe99e | 5390 | HOST_WIDE_INT offset = 0; |
5391 | ||
5392 | if (GET_CODE (addr) == AND) | |
5393 | addr = XEXP (addr, 0); | |
6e0fe99e | 5394 | |
a3e39a24 | 5395 | if (GET_CODE (addr) == PLUS |
c933fb42 | 5396 | && CONST_INT_P (XEXP (addr, 1))) |
6e0fe99e | 5397 | { |
5398 | offset = INTVAL (XEXP (addr, 1)); | |
a3e39a24 | 5399 | addr = XEXP (addr, 0); |
6e0fe99e | 5400 | } |
1f0ce6a6 | 5401 | |
5402 | if (GET_CODE (addr) == LO_SUM) | |
5403 | { | |
5f7b9df8 | 5404 | const char *reloc16, *reloclo; |
5405 | rtx op1 = XEXP (addr, 1); | |
5406 | ||
5407 | if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1, 0)) == UNSPEC) | |
5408 | { | |
5409 | op1 = XEXP (op1, 0); | |
5410 | switch (XINT (op1, 1)) | |
5411 | { | |
5412 | case UNSPEC_DTPREL: | |
5413 | reloc16 = NULL; | |
5414 | reloclo = (alpha_tls_size == 16 ? "dtprel" : "dtprello"); | |
5415 | break; | |
5416 | case UNSPEC_TPREL: | |
5417 | reloc16 = NULL; | |
5418 | reloclo = (alpha_tls_size == 16 ? "tprel" : "tprello"); | |
5419 | break; | |
5420 | default: | |
5421 | output_operand_lossage ("unknown relocation unspec"); | |
5422 | return; | |
5423 | } | |
5424 | ||
5425 | output_addr_const (file, XVECEXP (op1, 0, 0)); | |
5426 | } | |
5427 | else | |
5428 | { | |
5429 | reloc16 = "gprel"; | |
5430 | reloclo = "gprellow"; | |
5431 | output_addr_const (file, op1); | |
5432 | } | |
5433 | ||
1f0ce6a6 | 5434 | if (offset) |
4840a03a | 5435 | fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset); |
9e7454d0 | 5436 | |
1f0ce6a6 | 5437 | addr = XEXP (addr, 0); |
4d10b463 | 5438 | switch (GET_CODE (addr)) |
5439 | { | |
5440 | case REG: | |
5441 | basereg = REGNO (addr); | |
5442 | break; | |
5443 | ||
5444 | case SUBREG: | |
5445 | basereg = subreg_regno (addr); | |
5446 | break; | |
5447 | ||
5448 | default: | |
5449 | gcc_unreachable (); | |
5450 | } | |
5dcb037d | 5451 | |
5452 | fprintf (file, "($%d)\t\t!%s", basereg, | |
5f7b9df8 | 5453 | (basereg == 29 ? reloc16 : reloclo)); |
1f0ce6a6 | 5454 | return; |
5455 | } | |
5456 | ||
4d10b463 | 5457 | switch (GET_CODE (addr)) |
5458 | { | |
5459 | case REG: | |
5460 | basereg = REGNO (addr); | |
5461 | break; | |
5462 | ||
5463 | case SUBREG: | |
5464 | basereg = subreg_regno (addr); | |
5465 | break; | |
5466 | ||
5467 | case CONST_INT: | |
5468 | offset = INTVAL (addr); | |
5469 | break; | |
cf73d31f | 5470 | |
4d10b463 | 5471 | case SYMBOL_REF: |
90449b57 | 5472 | gcc_assert(TARGET_ABI_OPEN_VMS || this_is_asm_operands); |
cf73d31f | 5473 | fprintf (file, "%s", XSTR (addr, 0)); |
5474 | return; | |
4d10b463 | 5475 | |
5476 | case CONST: | |
90449b57 | 5477 | gcc_assert(TARGET_ABI_OPEN_VMS || this_is_asm_operands); |
4d10b463 | 5478 | gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS |
5479 | && GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF); | |
6433714e | 5480 | fprintf (file, "%s+" HOST_WIDE_INT_PRINT_DEC, |
cf73d31f | 5481 | XSTR (XEXP (XEXP (addr, 0), 0), 0), |
5482 | INTVAL (XEXP (XEXP (addr, 0), 1))); | |
5483 | return; | |
90449b57 | 5484 | |
4d10b463 | 5485 | default: |
90449b57 | 5486 | output_operand_lossage ("invalid operand address"); |
5487 | return; | |
4d10b463 | 5488 | } |
6e0fe99e | 5489 | |
4840a03a | 5490 | fprintf (file, HOST_WIDE_INT_PRINT_DEC "($%d)", offset, basereg); |
6e0fe99e | 5491 | } |
bf2a98b3 | 5492 | \f |
9e042f31 | 5493 | /* Emit RTL insns to initialize the variable parts of a trampoline at |
7bcbe23a | 5494 | M_TRAMP. FNDECL is target function's decl. CHAIN_VALUE is an rtx |
5495 | for the static chain value for the function. */ | |
96297568 | 5496 | |
7bcbe23a | 5497 | static void |
5498 | alpha_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) | |
9e042f31 | 5499 | { |
7bcbe23a | 5500 | rtx fnaddr, mem, word1, word2; |
5501 | ||
5502 | fnaddr = XEXP (DECL_RTL (fndecl), 0); | |
9e042f31 | 5503 | |
17683b9f | 5504 | #ifdef POINTERS_EXTEND_UNSIGNED |
7bcbe23a | 5505 | fnaddr = convert_memory_address (Pmode, fnaddr); |
5506 | chain_value = convert_memory_address (Pmode, chain_value); | |
17683b9f | 5507 | #endif |
5508 | ||
d2f33c43 | 5509 | if (TARGET_ABI_OPEN_VMS) |
5510 | { | |
d2f33c43 | 5511 | const char *fnname; |
5512 | char *trname; | |
5513 | ||
5514 | /* Construct the name of the trampoline entry point. */ | |
5515 | fnname = XSTR (fnaddr, 0); | |
5516 | trname = (char *) alloca (strlen (fnname) + 5); | |
5517 | strcpy (trname, fnname); | |
5518 | strcat (trname, "..tr"); | |
7bcbe23a | 5519 | fnname = ggc_alloc_string (trname, strlen (trname) + 1); |
5520 | word2 = gen_rtx_SYMBOL_REF (Pmode, fnname); | |
d2f33c43 | 5521 | |
5522 | /* Trampoline (or "bounded") procedure descriptor is constructed from | |
5523 | the function's procedure descriptor with certain fields zeroed IAW | |
5524 | the VMS calling standard. This is stored in the first quadword. */ | |
7bcbe23a | 5525 | word1 = force_reg (DImode, gen_const_mem (DImode, fnaddr)); |
3ea24468 | 5526 | word1 = expand_and (DImode, word1, |
1fa4dd5c | 5527 | GEN_INT (HOST_WIDE_INT_C (0xffff0fff0000fff0)), |
5528 | NULL); | |
d2f33c43 | 5529 | } |
7bcbe23a | 5530 | else |
5531 | { | |
5532 | /* These 4 instructions are: | |
5533 | ldq $1,24($27) | |
5534 | ldq $27,16($27) | |
5535 | jmp $31,($27),0 | |
5536 | nop | |
5537 | We don't bother setting the HINT field of the jump; the nop | |
5538 | is merely there for padding. */ | |
1fa4dd5c | 5539 | word1 = GEN_INT (HOST_WIDE_INT_C (0xa77b0010a43b0018)); |
5540 | word2 = GEN_INT (HOST_WIDE_INT_C (0x47ff041f6bfb0000)); | |
7bcbe23a | 5541 | } |
5542 | ||
5543 | /* Store the first two words, as computed above. */ | |
5544 | mem = adjust_address (m_tramp, DImode, 0); | |
5545 | emit_move_insn (mem, word1); | |
5546 | mem = adjust_address (m_tramp, DImode, 8); | |
5547 | emit_move_insn (mem, word2); | |
5548 | ||
5549 | /* Store function address and static chain value. */ | |
5550 | mem = adjust_address (m_tramp, Pmode, 16); | |
5551 | emit_move_insn (mem, fnaddr); | |
5552 | mem = adjust_address (m_tramp, Pmode, 24); | |
5553 | emit_move_insn (mem, chain_value); | |
d2f33c43 | 5554 | |
4505d022 | 5555 | if (TARGET_ABI_OSF) |
7bcbe23a | 5556 | { |
5557 | emit_insn (gen_imb ()); | |
a6f06169 | 5558 | #ifdef HAVE_ENABLE_EXECUTE_STACK |
7bcbe23a | 5559 | emit_library_call (init_one_libfunc ("__enable_execute_stack"), |
5560 | LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode); | |
9e042f31 | 5561 | #endif |
7bcbe23a | 5562 | } |
9e042f31 | 5563 | } |
5564 | \f | |
915c336f | 5565 | /* Determine where to put an argument to a function. |
5566 | Value is zero to push the argument on the stack, | |
5567 | or a hard register in which to store the argument. | |
5568 | ||
5569 | MODE is the argument's machine mode. | |
5570 | TYPE is the data type of the argument (as a tree). | |
5571 | This is null for libcalls where that information may | |
5572 | not be available. | |
5573 | CUM is a variable of type CUMULATIVE_ARGS which gives info about | |
5574 | the preceding args and about the function being called. | |
5575 | NAMED is nonzero if this argument is a named parameter | |
5576 | (otherwise it is an extra parameter matching an ellipsis). | |
5577 | ||
5578 | On Alpha the first 6 words of args are normally in registers | |
5579 | and the rest are pushed. */ | |
5580 | ||
54ea4630 | 5581 | static rtx |
3754d046 | 5582 | alpha_function_arg (cumulative_args_t cum_v, machine_mode mode, |
54ea4630 | 5583 | const_tree type, bool named ATTRIBUTE_UNUSED) |
915c336f | 5584 | { |
39cba157 | 5585 | CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); |
915c336f | 5586 | int basereg; |
57e47080 | 5587 | int num_args; |
915c336f | 5588 | |
a685f5d8 | 5589 | /* Don't get confused and pass small structures in FP registers. */ |
5590 | if (type && AGGREGATE_TYPE_P (type)) | |
9caef960 | 5591 | basereg = 16; |
a685f5d8 | 5592 | else |
5593 | { | |
5594 | #ifdef ENABLE_CHECKING | |
92d40bc4 | 5595 | /* With alpha_split_complex_arg, we shouldn't see any raw complex |
a685f5d8 | 5596 | values here. */ |
4d10b463 | 5597 | gcc_assert (!COMPLEX_MODE_P (mode)); |
a685f5d8 | 5598 | #endif |
5599 | ||
5600 | /* Set up defaults for FP operands passed in FP registers, and | |
5601 | integral operands passed in integer registers. */ | |
5602 | if (TARGET_FPREGS && GET_MODE_CLASS (mode) == MODE_FLOAT) | |
5603 | basereg = 32 + 16; | |
5604 | else | |
5605 | basereg = 16; | |
5606 | } | |
9caef960 | 5607 | |
5608 | /* ??? Irritatingly, the definition of CUMULATIVE_ARGS is different for | |
54ea4630 | 5609 | the two platforms, so we can't avoid conditional compilation. */ |
1467e953 | 5610 | #if TARGET_ABI_OPEN_VMS |
9caef960 | 5611 | { |
5612 | if (mode == VOIDmode) | |
b50190db | 5613 | return alpha_arg_info_reg_val (*cum); |
1467e953 | 5614 | |
54ea4630 | 5615 | num_args = cum->num_args; |
0336f0f0 | 5616 | if (num_args >= 6 |
5617 | || targetm.calls.must_pass_in_stack (mode, type)) | |
9caef960 | 5618 | return NULL_RTX; |
5619 | } | |
a685f5d8 | 5620 | #elif TARGET_ABI_OSF |
9caef960 | 5621 | { |
54ea4630 | 5622 | if (*cum >= 6) |
9caef960 | 5623 | return NULL_RTX; |
54ea4630 | 5624 | num_args = *cum; |
9caef960 | 5625 | |
5626 | /* VOID is passed as a special flag for "last argument". */ | |
5627 | if (type == void_type_node) | |
5628 | basereg = 16; | |
0336f0f0 | 5629 | else if (targetm.calls.must_pass_in_stack (mode, type)) |
9caef960 | 5630 | return NULL_RTX; |
9caef960 | 5631 | } |
a685f5d8 | 5632 | #else |
5633 | #error Unhandled ABI | |
5634 | #endif | |
915c336f | 5635 | |
57e47080 | 5636 | return gen_rtx_REG (mode, num_args + basereg); |
915c336f | 5637 | } |
5638 | ||
54ea4630 | 5639 | /* Update the data in CUM to advance over an argument |
5640 | of mode MODE and data type TYPE. | |
5641 | (TYPE is null for libcalls where that information may not be available.) */ | |
5642 | ||
5643 | static void | |
3754d046 | 5644 | alpha_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, |
302d2812 | 5645 | const_tree type, bool named ATTRIBUTE_UNUSED) |
54ea4630 | 5646 | { |
39cba157 | 5647 | CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); |
54ea4630 | 5648 | bool onstack = targetm.calls.must_pass_in_stack (mode, type); |
5649 | int increment = onstack ? 6 : ALPHA_ARG_SIZE (mode, type, named); | |
5650 | ||
5651 | #if TARGET_ABI_OSF | |
5652 | *cum += increment; | |
5653 | #else | |
5654 | if (!onstack && cum->num_args < 6) | |
5655 | cum->atypes[cum->num_args] = alpha_arg_type (mode); | |
5656 | cum->num_args += increment; | |
5657 | #endif | |
5658 | } | |
5659 | ||
f054eb3c | 5660 | static int |
39cba157 | 5661 | alpha_arg_partial_bytes (cumulative_args_t cum_v, |
3754d046 | 5662 | machine_mode mode ATTRIBUTE_UNUSED, |
f054eb3c | 5663 | tree type ATTRIBUTE_UNUSED, |
5664 | bool named ATTRIBUTE_UNUSED) | |
5665 | { | |
5666 | int words = 0; | |
39cba157 | 5667 | CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED = get_cumulative_args (cum_v); |
f054eb3c | 5668 | |
5669 | #if TARGET_ABI_OPEN_VMS | |
5670 | if (cum->num_args < 6 | |
5671 | && 6 < cum->num_args + ALPHA_ARG_SIZE (mode, type, named)) | |
5c5b637a | 5672 | words = 6 - cum->num_args; |
f054eb3c | 5673 | #elif TARGET_ABI_OSF |
5674 | if (*cum < 6 && 6 < *cum + ALPHA_ARG_SIZE (mode, type, named)) | |
5675 | words = 6 - *cum; | |
5676 | #else | |
5677 | #error Unhandled ABI | |
5678 | #endif | |
5679 | ||
5680 | return words * UNITS_PER_WORD; | |
5681 | } | |
5682 | ||
5683 | ||
a685f5d8 | 5684 | /* Return true if TYPE must be returned in memory, instead of in registers. */ |
5685 | ||
dd9f3024 | 5686 | static bool |
fb80456a | 5687 | alpha_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) |
a685f5d8 | 5688 | { |
3754d046 | 5689 | machine_mode mode = VOIDmode; |
a685f5d8 | 5690 | int size; |
5691 | ||
5692 | if (type) | |
5693 | { | |
5694 | mode = TYPE_MODE (type); | |
5695 | ||
cfdbb1f5 | 5696 | /* All aggregates are returned in memory, except on OpenVMS where |
5697 | records that fit 64 bits should be returned by immediate value | |
5698 | as required by section 3.8.7.1 of the OpenVMS Calling Standard. */ | |
5699 | if (TARGET_ABI_OPEN_VMS | |
5700 | && TREE_CODE (type) != ARRAY_TYPE | |
5701 | && (unsigned HOST_WIDE_INT) int_size_in_bytes(type) <= 8) | |
5702 | return false; | |
5703 | ||
a685f5d8 | 5704 | if (AGGREGATE_TYPE_P (type)) |
5705 | return true; | |
5706 | } | |
5707 | ||
5708 | size = GET_MODE_SIZE (mode); | |
5709 | switch (GET_MODE_CLASS (mode)) | |
5710 | { | |
5711 | case MODE_VECTOR_FLOAT: | |
5712 | /* Pass all float vectors in memory, like an aggregate. */ | |
5713 | return true; | |
5714 | ||
5715 | case MODE_COMPLEX_FLOAT: | |
5716 | /* We judge complex floats on the size of their element, | |
5717 | not the size of the whole type. */ | |
5718 | size = GET_MODE_UNIT_SIZE (mode); | |
5719 | break; | |
5720 | ||
5721 | case MODE_INT: | |
5722 | case MODE_FLOAT: | |
5723 | case MODE_COMPLEX_INT: | |
5724 | case MODE_VECTOR_INT: | |
5725 | break; | |
5726 | ||
5727 | default: | |
9e7454d0 | 5728 | /* ??? We get called on all sorts of random stuff from |
4d10b463 | 5729 | aggregate_value_p. We must return something, but it's not |
5730 | clear what's safe to return. Pretend it's a struct I | |
5731 | guess. */ | |
a685f5d8 | 5732 | return true; |
5733 | } | |
5734 | ||
5735 | /* Otherwise types must fit in one register. */ | |
5736 | return size > UNITS_PER_WORD; | |
5737 | } | |
5738 | ||
b981d932 | 5739 | /* Return true if TYPE should be passed by invisible reference. */ |
5740 | ||
5741 | static bool | |
39cba157 | 5742 | alpha_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED, |
3754d046 | 5743 | machine_mode mode, |
fb80456a | 5744 | const_tree type ATTRIBUTE_UNUSED, |
b981d932 | 5745 | bool named ATTRIBUTE_UNUSED) |
5746 | { | |
5747 | return mode == TFmode || mode == TCmode; | |
5748 | } | |
5749 | ||
a685f5d8 | 5750 | /* Define how to find the value returned by a function. VALTYPE is the |
5751 | data type of the value (as a tree). If the precise function being | |
5752 | called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0. | |
5753 | MODE is set instead of VALTYPE for libcalls. | |
5754 | ||
5755 | On Alpha the value is found in $0 for integer functions and | |
5756 | $f0 for floating-point functions. */ | |
5757 | ||
5758 | rtx | |
fb80456a | 5759 | function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED, |
3754d046 | 5760 | machine_mode mode) |
a685f5d8 | 5761 | { |
f5e8a4bc | 5762 | unsigned int regnum, dummy ATTRIBUTE_UNUSED; |
8deb3959 | 5763 | enum mode_class mclass; |
a685f5d8 | 5764 | |
4d10b463 | 5765 | gcc_assert (!valtype || !alpha_return_in_memory (valtype, func)); |
a685f5d8 | 5766 | |
5767 | if (valtype) | |
5768 | mode = TYPE_MODE (valtype); | |
5769 | ||
8deb3959 | 5770 | mclass = GET_MODE_CLASS (mode); |
5771 | switch (mclass) | |
a685f5d8 | 5772 | { |
5773 | case MODE_INT: | |
cfdbb1f5 | 5774 | /* Do the same thing as PROMOTE_MODE except for libcalls on VMS, |
5775 | where we have them returning both SImode and DImode. */ | |
5776 | if (!(TARGET_ABI_OPEN_VMS && valtype && AGGREGATE_TYPE_P (valtype))) | |
5777 | PROMOTE_MODE (mode, dummy, valtype); | |
8e262b5e | 5778 | /* FALLTHRU */ |
a685f5d8 | 5779 | |
5780 | case MODE_COMPLEX_INT: | |
5781 | case MODE_VECTOR_INT: | |
5782 | regnum = 0; | |
5783 | break; | |
5784 | ||
5785 | case MODE_FLOAT: | |
5786 | regnum = 32; | |
5787 | break; | |
5788 | ||
5789 | case MODE_COMPLEX_FLOAT: | |
5790 | { | |
3754d046 | 5791 | machine_mode cmode = GET_MODE_INNER (mode); |
a685f5d8 | 5792 | |
5793 | return gen_rtx_PARALLEL | |
5794 | (VOIDmode, | |
5795 | gen_rtvec (2, | |
5796 | gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 32), | |
bcd9bd66 | 5797 | const0_rtx), |
a685f5d8 | 5798 | gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 33), |
5799 | GEN_INT (GET_MODE_SIZE (cmode))))); | |
5800 | } | |
5801 | ||
cfdbb1f5 | 5802 | case MODE_RANDOM: |
5803 | /* We should only reach here for BLKmode on VMS. */ | |
5804 | gcc_assert (TARGET_ABI_OPEN_VMS && mode == BLKmode); | |
5805 | regnum = 0; | |
5806 | break; | |
5807 | ||
a685f5d8 | 5808 | default: |
4d10b463 | 5809 | gcc_unreachable (); |
a685f5d8 | 5810 | } |
5811 | ||
5812 | return gen_rtx_REG (mode, regnum); | |
5813 | } | |
5814 | ||
9e7454d0 | 5815 | /* TCmode complex values are passed by invisible reference. We |
92d40bc4 | 5816 | should not split these values. */ |
5817 | ||
5818 | static bool | |
a9f1838b | 5819 | alpha_split_complex_arg (const_tree type) |
92d40bc4 | 5820 | { |
5821 | return TYPE_MODE (type) != TCmode; | |
5822 | } | |
5823 | ||
2e15d750 | 5824 | static tree |
5825 | alpha_build_builtin_va_list (void) | |
bf2a98b3 | 5826 | { |
7ba21c9f | 5827 | tree base, ofs, space, record, type_decl; |
bf2a98b3 | 5828 | |
04d75965 | 5829 | if (TARGET_ABI_OPEN_VMS) |
e7aabeab | 5830 | return ptr_type_node; |
5831 | ||
a1f71e15 | 5832 | record = (*lang_hooks.types.make_type) (RECORD_TYPE); |
54e46243 | 5833 | type_decl = build_decl (BUILTINS_LOCATION, |
5834 | TYPE_DECL, get_identifier ("__va_list_tag"), record); | |
bc907808 | 5835 | TYPE_STUB_DECL (record) = type_decl; |
0054fd98 | 5836 | TYPE_NAME (record) = type_decl; |
5837 | ||
e7aabeab | 5838 | /* C++? SET_IS_AGGR_TYPE (record, 1); */ |
bf2a98b3 | 5839 | |
7ba21c9f | 5840 | /* Dummy field to prevent alignment warnings. */ |
54e46243 | 5841 | space = build_decl (BUILTINS_LOCATION, |
5842 | FIELD_DECL, NULL_TREE, integer_type_node); | |
7ba21c9f | 5843 | DECL_FIELD_CONTEXT (space) = record; |
5844 | DECL_ARTIFICIAL (space) = 1; | |
5845 | DECL_IGNORED_P (space) = 1; | |
5846 | ||
54e46243 | 5847 | ofs = build_decl (BUILTINS_LOCATION, |
5848 | FIELD_DECL, get_identifier ("__offset"), | |
e7aabeab | 5849 | integer_type_node); |
5850 | DECL_FIELD_CONTEXT (ofs) = record; | |
1767a056 | 5851 | DECL_CHAIN (ofs) = space; |
fc4c89ed | 5852 | |
54e46243 | 5853 | base = build_decl (BUILTINS_LOCATION, |
5854 | FIELD_DECL, get_identifier ("__base"), | |
e7aabeab | 5855 | ptr_type_node); |
5856 | DECL_FIELD_CONTEXT (base) = record; | |
1767a056 | 5857 | DECL_CHAIN (base) = ofs; |
fc4c89ed | 5858 | |
e7aabeab | 5859 | TYPE_FIELDS (record) = base; |
5860 | layout_type (record); | |
5861 | ||
a6c787e5 | 5862 | va_list_gpr_counter_field = ofs; |
e7aabeab | 5863 | return record; |
5864 | } | |
5865 | ||
7955d282 | 5866 | #if TARGET_ABI_OSF |
a6c787e5 | 5867 | /* Helper function for alpha_stdarg_optimize_hook. Skip over casts |
5868 | and constant additions. */ | |
5869 | ||
94c0325b | 5870 | static gimple |
a6c787e5 | 5871 | va_list_skip_additions (tree lhs) |
5872 | { | |
94c0325b | 5873 | gimple stmt; |
a6c787e5 | 5874 | |
5875 | for (;;) | |
5876 | { | |
94c0325b | 5877 | enum tree_code code; |
5878 | ||
a6c787e5 | 5879 | stmt = SSA_NAME_DEF_STMT (lhs); |
5880 | ||
94c0325b | 5881 | if (gimple_code (stmt) == GIMPLE_PHI) |
a6c787e5 | 5882 | return stmt; |
5883 | ||
94c0325b | 5884 | if (!is_gimple_assign (stmt) |
5885 | || gimple_assign_lhs (stmt) != lhs) | |
5886 | return NULL; | |
a6c787e5 | 5887 | |
94c0325b | 5888 | if (TREE_CODE (gimple_assign_rhs1 (stmt)) != SSA_NAME) |
5889 | return stmt; | |
5890 | code = gimple_assign_rhs_code (stmt); | |
5891 | if (!CONVERT_EXPR_CODE_P (code) | |
5892 | && ((code != PLUS_EXPR && code != POINTER_PLUS_EXPR) | |
5893 | || TREE_CODE (gimple_assign_rhs2 (stmt)) != INTEGER_CST | |
cd4547bf | 5894 | || !tree_fits_uhwi_p (gimple_assign_rhs2 (stmt)))) |
94c0325b | 5895 | return stmt; |
a6c787e5 | 5896 | |
94c0325b | 5897 | lhs = gimple_assign_rhs1 (stmt); |
a6c787e5 | 5898 | } |
5899 | } | |
5900 | ||
5901 | /* Check if LHS = RHS statement is | |
5902 | LHS = *(ap.__base + ap.__offset + cst) | |
5903 | or | |
5904 | LHS = *(ap.__base | |
5905 | + ((ap.__offset + cst <= 47) | |
5906 | ? ap.__offset + cst - 48 : ap.__offset + cst) + cst2). | |
5907 | If the former, indicate that GPR registers are needed, | |
5908 | if the latter, indicate that FPR registers are needed. | |
adde8f91 | 5909 | |
5910 | Also look for LHS = (*ptr).field, where ptr is one of the forms | |
5911 | listed above. | |
5912 | ||
a6c787e5 | 5913 | On alpha, cfun->va_list_gpr_size is used as size of the needed |
adde8f91 | 5914 | regs and cfun->va_list_fpr_size is a bitmask, bit 0 set if GPR |
5915 | registers are needed and bit 1 set if FPR registers are needed. | |
5916 | Return true if va_list references should not be scanned for the | |
5917 | current statement. */ | |
a6c787e5 | 5918 | |
5919 | static bool | |
75a70cf9 | 5920 | alpha_stdarg_optimize_hook (struct stdarg_info *si, const_gimple stmt) |
a6c787e5 | 5921 | { |
94c0325b | 5922 | tree base, offset, rhs; |
a6c787e5 | 5923 | int offset_arg = 1; |
94c0325b | 5924 | gimple base_stmt; |
a6c787e5 | 5925 | |
94c0325b | 5926 | if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) |
5927 | != GIMPLE_SINGLE_RHS) | |
5928 | return false; | |
5929 | ||
5930 | rhs = gimple_assign_rhs1 (stmt); | |
adde8f91 | 5931 | while (handled_component_p (rhs)) |
5932 | rhs = TREE_OPERAND (rhs, 0); | |
182cf5a9 | 5933 | if (TREE_CODE (rhs) != MEM_REF |
a6c787e5 | 5934 | || TREE_CODE (TREE_OPERAND (rhs, 0)) != SSA_NAME) |
5935 | return false; | |
5936 | ||
94c0325b | 5937 | stmt = va_list_skip_additions (TREE_OPERAND (rhs, 0)); |
5938 | if (stmt == NULL | |
5939 | || !is_gimple_assign (stmt) | |
5940 | || gimple_assign_rhs_code (stmt) != POINTER_PLUS_EXPR) | |
a6c787e5 | 5941 | return false; |
5942 | ||
94c0325b | 5943 | base = gimple_assign_rhs1 (stmt); |
a6c787e5 | 5944 | if (TREE_CODE (base) == SSA_NAME) |
94c0325b | 5945 | { |
5946 | base_stmt = va_list_skip_additions (base); | |
5947 | if (base_stmt | |
5948 | && is_gimple_assign (base_stmt) | |
5949 | && gimple_assign_rhs_code (base_stmt) == COMPONENT_REF) | |
5950 | base = gimple_assign_rhs1 (base_stmt); | |
5951 | } | |
a6c787e5 | 5952 | |
5953 | if (TREE_CODE (base) != COMPONENT_REF | |
5954 | || TREE_OPERAND (base, 1) != TYPE_FIELDS (va_list_type_node)) | |
5955 | { | |
94c0325b | 5956 | base = gimple_assign_rhs2 (stmt); |
a6c787e5 | 5957 | if (TREE_CODE (base) == SSA_NAME) |
94c0325b | 5958 | { |
5959 | base_stmt = va_list_skip_additions (base); | |
5960 | if (base_stmt | |
5961 | && is_gimple_assign (base_stmt) | |
5962 | && gimple_assign_rhs_code (base_stmt) == COMPONENT_REF) | |
5963 | base = gimple_assign_rhs1 (base_stmt); | |
5964 | } | |
a6c787e5 | 5965 | |
5966 | if (TREE_CODE (base) != COMPONENT_REF | |
5967 | || TREE_OPERAND (base, 1) != TYPE_FIELDS (va_list_type_node)) | |
5968 | return false; | |
5969 | ||
5970 | offset_arg = 0; | |
5971 | } | |
5972 | ||
5973 | base = get_base_address (base); | |
5974 | if (TREE_CODE (base) != VAR_DECL | |
72952522 | 5975 | || !bitmap_bit_p (si->va_list_vars, DECL_UID (base) + num_ssa_names)) |
a6c787e5 | 5976 | return false; |
5977 | ||
94c0325b | 5978 | offset = gimple_op (stmt, 1 + offset_arg); |
a6c787e5 | 5979 | if (TREE_CODE (offset) == SSA_NAME) |
a6c787e5 | 5980 | { |
94c0325b | 5981 | gimple offset_stmt = va_list_skip_additions (offset); |
a6c787e5 | 5982 | |
94c0325b | 5983 | if (offset_stmt |
5984 | && gimple_code (offset_stmt) == GIMPLE_PHI) | |
a6c787e5 | 5985 | { |
94c0325b | 5986 | HOST_WIDE_INT sub; |
5987 | gimple arg1_stmt, arg2_stmt; | |
5988 | tree arg1, arg2; | |
5989 | enum tree_code code1, code2; | |
a6c787e5 | 5990 | |
94c0325b | 5991 | if (gimple_phi_num_args (offset_stmt) != 2) |
7955d282 | 5992 | goto escapes; |
a6c787e5 | 5993 | |
94c0325b | 5994 | arg1_stmt |
5995 | = va_list_skip_additions (gimple_phi_arg_def (offset_stmt, 0)); | |
5996 | arg2_stmt | |
5997 | = va_list_skip_additions (gimple_phi_arg_def (offset_stmt, 1)); | |
5998 | if (arg1_stmt == NULL | |
5999 | || !is_gimple_assign (arg1_stmt) | |
6000 | || arg2_stmt == NULL | |
6001 | || !is_gimple_assign (arg2_stmt)) | |
6002 | goto escapes; | |
a6c787e5 | 6003 | |
94c0325b | 6004 | code1 = gimple_assign_rhs_code (arg1_stmt); |
6005 | code2 = gimple_assign_rhs_code (arg2_stmt); | |
6006 | if (code1 == COMPONENT_REF | |
6007 | && (code2 == MINUS_EXPR || code2 == PLUS_EXPR)) | |
6008 | /* Do nothing. */; | |
6009 | else if (code2 == COMPONENT_REF | |
6010 | && (code1 == MINUS_EXPR || code1 == PLUS_EXPR)) | |
6011 | { | |
6012 | gimple tem = arg1_stmt; | |
6013 | code2 = code1; | |
6014 | arg1_stmt = arg2_stmt; | |
6015 | arg2_stmt = tem; | |
6016 | } | |
6017 | else | |
6018 | goto escapes; | |
7955d282 | 6019 | |
35ec552a | 6020 | if (!tree_fits_shwi_p (gimple_assign_rhs2 (arg2_stmt))) |
94c0325b | 6021 | goto escapes; |
7955d282 | 6022 | |
fcb97e84 | 6023 | sub = tree_to_shwi (gimple_assign_rhs2 (arg2_stmt)); |
94c0325b | 6024 | if (code2 == MINUS_EXPR) |
6025 | sub = -sub; | |
6026 | if (sub < -48 || sub > -32) | |
6027 | goto escapes; | |
a6c787e5 | 6028 | |
94c0325b | 6029 | arg1 = gimple_assign_rhs1 (arg1_stmt); |
6030 | arg2 = gimple_assign_rhs1 (arg2_stmt); | |
6031 | if (TREE_CODE (arg2) == SSA_NAME) | |
6032 | { | |
6033 | arg2_stmt = va_list_skip_additions (arg2); | |
6034 | if (arg2_stmt == NULL | |
6035 | || !is_gimple_assign (arg2_stmt) | |
6036 | || gimple_assign_rhs_code (arg2_stmt) != COMPONENT_REF) | |
6037 | goto escapes; | |
6038 | arg2 = gimple_assign_rhs1 (arg2_stmt); | |
6039 | } | |
6040 | if (arg1 != arg2) | |
6041 | goto escapes; | |
6042 | ||
6043 | if (TREE_CODE (arg1) != COMPONENT_REF | |
6044 | || TREE_OPERAND (arg1, 1) != va_list_gpr_counter_field | |
6045 | || get_base_address (arg1) != base) | |
6046 | goto escapes; | |
6047 | ||
6048 | /* Need floating point regs. */ | |
6049 | cfun->va_list_fpr_size |= 2; | |
6050 | return false; | |
6051 | } | |
6052 | if (offset_stmt | |
6053 | && is_gimple_assign (offset_stmt) | |
6054 | && gimple_assign_rhs_code (offset_stmt) == COMPONENT_REF) | |
6055 | offset = gimple_assign_rhs1 (offset_stmt); | |
6056 | } | |
6057 | if (TREE_CODE (offset) != COMPONENT_REF | |
6058 | || TREE_OPERAND (offset, 1) != va_list_gpr_counter_field | |
6059 | || get_base_address (offset) != base) | |
a6c787e5 | 6060 | goto escapes; |
6061 | else | |
6062 | /* Need general regs. */ | |
6063 | cfun->va_list_fpr_size |= 1; | |
6064 | return false; | |
6065 | ||
6066 | escapes: | |
6067 | si->va_list_escapes = true; | |
6068 | return false; | |
6069 | } | |
7955d282 | 6070 | #endif |
a6c787e5 | 6071 | |
4310aa50 | 6072 | /* Perform any needed actions needed for a function that is receiving a |
dd9f3024 | 6073 | variable number of arguments. */ |
4310aa50 | 6074 | |
dd9f3024 | 6075 | static void |
3754d046 | 6076 | alpha_setup_incoming_varargs (cumulative_args_t pcum, machine_mode mode, |
2dc656b7 | 6077 | tree type, int *pretend_size, int no_rtl) |
dd9f3024 | 6078 | { |
39cba157 | 6079 | CUMULATIVE_ARGS cum = *get_cumulative_args (pcum); |
2dc656b7 | 6080 | |
6081 | /* Skip the current argument. */ | |
39cba157 | 6082 | targetm.calls.function_arg_advance (pack_cumulative_args (&cum), mode, type, |
6083 | true); | |
2dc656b7 | 6084 | |
04d75965 | 6085 | #if TARGET_ABI_OPEN_VMS |
dd9f3024 | 6086 | /* For VMS, we allocate space for all 6 arg registers plus a count. |
4310aa50 | 6087 | |
dd9f3024 | 6088 | However, if NO registers need to be saved, don't allocate any space. |
6089 | This is not only because we won't need the space, but because AP | |
6090 | includes the current_pretend_args_size and we don't want to mess up | |
6091 | any ap-relative addresses already made. */ | |
2dc656b7 | 6092 | if (cum.num_args < 6) |
dd9f3024 | 6093 | { |
6094 | if (!no_rtl) | |
6095 | { | |
6096 | emit_move_insn (gen_rtx_REG (DImode, 1), virtual_incoming_args_rtx); | |
6097 | emit_insn (gen_arg_home ()); | |
6098 | } | |
6099 | *pretend_size = 7 * UNITS_PER_WORD; | |
6100 | } | |
6101 | #else | |
6102 | /* On OSF/1 and friends, we allocate space for all 12 arg registers, but | |
6103 | only push those that are remaining. However, if NO registers need to | |
6104 | be saved, don't allocate any space. This is not only because we won't | |
6105 | need the space, but because AP includes the current_pretend_args_size | |
6106 | and we don't want to mess up any ap-relative addresses already made. | |
6107 | ||
6108 | If we are not to use the floating-point registers, save the integer | |
6109 | registers where we would put the floating-point registers. This is | |
6110 | not the most efficient way to implement varargs with just one register | |
6111 | class, but it isn't worth doing anything more efficient in this rare | |
6112 | case. */ | |
4310aa50 | 6113 | if (cum >= 6) |
6114 | return; | |
6115 | ||
6116 | if (!no_rtl) | |
6117 | { | |
32c2fdea | 6118 | int count; |
6119 | alias_set_type set = get_varargs_alias_set (); | |
4310aa50 | 6120 | rtx tmp; |
6121 | ||
7955d282 | 6122 | count = cfun->va_list_gpr_size / UNITS_PER_WORD; |
6123 | if (count > 6 - cum) | |
6124 | count = 6 - cum; | |
4310aa50 | 6125 | |
7955d282 | 6126 | /* Detect whether integer registers or floating-point registers |
6127 | are needed by the detected va_arg statements. See above for | |
6128 | how these values are computed. Note that the "escape" value | |
6129 | is VA_LIST_MAX_FPR_SIZE, which is 255, which has both of | |
6130 | these bits set. */ | |
6131 | gcc_assert ((VA_LIST_MAX_FPR_SIZE & 3) == 3); | |
6132 | ||
6133 | if (cfun->va_list_fpr_size & 1) | |
6134 | { | |
6135 | tmp = gen_rtx_MEM (BLKmode, | |
29c05e22 | 6136 | plus_constant (Pmode, virtual_incoming_args_rtx, |
7955d282 | 6137 | (cum + 6) * UNITS_PER_WORD)); |
ae2dd339 | 6138 | MEM_NOTRAP_P (tmp) = 1; |
7955d282 | 6139 | set_mem_alias_set (tmp, set); |
6140 | move_block_from_reg (16 + cum, tmp, count); | |
6141 | } | |
6142 | ||
6143 | if (cfun->va_list_fpr_size & 2) | |
6144 | { | |
6145 | tmp = gen_rtx_MEM (BLKmode, | |
29c05e22 | 6146 | plus_constant (Pmode, virtual_incoming_args_rtx, |
7955d282 | 6147 | cum * UNITS_PER_WORD)); |
ae2dd339 | 6148 | MEM_NOTRAP_P (tmp) = 1; |
7955d282 | 6149 | set_mem_alias_set (tmp, set); |
6150 | move_block_from_reg (16 + cum + TARGET_FPREGS*32, tmp, count); | |
6151 | } | |
6152 | } | |
4310aa50 | 6153 | *pretend_size = 12 * UNITS_PER_WORD; |
f6940372 | 6154 | #endif |
dd9f3024 | 6155 | } |
4310aa50 | 6156 | |
8a58ed0a | 6157 | static void |
92643d95 | 6158 | alpha_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) |
e7aabeab | 6159 | { |
6160 | HOST_WIDE_INT offset; | |
6161 | tree t, offset_field, base_field; | |
fc4c89ed | 6162 | |
80909c64 | 6163 | if (TREE_CODE (TREE_TYPE (valist)) == ERROR_MARK) |
6164 | return; | |
6165 | ||
6644435d | 6166 | /* For Unix, TARGET_SETUP_INCOMING_VARARGS moves the starting address base |
e7aabeab | 6167 | up by 48, storing fp arg registers in the first 48 bytes, and the |
6168 | integer arg registers in the next 48 bytes. This is only done, | |
6169 | however, if any integer registers need to be stored. | |
6170 | ||
6171 | If no integer registers need be stored, then we must subtract 48 | |
6172 | in order to account for the integer arg registers which are counted | |
4310aa50 | 6173 | in argsize above, but which are not actually stored on the stack. |
6174 | Must further be careful here about structures straddling the last | |
9e7454d0 | 6175 | integer argument register; that futzes with pretend_args_size, |
4310aa50 | 6176 | which changes the meaning of AP. */ |
e7aabeab | 6177 | |
2dc656b7 | 6178 | if (NUM_ARGS < 6) |
fc264da3 | 6179 | offset = TARGET_ABI_OPEN_VMS ? UNITS_PER_WORD : 6 * UNITS_PER_WORD; |
8df4a58b | 6180 | else |
abe32cce | 6181 | offset = -6 * UNITS_PER_WORD + crtl->args.pretend_args_size; |
e7aabeab | 6182 | |
fc264da3 | 6183 | if (TARGET_ABI_OPEN_VMS) |
6184 | { | |
cfdbb1f5 | 6185 | t = make_tree (ptr_type_node, virtual_incoming_args_rtx); |
2cc66f2a | 6186 | t = fold_build_pointer_plus_hwi (t, offset + NUM_ARGS * UNITS_PER_WORD); |
cfdbb1f5 | 6187 | t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t); |
fc264da3 | 6188 | TREE_SIDE_EFFECTS (t) = 1; |
fc264da3 | 6189 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); |
6190 | } | |
6191 | else | |
6192 | { | |
6193 | base_field = TYPE_FIELDS (TREE_TYPE (valist)); | |
1767a056 | 6194 | offset_field = DECL_CHAIN (base_field); |
fc264da3 | 6195 | |
ed03eadb | 6196 | base_field = build3 (COMPONENT_REF, TREE_TYPE (base_field), |
6197 | valist, base_field, NULL_TREE); | |
6198 | offset_field = build3 (COMPONENT_REF, TREE_TYPE (offset_field), | |
6199 | valist, offset_field, NULL_TREE); | |
fc264da3 | 6200 | |
6201 | t = make_tree (ptr_type_node, virtual_incoming_args_rtx); | |
2cc66f2a | 6202 | t = fold_build_pointer_plus_hwi (t, offset); |
75a70cf9 | 6203 | t = build2 (MODIFY_EXPR, TREE_TYPE (base_field), base_field, t); |
fc264da3 | 6204 | TREE_SIDE_EFFECTS (t) = 1; |
6205 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
6206 | ||
7016c612 | 6207 | t = build_int_cst (NULL_TREE, NUM_ARGS * UNITS_PER_WORD); |
75a70cf9 | 6208 | t = build2 (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, t); |
fc264da3 | 6209 | TREE_SIDE_EFFECTS (t) = 1; |
6210 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
6211 | } | |
e7aabeab | 6212 | } |
6213 | ||
de8f9b94 | 6214 | static tree |
94c0325b | 6215 | alpha_gimplify_va_arg_1 (tree type, tree base, tree offset, |
75a70cf9 | 6216 | gimple_seq *pre_p) |
de8f9b94 | 6217 | { |
94c0325b | 6218 | tree type_size, ptr_type, addend, t, addr; |
6219 | gimple_seq internal_post; | |
de8f9b94 | 6220 | |
de8f9b94 | 6221 | /* If the type could not be passed in registers, skip the block |
6222 | reserved for the registers. */ | |
0336f0f0 | 6223 | if (targetm.calls.must_pass_in_stack (TYPE_MODE (type), type)) |
de8f9b94 | 6224 | { |
7016c612 | 6225 | t = build_int_cst (TREE_TYPE (offset), 6*8); |
75a70cf9 | 6226 | gimplify_assign (offset, |
6227 | build2 (MAX_EXPR, TREE_TYPE (offset), offset, t), | |
6228 | pre_p); | |
de8f9b94 | 6229 | } |
6230 | ||
6231 | addend = offset; | |
bd746187 | 6232 | ptr_type = build_pointer_type_for_mode (type, ptr_mode, true); |
de8f9b94 | 6233 | |
2cd7bb84 | 6234 | if (TREE_CODE (type) == COMPLEX_TYPE) |
de8f9b94 | 6235 | { |
6236 | tree real_part, imag_part, real_temp; | |
6237 | ||
c7b3f103 | 6238 | real_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, |
6239 | offset, pre_p); | |
6240 | ||
6241 | /* Copy the value into a new temporary, lest the formal temporary | |
de8f9b94 | 6242 | be reused out from under us. */ |
c7b3f103 | 6243 | real_temp = get_initialized_tmp_var (real_part, pre_p, NULL); |
de8f9b94 | 6244 | |
c7b3f103 | 6245 | imag_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, |
6246 | offset, pre_p); | |
de8f9b94 | 6247 | |
ed03eadb | 6248 | return build2 (COMPLEX_EXPR, type, real_temp, imag_part); |
de8f9b94 | 6249 | } |
6250 | else if (TREE_CODE (type) == REAL_TYPE) | |
6251 | { | |
6252 | tree fpaddend, cond, fourtyeight; | |
6253 | ||
7016c612 | 6254 | fourtyeight = build_int_cst (TREE_TYPE (addend), 6*8); |
ed03eadb | 6255 | fpaddend = fold_build2 (MINUS_EXPR, TREE_TYPE (addend), |
6256 | addend, fourtyeight); | |
6257 | cond = fold_build2 (LT_EXPR, boolean_type_node, addend, fourtyeight); | |
6258 | addend = fold_build3 (COND_EXPR, TREE_TYPE (addend), cond, | |
6259 | fpaddend, addend); | |
de8f9b94 | 6260 | } |
6261 | ||
6262 | /* Build the final address and force that value into a temporary. */ | |
2cc66f2a | 6263 | addr = fold_build_pointer_plus (fold_convert (ptr_type, base), addend); |
c7b3f103 | 6264 | internal_post = NULL; |
6265 | gimplify_expr (&addr, pre_p, &internal_post, is_gimple_val, fb_rvalue); | |
94c0325b | 6266 | gimple_seq_add_seq (pre_p, internal_post); |
de8f9b94 | 6267 | |
6268 | /* Update the offset field. */ | |
c7b3f103 | 6269 | type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type)); |
6270 | if (type_size == NULL || TREE_OVERFLOW (type_size)) | |
6271 | t = size_zero_node; | |
6272 | else | |
6273 | { | |
6274 | t = size_binop (PLUS_EXPR, type_size, size_int (7)); | |
6275 | t = size_binop (TRUNC_DIV_EXPR, t, size_int (8)); | |
6276 | t = size_binop (MULT_EXPR, t, size_int (8)); | |
6277 | } | |
6278 | t = fold_convert (TREE_TYPE (offset), t); | |
75a70cf9 | 6279 | gimplify_assign (offset, build2 (PLUS_EXPR, TREE_TYPE (offset), offset, t), |
6280 | pre_p); | |
de8f9b94 | 6281 | |
063f5fdd | 6282 | return build_va_arg_indirect_ref (addr); |
de8f9b94 | 6283 | } |
6284 | ||
e0eca1fa | 6285 | static tree |
75a70cf9 | 6286 | alpha_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, |
6287 | gimple_seq *post_p) | |
de8f9b94 | 6288 | { |
e0eca1fa | 6289 | tree offset_field, base_field, offset, base, t, r; |
2cd7bb84 | 6290 | bool indirect; |
de8f9b94 | 6291 | |
04d75965 | 6292 | if (TARGET_ABI_OPEN_VMS) |
e0eca1fa | 6293 | return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); |
de8f9b94 | 6294 | |
6295 | base_field = TYPE_FIELDS (va_list_type_node); | |
1767a056 | 6296 | offset_field = DECL_CHAIN (base_field); |
ed03eadb | 6297 | base_field = build3 (COMPONENT_REF, TREE_TYPE (base_field), |
6298 | valist, base_field, NULL_TREE); | |
6299 | offset_field = build3 (COMPONENT_REF, TREE_TYPE (offset_field), | |
6300 | valist, offset_field, NULL_TREE); | |
de8f9b94 | 6301 | |
c7b3f103 | 6302 | /* Pull the fields of the structure out into temporaries. Since we never |
6303 | modify the base field, we can use a formal temporary. Sign-extend the | |
6304 | offset field so that it's the proper width for pointer arithmetic. */ | |
6305 | base = get_formal_tmp_var (base_field, pre_p); | |
de8f9b94 | 6306 | |
a51edb4c | 6307 | t = fold_convert (build_nonstandard_integer_type (64, 0), offset_field); |
c7b3f103 | 6308 | offset = get_initialized_tmp_var (t, pre_p, NULL); |
de8f9b94 | 6309 | |
2cd7bb84 | 6310 | indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false); |
6311 | if (indirect) | |
bd746187 | 6312 | type = build_pointer_type_for_mode (type, ptr_mode, true); |
2cd7bb84 | 6313 | |
de8f9b94 | 6314 | /* Find the value. Note that this will be a stable indirection, or |
6315 | a composite of stable indirections in the case of complex. */ | |
c7b3f103 | 6316 | r = alpha_gimplify_va_arg_1 (type, base, offset, pre_p); |
de8f9b94 | 6317 | |
6318 | /* Stuff the offset temporary back into its field. */ | |
94c0325b | 6319 | gimplify_assign (unshare_expr (offset_field), |
75a70cf9 | 6320 | fold_convert (TREE_TYPE (offset_field), offset), pre_p); |
e0eca1fa | 6321 | |
2cd7bb84 | 6322 | if (indirect) |
063f5fdd | 6323 | r = build_va_arg_indirect_ref (r); |
2cd7bb84 | 6324 | |
e0eca1fa | 6325 | return r; |
de8f9b94 | 6326 | } |
bf2a98b3 | 6327 | \f |
f2cc13dc | 6328 | /* Builtins. */ |
6329 | ||
6330 | enum alpha_builtin | |
6331 | { | |
6332 | ALPHA_BUILTIN_CMPBGE, | |
ae4cd3a5 | 6333 | ALPHA_BUILTIN_EXTBL, |
6334 | ALPHA_BUILTIN_EXTWL, | |
6335 | ALPHA_BUILTIN_EXTLL, | |
f2cc13dc | 6336 | ALPHA_BUILTIN_EXTQL, |
ae4cd3a5 | 6337 | ALPHA_BUILTIN_EXTWH, |
6338 | ALPHA_BUILTIN_EXTLH, | |
f2cc13dc | 6339 | ALPHA_BUILTIN_EXTQH, |
ae4cd3a5 | 6340 | ALPHA_BUILTIN_INSBL, |
6341 | ALPHA_BUILTIN_INSWL, | |
6342 | ALPHA_BUILTIN_INSLL, | |
6343 | ALPHA_BUILTIN_INSQL, | |
6344 | ALPHA_BUILTIN_INSWH, | |
6345 | ALPHA_BUILTIN_INSLH, | |
6346 | ALPHA_BUILTIN_INSQH, | |
6347 | ALPHA_BUILTIN_MSKBL, | |
6348 | ALPHA_BUILTIN_MSKWL, | |
6349 | ALPHA_BUILTIN_MSKLL, | |
6350 | ALPHA_BUILTIN_MSKQL, | |
6351 | ALPHA_BUILTIN_MSKWH, | |
6352 | ALPHA_BUILTIN_MSKLH, | |
6353 | ALPHA_BUILTIN_MSKQH, | |
6354 | ALPHA_BUILTIN_UMULH, | |
f2cc13dc | 6355 | ALPHA_BUILTIN_ZAP, |
6356 | ALPHA_BUILTIN_ZAPNOT, | |
6357 | ALPHA_BUILTIN_AMASK, | |
6358 | ALPHA_BUILTIN_IMPLVER, | |
6359 | ALPHA_BUILTIN_RPCC, | |
50f36bdb | 6360 | ALPHA_BUILTIN_ESTABLISH_VMS_CONDITION_HANDLER, |
6361 | ALPHA_BUILTIN_REVERT_VMS_CONDITION_HANDLER, | |
f2cc13dc | 6362 | |
6363 | /* TARGET_MAX */ | |
6364 | ALPHA_BUILTIN_MINUB8, | |
6365 | ALPHA_BUILTIN_MINSB8, | |
6366 | ALPHA_BUILTIN_MINUW4, | |
6367 | ALPHA_BUILTIN_MINSW4, | |
6368 | ALPHA_BUILTIN_MAXUB8, | |
6369 | ALPHA_BUILTIN_MAXSB8, | |
6370 | ALPHA_BUILTIN_MAXUW4, | |
6371 | ALPHA_BUILTIN_MAXSW4, | |
6372 | ALPHA_BUILTIN_PERR, | |
6373 | ALPHA_BUILTIN_PKLB, | |
6374 | ALPHA_BUILTIN_PKWB, | |
6375 | ALPHA_BUILTIN_UNPKBL, | |
6376 | ALPHA_BUILTIN_UNPKBW, | |
6377 | ||
ae4cd3a5 | 6378 | /* TARGET_CIX */ |
6379 | ALPHA_BUILTIN_CTTZ, | |
6380 | ALPHA_BUILTIN_CTLZ, | |
6381 | ALPHA_BUILTIN_CTPOP, | |
6382 | ||
f2cc13dc | 6383 | ALPHA_BUILTIN_max |
6384 | }; | |
6385 | ||
ff8e23a2 | 6386 | static enum insn_code const code_for_builtin[ALPHA_BUILTIN_max] = { |
ae4cd3a5 | 6387 | CODE_FOR_builtin_cmpbge, |
9bab4302 | 6388 | CODE_FOR_extbl, |
6389 | CODE_FOR_extwl, | |
6390 | CODE_FOR_extll, | |
6391 | CODE_FOR_extql, | |
6392 | CODE_FOR_extwh, | |
6393 | CODE_FOR_extlh, | |
6394 | CODE_FOR_extqh, | |
ae4cd3a5 | 6395 | CODE_FOR_builtin_insbl, |
6396 | CODE_FOR_builtin_inswl, | |
6397 | CODE_FOR_builtin_insll, | |
9bab4302 | 6398 | CODE_FOR_insql, |
6399 | CODE_FOR_inswh, | |
6400 | CODE_FOR_inslh, | |
6401 | CODE_FOR_insqh, | |
6402 | CODE_FOR_mskbl, | |
6403 | CODE_FOR_mskwl, | |
6404 | CODE_FOR_mskll, | |
6405 | CODE_FOR_mskql, | |
6406 | CODE_FOR_mskwh, | |
6407 | CODE_FOR_msklh, | |
6408 | CODE_FOR_mskqh, | |
ae4cd3a5 | 6409 | CODE_FOR_umuldi3_highpart, |
6410 | CODE_FOR_builtin_zap, | |
6411 | CODE_FOR_builtin_zapnot, | |
6412 | CODE_FOR_builtin_amask, | |
6413 | CODE_FOR_builtin_implver, | |
6414 | CODE_FOR_builtin_rpcc, | |
50f36bdb | 6415 | CODE_FOR_builtin_establish_vms_condition_handler, |
6416 | CODE_FOR_builtin_revert_vms_condition_handler, | |
ae4cd3a5 | 6417 | |
6418 | /* TARGET_MAX */ | |
6419 | CODE_FOR_builtin_minub8, | |
6420 | CODE_FOR_builtin_minsb8, | |
6421 | CODE_FOR_builtin_minuw4, | |
6422 | CODE_FOR_builtin_minsw4, | |
6423 | CODE_FOR_builtin_maxub8, | |
6424 | CODE_FOR_builtin_maxsb8, | |
6425 | CODE_FOR_builtin_maxuw4, | |
6426 | CODE_FOR_builtin_maxsw4, | |
6427 | CODE_FOR_builtin_perr, | |
6428 | CODE_FOR_builtin_pklb, | |
6429 | CODE_FOR_builtin_pkwb, | |
6430 | CODE_FOR_builtin_unpkbl, | |
6431 | CODE_FOR_builtin_unpkbw, | |
6432 | ||
6433 | /* TARGET_CIX */ | |
849c7bc6 | 6434 | CODE_FOR_ctzdi2, |
6435 | CODE_FOR_clzdi2, | |
6436 | CODE_FOR_popcountdi2 | |
ae4cd3a5 | 6437 | }; |
6438 | ||
f2cc13dc | 6439 | struct alpha_builtin_def |
6440 | { | |
6441 | const char *name; | |
6442 | enum alpha_builtin code; | |
6443 | unsigned int target_mask; | |
849c7bc6 | 6444 | bool is_const; |
f2cc13dc | 6445 | }; |
6446 | ||
6447 | static struct alpha_builtin_def const zero_arg_builtins[] = { | |
849c7bc6 | 6448 | { "__builtin_alpha_implver", ALPHA_BUILTIN_IMPLVER, 0, true }, |
6449 | { "__builtin_alpha_rpcc", ALPHA_BUILTIN_RPCC, 0, false } | |
f2cc13dc | 6450 | }; |
6451 | ||
6452 | static struct alpha_builtin_def const one_arg_builtins[] = { | |
849c7bc6 | 6453 | { "__builtin_alpha_amask", ALPHA_BUILTIN_AMASK, 0, true }, |
6454 | { "__builtin_alpha_pklb", ALPHA_BUILTIN_PKLB, MASK_MAX, true }, | |
6455 | { "__builtin_alpha_pkwb", ALPHA_BUILTIN_PKWB, MASK_MAX, true }, | |
6456 | { "__builtin_alpha_unpkbl", ALPHA_BUILTIN_UNPKBL, MASK_MAX, true }, | |
6457 | { "__builtin_alpha_unpkbw", ALPHA_BUILTIN_UNPKBW, MASK_MAX, true }, | |
6458 | { "__builtin_alpha_cttz", ALPHA_BUILTIN_CTTZ, MASK_CIX, true }, | |
6459 | { "__builtin_alpha_ctlz", ALPHA_BUILTIN_CTLZ, MASK_CIX, true }, | |
6460 | { "__builtin_alpha_ctpop", ALPHA_BUILTIN_CTPOP, MASK_CIX, true } | |
f2cc13dc | 6461 | }; |
6462 | ||
6463 | static struct alpha_builtin_def const two_arg_builtins[] = { | |
849c7bc6 | 6464 | { "__builtin_alpha_cmpbge", ALPHA_BUILTIN_CMPBGE, 0, true }, |
6465 | { "__builtin_alpha_extbl", ALPHA_BUILTIN_EXTBL, 0, true }, | |
6466 | { "__builtin_alpha_extwl", ALPHA_BUILTIN_EXTWL, 0, true }, | |
6467 | { "__builtin_alpha_extll", ALPHA_BUILTIN_EXTLL, 0, true }, | |
6468 | { "__builtin_alpha_extql", ALPHA_BUILTIN_EXTQL, 0, true }, | |
6469 | { "__builtin_alpha_extwh", ALPHA_BUILTIN_EXTWH, 0, true }, | |
6470 | { "__builtin_alpha_extlh", ALPHA_BUILTIN_EXTLH, 0, true }, | |
6471 | { "__builtin_alpha_extqh", ALPHA_BUILTIN_EXTQH, 0, true }, | |
6472 | { "__builtin_alpha_insbl", ALPHA_BUILTIN_INSBL, 0, true }, | |
6473 | { "__builtin_alpha_inswl", ALPHA_BUILTIN_INSWL, 0, true }, | |
6474 | { "__builtin_alpha_insll", ALPHA_BUILTIN_INSLL, 0, true }, | |
6475 | { "__builtin_alpha_insql", ALPHA_BUILTIN_INSQL, 0, true }, | |
6476 | { "__builtin_alpha_inswh", ALPHA_BUILTIN_INSWH, 0, true }, | |
6477 | { "__builtin_alpha_inslh", ALPHA_BUILTIN_INSLH, 0, true }, | |
6478 | { "__builtin_alpha_insqh", ALPHA_BUILTIN_INSQH, 0, true }, | |
6479 | { "__builtin_alpha_mskbl", ALPHA_BUILTIN_MSKBL, 0, true }, | |
6480 | { "__builtin_alpha_mskwl", ALPHA_BUILTIN_MSKWL, 0, true }, | |
6481 | { "__builtin_alpha_mskll", ALPHA_BUILTIN_MSKLL, 0, true }, | |
6482 | { "__builtin_alpha_mskql", ALPHA_BUILTIN_MSKQL, 0, true }, | |
6483 | { "__builtin_alpha_mskwh", ALPHA_BUILTIN_MSKWH, 0, true }, | |
6484 | { "__builtin_alpha_msklh", ALPHA_BUILTIN_MSKLH, 0, true }, | |
6485 | { "__builtin_alpha_mskqh", ALPHA_BUILTIN_MSKQH, 0, true }, | |
6486 | { "__builtin_alpha_umulh", ALPHA_BUILTIN_UMULH, 0, true }, | |
6487 | { "__builtin_alpha_zap", ALPHA_BUILTIN_ZAP, 0, true }, | |
6488 | { "__builtin_alpha_zapnot", ALPHA_BUILTIN_ZAPNOT, 0, true }, | |
6489 | { "__builtin_alpha_minub8", ALPHA_BUILTIN_MINUB8, MASK_MAX, true }, | |
6490 | { "__builtin_alpha_minsb8", ALPHA_BUILTIN_MINSB8, MASK_MAX, true }, | |
6491 | { "__builtin_alpha_minuw4", ALPHA_BUILTIN_MINUW4, MASK_MAX, true }, | |
6492 | { "__builtin_alpha_minsw4", ALPHA_BUILTIN_MINSW4, MASK_MAX, true }, | |
6493 | { "__builtin_alpha_maxub8", ALPHA_BUILTIN_MAXUB8, MASK_MAX, true }, | |
6494 | { "__builtin_alpha_maxsb8", ALPHA_BUILTIN_MAXSB8, MASK_MAX, true }, | |
6495 | { "__builtin_alpha_maxuw4", ALPHA_BUILTIN_MAXUW4, MASK_MAX, true }, | |
6496 | { "__builtin_alpha_maxsw4", ALPHA_BUILTIN_MAXSW4, MASK_MAX, true }, | |
6497 | { "__builtin_alpha_perr", ALPHA_BUILTIN_PERR, MASK_MAX, true } | |
f2cc13dc | 6498 | }; |
6499 | ||
21c2a8b2 | 6500 | static GTY(()) tree alpha_dimode_u; |
849c7bc6 | 6501 | static GTY(()) tree alpha_v8qi_u; |
6502 | static GTY(()) tree alpha_v8qi_s; | |
6503 | static GTY(()) tree alpha_v4hi_u; | |
6504 | static GTY(()) tree alpha_v4hi_s; | |
6505 | ||
bad4fb18 | 6506 | static GTY(()) tree alpha_builtins[(int) ALPHA_BUILTIN_max]; |
6507 | ||
6508 | /* Return the alpha builtin for CODE. */ | |
6509 | ||
6510 | static tree | |
6511 | alpha_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) | |
6512 | { | |
6513 | if (code >= ALPHA_BUILTIN_max) | |
6514 | return error_mark_node; | |
6515 | return alpha_builtins[code]; | |
6516 | } | |
6517 | ||
6518 | /* Helper function of alpha_init_builtins. Add the built-in specified | |
6519 | by NAME, TYPE, CODE, and ECF. */ | |
6520 | ||
6521 | static void | |
6522 | alpha_builtin_function (const char *name, tree ftype, | |
6523 | enum alpha_builtin code, unsigned ecf) | |
6524 | { | |
6525 | tree decl = add_builtin_function (name, ftype, (int) code, | |
6526 | BUILT_IN_MD, NULL, NULL_TREE); | |
6527 | ||
6528 | if (ecf & ECF_CONST) | |
6529 | TREE_READONLY (decl) = 1; | |
6530 | if (ecf & ECF_NOTHROW) | |
6531 | TREE_NOTHROW (decl) = 1; | |
6532 | ||
6533 | alpha_builtins [(int) code] = decl; | |
6534 | } | |
6535 | ||
b657e73a | 6536 | /* Helper function of alpha_init_builtins. Add the COUNT built-in |
6537 | functions pointed to by P, with function type FTYPE. */ | |
6538 | ||
6539 | static void | |
6540 | alpha_add_builtins (const struct alpha_builtin_def *p, size_t count, | |
6541 | tree ftype) | |
6542 | { | |
b657e73a | 6543 | size_t i; |
6544 | ||
6545 | for (i = 0; i < count; ++i, ++p) | |
6546 | if ((target_flags & p->target_mask) == p->target_mask) | |
bad4fb18 | 6547 | alpha_builtin_function (p->name, ftype, p->code, |
6548 | (p->is_const ? ECF_CONST : 0) | ECF_NOTHROW); | |
b657e73a | 6549 | } |
6550 | ||
f2cc13dc | 6551 | static void |
92643d95 | 6552 | alpha_init_builtins (void) |
f2cc13dc | 6553 | { |
bad4fb18 | 6554 | tree ftype; |
f2cc13dc | 6555 | |
21c2a8b2 | 6556 | alpha_dimode_u = lang_hooks.types.type_for_mode (DImode, 1); |
6557 | alpha_v8qi_u = build_vector_type (unsigned_intQI_type_node, 8); | |
6558 | alpha_v8qi_s = build_vector_type (intQI_type_node, 8); | |
6559 | alpha_v4hi_u = build_vector_type (unsigned_intHI_type_node, 4); | |
6560 | alpha_v4hi_s = build_vector_type (intHI_type_node, 4); | |
e2dc233c | 6561 | |
21c2a8b2 | 6562 | ftype = build_function_type_list (alpha_dimode_u, NULL_TREE); |
6563 | alpha_add_builtins (zero_arg_builtins, ARRAY_SIZE (zero_arg_builtins), ftype); | |
f2cc13dc | 6564 | |
21c2a8b2 | 6565 | ftype = build_function_type_list (alpha_dimode_u, alpha_dimode_u, NULL_TREE); |
6566 | alpha_add_builtins (one_arg_builtins, ARRAY_SIZE (one_arg_builtins), ftype); | |
f2cc13dc | 6567 | |
21c2a8b2 | 6568 | ftype = build_function_type_list (alpha_dimode_u, alpha_dimode_u, |
6569 | alpha_dimode_u, NULL_TREE); | |
6570 | alpha_add_builtins (two_arg_builtins, ARRAY_SIZE (two_arg_builtins), ftype); | |
938e069b | 6571 | |
50f36bdb | 6572 | if (TARGET_ABI_OPEN_VMS) |
6573 | { | |
6574 | ftype = build_function_type_list (ptr_type_node, ptr_type_node, | |
6575 | NULL_TREE); | |
bad4fb18 | 6576 | alpha_builtin_function ("__builtin_establish_vms_condition_handler", |
6577 | ftype, | |
6578 | ALPHA_BUILTIN_ESTABLISH_VMS_CONDITION_HANDLER, | |
6579 | 0); | |
50f36bdb | 6580 | |
6581 | ftype = build_function_type_list (ptr_type_node, void_type_node, | |
6582 | NULL_TREE); | |
bad4fb18 | 6583 | alpha_builtin_function ("__builtin_revert_vms_condition_handler", ftype, |
6584 | ALPHA_BUILTIN_REVERT_VMS_CONDITION_HANDLER, 0); | |
ded97e77 | 6585 | |
6586 | vms_patch_builtins (); | |
50f36bdb | 6587 | } |
f2cc13dc | 6588 | } |
6589 | ||
6590 | /* Expand an expression EXP that calls a built-in function, | |
6591 | with result going to TARGET if that's convenient | |
6592 | (and in mode MODE if that's convenient). | |
6593 | SUBTARGET may be used as the target for computing one of EXP's operands. | |
6594 | IGNORE is nonzero if the value is to be ignored. */ | |
6595 | ||
6596 | static rtx | |
92643d95 | 6597 | alpha_expand_builtin (tree exp, rtx target, |
6598 | rtx subtarget ATTRIBUTE_UNUSED, | |
3754d046 | 6599 | machine_mode mode ATTRIBUTE_UNUSED, |
92643d95 | 6600 | int ignore ATTRIBUTE_UNUSED) |
f2cc13dc | 6601 | { |
f2cc13dc | 6602 | #define MAX_ARGS 2 |
6603 | ||
c2f47e15 | 6604 | tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); |
f2cc13dc | 6605 | unsigned int fcode = DECL_FUNCTION_CODE (fndecl); |
c2f47e15 | 6606 | tree arg; |
6607 | call_expr_arg_iterator iter; | |
f2cc13dc | 6608 | enum insn_code icode; |
6609 | rtx op[MAX_ARGS], pat; | |
6610 | int arity; | |
938e069b | 6611 | bool nonvoid; |
f2cc13dc | 6612 | |
6613 | if (fcode >= ALPHA_BUILTIN_max) | |
6614 | internal_error ("bad builtin fcode"); | |
6615 | icode = code_for_builtin[fcode]; | |
6616 | if (icode == 0) | |
6617 | internal_error ("bad builtin fcode"); | |
6618 | ||
938e069b | 6619 | nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; |
6620 | ||
c2f47e15 | 6621 | arity = 0; |
6622 | FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) | |
f2cc13dc | 6623 | { |
6624 | const struct insn_operand_data *insn_op; | |
6625 | ||
f2cc13dc | 6626 | if (arg == error_mark_node) |
6627 | return NULL_RTX; | |
6628 | if (arity > MAX_ARGS) | |
6629 | return NULL_RTX; | |
6630 | ||
938e069b | 6631 | insn_op = &insn_data[icode].operand[arity + nonvoid]; |
6632 | ||
0a48089c | 6633 | op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL); |
f2cc13dc | 6634 | |
f2cc13dc | 6635 | if (!(*insn_op->predicate) (op[arity], insn_op->mode)) |
6636 | op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]); | |
c2f47e15 | 6637 | arity++; |
f2cc13dc | 6638 | } |
6639 | ||
938e069b | 6640 | if (nonvoid) |
6641 | { | |
3754d046 | 6642 | machine_mode tmode = insn_data[icode].operand[0].mode; |
938e069b | 6643 | if (!target |
6644 | || GET_MODE (target) != tmode | |
6645 | || !(*insn_data[icode].operand[0].predicate) (target, tmode)) | |
6646 | target = gen_reg_rtx (tmode); | |
6647 | } | |
f2cc13dc | 6648 | |
6649 | switch (arity) | |
6650 | { | |
6651 | case 0: | |
6652 | pat = GEN_FCN (icode) (target); | |
6653 | break; | |
6654 | case 1: | |
938e069b | 6655 | if (nonvoid) |
6656 | pat = GEN_FCN (icode) (target, op[0]); | |
6657 | else | |
6658 | pat = GEN_FCN (icode) (op[0]); | |
f2cc13dc | 6659 | break; |
6660 | case 2: | |
6661 | pat = GEN_FCN (icode) (target, op[0], op[1]); | |
6662 | break; | |
6663 | default: | |
4d10b463 | 6664 | gcc_unreachable (); |
f2cc13dc | 6665 | } |
6666 | if (!pat) | |
6667 | return NULL_RTX; | |
6668 | emit_insn (pat); | |
6669 | ||
938e069b | 6670 | if (nonvoid) |
6671 | return target; | |
6672 | else | |
6673 | return const0_rtx; | |
f2cc13dc | 6674 | } |
849c7bc6 | 6675 | |
849c7bc6 | 6676 | /* Fold the builtin for the CMPBGE instruction. This is a vector comparison |
85c36fd1 | 6677 | with an 8-bit output vector. OPINT contains the integer operands; bit N |
849c7bc6 | 6678 | of OP_CONST is set if OPINT[N] is valid. */ |
6679 | ||
6680 | static tree | |
6681 | alpha_fold_builtin_cmpbge (unsigned HOST_WIDE_INT opint[], long op_const) | |
6682 | { | |
6683 | if (op_const == 3) | |
6684 | { | |
6685 | int i, val; | |
6686 | for (i = 0, val = 0; i < 8; ++i) | |
6687 | { | |
6688 | unsigned HOST_WIDE_INT c0 = (opint[0] >> (i * 8)) & 0xff; | |
6689 | unsigned HOST_WIDE_INT c1 = (opint[1] >> (i * 8)) & 0xff; | |
6690 | if (c0 >= c1) | |
6691 | val |= 1 << i; | |
6692 | } | |
21c2a8b2 | 6693 | return build_int_cst (alpha_dimode_u, val); |
849c7bc6 | 6694 | } |
3def9653 | 6695 | else if (op_const == 2 && opint[1] == 0) |
21c2a8b2 | 6696 | return build_int_cst (alpha_dimode_u, 0xff); |
849c7bc6 | 6697 | return NULL; |
6698 | } | |
6699 | ||
6700 | /* Fold the builtin for the ZAPNOT instruction. This is essentially a | |
6701 | specialized form of an AND operation. Other byte manipulation instructions | |
6702 | are defined in terms of this instruction, so this is also used as a | |
6703 | subroutine for other builtins. | |
6704 | ||
6705 | OP contains the tree operands; OPINT contains the extracted integer values. | |
6706 | Bit N of OP_CONST it set if OPINT[N] is valid. OP may be null if only | |
6707 | OPINT may be considered. */ | |
6708 | ||
6709 | static tree | |
6710 | alpha_fold_builtin_zapnot (tree *op, unsigned HOST_WIDE_INT opint[], | |
6711 | long op_const) | |
6712 | { | |
6713 | if (op_const & 2) | |
6714 | { | |
6715 | unsigned HOST_WIDE_INT mask = 0; | |
6716 | int i; | |
6717 | ||
6718 | for (i = 0; i < 8; ++i) | |
6719 | if ((opint[1] >> i) & 1) | |
6720 | mask |= (unsigned HOST_WIDE_INT)0xff << (i * 8); | |
6721 | ||
6722 | if (op_const & 1) | |
21c2a8b2 | 6723 | return build_int_cst (alpha_dimode_u, opint[0] & mask); |
849c7bc6 | 6724 | |
6725 | if (op) | |
21c2a8b2 | 6726 | return fold_build2 (BIT_AND_EXPR, alpha_dimode_u, op[0], |
6727 | build_int_cst (alpha_dimode_u, mask)); | |
849c7bc6 | 6728 | } |
6729 | else if ((op_const & 1) && opint[0] == 0) | |
21c2a8b2 | 6730 | return build_int_cst (alpha_dimode_u, 0); |
849c7bc6 | 6731 | return NULL; |
6732 | } | |
6733 | ||
6734 | /* Fold the builtins for the EXT family of instructions. */ | |
6735 | ||
6736 | static tree | |
6737 | alpha_fold_builtin_extxx (tree op[], unsigned HOST_WIDE_INT opint[], | |
6738 | long op_const, unsigned HOST_WIDE_INT bytemask, | |
6739 | bool is_high) | |
6740 | { | |
6741 | long zap_const = 2; | |
6742 | tree *zap_op = NULL; | |
6743 | ||
6744 | if (op_const & 2) | |
6745 | { | |
6746 | unsigned HOST_WIDE_INT loc; | |
6747 | ||
6748 | loc = opint[1] & 7; | |
9bab4302 | 6749 | loc *= BITS_PER_UNIT; |
849c7bc6 | 6750 | |
6751 | if (loc != 0) | |
6752 | { | |
6753 | if (op_const & 1) | |
6754 | { | |
6755 | unsigned HOST_WIDE_INT temp = opint[0]; | |
6756 | if (is_high) | |
6757 | temp <<= loc; | |
6758 | else | |
6759 | temp >>= loc; | |
6760 | opint[0] = temp; | |
6761 | zap_const = 3; | |
6762 | } | |
6763 | } | |
6764 | else | |
6765 | zap_op = op; | |
6766 | } | |
6767 | ||
6768 | opint[1] = bytemask; | |
6769 | return alpha_fold_builtin_zapnot (zap_op, opint, zap_const); | |
6770 | } | |
6771 | ||
6772 | /* Fold the builtins for the INS family of instructions. */ | |
6773 | ||
6774 | static tree | |
6775 | alpha_fold_builtin_insxx (tree op[], unsigned HOST_WIDE_INT opint[], | |
6776 | long op_const, unsigned HOST_WIDE_INT bytemask, | |
6777 | bool is_high) | |
6778 | { | |
6779 | if ((op_const & 1) && opint[0] == 0) | |
21c2a8b2 | 6780 | return build_int_cst (alpha_dimode_u, 0); |
849c7bc6 | 6781 | |
6782 | if (op_const & 2) | |
6783 | { | |
6784 | unsigned HOST_WIDE_INT temp, loc, byteloc; | |
6785 | tree *zap_op = NULL; | |
6786 | ||
6787 | loc = opint[1] & 7; | |
849c7bc6 | 6788 | bytemask <<= loc; |
6789 | ||
6790 | temp = opint[0]; | |
6791 | if (is_high) | |
6792 | { | |
6793 | byteloc = (64 - (loc * 8)) & 0x3f; | |
6794 | if (byteloc == 0) | |
6795 | zap_op = op; | |
6796 | else | |
6797 | temp >>= byteloc; | |
6798 | bytemask >>= 8; | |
6799 | } | |
6800 | else | |
6801 | { | |
6802 | byteloc = loc * 8; | |
6803 | if (byteloc == 0) | |
6804 | zap_op = op; | |
6805 | else | |
6806 | temp <<= byteloc; | |
6807 | } | |
6808 | ||
6809 | opint[0] = temp; | |
6810 | opint[1] = bytemask; | |
6811 | return alpha_fold_builtin_zapnot (zap_op, opint, op_const); | |
6812 | } | |
6813 | ||
6814 | return NULL; | |
6815 | } | |
6816 | ||
6817 | static tree | |
6818 | alpha_fold_builtin_mskxx (tree op[], unsigned HOST_WIDE_INT opint[], | |
6819 | long op_const, unsigned HOST_WIDE_INT bytemask, | |
6820 | bool is_high) | |
6821 | { | |
6822 | if (op_const & 2) | |
6823 | { | |
6824 | unsigned HOST_WIDE_INT loc; | |
6825 | ||
6826 | loc = opint[1] & 7; | |
849c7bc6 | 6827 | bytemask <<= loc; |
6828 | ||
6829 | if (is_high) | |
6830 | bytemask >>= 8; | |
6831 | ||
6832 | opint[1] = bytemask ^ 0xff; | |
6833 | } | |
6834 | ||
6835 | return alpha_fold_builtin_zapnot (op, opint, op_const); | |
6836 | } | |
6837 | ||
849c7bc6 | 6838 | static tree |
6839 | alpha_fold_vector_minmax (enum tree_code code, tree op[], tree vtype) | |
6840 | { | |
6841 | tree op0 = fold_convert (vtype, op[0]); | |
6842 | tree op1 = fold_convert (vtype, op[1]); | |
b3da1868 | 6843 | tree val = fold_build2 (code, vtype, op0, op1); |
21c2a8b2 | 6844 | return fold_build1 (VIEW_CONVERT_EXPR, alpha_dimode_u, val); |
849c7bc6 | 6845 | } |
6846 | ||
6847 | static tree | |
6848 | alpha_fold_builtin_perr (unsigned HOST_WIDE_INT opint[], long op_const) | |
6849 | { | |
6850 | unsigned HOST_WIDE_INT temp = 0; | |
6851 | int i; | |
6852 | ||
6853 | if (op_const != 3) | |
6854 | return NULL; | |
6855 | ||
6856 | for (i = 0; i < 8; ++i) | |
6857 | { | |
6858 | unsigned HOST_WIDE_INT a = (opint[0] >> (i * 8)) & 0xff; | |
6859 | unsigned HOST_WIDE_INT b = (opint[1] >> (i * 8)) & 0xff; | |
6860 | if (a >= b) | |
6861 | temp += a - b; | |
6862 | else | |
6863 | temp += b - a; | |
6864 | } | |
6865 | ||
21c2a8b2 | 6866 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6867 | } |
6868 | ||
6869 | static tree | |
6870 | alpha_fold_builtin_pklb (unsigned HOST_WIDE_INT opint[], long op_const) | |
6871 | { | |
6872 | unsigned HOST_WIDE_INT temp; | |
6873 | ||
6874 | if (op_const == 0) | |
6875 | return NULL; | |
6876 | ||
6877 | temp = opint[0] & 0xff; | |
6878 | temp |= (opint[0] >> 24) & 0xff00; | |
6879 | ||
21c2a8b2 | 6880 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6881 | } |
6882 | ||
6883 | static tree | |
6884 | alpha_fold_builtin_pkwb (unsigned HOST_WIDE_INT opint[], long op_const) | |
6885 | { | |
6886 | unsigned HOST_WIDE_INT temp; | |
6887 | ||
6888 | if (op_const == 0) | |
6889 | return NULL; | |
6890 | ||
6891 | temp = opint[0] & 0xff; | |
6892 | temp |= (opint[0] >> 8) & 0xff00; | |
6893 | temp |= (opint[0] >> 16) & 0xff0000; | |
6894 | temp |= (opint[0] >> 24) & 0xff000000; | |
6895 | ||
21c2a8b2 | 6896 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6897 | } |
6898 | ||
6899 | static tree | |
6900 | alpha_fold_builtin_unpkbl (unsigned HOST_WIDE_INT opint[], long op_const) | |
6901 | { | |
6902 | unsigned HOST_WIDE_INT temp; | |
6903 | ||
6904 | if (op_const == 0) | |
6905 | return NULL; | |
6906 | ||
6907 | temp = opint[0] & 0xff; | |
6908 | temp |= (opint[0] & 0xff00) << 24; | |
6909 | ||
21c2a8b2 | 6910 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6911 | } |
6912 | ||
6913 | static tree | |
6914 | alpha_fold_builtin_unpkbw (unsigned HOST_WIDE_INT opint[], long op_const) | |
6915 | { | |
6916 | unsigned HOST_WIDE_INT temp; | |
6917 | ||
6918 | if (op_const == 0) | |
6919 | return NULL; | |
6920 | ||
6921 | temp = opint[0] & 0xff; | |
6922 | temp |= (opint[0] & 0x0000ff00) << 8; | |
6923 | temp |= (opint[0] & 0x00ff0000) << 16; | |
6924 | temp |= (opint[0] & 0xff000000) << 24; | |
6925 | ||
21c2a8b2 | 6926 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6927 | } |
6928 | ||
6929 | static tree | |
6930 | alpha_fold_builtin_cttz (unsigned HOST_WIDE_INT opint[], long op_const) | |
6931 | { | |
6932 | unsigned HOST_WIDE_INT temp; | |
6933 | ||
6934 | if (op_const == 0) | |
6935 | return NULL; | |
6936 | ||
6937 | if (opint[0] == 0) | |
6938 | temp = 64; | |
6939 | else | |
6940 | temp = exact_log2 (opint[0] & -opint[0]); | |
6941 | ||
21c2a8b2 | 6942 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6943 | } |
6944 | ||
6945 | static tree | |
6946 | alpha_fold_builtin_ctlz (unsigned HOST_WIDE_INT opint[], long op_const) | |
6947 | { | |
6948 | unsigned HOST_WIDE_INT temp; | |
6949 | ||
6950 | if (op_const == 0) | |
6951 | return NULL; | |
6952 | ||
6953 | if (opint[0] == 0) | |
6954 | temp = 64; | |
6955 | else | |
6956 | temp = 64 - floor_log2 (opint[0]) - 1; | |
6957 | ||
21c2a8b2 | 6958 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6959 | } |
6960 | ||
6961 | static tree | |
6962 | alpha_fold_builtin_ctpop (unsigned HOST_WIDE_INT opint[], long op_const) | |
6963 | { | |
6964 | unsigned HOST_WIDE_INT temp, op; | |
6965 | ||
6966 | if (op_const == 0) | |
6967 | return NULL; | |
6968 | ||
6969 | op = opint[0]; | |
6970 | temp = 0; | |
6971 | while (op) | |
6972 | temp++, op &= op - 1; | |
6973 | ||
21c2a8b2 | 6974 | return build_int_cst (alpha_dimode_u, temp); |
849c7bc6 | 6975 | } |
6976 | ||
6977 | /* Fold one of our builtin functions. */ | |
6978 | ||
6979 | static tree | |
97d67146 | 6980 | alpha_fold_builtin (tree fndecl, int n_args, tree *op, |
6981 | bool ignore ATTRIBUTE_UNUSED) | |
849c7bc6 | 6982 | { |
849c7bc6 | 6983 | unsigned HOST_WIDE_INT opint[MAX_ARGS]; |
432093e5 | 6984 | long op_const = 0; |
97d67146 | 6985 | int i; |
849c7bc6 | 6986 | |
21c2a8b2 | 6987 | if (n_args > MAX_ARGS) |
97d67146 | 6988 | return NULL; |
6989 | ||
6990 | for (i = 0; i < n_args; i++) | |
849c7bc6 | 6991 | { |
97d67146 | 6992 | tree arg = op[i]; |
849c7bc6 | 6993 | if (arg == error_mark_node) |
6994 | return NULL; | |
849c7bc6 | 6995 | |
97d67146 | 6996 | opint[i] = 0; |
849c7bc6 | 6997 | if (TREE_CODE (arg) == INTEGER_CST) |
6998 | { | |
97d67146 | 6999 | op_const |= 1L << i; |
7000 | opint[i] = int_cst_value (arg); | |
849c7bc6 | 7001 | } |
7002 | } | |
7003 | ||
7004 | switch (DECL_FUNCTION_CODE (fndecl)) | |
7005 | { | |
7006 | case ALPHA_BUILTIN_CMPBGE: | |
7007 | return alpha_fold_builtin_cmpbge (opint, op_const); | |
7008 | ||
7009 | case ALPHA_BUILTIN_EXTBL: | |
7010 | return alpha_fold_builtin_extxx (op, opint, op_const, 0x01, false); | |
7011 | case ALPHA_BUILTIN_EXTWL: | |
7012 | return alpha_fold_builtin_extxx (op, opint, op_const, 0x03, false); | |
7013 | case ALPHA_BUILTIN_EXTLL: | |
7014 | return alpha_fold_builtin_extxx (op, opint, op_const, 0x0f, false); | |
7015 | case ALPHA_BUILTIN_EXTQL: | |
7016 | return alpha_fold_builtin_extxx (op, opint, op_const, 0xff, false); | |
7017 | case ALPHA_BUILTIN_EXTWH: | |
7018 | return alpha_fold_builtin_extxx (op, opint, op_const, 0x03, true); | |
7019 | case ALPHA_BUILTIN_EXTLH: | |
7020 | return alpha_fold_builtin_extxx (op, opint, op_const, 0x0f, true); | |
7021 | case ALPHA_BUILTIN_EXTQH: | |
7022 | return alpha_fold_builtin_extxx (op, opint, op_const, 0xff, true); | |
7023 | ||
7024 | case ALPHA_BUILTIN_INSBL: | |
7025 | return alpha_fold_builtin_insxx (op, opint, op_const, 0x01, false); | |
7026 | case ALPHA_BUILTIN_INSWL: | |
7027 | return alpha_fold_builtin_insxx (op, opint, op_const, 0x03, false); | |
7028 | case ALPHA_BUILTIN_INSLL: | |
7029 | return alpha_fold_builtin_insxx (op, opint, op_const, 0x0f, false); | |
7030 | case ALPHA_BUILTIN_INSQL: | |
7031 | return alpha_fold_builtin_insxx (op, opint, op_const, 0xff, false); | |
7032 | case ALPHA_BUILTIN_INSWH: | |
7033 | return alpha_fold_builtin_insxx (op, opint, op_const, 0x03, true); | |
7034 | case ALPHA_BUILTIN_INSLH: | |
7035 | return alpha_fold_builtin_insxx (op, opint, op_const, 0x0f, true); | |
7036 | case ALPHA_BUILTIN_INSQH: | |
7037 | return alpha_fold_builtin_insxx (op, opint, op_const, 0xff, true); | |
7038 | ||
7039 | case ALPHA_BUILTIN_MSKBL: | |
7040 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0x01, false); | |
7041 | case ALPHA_BUILTIN_MSKWL: | |
7042 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0x03, false); | |
7043 | case ALPHA_BUILTIN_MSKLL: | |
7044 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0x0f, false); | |
7045 | case ALPHA_BUILTIN_MSKQL: | |
7046 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0xff, false); | |
7047 | case ALPHA_BUILTIN_MSKWH: | |
7048 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0x03, true); | |
7049 | case ALPHA_BUILTIN_MSKLH: | |
7050 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0x0f, true); | |
7051 | case ALPHA_BUILTIN_MSKQH: | |
7052 | return alpha_fold_builtin_mskxx (op, opint, op_const, 0xff, true); | |
7053 | ||
849c7bc6 | 7054 | case ALPHA_BUILTIN_ZAP: |
7055 | opint[1] ^= 0xff; | |
7056 | /* FALLTHRU */ | |
7057 | case ALPHA_BUILTIN_ZAPNOT: | |
7058 | return alpha_fold_builtin_zapnot (op, opint, op_const); | |
7059 | ||
7060 | case ALPHA_BUILTIN_MINUB8: | |
7061 | return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v8qi_u); | |
7062 | case ALPHA_BUILTIN_MINSB8: | |
7063 | return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v8qi_s); | |
7064 | case ALPHA_BUILTIN_MINUW4: | |
7065 | return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v4hi_u); | |
7066 | case ALPHA_BUILTIN_MINSW4: | |
7067 | return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v4hi_s); | |
7068 | case ALPHA_BUILTIN_MAXUB8: | |
7069 | return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v8qi_u); | |
7070 | case ALPHA_BUILTIN_MAXSB8: | |
7071 | return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v8qi_s); | |
7072 | case ALPHA_BUILTIN_MAXUW4: | |
7073 | return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v4hi_u); | |
7074 | case ALPHA_BUILTIN_MAXSW4: | |
7075 | return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v4hi_s); | |
7076 | ||
7077 | case ALPHA_BUILTIN_PERR: | |
7078 | return alpha_fold_builtin_perr (opint, op_const); | |
7079 | case ALPHA_BUILTIN_PKLB: | |
7080 | return alpha_fold_builtin_pklb (opint, op_const); | |
7081 | case ALPHA_BUILTIN_PKWB: | |
7082 | return alpha_fold_builtin_pkwb (opint, op_const); | |
7083 | case ALPHA_BUILTIN_UNPKBL: | |
7084 | return alpha_fold_builtin_unpkbl (opint, op_const); | |
7085 | case ALPHA_BUILTIN_UNPKBW: | |
7086 | return alpha_fold_builtin_unpkbw (opint, op_const); | |
7087 | ||
7088 | case ALPHA_BUILTIN_CTTZ: | |
7089 | return alpha_fold_builtin_cttz (opint, op_const); | |
7090 | case ALPHA_BUILTIN_CTLZ: | |
7091 | return alpha_fold_builtin_ctlz (opint, op_const); | |
7092 | case ALPHA_BUILTIN_CTPOP: | |
7093 | return alpha_fold_builtin_ctpop (opint, op_const); | |
7094 | ||
7095 | case ALPHA_BUILTIN_AMASK: | |
7096 | case ALPHA_BUILTIN_IMPLVER: | |
7097 | case ALPHA_BUILTIN_RPCC: | |
849c7bc6 | 7098 | /* None of these are foldable at compile-time. */ |
7099 | default: | |
7100 | return NULL; | |
7101 | } | |
7102 | } | |
e3825818 | 7103 | |
7104 | bool | |
7105 | alpha_gimple_fold_builtin (gimple_stmt_iterator *gsi) | |
7106 | { | |
7107 | bool changed = false; | |
7108 | gimple stmt = gsi_stmt (*gsi); | |
7109 | tree call = gimple_call_fn (stmt); | |
7110 | gimple new_stmt = NULL; | |
7111 | ||
7112 | if (call) | |
7113 | { | |
7114 | tree fndecl = gimple_call_fndecl (stmt); | |
7115 | ||
7116 | if (fndecl) | |
7117 | { | |
7118 | tree arg0, arg1; | |
7119 | ||
7120 | switch (DECL_FUNCTION_CODE (fndecl)) | |
7121 | { | |
7122 | case ALPHA_BUILTIN_UMULH: | |
7123 | arg0 = gimple_call_arg (stmt, 0); | |
7124 | arg1 = gimple_call_arg (stmt, 1); | |
7125 | ||
84d842ae | 7126 | new_stmt = gimple_build_assign (gimple_call_lhs (stmt), |
7127 | MULT_HIGHPART_EXPR, arg0, arg1); | |
e3825818 | 7128 | break; |
7129 | default: | |
7130 | break; | |
7131 | } | |
7132 | } | |
7133 | } | |
7134 | ||
7135 | if (new_stmt) | |
7136 | { | |
7137 | gsi_replace (gsi, new_stmt, true); | |
7138 | changed = true; | |
7139 | } | |
7140 | ||
7141 | return changed; | |
7142 | } | |
f2cc13dc | 7143 | \f |
bf2a98b3 | 7144 | /* This page contains routines that are used to determine what the function |
7145 | prologue and epilogue code will do and write them out. */ | |
7146 | ||
7147 | /* Compute the size of the save area in the stack. */ | |
7148 | ||
8df4a58b | 7149 | /* These variables are used for communication between the following functions. |
7150 | They indicate various things about the current function being compiled | |
7151 | that are used to tell what kind of prologue, epilogue and procedure | |
efee20da | 7152 | descriptor to generate. */ |
8df4a58b | 7153 | |
7154 | /* Nonzero if we need a stack procedure. */ | |
b19d7ab1 | 7155 | enum alpha_procedure_types {PT_NULL = 0, PT_REGISTER = 1, PT_STACK = 2}; |
7156 | static enum alpha_procedure_types alpha_procedure_type; | |
8df4a58b | 7157 | |
7158 | /* Register number (either FP or SP) that is used to unwind the frame. */ | |
b9a5aa8e | 7159 | static int vms_unwind_regno; |
8df4a58b | 7160 | |
7161 | /* Register number used to save FP. We need not have one for RA since | |
7162 | we don't modify it for register procedures. This is only defined | |
7163 | for register frame procedures. */ | |
b9a5aa8e | 7164 | static int vms_save_fp_regno; |
8df4a58b | 7165 | |
7166 | /* Register number used to reference objects off our PV. */ | |
b9a5aa8e | 7167 | static int vms_base_regno; |
8df4a58b | 7168 | |
2cf1388a | 7169 | /* Compute register masks for saved registers. */ |
8df4a58b | 7170 | |
7171 | static void | |
92643d95 | 7172 | alpha_sa_mask (unsigned long *imaskP, unsigned long *fmaskP) |
8df4a58b | 7173 | { |
7174 | unsigned long imask = 0; | |
7175 | unsigned long fmask = 0; | |
1f0ce6a6 | 7176 | unsigned int i; |
8df4a58b | 7177 | |
eaa112a0 | 7178 | /* When outputting a thunk, we don't have valid register life info, |
7179 | but assemble_start_function wants to output .frame and .mask | |
7180 | directives. */ | |
9247818a | 7181 | if (cfun->is_thunk) |
2cf1388a | 7182 | { |
961d6ddd | 7183 | *imaskP = 0; |
7184 | *fmaskP = 0; | |
7185 | return; | |
7186 | } | |
8df4a58b | 7187 | |
b19d7ab1 | 7188 | if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK) |
df7d0d23 | 7189 | imask |= (1UL << HARD_FRAME_POINTER_REGNUM); |
8df4a58b | 7190 | |
961d6ddd | 7191 | /* One for every register we have to save. */ |
7192 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
7193 | if (! fixed_regs[i] && ! call_used_regs[i] | |
04d75965 | 7194 | && df_regs_ever_live_p (i) && i != REG_RA) |
961d6ddd | 7195 | { |
7196 | if (i < 32) | |
df7d0d23 | 7197 | imask |= (1UL << i); |
961d6ddd | 7198 | else |
df7d0d23 | 7199 | fmask |= (1UL << (i - 32)); |
961d6ddd | 7200 | } |
7201 | ||
7202 | /* We need to restore these for the handler. */ | |
18d50ae6 | 7203 | if (crtl->calls_eh_return) |
c49ad9ef | 7204 | { |
7205 | for (i = 0; ; ++i) | |
7206 | { | |
7207 | unsigned regno = EH_RETURN_DATA_REGNO (i); | |
7208 | if (regno == INVALID_REGNUM) | |
7209 | break; | |
7210 | imask |= 1UL << regno; | |
7211 | } | |
c49ad9ef | 7212 | } |
9e7454d0 | 7213 | |
961d6ddd | 7214 | /* If any register spilled, then spill the return address also. */ |
7215 | /* ??? This is required by the Digital stack unwind specification | |
7216 | and isn't needed if we're doing Dwarf2 unwinding. */ | |
7217 | if (imask || fmask || alpha_ra_ever_killed ()) | |
df7d0d23 | 7218 | imask |= (1UL << REG_RA); |
b9a5aa8e | 7219 | |
8df4a58b | 7220 | *imaskP = imask; |
7221 | *fmaskP = fmask; | |
8df4a58b | 7222 | } |
7223 | ||
7224 | int | |
92643d95 | 7225 | alpha_sa_size (void) |
8df4a58b | 7226 | { |
5aae9d06 | 7227 | unsigned long mask[2]; |
8df4a58b | 7228 | int sa_size = 0; |
5aae9d06 | 7229 | int i, j; |
8df4a58b | 7230 | |
5aae9d06 | 7231 | alpha_sa_mask (&mask[0], &mask[1]); |
7232 | ||
04d75965 | 7233 | for (j = 0; j < 2; ++j) |
7234 | for (i = 0; i < 32; ++i) | |
7235 | if ((mask[j] >> i) & 1) | |
7236 | sa_size++; | |
9caef960 | 7237 | |
04d75965 | 7238 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7239 | { |
d3832055 | 7240 | /* Start with a stack procedure if we make any calls (REG_RA used), or |
7241 | need a frame pointer, with a register procedure if we otherwise need | |
7242 | at least a slot, and with a null procedure in other cases. */ | |
7243 | if ((mask[0] >> REG_RA) & 1 || frame_pointer_needed) | |
b19d7ab1 | 7244 | alpha_procedure_type = PT_STACK; |
7245 | else if (get_frame_size() != 0) | |
7246 | alpha_procedure_type = PT_REGISTER; | |
7247 | else | |
7248 | alpha_procedure_type = PT_NULL; | |
5aae9d06 | 7249 | |
2ab60bb1 | 7250 | /* Don't reserve space for saving FP & RA yet. Do that later after we've |
5aae9d06 | 7251 | made the final decision on stack procedure vs register procedure. */ |
b19d7ab1 | 7252 | if (alpha_procedure_type == PT_STACK) |
2ab60bb1 | 7253 | sa_size -= 2; |
b9a5aa8e | 7254 | |
7255 | /* Decide whether to refer to objects off our PV via FP or PV. | |
7256 | If we need FP for something else or if we receive a nonlocal | |
7257 | goto (which expects PV to contain the value), we must use PV. | |
7258 | Otherwise, start by assuming we can use FP. */ | |
b19d7ab1 | 7259 | |
7260 | vms_base_regno | |
7261 | = (frame_pointer_needed | |
18d50ae6 | 7262 | || cfun->has_nonlocal_label |
b19d7ab1 | 7263 | || alpha_procedure_type == PT_STACK |
abe32cce | 7264 | || crtl->outgoing_args_size) |
b19d7ab1 | 7265 | ? REG_PV : HARD_FRAME_POINTER_REGNUM; |
b9a5aa8e | 7266 | |
7267 | /* If we want to copy PV into FP, we need to find some register | |
7268 | in which to save FP. */ | |
7269 | ||
7270 | vms_save_fp_regno = -1; | |
7271 | if (vms_base_regno == HARD_FRAME_POINTER_REGNUM) | |
7272 | for (i = 0; i < 32; i++) | |
3072d30e | 7273 | if (! fixed_regs[i] && call_used_regs[i] && ! df_regs_ever_live_p (i)) |
b9a5aa8e | 7274 | vms_save_fp_regno = i; |
7275 | ||
50f36bdb | 7276 | /* A VMS condition handler requires a stack procedure in our |
7277 | implementation. (not required by the calling standard). */ | |
7278 | if ((vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER) | |
7279 | || cfun->machine->uses_condition_handler) | |
b19d7ab1 | 7280 | vms_base_regno = REG_PV, alpha_procedure_type = PT_STACK; |
7281 | else if (alpha_procedure_type == PT_NULL) | |
7282 | vms_base_regno = REG_PV; | |
b9a5aa8e | 7283 | |
7284 | /* Stack unwinding should be done via FP unless we use it for PV. */ | |
7285 | vms_unwind_regno = (vms_base_regno == REG_PV | |
7286 | ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); | |
7287 | ||
50f36bdb | 7288 | /* If this is a stack procedure, allow space for saving FP, RA and |
7289 | a condition handler slot if needed. */ | |
b19d7ab1 | 7290 | if (alpha_procedure_type == PT_STACK) |
50f36bdb | 7291 | sa_size += 2 + cfun->machine->uses_condition_handler; |
b9a5aa8e | 7292 | } |
7293 | else | |
7294 | { | |
b9a5aa8e | 7295 | /* Our size must be even (multiple of 16 bytes). */ |
7296 | if (sa_size & 1) | |
7297 | sa_size++; | |
7298 | } | |
8df4a58b | 7299 | |
7300 | return sa_size * 8; | |
7301 | } | |
7302 | ||
4310aa50 | 7303 | /* Define the offset between two registers, one to be eliminated, |
7304 | and the other its replacement, at the start of a routine. */ | |
7305 | ||
7306 | HOST_WIDE_INT | |
92643d95 | 7307 | alpha_initial_elimination_offset (unsigned int from, |
7308 | unsigned int to ATTRIBUTE_UNUSED) | |
4310aa50 | 7309 | { |
7310 | HOST_WIDE_INT ret; | |
7311 | ||
7312 | ret = alpha_sa_size (); | |
abe32cce | 7313 | ret += ALPHA_ROUND (crtl->outgoing_args_size); |
4310aa50 | 7314 | |
4d10b463 | 7315 | switch (from) |
7316 | { | |
7317 | case FRAME_POINTER_REGNUM: | |
7318 | break; | |
7319 | ||
7320 | case ARG_POINTER_REGNUM: | |
7321 | ret += (ALPHA_ROUND (get_frame_size () | |
abe32cce | 7322 | + crtl->args.pretend_args_size) |
7323 | - crtl->args.pretend_args_size); | |
4d10b463 | 7324 | break; |
7325 | ||
7326 | default: | |
7327 | gcc_unreachable (); | |
7328 | } | |
4310aa50 | 7329 | |
7330 | return ret; | |
7331 | } | |
7332 | ||
d3832055 | 7333 | #if TARGET_ABI_OPEN_VMS |
7334 | ||
cd90919d | 7335 | /* Worker function for TARGET_CAN_ELIMINATE. */ |
7336 | ||
7337 | static bool | |
7338 | alpha_vms_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) | |
8df4a58b | 7339 | { |
d3832055 | 7340 | /* We need the alpha_procedure_type to decide. Evaluate it now. */ |
8df4a58b | 7341 | alpha_sa_size (); |
d3832055 | 7342 | |
7343 | switch (alpha_procedure_type) | |
7344 | { | |
7345 | case PT_NULL: | |
7346 | /* NULL procedures have no frame of their own and we only | |
7347 | know how to resolve from the current stack pointer. */ | |
7348 | return to == STACK_POINTER_REGNUM; | |
7349 | ||
7350 | case PT_REGISTER: | |
7351 | case PT_STACK: | |
7352 | /* We always eliminate except to the stack pointer if there is no | |
7353 | usable frame pointer at hand. */ | |
7354 | return (to != STACK_POINTER_REGNUM | |
7355 | || vms_unwind_regno != HARD_FRAME_POINTER_REGNUM); | |
7356 | } | |
7357 | ||
7358 | gcc_unreachable (); | |
8df4a58b | 7359 | } |
7360 | ||
d3832055 | 7361 | /* FROM is to be eliminated for TO. Return the offset so that TO+offset |
7362 | designates the same location as FROM. */ | |
7363 | ||
7364 | HOST_WIDE_INT | |
7365 | alpha_vms_initial_elimination_offset (unsigned int from, unsigned int to) | |
7366 | { | |
7367 | /* The only possible attempts we ever expect are ARG or FRAME_PTR to | |
7368 | HARD_FRAME or STACK_PTR. We need the alpha_procedure_type to decide | |
7369 | on the proper computations and will need the register save area size | |
7370 | in most cases. */ | |
7371 | ||
7372 | HOST_WIDE_INT sa_size = alpha_sa_size (); | |
7373 | ||
7374 | /* PT_NULL procedures have no frame of their own and we only allow | |
7375 | elimination to the stack pointer. This is the argument pointer and we | |
7376 | resolve the soft frame pointer to that as well. */ | |
7377 | ||
7378 | if (alpha_procedure_type == PT_NULL) | |
7379 | return 0; | |
7380 | ||
7381 | /* For a PT_STACK procedure the frame layout looks as follows | |
7382 | ||
7383 | -----> decreasing addresses | |
7384 | ||
7385 | < size rounded up to 16 | likewise > | |
7386 | --------------#------------------------------+++--------------+++-------# | |
7387 | incoming args # pretended args | "frame" | regs sa | PV | outgoing args # | |
7388 | --------------#---------------------------------------------------------# | |
7389 | ^ ^ ^ ^ | |
7390 | ARG_PTR FRAME_PTR HARD_FRAME_PTR STACK_PTR | |
7391 | ||
7392 | ||
7393 | PT_REGISTER procedures are similar in that they may have a frame of their | |
7394 | own. They have no regs-sa/pv/outgoing-args area. | |
7395 | ||
7396 | We first compute offset to HARD_FRAME_PTR, then add what we need to get | |
7397 | to STACK_PTR if need be. */ | |
7398 | ||
7399 | { | |
7400 | HOST_WIDE_INT offset; | |
7401 | HOST_WIDE_INT pv_save_size = alpha_procedure_type == PT_STACK ? 8 : 0; | |
7402 | ||
7403 | switch (from) | |
7404 | { | |
7405 | case FRAME_POINTER_REGNUM: | |
7406 | offset = ALPHA_ROUND (sa_size + pv_save_size); | |
7407 | break; | |
7408 | case ARG_POINTER_REGNUM: | |
7409 | offset = (ALPHA_ROUND (sa_size + pv_save_size | |
7410 | + get_frame_size () | |
7411 | + crtl->args.pretend_args_size) | |
7412 | - crtl->args.pretend_args_size); | |
7413 | break; | |
7414 | default: | |
7415 | gcc_unreachable (); | |
7416 | } | |
7417 | ||
7418 | if (to == STACK_POINTER_REGNUM) | |
7419 | offset += ALPHA_ROUND (crtl->outgoing_args_size); | |
7420 | ||
7421 | return offset; | |
7422 | } | |
8df4a58b | 7423 | } |
7424 | ||
00dca3d4 | 7425 | #define COMMON_OBJECT "common_object" |
7426 | ||
7427 | static tree | |
7428 | common_object_handler (tree *node, tree name ATTRIBUTE_UNUSED, | |
7429 | tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, | |
7430 | bool *no_add_attrs ATTRIBUTE_UNUSED) | |
7431 | { | |
7432 | tree decl = *node; | |
7433 | gcc_assert (DECL_P (decl)); | |
7434 | ||
7435 | DECL_COMMON (decl) = 1; | |
7436 | return NULL_TREE; | |
7437 | } | |
2d280039 | 7438 | |
cd819d2f | 7439 | static const struct attribute_spec vms_attribute_table[] = |
bf2a98b3 | 7440 | { |
ac86af5d | 7441 | /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, |
7442 | affects_type_identity } */ | |
7443 | { COMMON_OBJECT, 0, 1, true, false, false, common_object_handler, false }, | |
7444 | { NULL, 0, 0, false, false, false, NULL, false } | |
e3c541f0 | 7445 | }; |
bf2a98b3 | 7446 | |
00dca3d4 | 7447 | void |
7448 | vms_output_aligned_decl_common(FILE *file, tree decl, const char *name, | |
7449 | unsigned HOST_WIDE_INT size, | |
7450 | unsigned int align) | |
7451 | { | |
7452 | tree attr = DECL_ATTRIBUTES (decl); | |
7453 | fprintf (file, "%s", COMMON_ASM_OP); | |
7454 | assemble_name (file, name); | |
7455 | fprintf (file, "," HOST_WIDE_INT_PRINT_UNSIGNED, size); | |
7456 | /* ??? Unlike on OSF/1, the alignment factor is not in log units. */ | |
7457 | fprintf (file, ",%u", align / BITS_PER_UNIT); | |
7458 | if (attr) | |
7459 | { | |
7460 | attr = lookup_attribute (COMMON_OBJECT, attr); | |
7461 | if (attr) | |
7462 | fprintf (file, ",%s", | |
7463 | IDENTIFIER_POINTER (TREE_VALUE (TREE_VALUE (attr)))); | |
7464 | } | |
7465 | fputc ('\n', file); | |
7466 | } | |
7467 | ||
7468 | #undef COMMON_OBJECT | |
7469 | ||
2d280039 | 7470 | #endif |
7471 | ||
fe508bee | 7472 | bool |
92643d95 | 7473 | alpha_find_lo_sum_using_gp (rtx insn) |
a3859c0f | 7474 | { |
fe508bee | 7475 | subrtx_iterator::array_type array; |
7476 | FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST) | |
7477 | { | |
7478 | const_rtx x = *iter; | |
7479 | if (GET_CODE (x) == LO_SUM && XEXP (x, 0) == pic_offset_table_rtx) | |
7480 | return true; | |
7481 | } | |
7482 | return false; | |
1f0ce6a6 | 7483 | } |
7484 | ||
b9a5aa8e | 7485 | static int |
92643d95 | 7486 | alpha_does_function_need_gp (void) |
b9a5aa8e | 7487 | { |
7f0256ea | 7488 | rtx_insn *insn; |
bf2a98b3 | 7489 | |
9caef960 | 7490 | /* The GP being variable is an OSF abi thing. */ |
7491 | if (! TARGET_ABI_OSF) | |
b9a5aa8e | 7492 | return 0; |
bf2a98b3 | 7493 | |
008fdc59 | 7494 | /* We need the gp to load the address of __mcount. */ |
18d50ae6 | 7495 | if (TARGET_PROFILING_NEEDS_GP && crtl->profile) |
b9a5aa8e | 7496 | return 1; |
0e0a0e7a | 7497 | |
008fdc59 | 7498 | /* The code emitted by alpha_output_mi_thunk_osf uses the gp. */ |
9247818a | 7499 | if (cfun->is_thunk) |
2cf1388a | 7500 | return 1; |
2cf1388a | 7501 | |
008fdc59 | 7502 | /* The nonlocal receiver pattern assumes that the gp is valid for |
7503 | the nested function. Reasonable because it's almost always set | |
7504 | correctly already. For the cases where that's wrong, make sure | |
7505 | the nested function loads its gp on entry. */ | |
18d50ae6 | 7506 | if (crtl->has_nonlocal_goto) |
008fdc59 | 7507 | return 1; |
7508 | ||
9e7454d0 | 7509 | /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first. |
b9a5aa8e | 7510 | Even if we are a static function, we still need to do this in case |
7511 | our address is taken and passed to something like qsort. */ | |
bf2a98b3 | 7512 | |
b9a5aa8e | 7513 | push_topmost_sequence (); |
7514 | insn = get_insns (); | |
7515 | pop_topmost_sequence (); | |
8df4a58b | 7516 | |
b9a5aa8e | 7517 | for (; insn; insn = NEXT_INSN (insn)) |
30608852 | 7518 | if (NONDEBUG_INSN_P (insn) |
b9a5aa8e | 7519 | && GET_CODE (PATTERN (insn)) != USE |
a3859c0f | 7520 | && GET_CODE (PATTERN (insn)) != CLOBBER |
7521 | && get_attr_usegp (insn)) | |
7522 | return 1; | |
bf2a98b3 | 7523 | |
b9a5aa8e | 7524 | return 0; |
bf2a98b3 | 7525 | } |
7526 | ||
7d73bc2a | 7527 | \f |
5a965225 | 7528 | /* Helper function to set RTX_FRAME_RELATED_P on instructions, including |
7529 | sequences. */ | |
7530 | ||
7f0256ea | 7531 | static rtx_insn * |
92643d95 | 7532 | set_frame_related_p (void) |
5a965225 | 7533 | { |
7f0256ea | 7534 | rtx_insn *seq = get_insns (); |
7535 | rtx_insn *insn; | |
31d3e01c | 7536 | |
5a965225 | 7537 | end_sequence (); |
7538 | ||
31d3e01c | 7539 | if (!seq) |
7f0256ea | 7540 | return NULL; |
31d3e01c | 7541 | |
7542 | if (INSN_P (seq)) | |
5a965225 | 7543 | { |
31d3e01c | 7544 | insn = seq; |
7545 | while (insn != NULL_RTX) | |
7546 | { | |
7547 | RTX_FRAME_RELATED_P (insn) = 1; | |
7548 | insn = NEXT_INSN (insn); | |
7549 | } | |
7550 | seq = emit_insn (seq); | |
5a965225 | 7551 | } |
7552 | else | |
7553 | { | |
7554 | seq = emit_insn (seq); | |
7555 | RTX_FRAME_RELATED_P (seq) = 1; | |
5a965225 | 7556 | } |
31d3e01c | 7557 | return seq; |
5a965225 | 7558 | } |
7559 | ||
7560 | #define FRP(exp) (start_sequence (), exp, set_frame_related_p ()) | |
7561 | ||
fb0de38e | 7562 | /* Generates a store with the proper unwind info attached. VALUE is |
183f1993 | 7563 | stored at BASE_REG+BASE_OFS. If FRAME_BIAS is nonzero, then BASE_REG |
fb0de38e | 7564 | contains SP+FRAME_BIAS, and that is the unwind info that should be |
7565 | generated. If FRAME_REG != VALUE, then VALUE is being stored on | |
7566 | behalf of FRAME_REG, and FRAME_REG should be present in the unwind. */ | |
7567 | ||
7568 | static void | |
7569 | emit_frame_store_1 (rtx value, rtx base_reg, HOST_WIDE_INT frame_bias, | |
7570 | HOST_WIDE_INT base_ofs, rtx frame_reg) | |
7571 | { | |
7f0256ea | 7572 | rtx addr, mem; |
7573 | rtx_insn *insn; | |
fb0de38e | 7574 | |
29c05e22 | 7575 | addr = plus_constant (Pmode, base_reg, base_ofs); |
656e2b9d | 7576 | mem = gen_frame_mem (DImode, addr); |
fb0de38e | 7577 | |
7578 | insn = emit_move_insn (mem, value); | |
7579 | RTX_FRAME_RELATED_P (insn) = 1; | |
7580 | ||
7581 | if (frame_bias || value != frame_reg) | |
7582 | { | |
7583 | if (frame_bias) | |
7584 | { | |
29c05e22 | 7585 | addr = plus_constant (Pmode, stack_pointer_rtx, |
7586 | frame_bias + base_ofs); | |
fb0de38e | 7587 | mem = gen_rtx_MEM (DImode, addr); |
7588 | } | |
7589 | ||
0a48089c | 7590 | add_reg_note (insn, REG_FRAME_RELATED_EXPR, |
d1f9b275 | 7591 | gen_rtx_SET (mem, frame_reg)); |
fb0de38e | 7592 | } |
7593 | } | |
7594 | ||
7595 | static void | |
7596 | emit_frame_store (unsigned int regno, rtx base_reg, | |
7597 | HOST_WIDE_INT frame_bias, HOST_WIDE_INT base_ofs) | |
7598 | { | |
7599 | rtx reg = gen_rtx_REG (DImode, regno); | |
7600 | emit_frame_store_1 (reg, base_reg, frame_bias, base_ofs, reg); | |
7601 | } | |
7602 | ||
990495a7 | 7603 | /* Compute the frame size. SIZE is the size of the "naked" frame |
7604 | and SA_SIZE is the size of the register save area. */ | |
7605 | ||
7606 | static HOST_WIDE_INT | |
7607 | compute_frame_size (HOST_WIDE_INT size, HOST_WIDE_INT sa_size) | |
7608 | { | |
7609 | if (TARGET_ABI_OPEN_VMS) | |
7610 | return ALPHA_ROUND (sa_size | |
7611 | + (alpha_procedure_type == PT_STACK ? 8 : 0) | |
7612 | + size | |
7613 | + crtl->args.pretend_args_size); | |
990495a7 | 7614 | else |
7615 | return ALPHA_ROUND (crtl->outgoing_args_size) | |
7616 | + sa_size | |
7617 | + ALPHA_ROUND (size | |
7618 | + crtl->args.pretend_args_size); | |
7619 | } | |
7620 | ||
bf2a98b3 | 7621 | /* Write function prologue. */ |
7622 | ||
8df4a58b | 7623 | /* On vms we have two kinds of functions: |
7624 | ||
7625 | - stack frame (PROC_STACK) | |
7626 | these are 'normal' functions with local vars and which are | |
7627 | calling other functions | |
7628 | - register frame (PROC_REGISTER) | |
7629 | keeps all data in registers, needs no stack | |
7630 | ||
7631 | We must pass this to the assembler so it can generate the | |
7632 | proper pdsc (procedure descriptor) | |
7633 | This is done with the '.pdesc' command. | |
7634 | ||
b9a5aa8e | 7635 | On not-vms, we don't really differentiate between the two, as we can |
7636 | simply allocate stack without saving registers. */ | |
8df4a58b | 7637 | |
7638 | void | |
92643d95 | 7639 | alpha_expand_prologue (void) |
8df4a58b | 7640 | { |
b9a5aa8e | 7641 | /* Registers to save. */ |
8df4a58b | 7642 | unsigned long imask = 0; |
7643 | unsigned long fmask = 0; | |
7644 | /* Stack space needed for pushing registers clobbered by us. */ | |
04d75965 | 7645 | HOST_WIDE_INT sa_size, sa_bias; |
8df4a58b | 7646 | /* Complete stack size needed. */ |
7647 | HOST_WIDE_INT frame_size; | |
e1f9b4f8 | 7648 | /* Probed stack size; it additionally includes the size of |
7649 | the "reserve region" if any. */ | |
7650 | HOST_WIDE_INT probed_size; | |
8df4a58b | 7651 | /* Offset from base reg to register save area. */ |
b9a5aa8e | 7652 | HOST_WIDE_INT reg_offset; |
fb0de38e | 7653 | rtx sa_reg; |
8df4a58b | 7654 | int i; |
7655 | ||
7656 | sa_size = alpha_sa_size (); | |
990495a7 | 7657 | frame_size = compute_frame_size (get_frame_size (), sa_size); |
8df4a58b | 7658 | |
8c0dd614 | 7659 | if (flag_stack_usage_info) |
990495a7 | 7660 | current_function_static_stack_size = frame_size; |
8df4a58b | 7661 | |
1467e953 | 7662 | if (TARGET_ABI_OPEN_VMS) |
50f36bdb | 7663 | reg_offset = 8 + 8 * cfun->machine->uses_condition_handler; |
b9a5aa8e | 7664 | else |
abe32cce | 7665 | reg_offset = ALPHA_ROUND (crtl->outgoing_args_size); |
8df4a58b | 7666 | |
b9a5aa8e | 7667 | alpha_sa_mask (&imask, &fmask); |
8df4a58b | 7668 | |
a314eb5e | 7669 | /* Emit an insn to reload GP, if needed. */ |
1467e953 | 7670 | if (TARGET_ABI_OSF) |
a314eb5e | 7671 | { |
7672 | alpha_function_needs_gp = alpha_does_function_need_gp (); | |
7673 | if (alpha_function_needs_gp) | |
7674 | emit_insn (gen_prologue_ldgp ()); | |
7675 | } | |
7676 | ||
30dceb30 | 7677 | /* TARGET_PROFILING_NEEDS_GP actually implies that we need to insert |
7678 | the call to mcount ourselves, rather than having the linker do it | |
7679 | magically in response to -pg. Since _mcount has special linkage, | |
7680 | don't represent the call as a call. */ | |
18d50ae6 | 7681 | if (TARGET_PROFILING_NEEDS_GP && crtl->profile) |
30dceb30 | 7682 | emit_insn (gen_prologue_mcount ()); |
9caef960 | 7683 | |
8df4a58b | 7684 | /* Adjust the stack by the frame size. If the frame size is > 4096 |
7685 | bytes, we need to be sure we probe somewhere in the first and last | |
7686 | 4096 bytes (we can probably get away without the latter test) and | |
7687 | every 8192 bytes in between. If the frame size is > 32768, we | |
7688 | do this in a loop. Otherwise, we generate the explicit probe | |
9e7454d0 | 7689 | instructions. |
8df4a58b | 7690 | |
7691 | Note that we are only allowed to adjust sp once in the prologue. */ | |
7692 | ||
e1f9b4f8 | 7693 | probed_size = frame_size; |
7694 | if (flag_stack_check) | |
7695 | probed_size += STACK_CHECK_PROTECT; | |
7696 | ||
7697 | if (probed_size <= 32768) | |
8df4a58b | 7698 | { |
e1f9b4f8 | 7699 | if (probed_size > 4096) |
8df4a58b | 7700 | { |
baf8b2cc | 7701 | int probed; |
8df4a58b | 7702 | |
e1f9b4f8 | 7703 | for (probed = 4096; probed < probed_size; probed += 8192) |
04d75965 | 7704 | emit_insn (gen_probe_stack (GEN_INT (-probed))); |
8df4a58b | 7705 | |
e1f9b4f8 | 7706 | /* We only have to do this probe if we aren't saving registers or |
7707 | if we are probing beyond the frame because of -fstack-check. */ | |
7708 | if ((sa_size == 0 && probed_size > probed - 4096) | |
7709 | || flag_stack_check) | |
7710 | emit_insn (gen_probe_stack (GEN_INT (-probed_size))); | |
8df4a58b | 7711 | } |
7712 | ||
7713 | if (frame_size != 0) | |
205b281f | 7714 | FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, |
04d75965 | 7715 | GEN_INT (-frame_size)))); |
8df4a58b | 7716 | } |
7717 | else | |
7718 | { | |
b9a5aa8e | 7719 | /* Here we generate code to set R22 to SP + 4096 and set R23 to the |
8df4a58b | 7720 | number of 8192 byte blocks to probe. We then probe each block |
7721 | in the loop and then set SP to the proper location. If the | |
7722 | amount remaining is > 4096, we have to do one more probe if we | |
e1f9b4f8 | 7723 | are not saving any registers or if we are probing beyond the |
7724 | frame because of -fstack-check. */ | |
8df4a58b | 7725 | |
e1f9b4f8 | 7726 | HOST_WIDE_INT blocks = (probed_size + 4096) / 8192; |
7727 | HOST_WIDE_INT leftover = probed_size + 4096 - blocks * 8192; | |
b9a5aa8e | 7728 | rtx ptr = gen_rtx_REG (DImode, 22); |
7729 | rtx count = gen_rtx_REG (DImode, 23); | |
cd28cb76 | 7730 | rtx seq; |
8df4a58b | 7731 | |
b9a5aa8e | 7732 | emit_move_insn (count, GEN_INT (blocks)); |
04d75965 | 7733 | emit_insn (gen_adddi3 (ptr, stack_pointer_rtx, GEN_INT (4096))); |
8df4a58b | 7734 | |
b9a5aa8e | 7735 | /* Because of the difficulty in emitting a new basic block this |
7736 | late in the compilation, generate the loop as a single insn. */ | |
7737 | emit_insn (gen_prologue_stack_probe_loop (count, ptr)); | |
8df4a58b | 7738 | |
e1f9b4f8 | 7739 | if ((leftover > 4096 && sa_size == 0) || flag_stack_check) |
b9a5aa8e | 7740 | { |
29c05e22 | 7741 | rtx last = gen_rtx_MEM (DImode, |
7742 | plus_constant (Pmode, ptr, -leftover)); | |
b9a5aa8e | 7743 | MEM_VOLATILE_P (last) = 1; |
7744 | emit_move_insn (last, const0_rtx); | |
7745 | } | |
8df4a58b | 7746 | |
1b803a4f | 7747 | if (flag_stack_check) |
f88f2646 | 7748 | { |
1b803a4f | 7749 | /* If -fstack-check is specified we have to load the entire |
7750 | constant into a register and subtract from the sp in one go, | |
7751 | because the probed stack size is not equal to the frame size. */ | |
f88f2646 | 7752 | HOST_WIDE_INT lo, hi; |
05bea6dd | 7753 | lo = ((frame_size & 0xffff) ^ 0x8000) - 0x8000; |
7754 | hi = frame_size - lo; | |
5a965225 | 7755 | |
cd28cb76 | 7756 | emit_move_insn (ptr, GEN_INT (hi)); |
df9e12ce | 7757 | emit_insn (gen_adddi3 (ptr, ptr, GEN_INT (lo))); |
cd28cb76 | 7758 | seq = emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, |
7759 | ptr)); | |
f88f2646 | 7760 | } |
7761 | else | |
7762 | { | |
f88f2646 | 7763 | seq = emit_insn (gen_adddi3 (stack_pointer_rtx, ptr, |
7764 | GEN_INT (-leftover))); | |
f88f2646 | 7765 | } |
cd28cb76 | 7766 | |
7767 | /* This alternative is special, because the DWARF code cannot | |
7768 | possibly intuit through the loop above. So we invent this | |
7769 | note it looks at instead. */ | |
7770 | RTX_FRAME_RELATED_P (seq) = 1; | |
0a48089c | 7771 | add_reg_note (seq, REG_FRAME_RELATED_EXPR, |
d1f9b275 | 7772 | gen_rtx_SET (stack_pointer_rtx, |
29c05e22 | 7773 | plus_constant (Pmode, stack_pointer_rtx, |
04d75965 | 7774 | -frame_size))); |
8df4a58b | 7775 | } |
7776 | ||
04d75965 | 7777 | /* Cope with very large offsets to the register save area. */ |
7778 | sa_bias = 0; | |
7779 | sa_reg = stack_pointer_rtx; | |
7780 | if (reg_offset + sa_size > 0x8000) | |
8df4a58b | 7781 | { |
04d75965 | 7782 | int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000; |
7783 | rtx sa_bias_rtx; | |
8df4a58b | 7784 | |
04d75965 | 7785 | if (low + sa_size <= 0x8000) |
7786 | sa_bias = reg_offset - low, reg_offset = low; | |
7787 | else | |
7788 | sa_bias = reg_offset, reg_offset = 0; | |
9e7454d0 | 7789 | |
04d75965 | 7790 | sa_reg = gen_rtx_REG (DImode, 24); |
7791 | sa_bias_rtx = GEN_INT (sa_bias); | |
8df4a58b | 7792 | |
04d75965 | 7793 | if (add_operand (sa_bias_rtx, DImode)) |
7794 | emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, sa_bias_rtx)); | |
7795 | else | |
9caef960 | 7796 | { |
04d75965 | 7797 | emit_move_insn (sa_reg, sa_bias_rtx); |
7798 | emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, sa_reg)); | |
9caef960 | 7799 | } |
04d75965 | 7800 | } |
8df4a58b | 7801 | |
04d75965 | 7802 | /* Save regs in stack order. Beginning with VMS PV. */ |
7803 | if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK) | |
7804 | emit_frame_store (REG_PV, stack_pointer_rtx, 0, 0); | |
8df4a58b | 7805 | |
04d75965 | 7806 | /* Save register RA next. */ |
7807 | if (imask & (1UL << REG_RA)) | |
9caef960 | 7808 | { |
04d75965 | 7809 | emit_frame_store (REG_RA, sa_reg, sa_bias, reg_offset); |
7810 | imask &= ~(1UL << REG_RA); | |
7811 | reg_offset += 8; | |
9caef960 | 7812 | } |
8df4a58b | 7813 | |
04d75965 | 7814 | /* Now save any other registers required to be saved. */ |
7815 | for (i = 0; i < 31; i++) | |
7816 | if (imask & (1UL << i)) | |
7817 | { | |
7818 | emit_frame_store (i, sa_reg, sa_bias, reg_offset); | |
7819 | reg_offset += 8; | |
7820 | } | |
7821 | ||
7822 | for (i = 0; i < 31; i++) | |
7823 | if (fmask & (1UL << i)) | |
7824 | { | |
7825 | emit_frame_store (i+32, sa_reg, sa_bias, reg_offset); | |
7826 | reg_offset += 8; | |
7827 | } | |
7828 | ||
1467e953 | 7829 | if (TARGET_ABI_OPEN_VMS) |
8df4a58b | 7830 | { |
d30e4246 | 7831 | /* Register frame procedures save the fp. */ |
b19d7ab1 | 7832 | if (alpha_procedure_type == PT_REGISTER) |
d30e4246 | 7833 | { |
7f0256ea | 7834 | rtx_insn *insn = |
7835 | emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno), | |
7836 | hard_frame_pointer_rtx); | |
d30e4246 | 7837 | add_reg_note (insn, REG_CFA_REGISTER, NULL); |
7838 | RTX_FRAME_RELATED_P (insn) = 1; | |
7839 | } | |
8df4a58b | 7840 | |
b19d7ab1 | 7841 | if (alpha_procedure_type != PT_NULL && vms_base_regno != REG_PV) |
6d50e356 | 7842 | emit_insn (gen_force_movdi (gen_rtx_REG (DImode, vms_base_regno), |
7843 | gen_rtx_REG (DImode, REG_PV))); | |
8df4a58b | 7844 | |
b19d7ab1 | 7845 | if (alpha_procedure_type != PT_NULL |
7846 | && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM) | |
205b281f | 7847 | FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); |
8df4a58b | 7848 | |
b9a5aa8e | 7849 | /* If we have to allocate space for outgoing args, do it now. */ |
abe32cce | 7850 | if (crtl->outgoing_args_size != 0) |
81a5b286 | 7851 | { |
7f0256ea | 7852 | rtx_insn *seq |
9e7454d0 | 7853 | = emit_move_insn (stack_pointer_rtx, |
81a5b286 | 7854 | plus_constant |
29c05e22 | 7855 | (Pmode, hard_frame_pointer_rtx, |
81a5b286 | 7856 | - (ALPHA_ROUND |
abe32cce | 7857 | (crtl->outgoing_args_size)))); |
9e7454d0 | 7858 | |
81a5b286 | 7859 | /* Only set FRAME_RELATED_P on the stack adjustment we just emitted |
7860 | if ! frame_pointer_needed. Setting the bit will change the CFA | |
7861 | computation rule to use sp again, which would be wrong if we had | |
7862 | frame_pointer_needed, as this means sp might move unpredictably | |
7863 | later on. | |
7864 | ||
7865 | Also, note that | |
7866 | frame_pointer_needed | |
7867 | => vms_unwind_regno == HARD_FRAME_POINTER_REGNUM | |
7868 | and | |
abe32cce | 7869 | crtl->outgoing_args_size != 0 |
81a5b286 | 7870 | => alpha_procedure_type != PT_NULL, |
7871 | ||
7872 | so when we are not setting the bit here, we are guaranteed to | |
5910bb95 | 7873 | have emitted an FRP frame pointer update just before. */ |
81a5b286 | 7874 | RTX_FRAME_RELATED_P (seq) = ! frame_pointer_needed; |
7875 | } | |
b9a5aa8e | 7876 | } |
04d75965 | 7877 | else |
b9a5aa8e | 7878 | { |
7879 | /* If we need a frame pointer, set it from the stack pointer. */ | |
7880 | if (frame_pointer_needed) | |
7881 | { | |
7882 | if (TARGET_CAN_FAULT_IN_PROLOGUE) | |
5a965225 | 7883 | FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); |
8df4a58b | 7884 | else |
205b281f | 7885 | /* This must always be the last instruction in the |
7886 | prologue, thus we emit a special move + clobber. */ | |
5a965225 | 7887 | FRP (emit_insn (gen_init_fp (hard_frame_pointer_rtx, |
7888 | stack_pointer_rtx, sa_reg))); | |
8df4a58b | 7889 | } |
8df4a58b | 7890 | } |
7891 | ||
b9a5aa8e | 7892 | /* The ABIs for VMS and OSF/1 say that while we can schedule insns into |
7893 | the prologue, for exception handling reasons, we cannot do this for | |
7894 | any insn that might fault. We could prevent this for mems with a | |
7895 | (clobber:BLK (scratch)), but this doesn't work for fp insns. So we | |
7896 | have to prevent all such scheduling with a blockage. | |
8df4a58b | 7897 | |
9e7454d0 | 7898 | Linux, on the other hand, never bothered to implement OSF/1's |
b9a5aa8e | 7899 | exception handling, and so doesn't care about such things. Anyone |
7900 | planning to use dwarf2 frame-unwind info can also omit the blockage. */ | |
8df4a58b | 7901 | |
b9a5aa8e | 7902 | if (! TARGET_CAN_FAULT_IN_PROLOGUE) |
7903 | emit_insn (gen_blockage ()); | |
1fce2e8a | 7904 | } |
7905 | ||
e3b8b697 | 7906 | /* Count the number of .file directives, so that .loc is up to date. */ |
d0de818d | 7907 | int num_source_filenames = 0; |
e3b8b697 | 7908 | |
2cf1388a | 7909 | /* Output the textual info surrounding the prologue. */ |
8df4a58b | 7910 | |
b9a5aa8e | 7911 | void |
92643d95 | 7912 | alpha_start_function (FILE *file, const char *fnname, |
7913 | tree decl ATTRIBUTE_UNUSED) | |
0c0464e6 | 7914 | { |
b9a5aa8e | 7915 | unsigned long imask = 0; |
7916 | unsigned long fmask = 0; | |
7917 | /* Stack space needed for pushing registers clobbered by us. */ | |
7918 | HOST_WIDE_INT sa_size; | |
7919 | /* Complete stack size needed. */ | |
f9e9d81d | 7920 | unsigned HOST_WIDE_INT frame_size; |
126b6848 | 7921 | /* The maximum debuggable frame size. */ |
7922 | unsigned HOST_WIDE_INT max_frame_size = 1UL << 31; | |
b9a5aa8e | 7923 | /* Offset from base reg to register save area. */ |
7924 | HOST_WIDE_INT reg_offset; | |
2cf1388a | 7925 | char *entry_label = (char *) alloca (strlen (fnname) + 6); |
d2f33c43 | 7926 | char *tramp_label = (char *) alloca (strlen (fnname) + 6); |
b9a5aa8e | 7927 | int i; |
0c0464e6 | 7928 | |
1f697db5 | 7929 | #if TARGET_ABI_OPEN_VMS |
784576c7 | 7930 | vms_start_function (fnname); |
1f697db5 | 7931 | #endif |
7932 | ||
a314eb5e | 7933 | alpha_fnname = fnname; |
b9a5aa8e | 7934 | sa_size = alpha_sa_size (); |
990495a7 | 7935 | frame_size = compute_frame_size (get_frame_size (), sa_size); |
0c0464e6 | 7936 | |
1467e953 | 7937 | if (TARGET_ABI_OPEN_VMS) |
50f36bdb | 7938 | reg_offset = 8 + 8 * cfun->machine->uses_condition_handler; |
b9a5aa8e | 7939 | else |
abe32cce | 7940 | reg_offset = ALPHA_ROUND (crtl->outgoing_args_size); |
0c0464e6 | 7941 | |
b9a5aa8e | 7942 | alpha_sa_mask (&imask, &fmask); |
bf2a98b3 | 7943 | |
b9a5aa8e | 7944 | /* Issue function start and label. */ |
04d75965 | 7945 | if (TARGET_ABI_OPEN_VMS || !flag_inhibit_size_directive) |
f1fe649e | 7946 | { |
b9a5aa8e | 7947 | fputs ("\t.ent ", file); |
2cf1388a | 7948 | assemble_name (file, fnname); |
b9a5aa8e | 7949 | putc ('\n', file); |
a314eb5e | 7950 | |
7951 | /* If the function needs GP, we'll write the "..ng" label there. | |
7952 | Otherwise, do it here. */ | |
961d6ddd | 7953 | if (TARGET_ABI_OSF |
7954 | && ! alpha_function_needs_gp | |
9247818a | 7955 | && ! cfun->is_thunk) |
a314eb5e | 7956 | { |
7957 | putc ('$', file); | |
7958 | assemble_name (file, fnname); | |
7959 | fputs ("..ng:\n", file); | |
7960 | } | |
f1fe649e | 7961 | } |
d2f33c43 | 7962 | /* Nested functions on VMS that are potentially called via trampoline |
7963 | get a special transfer entry point that loads the called functions | |
7964 | procedure descriptor and static chain. */ | |
7965 | if (TARGET_ABI_OPEN_VMS | |
7966 | && !TREE_PUBLIC (decl) | |
7967 | && DECL_CONTEXT (decl) | |
d8f99b92 | 7968 | && !TYPE_P (DECL_CONTEXT (decl)) |
7969 | && TREE_CODE (DECL_CONTEXT (decl)) != TRANSLATION_UNIT_DECL) | |
d2f33c43 | 7970 | { |
7971 | strcpy (tramp_label, fnname); | |
7972 | strcat (tramp_label, "..tr"); | |
7973 | ASM_OUTPUT_LABEL (file, tramp_label); | |
7974 | fprintf (file, "\tldq $1,24($27)\n"); | |
7975 | fprintf (file, "\tldq $27,16($27)\n"); | |
7976 | } | |
449b7f2d | 7977 | |
2cf1388a | 7978 | strcpy (entry_label, fnname); |
1467e953 | 7979 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7980 | strcat (entry_label, "..en"); |
9caef960 | 7981 | |
b9a5aa8e | 7982 | ASM_OUTPUT_LABEL (file, entry_label); |
7983 | inside_function = TRUE; | |
449b7f2d | 7984 | |
1467e953 | 7985 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 7986 | fprintf (file, "\t.base $%d\n", vms_base_regno); |
bf2a98b3 | 7987 | |
4505d022 | 7988 | if (TARGET_ABI_OSF |
7989 | && TARGET_IEEE_CONFORMANT | |
b9a5aa8e | 7990 | && !flag_inhibit_size_directive) |
9c0e5703 | 7991 | { |
b9a5aa8e | 7992 | /* Set flags in procedure descriptor to request IEEE-conformant |
7993 | math-library routines. The value we set it to is PDSC_EXC_IEEE | |
65abff06 | 7994 | (/usr/include/pdsc.h). */ |
b9a5aa8e | 7995 | fputs ("\t.eflag 48\n", file); |
9c0e5703 | 7996 | } |
bf2a98b3 | 7997 | |
b9a5aa8e | 7998 | /* Set up offsets to alpha virtual arg/local debugging pointer. */ |
abe32cce | 7999 | alpha_auto_offset = -frame_size + crtl->args.pretend_args_size; |
b9a5aa8e | 8000 | alpha_arg_offset = -frame_size + 48; |
cb015df5 | 8001 | |
b9a5aa8e | 8002 | /* Describe our frame. If the frame size is larger than an integer, |
8003 | print it as zero to avoid an assembler error. We won't be | |
8004 | properly describing such a frame, but that's the best we can do. */ | |
04d75965 | 8005 | if (TARGET_ABI_OPEN_VMS) |
4840a03a | 8006 | fprintf (file, "\t.frame $%d," HOST_WIDE_INT_PRINT_DEC ",$26," |
8007 | HOST_WIDE_INT_PRINT_DEC "\n", | |
8008 | vms_unwind_regno, | |
8009 | frame_size >= (1UL << 31) ? 0 : frame_size, | |
8010 | reg_offset); | |
b9a5aa8e | 8011 | else if (!flag_inhibit_size_directive) |
4840a03a | 8012 | fprintf (file, "\t.frame $%d," HOST_WIDE_INT_PRINT_DEC ",$26,%d\n", |
8013 | (frame_pointer_needed | |
8014 | ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM), | |
6dbdfeeb | 8015 | frame_size >= max_frame_size ? 0 : frame_size, |
abe32cce | 8016 | crtl->args.pretend_args_size); |
15d5236f | 8017 | |
b9a5aa8e | 8018 | /* Describe which registers were spilled. */ |
04d75965 | 8019 | if (TARGET_ABI_OPEN_VMS) |
15d5236f | 8020 | { |
b9a5aa8e | 8021 | if (imask) |
9caef960 | 8022 | /* ??? Does VMS care if mask contains ra? The old code didn't |
b9a5aa8e | 8023 | set it, so I don't here. */ |
df7d0d23 | 8024 | fprintf (file, "\t.mask 0x%lx,0\n", imask & ~(1UL << REG_RA)); |
b9a5aa8e | 8025 | if (fmask) |
769ea120 | 8026 | fprintf (file, "\t.fmask 0x%lx,0\n", fmask); |
b19d7ab1 | 8027 | if (alpha_procedure_type == PT_REGISTER) |
b9a5aa8e | 8028 | fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno); |
8029 | } | |
8030 | else if (!flag_inhibit_size_directive) | |
8031 | { | |
8032 | if (imask) | |
15d5236f | 8033 | { |
4840a03a | 8034 | fprintf (file, "\t.mask 0x%lx," HOST_WIDE_INT_PRINT_DEC "\n", imask, |
6dbdfeeb | 8035 | frame_size >= max_frame_size ? 0 : reg_offset - frame_size); |
b9a5aa8e | 8036 | |
8037 | for (i = 0; i < 32; ++i) | |
df7d0d23 | 8038 | if (imask & (1UL << i)) |
b9a5aa8e | 8039 | reg_offset += 8; |
15d5236f | 8040 | } |
b9a5aa8e | 8041 | |
8042 | if (fmask) | |
4840a03a | 8043 | fprintf (file, "\t.fmask 0x%lx," HOST_WIDE_INT_PRINT_DEC "\n", fmask, |
6dbdfeeb | 8044 | frame_size >= max_frame_size ? 0 : reg_offset - frame_size); |
bf2a98b3 | 8045 | } |
8046 | ||
1467e953 | 8047 | #if TARGET_ABI_OPEN_VMS |
50f36bdb | 8048 | /* If a user condition handler has been installed at some point, emit |
8049 | the procedure descriptor bits to point the Condition Handling Facility | |
8050 | at the indirection wrapper, and state the fp offset at which the user | |
8051 | handler may be found. */ | |
8052 | if (cfun->machine->uses_condition_handler) | |
8053 | { | |
8054 | fprintf (file, "\t.handler __gcc_shell_handler\n"); | |
8055 | fprintf (file, "\t.handler_data %d\n", VMS_COND_HANDLER_FP_OFFSET); | |
8056 | } | |
8057 | ||
5ce94904 | 8058 | #ifdef TARGET_VMS_CRASH_DEBUG |
8059 | /* Support of minimal traceback info. */ | |
2f14b1f9 | 8060 | switch_to_section (readonly_data_section); |
b9a5aa8e | 8061 | fprintf (file, "\t.align 3\n"); |
2cf1388a | 8062 | assemble_name (file, fnname); fputs ("..na:\n", file); |
b9a5aa8e | 8063 | fputs ("\t.ascii \"", file); |
2cf1388a | 8064 | assemble_name (file, fnname); |
b9a5aa8e | 8065 | fputs ("\\0\"\n", file); |
2f14b1f9 | 8066 | switch_to_section (text_section); |
b9a5aa8e | 8067 | #endif |
5ce94904 | 8068 | #endif /* TARGET_ABI_OPEN_VMS */ |
b9a5aa8e | 8069 | } |
bf2a98b3 | 8070 | |
b9a5aa8e | 8071 | /* Emit the .prologue note at the scheduled end of the prologue. */ |
16b3392b | 8072 | |
85ae73e8 | 8073 | static void |
92643d95 | 8074 | alpha_output_function_end_prologue (FILE *file) |
b9a5aa8e | 8075 | { |
04d75965 | 8076 | if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 8077 | fputs ("\t.prologue\n", file); |
b9a5aa8e | 8078 | else if (!flag_inhibit_size_directive) |
961d6ddd | 8079 | fprintf (file, "\t.prologue %d\n", |
9247818a | 8080 | alpha_function_needs_gp || cfun->is_thunk); |
bf2a98b3 | 8081 | } |
8082 | ||
8083 | /* Write function epilogue. */ | |
8084 | ||
8085 | void | |
92643d95 | 8086 | alpha_expand_epilogue (void) |
bf2a98b3 | 8087 | { |
b9a5aa8e | 8088 | /* Registers to save. */ |
8089 | unsigned long imask = 0; | |
8090 | unsigned long fmask = 0; | |
8091 | /* Stack space needed for pushing registers clobbered by us. */ | |
8092 | HOST_WIDE_INT sa_size; | |
8093 | /* Complete stack size needed. */ | |
8094 | HOST_WIDE_INT frame_size; | |
8095 | /* Offset from base reg to register save area. */ | |
8096 | HOST_WIDE_INT reg_offset; | |
8097 | int fp_is_frame_pointer, fp_offset; | |
8098 | rtx sa_reg, sa_reg_exp = NULL; | |
d30e4246 | 8099 | rtx sp_adj1, sp_adj2, mem, reg, insn; |
11016d99 | 8100 | rtx eh_ofs; |
d30e4246 | 8101 | rtx cfa_restores = NULL_RTX; |
bf2a98b3 | 8102 | int i; |
8103 | ||
b9a5aa8e | 8104 | sa_size = alpha_sa_size (); |
990495a7 | 8105 | frame_size = compute_frame_size (get_frame_size (), sa_size); |
bf2a98b3 | 8106 | |
1467e953 | 8107 | if (TARGET_ABI_OPEN_VMS) |
b19d7ab1 | 8108 | { |
8109 | if (alpha_procedure_type == PT_STACK) | |
50f36bdb | 8110 | reg_offset = 8 + 8 * cfun->machine->uses_condition_handler; |
b19d7ab1 | 8111 | else |
8112 | reg_offset = 0; | |
8113 | } | |
b9a5aa8e | 8114 | else |
abe32cce | 8115 | reg_offset = ALPHA_ROUND (crtl->outgoing_args_size); |
b9a5aa8e | 8116 | |
8117 | alpha_sa_mask (&imask, &fmask); | |
8118 | ||
b19d7ab1 | 8119 | fp_is_frame_pointer |
4505d022 | 8120 | = (TARGET_ABI_OPEN_VMS |
8121 | ? alpha_procedure_type == PT_STACK | |
8122 | : frame_pointer_needed); | |
29768226 | 8123 | fp_offset = 0; |
8124 | sa_reg = stack_pointer_rtx; | |
b9a5aa8e | 8125 | |
18d50ae6 | 8126 | if (crtl->calls_eh_return) |
c92c328f | 8127 | eh_ofs = EH_RETURN_STACKADJ_RTX; |
8128 | else | |
8129 | eh_ofs = NULL_RTX; | |
8130 | ||
04d75965 | 8131 | if (sa_size) |
b9a5aa8e | 8132 | { |
8133 | /* If we have a frame pointer, restore SP from it. */ | |
4505d022 | 8134 | if (TARGET_ABI_OPEN_VMS |
8135 | ? vms_unwind_regno == HARD_FRAME_POINTER_REGNUM | |
8136 | : frame_pointer_needed) | |
d30e4246 | 8137 | emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); |
15d5236f | 8138 | |
b9a5aa8e | 8139 | /* Cope with very large offsets to the register save area. */ |
b9a5aa8e | 8140 | if (reg_offset + sa_size > 0x8000) |
bf2a98b3 | 8141 | { |
b9a5aa8e | 8142 | int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000; |
8143 | HOST_WIDE_INT bias; | |
8144 | ||
8145 | if (low + sa_size <= 0x8000) | |
8146 | bias = reg_offset - low, reg_offset = low; | |
9e7454d0 | 8147 | else |
b9a5aa8e | 8148 | bias = reg_offset, reg_offset = 0; |
8149 | ||
8150 | sa_reg = gen_rtx_REG (DImode, 22); | |
29c05e22 | 8151 | sa_reg_exp = plus_constant (Pmode, stack_pointer_rtx, bias); |
b9a5aa8e | 8152 | |
d30e4246 | 8153 | emit_move_insn (sa_reg, sa_reg_exp); |
bf2a98b3 | 8154 | } |
9e7454d0 | 8155 | |
65abff06 | 8156 | /* Restore registers in order, excepting a true frame pointer. */ |
bf2a98b3 | 8157 | |
29c05e22 | 8158 | mem = gen_frame_mem (DImode, plus_constant (Pmode, sa_reg, reg_offset)); |
d30e4246 | 8159 | reg = gen_rtx_REG (DImode, REG_RA); |
8160 | emit_move_insn (reg, mem); | |
8161 | cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores); | |
c92c328f | 8162 | |
b9a5aa8e | 8163 | reg_offset += 8; |
df7d0d23 | 8164 | imask &= ~(1UL << REG_RA); |
16b3392b | 8165 | |
c49ad9ef | 8166 | for (i = 0; i < 31; ++i) |
df7d0d23 | 8167 | if (imask & (1UL << i)) |
bf2a98b3 | 8168 | { |
b9a5aa8e | 8169 | if (i == HARD_FRAME_POINTER_REGNUM && fp_is_frame_pointer) |
16b3392b | 8170 | fp_offset = reg_offset; |
8171 | else | |
b9a5aa8e | 8172 | { |
656e2b9d | 8173 | mem = gen_frame_mem (DImode, |
29c05e22 | 8174 | plus_constant (Pmode, sa_reg, |
8175 | reg_offset)); | |
d30e4246 | 8176 | reg = gen_rtx_REG (DImode, i); |
8177 | emit_move_insn (reg, mem); | |
8178 | cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, | |
8179 | cfa_restores); | |
b9a5aa8e | 8180 | } |
bf2a98b3 | 8181 | reg_offset += 8; |
8182 | } | |
8183 | ||
c49ad9ef | 8184 | for (i = 0; i < 31; ++i) |
df7d0d23 | 8185 | if (fmask & (1UL << i)) |
bf2a98b3 | 8186 | { |
29c05e22 | 8187 | mem = gen_frame_mem (DFmode, plus_constant (Pmode, sa_reg, |
8188 | reg_offset)); | |
d30e4246 | 8189 | reg = gen_rtx_REG (DFmode, i+32); |
8190 | emit_move_insn (reg, mem); | |
8191 | cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores); | |
bf2a98b3 | 8192 | reg_offset += 8; |
8193 | } | |
b9a5aa8e | 8194 | } |
bf2a98b3 | 8195 | |
11016d99 | 8196 | if (frame_size || eh_ofs) |
b9a5aa8e | 8197 | { |
ec37ccb4 | 8198 | sp_adj1 = stack_pointer_rtx; |
8199 | ||
11016d99 | 8200 | if (eh_ofs) |
ec37ccb4 | 8201 | { |
8202 | sp_adj1 = gen_rtx_REG (DImode, 23); | |
8203 | emit_move_insn (sp_adj1, | |
11016d99 | 8204 | gen_rtx_PLUS (Pmode, stack_pointer_rtx, eh_ofs)); |
ec37ccb4 | 8205 | } |
8206 | ||
b9a5aa8e | 8207 | /* If the stack size is large, begin computation into a temporary |
8208 | register so as not to interfere with a potential fp restore, | |
8209 | which must be consecutive with an SP restore. */ | |
04d75965 | 8210 | if (frame_size < 32768 && !cfun->calls_alloca) |
ec37ccb4 | 8211 | sp_adj2 = GEN_INT (frame_size); |
b9a5aa8e | 8212 | else if (frame_size < 0x40007fffL) |
8213 | { | |
8214 | int low = ((frame_size & 0xffff) ^ 0x8000) - 0x8000; | |
8215 | ||
29c05e22 | 8216 | sp_adj2 = plus_constant (Pmode, sp_adj1, frame_size - low); |
b9a5aa8e | 8217 | if (sa_reg_exp && rtx_equal_p (sa_reg_exp, sp_adj2)) |
8218 | sp_adj1 = sa_reg; | |
8219 | else | |
8220 | { | |
8221 | sp_adj1 = gen_rtx_REG (DImode, 23); | |
d30e4246 | 8222 | emit_move_insn (sp_adj1, sp_adj2); |
b9a5aa8e | 8223 | } |
8224 | sp_adj2 = GEN_INT (low); | |
8225 | } | |
0e0a0e7a | 8226 | else |
b9a5aa8e | 8227 | { |
ec37ccb4 | 8228 | rtx tmp = gen_rtx_REG (DImode, 23); |
d30e4246 | 8229 | sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, 3, false); |
ec37ccb4 | 8230 | if (!sp_adj2) |
b9a5aa8e | 8231 | { |
8232 | /* We can't drop new things to memory this late, afaik, | |
8233 | so build it up by pieces. */ | |
debb7e7a | 8234 | sp_adj2 = alpha_emit_set_long_const (tmp, frame_size); |
4d10b463 | 8235 | gcc_assert (sp_adj2); |
b9a5aa8e | 8236 | } |
b9a5aa8e | 8237 | } |
bf2a98b3 | 8238 | |
b9a5aa8e | 8239 | /* From now on, things must be in order. So emit blockages. */ |
8240 | ||
8241 | /* Restore the frame pointer. */ | |
04d75965 | 8242 | if (fp_is_frame_pointer) |
b9a5aa8e | 8243 | { |
8244 | emit_insn (gen_blockage ()); | |
29c05e22 | 8245 | mem = gen_frame_mem (DImode, plus_constant (Pmode, sa_reg, |
8246 | fp_offset)); | |
d30e4246 | 8247 | emit_move_insn (hard_frame_pointer_rtx, mem); |
8248 | cfa_restores = alloc_reg_note (REG_CFA_RESTORE, | |
8249 | hard_frame_pointer_rtx, cfa_restores); | |
b9a5aa8e | 8250 | } |
1467e953 | 8251 | else if (TARGET_ABI_OPEN_VMS) |
b9a5aa8e | 8252 | { |
8253 | emit_insn (gen_blockage ()); | |
d30e4246 | 8254 | emit_move_insn (hard_frame_pointer_rtx, |
8255 | gen_rtx_REG (DImode, vms_save_fp_regno)); | |
8256 | cfa_restores = alloc_reg_note (REG_CFA_RESTORE, | |
8257 | hard_frame_pointer_rtx, cfa_restores); | |
b9a5aa8e | 8258 | } |
8259 | ||
8260 | /* Restore the stack pointer. */ | |
8261 | emit_insn (gen_blockage ()); | |
9caef960 | 8262 | if (sp_adj2 == const0_rtx) |
d30e4246 | 8263 | insn = emit_move_insn (stack_pointer_rtx, sp_adj1); |
9caef960 | 8264 | else |
d30e4246 | 8265 | insn = emit_move_insn (stack_pointer_rtx, |
8266 | gen_rtx_PLUS (DImode, sp_adj1, sp_adj2)); | |
8267 | REG_NOTES (insn) = cfa_restores; | |
8268 | add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx); | |
8269 | RTX_FRAME_RELATED_P (insn) = 1; | |
b9a5aa8e | 8270 | } |
9e7454d0 | 8271 | else |
b9a5aa8e | 8272 | { |
d30e4246 | 8273 | gcc_assert (cfa_restores == NULL); |
8274 | ||
b19d7ab1 | 8275 | if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_REGISTER) |
b9a5aa8e | 8276 | { |
8277 | emit_insn (gen_blockage ()); | |
d30e4246 | 8278 | insn = emit_move_insn (hard_frame_pointer_rtx, |
8279 | gen_rtx_REG (DImode, vms_save_fp_regno)); | |
8280 | add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx); | |
8281 | RTX_FRAME_RELATED_P (insn) = 1; | |
b9a5aa8e | 8282 | } |
bf2a98b3 | 8283 | } |
b9a5aa8e | 8284 | } |
cf73d31f | 8285 | \f |
b9a5aa8e | 8286 | /* Output the rest of the textual info surrounding the epilogue. */ |
8287 | ||
8288 | void | |
92643d95 | 8289 | alpha_end_function (FILE *file, const char *fnname, tree decl ATTRIBUTE_UNUSED) |
b9a5aa8e | 8290 | { |
7f0256ea | 8291 | rtx_insn *insn; |
32a8f747 | 8292 | |
8293 | /* We output a nop after noreturn calls at the very end of the function to | |
8294 | ensure that the return address always remains in the caller's code range, | |
8295 | as not doing so might confuse unwinding engines. */ | |
8296 | insn = get_last_insn (); | |
8297 | if (!INSN_P (insn)) | |
8298 | insn = prev_active_insn (insn); | |
937fc2f7 | 8299 | if (insn && CALL_P (insn)) |
32a8f747 | 8300 | output_asm_insn (get_insn_template (CODE_FOR_nop, NULL), NULL); |
8301 | ||
04b0d94a | 8302 | #if TARGET_ABI_OPEN_VMS |
5ce94904 | 8303 | /* Write the linkage entries. */ |
8304 | alpha_write_linkage (file, fnname); | |
04b0d94a | 8305 | #endif |
8306 | ||
bf2a98b3 | 8307 | /* End the function. */ |
38021748 | 8308 | if (TARGET_ABI_OPEN_VMS |
8309 | || !flag_inhibit_size_directive) | |
f1fe649e | 8310 | { |
b9a5aa8e | 8311 | fputs ("\t.end ", file); |
2cf1388a | 8312 | assemble_name (file, fnname); |
b9a5aa8e | 8313 | putc ('\n', file); |
f1fe649e | 8314 | } |
449b7f2d | 8315 | inside_function = FALSE; |
bf2a98b3 | 8316 | } |
961d6ddd | 8317 | |
6988553d | 8318 | #if TARGET_ABI_OSF |
8319 | /* Emit a tail call to FUNCTION after adjusting THIS by DELTA. | |
961d6ddd | 8320 | |
8321 | In order to avoid the hordes of differences between generated code | |
8322 | with and without TARGET_EXPLICIT_RELOCS, and to avoid duplicating | |
8323 | lots of code loading up large constants, generate rtl and emit it | |
8324 | instead of going straight to text. | |
8325 | ||
8326 | Not sure why this idea hasn't been explored before... */ | |
8327 | ||
6988553d | 8328 | static void |
92643d95 | 8329 | alpha_output_mi_thunk_osf (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, |
8330 | HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, | |
8331 | tree function) | |
961d6ddd | 8332 | { |
8333 | HOST_WIDE_INT hi, lo; | |
7f0256ea | 8334 | rtx this_rtx, funexp; |
8335 | rtx_insn *insn; | |
961d6ddd | 8336 | |
8337 | /* We always require a valid GP. */ | |
8338 | emit_insn (gen_prologue_ldgp ()); | |
31b97e8f | 8339 | emit_note (NOTE_INSN_PROLOGUE_END); |
961d6ddd | 8340 | |
8341 | /* Find the "this" pointer. If the function returns a structure, | |
8342 | the structure return pointer is in $16. */ | |
45550790 | 8343 | if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) |
8deb3959 | 8344 | this_rtx = gen_rtx_REG (Pmode, 17); |
961d6ddd | 8345 | else |
8deb3959 | 8346 | this_rtx = gen_rtx_REG (Pmode, 16); |
961d6ddd | 8347 | |
8348 | /* Add DELTA. When possible we use ldah+lda. Otherwise load the | |
8349 | entire constant for the add. */ | |
8350 | lo = ((delta & 0xffff) ^ 0x8000) - 0x8000; | |
8351 | hi = (((delta - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
8352 | if (hi + lo == delta) | |
8353 | { | |
8354 | if (hi) | |
8deb3959 | 8355 | emit_insn (gen_adddi3 (this_rtx, this_rtx, GEN_INT (hi))); |
961d6ddd | 8356 | if (lo) |
8deb3959 | 8357 | emit_insn (gen_adddi3 (this_rtx, this_rtx, GEN_INT (lo))); |
961d6ddd | 8358 | } |
8359 | else | |
8360 | { | |
debb7e7a | 8361 | rtx tmp = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 0), delta); |
8deb3959 | 8362 | emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp)); |
961d6ddd | 8363 | } |
8364 | ||
a19ec9da | 8365 | /* Add a delta stored in the vtable at VCALL_OFFSET. */ |
8366 | if (vcall_offset) | |
8367 | { | |
8368 | rtx tmp, tmp2; | |
8369 | ||
8370 | tmp = gen_rtx_REG (Pmode, 0); | |
8deb3959 | 8371 | emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx)); |
a19ec9da | 8372 | |
8373 | lo = ((vcall_offset & 0xffff) ^ 0x8000) - 0x8000; | |
8374 | hi = (((vcall_offset - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000; | |
8375 | if (hi + lo == vcall_offset) | |
8376 | { | |
8377 | if (hi) | |
8378 | emit_insn (gen_adddi3 (tmp, tmp, GEN_INT (hi))); | |
8379 | } | |
8380 | else | |
8381 | { | |
8382 | tmp2 = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 1), | |
debb7e7a | 8383 | vcall_offset); |
a19ec9da | 8384 | emit_insn (gen_adddi3 (tmp, tmp, tmp2)); |
8385 | lo = 0; | |
8386 | } | |
8387 | if (lo) | |
8388 | tmp2 = gen_rtx_PLUS (Pmode, tmp, GEN_INT (lo)); | |
8389 | else | |
8390 | tmp2 = tmp; | |
8391 | emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp2)); | |
8392 | ||
8deb3959 | 8393 | emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp)); |
a19ec9da | 8394 | } |
8395 | ||
961d6ddd | 8396 | /* Generate a tail call to the target function. */ |
8397 | if (! TREE_USED (function)) | |
8398 | { | |
8399 | assemble_external (function); | |
8400 | TREE_USED (function) = 1; | |
8401 | } | |
8402 | funexp = XEXP (DECL_RTL (function), 0); | |
8403 | funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); | |
8404 | insn = emit_call_insn (gen_sibcall (funexp, const0_rtx)); | |
8405 | SIBLING_CALL_P (insn) = 1; | |
8406 | ||
8407 | /* Run just enough of rest_of_compilation to get the insns emitted. | |
8408 | There's not really enough bulk here to make other passes such as | |
8409 | instruction scheduling worth while. Note that use_thunk calls | |
8410 | assemble_start_function and assemble_end_function. */ | |
8411 | insn = get_insns (); | |
8412 | shorten_branches (insn); | |
8413 | final_start_function (insn, file, 1); | |
4bf029b0 | 8414 | final (insn, file, 1); |
961d6ddd | 8415 | final_end_function (); |
8416 | } | |
6988553d | 8417 | #endif /* TARGET_ABI_OSF */ |
449b7f2d | 8418 | \f |
8419 | /* Debugging support. */ | |
8420 | ||
8421 | #include "gstab.h" | |
8422 | ||
449b7f2d | 8423 | /* Name of the file containing the current function. */ |
8424 | ||
ace75b22 | 8425 | static const char *current_function_file = ""; |
449b7f2d | 8426 | |
8427 | /* Offsets to alpha virtual arg/local debugging pointers. */ | |
8428 | ||
8429 | long alpha_arg_offset; | |
8430 | long alpha_auto_offset; | |
8431 | \f | |
8432 | /* Emit a new filename to a stream. */ | |
8433 | ||
8434 | void | |
92643d95 | 8435 | alpha_output_filename (FILE *stream, const char *name) |
449b7f2d | 8436 | { |
8437 | static int first_time = TRUE; | |
449b7f2d | 8438 | |
8439 | if (first_time) | |
8440 | { | |
8441 | first_time = FALSE; | |
8442 | ++num_source_filenames; | |
8443 | current_function_file = name; | |
8444 | fprintf (stream, "\t.file\t%d ", num_source_filenames); | |
8445 | output_quoted_string (stream, name); | |
8446 | fprintf (stream, "\n"); | |
449b7f2d | 8447 | } |
8448 | ||
449b7f2d | 8449 | else if (name != current_function_file |
be3797c1 | 8450 | && strcmp (name, current_function_file) != 0) |
449b7f2d | 8451 | { |
48a5030b | 8452 | ++num_source_filenames; |
8453 | current_function_file = name; | |
8454 | fprintf (stream, "\t.file\t%d ", num_source_filenames); | |
449b7f2d | 8455 | |
8456 | output_quoted_string (stream, name); | |
8457 | fprintf (stream, "\n"); | |
8458 | } | |
8459 | } | |
c4622276 | 8460 | \f |
8461 | /* Structure to show the current status of registers and memory. */ | |
8462 | ||
8463 | struct shadow_summary | |
8464 | { | |
8465 | struct { | |
495c4a78 | 8466 | unsigned int i : 31; /* Mask of int regs */ |
8467 | unsigned int fp : 31; /* Mask of fp regs */ | |
8468 | unsigned int mem : 1; /* mem == imem | fpmem */ | |
c4622276 | 8469 | } used, defd; |
8470 | }; | |
8471 | ||
8472 | /* Summary the effects of expression X on the machine. Update SUM, a pointer | |
8473 | to the summary structure. SET is nonzero if the insn is setting the | |
8474 | object, otherwise zero. */ | |
8475 | ||
8476 | static void | |
92643d95 | 8477 | summarize_insn (rtx x, struct shadow_summary *sum, int set) |
c4622276 | 8478 | { |
d2ca078f | 8479 | const char *format_ptr; |
c4622276 | 8480 | int i, j; |
8481 | ||
8482 | if (x == 0) | |
8483 | return; | |
8484 | ||
8485 | switch (GET_CODE (x)) | |
8486 | { | |
8487 | /* ??? Note that this case would be incorrect if the Alpha had a | |
8488 | ZERO_EXTRACT in SET_DEST. */ | |
8489 | case SET: | |
8490 | summarize_insn (SET_SRC (x), sum, 0); | |
8491 | summarize_insn (SET_DEST (x), sum, 1); | |
8492 | break; | |
8493 | ||
8494 | case CLOBBER: | |
8495 | summarize_insn (XEXP (x, 0), sum, 1); | |
8496 | break; | |
8497 | ||
8498 | case USE: | |
8499 | summarize_insn (XEXP (x, 0), sum, 0); | |
8500 | break; | |
8501 | ||
a886cc41 | 8502 | case ASM_OPERANDS: |
8503 | for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--) | |
8504 | summarize_insn (ASM_OPERANDS_INPUT (x, i), sum, 0); | |
8505 | break; | |
8506 | ||
c4622276 | 8507 | case PARALLEL: |
3a5dbb5e | 8508 | for (i = XVECLEN (x, 0) - 1; i >= 0; i--) |
c4622276 | 8509 | summarize_insn (XVECEXP (x, 0, i), sum, 0); |
8510 | break; | |
8511 | ||
a886cc41 | 8512 | case SUBREG: |
b9a5aa8e | 8513 | summarize_insn (SUBREG_REG (x), sum, 0); |
8514 | break; | |
a886cc41 | 8515 | |
c4622276 | 8516 | case REG: |
8517 | { | |
8518 | int regno = REGNO (x); | |
f3d263a7 | 8519 | unsigned long mask = ((unsigned long) 1) << (regno % 32); |
c4622276 | 8520 | |
8521 | if (regno == 31 || regno == 63) | |
8522 | break; | |
8523 | ||
8524 | if (set) | |
8525 | { | |
8526 | if (regno < 32) | |
8527 | sum->defd.i |= mask; | |
8528 | else | |
8529 | sum->defd.fp |= mask; | |
8530 | } | |
8531 | else | |
8532 | { | |
8533 | if (regno < 32) | |
8534 | sum->used.i |= mask; | |
8535 | else | |
8536 | sum->used.fp |= mask; | |
8537 | } | |
8538 | } | |
8539 | break; | |
8540 | ||
8541 | case MEM: | |
8542 | if (set) | |
8543 | sum->defd.mem = 1; | |
8544 | else | |
8545 | sum->used.mem = 1; | |
8546 | ||
8547 | /* Find the regs used in memory address computation: */ | |
8548 | summarize_insn (XEXP (x, 0), sum, 0); | |
8549 | break; | |
8550 | ||
5c5c1f00 | 8551 | case CONST_INT: case CONST_WIDE_INT: case CONST_DOUBLE: |
8552 | case SYMBOL_REF: case LABEL_REF: case CONST: | |
5bdbf614 | 8553 | case SCRATCH: case ASM_INPUT: |
2d710b28 | 8554 | break; |
8555 | ||
c4622276 | 8556 | /* Handle common unary and binary ops for efficiency. */ |
8557 | case COMPARE: case PLUS: case MINUS: case MULT: case DIV: | |
8558 | case MOD: case UDIV: case UMOD: case AND: case IOR: | |
8559 | case XOR: case ASHIFT: case ROTATE: case ASHIFTRT: case LSHIFTRT: | |
8560 | case ROTATERT: case SMIN: case SMAX: case UMIN: case UMAX: | |
8561 | case NE: case EQ: case GE: case GT: case LE: | |
8562 | case LT: case GEU: case GTU: case LEU: case LTU: | |
8563 | summarize_insn (XEXP (x, 0), sum, 0); | |
8564 | summarize_insn (XEXP (x, 1), sum, 0); | |
8565 | break; | |
8566 | ||
8567 | case NEG: case NOT: case SIGN_EXTEND: case ZERO_EXTEND: | |
8568 | case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: case FLOAT: | |
8569 | case FIX: case UNSIGNED_FLOAT: case UNSIGNED_FIX: case ABS: | |
9e7454d0 | 8570 | case SQRT: case FFS: |
c4622276 | 8571 | summarize_insn (XEXP (x, 0), sum, 0); |
8572 | break; | |
8573 | ||
8574 | default: | |
8575 | format_ptr = GET_RTX_FORMAT (GET_CODE (x)); | |
3a5dbb5e | 8576 | for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) |
cada32d3 | 8577 | switch (format_ptr[i]) |
c4622276 | 8578 | { |
8579 | case 'e': | |
8580 | summarize_insn (XEXP (x, i), sum, 0); | |
8581 | break; | |
8582 | ||
8583 | case 'E': | |
3a5dbb5e | 8584 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) |
c4622276 | 8585 | summarize_insn (XVECEXP (x, i, j), sum, 0); |
8586 | break; | |
8587 | ||
1dc5f36f | 8588 | case 'i': |
8589 | break; | |
8590 | ||
c4622276 | 8591 | default: |
4d10b463 | 8592 | gcc_unreachable (); |
c4622276 | 8593 | } |
8594 | } | |
8595 | } | |
c4622276 | 8596 | |
b9a5aa8e | 8597 | /* Ensure a sufficient number of `trapb' insns are in the code when |
8598 | the user requests code with a trap precision of functions or | |
8599 | instructions. | |
8600 | ||
8601 | In naive mode, when the user requests a trap-precision of | |
8602 | "instruction", a trapb is needed after every instruction that may | |
8603 | generate a trap. This ensures that the code is resumption safe but | |
8604 | it is also slow. | |
8605 | ||
8606 | When optimizations are turned on, we delay issuing a trapb as long | |
8607 | as possible. In this context, a trap shadow is the sequence of | |
8608 | instructions that starts with a (potentially) trap generating | |
8609 | instruction and extends to the next trapb or call_pal instruction | |
8610 | (but GCC never generates call_pal by itself). We can delay (and | |
8611 | therefore sometimes omit) a trapb subject to the following | |
8612 | conditions: | |
8613 | ||
8614 | (a) On entry to the trap shadow, if any Alpha register or memory | |
8615 | location contains a value that is used as an operand value by some | |
8616 | instruction in the trap shadow (live on entry), then no instruction | |
8617 | in the trap shadow may modify the register or memory location. | |
8618 | ||
8619 | (b) Within the trap shadow, the computation of the base register | |
8620 | for a memory load or store instruction may not involve using the | |
8621 | result of an instruction that might generate an UNPREDICTABLE | |
8622 | result. | |
8623 | ||
8624 | (c) Within the trap shadow, no register may be used more than once | |
8625 | as a destination register. (This is to make life easier for the | |
8626 | trap-handler.) | |
c4622276 | 8627 | |
18adf4f6 | 8628 | (d) The trap shadow may not include any branch instructions. */ |
c4622276 | 8629 | |
18adf4f6 | 8630 | static void |
92643d95 | 8631 | alpha_handle_trap_shadows (void) |
c4622276 | 8632 | { |
18adf4f6 | 8633 | struct shadow_summary shadow; |
8634 | int trap_pending, exception_nesting; | |
91a55c11 | 8635 | rtx_insn *i, *n; |
c4622276 | 8636 | |
18adf4f6 | 8637 | trap_pending = 0; |
8638 | exception_nesting = 0; | |
8639 | shadow.used.i = 0; | |
8640 | shadow.used.fp = 0; | |
8641 | shadow.used.mem = 0; | |
8642 | shadow.defd = shadow.used; | |
9e7454d0 | 8643 | |
2efea8c0 | 8644 | for (i = get_insns (); i ; i = NEXT_INSN (i)) |
18adf4f6 | 8645 | { |
c933fb42 | 8646 | if (NOTE_P (i)) |
18adf4f6 | 8647 | { |
ad4583d9 | 8648 | switch (NOTE_KIND (i)) |
18adf4f6 | 8649 | { |
8650 | case NOTE_INSN_EH_REGION_BEG: | |
8651 | exception_nesting++; | |
8652 | if (trap_pending) | |
8653 | goto close_shadow; | |
8654 | break; | |
8655 | ||
8656 | case NOTE_INSN_EH_REGION_END: | |
8657 | exception_nesting--; | |
8658 | if (trap_pending) | |
8659 | goto close_shadow; | |
8660 | break; | |
8661 | ||
8662 | case NOTE_INSN_EPILOGUE_BEG: | |
8663 | if (trap_pending && alpha_tp >= ALPHA_TP_FUNC) | |
8664 | goto close_shadow; | |
8665 | break; | |
8666 | } | |
8667 | } | |
8668 | else if (trap_pending) | |
8669 | { | |
8670 | if (alpha_tp == ALPHA_TP_FUNC) | |
8671 | { | |
c933fb42 | 8672 | if (JUMP_P (i) |
18adf4f6 | 8673 | && GET_CODE (PATTERN (i)) == RETURN) |
8674 | goto close_shadow; | |
8675 | } | |
8676 | else if (alpha_tp == ALPHA_TP_INSN) | |
8677 | { | |
8678 | if (optimize > 0) | |
8679 | { | |
8680 | struct shadow_summary sum; | |
8681 | ||
8682 | sum.used.i = 0; | |
8683 | sum.used.fp = 0; | |
8684 | sum.used.mem = 0; | |
a886cc41 | 8685 | sum.defd = sum.used; |
18adf4f6 | 8686 | |
8687 | switch (GET_CODE (i)) | |
8688 | { | |
8689 | case INSN: | |
4d10b463 | 8690 | /* Annoyingly, get_attr_trap will die on these. */ |
fad0a39b | 8691 | if (GET_CODE (PATTERN (i)) == USE |
8692 | || GET_CODE (PATTERN (i)) == CLOBBER) | |
18adf4f6 | 8693 | break; |
8694 | ||
8695 | summarize_insn (PATTERN (i), &sum, 0); | |
8696 | ||
8697 | if ((sum.defd.i & shadow.defd.i) | |
8698 | || (sum.defd.fp & shadow.defd.fp)) | |
8699 | { | |
8700 | /* (c) would be violated */ | |
8701 | goto close_shadow; | |
8702 | } | |
8703 | ||
8704 | /* Combine shadow with summary of current insn: */ | |
8705 | shadow.used.i |= sum.used.i; | |
8706 | shadow.used.fp |= sum.used.fp; | |
8707 | shadow.used.mem |= sum.used.mem; | |
8708 | shadow.defd.i |= sum.defd.i; | |
8709 | shadow.defd.fp |= sum.defd.fp; | |
8710 | shadow.defd.mem |= sum.defd.mem; | |
8711 | ||
8712 | if ((sum.defd.i & shadow.used.i) | |
8713 | || (sum.defd.fp & shadow.used.fp) | |
8714 | || (sum.defd.mem & shadow.used.mem)) | |
8715 | { | |
8716 | /* (a) would be violated (also takes care of (b)) */ | |
4d10b463 | 8717 | gcc_assert (get_attr_trap (i) != TRAP_YES |
8718 | || (!(sum.defd.i & sum.used.i) | |
8719 | && !(sum.defd.fp & sum.used.fp))); | |
18adf4f6 | 8720 | |
8721 | goto close_shadow; | |
8722 | } | |
8723 | break; | |
8724 | ||
acaaf650 | 8725 | case BARRIER: |
8726 | /* __builtin_unreachable can expand to no code at all, | |
8727 | leaving (barrier) RTXes in the instruction stream. */ | |
8728 | goto close_shadow_notrapb; | |
8729 | ||
18adf4f6 | 8730 | case JUMP_INSN: |
8731 | case CALL_INSN: | |
8732 | case CODE_LABEL: | |
8733 | goto close_shadow; | |
8734 | ||
8735 | default: | |
4d10b463 | 8736 | gcc_unreachable (); |
18adf4f6 | 8737 | } |
8738 | } | |
8739 | else | |
8740 | { | |
8741 | close_shadow: | |
b9b4428b | 8742 | n = emit_insn_before (gen_trapb (), i); |
8743 | PUT_MODE (n, TImode); | |
8744 | PUT_MODE (i, TImode); | |
acaaf650 | 8745 | close_shadow_notrapb: |
18adf4f6 | 8746 | trap_pending = 0; |
8747 | shadow.used.i = 0; | |
8748 | shadow.used.fp = 0; | |
8749 | shadow.used.mem = 0; | |
8750 | shadow.defd = shadow.used; | |
8751 | } | |
8752 | } | |
8753 | } | |
c4622276 | 8754 | |
609d4083 | 8755 | if ((exception_nesting > 0 || alpha_tp >= ALPHA_TP_FUNC) |
c933fb42 | 8756 | && NONJUMP_INSN_P (i) |
609d4083 | 8757 | && GET_CODE (PATTERN (i)) != USE |
8758 | && GET_CODE (PATTERN (i)) != CLOBBER | |
8759 | && get_attr_trap (i) == TRAP_YES) | |
8760 | { | |
8761 | if (optimize && !trap_pending) | |
8762 | summarize_insn (PATTERN (i), &shadow, 0); | |
8763 | trap_pending = 1; | |
8764 | } | |
c4622276 | 8765 | } |
8766 | } | |
b9b4428b | 8767 | \f |
b9b4428b | 8768 | /* Alpha can only issue instruction groups simultaneously if they are |
5910bb95 | 8769 | suitably aligned. This is very processor-specific. */ |
07770f18 | 8770 | /* There are a number of entries in alphaev4_insn_pipe and alphaev5_insn_pipe |
8771 | that are marked "fake". These instructions do not exist on that target, | |
8772 | but it is possible to see these insns with deranged combinations of | |
8773 | command-line options, such as "-mtune=ev4 -mmax". Instead of aborting, | |
8774 | choose a result at random. */ | |
b9b4428b | 8775 | |
849674a3 | 8776 | enum alphaev4_pipe { |
8777 | EV4_STOP = 0, | |
8778 | EV4_IB0 = 1, | |
8779 | EV4_IB1 = 2, | |
8780 | EV4_IBX = 4 | |
8781 | }; | |
8782 | ||
b9b4428b | 8783 | enum alphaev5_pipe { |
8784 | EV5_STOP = 0, | |
8785 | EV5_NONE = 1, | |
8786 | EV5_E01 = 2, | |
8787 | EV5_E0 = 4, | |
8788 | EV5_E1 = 8, | |
8789 | EV5_FAM = 16, | |
8790 | EV5_FA = 32, | |
8791 | EV5_FM = 64 | |
8792 | }; | |
8793 | ||
849674a3 | 8794 | static enum alphaev4_pipe |
7f0256ea | 8795 | alphaev4_insn_pipe (rtx_insn *insn) |
849674a3 | 8796 | { |
8797 | if (recog_memoized (insn) < 0) | |
8798 | return EV4_STOP; | |
8799 | if (get_attr_length (insn) != 4) | |
8800 | return EV4_STOP; | |
8801 | ||
8802 | switch (get_attr_type (insn)) | |
8803 | { | |
8804 | case TYPE_ILD: | |
f155876e | 8805 | case TYPE_LDSYM: |
849674a3 | 8806 | case TYPE_FLD: |
f155876e | 8807 | case TYPE_LD_L: |
849674a3 | 8808 | return EV4_IBX; |
8809 | ||
849674a3 | 8810 | case TYPE_IADD: |
8811 | case TYPE_ILOG: | |
8812 | case TYPE_ICMOV: | |
8813 | case TYPE_ICMP: | |
849674a3 | 8814 | case TYPE_FST: |
8815 | case TYPE_SHIFT: | |
8816 | case TYPE_IMUL: | |
8817 | case TYPE_FBR: | |
07770f18 | 8818 | case TYPE_MVI: /* fake */ |
849674a3 | 8819 | return EV4_IB0; |
8820 | ||
f155876e | 8821 | case TYPE_IST: |
849674a3 | 8822 | case TYPE_MISC: |
8823 | case TYPE_IBR: | |
8824 | case TYPE_JSR: | |
1050b77e | 8825 | case TYPE_CALLPAL: |
849674a3 | 8826 | case TYPE_FCPYS: |
8827 | case TYPE_FCMOV: | |
8828 | case TYPE_FADD: | |
8829 | case TYPE_FDIV: | |
8830 | case TYPE_FMUL: | |
f155876e | 8831 | case TYPE_ST_C: |
8832 | case TYPE_MB: | |
07770f18 | 8833 | case TYPE_FSQRT: /* fake */ |
8834 | case TYPE_FTOI: /* fake */ | |
8835 | case TYPE_ITOF: /* fake */ | |
849674a3 | 8836 | return EV4_IB1; |
8837 | ||
8838 | default: | |
4d10b463 | 8839 | gcc_unreachable (); |
849674a3 | 8840 | } |
8841 | } | |
8842 | ||
b9b4428b | 8843 | static enum alphaev5_pipe |
7f0256ea | 8844 | alphaev5_insn_pipe (rtx_insn *insn) |
b9b4428b | 8845 | { |
8846 | if (recog_memoized (insn) < 0) | |
8847 | return EV5_STOP; | |
8848 | if (get_attr_length (insn) != 4) | |
8849 | return EV5_STOP; | |
8850 | ||
8851 | switch (get_attr_type (insn)) | |
8852 | { | |
8853 | case TYPE_ILD: | |
8854 | case TYPE_FLD: | |
8855 | case TYPE_LDSYM: | |
8856 | case TYPE_IADD: | |
8857 | case TYPE_ILOG: | |
8858 | case TYPE_ICMOV: | |
8859 | case TYPE_ICMP: | |
8860 | return EV5_E01; | |
8861 | ||
8862 | case TYPE_IST: | |
8863 | case TYPE_FST: | |
8864 | case TYPE_SHIFT: | |
8865 | case TYPE_IMUL: | |
8866 | case TYPE_MISC: | |
8867 | case TYPE_MVI: | |
f155876e | 8868 | case TYPE_LD_L: |
8869 | case TYPE_ST_C: | |
8870 | case TYPE_MB: | |
07770f18 | 8871 | case TYPE_FTOI: /* fake */ |
8872 | case TYPE_ITOF: /* fake */ | |
b9b4428b | 8873 | return EV5_E0; |
8874 | ||
8875 | case TYPE_IBR: | |
8876 | case TYPE_JSR: | |
1050b77e | 8877 | case TYPE_CALLPAL: |
b9b4428b | 8878 | return EV5_E1; |
8879 | ||
8880 | case TYPE_FCPYS: | |
8881 | return EV5_FAM; | |
8882 | ||
8883 | case TYPE_FBR: | |
8884 | case TYPE_FCMOV: | |
8885 | case TYPE_FADD: | |
8886 | case TYPE_FDIV: | |
07770f18 | 8887 | case TYPE_FSQRT: /* fake */ |
b9b4428b | 8888 | return EV5_FA; |
8889 | ||
8890 | case TYPE_FMUL: | |
8891 | return EV5_FM; | |
ddca68f8 | 8892 | |
8893 | default: | |
4d10b463 | 8894 | gcc_unreachable (); |
b9b4428b | 8895 | } |
b9b4428b | 8896 | } |
8897 | ||
9e7454d0 | 8898 | /* IN_USE is a mask of the slots currently filled within the insn group. |
849674a3 | 8899 | The mask bits come from alphaev4_pipe above. If EV4_IBX is set, then |
9e7454d0 | 8900 | the insn in EV4_IB0 can be swapped by the hardware into EV4_IB1. |
849674a3 | 8901 | |
8902 | LEN is, of course, the length of the group in bytes. */ | |
8903 | ||
7f0256ea | 8904 | static rtx_insn * |
8905 | alphaev4_next_group (rtx_insn *insn, int *pin_use, int *plen) | |
849674a3 | 8906 | { |
8907 | int len, in_use; | |
8908 | ||
8909 | len = in_use = 0; | |
8910 | ||
9204e736 | 8911 | if (! INSN_P (insn) |
849674a3 | 8912 | || GET_CODE (PATTERN (insn)) == CLOBBER |
8913 | || GET_CODE (PATTERN (insn)) == USE) | |
8914 | goto next_and_done; | |
8915 | ||
8916 | while (1) | |
8917 | { | |
8918 | enum alphaev4_pipe pipe; | |
8919 | ||
8920 | pipe = alphaev4_insn_pipe (insn); | |
8921 | switch (pipe) | |
8922 | { | |
8923 | case EV4_STOP: | |
8924 | /* Force complex instructions to start new groups. */ | |
8925 | if (in_use) | |
8926 | goto done; | |
8927 | ||
20833d12 | 8928 | /* If this is a completely unrecognized insn, it's an asm. |
849674a3 | 8929 | We don't know how long it is, so record length as -1 to |
8930 | signal a needed realignment. */ | |
8931 | if (recog_memoized (insn) < 0) | |
8932 | len = -1; | |
8933 | else | |
8934 | len = get_attr_length (insn); | |
8935 | goto next_and_done; | |
8936 | ||
8937 | case EV4_IBX: | |
8938 | if (in_use & EV4_IB0) | |
8939 | { | |
8940 | if (in_use & EV4_IB1) | |
8941 | goto done; | |
8942 | in_use |= EV4_IB1; | |
8943 | } | |
8944 | else | |
8945 | in_use |= EV4_IB0 | EV4_IBX; | |
8946 | break; | |
8947 | ||
8948 | case EV4_IB0: | |
8949 | if (in_use & EV4_IB0) | |
8950 | { | |
8951 | if (!(in_use & EV4_IBX) || (in_use & EV4_IB1)) | |
8952 | goto done; | |
8953 | in_use |= EV4_IB1; | |
8954 | } | |
8955 | in_use |= EV4_IB0; | |
8956 | break; | |
8957 | ||
8958 | case EV4_IB1: | |
8959 | if (in_use & EV4_IB1) | |
8960 | goto done; | |
8961 | in_use |= EV4_IB1; | |
8962 | break; | |
8963 | ||
8964 | default: | |
4d10b463 | 8965 | gcc_unreachable (); |
849674a3 | 8966 | } |
8967 | len += 4; | |
9e7454d0 | 8968 | |
849674a3 | 8969 | /* Haifa doesn't do well scheduling branches. */ |
c933fb42 | 8970 | if (JUMP_P (insn)) |
849674a3 | 8971 | goto next_and_done; |
8972 | ||
8973 | next: | |
8974 | insn = next_nonnote_insn (insn); | |
8975 | ||
9204e736 | 8976 | if (!insn || ! INSN_P (insn)) |
849674a3 | 8977 | goto done; |
8978 | ||
8979 | /* Let Haifa tell us where it thinks insn group boundaries are. */ | |
8980 | if (GET_MODE (insn) == TImode) | |
8981 | goto done; | |
8982 | ||
8983 | if (GET_CODE (insn) == CLOBBER || GET_CODE (insn) == USE) | |
8984 | goto next; | |
8985 | } | |
8986 | ||
8987 | next_and_done: | |
8988 | insn = next_nonnote_insn (insn); | |
8989 | ||
8990 | done: | |
8991 | *plen = len; | |
8992 | *pin_use = in_use; | |
8993 | return insn; | |
8994 | } | |
8995 | ||
9e7454d0 | 8996 | /* IN_USE is a mask of the slots currently filled within the insn group. |
849674a3 | 8997 | The mask bits come from alphaev5_pipe above. If EV5_E01 is set, then |
9e7454d0 | 8998 | the insn in EV5_E0 can be swapped by the hardware into EV5_E1. |
b9b4428b | 8999 | |
9000 | LEN is, of course, the length of the group in bytes. */ | |
9001 | ||
7f0256ea | 9002 | static rtx_insn * |
9003 | alphaev5_next_group (rtx_insn *insn, int *pin_use, int *plen) | |
b9b4428b | 9004 | { |
9005 | int len, in_use; | |
9006 | ||
9007 | len = in_use = 0; | |
9008 | ||
9204e736 | 9009 | if (! INSN_P (insn) |
ddca68f8 | 9010 | || GET_CODE (PATTERN (insn)) == CLOBBER |
9011 | || GET_CODE (PATTERN (insn)) == USE) | |
9012 | goto next_and_done; | |
b9b4428b | 9013 | |
ddca68f8 | 9014 | while (1) |
b9b4428b | 9015 | { |
9016 | enum alphaev5_pipe pipe; | |
b9b4428b | 9017 | |
9018 | pipe = alphaev5_insn_pipe (insn); | |
9019 | switch (pipe) | |
9020 | { | |
9021 | case EV5_STOP: | |
9022 | /* Force complex instructions to start new groups. */ | |
9023 | if (in_use) | |
9024 | goto done; | |
9025 | ||
20833d12 | 9026 | /* If this is a completely unrecognized insn, it's an asm. |
b9b4428b | 9027 | We don't know how long it is, so record length as -1 to |
9028 | signal a needed realignment. */ | |
9029 | if (recog_memoized (insn) < 0) | |
9030 | len = -1; | |
9031 | else | |
9032 | len = get_attr_length (insn); | |
ddca68f8 | 9033 | goto next_and_done; |
b9b4428b | 9034 | |
4d10b463 | 9035 | /* ??? Most of the places below, we would like to assert never |
9036 | happen, as it would indicate an error either in Haifa, or | |
9037 | in the scheduling description. Unfortunately, Haifa never | |
9038 | schedules the last instruction of the BB, so we don't have | |
9039 | an accurate TI bit to go off. */ | |
b9b4428b | 9040 | case EV5_E01: |
9041 | if (in_use & EV5_E0) | |
9042 | { | |
9043 | if (in_use & EV5_E1) | |
9044 | goto done; | |
9045 | in_use |= EV5_E1; | |
9046 | } | |
9047 | else | |
9048 | in_use |= EV5_E0 | EV5_E01; | |
9049 | break; | |
9050 | ||
9051 | case EV5_E0: | |
9052 | if (in_use & EV5_E0) | |
9053 | { | |
849674a3 | 9054 | if (!(in_use & EV5_E01) || (in_use & EV5_E1)) |
b9b4428b | 9055 | goto done; |
9056 | in_use |= EV5_E1; | |
9057 | } | |
9058 | in_use |= EV5_E0; | |
9059 | break; | |
9060 | ||
9061 | case EV5_E1: | |
9062 | if (in_use & EV5_E1) | |
9063 | goto done; | |
9064 | in_use |= EV5_E1; | |
9065 | break; | |
9066 | ||
9067 | case EV5_FAM: | |
9068 | if (in_use & EV5_FA) | |
9069 | { | |
9070 | if (in_use & EV5_FM) | |
9071 | goto done; | |
9072 | in_use |= EV5_FM; | |
9073 | } | |
9074 | else | |
9075 | in_use |= EV5_FA | EV5_FAM; | |
9076 | break; | |
9077 | ||
9078 | case EV5_FA: | |
9079 | if (in_use & EV5_FA) | |
9080 | goto done; | |
9081 | in_use |= EV5_FA; | |
9082 | break; | |
9083 | ||
9084 | case EV5_FM: | |
9085 | if (in_use & EV5_FM) | |
9086 | goto done; | |
9087 | in_use |= EV5_FM; | |
9088 | break; | |
9089 | ||
9090 | case EV5_NONE: | |
9091 | break; | |
9092 | ||
9093 | default: | |
4d10b463 | 9094 | gcc_unreachable (); |
b9b4428b | 9095 | } |
9096 | len += 4; | |
9e7454d0 | 9097 | |
b9b4428b | 9098 | /* Haifa doesn't do well scheduling branches. */ |
9099 | /* ??? If this is predicted not-taken, slotting continues, except | |
9100 | that no more IBR, FBR, or JSR insns may be slotted. */ | |
c933fb42 | 9101 | if (JUMP_P (insn)) |
ddca68f8 | 9102 | goto next_and_done; |
b9b4428b | 9103 | |
ddca68f8 | 9104 | next: |
b9b4428b | 9105 | insn = next_nonnote_insn (insn); |
9106 | ||
9204e736 | 9107 | if (!insn || ! INSN_P (insn)) |
b9b4428b | 9108 | goto done; |
f9137da0 | 9109 | |
b9b4428b | 9110 | /* Let Haifa tell us where it thinks insn group boundaries are. */ |
9111 | if (GET_MODE (insn) == TImode) | |
9112 | goto done; | |
9113 | ||
ddca68f8 | 9114 | if (GET_CODE (insn) == CLOBBER || GET_CODE (insn) == USE) |
9115 | goto next; | |
b9b4428b | 9116 | } |
ddca68f8 | 9117 | |
9118 | next_and_done: | |
9119 | insn = next_nonnote_insn (insn); | |
b9b4428b | 9120 | |
9121 | done: | |
9122 | *plen = len; | |
9123 | *pin_use = in_use; | |
9124 | return insn; | |
b9b4428b | 9125 | } |
9126 | ||
849674a3 | 9127 | static rtx |
92643d95 | 9128 | alphaev4_next_nop (int *pin_use) |
849674a3 | 9129 | { |
9130 | int in_use = *pin_use; | |
9131 | rtx nop; | |
9132 | ||
9133 | if (!(in_use & EV4_IB0)) | |
9134 | { | |
9135 | in_use |= EV4_IB0; | |
9136 | nop = gen_nop (); | |
9137 | } | |
9138 | else if ((in_use & (EV4_IBX|EV4_IB1)) == EV4_IBX) | |
9139 | { | |
9140 | in_use |= EV4_IB1; | |
9141 | nop = gen_nop (); | |
9142 | } | |
9143 | else if (TARGET_FP && !(in_use & EV4_IB1)) | |
9144 | { | |
9145 | in_use |= EV4_IB1; | |
9146 | nop = gen_fnop (); | |
9147 | } | |
9148 | else | |
9149 | nop = gen_unop (); | |
9150 | ||
9151 | *pin_use = in_use; | |
9152 | return nop; | |
9153 | } | |
9154 | ||
9155 | static rtx | |
92643d95 | 9156 | alphaev5_next_nop (int *pin_use) |
849674a3 | 9157 | { |
9158 | int in_use = *pin_use; | |
9159 | rtx nop; | |
9160 | ||
9161 | if (!(in_use & EV5_E1)) | |
9162 | { | |
9163 | in_use |= EV5_E1; | |
9164 | nop = gen_nop (); | |
9165 | } | |
9166 | else if (TARGET_FP && !(in_use & EV5_FA)) | |
9167 | { | |
9168 | in_use |= EV5_FA; | |
9169 | nop = gen_fnop (); | |
9170 | } | |
9171 | else if (TARGET_FP && !(in_use & EV5_FM)) | |
9172 | { | |
9173 | in_use |= EV5_FM; | |
9174 | nop = gen_fnop (); | |
9175 | } | |
9176 | else | |
9177 | nop = gen_unop (); | |
9178 | ||
9179 | *pin_use = in_use; | |
9180 | return nop; | |
9181 | } | |
9182 | ||
9183 | /* The instruction group alignment main loop. */ | |
9184 | ||
b9b4428b | 9185 | static void |
b80c91bc | 9186 | alpha_align_insns_1 (unsigned int max_align, |
7f0256ea | 9187 | rtx_insn *(*next_group) (rtx_insn *, int *, int *), |
b80c91bc | 9188 | rtx (*next_nop) (int *)) |
b9b4428b | 9189 | { |
9190 | /* ALIGN is the known alignment for the insn group. */ | |
b53f315c | 9191 | unsigned int align; |
b9b4428b | 9192 | /* OFS is the offset of the current insn in the insn group. */ |
9193 | int ofs; | |
fd1ace94 | 9194 | int prev_in_use, in_use, len, ldgp; |
7f0256ea | 9195 | rtx_insn *i, *next; |
b9b4428b | 9196 | |
9197 | /* Let shorten branches care for assigning alignments to code labels. */ | |
2efea8c0 | 9198 | shorten_branches (get_insns ()); |
b9b4428b | 9199 | |
d815ce59 | 9200 | if (align_functions < 4) |
9201 | align = 4; | |
eeca3ba1 | 9202 | else if ((unsigned int) align_functions < max_align) |
d815ce59 | 9203 | align = align_functions; |
9204 | else | |
9205 | align = max_align; | |
e2c8a34a | 9206 | |
b9b4428b | 9207 | ofs = prev_in_use = 0; |
2efea8c0 | 9208 | i = get_insns (); |
c933fb42 | 9209 | if (NOTE_P (i)) |
b9b4428b | 9210 | i = next_nonnote_insn (i); |
9211 | ||
fd1ace94 | 9212 | ldgp = alpha_function_needs_gp ? 8 : 0; |
9213 | ||
b9b4428b | 9214 | while (i) |
9215 | { | |
b53f315c | 9216 | next = (*next_group) (i, &in_use, &len); |
b9b4428b | 9217 | |
9218 | /* When we see a label, resync alignment etc. */ | |
c933fb42 | 9219 | if (LABEL_P (i)) |
b9b4428b | 9220 | { |
b53f315c | 9221 | unsigned int new_align = 1 << label_to_alignment (i); |
9222 | ||
b9b4428b | 9223 | if (new_align >= align) |
9224 | { | |
849674a3 | 9225 | align = new_align < max_align ? new_align : max_align; |
b9b4428b | 9226 | ofs = 0; |
9227 | } | |
b53f315c | 9228 | |
b9b4428b | 9229 | else if (ofs & (new_align-1)) |
9230 | ofs = (ofs | (new_align-1)) + 1; | |
4d10b463 | 9231 | gcc_assert (!len); |
b9b4428b | 9232 | } |
9233 | ||
9234 | /* Handle complex instructions special. */ | |
9235 | else if (in_use == 0) | |
9236 | { | |
9237 | /* Asms will have length < 0. This is a signal that we have | |
9238 | lost alignment knowledge. Assume, however, that the asm | |
9239 | will not mis-align instructions. */ | |
9240 | if (len < 0) | |
9241 | { | |
9242 | ofs = 0; | |
9243 | align = 4; | |
9244 | len = 0; | |
9245 | } | |
9246 | } | |
9247 | ||
9248 | /* If the known alignment is smaller than the recognized insn group, | |
9249 | realign the output. */ | |
1f0ce6a6 | 9250 | else if ((int) align < len) |
b9b4428b | 9251 | { |
b53f315c | 9252 | unsigned int new_log_align = len > 8 ? 4 : 3; |
7f0256ea | 9253 | rtx_insn *prev, *where; |
b9b4428b | 9254 | |
943a1b57 | 9255 | where = prev = prev_nonnote_insn (i); |
c933fb42 | 9256 | if (!where || !LABEL_P (where)) |
b9b4428b | 9257 | where = i; |
9258 | ||
943a1b57 | 9259 | /* Can't realign between a call and its gp reload. */ |
9260 | if (! (TARGET_EXPLICIT_RELOCS | |
c933fb42 | 9261 | && prev && CALL_P (prev))) |
943a1b57 | 9262 | { |
9263 | emit_insn_before (gen_realign (GEN_INT (new_log_align)), where); | |
9264 | align = 1 << new_log_align; | |
9265 | ofs = 0; | |
9266 | } | |
b9b4428b | 9267 | } |
9268 | ||
fd1ace94 | 9269 | /* We may not insert padding inside the initial ldgp sequence. */ |
9270 | else if (ldgp > 0) | |
9271 | ldgp -= len; | |
9272 | ||
b9b4428b | 9273 | /* If the group won't fit in the same INT16 as the previous, |
9274 | we need to add padding to keep the group together. Rather | |
9275 | than simply leaving the insn filling to the assembler, we | |
9276 | can make use of the knowledge of what sorts of instructions | |
9277 | were issued in the previous group to make sure that all of | |
9278 | the added nops are really free. */ | |
1f0ce6a6 | 9279 | else if (ofs + len > (int) align) |
b9b4428b | 9280 | { |
9281 | int nop_count = (align - ofs) / 4; | |
7f0256ea | 9282 | rtx_insn *where; |
b9b4428b | 9283 | |
efee20da | 9284 | /* Insert nops before labels, branches, and calls to truly merge |
943a1b57 | 9285 | the execution of the nops with the previous instruction group. */ |
b9b4428b | 9286 | where = prev_nonnote_insn (i); |
849674a3 | 9287 | if (where) |
b9b4428b | 9288 | { |
c933fb42 | 9289 | if (LABEL_P (where)) |
b9b4428b | 9290 | { |
7f0256ea | 9291 | rtx_insn *where2 = prev_nonnote_insn (where); |
c933fb42 | 9292 | if (where2 && JUMP_P (where2)) |
849674a3 | 9293 | where = where2; |
b9b4428b | 9294 | } |
c933fb42 | 9295 | else if (NONJUMP_INSN_P (where)) |
849674a3 | 9296 | where = i; |
b9b4428b | 9297 | } |
849674a3 | 9298 | else |
9299 | where = i; | |
9300 | ||
9e7454d0 | 9301 | do |
849674a3 | 9302 | emit_insn_before ((*next_nop)(&prev_in_use), where); |
b9b4428b | 9303 | while (--nop_count); |
9304 | ofs = 0; | |
9305 | } | |
9306 | ||
9307 | ofs = (ofs + len) & (align - 1); | |
9308 | prev_in_use = in_use; | |
9309 | i = next; | |
9310 | } | |
9311 | } | |
a27deefc | 9312 | |
b80c91bc | 9313 | static void |
9314 | alpha_align_insns (void) | |
9315 | { | |
9316 | if (alpha_tune == PROCESSOR_EV4) | |
9317 | alpha_align_insns_1 (8, alphaev4_next_group, alphaev4_next_nop); | |
9318 | else if (alpha_tune == PROCESSOR_EV5) | |
9319 | alpha_align_insns_1 (16, alphaev5_next_group, alphaev5_next_nop); | |
9320 | else | |
9321 | gcc_unreachable (); | |
9322 | } | |
9323 | ||
0578f206 | 9324 | /* Insert an unop between sibcall or noreturn function call and GP load. */ |
a27deefc | 9325 | |
9326 | static void | |
0578f206 | 9327 | alpha_pad_function_end (void) |
a27deefc | 9328 | { |
7f0256ea | 9329 | rtx_insn *insn, *next; |
a27deefc | 9330 | |
9331 | for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) | |
9332 | { | |
60f629bc | 9333 | if (!CALL_P (insn) |
9334 | || !(SIBLING_CALL_P (insn) | |
9335 | || find_reg_note (insn, REG_NORETURN, NULL_RTX))) | |
a27deefc | 9336 | continue; |
9337 | ||
38557452 | 9338 | /* Make sure we do not split a call and its corresponding |
9339 | CALL_ARG_LOCATION note. */ | |
60f629bc | 9340 | next = NEXT_INSN (insn); |
9341 | if (next == NULL) | |
9342 | continue; | |
60f629bc | 9343 | if (NOTE_P (next) && NOTE_KIND (next) == NOTE_INSN_CALL_ARG_LOCATION) |
9344 | insn = next; | |
38557452 | 9345 | |
a27deefc | 9346 | next = next_active_insn (insn); |
a27deefc | 9347 | if (next) |
9348 | { | |
9349 | rtx pat = PATTERN (next); | |
9350 | ||
9351 | if (GET_CODE (pat) == SET | |
9352 | && GET_CODE (SET_SRC (pat)) == UNSPEC_VOLATILE | |
9353 | && XINT (SET_SRC (pat), 1) == UNSPECV_LDGP1) | |
9354 | emit_insn_after (gen_unop (), insn); | |
9355 | } | |
9356 | } | |
9357 | } | |
b9b4428b | 9358 | \f |
35a3065a | 9359 | /* Machine dependent reorg pass. */ |
18adf4f6 | 9360 | |
2efea8c0 | 9361 | static void |
92643d95 | 9362 | alpha_reorg (void) |
18adf4f6 | 9363 | { |
0578f206 | 9364 | /* Workaround for a linker error that triggers when an exception |
9365 | handler immediatelly follows a sibcall or a noreturn function. | |
9366 | ||
9367 | In the sibcall case: | |
9368 | ||
9369 | The instruction stream from an object file: | |
9370 | ||
9371 | 1d8: 00 00 fb 6b jmp (t12) | |
9372 | 1dc: 00 00 ba 27 ldah gp,0(ra) | |
9373 | 1e0: 00 00 bd 23 lda gp,0(gp) | |
9374 | 1e4: 00 00 7d a7 ldq t12,0(gp) | |
9375 | 1e8: 00 40 5b 6b jsr ra,(t12),1ec <__funcZ+0x1ec> | |
9376 | ||
9377 | was converted in the final link pass to: | |
9378 | ||
9379 | 12003aa88: 67 fa ff c3 br 120039428 <...> | |
9380 | 12003aa8c: 00 00 fe 2f unop | |
9381 | 12003aa90: 00 00 fe 2f unop | |
9382 | 12003aa94: 48 83 7d a7 ldq t12,-31928(gp) | |
9383 | 12003aa98: 00 40 5b 6b jsr ra,(t12),12003aa9c <__func+0x1ec> | |
9384 | ||
9385 | And in the noreturn case: | |
a27deefc | 9386 | |
9387 | The instruction stream from an object file: | |
9388 | ||
9389 | 54: 00 40 5b 6b jsr ra,(t12),58 <__func+0x58> | |
9390 | 58: 00 00 ba 27 ldah gp,0(ra) | |
9391 | 5c: 00 00 bd 23 lda gp,0(gp) | |
9392 | 60: 00 00 7d a7 ldq t12,0(gp) | |
9393 | 64: 00 40 5b 6b jsr ra,(t12),68 <__func+0x68> | |
9394 | ||
9395 | was converted in the final link pass to: | |
9396 | ||
9397 | fdb24: a0 03 40 d3 bsr ra,fe9a8 <_called_func+0x8> | |
9398 | fdb28: 00 00 fe 2f unop | |
9399 | fdb2c: 00 00 fe 2f unop | |
9400 | fdb30: 30 82 7d a7 ldq t12,-32208(gp) | |
9401 | fdb34: 00 40 5b 6b jsr ra,(t12),fdb38 <__func+0x68> | |
9402 | ||
9403 | GP load instructions were wrongly cleared by the linker relaxation | |
9404 | pass. This workaround prevents removal of GP loads by inserting | |
0578f206 | 9405 | an unop instruction between a sibcall or noreturn function call and |
a27deefc | 9406 | exception handler prologue. */ |
9407 | ||
9408 | if (current_function_has_exception_handlers ()) | |
0578f206 | 9409 | alpha_pad_function_end (); |
18adf4f6 | 9410 | } |
18adf4f6 | 9411 | \f |
92c473b8 | 9412 | static void |
9413 | alpha_file_start (void) | |
9414 | { | |
9415 | default_file_start (); | |
92c473b8 | 9416 | |
9417 | fputs ("\t.set noreorder\n", asm_out_file); | |
9418 | fputs ("\t.set volatile\n", asm_out_file); | |
4505d022 | 9419 | if (TARGET_ABI_OSF) |
92c473b8 | 9420 | fputs ("\t.set noat\n", asm_out_file); |
9421 | if (TARGET_EXPLICIT_RELOCS) | |
9422 | fputs ("\t.set nomacro\n", asm_out_file); | |
9423 | if (TARGET_SUPPORT_ARCH | TARGET_BWX | TARGET_MAX | TARGET_FIX | TARGET_CIX) | |
fb64edde | 9424 | { |
9425 | const char *arch; | |
9426 | ||
9427 | if (alpha_cpu == PROCESSOR_EV6 || TARGET_FIX || TARGET_CIX) | |
9428 | arch = "ev6"; | |
9429 | else if (TARGET_MAX) | |
9430 | arch = "pca56"; | |
9431 | else if (TARGET_BWX) | |
9432 | arch = "ev56"; | |
9433 | else if (alpha_cpu == PROCESSOR_EV5) | |
9434 | arch = "ev5"; | |
9435 | else | |
9436 | arch = "ev4"; | |
9437 | ||
9438 | fprintf (asm_out_file, "\t.arch %s\n", arch); | |
9439 | } | |
92c473b8 | 9440 | } |
92c473b8 | 9441 | |
4e151b05 | 9442 | /* Since we don't have a .dynbss section, we should not allow global |
9443 | relocations in the .rodata section. */ | |
9444 | ||
9445 | static int | |
9446 | alpha_elf_reloc_rw_mask (void) | |
9447 | { | |
9448 | return flag_pic ? 3 : 2; | |
9449 | } | |
bbfbe351 | 9450 | |
2f14b1f9 | 9451 | /* Return a section for X. The only special thing we do here is to |
9452 | honor small data. */ | |
bbfbe351 | 9453 | |
2f14b1f9 | 9454 | static section * |
3754d046 | 9455 | alpha_elf_select_rtx_section (machine_mode mode, rtx x, |
92643d95 | 9456 | unsigned HOST_WIDE_INT align) |
bbfbe351 | 9457 | { |
9458 | if (TARGET_SMALL_DATA && GET_MODE_SIZE (mode) <= g_switch_value) | |
5910bb95 | 9459 | /* ??? Consider using mergeable sdata sections. */ |
2f14b1f9 | 9460 | return sdata_section; |
bbfbe351 | 9461 | else |
2f14b1f9 | 9462 | return default_elf_select_rtx_section (mode, x, align); |
bbfbe351 | 9463 | } |
9464 | ||
cc2af183 | 9465 | static unsigned int |
9466 | alpha_elf_section_type_flags (tree decl, const char *name, int reloc) | |
9467 | { | |
9468 | unsigned int flags = 0; | |
9469 | ||
9470 | if (strcmp (name, ".sdata") == 0 | |
9471 | || strncmp (name, ".sdata.", 7) == 0 | |
9472 | || strncmp (name, ".gnu.linkonce.s.", 16) == 0 | |
9473 | || strcmp (name, ".sbss") == 0 | |
9474 | || strncmp (name, ".sbss.", 6) == 0 | |
9475 | || strncmp (name, ".gnu.linkonce.sb.", 17) == 0) | |
9476 | flags = SECTION_SMALL; | |
9477 | ||
9478 | flags |= default_section_type_flags (decl, name, reloc); | |
9479 | return flags; | |
9480 | } | |
bbfbe351 | 9481 | \f |
9de382d9 | 9482 | /* Structure to collect function names for final output in link section. */ |
9483 | /* Note that items marked with GTY can't be ifdef'ed out. */ | |
573aba85 | 9484 | |
5ce94904 | 9485 | enum reloc_kind |
9486 | { | |
9487 | KIND_LINKAGE, | |
9488 | KIND_CODEADDR | |
9489 | }; | |
573aba85 | 9490 | |
fb1e4f4a | 9491 | struct GTY(()) alpha_links |
573aba85 | 9492 | { |
5ce94904 | 9493 | rtx func; |
573aba85 | 9494 | rtx linkage; |
9de382d9 | 9495 | enum reloc_kind rkind; |
9496 | }; | |
9497 | ||
1467e953 | 9498 | #if TARGET_ABI_OPEN_VMS |
8df4a58b | 9499 | |
0dbd1c74 | 9500 | /* Return the VMS argument type corresponding to MODE. */ |
8df4a58b | 9501 | |
0dbd1c74 | 9502 | enum avms_arg_type |
3754d046 | 9503 | alpha_arg_type (machine_mode mode) |
0dbd1c74 | 9504 | { |
9505 | switch (mode) | |
8df4a58b | 9506 | { |
0dbd1c74 | 9507 | case SFmode: |
9508 | return TARGET_FLOAT_VAX ? FF : FS; | |
9509 | case DFmode: | |
9510 | return TARGET_FLOAT_VAX ? FD : FT; | |
9511 | default: | |
9512 | return I64; | |
8df4a58b | 9513 | } |
0dbd1c74 | 9514 | } |
8df4a58b | 9515 | |
0dbd1c74 | 9516 | /* Return an rtx for an integer representing the VMS Argument Information |
9517 | register value. */ | |
8df4a58b | 9518 | |
1dd6c958 | 9519 | rtx |
92643d95 | 9520 | alpha_arg_info_reg_val (CUMULATIVE_ARGS cum) |
0dbd1c74 | 9521 | { |
9522 | unsigned HOST_WIDE_INT regval = cum.num_args; | |
9523 | int i; | |
8df4a58b | 9524 | |
0dbd1c74 | 9525 | for (i = 0; i < 6; i++) |
9526 | regval |= ((int) cum.atypes[i]) << (i * 3 + 8); | |
8df4a58b | 9527 | |
0dbd1c74 | 9528 | return GEN_INT (regval); |
9529 | } | |
9530 | \f | |
8df4a58b | 9531 | |
c45d3ddf | 9532 | /* Return a SYMBOL_REF representing the reference to the .linkage entry |
9533 | of function FUNC built for calls made from CFUNDECL. LFLAG is 1 if | |
9534 | this is the reference to the linkage pointer value, 0 if this is the | |
9535 | reference to the function entry value. RFLAG is 1 if this a reduced | |
9536 | reference (code address only), 0 if this is a full reference. */ | |
9537 | ||
cf73d31f | 9538 | rtx |
5ce94904 | 9539 | alpha_use_linkage (rtx func, bool lflag, bool rflag) |
cf73d31f | 9540 | { |
5ce94904 | 9541 | struct alpha_links *al = NULL; |
c45d3ddf | 9542 | const char *name = XSTR (func, 0); |
cf73d31f | 9543 | |
5ce94904 | 9544 | if (cfun->machine->links) |
cf73d31f | 9545 | { |
cf73d31f | 9546 | /* Is this name already defined? */ |
1ddffe86 | 9547 | alpha_links **slot = cfun->machine->links->get (name); |
d4786b13 | 9548 | if (slot) |
9549 | al = *slot; | |
cf73d31f | 9550 | } |
9551 | else | |
d4786b13 | 9552 | cfun->machine->links |
9553 | = hash_map<const char *, alpha_links *, string_traits>::create_ggc (64); | |
cf73d31f | 9554 | |
5ce94904 | 9555 | if (al == NULL) |
cf73d31f | 9556 | { |
5ce94904 | 9557 | size_t buf_len; |
cf73d31f | 9558 | char *linksym; |
47544e52 | 9559 | tree id; |
cf73d31f | 9560 | |
9561 | if (name[0] == '*') | |
9562 | name++; | |
9563 | ||
47544e52 | 9564 | /* Follow transparent alias, as this is used for CRTL translations. */ |
9565 | id = maybe_get_identifier (name); | |
9566 | if (id) | |
9567 | { | |
9568 | while (IDENTIFIER_TRANSPARENT_ALIAS (id)) | |
9569 | id = TREE_CHAIN (id); | |
9570 | name = IDENTIFIER_POINTER (id); | |
9571 | } | |
9572 | ||
5ce94904 | 9573 | buf_len = strlen (name) + 8 + 9; |
9574 | linksym = (char *) alloca (buf_len); | |
9575 | snprintf (linksym, buf_len, "$%d..%s..lk", cfun->funcdef_no, name); | |
cf73d31f | 9576 | |
25a27413 | 9577 | al = ggc_alloc<alpha_links> (); |
5ce94904 | 9578 | al->func = func; |
9579 | al->linkage = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (linksym)); | |
cf73d31f | 9580 | |
d4786b13 | 9581 | cfun->machine->links->put (ggc_strdup (name), al); |
cf73d31f | 9582 | } |
9583 | ||
5ce94904 | 9584 | al->rkind = rflag ? KIND_CODEADDR : KIND_LINKAGE; |
9e7454d0 | 9585 | |
cf73d31f | 9586 | if (lflag) |
29c05e22 | 9587 | return gen_rtx_MEM (Pmode, plus_constant (Pmode, al->linkage, 8)); |
cf73d31f | 9588 | else |
9589 | return al->linkage; | |
9590 | } | |
9591 | ||
57e47080 | 9592 | static int |
1ddffe86 | 9593 | alpha_write_one_linkage (const char *name, alpha_links *link, FILE *stream) |
57e47080 | 9594 | { |
5ce94904 | 9595 | ASM_OUTPUT_INTERNAL_LABEL (stream, XSTR (link->linkage, 0)); |
cf73d31f | 9596 | if (link->rkind == KIND_CODEADDR) |
57e47080 | 9597 | { |
5ce94904 | 9598 | /* External and used, request code address. */ |
47544e52 | 9599 | fprintf (stream, "\t.code_address "); |
57e47080 | 9600 | } |
9601 | else | |
9602 | { | |
5ce94904 | 9603 | if (!SYMBOL_REF_EXTERNAL_P (link->func) |
9604 | && SYMBOL_REF_LOCAL_P (link->func)) | |
cf73d31f | 9605 | { |
5ce94904 | 9606 | /* Locally defined, build linkage pair. */ |
cf73d31f | 9607 | fprintf (stream, "\t.quad %s..en\n", name); |
47544e52 | 9608 | fprintf (stream, "\t.quad "); |
cf73d31f | 9609 | } |
9610 | else | |
9611 | { | |
5ce94904 | 9612 | /* External, request linkage pair. */ |
47544e52 | 9613 | fprintf (stream, "\t.linkage "); |
cf73d31f | 9614 | } |
57e47080 | 9615 | } |
47544e52 | 9616 | assemble_name (stream, name); |
9617 | fputs ("\n", stream); | |
57e47080 | 9618 | |
9619 | return 0; | |
9620 | } | |
8df4a58b | 9621 | |
cf73d31f | 9622 | static void |
5ce94904 | 9623 | alpha_write_linkage (FILE *stream, const char *funname) |
8df4a58b | 9624 | { |
2f14b1f9 | 9625 | fprintf (stream, "\t.link\n"); |
cf73d31f | 9626 | fprintf (stream, "\t.align 3\n"); |
2f14b1f9 | 9627 | in_section = NULL; |
9628 | ||
5ce94904 | 9629 | #ifdef TARGET_VMS_CRASH_DEBUG |
cf73d31f | 9630 | fputs ("\t.name ", stream); |
9631 | assemble_name (stream, funname); | |
9632 | fputs ("..na\n", stream); | |
5ce94904 | 9633 | #endif |
9634 | ||
cf73d31f | 9635 | ASM_OUTPUT_LABEL (stream, funname); |
9636 | fprintf (stream, "\t.pdesc "); | |
9637 | assemble_name (stream, funname); | |
9638 | fprintf (stream, "..en,%s\n", | |
9639 | alpha_procedure_type == PT_STACK ? "stack" | |
9640 | : alpha_procedure_type == PT_REGISTER ? "reg" : "null"); | |
9641 | ||
5ce94904 | 9642 | if (cfun->machine->links) |
c64a8830 | 9643 | { |
d4786b13 | 9644 | hash_map<const char *, alpha_links *, string_traits>::iterator iter |
9645 | = cfun->machine->links->begin (); | |
9646 | for (; iter != cfun->machine->links->end (); ++iter) | |
9647 | alpha_write_one_linkage ((*iter).first, (*iter).second, stream); | |
c64a8830 | 9648 | } |
8df4a58b | 9649 | } |
9650 | ||
2cb4ac60 | 9651 | /* Switch to an arbitrary section NAME with attributes as specified |
9652 | by FLAGS. ALIGN specifies any known alignment requirements for | |
9653 | the section; 0 if the default should be used. */ | |
9654 | ||
9655 | static void | |
537cd941 | 9656 | vms_asm_named_section (const char *name, unsigned int flags, |
9657 | tree decl ATTRIBUTE_UNUSED) | |
2cb4ac60 | 9658 | { |
c64a8830 | 9659 | fputc ('\n', asm_out_file); |
9660 | fprintf (asm_out_file, ".section\t%s", name); | |
2cb4ac60 | 9661 | |
c64a8830 | 9662 | if (flags & SECTION_DEBUG) |
9663 | fprintf (asm_out_file, ",NOWRT"); | |
9664 | ||
9665 | fputc ('\n', asm_out_file); | |
2cb4ac60 | 9666 | } |
9667 | ||
01d15dc5 | 9668 | /* Record an element in the table of global constructors. SYMBOL is |
9669 | a SYMBOL_REF of the function to be called; PRIORITY is a number | |
9e7454d0 | 9670 | between 0 and MAX_INIT_PRIORITY. |
01d15dc5 | 9671 | |
9672 | Differs from default_ctors_section_asm_out_constructor in that the | |
9673 | width of the .ctors entry is always 64 bits, rather than the 32 bits | |
9674 | used by a normal pointer. */ | |
9675 | ||
9676 | static void | |
92643d95 | 9677 | vms_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED) |
01d15dc5 | 9678 | { |
2f14b1f9 | 9679 | switch_to_section (ctors_section); |
09d688ff | 9680 | assemble_align (BITS_PER_WORD); |
9681 | assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1); | |
01d15dc5 | 9682 | } |
9683 | ||
9684 | static void | |
92643d95 | 9685 | vms_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED) |
01d15dc5 | 9686 | { |
2f14b1f9 | 9687 | switch_to_section (dtors_section); |
09d688ff | 9688 | assemble_align (BITS_PER_WORD); |
9689 | assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1); | |
01d15dc5 | 9690 | } |
8df4a58b | 9691 | #else |
cf73d31f | 9692 | rtx |
c45d3ddf | 9693 | alpha_use_linkage (rtx func ATTRIBUTE_UNUSED, |
5ce94904 | 9694 | bool lflag ATTRIBUTE_UNUSED, |
9695 | bool rflag ATTRIBUTE_UNUSED) | |
cf73d31f | 9696 | { |
9697 | return NULL_RTX; | |
9698 | } | |
9699 | ||
1467e953 | 9700 | #endif /* TARGET_ABI_OPEN_VMS */ |
9caef960 | 9701 | \f |
f2f543a3 | 9702 | static void |
9703 | alpha_init_libfuncs (void) | |
9704 | { | |
04d75965 | 9705 | if (TARGET_ABI_OPEN_VMS) |
f2f543a3 | 9706 | { |
9707 | /* Use the VMS runtime library functions for division and | |
9708 | remainder. */ | |
9709 | set_optab_libfunc (sdiv_optab, SImode, "OTS$DIV_I"); | |
9710 | set_optab_libfunc (sdiv_optab, DImode, "OTS$DIV_L"); | |
9711 | set_optab_libfunc (udiv_optab, SImode, "OTS$DIV_UI"); | |
9712 | set_optab_libfunc (udiv_optab, DImode, "OTS$DIV_UL"); | |
9713 | set_optab_libfunc (smod_optab, SImode, "OTS$REM_I"); | |
9714 | set_optab_libfunc (smod_optab, DImode, "OTS$REM_L"); | |
9715 | set_optab_libfunc (umod_optab, SImode, "OTS$REM_UI"); | |
9716 | set_optab_libfunc (umod_optab, DImode, "OTS$REM_UL"); | |
2db66e7c | 9717 | abort_libfunc = init_one_libfunc ("decc$abort"); |
9718 | memcmp_libfunc = init_one_libfunc ("decc$memcmp"); | |
9719 | #ifdef MEM_LIBFUNCS_INIT | |
9720 | MEM_LIBFUNCS_INIT; | |
9721 | #endif | |
f2f543a3 | 9722 | } |
9723 | } | |
9724 | ||
b2d7ede1 | 9725 | /* On the Alpha, we use this to disable the floating-point registers |
9726 | when they don't exist. */ | |
9727 | ||
9728 | static void | |
9729 | alpha_conditional_register_usage (void) | |
9730 | { | |
9731 | int i; | |
9732 | if (! TARGET_FPREGS) | |
9733 | for (i = 32; i < 63; i++) | |
9734 | fixed_regs[i] = call_used_regs[i] = 1; | |
9735 | } | |
d5065e6e | 9736 | |
9737 | /* Canonicalize a comparison from one we don't have to one we do have. */ | |
9738 | ||
9739 | static void | |
9740 | alpha_canonicalize_comparison (int *code, rtx *op0, rtx *op1, | |
9741 | bool op0_preserve_value) | |
9742 | { | |
9743 | if (!op0_preserve_value | |
9744 | && (*code == GE || *code == GT || *code == GEU || *code == GTU) | |
9745 | && (REG_P (*op1) || *op1 == const0_rtx)) | |
9746 | { | |
9747 | rtx tem = *op0; | |
9748 | *op0 = *op1; | |
9749 | *op1 = tem; | |
9750 | *code = (int)swap_condition ((enum rtx_code)*code); | |
9751 | } | |
9752 | ||
9753 | if ((*code == LT || *code == LTU) | |
9754 | && CONST_INT_P (*op1) && INTVAL (*op1) == 256) | |
9755 | { | |
9756 | *code = *code == LT ? LE : LEU; | |
9757 | *op1 = GEN_INT (255); | |
9758 | } | |
9759 | } | |
175a5f5f | 9760 | |
9761 | /* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV. */ | |
9762 | ||
9763 | static void | |
9764 | alpha_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) | |
9765 | { | |
9766 | const unsigned HOST_WIDE_INT SWCR_STATUS_MASK = (0x3fUL << 17); | |
9767 | ||
9768 | tree fenv_var, get_fpscr, set_fpscr, mask, ld_fenv, masked_fenv; | |
9769 | tree new_fenv_var, reload_fenv, restore_fnenv; | |
9770 | tree update_call, atomic_feraiseexcept, hold_fnclex; | |
9771 | ||
9772 | /* Assume OSF/1 compatible interfaces. */ | |
9773 | if (!TARGET_ABI_OSF) | |
9774 | return; | |
9775 | ||
9776 | /* Generate the equivalent of : | |
9777 | unsigned long fenv_var; | |
9778 | fenv_var = __ieee_get_fp_control (); | |
9779 | ||
9780 | unsigned long masked_fenv; | |
9781 | masked_fenv = fenv_var & mask; | |
9782 | ||
9783 | __ieee_set_fp_control (masked_fenv); */ | |
9784 | ||
98cfaaca | 9785 | fenv_var = create_tmp_var (long_unsigned_type_node); |
175a5f5f | 9786 | get_fpscr |
9787 | = build_fn_decl ("__ieee_get_fp_control", | |
9788 | build_function_type_list (long_unsigned_type_node, NULL)); | |
9789 | set_fpscr | |
9790 | = build_fn_decl ("__ieee_set_fp_control", | |
9791 | build_function_type_list (void_type_node, NULL)); | |
9792 | mask = build_int_cst (long_unsigned_type_node, ~SWCR_STATUS_MASK); | |
9793 | ld_fenv = build2 (MODIFY_EXPR, long_unsigned_type_node, | |
9794 | fenv_var, build_call_expr (get_fpscr, 0)); | |
9795 | masked_fenv = build2 (BIT_AND_EXPR, long_unsigned_type_node, fenv_var, mask); | |
9796 | hold_fnclex = build_call_expr (set_fpscr, 1, masked_fenv); | |
9797 | *hold = build2 (COMPOUND_EXPR, void_type_node, | |
9798 | build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv), | |
9799 | hold_fnclex); | |
9800 | ||
9801 | /* Store the value of masked_fenv to clear the exceptions: | |
9802 | __ieee_set_fp_control (masked_fenv); */ | |
9803 | ||
9804 | *clear = build_call_expr (set_fpscr, 1, masked_fenv); | |
9805 | ||
9806 | /* Generate the equivalent of : | |
9807 | unsigned long new_fenv_var; | |
9808 | new_fenv_var = __ieee_get_fp_control (); | |
9809 | ||
9810 | __ieee_set_fp_control (fenv_var); | |
9811 | ||
9812 | __atomic_feraiseexcept (new_fenv_var); */ | |
9813 | ||
98cfaaca | 9814 | new_fenv_var = create_tmp_var (long_unsigned_type_node); |
175a5f5f | 9815 | reload_fenv = build2 (MODIFY_EXPR, long_unsigned_type_node, new_fenv_var, |
9816 | build_call_expr (get_fpscr, 0)); | |
9817 | restore_fnenv = build_call_expr (set_fpscr, 1, fenv_var); | |
9818 | atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT); | |
9819 | update_call | |
9820 | = build_call_expr (atomic_feraiseexcept, 1, | |
9821 | fold_convert (integer_type_node, new_fenv_var)); | |
9822 | *update = build2 (COMPOUND_EXPR, void_type_node, | |
9823 | build2 (COMPOUND_EXPR, void_type_node, | |
9824 | reload_fenv, restore_fnenv), update_call); | |
9825 | } | |
92643d95 | 9826 | \f |
9827 | /* Initialize the GCC target structure. */ | |
9828 | #if TARGET_ABI_OPEN_VMS | |
9829 | # undef TARGET_ATTRIBUTE_TABLE | |
9830 | # define TARGET_ATTRIBUTE_TABLE vms_attribute_table | |
cd90919d | 9831 | # undef TARGET_CAN_ELIMINATE |
9832 | # define TARGET_CAN_ELIMINATE alpha_vms_can_eliminate | |
92643d95 | 9833 | #endif |
9834 | ||
9835 | #undef TARGET_IN_SMALL_DATA_P | |
9836 | #define TARGET_IN_SMALL_DATA_P alpha_in_small_data_p | |
9837 | ||
92643d95 | 9838 | #undef TARGET_ASM_ALIGNED_HI_OP |
9839 | #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" | |
9840 | #undef TARGET_ASM_ALIGNED_DI_OP | |
9841 | #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" | |
9842 | ||
9843 | /* Default unaligned ops are provided for ELF systems. To get unaligned | |
9844 | data for non-ELF systems, we have to turn off auto alignment. */ | |
48a5030b | 9845 | #if TARGET_ABI_OPEN_VMS |
92643d95 | 9846 | #undef TARGET_ASM_UNALIGNED_HI_OP |
9847 | #define TARGET_ASM_UNALIGNED_HI_OP "\t.align 0\n\t.word\t" | |
9848 | #undef TARGET_ASM_UNALIGNED_SI_OP | |
9849 | #define TARGET_ASM_UNALIGNED_SI_OP "\t.align 0\n\t.long\t" | |
9850 | #undef TARGET_ASM_UNALIGNED_DI_OP | |
9851 | #define TARGET_ASM_UNALIGNED_DI_OP "\t.align 0\n\t.quad\t" | |
9852 | #endif | |
9853 | ||
4e151b05 | 9854 | #undef TARGET_ASM_RELOC_RW_MASK |
9855 | #define TARGET_ASM_RELOC_RW_MASK alpha_elf_reloc_rw_mask | |
92643d95 | 9856 | #undef TARGET_ASM_SELECT_RTX_SECTION |
9857 | #define TARGET_ASM_SELECT_RTX_SECTION alpha_elf_select_rtx_section | |
cc2af183 | 9858 | #undef TARGET_SECTION_TYPE_FLAGS |
9859 | #define TARGET_SECTION_TYPE_FLAGS alpha_elf_section_type_flags | |
92643d95 | 9860 | |
9861 | #undef TARGET_ASM_FUNCTION_END_PROLOGUE | |
9862 | #define TARGET_ASM_FUNCTION_END_PROLOGUE alpha_output_function_end_prologue | |
9863 | ||
f2f543a3 | 9864 | #undef TARGET_INIT_LIBFUNCS |
9865 | #define TARGET_INIT_LIBFUNCS alpha_init_libfuncs | |
9866 | ||
41e3a0c7 | 9867 | #undef TARGET_LEGITIMIZE_ADDRESS |
9868 | #define TARGET_LEGITIMIZE_ADDRESS alpha_legitimize_address | |
649bdf00 | 9869 | #undef TARGET_MODE_DEPENDENT_ADDRESS_P |
9870 | #define TARGET_MODE_DEPENDENT_ADDRESS_P alpha_mode_dependent_address_p | |
41e3a0c7 | 9871 | |
92c473b8 | 9872 | #undef TARGET_ASM_FILE_START |
9873 | #define TARGET_ASM_FILE_START alpha_file_start | |
92c473b8 | 9874 | |
92643d95 | 9875 | #undef TARGET_SCHED_ADJUST_COST |
9876 | #define TARGET_SCHED_ADJUST_COST alpha_adjust_cost | |
9877 | #undef TARGET_SCHED_ISSUE_RATE | |
9878 | #define TARGET_SCHED_ISSUE_RATE alpha_issue_rate | |
92643d95 | 9879 | #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD |
9880 | #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \ | |
9881 | alpha_multipass_dfa_lookahead | |
9882 | ||
9883 | #undef TARGET_HAVE_TLS | |
9884 | #define TARGET_HAVE_TLS HAVE_AS_TLS | |
9885 | ||
bad4fb18 | 9886 | #undef TARGET_BUILTIN_DECL |
9887 | #define TARGET_BUILTIN_DECL alpha_builtin_decl | |
92643d95 | 9888 | #undef TARGET_INIT_BUILTINS |
9889 | #define TARGET_INIT_BUILTINS alpha_init_builtins | |
9890 | #undef TARGET_EXPAND_BUILTIN | |
9891 | #define TARGET_EXPAND_BUILTIN alpha_expand_builtin | |
849c7bc6 | 9892 | #undef TARGET_FOLD_BUILTIN |
9893 | #define TARGET_FOLD_BUILTIN alpha_fold_builtin | |
e3825818 | 9894 | #undef TARGET_GIMPLE_FOLD_BUILTIN |
9895 | #define TARGET_GIMPLE_FOLD_BUILTIN alpha_gimple_fold_builtin | |
92643d95 | 9896 | |
9897 | #undef TARGET_FUNCTION_OK_FOR_SIBCALL | |
9898 | #define TARGET_FUNCTION_OK_FOR_SIBCALL alpha_function_ok_for_sibcall | |
9899 | #undef TARGET_CANNOT_COPY_INSN_P | |
9900 | #define TARGET_CANNOT_COPY_INSN_P alpha_cannot_copy_insn_p | |
ca316360 | 9901 | #undef TARGET_LEGITIMATE_CONSTANT_P |
9902 | #define TARGET_LEGITIMATE_CONSTANT_P alpha_legitimate_constant_p | |
c0da4391 | 9903 | #undef TARGET_CANNOT_FORCE_CONST_MEM |
9904 | #define TARGET_CANNOT_FORCE_CONST_MEM alpha_cannot_force_const_mem | |
92643d95 | 9905 | |
9906 | #if TARGET_ABI_OSF | |
9907 | #undef TARGET_ASM_OUTPUT_MI_THUNK | |
9908 | #define TARGET_ASM_OUTPUT_MI_THUNK alpha_output_mi_thunk_osf | |
9909 | #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK | |
a9f1838b | 9910 | #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true |
7955d282 | 9911 | #undef TARGET_STDARG_OPTIMIZE_HOOK |
9912 | #define TARGET_STDARG_OPTIMIZE_HOOK alpha_stdarg_optimize_hook | |
92643d95 | 9913 | #endif |
9914 | ||
c2ec39b5 | 9915 | /* Use 16-bits anchor. */ |
9916 | #undef TARGET_MIN_ANCHOR_OFFSET | |
9917 | #define TARGET_MIN_ANCHOR_OFFSET -0x7fff - 1 | |
9918 | #undef TARGET_MAX_ANCHOR_OFFSET | |
9919 | #define TARGET_MAX_ANCHOR_OFFSET 0x7fff | |
9920 | #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P | |
9921 | #define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true | |
9922 | ||
92643d95 | 9923 | #undef TARGET_RTX_COSTS |
9924 | #define TARGET_RTX_COSTS alpha_rtx_costs | |
9925 | #undef TARGET_ADDRESS_COST | |
d9c5e5f4 | 9926 | #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0 |
92643d95 | 9927 | |
9928 | #undef TARGET_MACHINE_DEPENDENT_REORG | |
9929 | #define TARGET_MACHINE_DEPENDENT_REORG alpha_reorg | |
9930 | ||
3b2411a8 | 9931 | #undef TARGET_PROMOTE_FUNCTION_MODE |
9932 | #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote | |
dd9f3024 | 9933 | #undef TARGET_PROMOTE_PROTOTYPES |
fb80456a | 9934 | #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false |
dd9f3024 | 9935 | #undef TARGET_RETURN_IN_MEMORY |
9936 | #define TARGET_RETURN_IN_MEMORY alpha_return_in_memory | |
b981d932 | 9937 | #undef TARGET_PASS_BY_REFERENCE |
9938 | #define TARGET_PASS_BY_REFERENCE alpha_pass_by_reference | |
dd9f3024 | 9939 | #undef TARGET_SETUP_INCOMING_VARARGS |
9940 | #define TARGET_SETUP_INCOMING_VARARGS alpha_setup_incoming_varargs | |
9941 | #undef TARGET_STRICT_ARGUMENT_NAMING | |
9942 | #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true | |
9943 | #undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED | |
9944 | #define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true | |
92d40bc4 | 9945 | #undef TARGET_SPLIT_COMPLEX_ARG |
9946 | #define TARGET_SPLIT_COMPLEX_ARG alpha_split_complex_arg | |
de8f9b94 | 9947 | #undef TARGET_GIMPLIFY_VA_ARG_EXPR |
9948 | #define TARGET_GIMPLIFY_VA_ARG_EXPR alpha_gimplify_va_arg | |
f054eb3c | 9949 | #undef TARGET_ARG_PARTIAL_BYTES |
9950 | #define TARGET_ARG_PARTIAL_BYTES alpha_arg_partial_bytes | |
54ea4630 | 9951 | #undef TARGET_FUNCTION_ARG |
9952 | #define TARGET_FUNCTION_ARG alpha_function_arg | |
9953 | #undef TARGET_FUNCTION_ARG_ADVANCE | |
9954 | #define TARGET_FUNCTION_ARG_ADVANCE alpha_function_arg_advance | |
7bcbe23a | 9955 | #undef TARGET_TRAMPOLINE_INIT |
9956 | #define TARGET_TRAMPOLINE_INIT alpha_trampoline_init | |
b2aef146 | 9957 | |
0d25d8c2 | 9958 | #undef TARGET_INSTANTIATE_DECLS |
9959 | #define TARGET_INSTANTIATE_DECLS alpha_instantiate_decls | |
9960 | ||
0d96cd2b | 9961 | #undef TARGET_SECONDARY_RELOAD |
9962 | #define TARGET_SECONDARY_RELOAD alpha_secondary_reload | |
9963 | ||
b2aef146 | 9964 | #undef TARGET_SCALAR_MODE_SUPPORTED_P |
9965 | #define TARGET_SCALAR_MODE_SUPPORTED_P alpha_scalar_mode_supported_p | |
9e7454d0 | 9966 | #undef TARGET_VECTOR_MODE_SUPPORTED_P |
9967 | #define TARGET_VECTOR_MODE_SUPPORTED_P alpha_vector_mode_supported_p | |
dd9f3024 | 9968 | |
2e15d750 | 9969 | #undef TARGET_BUILD_BUILTIN_VA_LIST |
9970 | #define TARGET_BUILD_BUILTIN_VA_LIST alpha_build_builtin_va_list | |
9971 | ||
8a58ed0a | 9972 | #undef TARGET_EXPAND_BUILTIN_VA_START |
9973 | #define TARGET_EXPAND_BUILTIN_VA_START alpha_va_start | |
9974 | ||
4c834714 | 9975 | #undef TARGET_OPTION_OVERRIDE |
9976 | #define TARGET_OPTION_OVERRIDE alpha_option_override | |
9977 | ||
3032a4ea | 9978 | #undef TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE |
9979 | #define TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE \ | |
9980 | alpha_override_options_after_change | |
9981 | ||
4257b08a | 9982 | #ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING |
eddcdde1 | 9983 | #undef TARGET_MANGLE_TYPE |
9984 | #define TARGET_MANGLE_TYPE alpha_mangle_type | |
4257b08a | 9985 | #endif |
9986 | ||
fd50b071 | 9987 | #undef TARGET_LEGITIMATE_ADDRESS_P |
9988 | #define TARGET_LEGITIMATE_ADDRESS_P alpha_legitimate_address_p | |
9989 | ||
b2d7ede1 | 9990 | #undef TARGET_CONDITIONAL_REGISTER_USAGE |
9991 | #define TARGET_CONDITIONAL_REGISTER_USAGE alpha_conditional_register_usage | |
9992 | ||
d5065e6e | 9993 | #undef TARGET_CANONICALIZE_COMPARISON |
9994 | #define TARGET_CANONICALIZE_COMPARISON alpha_canonicalize_comparison | |
9995 | ||
175a5f5f | 9996 | #undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV |
9997 | #define TARGET_ATOMIC_ASSIGN_EXPAND_FENV alpha_atomic_assign_expand_fenv | |
9998 | ||
92643d95 | 9999 | struct gcc_target targetm = TARGET_INITIALIZER; |
10000 | ||
10001 | \f | |
1f3233d1 | 10002 | #include "gt-alpha.h" |