]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/visium/visium.c
2015-06-08 Andrew MacLeod <amacleod@redhat.com>
[thirdparty/gcc.git] / gcc / config / visium / visium.c
1 /* Output routines for Visium.
2 Copyright (C) 2002-2015 Free Software Foundation, Inc.
3 Contributed by C.Nettleton, J.P.Parkes and P.Garbett.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "input.h"
26 #include "alias.h"
27 #include "flags.h"
28 #include "symtab.h"
29 #include "tree-core.h"
30 #include "fold-const.h"
31 #include "tree-check.h"
32 #include "tree.h"
33 #include "stringpool.h"
34 #include "stor-layout.h"
35 #include "calls.h"
36 #include "varasm.h"
37 #include "rtl.h"
38 #include "regs.h"
39 #include "hard-reg-set.h"
40 #include "insn-config.h"
41 #include "conditions.h"
42 #include "output.h"
43 #include "insn-attr.h"
44 #include "function.h"
45 #include "expmed.h"
46 #include "dojump.h"
47 #include "explow.h"
48 #include "emit-rtl.h"
49 #include "stmt.h"
50 #include "expr.h"
51 #include "recog.h"
52 #include "diagnostic-core.h"
53 #include "tm_p.h"
54 #include "optabs.h"
55 #include "target.h"
56 #include "target-def.h"
57 #include "common/common-target.h"
58 #include "predict.h"
59 #include "basic-block.h"
60 #include "gimple-expr.h"
61 #include "gimplify.h"
62 #include "langhooks.h"
63 #include "reload.h"
64 #include "tm-constrs.h"
65 #include "df.h"
66 #include "params.h"
67 #include "errors.h"
68 #include "tree-pass.h"
69 #include "context.h"
70 #include "builtins.h"
71
72 /* Machine specific function data. */
73 struct GTY (()) machine_function
74 {
75 /* Size of the frame of the function. */
76 int frame_size;
77
78 /* Size of the reg parm save area, non-zero only for functions with variable
79 argument list. We cannot use the crtl->args.pretend_args_size machinery
80 for this purpose because this size is added to virtual_incoming_args_rtx
81 to give the location of the first parameter passed by the caller on the
82 stack and virtual_incoming_args_rtx is also the location of the first
83 parameter on the stack. So crtl->args.pretend_args_size can be non-zero
84 only if the first non-register named parameter is not passed entirely on
85 the stack and this runs afoul of the need to have a reg parm save area
86 even with a variable argument list starting on the stack because of the
87 separate handling of general and floating-point registers. */
88 int reg_parm_save_area_size;
89
90 /* True if we have created an rtx which relies on the frame pointer. */
91 bool frame_needed;
92
93 /* True if we have exposed the flags register. From this moment on, we
94 cannot generate simple operations for integer registers. We could
95 use reload_completed for this purpose, but this would cripple the
96 postreload CSE and GCSE passes which run before postreload split. */
97 bool flags_exposed;
98 };
99
100 #define visium_frame_size cfun->machine->frame_size
101 #define visium_reg_parm_save_area_size cfun->machine->reg_parm_save_area_size
102 #define visium_frame_needed cfun->machine->frame_needed
103 #define visium_flags_exposed cfun->machine->flags_exposed
104
105 /* 1 if the next opcode is to be specially indented. */
106 int visium_indent_opcode = 0;
107
108 /* Register number used for long branches when LR isn't available. It
109 must be a call-used register since it isn't saved on function entry.
110 We do not care whether the branch is predicted or not on the GR6,
111 given how unlikely it is to have a long branch in a leaf function. */
112 static unsigned int long_branch_regnum = 31;
113
114 static void visium_output_address (FILE *, enum machine_mode, rtx);
115 static tree visium_handle_interrupt_attr (tree *, tree, tree, int, bool *);
116 static inline bool current_function_saves_fp (void);
117 static inline bool current_function_saves_lr (void);
118 static inline bool current_function_has_lr_slot (void);
119
120 /* Supported attributes:
121 interrupt -- specifies this function is an interrupt handler. */
122 static const struct attribute_spec visium_attribute_table[] =
123 {
124 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
125 affects_type_identity } */
126 {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false},
127 {NULL, 0, 0, false, false, false, NULL, false}
128 };
129
130 static struct machine_function *visium_init_machine_status (void);
131
132 /* Target hooks and TARGET_INITIALIZER */
133
134 static bool visium_pass_by_reference (cumulative_args_t, enum machine_mode,
135 const_tree, bool);
136
137 static rtx visium_function_arg (cumulative_args_t, enum machine_mode,
138 const_tree, bool);
139
140 static void visium_function_arg_advance (cumulative_args_t, enum machine_mode,
141 const_tree, bool);
142
143 static bool visium_return_in_memory (const_tree, const_tree fntype);
144
145 static rtx visium_function_value (const_tree, const_tree fn_decl_or_type,
146 bool);
147
148 static rtx visium_libcall_value (enum machine_mode, const_rtx);
149
150 static void visium_setup_incoming_varargs (cumulative_args_t,
151 enum machine_mode,
152 tree, int *, int);
153
154 static void visium_va_start (tree valist, rtx nextarg);
155
156 static tree visium_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
157
158 static bool visium_function_ok_for_sibcall (tree, tree);
159
160 static bool visium_frame_pointer_required (void);
161
162 static tree visium_build_builtin_va_list (void);
163
164 static rtx_insn *visium_md_asm_adjust (vec<rtx> &, vec<rtx> &,
165 vec<const char *> &,
166 vec<rtx> &, HARD_REG_SET &);
167
168 static bool visium_legitimate_constant_p (enum machine_mode, rtx);
169
170 static bool visium_legitimate_address_p (enum machine_mode, rtx, bool);
171
172 static void visium_conditional_register_usage (void);
173
174 static rtx visium_legitimize_address (rtx, rtx, enum machine_mode);
175
176 static reg_class_t visium_secondary_reload (bool, rtx, reg_class_t,
177 enum machine_mode,
178 secondary_reload_info *);
179
180 static bool visium_class_likely_spilled_p (reg_class_t);
181
182 static void visium_trampoline_init (rtx, tree, rtx);
183
184 static int visium_issue_rate (void);
185
186 static int visium_adjust_priority (rtx_insn *, int);
187
188 static int visium_adjust_cost (rtx_insn *, rtx, rtx_insn *, int);
189
190 static int visium_register_move_cost (enum machine_mode, reg_class_t,
191 reg_class_t);
192
193 static int visium_memory_move_cost (enum machine_mode, reg_class_t, bool);
194
195 static bool visium_rtx_costs (rtx, int, int, int, int *, bool);
196
197 static void visium_option_override (void);
198
199 static unsigned int visium_reorg (void);
200
201 /* Setup the global target hooks structure. */
202
203 #undef TARGET_MAX_ANCHOR_OFFSET
204 #define TARGET_MAX_ANCHOR_OFFSET 31
205
206 #undef TARGET_PASS_BY_REFERENCE
207 #define TARGET_PASS_BY_REFERENCE visium_pass_by_reference
208
209 #undef TARGET_FUNCTION_ARG
210 #define TARGET_FUNCTION_ARG visium_function_arg
211
212 #undef TARGET_FUNCTION_ARG_ADVANCE
213 #define TARGET_FUNCTION_ARG_ADVANCE visium_function_arg_advance
214
215 #undef TARGET_RETURN_IN_MEMORY
216 #define TARGET_RETURN_IN_MEMORY visium_return_in_memory
217
218 #undef TARGET_FUNCTION_VALUE
219 #define TARGET_FUNCTION_VALUE visium_function_value
220
221 #undef TARGET_LIBCALL_VALUE
222 #define TARGET_LIBCALL_VALUE visium_libcall_value
223
224 #undef TARGET_SETUP_INCOMING_VARARGS
225 #define TARGET_SETUP_INCOMING_VARARGS visium_setup_incoming_varargs
226
227 #undef TARGET_EXPAND_BUILTIN_VA_START
228 #define TARGET_EXPAND_BUILTIN_VA_START visium_va_start
229
230 #undef TARGET_BUILD_BUILTIN_VA_LIST
231 #define TARGET_BUILD_BUILTIN_VA_LIST visium_build_builtin_va_list
232
233 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
234 #define TARGET_GIMPLIFY_VA_ARG_EXPR visium_gimplify_va_arg
235
236 #undef TARGET_LEGITIMATE_CONSTANT_P
237 #define TARGET_LEGITIMATE_CONSTANT_P visium_legitimate_constant_p
238
239 #undef TARGET_LEGITIMATE_ADDRESS_P
240 #define TARGET_LEGITIMATE_ADDRESS_P visium_legitimate_address_p
241
242 #undef TARGET_ATTRIBUTE_TABLE
243 #define TARGET_ATTRIBUTE_TABLE visium_attribute_table
244
245 #undef TARGET_ADDRESS_COST
246 #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
247
248 #undef TARGET_STRICT_ARGUMENT_NAMING
249 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
250
251 #undef TARGET_SCHED_ISSUE_RATE
252 #define TARGET_SCHED_ISSUE_RATE visium_issue_rate
253
254 #undef TARGET_SCHED_ADJUST_PRIORITY
255 #define TARGET_SCHED_ADJUST_PRIORITY visium_adjust_priority
256
257 #undef TARGET_SCHED_ADJUST_COST
258 #define TARGET_SCHED_ADJUST_COST visium_adjust_cost
259
260 #undef TARGET_MEMORY_MOVE_COST
261 #define TARGET_MEMORY_MOVE_COST visium_memory_move_cost
262
263 #undef TARGET_REGISTER_MOVE_COST
264 #define TARGET_REGISTER_MOVE_COST visium_register_move_cost
265
266 #undef TARGET_RTX_COSTS
267 #define TARGET_RTX_COSTS visium_rtx_costs
268
269 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
270 #define TARGET_FUNCTION_OK_FOR_SIBCALL visium_function_ok_for_sibcall
271
272 #undef TARGET_FRAME_POINTER_REQUIRED
273 #define TARGET_FRAME_POINTER_REQUIRED visium_frame_pointer_required
274
275 #undef TARGET_SECONDARY_RELOAD
276 #define TARGET_SECONDARY_RELOAD visium_secondary_reload
277
278 #undef TARGET_CLASS_LIKELY_SPILLED_P
279 #define TARGET_CLASS_LIKELY_SPILLED_P visium_class_likely_spilled_p
280
281 #undef TARGET_LEGITIMIZE_ADDRESS
282 #define TARGET_LEGITIMIZE_ADDRESS visium_legitimize_address
283
284 #undef TARGET_OPTION_OVERRIDE
285 #define TARGET_OPTION_OVERRIDE visium_option_override
286
287 #undef TARGET_CONDITIONAL_REGISTER_USAGE
288 #define TARGET_CONDITIONAL_REGISTER_USAGE visium_conditional_register_usage
289
290 #undef TARGET_TRAMPOLINE_INIT
291 #define TARGET_TRAMPOLINE_INIT visium_trampoline_init
292
293 #undef TARGET_MD_ASM_ADJUST
294 #define TARGET_MD_ASM_ADJUST visium_md_asm_adjust
295
296 #undef TARGET_FLAGS_REGNUM
297 #define TARGET_FLAGS_REGNUM FLAGS_REGNUM
298
299 struct gcc_target targetm = TARGET_INITIALIZER;
300
301 namespace {
302
303 const pass_data pass_data_visium_reorg =
304 {
305 RTL_PASS, /* type */
306 "mach2", /* name */
307 OPTGROUP_NONE, /* optinfo_flags */
308 TV_MACH_DEP, /* tv_id */
309 0, /* properties_required */
310 0, /* properties_provided */
311 0, /* properties_destroyed */
312 0, /* todo_flags_start */
313 0, /* todo_flags_finish */
314 };
315
316 class pass_visium_reorg : public rtl_opt_pass
317 {
318 public:
319 pass_visium_reorg(gcc::context *ctxt)
320 : rtl_opt_pass(pass_data_visium_reorg, ctxt)
321 {}
322
323 /* opt_pass methods: */
324 virtual unsigned int execute (function *)
325 {
326 return visium_reorg ();
327 }
328
329 }; // class pass_work_around_errata
330
331 } // anon namespace
332
333 rtl_opt_pass *
334 make_pass_visium_reorg (gcc::context *ctxt)
335 {
336 return new pass_visium_reorg (ctxt);
337 }
338
339 /* Options override for Visium. */
340
341 static void
342 visium_option_override (void)
343 {
344 if (flag_pic == 1)
345 warning (OPT_fpic, "-fpic is not supported");
346 if (flag_pic == 2)
347 warning (OPT_fPIC, "-fPIC is not supported");
348
349 /* MCM is the default in the GR5/GR6 era. */
350 target_flags |= MASK_MCM;
351
352 /* FPU is the default with MCM, but don't override an explicit option. */
353 if ((target_flags_explicit & MASK_FPU) == 0)
354 target_flags |= MASK_FPU;
355
356 /* The supervisor mode is the default. */
357 if ((target_flags_explicit & MASK_SV_MODE) == 0)
358 target_flags |= MASK_SV_MODE;
359
360 /* The GR6 has the Block Move Instructions and an IEEE-compliant FPU. */
361 if (visium_cpu_and_features == PROCESSOR_GR6)
362 {
363 target_flags |= MASK_BMI;
364 if (target_flags & MASK_FPU)
365 target_flags |= MASK_FPU_IEEE;
366 }
367
368 /* Set -mtune from -mcpu if not specified. */
369 if (!global_options_set.x_visium_cpu)
370 visium_cpu = visium_cpu_and_features;
371
372 /* Align functions on 256-byte (32-quadword) for GR5 and 64-byte (8-quadword)
373 boundaries for GR6 so they start a new burst mode window. */
374 if (align_functions == 0)
375 {
376 if (visium_cpu == PROCESSOR_GR6)
377 align_functions = 64;
378 else
379 align_functions = 256;
380
381 /* Allow the size of compilation units to double because of inlining.
382 In practice the global size of the object code is hardly affected
383 because the additional instructions will take up the padding. */
384 maybe_set_param_value (PARAM_INLINE_UNIT_GROWTH, 100,
385 global_options.x_param_values,
386 global_options_set.x_param_values);
387 }
388
389 /* Likewise for loops. */
390 if (align_loops == 0)
391 {
392 if (visium_cpu == PROCESSOR_GR6)
393 align_loops = 64;
394 else
395 {
396 align_loops = 256;
397 /* But not if they are too far away from a 256-byte boundary. */
398 align_loops_max_skip = 31;
399 }
400 }
401
402 /* Align all jumps on quadword boundaries for the burst mode, and even
403 on 8-quadword boundaries for GR6 so they start a new window. */
404 if (align_jumps == 0)
405 {
406 if (visium_cpu == PROCESSOR_GR6)
407 align_jumps = 64;
408 else
409 align_jumps = 8;
410 }
411
412 /* We register a machine-specific pass. This pass must be scheduled as
413 late as possible so that we have the (essentially) final form of the
414 insn stream to work on. Registering the pass must be done at start up.
415 It's convenient to do it here. */
416 opt_pass *visium_reorg_pass = make_pass_visium_reorg (g);
417 struct register_pass_info insert_pass_visium_reorg =
418 {
419 visium_reorg_pass, /* pass */
420 "dbr", /* reference_pass_name */
421 1, /* ref_pass_instance_number */
422 PASS_POS_INSERT_AFTER /* po_op */
423 };
424 register_pass (&insert_pass_visium_reorg);
425 }
426
427 /* Return the number of instructions that can issue on the same cycle. */
428
429 static int
430 visium_issue_rate (void)
431 {
432 switch (visium_cpu)
433 {
434 case PROCESSOR_GR5:
435 return 1;
436
437 case PROCESSOR_GR6:
438 return 2;
439
440 default:
441 gcc_unreachable ();
442 }
443 }
444
445 /* Return the adjusted PRIORITY of INSN. */
446
447 static int
448 visium_adjust_priority (rtx_insn *insn, int priority)
449 {
450 /* On the GR5, we slightly increase the priority of writes in order to avoid
451 scheduling a read on the next cycle. This is necessary in addition to the
452 associated insn reservation because there are no data dependencies.
453 We also slightly increase the priority of reads from ROM in order to group
454 them as much as possible. These reads are a bit problematic because they
455 conflict with the instruction fetches, i.e. the data and instruction buses
456 tread on each other's toes when they are executed. */
457 if (visium_cpu == PROCESSOR_GR5
458 && reload_completed
459 && INSN_P (insn)
460 && recog_memoized (insn) >= 0)
461 {
462 enum attr_type attr_type = get_attr_type (insn);
463 if (attr_type == TYPE_REG_MEM
464 || (attr_type == TYPE_MEM_REG
465 && MEM_READONLY_P (SET_SRC (PATTERN (insn)))))
466 return priority + 1;
467 }
468
469 return priority;
470 }
471
472 /* Adjust the cost of a scheduling dependency. Return the new cost of
473 a dependency LINK of INSN on DEP_INSN. COST is the current cost. */
474
475 static int
476 visium_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, int cost)
477 {
478 enum attr_type attr_type;
479
480 /* Don't adjust costs for true dependencies as they are described with
481 bypasses. But we make an exception for the first scheduling pass to
482 help the subsequent postreload compare elimination pass. */
483 if (REG_NOTE_KIND (link) == REG_DEP_TRUE)
484 {
485 if (!reload_completed
486 && recog_memoized (insn) >= 0
487 && get_attr_type (insn) == TYPE_CMP)
488 {
489 rtx pat = PATTERN (insn);
490 gcc_assert (GET_CODE (pat) == SET);
491 rtx src = SET_SRC (pat);
492
493 /* Only the branches can be modified by the postreload compare
494 elimination pass, not the cstores because they accept only
495 unsigned comparison operators and they are eliminated if
496 one of the operands is zero. */
497 if (GET_CODE (src) == IF_THEN_ELSE
498 && XEXP (XEXP (src, 0), 1) == const0_rtx
499 && recog_memoized (dep_insn) >= 0)
500 {
501 enum attr_type dep_attr_type = get_attr_type (dep_insn);
502
503 /* The logical instructions use CCmode and thus work with any
504 comparison operator, whereas the arithmetic instructions use
505 CC_NOOVmode and thus work with only a small subset. */
506 if (dep_attr_type == TYPE_LOGIC
507 || (dep_attr_type == TYPE_ARITH
508 && visium_noov_operator (XEXP (src, 0),
509 GET_MODE (XEXP (src, 0)))))
510 return 0;
511 }
512 }
513
514 return cost;
515 }
516
517 if (recog_memoized (insn) < 0)
518 return 0;
519
520 attr_type = get_attr_type (insn);
521
522 /* Anti dependency: DEP_INSN reads a register that INSN writes some
523 cycles later. */
524 if (REG_NOTE_KIND (link) == REG_DEP_ANTI)
525 {
526 /* On the GR5, the latency of FP instructions needs to be taken into
527 account for every dependency involving a write. */
528 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
529 {
530 /* INSN is FLOAD. */
531 rtx pat = PATTERN (insn);
532 rtx dep_pat = PATTERN (dep_insn);
533
534 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
535 /* If this happens, we have to extend this to schedule
536 optimally. Return 0 for now. */
537 return 0;
538
539 if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
540 {
541 if (recog_memoized (dep_insn) < 0)
542 return 0;
543
544 switch (get_attr_type (dep_insn))
545 {
546 case TYPE_FDIV:
547 case TYPE_FSQRT:
548 case TYPE_FTOI:
549 case TYPE_ITOF:
550 case TYPE_FP:
551 case TYPE_FMOVE:
552 /* A fload can't be issued until a preceding arithmetic
553 operation has finished if the target of the fload is
554 any of the sources (or destination) of the arithmetic
555 operation. Note that the latency may be (much)
556 greater than this if the preceding instruction
557 concerned is in a queue. */
558 return insn_default_latency (dep_insn);
559
560 default:
561 return 0;
562 }
563 }
564 }
565
566 /* On the GR6, we try to make sure that the link register is restored
567 sufficiently ahead of the return as to yield a correct prediction
568 from the branch predictor. By default there is no true dependency
569 but an anti dependency between them, so we simply reuse it. */
570 else if (attr_type == TYPE_RET && visium_cpu == PROCESSOR_GR6)
571 {
572 rtx dep_pat = PATTERN (dep_insn);
573 if (GET_CODE (dep_pat) == SET
574 && REG_P (SET_DEST (dep_pat))
575 && REGNO (SET_DEST (dep_pat)) == LINK_REGNUM)
576 return 8;
577 }
578
579 /* For other anti dependencies, the cost is 0. */
580 return 0;
581 }
582
583 /* Output dependency: DEP_INSN writes a register that INSN writes some
584 cycles later. */
585 else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
586 {
587 /* On the GR5, the latency of FP instructions needs to be taken into
588 account for every dependency involving a write. */
589 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
590 {
591 /* INSN is FLOAD. */
592 rtx pat = PATTERN (insn);
593 rtx dep_pat = PATTERN (dep_insn);
594
595 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
596 /* If this happens, we have to extend this to schedule
597 optimally. Return 0 for now. */
598 return 0;
599
600 if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat)))
601 {
602 if (recog_memoized (dep_insn) < 0)
603 return 0;
604
605 switch (get_attr_type (dep_insn))
606 {
607 case TYPE_FDIV:
608 case TYPE_FSQRT:
609 case TYPE_FTOI:
610 case TYPE_ITOF:
611 case TYPE_FP:
612 case TYPE_FMOVE:
613 /* A fload can't be issued until a preceding arithmetic
614 operation has finished if the target of the fload is
615 the destination of the arithmetic operation. Note that
616 the latency may be (much) greater than this if the
617 preceding instruction concerned is in a queue. */
618 return insn_default_latency (dep_insn);
619
620 default:
621 return 0;
622 }
623 }
624 }
625
626 /* For other output dependencies, the cost is 0. */
627 return 0;
628 }
629
630 return 0;
631 }
632
633 /* Handle an "interrupt_handler" attribute; arguments as in
634 struct attribute_spec.handler. */
635
636 static tree
637 visium_handle_interrupt_attr (tree *node, tree name,
638 tree args ATTRIBUTE_UNUSED,
639 int flags ATTRIBUTE_UNUSED,
640 bool *no_add_attrs)
641 {
642 if (TREE_CODE (*node) != FUNCTION_DECL)
643 {
644 warning (OPT_Wattributes, "%qE attribute only applies to functions",
645 name);
646 *no_add_attrs = true;
647 }
648 else if (!TARGET_SV_MODE)
649 {
650 error ("an interrupt handler cannot be compiled with -muser-mode");
651 *no_add_attrs = true;
652 }
653
654 return NULL_TREE;
655 }
656
657 /* Return non-zero if the current function is an interrupt function. */
658
659 int
660 visium_interrupt_function_p (void)
661 {
662 return
663 lookup_attribute ("interrupt",
664 DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
665 }
666
667 /* Conditionally modify the settings of the register file. */
668
669 static void
670 visium_conditional_register_usage (void)
671 {
672 /* If the supervisor mode is disabled, mask some general registers. */
673 if (!TARGET_SV_MODE)
674 {
675 if (visium_cpu_and_features == PROCESSOR_GR5)
676 {
677 fixed_regs[24] = call_used_regs[24] = 1;
678 fixed_regs[25] = call_used_regs[25] = 1;
679 fixed_regs[26] = call_used_regs[26] = 1;
680 fixed_regs[27] = call_used_regs[27] = 1;
681 fixed_regs[28] = call_used_regs[28] = 1;
682 call_really_used_regs[24] = 0;
683 call_really_used_regs[25] = 0;
684 call_really_used_regs[26] = 0;
685 call_really_used_regs[27] = 0;
686 call_really_used_regs[28] = 0;
687 }
688
689 fixed_regs[31] = call_used_regs[31] = 1;
690 call_really_used_regs[31] = 0;
691
692 /* We also need to change the long-branch register. */
693 if (visium_cpu_and_features == PROCESSOR_GR5)
694 long_branch_regnum = 20;
695 else
696 long_branch_regnum = 28;
697 }
698
699 /* If the FPU is disabled, mask the FP registers. */
700 if (!TARGET_FPU)
701 {
702 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
703 {
704 fixed_regs[i] = call_used_regs[i] = 1;
705 call_really_used_regs[i] = 0;
706 }
707 }
708 }
709
710 /* Prepend to CLOBBERS hard registers that are automatically clobbered for
711 an asm We do this for the FLAGS to maintain source compatibility with
712 the original cc0-based compiler. */
713
714 static rtx_insn *
715 visium_md_asm_adjust (vec<rtx> &/*outputs*/, vec<rtx> &/*inputs*/,
716 vec<const char *> &/*constraints*/,
717 vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs)
718 {
719 clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REGNUM));
720 SET_HARD_REG_BIT (clobbered_regs, FLAGS_REGNUM);
721 return NULL;
722 }
723
724 /* Return true if X is a legitimate constant for a MODE immediate operand.
725 X is guaranteed to satisfy the CONSTANT_P predicate. */
726
727 static bool
728 visium_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
729 rtx x ATTRIBUTE_UNUSED)
730 {
731 return true;
732 }
733
734 /* Compute the alignment for a variable. The alignment of an aggregate is
735 set to be at least that of a scalar less than or equal to it in size. */
736
737 unsigned int
738 visium_data_alignment (tree type, unsigned int align)
739 {
740 if (AGGREGATE_TYPE_P (type)
741 && TYPE_SIZE (type)
742 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && align < 32)
743 {
744 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 32)
745 return 32;
746
747 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 && align < 16)
748 return 16;
749 }
750
751 return align;
752 }
753
754 /* Helper function for HARD_REGNO_RENAME_OK (FROM, TO). Return non-zero if
755 it is OK to rename a hard register FROM to another hard register TO. */
756
757 int
758 visium_hard_regno_rename_ok (unsigned int from ATTRIBUTE_UNUSED,
759 unsigned int to)
760 {
761 /* If the function doesn't save LR, then the long-branch register will be
762 used for long branches so we need to know whether it is live before the
763 frame layout is computed. */
764 if (!current_function_saves_lr () && to == long_branch_regnum)
765 return 0;
766
767 /* Interrupt functions can only use registers that have already been
768 saved by the prologue, even if they would normally be call-clobbered. */
769 if (crtl->is_leaf
770 && !df_regs_ever_live_p (to)
771 && visium_interrupt_function_p ())
772 return 0;
773
774 return 1;
775 }
776
777 /* Return true if it is ok to do sibling call optimization for the specified
778 call expression EXP. DECL will be the called function, or NULL if this
779 is an indirect call. */
780
781 static bool
782 visium_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
783 tree exp ATTRIBUTE_UNUSED)
784 {
785 return !visium_interrupt_function_p ();
786 }
787
788 /* Prepare operands for a move define_expand in MODE. */
789
790 void
791 prepare_move_operands (rtx *operands, enum machine_mode mode)
792 {
793 /* If the output is not a register, the input must be. */
794 if (GET_CODE (operands[0]) == MEM && !reg_or_0_operand (operands[1], mode))
795 operands[1] = force_reg (mode, operands[1]);
796 }
797
798 /* Return true if the operands are valid for a simple move insn. */
799
800 bool
801 ok_for_simple_move_operands (rtx *operands, enum machine_mode mode)
802 {
803 /* One of the operands must be a register. */
804 if (!register_operand (operands[0], mode)
805 && !reg_or_0_operand (operands[1], mode))
806 return false;
807
808 /* Once the flags are exposed, no simple moves between integer registers. */
809 if (visium_flags_exposed
810 && gpc_reg_operand (operands[0], mode)
811 && gpc_reg_operand (operands[1], mode))
812 return false;
813
814 return true;
815 }
816
817 /* Return true if the operands are valid for a simple move strict insn. */
818
819 bool
820 ok_for_simple_move_strict_operands (rtx *operands, enum machine_mode mode)
821 {
822 /* Once the flags are exposed, no simple moves between integer registers.
823 Note that, in QImode only, a zero source counts as an integer register
824 since it will be emitted as r0. */
825 if (visium_flags_exposed
826 && gpc_reg_operand (operands[0], mode)
827 && (gpc_reg_operand (operands[1], mode)
828 || (mode == QImode && operands[1] == const0_rtx)))
829 return false;
830
831 return true;
832 }
833
834 /* Return true if the operands are valid for a simple arithmetic or logical
835 insn. */
836
837 bool
838 ok_for_simple_arith_logic_operands (rtx *, enum machine_mode)
839 {
840 /* Once the flags are exposed, no simple arithmetic or logical operations
841 between integer registers. */
842 return !visium_flags_exposed;
843 }
844
845 /* Return non-zero if a branch or call instruction will be emitting a nop
846 into its delay slot. */
847
848 int
849 empty_delay_slot (rtx_insn *insn)
850 {
851 rtx seq;
852
853 /* If no previous instruction (should not happen), return true. */
854 if (PREV_INSN (insn) == NULL)
855 return 1;
856
857 seq = NEXT_INSN (PREV_INSN (insn));
858 if (GET_CODE (PATTERN (seq)) == SEQUENCE)
859 return 0;
860
861 return 1;
862 }
863
864 /* Wrapper around single_set which returns the first SET of a pair if the
865 second SET is to the flags register. */
866
867 static rtx
868 single_set_and_flags (rtx_insn *insn)
869 {
870 if (multiple_sets (insn))
871 {
872 rtx pat = PATTERN (insn);
873 if (XVECLEN (pat, 0) == 2
874 && GET_CODE (XVECEXP (pat, 0, 1)) == SET
875 && REG_P (SET_DEST (XVECEXP (pat, 0, 1)))
876 && REGNO (SET_DEST (XVECEXP (pat, 0, 1))) == FLAGS_REGNUM)
877 return XVECEXP (pat, 0, 0);
878 }
879
880 return single_set (insn);
881 }
882
883 /* This is called with OUT_INSN an instruction setting a (base) register
884 and IN_INSN a read or a write. Return 1 if these instructions together
885 constitute a pipeline hazard.
886
887 On the original architecture, a pipeline data hazard occurs when the Dest
888 of one instruction becomes the SrcA for an immediately following READ or
889 WRITE instruction with a non-zero index (indexing occurs at the decode
890 stage and so a NOP must be inserted in-between for this to work).
891
892 An example is:
893
894 move.l r2,r1
895 read.l r4,10(r2)
896
897 On the MCM, the non-zero index condition is lifted but the hazard is
898 patched up by the hardware through the injection of wait states:
899
900 move.l r2,r1
901 read.l r4,(r2)
902
903 We nevertheless try to schedule instructions around this. */
904
905 int
906 gr5_hazard_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
907 {
908 rtx out_set, in_set, dest, memexpr;
909 unsigned int out_reg, in_reg;
910
911 /* A CALL is storage register class, but the link register is of no
912 interest here. */
913 if (GET_CODE (out_insn) == CALL_INSN)
914 return 0;
915
916 out_set = single_set_and_flags (out_insn);
917 dest = SET_DEST (out_set);
918
919 /* Should be no stall/hazard if OUT_INSN is MEM := ???. This only
920 occurs prior to reload. */
921 if (GET_CODE (dest) == MEM)
922 return 0;
923
924 if (GET_CODE (dest) == STRICT_LOW_PART)
925 dest = XEXP (dest, 0);
926 if (GET_CODE (dest) == SUBREG)
927 dest = SUBREG_REG (dest);
928 out_reg = REGNO (dest);
929
930 in_set = single_set_and_flags (in_insn);
931
932 /* If IN_INSN is MEM := MEM, it's the source that counts. */
933 if (GET_CODE (SET_SRC (in_set)) == MEM)
934 memexpr = XEXP (SET_SRC (in_set), 0);
935 else
936 memexpr = XEXP (SET_DEST (in_set), 0);
937
938 if (GET_CODE (memexpr) == PLUS)
939 {
940 memexpr = XEXP (memexpr, 0);
941 if (GET_CODE (memexpr) == SUBREG)
942 in_reg = REGNO (SUBREG_REG (memexpr));
943 else
944 in_reg = REGNO (memexpr);
945
946 if (in_reg == out_reg)
947 return 1;
948 }
949 else if (TARGET_MCM)
950 {
951 if (GET_CODE (memexpr) == STRICT_LOW_PART)
952 memexpr = XEXP (memexpr, 0);
953 if (GET_CODE (memexpr) == SUBREG)
954 memexpr = SUBREG_REG (memexpr);
955 in_reg = REGNO (memexpr);
956
957 if (in_reg == out_reg)
958 return 1;
959 }
960
961 return 0;
962 }
963
964 /* Return true if INSN is an empty asm instruction. */
965
966 static bool
967 empty_asm_p (rtx insn)
968 {
969 rtx body = PATTERN (insn);
970 const char *templ;
971
972 if (GET_CODE (body) == ASM_INPUT)
973 templ = XSTR (body, 0);
974 else if (asm_noperands (body) >= 0)
975 templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
976 else
977 templ = NULL;
978
979 return (templ && templ[0] == '\0');
980 }
981
982 /* Insert a NOP immediately before INSN wherever there is a pipeline hazard.
983 LAST_REG records the register set in the last insn and LAST_INSN_CALL
984 records whether the last insn was a call insn. */
985
986 static void
987 gr5_avoid_hazard (rtx_insn *insn, unsigned int *last_reg, bool *last_insn_call)
988 {
989 unsigned int dest_reg = 0;
990 rtx set;
991
992 switch (GET_CODE (insn))
993 {
994 case CALL_INSN:
995 *last_reg = 0;
996 *last_insn_call = true;
997 return;
998
999 case JUMP_INSN:
1000 /* If this is an empty asm, just skip it. */
1001 if (!empty_asm_p (insn))
1002 {
1003 *last_reg = 0;
1004 *last_insn_call = false;
1005 }
1006 return;
1007
1008 case INSN:
1009 /* If this is an empty asm, just skip it. */
1010 if (empty_asm_p (insn))
1011 return;
1012 break;
1013
1014 default:
1015 return;
1016 }
1017
1018 set = single_set_and_flags (insn);
1019 if (set != NULL_RTX)
1020 {
1021 rtx dest = SET_DEST (set);
1022 const bool double_p = GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD;
1023 rtx memrtx = NULL;
1024
1025 if (GET_CODE (SET_SRC (set)) == MEM)
1026 {
1027 memrtx = XEXP (SET_SRC (set), 0);
1028 if (GET_CODE (dest) == STRICT_LOW_PART)
1029 dest = XEXP (dest, 0);
1030 if (REG_P (dest))
1031 dest_reg = REGNO (dest);
1032
1033 /* If this is a DI or DF mode memory to register
1034 copy, then if rd = rs we get
1035
1036 rs + 1 := 1[rs]
1037 rs := [rs]
1038
1039 otherwise the order is
1040
1041 rd := [rs]
1042 rd + 1 := 1[rs] */
1043
1044 if (double_p)
1045 {
1046 unsigned int base_reg;
1047
1048 if (GET_CODE (memrtx) == PLUS)
1049 base_reg = REGNO (XEXP (memrtx, 0));
1050 else
1051 base_reg = REGNO (memrtx);
1052
1053 if (dest_reg != base_reg)
1054 dest_reg++;
1055 }
1056 }
1057
1058 else if (GET_CODE (dest) == MEM)
1059 memrtx = XEXP (dest, 0);
1060
1061 else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC)
1062 {
1063 if (GET_CODE (dest) == STRICT_LOW_PART
1064 ||GET_CODE (dest) == ZERO_EXTRACT)
1065 dest = XEXP (dest, 0);
1066 dest_reg = REGNO (dest);
1067
1068 if (GET_CODE (SET_SRC (set)) == REG)
1069 {
1070 unsigned int srcreg = REGNO (SET_SRC (set));
1071
1072 /* Check for rs := rs, which will be deleted. */
1073 if (srcreg == dest_reg)
1074 return;
1075
1076 /* In the case of a DI or DF mode move from register to
1077 register there is overlap if rd = rs + 1 in which case
1078 the order of the copies is reversed :
1079
1080 rd + 1 := rs + 1;
1081 rd := rs */
1082
1083 if (double_p && dest_reg != srcreg + 1)
1084 dest_reg++;
1085 }
1086 }
1087
1088 /* If this is the delay slot of a call insn, any register it sets
1089 is not relevant. */
1090 if (*last_insn_call)
1091 dest_reg = 0;
1092
1093 /* If the previous insn sets the value of a register, and this insn
1094 uses a base register, check for the pipeline hazard where it is
1095 the same register in each case. */
1096 if (*last_reg != 0 && memrtx != NULL_RTX)
1097 {
1098 unsigned int reg = 0;
1099
1100 /* Check for an index (original architecture). */
1101 if (GET_CODE (memrtx) == PLUS)
1102 reg = REGNO (XEXP (memrtx, 0));
1103
1104 /* Check for an MCM target or rs := [rs], in DI or DF mode. */
1105 else if (TARGET_MCM || (double_p && REGNO (memrtx) == dest_reg))
1106 reg = REGNO (memrtx);
1107
1108 /* Remove any pipeline hazard by inserting a NOP. */
1109 if (reg == *last_reg)
1110 {
1111 if (dump_file)
1112 fprintf (dump_file,
1113 "inserting nop before insn %d\n", INSN_UID (insn));
1114 emit_insn_after (gen_hazard_nop (), prev_active_insn (insn));
1115 emit_insn_after (gen_blockage (), insn);
1116 }
1117 }
1118
1119 *last_reg = dest_reg;
1120 }
1121
1122 *last_insn_call = false;
1123 }
1124
1125 /* Go through the instruction stream and insert nops where necessary to avoid
1126 pipeline hazards. There are two cases:
1127
1128 1. On the original architecture, it is invalid to set the value of a
1129 (base) register and then use it in an address with a non-zero index
1130 in the next instruction.
1131
1132 2. On the MCM, setting the value of a (base) register and then using
1133 it in address (including with zero index) in the next instruction
1134 will result in a pipeline stall of 3 cycles. */
1135
1136 static void
1137 gr5_hazard_avoidance (void)
1138 {
1139 unsigned int last_reg = 0;
1140 bool last_insn_call = false;
1141 rtx_insn *insn;
1142
1143 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1144 if (INSN_P (insn))
1145 {
1146 rtx pat = PATTERN (insn);
1147
1148 if (GET_CODE (pat) == SEQUENCE)
1149 {
1150 for (int i = 0; i < XVECLEN (pat, 0); i++)
1151 gr5_avoid_hazard (as_a <rtx_insn *> (XVECEXP (pat, 0, i)),
1152 &last_reg, &last_insn_call);
1153 }
1154
1155 else if (GET_CODE (insn) == CALL_INSN)
1156 {
1157 /* This call is going to get a nop in its delay slot. */
1158 last_reg = 0;
1159 last_insn_call = false;
1160 }
1161
1162 else
1163 gr5_avoid_hazard (insn, &last_reg, &last_insn_call);
1164 }
1165
1166 else if (GET_CODE (insn) == BARRIER)
1167 last_reg = 0;
1168 }
1169
1170 /* Perform a target-specific pass over the instruction stream. The compiler
1171 will run it at all optimization levels, just after the point at which it
1172 normally does delayed-branch scheduling. */
1173
1174 static unsigned int
1175 visium_reorg (void)
1176 {
1177 if (visium_cpu == PROCESSOR_GR5)
1178 gr5_hazard_avoidance ();
1179
1180 return 0;
1181 }
1182 /* Return true if an argument must be passed by indirect reference. */
1183
1184 static bool
1185 visium_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1186 enum machine_mode mode ATTRIBUTE_UNUSED,
1187 const_tree type,
1188 bool named ATTRIBUTE_UNUSED)
1189 {
1190 return type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1191 }
1192
1193 /* Define how arguments are passed.
1194
1195 A range of general registers and floating registers is available
1196 for passing arguments. When the class of registers which an
1197 argument would normally use is exhausted, that argument, is passed
1198 in the overflow region of the stack. No argument is split between
1199 registers and stack.
1200
1201 Arguments of type float or _Complex float go in FP registers if FP
1202 hardware is available. If there is no FP hardware, arguments of
1203 type float go in general registers. All other arguments are passed
1204 in general registers. */
1205
1206 static rtx
1207 visium_function_arg (cumulative_args_t pcum_v, enum machine_mode mode,
1208 const_tree type ATTRIBUTE_UNUSED,
1209 bool named ATTRIBUTE_UNUSED)
1210 {
1211 int size;
1212 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1213
1214 size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1215 if (mode == VOIDmode)
1216 return GEN_INT (0);
1217
1218 /* Scalar or complex single precision floating point arguments are returned
1219 in floating registers. */
1220 if (TARGET_FPU
1221 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1222 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1223 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1224 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1225 {
1226 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1227 return gen_rtx_REG (mode, FP_ARG_FIRST + ca->frcount);
1228 else
1229 return NULL_RTX;
1230 }
1231
1232 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1233 return gen_rtx_REG (mode, ca->grcount + GP_ARG_FIRST);
1234
1235 return NULL_RTX;
1236 }
1237
1238 /* Update the summarizer variable pointed to by PCUM_V to advance past an
1239 argument in the argument list. The values MODE, TYPE and NAMED describe
1240 that argument. Once this is done, the variable CUM is suitable for
1241 analyzing the _following_ argument with visium_function_arg. */
1242
1243 static void
1244 visium_function_arg_advance (cumulative_args_t pcum_v,
1245 enum machine_mode mode,
1246 const_tree type ATTRIBUTE_UNUSED,
1247 bool named)
1248 {
1249 int size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1250 int stack_size = 0;
1251 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1252
1253 /* Scalar or complex single precision floating point arguments are returned
1254 in floating registers. */
1255 if (TARGET_FPU
1256 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1257 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1258 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1259 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1260 {
1261 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1262 ca->frcount += size;
1263 else
1264 {
1265 stack_size = size;
1266 ca->frcount = MAX_ARGS_IN_FP_REGISTERS;
1267 }
1268 }
1269 else
1270 {
1271 /* Everything else goes in a general register, if enough are
1272 available. */
1273 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1274 ca->grcount += size;
1275 else
1276 {
1277 stack_size = size;
1278 ca->grcount = MAX_ARGS_IN_GP_REGISTERS;
1279 }
1280 }
1281
1282 if (named)
1283 ca->stack_words += stack_size;
1284 }
1285
1286 /* Specify whether to return the return value in memory. */
1287
1288 static bool
1289 visium_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1290 {
1291 return (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1292 }
1293
1294 /* Define how scalar values are returned. */
1295
1296 static rtx
1297 visium_function_value_1 (enum machine_mode mode)
1298 {
1299 /* Scalar or complex single precision floating point values
1300 are returned in floating register f1. */
1301 if (TARGET_FPU
1302 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1303 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1304 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1305 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1306 return gen_rtx_REG (mode, FP_RETURN_REGNUM);
1307
1308 /* All others are returned in r1. */
1309 return gen_rtx_REG (mode, RETURN_REGNUM);
1310 }
1311
1312 /* Return an RTX representing the place where a function returns or receives
1313 a value of data type RET_TYPE. */
1314
1315 static rtx
1316 visium_function_value (const_tree ret_type,
1317 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1318 bool outgoing ATTRIBUTE_UNUSED)
1319 {
1320 return visium_function_value_1 (TYPE_MODE (ret_type));
1321 }
1322
1323 /* Return an RTX representing the place where the library function result will
1324 be returned. */
1325
1326 static rtx
1327 visium_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1328 {
1329 return visium_function_value_1 (mode);
1330 }
1331
1332 /* Store the anonymous register arguments into the stack so that all the
1333 arguments appear to have been passed consecutively on the stack. */
1334
1335 static void
1336 visium_setup_incoming_varargs (cumulative_args_t pcum_v,
1337 enum machine_mode mode,
1338 tree type,
1339 int *pretend_size ATTRIBUTE_UNUSED,
1340 int no_rtl)
1341 {
1342 cumulative_args_t local_args_so_far;
1343 CUMULATIVE_ARGS local_copy;
1344 CUMULATIVE_ARGS *locargs;
1345 int gp_saved, fp_saved, size;
1346
1347 /* Create an internal cumulative_args_t pointer to internally define
1348 storage to ensure calling TARGET_FUNCTION_ARG_ADVANCE does not
1349 make global changes. */
1350 local_args_so_far.p = &local_copy;
1351 locargs = get_cumulative_args (pcum_v);
1352
1353 #ifdef ENABLE_CHECKING
1354 local_args_so_far.magic = CUMULATIVE_ARGS_MAGIC;
1355 #endif
1356
1357 local_copy.grcount = locargs->grcount;
1358 local_copy.frcount = locargs->frcount;
1359 local_copy.stack_words = locargs->stack_words;
1360
1361 /* The caller has advanced ARGS_SO_FAR up to, but not beyond, the last named
1362 argument. Advance a local copy of ARGS_SO_FAR past the last "real" named
1363 argument, to find out how many registers are left over. */
1364 TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, mode, type, 1);
1365
1366 /* Find how many registers we need to save. */
1367 locargs = get_cumulative_args (local_args_so_far);
1368 gp_saved = MAX_ARGS_IN_GP_REGISTERS - locargs->grcount;
1369 fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - locargs->frcount : 0);
1370 size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_HWFPVALUE);
1371
1372 if (!no_rtl && size > 0)
1373 {
1374 /* To avoid negative offsets, which are not valid addressing modes on
1375 the Visium, we create a base register for the pretend args. */
1376 rtx ptr
1377 = force_reg (Pmode,
1378 plus_constant (Pmode, virtual_incoming_args_rtx, -size));
1379
1380 if (gp_saved > 0)
1381 {
1382 rtx mem
1383 = gen_rtx_MEM (BLKmode,
1384 plus_constant (Pmode,
1385 ptr,
1386 fp_saved * UNITS_PER_HWFPVALUE));
1387 MEM_NOTRAP_P (mem) = 1;
1388 set_mem_alias_set (mem, get_varargs_alias_set ());
1389 move_block_from_reg (locargs->grcount + GP_ARG_FIRST, mem, gp_saved);
1390 }
1391
1392 if (fp_saved > 0)
1393 {
1394 rtx mem = gen_rtx_MEM (BLKmode, ptr);
1395 MEM_NOTRAP_P (mem) = 1;
1396 set_mem_alias_set (mem, get_varargs_alias_set ());
1397 gcc_assert (UNITS_PER_WORD == UNITS_PER_HWFPVALUE);
1398 move_block_from_reg (locargs->frcount + FP_ARG_FIRST, mem, fp_saved);
1399 }
1400 }
1401
1402 visium_reg_parm_save_area_size = size;
1403 }
1404
1405 /* Define the `__builtin_va_list' type for the ABI. */
1406
1407 static tree
1408 visium_build_builtin_va_list (void)
1409 {
1410 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes, record;
1411
1412 record = (*lang_hooks.types.make_type) (RECORD_TYPE);
1413 f_ovfl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1414 get_identifier ("__overflow_argptr"), ptr_type_node);
1415 f_gbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1416 get_identifier ("__gpr_base"), ptr_type_node);
1417 f_fbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1418 get_identifier ("__fpr_base"), ptr_type_node);
1419 f_gbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1420 get_identifier ("__gpr_bytes"),
1421 short_unsigned_type_node);
1422 f_fbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1423 get_identifier ("__fpr_bytes"),
1424 short_unsigned_type_node);
1425
1426 DECL_FIELD_CONTEXT (f_ovfl) = record;
1427 DECL_FIELD_CONTEXT (f_gbase) = record;
1428 DECL_FIELD_CONTEXT (f_fbase) = record;
1429 DECL_FIELD_CONTEXT (f_gbytes) = record;
1430 DECL_FIELD_CONTEXT (f_fbytes) = record;
1431 TYPE_FIELDS (record) = f_ovfl;
1432 TREE_CHAIN (f_ovfl) = f_gbase;
1433 TREE_CHAIN (f_gbase) = f_fbase;
1434 TREE_CHAIN (f_fbase) = f_gbytes;
1435 TREE_CHAIN (f_gbytes) = f_fbytes;
1436 layout_type (record);
1437
1438 return record;
1439 }
1440
1441 /* Implement `va_start' for varargs and stdarg. */
1442
1443 static void
1444 visium_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
1445 {
1446 const CUMULATIVE_ARGS *ca = &crtl->args.info;
1447 int gp_saved = MAX_ARGS_IN_GP_REGISTERS - ca->grcount;
1448 int fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - ca->frcount : 0);
1449 int named_stack_size = ca->stack_words * UNITS_PER_WORD, offset;
1450 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1451 tree ovfl, gbase, gbytes, fbase, fbytes, t;
1452
1453 f_ovfl = TYPE_FIELDS (va_list_type_node);
1454 f_gbase = TREE_CHAIN (f_ovfl);
1455 f_fbase = TREE_CHAIN (f_gbase);
1456 f_gbytes = TREE_CHAIN (f_fbase);
1457 f_fbytes = TREE_CHAIN (f_gbytes);
1458 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1459 gbase = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1460 NULL_TREE);
1461 fbase = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1462 NULL_TREE);
1463 gbytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), valist, f_gbytes,
1464 NULL_TREE);
1465 fbytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), valist, f_fbytes,
1466 NULL_TREE);
1467
1468 /* Store the stacked vararg pointer in the OVFL member. */
1469 t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
1470 t = fold_build_pointer_plus_hwi (t, named_stack_size);
1471 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
1472 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1473
1474 /* Store the base address of the GPR save area into GBASE. */
1475 t = make_tree (TREE_TYPE (gbase), virtual_incoming_args_rtx);
1476 offset = MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD;
1477 t = fold_build_pointer_plus_hwi (t, -offset);
1478 t = build2 (MODIFY_EXPR, TREE_TYPE (gbase), gbase, t);
1479 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1480
1481 /* Store the base address of the FPR save area into FBASE. */
1482 if (fp_saved)
1483 {
1484 t = make_tree (TREE_TYPE (fbase), virtual_incoming_args_rtx);
1485 offset = gp_saved * UNITS_PER_WORD
1486 + MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE;
1487 t = fold_build_pointer_plus_hwi (t, -offset);
1488 t = build2 (MODIFY_EXPR, TREE_TYPE (fbase), fbase, t);
1489 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1490 }
1491
1492 /* Fill in the GBYTES member. */
1493 t = build2 (MODIFY_EXPR, TREE_TYPE (gbytes), gbytes,
1494 size_int (gp_saved * UNITS_PER_WORD));
1495 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1496
1497 /* Fill in the FBYTES member. */
1498 t = build2 (MODIFY_EXPR, TREE_TYPE (fbytes),
1499 fbytes, size_int (fp_saved * UNITS_PER_HWFPVALUE));
1500 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1501 }
1502
1503 /* Implement `va_arg'. */
1504
1505 static tree
1506 visium_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
1507 gimple_seq *post_p)
1508 {
1509 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1510 tree ovfl, base, bytes;
1511 HOST_WIDE_INT size, rsize;
1512 const bool by_reference_p
1513 = pass_by_reference (NULL, TYPE_MODE (type), type, false);
1514 const bool float_reg_arg_p
1515 = (TARGET_FPU && !by_reference_p
1516 && ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
1517 && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_HWFPVALUE)
1518 || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT
1519 && (GET_MODE_SIZE (TYPE_MODE (type))
1520 <= UNITS_PER_HWFPVALUE * 2))));
1521 const int max_save_area_size
1522 = (float_reg_arg_p ? MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE
1523 : MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD);
1524 tree t, u, offs;
1525 tree lab_false, lab_over, addr;
1526 tree ptrtype = build_pointer_type (type);
1527
1528 if (by_reference_p)
1529 {
1530 t = visium_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
1531 return build_va_arg_indirect_ref (t);
1532 }
1533
1534 size = int_size_in_bytes (type);
1535 rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
1536 f_ovfl = TYPE_FIELDS (va_list_type_node);
1537 f_gbase = TREE_CHAIN (f_ovfl);
1538 f_fbase = TREE_CHAIN (f_gbase);
1539 f_gbytes = TREE_CHAIN (f_fbase);
1540 f_fbytes = TREE_CHAIN (f_gbytes);
1541
1542 /* We maintain separate pointers and offsets for floating-point and
1543 general registers, but we need similar code in both cases.
1544
1545 Let:
1546
1547 BYTES be the number of unused bytes in the register save area.
1548 BASE be the base address of the register save area.
1549 OFFS be the current offset into the register save area. Either
1550 MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD - bytes or
1551 MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE - bytes
1552 depending upon whether the argument is in general or floating
1553 registers.
1554 ADDR_RTX be the address of the argument.
1555 RSIZE be the size in bytes of the argument.
1556 OVFL be the pointer to the stack overflow area.
1557
1558 The code we want is:
1559
1560 1: if (bytes >= rsize)
1561 2: {
1562 3: addr_rtx = base + offs;
1563 4: bytes -= rsize;
1564 5: }
1565 6: else
1566 7: {
1567 8: bytes = 0;
1568 9: addr_rtx = ovfl;
1569 10: ovfl += rsize;
1570 11: }
1571
1572 */
1573
1574 addr = create_tmp_var (ptr_type_node, "addr");
1575 lab_false = create_artificial_label (UNKNOWN_LOCATION);
1576 lab_over = create_artificial_label (UNKNOWN_LOCATION);
1577 if (float_reg_arg_p)
1578 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), unshare_expr (valist),
1579 f_fbytes, NULL_TREE);
1580 else
1581 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), unshare_expr (valist),
1582 f_gbytes, NULL_TREE);
1583
1584 /* [1] Emit code to branch if bytes < rsize. */
1585 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1586 t = build2 (LT_EXPR, boolean_type_node, bytes, t);
1587 u = build1 (GOTO_EXPR, void_type_node, lab_false);
1588 t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
1589 gimplify_and_add (t, pre_p);
1590
1591 /* [3] Emit code for: addr_rtx = base + offs, where
1592 offs = max_save_area_size - bytes. */
1593 t = fold_convert (sizetype, bytes);
1594 offs = build2 (MINUS_EXPR, sizetype, size_int (max_save_area_size), t);
1595 if (float_reg_arg_p)
1596 base = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1597 NULL_TREE);
1598 else
1599 base = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1600 NULL_TREE);
1601
1602 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, offs);
1603 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1604 gimplify_and_add (t, pre_p);
1605
1606 /* [4] Emit code for: bytes -= rsize. */
1607 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1608 t = build2 (MINUS_EXPR, TREE_TYPE (bytes), bytes, t);
1609 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), bytes, t);
1610 gimplify_and_add (t, pre_p);
1611
1612 /* [6] Emit code to branch over the else clause, then the label. */
1613 t = build1 (GOTO_EXPR, void_type_node, lab_over);
1614 gimplify_and_add (t, pre_p);
1615 t = build1 (LABEL_EXPR, void_type_node, lab_false);
1616 gimplify_and_add (t, pre_p);
1617
1618 /* [8] Emit code for: bytes = 0. */
1619 t = fold_convert (TREE_TYPE (bytes), size_int (0));
1620 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), unshare_expr (bytes), t);
1621 gimplify_and_add (t, pre_p);
1622
1623 /* [9] Emit code for: addr_rtx = ovfl. */
1624 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1625 t = build2 (MODIFY_EXPR, void_type_node, addr, ovfl);
1626 gimplify_and_add (t, pre_p);
1627
1628 /* [10] Emit code for: ovfl += rsize. */
1629 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl), ovfl, size_int (rsize));
1630 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), unshare_expr (ovfl), t);
1631 gimplify_and_add (t, pre_p);
1632 t = build1 (LABEL_EXPR, void_type_node, lab_over);
1633 gimplify_and_add (t, pre_p);
1634 addr = fold_convert (ptrtype, addr);
1635
1636 return build_va_arg_indirect_ref (addr);
1637 }
1638
1639 /* Return true if OP is an offset suitable for use as a displacement in the
1640 address of a memory access in mode MODE. */
1641
1642 static bool
1643 rtx_ok_for_offset_p (enum machine_mode mode, rtx op)
1644 {
1645 if (!CONST_INT_P (op) || INTVAL (op) < 0)
1646 return false;
1647
1648 switch (mode)
1649 {
1650 case QImode:
1651 return INTVAL (op) <= 31;
1652
1653 case HImode:
1654 return (INTVAL (op) % 2) == 0 && INTVAL (op) < 63;
1655
1656 case SImode:
1657 case SFmode:
1658 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 127;
1659
1660 case DImode:
1661 case DFmode:
1662 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 123;
1663
1664 default:
1665 return false;
1666 }
1667 }
1668
1669 /* Return whether X is a legitimate memory address for a memory operand
1670 of mode MODE.
1671
1672 Legitimate addresses are defined in two variants: a strict variant
1673 and a non-strict one. The STRICT parameter chooses which variant
1674 is desired by the caller.
1675
1676 The strict variant is used in the reload pass. It must be defined
1677 so that any pseudo-register that has not been allocated a hard
1678 register is considered a memory reference. This is because in
1679 contexts where some kind of register is required, a
1680 pseudo-register with no hard register must be rejected. For
1681 non-hard registers, the strict variant should look up the
1682 `reg_renumber' array; it should then proceed using the hard
1683 register number in the array, or treat the pseudo as a memory
1684 reference if the array holds `-1'.
1685
1686 The non-strict variant is used in other passes. It must be
1687 defined to accept all pseudo-registers in every context where some
1688 kind of register is required. */
1689
1690 static bool
1691 visium_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
1692 {
1693 rtx base;
1694 unsigned int regno;
1695
1696 /* If X is base+disp, check that we have an appropriate offset. */
1697 if (GET_CODE (x) == PLUS)
1698 {
1699 if (!rtx_ok_for_offset_p (mode, XEXP (x, 1)))
1700 return false;
1701 base = XEXP (x, 0);
1702 }
1703 else
1704 base = x;
1705
1706 /* Now check the base: it must be either a register or a subreg thereof. */
1707 if (GET_CODE (base) == SUBREG)
1708 base = SUBREG_REG (base);
1709 if (!REG_P (base))
1710 return false;
1711
1712 regno = REGNO (base);
1713
1714 /* For the strict variant, the register must be REGNO_OK_FOR_BASE_P. */
1715 if (strict)
1716 return REGNO_OK_FOR_BASE_P (regno);
1717
1718 /* For the non-strict variant, the register may also be a pseudo. */
1719 return BASE_REGISTER_P (regno) || regno >= FIRST_PSEUDO_REGISTER;
1720 }
1721
1722 /* Try machine-dependent ways of modifying an illegitimate address
1723 to be legitimate. If we find one, return the new, valid address.
1724 This macro is used in only one place: `memory_address' in explow.c.
1725
1726 OLDX is the address as it was before break_out_memory_refs was called.
1727 In some cases it is useful to look at this to decide what needs to be done.
1728
1729 MODE and WIN are passed so that this macro can use
1730 GO_IF_LEGITIMATE_ADDRESS.
1731
1732 It is always safe for this macro to do nothing. It exists to recognize
1733 opportunities to optimize the output.
1734
1735 For Visium
1736
1737 memory (reg + <out of range int>)
1738
1739 is transformed to
1740
1741 base_int = <out of range int> & ~mask
1742 ptr_reg = reg + base_int
1743 memory (ptr_reg + <out of range int> - base_int)
1744
1745 Thus ptr_reg is a base register for a range of addresses,
1746 which should help CSE.
1747
1748 For a 1 byte reference mask is 0x1f
1749 for a 2 byte reference mask is 0x3f
1750 For a 4 byte reference mask is 0x7f
1751
1752 This reflects the indexing range of the processor.
1753
1754 For a > 4 byte reference the mask is 0x7f provided all of the words
1755 can be accessed with the base address obtained. Otherwise a mask
1756 of 0x3f is used.
1757
1758 On rare occasions an unaligned base register value with an
1759 unaligned offset is generated. Unaligned offsets are left alone for
1760 this reason. */
1761
1762 static rtx
1763 visium_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1764 enum machine_mode mode)
1765 {
1766 if (GET_CODE (x) == PLUS
1767 && GET_CODE (XEXP (x, 1)) == CONST_INT
1768 && GET_CODE (XEXP (x, 0)) == REG && mode != BLKmode)
1769 {
1770 int offset = INTVAL (XEXP (x, 1));
1771 int size = GET_MODE_SIZE (mode);
1772 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1773 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1774 int offset_base = offset & ~mask;
1775
1776 /* Check that all of the words can be accessed. */
1777 if (4 < size && 0x80 < size + offset - offset_base)
1778 offset_base = offset & ~0x3f;
1779 if (offset_base != 0 && offset_base != offset && (offset & mask1) == 0)
1780 {
1781 rtx ptr_reg = force_reg (Pmode,
1782 gen_rtx_PLUS (Pmode,
1783 XEXP (x, 0),
1784 GEN_INT (offset_base)));
1785
1786 return plus_constant (Pmode, ptr_reg, offset - offset_base);
1787 }
1788 }
1789
1790 return x;
1791 }
1792
1793 /* Perform a similar function to visium_legitimize_address, but this time
1794 for reload. Generating new registers is not an option here. Parts
1795 that need reloading are indicated by calling push_reload. */
1796
1797 rtx
1798 visium_legitimize_reload_address (rtx x, enum machine_mode mode, int opnum,
1799 int type, int ind ATTRIBUTE_UNUSED)
1800 {
1801 rtx newrtx, tem = NULL_RTX;
1802
1803 if (mode == BLKmode)
1804 return NULL_RTX;
1805
1806 if (optimize && GET_CODE (x) == PLUS)
1807 tem = simplify_binary_operation (PLUS, GET_MODE (x), XEXP (x, 0),
1808 XEXP (x, 1));
1809
1810 newrtx = tem ? tem : x;
1811 if (GET_CODE (newrtx) == PLUS
1812 && GET_CODE (XEXP (newrtx, 1)) == CONST_INT
1813 && GET_CODE (XEXP (newrtx, 0)) == REG
1814 && BASE_REGISTER_P (REGNO (XEXP (newrtx, 0))))
1815 {
1816 int offset = INTVAL (XEXP (newrtx, 1));
1817 int size = GET_MODE_SIZE (mode);
1818 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1819 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1820 int offset_base = offset & ~mask;
1821
1822 /* Check that all of the words can be accessed. */
1823 if (4 < size && 0x80 < size + offset - offset_base)
1824 offset_base = offset & ~0x3f;
1825
1826 if (offset_base && (offset & mask1) == 0)
1827 {
1828 rtx temp = gen_rtx_PLUS (Pmode,
1829 XEXP (newrtx, 0), GEN_INT (offset_base));
1830
1831 x = gen_rtx_PLUS (Pmode, temp, GEN_INT (offset - offset_base));
1832 push_reload (XEXP (x, 0), 0, &XEXP (x, 0), 0,
1833 BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum,
1834 (enum reload_type) type);
1835 return x;
1836 }
1837 }
1838
1839 return NULL_RTX;
1840 }
1841
1842 /* Return the cost of moving data of mode MODE from a register in class FROM to
1843 one in class TO. A value of 2 is the default; other values are interpreted
1844 relative to that. */
1845
1846 static int
1847 visium_register_move_cost (enum machine_mode mode, reg_class_t from,
1848 reg_class_t to)
1849 {
1850 const int numwords = (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) ? 1 : 2;
1851
1852 if (from == MDB || to == MDB)
1853 return 4;
1854 else if (from == MDC || to == MDC || (from == FP_REGS) != (to == FP_REGS))
1855 return 4 * numwords;
1856 else
1857 return 2 * numwords;
1858 }
1859
1860 /* Return the cost of moving data of mode MODE between a register of class
1861 CLASS and memory. IN is zero if the value is to be written to memory,
1862 non-zero if it is to be read in. This cost is relative to those in
1863 visium_register_move_cost. */
1864
1865 static int
1866 visium_memory_move_cost (enum machine_mode mode,
1867 reg_class_t to ATTRIBUTE_UNUSED,
1868 bool in)
1869 {
1870 /* Moving data in can be from PROM and this is expensive. */
1871 if (in)
1872 {
1873 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
1874 return 7;
1875 else
1876 return 13;
1877 }
1878
1879 /* Moving data out is mostly to RAM and should be cheaper. */
1880 else
1881 {
1882 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
1883 return 6;
1884 else
1885 return 12;
1886 }
1887 }
1888
1889 /* Return the relative costs of expression X. */
1890
1891 static bool
1892 visium_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
1893 int opno ATTRIBUTE_UNUSED, int *total,
1894 bool speed ATTRIBUTE_UNUSED)
1895 {
1896 enum machine_mode mode = GET_MODE (x);
1897
1898 switch (code)
1899 {
1900 case CONST_INT:
1901 /* Small integers are as cheap as registers. 4-byte values can
1902 be fetched as immediate constants - let's give that the cost
1903 of an extra insn. */
1904 *total = COSTS_N_INSNS (!satisfies_constraint_J (x));
1905 return true;
1906
1907 case CONST:
1908 case LABEL_REF:
1909 case SYMBOL_REF:
1910 *total = COSTS_N_INSNS (2);
1911 return true;
1912
1913 case CONST_DOUBLE:
1914 {
1915 rtx high, low;
1916 split_double (x, &high, &low);
1917 *total =
1918 COSTS_N_INSNS
1919 (!satisfies_constraint_J (high) + !satisfies_constraint_J (low));
1920 return true;
1921 }
1922
1923 case MULT:
1924 *total = COSTS_N_INSNS (3);
1925 return false;
1926
1927 case DIV:
1928 case UDIV:
1929 case MOD:
1930 case UMOD:
1931 if (mode == DImode)
1932 *total = COSTS_N_INSNS (64);
1933 else
1934 *total = COSTS_N_INSNS (32);
1935 return false;
1936
1937 case PLUS:
1938 case MINUS:
1939 case NEG:
1940 /* DImode operations are performed directly on the ALU. */
1941 if (mode == DImode)
1942 *total = COSTS_N_INSNS (2);
1943 else
1944 *total = COSTS_N_INSNS (1);
1945 return false;
1946
1947 case ASHIFT:
1948 case ASHIFTRT:
1949 case LSHIFTRT:
1950 /* DImode operations are performed on the EAM instead. */
1951 if (mode == DImode)
1952 *total = COSTS_N_INSNS (3);
1953 else
1954 *total = COSTS_N_INSNS (1);
1955 return false;
1956
1957 case COMPARE:
1958 /* This matches the btst pattern. */
1959 if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT
1960 && XEXP (x, 1) == const0_rtx
1961 && XEXP (XEXP (x, 0), 1) == const1_rtx
1962 && satisfies_constraint_K (XEXP (XEXP (x, 0), 2)))
1963 *total = COSTS_N_INSNS (1);
1964 return false;
1965
1966 default:
1967 return false;
1968 }
1969 }
1970
1971 /* Split a double move of OPERANDS in MODE. */
1972
1973 void
1974 split_double_move (rtx *operands, enum machine_mode mode)
1975 {
1976 bool swap = false;
1977
1978 /* Check register to register with overlap. */
1979 if (GET_CODE (operands[0]) == REG
1980 && GET_CODE (operands[1]) == REG
1981 && REGNO (operands[0]) == REGNO (operands[1]) + 1)
1982 swap = true;
1983
1984 /* Check memory to register where the base reg overlaps the destination. */
1985 if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == MEM)
1986 {
1987 rtx op = XEXP (operands[1], 0);
1988
1989 if (GET_CODE (op) == SUBREG)
1990 op = SUBREG_REG (op);
1991
1992 if (GET_CODE (op) == REG && REGNO (op) == REGNO (operands[0]))
1993 swap = true;
1994
1995 if (GET_CODE (op) == PLUS)
1996 {
1997 rtx x = XEXP (op, 0);
1998 rtx y = XEXP (op, 1);
1999
2000 if (GET_CODE (x) == REG && REGNO (x) == REGNO (operands[0]))
2001 swap = true;
2002
2003 if (GET_CODE (y) == REG && REGNO (y) == REGNO (operands[0]))
2004 swap = true;
2005 }
2006 }
2007
2008 if (swap)
2009 {
2010 operands[2] = operand_subword (operands[0], 1, 1, mode);
2011 operands[3] = operand_subword (operands[1], 1, 1, mode);
2012 operands[4] = operand_subword (operands[0], 0, 1, mode);
2013 operands[5] = operand_subword (operands[1], 0, 1, mode);
2014 }
2015 else
2016 {
2017 operands[2] = operand_subword (operands[0], 0, 1, mode);
2018 operands[3] = operand_subword (operands[1], 0, 1, mode);
2019 operands[4] = operand_subword (operands[0], 1, 1, mode);
2020 operands[5] = operand_subword (operands[1], 1, 1, mode);
2021 }
2022 }
2023
2024 /* Expand a copysign of OPERANDS in MODE. */
2025
2026 void
2027 visium_expand_copysign (rtx *operands, enum machine_mode mode)
2028 {
2029 rtx dest = operands[0];
2030 rtx op0 = operands[1];
2031 rtx op1 = operands[2];
2032 rtx mask = force_reg (SImode, GEN_INT (0x7fffffff));
2033 rtx x;
2034
2035 /* We manually handle SFmode because the abs and neg instructions of
2036 the FPU on the MCM have a non-standard behavior wrt NaNs. */
2037 gcc_assert (mode == SFmode);
2038
2039 /* First get all the non-sign bits of OP0. */
2040 if (GET_CODE (op0) == CONST_DOUBLE)
2041 {
2042 if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0)))
2043 op0 = simplify_unary_operation (ABS, mode, op0, mode);
2044 if (op0 != CONST0_RTX (mode))
2045 {
2046 long l;
2047 REAL_VALUE_TYPE rv;
2048 REAL_VALUE_FROM_CONST_DOUBLE (rv, op0);
2049 REAL_VALUE_TO_TARGET_SINGLE (rv, l);
2050 op0 = force_reg (SImode, GEN_INT (trunc_int_for_mode (l, SImode)));
2051 }
2052 }
2053 else
2054 {
2055 op0 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op0));
2056 op0 = force_reg (SImode, gen_rtx_AND (SImode, op0, mask));
2057 }
2058
2059 /* Then get the sign bit of OP1. */
2060 mask = force_reg (SImode, gen_rtx_NOT (SImode, mask));
2061 op1 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op1));
2062 op1 = force_reg (SImode, gen_rtx_AND (SImode, op1, mask));
2063
2064 /* Finally OR the two values. */
2065 if (op0 == CONST0_RTX (SFmode))
2066 x = op1;
2067 else
2068 x = force_reg (SImode, gen_rtx_IOR (SImode, op0, op1));
2069
2070 /* And move the result to the destination. */
2071 emit_insn (gen_rtx_SET (dest, gen_lowpart (SFmode, x)));
2072 }
2073
2074 /* Expand a cstore of OPERANDS in MODE for EQ/NE/LTU/GTU/GEU/LEU. We generate
2075 the result in the C flag and use the ADC/SUBC instructions to write it into
2076 the destination register.
2077
2078 It would also be possible to implement support for LT/GT/LE/GE by means of
2079 the RFLAG instruction followed by some shifts, but this can pessimize the
2080 generated code. */
2081
2082 void
2083 visium_expand_int_cstore (rtx *operands, enum machine_mode mode)
2084 {
2085 enum rtx_code code = GET_CODE (operands[1]);
2086 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], sltu;
2087 bool reverse = false;
2088
2089 switch (code)
2090 {
2091 case EQ:
2092 case NE:
2093 /* We use a special comparison to get the result in the C flag. */
2094 if (op2 != const0_rtx)
2095 op1 = force_reg (mode, gen_rtx_XOR (mode, op1, op2));
2096 op1 = gen_rtx_NOT (mode, op1);
2097 op2 = constm1_rtx;
2098 if (code == EQ)
2099 reverse = true;
2100 break;
2101
2102 case LEU:
2103 case GEU:
2104 /* The result is naturally in the C flag modulo a couple of tricks. */
2105 code = reverse_condition (code);
2106 reverse = true;
2107
2108 /* ... fall through ... */
2109
2110 case LTU:
2111 case GTU:
2112 if (code == GTU)
2113 {
2114 rtx tmp = op1;
2115 op1 = op2;
2116 op2 = tmp;
2117 }
2118 break;
2119
2120 default:
2121 gcc_unreachable ();
2122 }
2123
2124 /* We need either a single ADC or a SUBC and a PLUS. */
2125 sltu = gen_rtx_LTU (SImode, op1, op2);
2126
2127 if (reverse)
2128 {
2129 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, sltu));
2130 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2131 }
2132 else
2133 emit_insn (gen_rtx_SET (op0, sltu));
2134 }
2135
2136 /* Expand a cstore of OPERANDS in MODE for LT/GT/UNGE/UNLE. We generate the
2137 result in the C flag and use the ADC/SUBC instructions to write it into
2138 the destination register. */
2139
2140 void
2141 visium_expand_fp_cstore (rtx *operands,
2142 enum machine_mode mode ATTRIBUTE_UNUSED)
2143 {
2144 enum rtx_code code = GET_CODE (operands[1]);
2145 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], slt;
2146 bool reverse = false;
2147
2148 switch (code)
2149 {
2150 case UNLE:
2151 case UNGE:
2152 /* The result is naturally in the C flag modulo a couple of tricks. */
2153 code = reverse_condition_maybe_unordered (code);
2154 reverse = true;
2155
2156 /* ... fall through ... */
2157
2158 case LT:
2159 case GT:
2160 if (code == GT)
2161 {
2162 rtx tmp = op1;
2163 op1 = op2;
2164 op2 = tmp;
2165 }
2166 break;
2167
2168 default:
2169 gcc_unreachable ();
2170 }
2171
2172 /* We need either a single ADC or a SUBC and a PLUS. */
2173 slt = gen_rtx_LT (SImode, op1, op2);
2174
2175 if (reverse)
2176 {
2177 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, slt));
2178 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2179 }
2180 else
2181 emit_insn (gen_rtx_SET (op0, slt));
2182 }
2183
2184 /* Split a compare-and-store with CODE, operands OP2 and OP3, combined with
2185 operation with OP_CODE, operands OP0 and OP1. */
2186
2187 void
2188 visium_split_cstore (enum rtx_code op_code, rtx op0, rtx op1,
2189 enum rtx_code code, rtx op2, rtx op3)
2190 {
2191 enum machine_mode cc_mode = visium_select_cc_mode (code, op2, op3);
2192
2193 /* If a FP cstore was reversed, then it was originally UNGE/UNLE. */
2194 if (cc_mode == CCFPEmode && (op_code == NEG || op_code == MINUS))
2195 cc_mode = CCFPmode;
2196
2197 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2198 rtx x = gen_rtx_COMPARE (cc_mode, op2, op3);
2199 x = gen_rtx_SET (flags, x);
2200 emit_insn (x);
2201
2202 x = gen_rtx_fmt_ee (code, SImode, flags, const0_rtx);
2203 switch (op_code)
2204 {
2205 case SET:
2206 break;
2207 case NEG:
2208 x = gen_rtx_NEG (SImode, x);
2209 break;
2210 case PLUS:
2211 case MINUS:
2212 x = gen_rtx_fmt_ee (op_code, SImode, op1, x);
2213 break;
2214 default:
2215 gcc_unreachable ();
2216 }
2217
2218 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2219 XVECEXP (pat, 0, 0) = gen_rtx_SET (op0, x);
2220 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2221 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2222 emit_insn (pat);
2223
2224 visium_flags_exposed = true;
2225 }
2226
2227 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2228 address SRC_REG to DST with address DST_REG in 4-byte chunks. */
2229
2230 static void
2231 expand_block_move_4 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2232 {
2233 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__long_int_memcpy");
2234 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2235 unsigned int rem = bytes % 4;
2236
2237 if (TARGET_BMI)
2238 {
2239 unsigned int i;
2240 rtx insn;
2241
2242 emit_move_insn (regno_reg_rtx[1], dst_reg);
2243 emit_move_insn (regno_reg_rtx[2], src_reg);
2244 emit_move_insn (regno_reg_rtx[3], bytes_rtx);
2245
2246 insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (8));
2247 XVECEXP (insn, 0, 0)
2248 = gen_rtx_SET (replace_equiv_address_nv (dst, regno_reg_rtx[1]),
2249 replace_equiv_address_nv (src, regno_reg_rtx[2]));
2250 XVECEXP (insn, 0, 1) = gen_rtx_USE (VOIDmode, regno_reg_rtx[3]);
2251 for (i = 1; i <= 6; i++)
2252 XVECEXP (insn, 0, 1 + i)
2253 = gen_rtx_CLOBBER (VOIDmode, regno_reg_rtx[i]);
2254 emit_insn (insn);
2255 }
2256 else
2257 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, src_reg,
2258 Pmode,
2259 convert_to_mode (TYPE_MODE (sizetype),
2260 GEN_INT (bytes >> 2),
2261 TYPE_UNSIGNED (sizetype)),
2262 TYPE_MODE (sizetype));
2263 if (rem == 0)
2264 return;
2265
2266 dst = replace_equiv_address_nv (dst, dst_reg);
2267 src = replace_equiv_address_nv (src, src_reg);
2268 bytes -= rem;
2269
2270 if (rem > 1)
2271 {
2272 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2273 adjust_address_nv (src, HImode, bytes));
2274 bytes += 2;
2275 rem -= 2;
2276 }
2277
2278 if (rem > 0)
2279 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2280 adjust_address_nv (src, QImode, bytes));
2281 }
2282
2283 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2284 address SRC_REG to DST with address DST_REG in 2-bytes chunks. */
2285
2286 static void
2287 expand_block_move_2 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2288 {
2289 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__wrd_memcpy");
2290 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2291 unsigned int rem = bytes % 2;
2292
2293 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, src_reg,
2294 Pmode,
2295 convert_to_mode (TYPE_MODE (sizetype),
2296 GEN_INT (bytes >> 1),
2297 TYPE_UNSIGNED (sizetype)),
2298 TYPE_MODE (sizetype));
2299 if (rem == 0)
2300 return;
2301
2302 dst = replace_equiv_address_nv (dst, dst_reg);
2303 src = replace_equiv_address_nv (src, src_reg);
2304 bytes -= rem;
2305
2306 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2307 adjust_address_nv (src, QImode, bytes));
2308 }
2309
2310 /* Generate a call to a library function to move BYTES_RTX bytes from address
2311 SRC_REG to address DST_REG in 1-byte chunks. */
2312
2313 static void
2314 expand_block_move_1 (rtx dst_reg, rtx src_reg, rtx bytes_rtx)
2315 {
2316 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__byt_memcpy");
2317
2318 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
2319 src_reg, Pmode,
2320 convert_to_mode (TYPE_MODE (sizetype),
2321 bytes_rtx,
2322 TYPE_UNSIGNED (sizetype)),
2323 TYPE_MODE (sizetype));
2324 }
2325
2326 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2327 address DST_REG to VALUE_RTX in 4-byte chunks. */
2328
2329 static void
2330 expand_block_set_4 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2331 {
2332 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__long_int_memset");
2333 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2334 unsigned int rem = bytes % 4;
2335
2336 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2337 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
2338 value_rtx, Pmode,
2339 convert_to_mode (TYPE_MODE (sizetype),
2340 GEN_INT (bytes >> 2),
2341 TYPE_UNSIGNED (sizetype)),
2342 TYPE_MODE (sizetype));
2343 if (rem == 0)
2344 return;
2345
2346 dst = replace_equiv_address_nv (dst, dst_reg);
2347 bytes -= rem;
2348
2349 if (rem > 1)
2350 {
2351 if (CONST_INT_P (value_rtx))
2352 {
2353 const unsigned HOST_WIDE_INT value = UINTVAL (value_rtx) & 0xff;
2354 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2355 gen_int_mode ((value << 8) | value, HImode));
2356 }
2357 else
2358 {
2359 rtx temp = convert_to_mode (QImode, value_rtx, 1);
2360 emit_move_insn (adjust_address_nv (dst, QImode, bytes), temp);
2361 emit_move_insn (adjust_address_nv (dst, QImode, bytes + 1), temp);
2362 }
2363 bytes += 2;
2364 rem -= 2;
2365 }
2366
2367 if (rem > 0)
2368 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2369 convert_to_mode (QImode, value_rtx, 1));
2370 }
2371
2372 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2373 address DST_REG to VALUE_RTX in 2-byte chunks. */
2374
2375 static void
2376 expand_block_set_2 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2377 {
2378 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__wrd_memset");
2379 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2380 unsigned int rem = bytes % 2;
2381
2382 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2383 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
2384 value_rtx, Pmode,
2385 convert_to_mode (TYPE_MODE (sizetype),
2386 GEN_INT (bytes >> 1),
2387 TYPE_UNSIGNED (sizetype)),
2388 TYPE_MODE (sizetype));
2389 if (rem == 0)
2390 return;
2391
2392 dst = replace_equiv_address_nv (dst, dst_reg);
2393 bytes -= rem;
2394
2395 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2396 convert_to_mode (QImode, value_rtx, 1));
2397 }
2398
2399 /* Generate a call to a library function to set BYTES_RTX bytes at address
2400 DST_REG to VALUE_RTX in 1-byte chunks. */
2401
2402 static void
2403 expand_block_set_1 (rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2404 {
2405 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__byt_memset");
2406
2407 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2408 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
2409 value_rtx, Pmode,
2410 convert_to_mode (TYPE_MODE (sizetype),
2411 bytes_rtx,
2412 TYPE_UNSIGNED (sizetype)),
2413 TYPE_MODE (sizetype));
2414 }
2415
2416 /* Expand string/block move operations.
2417
2418 operands[0] is the pointer to the destination.
2419 operands[1] is the pointer to the source.
2420 operands[2] is the number of bytes to move.
2421 operands[3] is the alignment.
2422
2423 Return 1 upon success, 0 otherwise. */
2424
2425 int
2426 visium_expand_block_move (rtx *operands)
2427 {
2428 rtx dst = operands[0];
2429 rtx src = operands[1];
2430 rtx bytes_rtx = operands[2];
2431 rtx align_rtx = operands[3];
2432 const int align = INTVAL (align_rtx);
2433 rtx dst_reg, src_reg;
2434 tree dst_expr, src_expr;
2435
2436 /* We only handle a fixed number of bytes for now. */
2437 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2438 return 0;
2439
2440 /* Copy the addresses into scratch registers. */
2441 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2442 src_reg = copy_addr_to_reg (XEXP (src, 0));
2443
2444 /* Move the data with the appropriate granularity. */
2445 if (align >= 4)
2446 expand_block_move_4 (dst, dst_reg, src, src_reg, bytes_rtx);
2447 else if (align >= 2)
2448 expand_block_move_2 (dst, dst_reg, src, src_reg, bytes_rtx);
2449 else
2450 expand_block_move_1 (dst_reg, src_reg, bytes_rtx);
2451
2452 /* Since DST and SRC are passed to a libcall, mark the corresponding
2453 tree EXPR as addressable. */
2454 dst_expr = MEM_EXPR (dst);
2455 src_expr = MEM_EXPR (src);
2456 if (dst_expr)
2457 mark_addressable (dst_expr);
2458 if (src_expr)
2459 mark_addressable (src_expr);
2460
2461 return 1;
2462 }
2463
2464 /* Expand string/block set operations.
2465
2466 operands[0] is the pointer to the destination.
2467 operands[1] is the number of bytes to set.
2468 operands[2] is the source value.
2469 operands[3] is the alignment.
2470
2471 Return 1 upon success, 0 otherwise. */
2472
2473 int
2474 visium_expand_block_set (rtx *operands)
2475 {
2476 rtx dst = operands[0];
2477 rtx bytes_rtx = operands[1];
2478 rtx value_rtx = operands[2];
2479 rtx align_rtx = operands[3];
2480 const int align = INTVAL (align_rtx);
2481 rtx dst_reg;
2482 tree dst_expr;
2483
2484 /* We only handle a fixed number of bytes for now. */
2485 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2486 return 0;
2487
2488 /* Copy the address into a scratch register. */
2489 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2490
2491 /* Set the data with the appropriate granularity. */
2492 if (align >= 4)
2493 expand_block_set_4 (dst, dst_reg, value_rtx, bytes_rtx);
2494 else if (align >= 2)
2495 expand_block_set_2 (dst, dst_reg, value_rtx, bytes_rtx);
2496 else
2497 expand_block_set_1 (dst_reg, value_rtx, bytes_rtx);
2498
2499 /* Since DST is passed to a libcall, mark the corresponding
2500 tree EXPR as addressable. */
2501 dst_expr = MEM_EXPR (dst);
2502 if (dst_expr)
2503 mark_addressable (dst_expr);
2504
2505 return 1;
2506 }
2507
2508 /* Initialize a trampoline. M_TRAMP is an RTX for the memory block for the
2509 trampoline, FNDECL is the FUNCTION_DECL for the nested function and
2510 STATIC_CHAIN is an RTX for the static chain value that should be passed
2511 to the function when it is called. */
2512
2513 static void
2514 visium_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
2515 {
2516 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2517 rtx addr = XEXP (m_tramp, 0);
2518
2519 /* The trampoline initialization sequence is:
2520
2521 moviu r9,%u FUNCTION
2522 movil r9,%l FUNCTION
2523 moviu r20,%u STATIC
2524 bra tr,r9,r9
2525 movil r20,%l STATIC
2526
2527 We don't use r0 as the destination register of the branch because we want
2528 the Branch Pre-decode Logic of the GR6 to use the Address Load Array to
2529 predict the branch target. */
2530
2531 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 0)),
2532 plus_constant (SImode,
2533 expand_shift (RSHIFT_EXPR, SImode, fnaddr,
2534 16, NULL_RTX, 1),
2535 0x04a90000));
2536
2537 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 4)),
2538 plus_constant (SImode,
2539 expand_and (SImode, fnaddr, GEN_INT (0xffff),
2540 NULL_RTX),
2541 0x04890000));
2542
2543 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 8)),
2544 plus_constant (SImode,
2545 expand_shift (RSHIFT_EXPR, SImode,
2546 static_chain,
2547 16, NULL_RTX, 1),
2548 0x04b40000));
2549
2550 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)),
2551 gen_int_mode (0xff892404, SImode));
2552
2553 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 16)),
2554 plus_constant (SImode,
2555 expand_and (SImode, static_chain,
2556 GEN_INT (0xffff), NULL_RTX),
2557 0x04940000));
2558
2559 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__set_trampoline_parity"),
2560 LCT_NORMAL, VOIDmode, 1, addr, SImode);
2561 }
2562
2563 /* Return true if the current function must have and use a frame pointer. */
2564
2565 static bool
2566 visium_frame_pointer_required (void)
2567 {
2568 /* The frame pointer is required if the function isn't leaf to be able to
2569 do manual stack unwinding. */
2570 if (!crtl->is_leaf)
2571 return true;
2572
2573 /* If the stack pointer is dynamically modified in the function, it cannot
2574 serve as the frame pointer. */
2575 if (!crtl->sp_is_unchanging)
2576 return true;
2577
2578 /* If the function receives nonlocal gotos, it needs to save the frame
2579 pointer in the nonlocal_goto_save_area object. */
2580 if (cfun->has_nonlocal_label)
2581 return true;
2582
2583 /* The frame also needs to be established in some special cases. */
2584 if (visium_frame_needed)
2585 return true;
2586
2587 return false;
2588 }
2589
2590 /* Profiling support. Just a call to MCOUNT is needed. No labelled counter
2591 location is involved. Proper support for __builtin_return_address is also
2592 required, which is fairly straightforward provided a frame gets created. */
2593
2594 void
2595 visium_profile_hook (void)
2596 {
2597 visium_frame_needed = true;
2598 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "mcount"), LCT_NORMAL,
2599 VOIDmode, 0);
2600 }
2601
2602 /* A C expression whose value is RTL representing the address in a stack frame
2603 where the pointer to the caller's frame is stored. Assume that FRAMEADDR is
2604 an RTL expression for the address of the stack frame itself.
2605
2606 If you don't define this macro, the default is to return the value of
2607 FRAMEADDR--that is, the stack frame address is also the address of the stack
2608 word that points to the previous frame. */
2609
2610 rtx
2611 visium_dynamic_chain_address (rtx frame)
2612 {
2613 /* This is the default, but we need to make sure the frame gets created. */
2614 visium_frame_needed = true;
2615 return frame;
2616 }
2617
2618 /* A C expression whose value is RTL representing the value of the return
2619 address for the frame COUNT steps up from the current frame, after the
2620 prologue. FRAMEADDR is the frame pointer of the COUNT frame, or the frame
2621 pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
2622 defined.
2623
2624 The value of the expression must always be the correct address when COUNT is
2625 zero, but may be `NULL_RTX' if there is not way to determine the return
2626 address of other frames. */
2627
2628 rtx
2629 visium_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
2630 {
2631 /* Dont try to compute anything other than frame zero. */
2632 if (count != 0)
2633 return NULL_RTX;
2634
2635 visium_frame_needed = true;
2636 return
2637 gen_frame_mem (Pmode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2638 }
2639
2640 /* Helper function for EH_RETURN_HANDLER_RTX. Return the RTX representing a
2641 location in which to store the address of an exception handler to which we
2642 should return. */
2643
2644 rtx
2645 visium_eh_return_handler_rtx (void)
2646 {
2647 rtx mem
2648 = gen_frame_mem (SImode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2649 MEM_VOLATILE_P (mem) = 1;
2650 return mem;
2651 }
2652
2653 static struct machine_function *
2654 visium_init_machine_status (void)
2655 {
2656 return ggc_cleared_alloc<machine_function> ();
2657 }
2658
2659 /* The per-function data machinery is needed to indicate when a frame
2660 is required. */
2661
2662 void
2663 visium_init_expanders (void)
2664 {
2665 init_machine_status = visium_init_machine_status;
2666 }
2667
2668 /* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE,
2669 return the mode to be used for the comparison. */
2670
2671 enum machine_mode
2672 visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
2673 {
2674 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2675 {
2676 switch (code)
2677 {
2678 case EQ:
2679 case NE:
2680 case ORDERED:
2681 case UNORDERED:
2682 case UNLT:
2683 case UNLE:
2684 case UNGT:
2685 case UNGE:
2686 return CCFPmode;
2687
2688 case LT:
2689 case LE:
2690 case GT:
2691 case GE:
2692 return CCFPEmode;
2693
2694 /* These 2 comparison codes are not supported. */
2695 case UNEQ:
2696 case LTGT:
2697 default:
2698 gcc_unreachable ();
2699 }
2700 }
2701
2702 if (op1 != const0_rtx)
2703 return CCmode;
2704
2705 switch (GET_CODE (op0))
2706 {
2707 case PLUS:
2708 case MINUS:
2709 case NEG:
2710 case ASHIFT:
2711 case LTU:
2712 case LT:
2713 /* The V flag may be set differently from a COMPARE with zero.
2714 The consequence is that a comparison operator testing V must
2715 be turned into another operator not testing V and yielding
2716 the same result for a comparison with zero. That's possible
2717 for GE/LT which become NC/NS respectively, but not for GT/LE
2718 for which the altered operator doesn't exist on the Visium. */
2719 return CC_NOOVmode;
2720
2721 case ZERO_EXTRACT:
2722 /* This is a btst, the result is in C instead of Z. */
2723 return CC_BTSTmode;
2724
2725 case CONST_INT:
2726 /* This is a degenerate case, typically an uninitialized variable. */
2727 gcc_assert (op0 == constm1_rtx);
2728 case REG:
2729 case AND:
2730 case IOR:
2731 case XOR:
2732 case NOT:
2733 case ASHIFTRT:
2734 case LSHIFTRT:
2735 case TRUNCATE:
2736 case SIGN_EXTEND:
2737 /* Pretend that the flags are set as for a COMPARE with zero.
2738 That's mostly true, except for the 2 right shift insns that
2739 will set the C flag. But the C flag is relevant only for
2740 the unsigned comparison operators and they are eliminated
2741 when applied to a comparison with zero. */
2742 return CCmode;
2743
2744 default:
2745 gcc_unreachable ();
2746 }
2747 }
2748
2749 /* Split a compare-and-branch with CODE, operands OP0 and OP1, and LABEL. */
2750
2751 void
2752 visium_split_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx label)
2753 {
2754 enum machine_mode cc_mode = visium_select_cc_mode (code, op0, op1);
2755 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2756
2757 rtx x = gen_rtx_COMPARE (cc_mode, op0, op1);
2758 x = gen_rtx_SET (flags, x);
2759 emit_insn (x);
2760
2761 x = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
2762 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, gen_rtx_LABEL_REF (Pmode, label),
2763 pc_rtx);
2764 x = gen_rtx_SET (pc_rtx, x);
2765 emit_jump_insn (x);
2766
2767 visium_flags_exposed = true;
2768 }
2769
2770 /* Branch instructions on the Visium.
2771
2772 Setting aside the interrupt-handling specific instructions, the ISA has
2773 two branch instructions: BRR and BRA. The former is used to implement
2774 short branches (+/- 2^17) within functions and its target is encoded in
2775 the instruction. The latter is used to implement all the other types
2776 of control flow changes and its target might not be statically known
2777 or even easily predictable at run time. Here's a complete summary of
2778 the patterns that generate a BRA instruction:
2779
2780 1. Indirect jump
2781 2. Table jump
2782 3. Call
2783 4. Sibling call
2784 5. Return
2785 6. Long branch
2786 7. Trampoline
2787
2788 Among these patterns, only the return (5) and the long branch (6) can be
2789 conditional; all the other patterns are always unconditional.
2790
2791 The following algorithm can be used to identify the pattern for which
2792 the BRA instruction was generated and work out its target:
2793
2794 A. If the source is r21 and the destination is r0, this is a return (5)
2795 and the target is the caller (i.e. the value of r21 on function's
2796 entry).
2797
2798 B. If the source is rN, N != 21 and the destination is r0, this is either
2799 an indirect jump or a table jump (1, 2) and the target is not easily
2800 predictable.
2801
2802 C. If the source is rN, N != 21 and the destination is r21, this is a call
2803 (3) and the target is given by the preceding MOVIL/MOVIU pair for rN,
2804 unless this is an indirect call in which case the target is not easily
2805 predictable.
2806
2807 D. If the source is rN, N != 21 and the destination is also rN, this is
2808 either a sibling call or a trampoline (4, 7) and the target is given
2809 by the preceding MOVIL/MOVIU pair for rN.
2810
2811 E. If the source is r21 and the destination is also r21, this is a long
2812 branch (6) and the target is given by the preceding MOVIL/MOVIU pair
2813 for r21.
2814
2815 The other combinations are not used. This implementation has been devised
2816 to accommodate the branch predictor of the GR6 but is used unconditionally
2817 by the compiler, i.e. including for earlier processors. */
2818
2819 /* Output a conditional/unconditional branch to LABEL. COND is the string
2820 condition. INSN is the instruction. */
2821
2822 static const char *
2823 output_branch (rtx label, const char *cond, rtx_insn *insn)
2824 {
2825 char str[64];
2826 rtx operands[2];
2827
2828 gcc_assert (cond);
2829 operands[0] = label;
2830
2831 /* If the length of the instruction is greater than 8, then this is a
2832 long branch and we need to work harder to emit it properly. */
2833 if (get_attr_length (insn) > 8)
2834 {
2835 bool spilled;
2836
2837 /* If the link register has been saved, then we use it. */
2838 if (current_function_saves_lr ())
2839 {
2840 operands[1] = regno_reg_rtx [LINK_REGNUM];
2841 spilled = false;
2842 }
2843
2844 /* Or else, if the long-branch register isn't live, we use it. */
2845 else if (!df_regs_ever_live_p (long_branch_regnum))
2846 {
2847 operands[1] = regno_reg_rtx [long_branch_regnum];
2848 spilled = false;
2849 }
2850
2851 /* Otherwise, we will use the long-branch register but we need to
2852 spill it to the stack and reload it at the end. We should have
2853 reserved the LR slot for this purpose. */
2854 else
2855 {
2856 operands[1] = regno_reg_rtx [long_branch_regnum];
2857 spilled = true;
2858 gcc_assert (current_function_has_lr_slot ());
2859 }
2860
2861 /* First emit the spill to the stack:
2862
2863 insn_in_delay_slot
2864 write.l [1](sp),reg */
2865 if (spilled)
2866 {
2867 if (final_sequence)
2868 {
2869 rtx_insn *delay = NEXT_INSN (insn);
2870 int seen;
2871 gcc_assert (delay);
2872
2873 final_scan_insn (delay, asm_out_file, optimize, 0, &seen);
2874 PATTERN (delay) = gen_blockage ();
2875 INSN_CODE (delay) = -1;
2876 }
2877
2878 if (current_function_saves_fp ())
2879 output_asm_insn ("write.l 1(sp),%1", operands);
2880 else
2881 output_asm_insn ("write.l (sp),%1", operands);
2882 }
2883
2884 /* Then emit the core sequence:
2885
2886 moviu reg,%u label
2887 movil reg,%l label
2888 bra tr,reg,reg
2889
2890 We don't use r0 as the destination register of the branch because we
2891 want the Branch Pre-decode Logic of the GR6 to use the Address Load
2892 Array to predict the branch target. */
2893 output_asm_insn ("moviu %1,%%u %0", operands);
2894 output_asm_insn ("movil %1,%%l %0", operands);
2895 strcpy (str, "bra ");
2896 strcat (str, cond);
2897 strcat (str, ",%1,%1");
2898 if (!spilled)
2899 strcat (str, "%#");
2900 strcat (str, "\t\t;long branch");
2901 output_asm_insn (str, operands);
2902
2903 /* Finally emit the reload:
2904
2905 read.l reg,[1](sp) */
2906 if (spilled)
2907 {
2908 if (current_function_saves_fp ())
2909 output_asm_insn (" read.l %1,1(sp)", operands);
2910 else
2911 output_asm_insn (" read.l %1,(sp)", operands);
2912 }
2913 }
2914
2915 /* Or else, if the label is PC, then this is a return. */
2916 else if (label == pc_rtx)
2917 {
2918 strcpy (str, "bra ");
2919 strcat (str, cond);
2920 strcat (str, ",r21,r0%#\t\t;return");
2921 output_asm_insn (str, operands);
2922 }
2923
2924 /* Otherwise, this is a short branch. */
2925 else
2926 {
2927 strcpy (str, "brr ");
2928 strcat (str, cond);
2929 strcat (str, ",%0%#");
2930 output_asm_insn (str, operands);
2931 }
2932
2933 return "";
2934 }
2935
2936 /* Output an unconditional branch to LABEL. INSN is the instruction. */
2937
2938 const char *
2939 output_ubranch (rtx label, rtx_insn *insn)
2940 {
2941 return output_branch (label, "tr", insn);
2942 }
2943
2944 /* Output a conditional branch to LABEL. CODE is the comparison code.
2945 CC_MODE is the mode of the CC register. REVERSED is non-zero if we
2946 should reverse the sense of the comparison. INSN is the instruction. */
2947
2948 const char *
2949 output_cbranch (rtx label, enum rtx_code code, enum machine_mode cc_mode,
2950 int reversed, rtx_insn *insn)
2951 {
2952 const char *cond;
2953
2954 if (reversed)
2955 {
2956 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
2957 code = reverse_condition_maybe_unordered (code);
2958 else
2959 code = reverse_condition (code);
2960 }
2961
2962 switch (code)
2963 {
2964 case NE:
2965 if (cc_mode == CC_BTSTmode)
2966 cond = "cs";
2967 else
2968 cond = "ne";
2969 break;
2970
2971 case EQ:
2972 if (cc_mode == CC_BTSTmode)
2973 cond = "cc";
2974 else
2975 cond = "eq";
2976 break;
2977
2978 case GE:
2979 if (cc_mode == CC_NOOVmode)
2980 cond = "nc";
2981 else
2982 cond = "ge";
2983 break;
2984
2985 case GT:
2986 cond = "gt";
2987 break;
2988
2989 case LE:
2990 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
2991 cond = "ls";
2992 else
2993 cond = "le";
2994 break;
2995
2996 case LT:
2997 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
2998 cond = "ns";
2999 else if (cc_mode == CC_NOOVmode)
3000 cond = "ns";
3001 else
3002 cond = "lt";
3003 break;
3004
3005 case GEU:
3006 cond = "cc";
3007 break;
3008
3009 case GTU:
3010 cond = "hi";
3011 break;
3012
3013 case LEU:
3014 cond = "ls";
3015 break;
3016
3017 case LTU:
3018 cond = "cs";
3019 break;
3020
3021 case UNORDERED:
3022 cond = "os";
3023 break;
3024
3025 case ORDERED:
3026 cond = "oc";
3027 break;
3028
3029 case UNGE:
3030 cond = "nc";
3031 break;
3032
3033 case UNGT:
3034 cond = "hi";
3035 break;
3036
3037 case UNLE:
3038 cond = "le";
3039 break;
3040
3041 case UNLT:
3042 cond = "lt";
3043 break;
3044
3045 /* These 2 comparison codes are not supported. */
3046 case UNEQ:
3047 case LTGT:
3048 default:
3049 gcc_unreachable ();
3050 }
3051
3052 return output_branch (label, cond, insn);
3053 }
3054
3055 /* Helper function for PRINT_OPERAND (STREAM, X, CODE). Output to stdio
3056 stream FILE the assembler syntax for an instruction operand OP subject
3057 to the modifier LETTER. */
3058
3059 void
3060 print_operand (FILE *file, rtx op, int letter)
3061 {
3062 switch (letter)
3063 {
3064 case '#':
3065 /* Output an insn in a delay slot. */
3066 if (final_sequence)
3067 visium_indent_opcode = 1;
3068 else
3069 fputs ("\n\t nop", file);
3070 return;
3071
3072 case 'b':
3073 /* Print LS 8 bits of operand. */
3074 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xff);
3075 return;
3076
3077 case 'w':
3078 /* Print LS 16 bits of operand. */
3079 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xffff);
3080 return;
3081
3082 case 'u':
3083 /* Print MS 16 bits of operand. */
3084 fprintf (file,
3085 HOST_WIDE_INT_PRINT_UNSIGNED, (UINTVAL (op) >> 16) & 0xffff);
3086 return;
3087
3088 case 'r':
3089 /* It's either a register or zero. */
3090 if (GET_CODE (op) == REG)
3091 fputs (reg_names[REGNO (op)], file);
3092 else
3093 fputs (reg_names[0], file);
3094 return;
3095
3096 case 'f':
3097 /* It's either a FP register or zero. */
3098 if (GET_CODE (op) == REG)
3099 fputs (reg_names[REGNO (op)], file);
3100 else
3101 fputs (reg_names[FP_FIRST_REGNUM], file);
3102 return;
3103 }
3104
3105 switch (GET_CODE (op))
3106 {
3107 case REG:
3108 if (letter == 'd')
3109 fputs (reg_names[REGNO (op) + 1], file);
3110 else
3111 fputs (reg_names[REGNO (op)], file);
3112 break;
3113
3114 case SYMBOL_REF:
3115 case LABEL_REF:
3116 case CONST:
3117 output_addr_const (file, op);
3118 break;
3119
3120 case MEM:
3121 visium_output_address (file, GET_MODE (op), XEXP (op, 0));
3122 break;
3123
3124 case CONST_INT:
3125 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
3126 break;
3127
3128 case CODE_LABEL:
3129 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (op));
3130 break;
3131
3132 case HIGH:
3133 print_operand (file, XEXP (op, 1), letter);
3134 break;
3135
3136 default:
3137 fatal_insn ("illegal operand ", op);
3138 }
3139 }
3140
3141 /* Output to stdio stream FILE the assembler syntax for an instruction operand
3142 that is a memory reference in MODE and whose address is ADDR. */
3143
3144 static void
3145 visium_output_address (FILE *file, enum machine_mode mode, rtx addr)
3146 {
3147 switch (GET_CODE (addr))
3148 {
3149 case REG:
3150 case SUBREG:
3151 fprintf (file, "(%s)", reg_names[true_regnum (addr)]);
3152 break;
3153
3154 case PLUS:
3155 {
3156 rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
3157
3158 switch (GET_CODE (x))
3159 {
3160 case REG:
3161 case SUBREG:
3162 if (CONST_INT_P (y))
3163 {
3164 unsigned int regno = true_regnum (x);
3165 HOST_WIDE_INT val = INTVAL (y);
3166 switch (mode)
3167 {
3168 case SImode:
3169 case DImode:
3170 case SFmode:
3171 case DFmode:
3172 val >>= 2;
3173 break;
3174
3175 case HImode:
3176 val >>= 1;
3177 break;
3178
3179 case QImode:
3180 default:
3181 break;
3182 }
3183 fprintf (file, HOST_WIDE_INT_PRINT_DEC"(%s)", val,
3184 reg_names[regno]);
3185 }
3186 else
3187 fatal_insn ("illegal operand address (1)", addr);
3188 break;
3189
3190 default:
3191 if (CONSTANT_P (x) && CONSTANT_P (y))
3192 output_addr_const (file, addr);
3193 else
3194 fatal_insn ("illegal operand address (2)", addr);
3195 break;
3196 }
3197 }
3198 break;
3199
3200 case LABEL_REF:
3201 case SYMBOL_REF:
3202 case CONST_INT:
3203 case CONST:
3204 output_addr_const (file, addr);
3205 break;
3206
3207 case NOTE:
3208 if (NOTE_KIND (addr) != NOTE_INSN_DELETED_LABEL)
3209 fatal_insn ("illegal operand address (3)", addr);
3210 break;
3211
3212 case CODE_LABEL:
3213 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (addr));
3214 break;
3215
3216 default:
3217 fatal_insn ("illegal operand address (4)", addr);
3218 break;
3219 }
3220 }
3221
3222 /* Helper function for PRINT_OPERAND_ADDRESS (STREAM, X). Output to stdio
3223 stream FILE the assembler syntax for an instruction operand that is a
3224 memory reference whose address is ADDR. */
3225
3226 void
3227 print_operand_address (FILE *file, rtx addr)
3228 {
3229 visium_output_address (file, QImode, addr);
3230 }
3231
3232 /* The Visium stack frames look like:
3233
3234 Before call After call
3235 +-----------------------+ +-----------------------+
3236 | | | |
3237 high | previous | | previous |
3238 mem | frame | | frame |
3239 | | | |
3240 +-----------------------+ +-----------------------+
3241 | | | |
3242 | arguments on stack | | arguments on stack |
3243 | | | |
3244 SP+0->+-----------------------+ +-----------------------+
3245 | reg parm save area, |
3246 | only created for |
3247 | variable argument |
3248 | functions |
3249 +-----------------------+
3250 | |
3251 | register save area |
3252 | |
3253 +-----------------------+
3254 | |
3255 | local variables |
3256 | |
3257 FP+8->+-----------------------+
3258 | return address |
3259 FP+4->+-----------------------+
3260 | previous FP |
3261 FP+0->+-----------------------+
3262 | |
3263 | alloca allocations |
3264 | |
3265 +-----------------------+
3266 | |
3267 low | arguments on stack |
3268 mem | |
3269 SP+0->+-----------------------+
3270
3271 Notes:
3272 1) The "reg parm save area" does not exist for non variable argument fns.
3273 2) The FP register is not saved if `frame_pointer_needed' is zero and it
3274 is not altered in the current function.
3275 3) The return address is not saved if there is no frame pointer and the
3276 current function is leaf.
3277 4) If the return address is not saved and the static chain register is
3278 live in the function, we allocate the return address slot to be able
3279 to spill the register for a long branch. */
3280
3281 /* Define the register classes for local purposes. */
3282 enum reg_type { general, mdb, mdc, floating, last_type};
3283
3284 #define GET_REG_TYPE(regno) \
3285 (GP_REGISTER_P (regno) ? general : \
3286 (regno) == MDB_REGNUM ? mdb : \
3287 (regno) == MDC_REGNUM ? mdc : \
3288 floating)
3289
3290 /* First regno of each register type. */
3291 const int first_regno[last_type] = {0, MDB_REGNUM, MDC_REGNUM, FP_FIRST_REGNUM};
3292
3293 /* Size in bytes of each register type. */
3294 const int reg_type_size[last_type] = {4, 8, 4, 4};
3295
3296 /* Structure to be filled in by visium_compute_frame_size. */
3297 struct visium_frame_info
3298 {
3299 unsigned int save_area_size; /* # bytes in the reg parm save area. */
3300 unsigned int reg_size1; /* # bytes to store first block of regs. */
3301 unsigned int reg_size2; /* # bytes to store second block of regs. */
3302 unsigned int max_reg1; /* max. regno in first block */
3303 unsigned int var_size; /* # bytes that variables take up. */
3304 unsigned int save_fp; /* Nonzero if fp must be saved. */
3305 unsigned int save_lr; /* Nonzero if lr must be saved. */
3306 unsigned int lr_slot; /* Nonzero if the lr slot is needed. */
3307 unsigned int combine; /* Nonzero if we can combine the allocation of
3308 variables and regs. */
3309 unsigned int interrupt; /* Nonzero if the function is an interrupt
3310 handler. */
3311 unsigned int mask[last_type]; /* Masks of saved regs: gp, mdb, mdc, fp */
3312 };
3313
3314 /* Current frame information calculated by visium_compute_frame_size. */
3315 static struct visium_frame_info current_frame_info;
3316
3317 /* Accessor for current_frame_info.save_fp. */
3318
3319 static inline bool
3320 current_function_saves_fp (void)
3321 {
3322 return current_frame_info.save_fp != 0;
3323 }
3324
3325 /* Accessor for current_frame_info.save_lr. */
3326
3327 static inline bool
3328 current_function_saves_lr (void)
3329 {
3330 return current_frame_info.save_lr != 0;
3331 }
3332
3333 /* Accessor for current_frame_info.lr_slot. */
3334
3335 static inline bool
3336 current_function_has_lr_slot (void)
3337 {
3338 return current_frame_info.lr_slot != 0;
3339 }
3340
3341 /* Return non-zero if register REGNO needs to be saved in the frame. */
3342
3343 static int
3344 visium_save_reg_p (int interrupt, int regno)
3345 {
3346 switch (regno)
3347 {
3348 case HARD_FRAME_POINTER_REGNUM:
3349 /* This register is call-saved but handled specially. */
3350 return 0;
3351
3352 case MDC_REGNUM:
3353 /* This register is fixed but can be modified. */
3354 break;
3355
3356 case 29:
3357 case 30:
3358 /* These registers are fixed and hold the interrupt context. */
3359 return (interrupt != 0);
3360
3361 default:
3362 /* The other fixed registers are either immutable or special. */
3363 if (fixed_regs[regno])
3364 return 0;
3365 break;
3366 }
3367
3368 if (interrupt)
3369 {
3370 if (crtl->is_leaf)
3371 {
3372 if (df_regs_ever_live_p (regno))
3373 return 1;
3374 }
3375 else if (call_used_regs[regno])
3376 return 1;
3377
3378 /* To save mdb requires two temporary registers. To save mdc or
3379 any of the floating registers requires one temporary
3380 register. If this is an interrupt routine, the temporary
3381 registers need to be saved as well. These temporary registers
3382 are call used, so we only need deal with the case of leaf
3383 functions here. */
3384 if (regno == PROLOGUE_TMP_REGNUM)
3385 {
3386 if (df_regs_ever_live_p (MDB_REGNUM)
3387 || df_regs_ever_live_p (MDC_REGNUM))
3388 return 1;
3389
3390 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
3391 if (df_regs_ever_live_p (i))
3392 return 1;
3393 }
3394
3395 else if (regno == PROLOGUE_TMP_REGNUM + 1)
3396 {
3397 if (df_regs_ever_live_p (MDB_REGNUM))
3398 return 1;
3399 }
3400 }
3401
3402 return df_regs_ever_live_p (regno) && !call_used_regs[regno];
3403 }
3404
3405 /* Compute the frame size required by the function. This function is called
3406 during the reload pass and also by visium_expand_prologue. */
3407
3408 static int
3409 visium_compute_frame_size (int size)
3410 {
3411 const int save_area_size = visium_reg_parm_save_area_size;
3412 const int var_size = VISIUM_STACK_ALIGN (size);
3413 const int save_fp
3414 = frame_pointer_needed || df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM);
3415 const int save_lr = frame_pointer_needed || !crtl->is_leaf;
3416 const int lr_slot = !save_lr && df_regs_ever_live_p (long_branch_regnum);
3417 const int local_frame_offset
3418 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3419 const int interrupt = visium_interrupt_function_p ();
3420 unsigned int mask[last_type];
3421 int reg_size1 = 0;
3422 int max_reg1 = 0;
3423 int reg_size2 = 0;
3424 int reg_size;
3425 int combine;
3426 int frame_size;
3427 int regno;
3428
3429 memset (mask, 0, last_type * sizeof (unsigned int));
3430
3431 /* The registers may need stacking in 2 blocks since only 32 32-bit words
3432 can be indexed from a given base address. */
3433 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3434 {
3435 if (visium_save_reg_p (interrupt, regno))
3436 {
3437 enum reg_type reg_type = GET_REG_TYPE (regno);
3438 int mask_bit = 1 << (regno - first_regno[reg_type]);
3439 int nbytes = reg_type_size[reg_type];
3440
3441 if (reg_size1 + nbytes > 32 * UNITS_PER_WORD)
3442 break;
3443
3444 reg_size1 += nbytes;
3445 max_reg1 = regno;
3446 mask[reg_type] |= mask_bit;
3447 }
3448 }
3449
3450 for (regno = max_reg1 + 1; regno < FIRST_PSEUDO_REGISTER; regno++)
3451 {
3452 if (visium_save_reg_p (interrupt, regno))
3453 {
3454 enum reg_type reg_type = GET_REG_TYPE (regno);
3455 int mask_bit = 1 << (regno - first_regno[reg_type]);
3456 int nbytes = reg_type_size[reg_type];
3457
3458 reg_size2 += nbytes;
3459 mask[reg_type] |= mask_bit;
3460 }
3461 }
3462
3463 reg_size = reg_size2 ? reg_size2 : reg_size1;
3464 combine = (local_frame_offset + var_size + reg_size) <= 32 * UNITS_PER_WORD;
3465 frame_size
3466 = local_frame_offset + var_size + reg_size2 + reg_size1 + save_area_size;
3467
3468 current_frame_info.save_area_size = save_area_size;
3469 current_frame_info.reg_size1 = reg_size1;
3470 current_frame_info.max_reg1 = max_reg1;
3471 current_frame_info.reg_size2 = reg_size2;
3472 current_frame_info.var_size = var_size;
3473 current_frame_info.save_fp = save_fp;
3474 current_frame_info.save_lr = save_lr;
3475 current_frame_info.lr_slot = lr_slot;
3476 current_frame_info.combine = combine;
3477 current_frame_info.interrupt = interrupt;
3478
3479 memcpy (current_frame_info.mask, mask, last_type * sizeof (unsigned int));
3480
3481 return frame_size;
3482 }
3483
3484 /* Helper function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define
3485 the offset between two registers, one to be eliminated, and the other its
3486 replacement, at the start of a routine. */
3487
3488 int
3489 visium_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
3490 {
3491 const int frame_size = visium_compute_frame_size (get_frame_size ());
3492 const int save_fp = current_frame_info.save_fp;
3493 const int save_lr = current_frame_info.save_lr;
3494 const int lr_slot = current_frame_info.lr_slot;
3495 const int local_frame_offset
3496 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3497 int offset;
3498
3499 if (from == FRAME_POINTER_REGNUM)
3500 offset = local_frame_offset;
3501 else if (from == ARG_POINTER_REGNUM)
3502 offset = frame_size;
3503 else
3504 gcc_unreachable ();
3505
3506 return offset;
3507 }
3508
3509 /* For an interrupt handler, we may be saving call-clobbered registers.
3510 Say the epilogue uses these in addition to the link register. */
3511
3512 int
3513 visium_epilogue_uses (int regno)
3514 {
3515 if (regno == LINK_REGNUM)
3516 return 1;
3517
3518 if (reload_completed)
3519 {
3520 enum reg_type reg_type = GET_REG_TYPE (regno);
3521 int mask_bit = 1 << (regno - first_regno[reg_type]);
3522
3523 return (current_frame_info.mask[reg_type] & mask_bit) != 0;
3524 }
3525
3526 return 0;
3527 }
3528
3529 /* Wrapper around emit_insn that sets RTX_FRAME_RELATED_P on the insn. */
3530
3531 static rtx
3532 emit_frame_insn (rtx x)
3533 {
3534 x = emit_insn (x);
3535 RTX_FRAME_RELATED_P (x) = 1;
3536 return x;
3537 }
3538
3539 /* Allocate ALLOC bytes on the stack and save the registers LOW_REGNO to
3540 HIGH_REGNO at OFFSET from the stack pointer. */
3541
3542 static void
3543 visium_save_regs (int alloc, int offset, int low_regno, int high_regno)
3544 {
3545 /* If this is an interrupt handler function, then mark the register
3546 stores as volatile. This will prevent the instruction scheduler
3547 from scrambling the order of register saves. */
3548 const int volatile_p = current_frame_info.interrupt;
3549 int regno;
3550
3551 /* Allocate the stack space. */
3552 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, stack_pointer_rtx,
3553 GEN_INT (-alloc)));
3554
3555 for (regno = low_regno; regno <= high_regno; regno++)
3556 {
3557 enum reg_type reg_type = GET_REG_TYPE (regno);
3558 int mask_bit = 1 << (regno - first_regno[reg_type]);
3559 rtx insn;
3560
3561 if (current_frame_info.mask[reg_type] & mask_bit)
3562 {
3563 offset -= reg_type_size[reg_type];
3564 switch (reg_type)
3565 {
3566 case general:
3567 {
3568 rtx mem
3569 = gen_frame_mem (SImode,
3570 plus_constant (Pmode,
3571 stack_pointer_rtx, offset));
3572 MEM_VOLATILE_P (mem) = volatile_p;
3573 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, regno)));
3574 }
3575 break;
3576
3577 case mdb:
3578 {
3579 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3580 rtx mem
3581 = gen_frame_mem (DImode,
3582 plus_constant (Pmode,
3583 stack_pointer_rtx, offset));
3584 rtx reg = gen_rtx_REG (DImode, regno);
3585 MEM_VOLATILE_P (mem) = volatile_p;
3586 emit_insn (gen_movdi (tmp, reg));
3587 /* Do not generate CFI if in interrupt handler. */
3588 if (volatile_p)
3589 emit_insn (gen_movdi (mem, tmp));
3590 else
3591 {
3592 insn = emit_frame_insn (gen_movdi (mem, tmp));
3593 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3594 gen_rtx_SET (mem, reg));
3595 }
3596 }
3597 break;
3598
3599 case mdc:
3600 {
3601 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3602 rtx mem
3603 = gen_frame_mem (SImode,
3604 plus_constant (Pmode,
3605 stack_pointer_rtx, offset));
3606 rtx reg = gen_rtx_REG (SImode, regno);
3607 MEM_VOLATILE_P (mem) = volatile_p;
3608 emit_insn (gen_movsi (tmp, reg));
3609 insn = emit_frame_insn (gen_movsi (mem, tmp));
3610 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3611 gen_rtx_SET (mem, reg));
3612 }
3613 break;
3614
3615 case floating:
3616 {
3617 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3618 rtx mem
3619 = gen_frame_mem (SFmode,
3620 plus_constant (Pmode,
3621 stack_pointer_rtx, offset));
3622 rtx reg = gen_rtx_REG (SFmode, regno);
3623 MEM_VOLATILE_P (mem) = volatile_p;
3624 emit_insn (gen_movsf (tmp, reg));
3625 insn = emit_frame_insn (gen_movsf (mem, tmp));
3626 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3627 gen_rtx_SET (mem, reg));
3628 }
3629 break;
3630
3631 default:
3632 break;
3633 }
3634 }
3635 }
3636 }
3637
3638 /* This function generates the code for function entry. */
3639
3640 void
3641 visium_expand_prologue (void)
3642 {
3643 const int frame_size = visium_compute_frame_size (get_frame_size ());
3644 const int save_area_size = current_frame_info.save_area_size;
3645 const int reg_size1 = current_frame_info.reg_size1;
3646 const int max_reg1 = current_frame_info.max_reg1;
3647 const int reg_size2 = current_frame_info.reg_size2;
3648 const int var_size = current_frame_info.var_size;
3649 const int save_fp = current_frame_info.save_fp;
3650 const int save_lr = current_frame_info.save_lr;
3651 const int lr_slot = current_frame_info.lr_slot;
3652 const int local_frame_offset
3653 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3654 const int combine = current_frame_info.combine;
3655 int reg_size;
3656 int first_reg;
3657 int fsize;
3658
3659 /* Save the frame size for future references. */
3660 visium_frame_size = frame_size;
3661
3662 if (flag_stack_usage_info)
3663 current_function_static_stack_size = frame_size;
3664
3665 /* If the registers have to be stacked in 2 blocks, stack the first one. */
3666 if (reg_size2)
3667 {
3668 visium_save_regs (reg_size1 + save_area_size, reg_size1, 0, max_reg1);
3669 reg_size = reg_size2;
3670 first_reg = max_reg1 + 1;
3671 fsize = local_frame_offset + var_size + reg_size2;
3672 }
3673 else
3674 {
3675 reg_size = reg_size1;
3676 first_reg = 0;
3677 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
3678 }
3679
3680 /* If we can't combine register stacking with variable allocation, partially
3681 allocate and stack the (remaining) registers now. */
3682 if (reg_size && !combine)
3683 visium_save_regs (fsize - local_frame_offset - var_size, reg_size,
3684 first_reg, FIRST_PSEUDO_REGISTER - 1);
3685
3686 /* If we can combine register stacking with variable allocation, fully
3687 allocate and stack the (remaining) registers now. */
3688 if (reg_size && combine)
3689 visium_save_regs (fsize, local_frame_offset + var_size + reg_size,
3690 first_reg, FIRST_PSEUDO_REGISTER - 1);
3691
3692 /* Otherwise space may still need to be allocated for the variables. */
3693 else if (fsize)
3694 {
3695 const int alloc_size = reg_size ? local_frame_offset + var_size : fsize;
3696
3697 if (alloc_size > 65535)
3698 {
3699 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM), insn;
3700 emit_insn (gen_movsi (tmp, GEN_INT (alloc_size)));
3701 insn = emit_frame_insn (gen_subsi3_flags (stack_pointer_rtx,
3702 stack_pointer_rtx,
3703 tmp));
3704 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3705 gen_rtx_SET (stack_pointer_rtx,
3706 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3707 GEN_INT (-alloc_size))));
3708 }
3709 else
3710 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx,
3711 stack_pointer_rtx,
3712 GEN_INT (-alloc_size)));
3713 }
3714
3715 if (save_fp)
3716 emit_frame_insn (gen_movsi (gen_frame_mem (SImode, stack_pointer_rtx),
3717 hard_frame_pointer_rtx));
3718
3719 if (frame_pointer_needed)
3720 emit_frame_insn (gen_stack_save ());
3721
3722 if (save_lr)
3723 {
3724 rtx base_rtx, mem;
3725
3726 /* Normally the frame pointer and link register get saved via
3727 write.l (sp),fp
3728 move.l fp,sp
3729 write.l 1(sp),r21
3730
3731 Indexing off sp rather than fp to store the link register
3732 avoids presenting the instruction scheduler with an initial
3733 pipeline hazard. If however the frame is needed for eg.
3734 __builtin_return_address which needs to retrieve the saved
3735 value of the link register from the stack at fp + 4 then
3736 indexing from sp can confuse the dataflow, causing the link
3737 register to be retrieved before it has been saved. */
3738 if (cfun->machine->frame_needed)
3739 base_rtx = hard_frame_pointer_rtx;
3740 else
3741 base_rtx = stack_pointer_rtx;
3742
3743 mem = gen_frame_mem (SImode,
3744 plus_constant (Pmode,
3745 base_rtx, save_fp * UNITS_PER_WORD));
3746 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, LINK_REGNUM)));
3747 }
3748 }
3749
3750 static GTY(()) rtx cfa_restores;
3751
3752 /* Queue a REG_CFA_RESTORE note until next stack manipulation insn. */
3753
3754 static void
3755 visium_add_cfa_restore_note (rtx reg)
3756 {
3757 cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
3758 }
3759
3760 /* Add queued REG_CFA_RESTORE notes to INSN, if any. */
3761
3762 static void
3763 visium_add_queued_cfa_restore_notes (rtx insn)
3764 {
3765 rtx last;
3766 if (!cfa_restores)
3767 return;
3768 for (last = cfa_restores; XEXP (last, 1); last = XEXP (last, 1))
3769 ;
3770 XEXP (last, 1) = REG_NOTES (insn);
3771 REG_NOTES (insn) = cfa_restores;
3772 cfa_restores = NULL_RTX;
3773 }
3774
3775 /* Restore the registers LOW_REGNO to HIGH_REGNO from the save area at OFFSET
3776 from the stack pointer and pop DEALLOC bytes off the stack. */
3777
3778 static void
3779 visium_restore_regs (int dealloc, int offset, int high_regno, int low_regno)
3780 {
3781 /* If this is an interrupt handler function, then mark the register
3782 restores as volatile. This will prevent the instruction scheduler
3783 from scrambling the order of register restores. */
3784 const int volatile_p = current_frame_info.interrupt;
3785 int r30_offset = -1;
3786 int regno;
3787
3788 for (regno = high_regno; regno >= low_regno; --regno)
3789 {
3790 enum reg_type reg_type = GET_REG_TYPE (regno);
3791 int mask_bit = 1 << (regno - first_regno[reg_type]);
3792
3793 if (current_frame_info.mask[reg_type] & mask_bit)
3794 {
3795 switch (reg_type)
3796 {
3797 case general:
3798 /* Postpone restoring the interrupted context registers
3799 until last, since they need to be preceded by a dsi. */
3800 if (regno == 29)
3801 ;
3802 else if (regno == 30)
3803 r30_offset = offset;
3804 else
3805 {
3806 rtx mem
3807 = gen_frame_mem (SImode,
3808 plus_constant (Pmode,
3809 stack_pointer_rtx,
3810 offset));
3811 rtx reg = gen_rtx_REG (SImode, regno);
3812 MEM_VOLATILE_P (mem) = volatile_p;
3813 emit_insn (gen_movsi (reg, mem));
3814 visium_add_cfa_restore_note (reg);
3815 }
3816 break;
3817
3818 case mdb:
3819 {
3820 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3821 rtx mem
3822 = gen_frame_mem (DImode,
3823 plus_constant (Pmode,
3824 stack_pointer_rtx, offset));
3825 rtx reg = gen_rtx_REG (DImode, regno);
3826 MEM_VOLATILE_P (mem) = volatile_p;
3827 emit_insn (gen_movdi (tmp, mem));
3828 emit_insn (gen_movdi (reg, tmp));
3829 /* Do not generate CFI if in interrupt handler. */
3830 if (!volatile_p)
3831 visium_add_cfa_restore_note (reg);
3832 }
3833 break;
3834
3835 case mdc:
3836 {
3837 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3838 rtx mem
3839 = gen_frame_mem (SImode,
3840 plus_constant (Pmode,
3841 stack_pointer_rtx, offset));
3842 rtx reg = gen_rtx_REG (SImode, regno);
3843 MEM_VOLATILE_P (mem) = volatile_p;
3844 emit_insn (gen_movsi (tmp, mem));
3845 emit_insn (gen_movsi (reg, tmp));
3846 visium_add_cfa_restore_note (reg);
3847 }
3848 break;
3849
3850 case floating:
3851 {
3852 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3853 rtx mem
3854 = gen_frame_mem (SFmode,
3855 plus_constant (Pmode,
3856 stack_pointer_rtx, offset));
3857 rtx reg = gen_rtx_REG (SFmode, regno);
3858 MEM_VOLATILE_P (mem) = volatile_p;
3859 emit_insn (gen_movsf (tmp, mem));
3860 emit_insn (gen_movsf (reg, tmp));
3861 visium_add_cfa_restore_note (reg);
3862 }
3863 break;
3864
3865 default:
3866 break;
3867 }
3868
3869 offset += reg_type_size[reg_type];
3870 }
3871 }
3872
3873 /* If the interrupted context needs to be restored, precede the
3874 restores of r29 and r30 by a dsi. */
3875 if (r30_offset >= 0)
3876 {
3877 emit_insn (gen_dsi ());
3878 emit_move_insn (gen_rtx_REG (SImode, 30),
3879 gen_frame_mem (SImode,
3880 plus_constant (Pmode,
3881 stack_pointer_rtx,
3882 r30_offset)));
3883 emit_move_insn (gen_rtx_REG (SImode, 29),
3884 gen_frame_mem (SImode,
3885 plus_constant (Pmode,
3886 stack_pointer_rtx,
3887 r30_offset + 4)));
3888 }
3889
3890 /* Deallocate the stack space. */
3891 rtx insn = emit_frame_insn (gen_stack_pop (GEN_INT (dealloc)));
3892 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3893 gen_rtx_SET (stack_pointer_rtx,
3894 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3895 GEN_INT (dealloc))));
3896 visium_add_queued_cfa_restore_notes (insn);
3897 }
3898
3899 /* This function generates the code for function exit. */
3900
3901 void
3902 visium_expand_epilogue (void)
3903 {
3904 const int save_area_size = current_frame_info.save_area_size;
3905 const int reg_size1 = current_frame_info.reg_size1;
3906 const int max_reg1 = current_frame_info.max_reg1;
3907 const int reg_size2 = current_frame_info.reg_size2;
3908 const int var_size = current_frame_info.var_size;
3909 const int restore_fp = current_frame_info.save_fp;
3910 const int restore_lr = current_frame_info.save_lr;
3911 const int lr_slot = current_frame_info.lr_slot;
3912 const int local_frame_offset
3913 = (restore_fp + restore_lr + lr_slot) * UNITS_PER_WORD;
3914 const int combine = current_frame_info.combine;
3915 int reg_size;
3916 int last_reg;
3917 int fsize;
3918
3919 /* Do not bother restoring the stack pointer if it hasn't been changed in
3920 the function since it was saved _after_ the allocation of the frame. */
3921 if (!crtl->sp_is_unchanging)
3922 emit_insn (gen_stack_restore ());
3923
3924 /* Restore the frame pointer if necessary. The usual code would be:
3925
3926 move.l sp,fp
3927 read.l fp,(sp)
3928
3929 but for the MCM this constitutes a stall/hazard so it is changed to:
3930
3931 move.l sp,fp
3932 read.l fp,(fp)
3933
3934 if the stack pointer has actually been restored. */
3935 if (restore_fp)
3936 {
3937 rtx src;
3938
3939 if (TARGET_MCM && !crtl->sp_is_unchanging)
3940 src = gen_frame_mem (SImode, hard_frame_pointer_rtx);
3941 else
3942 src = gen_frame_mem (SImode, stack_pointer_rtx);
3943
3944 rtx insn = emit_frame_insn (gen_movsi (hard_frame_pointer_rtx, src));
3945 add_reg_note (insn, REG_CFA_ADJUST_CFA,
3946 gen_rtx_SET (stack_pointer_rtx,
3947 hard_frame_pointer_rtx));
3948 visium_add_cfa_restore_note (hard_frame_pointer_rtx);
3949 }
3950
3951 /* Restore the link register if necessary. */
3952 if (restore_lr)
3953 {
3954 rtx mem = gen_frame_mem (SImode,
3955 plus_constant (Pmode,
3956 stack_pointer_rtx,
3957 restore_fp * UNITS_PER_WORD));
3958 rtx reg = gen_rtx_REG (SImode, LINK_REGNUM);
3959 emit_insn (gen_movsi (reg, mem));
3960 visium_add_cfa_restore_note (reg);
3961 }
3962
3963 /* If we have two blocks of registers, deal with the second one first. */
3964 if (reg_size2)
3965 {
3966 reg_size = reg_size2;
3967 last_reg = max_reg1 + 1;
3968 fsize = local_frame_offset + var_size + reg_size2;
3969 }
3970 else
3971 {
3972 reg_size = reg_size1;
3973 last_reg = 0;
3974 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
3975 }
3976
3977 /* If the variable allocation could be combined with register stacking,
3978 restore the (remaining) registers and fully deallocate now. */
3979 if (reg_size && combine)
3980 visium_restore_regs (fsize, local_frame_offset + var_size,
3981 FIRST_PSEUDO_REGISTER - 1, last_reg);
3982
3983 /* Otherwise deallocate the variables first. */
3984 else if (fsize)
3985 {
3986 const int pop_size = reg_size ? local_frame_offset + var_size : fsize;
3987 rtx insn;
3988
3989 if (pop_size > 65535)
3990 {
3991 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3992 emit_move_insn (tmp, GEN_INT (pop_size));
3993 insn = emit_frame_insn (gen_stack_pop (tmp));
3994 }
3995 else
3996 insn = emit_frame_insn (gen_stack_pop (GEN_INT (pop_size)));
3997 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3998 gen_rtx_SET (stack_pointer_rtx,
3999 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4000 GEN_INT (pop_size))));
4001 visium_add_queued_cfa_restore_notes (insn);
4002 }
4003
4004 /* If the variable allocation couldn't be combined with register stacking,
4005 restore the (remaining) registers now and partially deallocate. */
4006 if (reg_size && !combine)
4007 visium_restore_regs (fsize - local_frame_offset - var_size, 0,
4008 FIRST_PSEUDO_REGISTER - 1, last_reg);
4009
4010 /* If the first block of registers has yet to be restored, do it now. */
4011 if (reg_size2)
4012 visium_restore_regs (reg_size1 + save_area_size, 0, max_reg1, 0);
4013
4014 /* If this is an exception return, make the necessary stack adjustment. */
4015 if (crtl->calls_eh_return)
4016 emit_insn (gen_stack_pop (EH_RETURN_STACKADJ_RTX));
4017 }
4018
4019 /* Return true if it is appropriate to emit `return' instructions in the
4020 body of a function. */
4021
4022 bool
4023 visium_can_use_return_insn_p (void)
4024 {
4025 return reload_completed
4026 && visium_frame_size == 0
4027 && !visium_interrupt_function_p ();
4028 }
4029
4030 /* Return the register class required for an intermediate register used to
4031 copy a register of RCLASS from/to X. If no such intermediate register is
4032 required, return NO_REGS. If more than one such intermediate register is
4033 required, describe the one that is closest in the copy chain to the reload
4034 register. */
4035
4036 static reg_class_t
4037 visium_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
4038 reg_class_t rclass,
4039 enum machine_mode mode ATTRIBUTE_UNUSED,
4040 secondary_reload_info *sri ATTRIBUTE_UNUSED)
4041 {
4042 int regno = true_regnum (x);
4043
4044 /* For MDB, MDC and FP_REGS, a general register is needed for a move to
4045 or from memory. */
4046 if (regno == -1 && (rclass == MDB || rclass == MDC || rclass == FP_REGS))
4047 return GENERAL_REGS;
4048
4049 /* Moves between MDB, MDC and FP_REGS also require a general register. */
4050 else if (((regno == R_MDB || regno == R_MDC) && rclass == FP_REGS)
4051 || (FP_REGISTER_P (regno) && (rclass == MDB || rclass == MDC)))
4052 return GENERAL_REGS;
4053
4054 /* Finally an (unlikely ?) move between MDB and MDC needs a general reg. */
4055 else if ((regno == R_MDB && rclass == MDC)
4056 || (rclass == MDB && regno == R_MDC))
4057 return GENERAL_REGS;
4058
4059 return NO_REGS;
4060 }
4061
4062 /* Return true if pseudos that have been assigned to registers of RCLASS
4063 would likely be spilled because registers of RCLASS are needed for
4064 spill registers. */
4065
4066 static bool
4067 visium_class_likely_spilled_p (reg_class_t rclass ATTRIBUTE_UNUSED)
4068 {
4069 /* Return false for classes R1, R2 and R3, which are intended to be used
4070 only in the source code in conjunction with block move instructions. */
4071 return false;
4072 }
4073
4074 /* Return the register number if OP is a REG or a SUBREG of a REG, and
4075 INVALID_REGNUM in all the other cases. */
4076
4077 unsigned int
4078 reg_or_subreg_regno (rtx op)
4079 {
4080 unsigned int regno;
4081
4082 if (GET_CODE (op) == REG)
4083 regno = REGNO (op);
4084 else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
4085 {
4086 if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
4087 regno = subreg_regno (op);
4088 else
4089 regno = REGNO (SUBREG_REG (op));
4090 }
4091 else
4092 regno = INVALID_REGNUM;
4093
4094 return regno;
4095 }
4096
4097 #include "gt-visium.h"