Turn HARD_REGNO_NREGS into a target hook
[official-gcc.git] / gcc / config / visium / visium.c
blob4a68f18835769791678785bda5f6f0a7771880c3
1 /* Output routines for Visium.
2 Copyright (C) 2002-2017 Free Software Foundation, Inc.
3 Contributed by C.Nettleton, J.P.Parkes and P.Garbett.
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "target.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "gimple-expr.h"
29 #include "df.h"
30 #include "memmodel.h"
31 #include "tm_p.h"
32 #include "stringpool.h"
33 #include "attribs.h"
34 #include "expmed.h"
35 #include "optabs.h"
36 #include "regs.h"
37 #include "emit-rtl.h"
38 #include "recog.h"
39 #include "diagnostic-core.h"
40 #include "alias.h"
41 #include "flags.h"
42 #include "fold-const.h"
43 #include "stor-layout.h"
44 #include "calls.h"
45 #include "varasm.h"
46 #include "output.h"
47 #include "insn-attr.h"
48 #include "explow.h"
49 #include "expr.h"
50 #include "gimplify.h"
51 #include "langhooks.h"
52 #include "reload.h"
53 #include "tm-constrs.h"
54 #include "params.h"
55 #include "tree-pass.h"
56 #include "context.h"
57 #include "builtins.h"
59 /* This file should be included last. */
60 #include "target-def.h"
62 /* Enumeration of indexes into machine_libfunc_table. */
63 enum machine_libfunc_index
65 MLTI_long_int_memcpy,
66 MLTI_wrd_memcpy,
67 MLTI_byt_memcpy,
69 MLTI_long_int_memset,
70 MLTI_wrd_memset,
71 MLTI_byt_memset,
73 MLTI_set_trampoline_parity,
75 MLTI_MAX
78 struct GTY(()) machine_libfuncs
80 rtx table[MLTI_MAX];
83 /* The table of Visium-specific libfuncs. */
84 static GTY(()) struct machine_libfuncs visium_libfuncs;
86 #define vlt visium_libfuncs.table
88 /* Accessor macros for visium_libfuncs. */
89 #define long_int_memcpy_libfunc (vlt[MLTI_long_int_memcpy])
90 #define wrd_memcpy_libfunc (vlt[MLTI_wrd_memcpy])
91 #define byt_memcpy_libfunc (vlt[MLTI_byt_memcpy])
92 #define long_int_memset_libfunc (vlt[MLTI_long_int_memset])
93 #define wrd_memset_libfunc (vlt[MLTI_wrd_memset])
94 #define byt_memset_libfunc (vlt[MLTI_byt_memset])
95 #define set_trampoline_parity_libfunc (vlt[MLTI_set_trampoline_parity])
97 /* Machine specific function data. */
98 struct GTY (()) machine_function
100 /* Size of the frame of the function. */
101 int frame_size;
103 /* Size of the reg parm save area, non-zero only for functions with variable
104 argument list. We cannot use the crtl->args.pretend_args_size machinery
105 for this purpose because this size is added to virtual_incoming_args_rtx
106 to give the location of the first parameter passed by the caller on the
107 stack and virtual_incoming_args_rtx is also the location of the first
108 parameter on the stack. So crtl->args.pretend_args_size can be non-zero
109 only if the first non-register named parameter is not passed entirely on
110 the stack and this runs afoul of the need to have a reg parm save area
111 even with a variable argument list starting on the stack because of the
112 separate handling of general and floating-point registers. */
113 int reg_parm_save_area_size;
115 /* True if we have created an rtx which relies on the frame pointer. */
116 bool frame_needed;
118 /* True if we have exposed the flags register. From this moment on, we
119 cannot generate simple operations for integer registers. We could
120 use reload_completed for this purpose, but this would cripple the
121 postreload CSE and GCSE passes which run before postreload split. */
122 bool flags_exposed;
125 #define visium_frame_size cfun->machine->frame_size
126 #define visium_reg_parm_save_area_size cfun->machine->reg_parm_save_area_size
127 #define visium_frame_needed cfun->machine->frame_needed
128 #define visium_flags_exposed cfun->machine->flags_exposed
130 /* 1 if the next opcode is to be specially indented. */
131 int visium_indent_opcode = 0;
133 /* Register number used for long branches when LR isn't available. It
134 must be a call-used register since it isn't saved on function entry.
135 We do not care whether the branch is predicted or not on the GR6,
136 given how unlikely it is to have a long branch in a leaf function. */
137 static unsigned int long_branch_regnum = 31;
139 static tree visium_handle_interrupt_attr (tree *, tree, tree, int, bool *);
140 static inline bool current_function_saves_fp (void);
141 static inline bool current_function_saves_lr (void);
142 static inline bool current_function_has_lr_slot (void);
144 /* Supported attributes:
145 interrupt -- specifies this function is an interrupt handler. */
146 static const struct attribute_spec visium_attribute_table[] =
148 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
149 affects_type_identity } */
150 {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false},
151 {NULL, 0, 0, false, false, false, NULL, false}
154 static struct machine_function *visium_init_machine_status (void);
156 /* Target hooks and TARGET_INITIALIZER */
158 static bool visium_pass_by_reference (cumulative_args_t, machine_mode,
159 const_tree, bool);
161 static rtx visium_function_arg (cumulative_args_t, machine_mode,
162 const_tree, bool);
164 static void visium_function_arg_advance (cumulative_args_t, machine_mode,
165 const_tree, bool);
167 static bool visium_return_in_memory (const_tree, const_tree fntype);
169 static rtx visium_function_value (const_tree, const_tree fn_decl_or_type,
170 bool);
172 static rtx visium_libcall_value (machine_mode, const_rtx);
174 static void visium_setup_incoming_varargs (cumulative_args_t,
175 machine_mode,
176 tree, int *, int);
178 static void visium_va_start (tree valist, rtx nextarg);
180 static tree visium_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
182 static bool visium_function_ok_for_sibcall (tree, tree);
184 static bool visium_frame_pointer_required (void);
186 static tree visium_build_builtin_va_list (void);
188 static rtx_insn *visium_md_asm_adjust (vec<rtx> &, vec<rtx> &,
189 vec<const char *> &,
190 vec<rtx> &, HARD_REG_SET &);
192 static bool visium_legitimate_constant_p (machine_mode, rtx);
194 static bool visium_legitimate_address_p (machine_mode, rtx, bool);
196 static bool visium_print_operand_punct_valid_p (unsigned char);
197 static void visium_print_operand (FILE *, rtx, int);
198 static void visium_print_operand_address (FILE *, machine_mode, rtx);
200 static void visium_conditional_register_usage (void);
202 static rtx visium_legitimize_address (rtx, rtx, machine_mode);
204 static reg_class_t visium_secondary_reload (bool, rtx, reg_class_t,
205 machine_mode,
206 secondary_reload_info *);
208 static bool visium_class_likely_spilled_p (reg_class_t);
210 static void visium_trampoline_init (rtx, tree, rtx);
212 static int visium_issue_rate (void);
214 static int visium_adjust_priority (rtx_insn *, int);
216 static int visium_adjust_cost (rtx_insn *, int, rtx_insn *, int, unsigned int);
218 static int visium_register_move_cost (machine_mode, reg_class_t,
219 reg_class_t);
221 static int visium_memory_move_cost (machine_mode, reg_class_t, bool);
223 static bool visium_rtx_costs (rtx, machine_mode, int, int, int *, bool);
225 static void visium_option_override (void);
227 static void visium_init_libfuncs (void);
229 static unsigned int visium_reorg (void);
231 static unsigned int visium_hard_regno_nregs (unsigned int, machine_mode);
233 static bool visium_hard_regno_mode_ok (unsigned int, machine_mode);
235 static bool visium_modes_tieable_p (machine_mode, machine_mode);
237 /* Setup the global target hooks structure. */
239 #undef TARGET_MAX_ANCHOR_OFFSET
240 #define TARGET_MAX_ANCHOR_OFFSET 31
242 #undef TARGET_PASS_BY_REFERENCE
243 #define TARGET_PASS_BY_REFERENCE visium_pass_by_reference
245 #undef TARGET_FUNCTION_ARG
246 #define TARGET_FUNCTION_ARG visium_function_arg
248 #undef TARGET_FUNCTION_ARG_ADVANCE
249 #define TARGET_FUNCTION_ARG_ADVANCE visium_function_arg_advance
251 #undef TARGET_RETURN_IN_MEMORY
252 #define TARGET_RETURN_IN_MEMORY visium_return_in_memory
254 #undef TARGET_FUNCTION_VALUE
255 #define TARGET_FUNCTION_VALUE visium_function_value
257 #undef TARGET_LIBCALL_VALUE
258 #define TARGET_LIBCALL_VALUE visium_libcall_value
260 #undef TARGET_SETUP_INCOMING_VARARGS
261 #define TARGET_SETUP_INCOMING_VARARGS visium_setup_incoming_varargs
263 #undef TARGET_EXPAND_BUILTIN_VA_START
264 #define TARGET_EXPAND_BUILTIN_VA_START visium_va_start
266 #undef TARGET_BUILD_BUILTIN_VA_LIST
267 #define TARGET_BUILD_BUILTIN_VA_LIST visium_build_builtin_va_list
269 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
270 #define TARGET_GIMPLIFY_VA_ARG_EXPR visium_gimplify_va_arg
272 #undef TARGET_LEGITIMATE_CONSTANT_P
273 #define TARGET_LEGITIMATE_CONSTANT_P visium_legitimate_constant_p
275 #undef TARGET_LRA_P
276 #define TARGET_LRA_P hook_bool_void_false
278 #undef TARGET_LEGITIMATE_ADDRESS_P
279 #define TARGET_LEGITIMATE_ADDRESS_P visium_legitimate_address_p
281 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
282 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P visium_print_operand_punct_valid_p
283 #undef TARGET_PRINT_OPERAND
284 #define TARGET_PRINT_OPERAND visium_print_operand
285 #undef TARGET_PRINT_OPERAND_ADDRESS
286 #define TARGET_PRINT_OPERAND_ADDRESS visium_print_operand_address
288 #undef TARGET_ATTRIBUTE_TABLE
289 #define TARGET_ATTRIBUTE_TABLE visium_attribute_table
291 #undef TARGET_ADDRESS_COST
292 #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
294 #undef TARGET_STRICT_ARGUMENT_NAMING
295 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
297 #undef TARGET_SCHED_ISSUE_RATE
298 #define TARGET_SCHED_ISSUE_RATE visium_issue_rate
300 #undef TARGET_SCHED_ADJUST_PRIORITY
301 #define TARGET_SCHED_ADJUST_PRIORITY visium_adjust_priority
303 #undef TARGET_SCHED_ADJUST_COST
304 #define TARGET_SCHED_ADJUST_COST visium_adjust_cost
306 #undef TARGET_MEMORY_MOVE_COST
307 #define TARGET_MEMORY_MOVE_COST visium_memory_move_cost
309 #undef TARGET_REGISTER_MOVE_COST
310 #define TARGET_REGISTER_MOVE_COST visium_register_move_cost
312 #undef TARGET_RTX_COSTS
313 #define TARGET_RTX_COSTS visium_rtx_costs
315 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
316 #define TARGET_FUNCTION_OK_FOR_SIBCALL visium_function_ok_for_sibcall
318 #undef TARGET_FRAME_POINTER_REQUIRED
319 #define TARGET_FRAME_POINTER_REQUIRED visium_frame_pointer_required
321 #undef TARGET_SECONDARY_RELOAD
322 #define TARGET_SECONDARY_RELOAD visium_secondary_reload
324 #undef TARGET_CLASS_LIKELY_SPILLED_P
325 #define TARGET_CLASS_LIKELY_SPILLED_P visium_class_likely_spilled_p
327 #undef TARGET_LEGITIMIZE_ADDRESS
328 #define TARGET_LEGITIMIZE_ADDRESS visium_legitimize_address
330 #undef TARGET_OPTION_OVERRIDE
331 #define TARGET_OPTION_OVERRIDE visium_option_override
333 #undef TARGET_INIT_LIBFUNCS
334 #define TARGET_INIT_LIBFUNCS visium_init_libfuncs
336 #undef TARGET_CONDITIONAL_REGISTER_USAGE
337 #define TARGET_CONDITIONAL_REGISTER_USAGE visium_conditional_register_usage
339 #undef TARGET_TRAMPOLINE_INIT
340 #define TARGET_TRAMPOLINE_INIT visium_trampoline_init
342 #undef TARGET_MD_ASM_ADJUST
343 #define TARGET_MD_ASM_ADJUST visium_md_asm_adjust
345 #undef TARGET_FLAGS_REGNUM
346 #define TARGET_FLAGS_REGNUM FLAGS_REGNUM
348 #undef TARGET_HARD_REGNO_NREGS
349 #define TARGET_HARD_REGNO_NREGS visium_hard_regno_nregs
351 #undef TARGET_HARD_REGNO_MODE_OK
352 #define TARGET_HARD_REGNO_MODE_OK visium_hard_regno_mode_ok
354 #undef TARGET_MODES_TIEABLE_P
355 #define TARGET_MODES_TIEABLE_P visium_modes_tieable_p
357 struct gcc_target targetm = TARGET_INITIALIZER;
359 namespace {
361 const pass_data pass_data_visium_reorg =
363 RTL_PASS, /* type */
364 "mach2", /* name */
365 OPTGROUP_NONE, /* optinfo_flags */
366 TV_MACH_DEP, /* tv_id */
367 0, /* properties_required */
368 0, /* properties_provided */
369 0, /* properties_destroyed */
370 0, /* todo_flags_start */
371 0, /* todo_flags_finish */
374 class pass_visium_reorg : public rtl_opt_pass
376 public:
377 pass_visium_reorg(gcc::context *ctxt)
378 : rtl_opt_pass(pass_data_visium_reorg, ctxt)
381 /* opt_pass methods: */
382 virtual unsigned int execute (function *)
384 return visium_reorg ();
387 }; // class pass_work_around_errata
389 } // anon namespace
391 rtl_opt_pass *
392 make_pass_visium_reorg (gcc::context *ctxt)
394 return new pass_visium_reorg (ctxt);
397 /* Options override for Visium. */
399 static void
400 visium_option_override (void)
402 if (flag_pic == 1)
403 warning (OPT_fpic, "-fpic is not supported");
404 if (flag_pic == 2)
405 warning (OPT_fPIC, "-fPIC is not supported");
407 /* MCM is the default in the GR5/GR6 era. */
408 target_flags |= MASK_MCM;
410 /* FPU is the default with MCM, but don't override an explicit option. */
411 if ((target_flags_explicit & MASK_FPU) == 0)
412 target_flags |= MASK_FPU;
414 /* The supervisor mode is the default. */
415 if ((target_flags_explicit & MASK_SV_MODE) == 0)
416 target_flags |= MASK_SV_MODE;
418 /* The GR6 has the Block Move Instructions and an IEEE-compliant FPU. */
419 if (visium_cpu_and_features == PROCESSOR_GR6)
421 target_flags |= MASK_BMI;
422 if (target_flags & MASK_FPU)
423 target_flags |= MASK_FPU_IEEE;
426 /* Set -mtune from -mcpu if not specified. */
427 if (!global_options_set.x_visium_cpu)
428 visium_cpu = visium_cpu_and_features;
430 /* Align functions on 256-byte (32-quadword) for GR5 and 64-byte (8-quadword)
431 boundaries for GR6 so they start a new burst mode window. */
432 if (align_functions == 0)
434 if (visium_cpu == PROCESSOR_GR6)
435 align_functions = 64;
436 else
437 align_functions = 256;
439 /* Allow the size of compilation units to double because of inlining.
440 In practice the global size of the object code is hardly affected
441 because the additional instructions will take up the padding. */
442 maybe_set_param_value (PARAM_INLINE_UNIT_GROWTH, 100,
443 global_options.x_param_values,
444 global_options_set.x_param_values);
447 /* Likewise for loops. */
448 if (align_loops == 0)
450 if (visium_cpu == PROCESSOR_GR6)
451 align_loops = 64;
452 else
454 align_loops = 256;
455 /* But not if they are too far away from a 256-byte boundary. */
456 align_loops_max_skip = 31;
460 /* Align all jumps on quadword boundaries for the burst mode, and even
461 on 8-quadword boundaries for GR6 so they start a new window. */
462 if (align_jumps == 0)
464 if (visium_cpu == PROCESSOR_GR6)
465 align_jumps = 64;
466 else
467 align_jumps = 8;
470 /* We register a machine-specific pass. This pass must be scheduled as
471 late as possible so that we have the (essentially) final form of the
472 insn stream to work on. Registering the pass must be done at start up.
473 It's convenient to do it here. */
474 opt_pass *visium_reorg_pass = make_pass_visium_reorg (g);
475 struct register_pass_info insert_pass_visium_reorg =
477 visium_reorg_pass, /* pass */
478 "dbr", /* reference_pass_name */
479 1, /* ref_pass_instance_number */
480 PASS_POS_INSERT_AFTER /* po_op */
482 register_pass (&insert_pass_visium_reorg);
485 /* Register the Visium-specific libfuncs with the middle-end. */
487 static void
488 visium_init_libfuncs (void)
490 if (!TARGET_BMI)
491 long_int_memcpy_libfunc = init_one_libfunc ("__long_int_memcpy");
492 wrd_memcpy_libfunc = init_one_libfunc ("__wrd_memcpy");
493 byt_memcpy_libfunc = init_one_libfunc ("__byt_memcpy");
495 long_int_memset_libfunc = init_one_libfunc ("__long_int_memset");
496 wrd_memset_libfunc = init_one_libfunc ("__wrd_memset");
497 byt_memset_libfunc = init_one_libfunc ("__byt_memset");
499 set_trampoline_parity_libfunc = init_one_libfunc ("__set_trampoline_parity");
502 /* Return the number of instructions that can issue on the same cycle. */
504 static int
505 visium_issue_rate (void)
507 switch (visium_cpu)
509 case PROCESSOR_GR5:
510 return 1;
512 case PROCESSOR_GR6:
513 return 2;
515 default:
516 gcc_unreachable ();
520 /* Return the adjusted PRIORITY of INSN. */
522 static int
523 visium_adjust_priority (rtx_insn *insn, int priority)
525 /* On the GR5, we slightly increase the priority of writes in order to avoid
526 scheduling a read on the next cycle. This is necessary in addition to the
527 associated insn reservation because there are no data dependencies.
528 We also slightly increase the priority of reads from ROM in order to group
529 them as much as possible. These reads are a bit problematic because they
530 conflict with the instruction fetches, i.e. the data and instruction buses
531 tread on each other's toes when they are executed. */
532 if (visium_cpu == PROCESSOR_GR5
533 && reload_completed
534 && INSN_P (insn)
535 && recog_memoized (insn) >= 0)
537 enum attr_type attr_type = get_attr_type (insn);
538 if (attr_type == TYPE_REG_MEM
539 || (attr_type == TYPE_MEM_REG
540 && MEM_READONLY_P (SET_SRC (PATTERN (insn)))))
541 return priority + 1;
544 return priority;
547 /* Adjust the cost of a scheduling dependency. Return the new cost of
548 a dependency LINK of INSN on DEP_INSN. COST is the current cost. */
550 static int
551 visium_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost,
552 unsigned int)
554 enum attr_type attr_type;
556 /* Don't adjust costs for true dependencies as they are described with
557 bypasses. But we make an exception for the first scheduling pass to
558 help the subsequent postreload compare elimination pass. */
559 if (dep_type == REG_DEP_TRUE)
561 if (!reload_completed
562 && recog_memoized (insn) >= 0
563 && get_attr_type (insn) == TYPE_CMP)
565 rtx pat = PATTERN (insn);
566 gcc_assert (GET_CODE (pat) == SET);
567 rtx src = SET_SRC (pat);
569 /* Only the branches can be modified by the postreload compare
570 elimination pass, not the cstores because they accept only
571 unsigned comparison operators and they are eliminated if
572 one of the operands is zero. */
573 if (GET_CODE (src) == IF_THEN_ELSE
574 && XEXP (XEXP (src, 0), 1) == const0_rtx
575 && recog_memoized (dep_insn) >= 0)
577 enum attr_type dep_attr_type = get_attr_type (dep_insn);
579 /* The logical instructions use CCmode and thus work with any
580 comparison operator, whereas the arithmetic instructions use
581 CCNZmode and thus work with only a small subset. */
582 if (dep_attr_type == TYPE_LOGIC
583 || (dep_attr_type == TYPE_ARITH
584 && visium_nz_comparison_operator (XEXP (src, 0),
585 GET_MODE
586 (XEXP (src, 0)))))
587 return 0;
591 return cost;
594 if (recog_memoized (insn) < 0)
595 return 0;
597 attr_type = get_attr_type (insn);
599 /* Anti dependency: DEP_INSN reads a register that INSN writes some
600 cycles later. */
601 if (dep_type == REG_DEP_ANTI)
603 /* On the GR5, the latency of FP instructions needs to be taken into
604 account for every dependency involving a write. */
605 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
607 /* INSN is FLOAD. */
608 rtx pat = PATTERN (insn);
609 rtx dep_pat = PATTERN (dep_insn);
611 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
612 /* If this happens, we have to extend this to schedule
613 optimally. Return 0 for now. */
614 return 0;
616 if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
618 if (recog_memoized (dep_insn) < 0)
619 return 0;
621 switch (get_attr_type (dep_insn))
623 case TYPE_FDIV:
624 case TYPE_FSQRT:
625 case TYPE_FTOI:
626 case TYPE_ITOF:
627 case TYPE_FP:
628 case TYPE_FMOVE:
629 /* A fload can't be issued until a preceding arithmetic
630 operation has finished if the target of the fload is
631 any of the sources (or destination) of the arithmetic
632 operation. Note that the latency may be (much)
633 greater than this if the preceding instruction
634 concerned is in a queue. */
635 return insn_default_latency (dep_insn);
637 default:
638 return 0;
643 /* On the GR6, we try to make sure that the link register is restored
644 sufficiently ahead of the return as to yield a correct prediction
645 from the branch predictor. By default there is no true dependency
646 but an anti dependency between them, so we simply reuse it. */
647 else if (attr_type == TYPE_RET && visium_cpu == PROCESSOR_GR6)
649 rtx dep_pat = PATTERN (dep_insn);
650 if (GET_CODE (dep_pat) == SET
651 && REG_P (SET_DEST (dep_pat))
652 && REGNO (SET_DEST (dep_pat)) == LINK_REGNUM)
653 return 8;
656 /* For other anti dependencies, the cost is 0. */
657 return 0;
660 /* Output dependency: DEP_INSN writes a register that INSN writes some
661 cycles later. */
662 else if (dep_type == REG_DEP_OUTPUT)
664 /* On the GR5, the latency of FP instructions needs to be taken into
665 account for every dependency involving a write. */
666 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
668 /* INSN is FLOAD. */
669 rtx pat = PATTERN (insn);
670 rtx dep_pat = PATTERN (dep_insn);
672 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
673 /* If this happens, we have to extend this to schedule
674 optimally. Return 0 for now. */
675 return 0;
677 if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat)))
679 if (recog_memoized (dep_insn) < 0)
680 return 0;
682 switch (get_attr_type (dep_insn))
684 case TYPE_FDIV:
685 case TYPE_FSQRT:
686 case TYPE_FTOI:
687 case TYPE_ITOF:
688 case TYPE_FP:
689 case TYPE_FMOVE:
690 /* A fload can't be issued until a preceding arithmetic
691 operation has finished if the target of the fload is
692 the destination of the arithmetic operation. Note that
693 the latency may be (much) greater than this if the
694 preceding instruction concerned is in a queue. */
695 return insn_default_latency (dep_insn);
697 default:
698 return 0;
703 /* For other output dependencies, the cost is 0. */
704 return 0;
707 return 0;
710 /* Handle an "interrupt_handler" attribute; arguments as in
711 struct attribute_spec.handler. */
713 static tree
714 visium_handle_interrupt_attr (tree *node, tree name,
715 tree args ATTRIBUTE_UNUSED,
716 int flags ATTRIBUTE_UNUSED,
717 bool *no_add_attrs)
719 if (TREE_CODE (*node) != FUNCTION_DECL)
721 warning (OPT_Wattributes, "%qE attribute only applies to functions",
722 name);
723 *no_add_attrs = true;
725 else if (!TARGET_SV_MODE)
727 error ("an interrupt handler cannot be compiled with -muser-mode");
728 *no_add_attrs = true;
731 return NULL_TREE;
734 /* Return non-zero if the current function is an interrupt function. */
737 visium_interrupt_function_p (void)
739 return
740 lookup_attribute ("interrupt",
741 DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
744 /* Conditionally modify the settings of the register file. */
746 static void
747 visium_conditional_register_usage (void)
749 /* If the supervisor mode is disabled, mask some general registers. */
750 if (!TARGET_SV_MODE)
752 if (visium_cpu_and_features == PROCESSOR_GR5)
754 fixed_regs[24] = call_used_regs[24] = 1;
755 fixed_regs[25] = call_used_regs[25] = 1;
756 fixed_regs[26] = call_used_regs[26] = 1;
757 fixed_regs[27] = call_used_regs[27] = 1;
758 fixed_regs[28] = call_used_regs[28] = 1;
759 call_really_used_regs[24] = 0;
760 call_really_used_regs[25] = 0;
761 call_really_used_regs[26] = 0;
762 call_really_used_regs[27] = 0;
763 call_really_used_regs[28] = 0;
766 fixed_regs[31] = call_used_regs[31] = 1;
767 call_really_used_regs[31] = 0;
769 /* We also need to change the long-branch register. */
770 if (visium_cpu_and_features == PROCESSOR_GR5)
771 long_branch_regnum = 20;
772 else
773 long_branch_regnum = 28;
776 /* If the FPU is disabled, mask the FP registers. */
777 if (!TARGET_FPU)
779 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
781 fixed_regs[i] = call_used_regs[i] = 1;
782 call_really_used_regs[i] = 0;
787 /* Prepend to CLOBBERS hard registers that are automatically clobbered for
788 an asm We do this for the FLAGS to maintain source compatibility with
789 the original cc0-based compiler. */
791 static rtx_insn *
792 visium_md_asm_adjust (vec<rtx> &/*outputs*/, vec<rtx> &/*inputs*/,
793 vec<const char *> &/*constraints*/,
794 vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs)
796 clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REGNUM));
797 SET_HARD_REG_BIT (clobbered_regs, FLAGS_REGNUM);
798 return NULL;
801 /* Return true if X is a legitimate constant for a MODE immediate operand.
802 X is guaranteed to satisfy the CONSTANT_P predicate. */
804 static bool
805 visium_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED,
806 rtx x ATTRIBUTE_UNUSED)
808 return true;
811 /* Compute the alignment for a variable. The alignment of an aggregate is
812 set to be at least that of a scalar less than or equal to it in size. */
814 unsigned int
815 visium_data_alignment (tree type, unsigned int align)
817 if (AGGREGATE_TYPE_P (type)
818 && TYPE_SIZE (type)
819 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && align < 32)
821 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 32)
822 return 32;
824 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 && align < 16)
825 return 16;
828 return align;
831 /* Helper function for HARD_REGNO_RENAME_OK (FROM, TO). Return non-zero if
832 it is OK to rename a hard register FROM to another hard register TO. */
835 visium_hard_regno_rename_ok (unsigned int from ATTRIBUTE_UNUSED,
836 unsigned int to)
838 /* If the function doesn't save LR, then the long-branch register will be
839 used for long branches so we need to know whether it is live before the
840 frame layout is computed. */
841 if (!current_function_saves_lr () && to == long_branch_regnum)
842 return 0;
844 /* Interrupt functions can only use registers that have already been
845 saved by the prologue, even if they would normally be call-clobbered. */
846 if (crtl->is_leaf
847 && !df_regs_ever_live_p (to)
848 && visium_interrupt_function_p ())
849 return 0;
851 return 1;
854 /* Implement TARGET_HARD_REGNO_NREGS. */
856 static unsigned int
857 visium_hard_regno_nregs (unsigned int regno, machine_mode mode)
859 if (regno == MDB_REGNUM)
860 return CEIL (GET_MODE_SIZE (mode), 2 * UNITS_PER_WORD);
861 return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
864 /* Implement TARGET_HARD_REGNO_MODE_OK.
866 Modes with sizes which cross from the one register class to the
867 other cannot be allowed. Only single floats are allowed in the
868 floating point registers, and only fixed point values in the EAM
869 registers. */
871 static bool
872 visium_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
874 if (GP_REGISTER_P (regno))
875 return GP_REGISTER_P (end_hard_regno (mode, regno) - 1);
877 if (FP_REGISTER_P (regno))
878 return mode == SFmode || (mode == SImode && TARGET_FPU_IEEE);
880 return (GET_MODE_CLASS (mode) == MODE_INT
881 && visium_hard_regno_nregs (regno, mode) == 1);
884 /* Implement TARGET_MODES_TIEABLE_P. */
886 static bool
887 visium_modes_tieable_p (machine_mode mode1, machine_mode mode2)
889 return (GET_MODE_CLASS (mode1) == MODE_INT
890 && GET_MODE_CLASS (mode2) == MODE_INT);
893 /* Return true if it is ok to do sibling call optimization for the specified
894 call expression EXP. DECL will be the called function, or NULL if this
895 is an indirect call. */
897 static bool
898 visium_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
899 tree exp ATTRIBUTE_UNUSED)
901 return !visium_interrupt_function_p ();
904 /* Prepare operands for a move define_expand in MODE. */
906 void
907 prepare_move_operands (rtx *operands, machine_mode mode)
909 /* If the output is not a register, the input must be. */
910 if (GET_CODE (operands[0]) == MEM && !reg_or_0_operand (operands[1], mode))
911 operands[1] = force_reg (mode, operands[1]);
914 /* Return true if the operands are valid for a simple move insn. */
916 bool
917 ok_for_simple_move_operands (rtx *operands, machine_mode mode)
919 /* One of the operands must be a register. */
920 if (!register_operand (operands[0], mode)
921 && !reg_or_0_operand (operands[1], mode))
922 return false;
924 /* Once the flags are exposed, no simple moves between integer registers. */
925 if (visium_flags_exposed
926 && gpc_reg_operand (operands[0], mode)
927 && gpc_reg_operand (operands[1], mode))
928 return false;
930 return true;
933 /* Return true if the operands are valid for a simple move strict insn. */
935 bool
936 ok_for_simple_move_strict_operands (rtx *operands, machine_mode mode)
938 /* Once the flags are exposed, no simple moves between integer registers.
939 Note that, in QImode only, a zero source counts as an integer register
940 since it will be emitted as r0. */
941 if (visium_flags_exposed
942 && gpc_reg_operand (operands[0], mode)
943 && (gpc_reg_operand (operands[1], mode)
944 || (mode == QImode && operands[1] == const0_rtx)))
945 return false;
947 return true;
950 /* Return true if the operands are valid for a simple arithmetic or logical
951 insn. */
953 bool
954 ok_for_simple_arith_logic_operands (rtx *, machine_mode)
956 /* Once the flags are exposed, no simple arithmetic or logical operations
957 between integer registers. */
958 return !visium_flags_exposed;
961 /* Return non-zero if a branch or call instruction will be emitting a nop
962 into its delay slot. */
965 empty_delay_slot (rtx_insn *insn)
967 rtx seq;
969 /* If no previous instruction (should not happen), return true. */
970 if (PREV_INSN (insn) == NULL)
971 return 1;
973 seq = NEXT_INSN (PREV_INSN (insn));
974 if (GET_CODE (PATTERN (seq)) == SEQUENCE)
975 return 0;
977 return 1;
980 /* Wrapper around single_set which returns the second SET of a pair if the
981 first SET is to the flags register. */
983 static rtx
984 single_set_and_flags (rtx_insn *insn)
986 if (multiple_sets (insn))
988 rtx pat = PATTERN (insn);
989 if (XVECLEN (pat, 0) == 2
990 && GET_CODE (XVECEXP (pat, 0, 0)) == SET
991 && REG_P (SET_DEST (XVECEXP (pat, 0, 0)))
992 && REGNO (SET_DEST (XVECEXP (pat, 0, 0))) == FLAGS_REGNUM)
993 return XVECEXP (pat, 0, 1);
996 return single_set (insn);
999 /* This is called with OUT_INSN an instruction setting a (base) register
1000 and IN_INSN a read or a write. Return 1 if these instructions together
1001 constitute a pipeline hazard.
1003 On the original architecture, a pipeline data hazard occurs when the Dest
1004 of one instruction becomes the SrcA for an immediately following READ or
1005 WRITE instruction with a non-zero index (indexing occurs at the decode
1006 stage and so a NOP must be inserted in-between for this to work).
1008 An example is:
1010 move.l r2,r1
1011 read.l r4,10(r2)
1013 On the MCM, the non-zero index condition is lifted but the hazard is
1014 patched up by the hardware through the injection of wait states:
1016 move.l r2,r1
1017 read.l r4,(r2)
1019 We nevertheless try to schedule instructions around this. */
1022 gr5_hazard_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
1024 rtx out_set, in_set, dest, memexpr;
1025 unsigned int out_reg, in_reg;
1027 /* A CALL is storage register class, but the link register is of no
1028 interest here. */
1029 if (GET_CODE (out_insn) == CALL_INSN)
1030 return 0;
1032 out_set = single_set_and_flags (out_insn);
1033 dest = SET_DEST (out_set);
1035 /* Should be no stall/hazard if OUT_INSN is MEM := ???. This only
1036 occurs prior to reload. */
1037 if (GET_CODE (dest) == MEM)
1038 return 0;
1040 if (GET_CODE (dest) == STRICT_LOW_PART)
1041 dest = XEXP (dest, 0);
1042 if (GET_CODE (dest) == SUBREG)
1043 dest = SUBREG_REG (dest);
1044 out_reg = REGNO (dest);
1046 in_set = single_set_and_flags (in_insn);
1048 /* If IN_INSN is MEM := MEM, it's the source that counts. */
1049 if (GET_CODE (SET_SRC (in_set)) == MEM)
1050 memexpr = XEXP (SET_SRC (in_set), 0);
1051 else
1052 memexpr = XEXP (SET_DEST (in_set), 0);
1054 if (GET_CODE (memexpr) == PLUS)
1056 memexpr = XEXP (memexpr, 0);
1057 if (GET_CODE (memexpr) == SUBREG)
1058 in_reg = REGNO (SUBREG_REG (memexpr));
1059 else
1060 in_reg = REGNO (memexpr);
1062 if (in_reg == out_reg)
1063 return 1;
1065 else if (TARGET_MCM)
1067 if (GET_CODE (memexpr) == STRICT_LOW_PART)
1068 memexpr = XEXP (memexpr, 0);
1069 if (GET_CODE (memexpr) == SUBREG)
1070 memexpr = SUBREG_REG (memexpr);
1071 in_reg = REGNO (memexpr);
1073 if (in_reg == out_reg)
1074 return 1;
1077 return 0;
1080 /* Return true if INSN is an empty asm instruction. */
1082 static bool
1083 empty_asm_p (rtx insn)
1085 rtx body = PATTERN (insn);
1086 const char *templ;
1088 if (GET_CODE (body) == ASM_INPUT)
1089 templ = XSTR (body, 0);
1090 else if (asm_noperands (body) >= 0)
1091 templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
1092 else
1093 templ = NULL;
1095 return (templ && templ[0] == '\0');
1098 /* Insert a NOP immediately before INSN wherever there is a pipeline hazard.
1099 LAST_REG records the register set in the last insn and LAST_INSN_CALL
1100 records whether the last insn was a call insn. */
1102 static void
1103 gr5_avoid_hazard (rtx_insn *insn, unsigned int *last_reg, bool *last_insn_call)
1105 unsigned int dest_reg = 0;
1106 rtx set;
1108 switch (GET_CODE (insn))
1110 case CALL_INSN:
1111 *last_reg = 0;
1112 *last_insn_call = true;
1113 return;
1115 case JUMP_INSN:
1116 /* If this is an empty asm, just skip it. */
1117 if (!empty_asm_p (insn))
1119 *last_reg = 0;
1120 *last_insn_call = false;
1122 return;
1124 case INSN:
1125 /* If this is an empty asm, just skip it. */
1126 if (empty_asm_p (insn))
1127 return;
1128 break;
1130 default:
1131 return;
1134 set = single_set_and_flags (insn);
1135 if (set != NULL_RTX)
1137 rtx dest = SET_DEST (set);
1138 const bool double_p = GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD;
1139 rtx memrtx = NULL;
1141 if (GET_CODE (SET_SRC (set)) == MEM)
1143 memrtx = XEXP (SET_SRC (set), 0);
1144 if (GET_CODE (dest) == STRICT_LOW_PART)
1145 dest = XEXP (dest, 0);
1146 if (REG_P (dest))
1147 dest_reg = REGNO (dest);
1149 /* If this is a DI or DF mode memory to register
1150 copy, then if rd = rs we get
1152 rs + 1 := 1[rs]
1153 rs := [rs]
1155 otherwise the order is
1157 rd := [rs]
1158 rd + 1 := 1[rs] */
1160 if (double_p)
1162 unsigned int base_reg;
1164 if (GET_CODE (memrtx) == PLUS)
1165 base_reg = REGNO (XEXP (memrtx, 0));
1166 else
1167 base_reg = REGNO (memrtx);
1169 if (dest_reg != base_reg)
1170 dest_reg++;
1174 else if (GET_CODE (dest) == MEM)
1175 memrtx = XEXP (dest, 0);
1177 else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC)
1179 if (GET_CODE (dest) == STRICT_LOW_PART
1180 ||GET_CODE (dest) == ZERO_EXTRACT)
1181 dest = XEXP (dest, 0);
1182 dest_reg = REGNO (dest);
1184 if (GET_CODE (SET_SRC (set)) == REG)
1186 unsigned int srcreg = REGNO (SET_SRC (set));
1188 /* Check for rs := rs, which will be deleted. */
1189 if (srcreg == dest_reg)
1190 return;
1192 /* In the case of a DI or DF mode move from register to
1193 register there is overlap if rd = rs + 1 in which case
1194 the order of the copies is reversed :
1196 rd + 1 := rs + 1;
1197 rd := rs */
1199 if (double_p && dest_reg != srcreg + 1)
1200 dest_reg++;
1204 /* If this is the delay slot of a call insn, any register it sets
1205 is not relevant. */
1206 if (*last_insn_call)
1207 dest_reg = 0;
1209 /* If the previous insn sets the value of a register, and this insn
1210 uses a base register, check for the pipeline hazard where it is
1211 the same register in each case. */
1212 if (*last_reg != 0 && memrtx != NULL_RTX)
1214 unsigned int reg = 0;
1216 /* Check for an index (original architecture). */
1217 if (GET_CODE (memrtx) == PLUS)
1218 reg = REGNO (XEXP (memrtx, 0));
1220 /* Check for an MCM target or rs := [rs], in DI or DF mode. */
1221 else if (TARGET_MCM || (double_p && REGNO (memrtx) == dest_reg))
1222 reg = REGNO (memrtx);
1224 /* Remove any pipeline hazard by inserting a NOP. */
1225 if (reg == *last_reg)
1227 if (dump_file)
1228 fprintf (dump_file,
1229 "inserting nop before insn %d\n", INSN_UID (insn));
1230 emit_insn_after (gen_hazard_nop (), prev_active_insn (insn));
1231 emit_insn_after (gen_blockage (), insn);
1235 *last_reg = dest_reg;
1238 *last_insn_call = false;
1241 /* Go through the instruction stream and insert nops where necessary to avoid
1242 pipeline hazards. There are two cases:
1244 1. On the original architecture, it is invalid to set the value of a
1245 (base) register and then use it in an address with a non-zero index
1246 in the next instruction.
1248 2. On the MCM, setting the value of a (base) register and then using
1249 it in address (including with zero index) in the next instruction
1250 will result in a pipeline stall of 3 cycles. */
1252 static void
1253 gr5_hazard_avoidance (void)
1255 unsigned int last_reg = 0;
1256 bool last_insn_call = false;
1257 rtx_insn *insn;
1259 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1260 if (INSN_P (insn))
1262 rtx pat = PATTERN (insn);
1264 if (GET_CODE (pat) == SEQUENCE)
1266 for (int i = 0; i < XVECLEN (pat, 0); i++)
1267 gr5_avoid_hazard (as_a <rtx_insn *> (XVECEXP (pat, 0, i)),
1268 &last_reg, &last_insn_call);
1271 else if (GET_CODE (insn) == CALL_INSN)
1273 /* This call is going to get a nop in its delay slot. */
1274 last_reg = 0;
1275 last_insn_call = false;
1278 else
1279 gr5_avoid_hazard (insn, &last_reg, &last_insn_call);
1282 else if (GET_CODE (insn) == BARRIER)
1283 last_reg = 0;
1286 /* Perform a target-specific pass over the instruction stream. The compiler
1287 will run it at all optimization levels, just after the point at which it
1288 normally does delayed-branch scheduling. */
1290 static unsigned int
1291 visium_reorg (void)
1293 if (visium_cpu == PROCESSOR_GR5)
1294 gr5_hazard_avoidance ();
1296 return 0;
1298 /* Return true if an argument must be passed by indirect reference. */
1300 static bool
1301 visium_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1302 machine_mode mode ATTRIBUTE_UNUSED,
1303 const_tree type,
1304 bool named ATTRIBUTE_UNUSED)
1306 return type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1309 /* Define how arguments are passed.
1311 A range of general registers and floating registers is available
1312 for passing arguments. When the class of registers which an
1313 argument would normally use is exhausted, that argument, is passed
1314 in the overflow region of the stack. No argument is split between
1315 registers and stack.
1317 Arguments of type float or _Complex float go in FP registers if FP
1318 hardware is available. If there is no FP hardware, arguments of
1319 type float go in general registers. All other arguments are passed
1320 in general registers. */
1322 static rtx
1323 visium_function_arg (cumulative_args_t pcum_v, machine_mode mode,
1324 const_tree type ATTRIBUTE_UNUSED,
1325 bool named ATTRIBUTE_UNUSED)
1327 int size;
1328 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1330 size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1331 if (mode == VOIDmode)
1332 return GEN_INT (0);
1334 /* Scalar or complex single precision floating point arguments are returned
1335 in floating registers. */
1336 if (TARGET_FPU
1337 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1338 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1339 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1340 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1342 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1343 return gen_rtx_REG (mode, FP_ARG_FIRST + ca->frcount);
1344 else
1345 return NULL_RTX;
1348 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1349 return gen_rtx_REG (mode, ca->grcount + GP_ARG_FIRST);
1351 return NULL_RTX;
1354 /* Update the summarizer variable pointed to by PCUM_V to advance past an
1355 argument in the argument list. The values MODE, TYPE and NAMED describe
1356 that argument. Once this is done, the variable CUM is suitable for
1357 analyzing the _following_ argument with visium_function_arg. */
1359 static void
1360 visium_function_arg_advance (cumulative_args_t pcum_v,
1361 machine_mode mode,
1362 const_tree type ATTRIBUTE_UNUSED,
1363 bool named)
1365 int size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1366 int stack_size = 0;
1367 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1369 /* Scalar or complex single precision floating point arguments are returned
1370 in floating registers. */
1371 if (TARGET_FPU
1372 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1373 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1374 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1375 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1377 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1378 ca->frcount += size;
1379 else
1381 stack_size = size;
1382 ca->frcount = MAX_ARGS_IN_FP_REGISTERS;
1385 else
1387 /* Everything else goes in a general register, if enough are
1388 available. */
1389 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1390 ca->grcount += size;
1391 else
1393 stack_size = size;
1394 ca->grcount = MAX_ARGS_IN_GP_REGISTERS;
1398 if (named)
1399 ca->stack_words += stack_size;
1402 /* Specify whether to return the return value in memory. */
1404 static bool
1405 visium_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1407 return (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1410 /* Define how scalar values are returned. */
1412 static rtx
1413 visium_function_value_1 (machine_mode mode)
1415 /* Scalar or complex single precision floating point values
1416 are returned in floating register f1. */
1417 if (TARGET_FPU
1418 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1419 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1420 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1421 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1422 return gen_rtx_REG (mode, FP_RETURN_REGNUM);
1424 /* All others are returned in r1. */
1425 return gen_rtx_REG (mode, RETURN_REGNUM);
1428 /* Return an RTX representing the place where a function returns or receives
1429 a value of data type RET_TYPE. */
1431 static rtx
1432 visium_function_value (const_tree ret_type,
1433 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1434 bool outgoing ATTRIBUTE_UNUSED)
1436 return visium_function_value_1 (TYPE_MODE (ret_type));
1439 /* Return an RTX representing the place where the library function result will
1440 be returned. */
1442 static rtx
1443 visium_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1445 return visium_function_value_1 (mode);
1448 /* Store the anonymous register arguments into the stack so that all the
1449 arguments appear to have been passed consecutively on the stack. */
1451 static void
1452 visium_setup_incoming_varargs (cumulative_args_t pcum_v,
1453 machine_mode mode,
1454 tree type,
1455 int *pretend_size ATTRIBUTE_UNUSED,
1456 int no_rtl)
1458 cumulative_args_t local_args_so_far;
1459 CUMULATIVE_ARGS local_copy;
1460 CUMULATIVE_ARGS *locargs;
1461 int gp_saved, fp_saved, size;
1463 /* Create an internal cumulative_args_t pointer to internally define
1464 storage to ensure calling TARGET_FUNCTION_ARG_ADVANCE does not
1465 make global changes. */
1466 local_args_so_far.p = &local_copy;
1467 locargs = get_cumulative_args (pcum_v);
1469 #if CHECKING_P
1470 local_args_so_far.magic = CUMULATIVE_ARGS_MAGIC;
1471 #endif
1473 local_copy.grcount = locargs->grcount;
1474 local_copy.frcount = locargs->frcount;
1475 local_copy.stack_words = locargs->stack_words;
1477 /* The caller has advanced ARGS_SO_FAR up to, but not beyond, the last named
1478 argument. Advance a local copy of ARGS_SO_FAR past the last "real" named
1479 argument, to find out how many registers are left over. */
1480 TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, mode, type, 1);
1482 /* Find how many registers we need to save. */
1483 locargs = get_cumulative_args (local_args_so_far);
1484 gp_saved = MAX_ARGS_IN_GP_REGISTERS - locargs->grcount;
1485 fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - locargs->frcount : 0);
1486 size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_HWFPVALUE);
1488 if (!no_rtl && size > 0)
1490 /* To avoid negative offsets, which are not valid addressing modes on
1491 the Visium, we create a base register for the pretend args. */
1492 rtx ptr
1493 = force_reg (Pmode,
1494 plus_constant (Pmode, virtual_incoming_args_rtx, -size));
1496 if (gp_saved > 0)
1498 rtx mem
1499 = gen_rtx_MEM (BLKmode,
1500 plus_constant (Pmode,
1501 ptr,
1502 fp_saved * UNITS_PER_HWFPVALUE));
1503 MEM_NOTRAP_P (mem) = 1;
1504 set_mem_alias_set (mem, get_varargs_alias_set ());
1505 move_block_from_reg (locargs->grcount + GP_ARG_FIRST, mem, gp_saved);
1508 if (fp_saved > 0)
1510 rtx mem = gen_rtx_MEM (BLKmode, ptr);
1511 MEM_NOTRAP_P (mem) = 1;
1512 set_mem_alias_set (mem, get_varargs_alias_set ());
1513 gcc_assert (UNITS_PER_WORD == UNITS_PER_HWFPVALUE);
1514 move_block_from_reg (locargs->frcount + FP_ARG_FIRST, mem, fp_saved);
1518 visium_reg_parm_save_area_size = size;
1521 /* Define the `__builtin_va_list' type for the ABI. */
1523 static tree
1524 visium_build_builtin_va_list (void)
1526 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes, record;
1528 record = (*lang_hooks.types.make_type) (RECORD_TYPE);
1529 f_ovfl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1530 get_identifier ("__overflow_argptr"), ptr_type_node);
1531 f_gbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1532 get_identifier ("__gpr_base"), ptr_type_node);
1533 f_fbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1534 get_identifier ("__fpr_base"), ptr_type_node);
1535 f_gbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1536 get_identifier ("__gpr_bytes"),
1537 short_unsigned_type_node);
1538 f_fbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1539 get_identifier ("__fpr_bytes"),
1540 short_unsigned_type_node);
1542 DECL_FIELD_CONTEXT (f_ovfl) = record;
1543 DECL_FIELD_CONTEXT (f_gbase) = record;
1544 DECL_FIELD_CONTEXT (f_fbase) = record;
1545 DECL_FIELD_CONTEXT (f_gbytes) = record;
1546 DECL_FIELD_CONTEXT (f_fbytes) = record;
1547 TYPE_FIELDS (record) = f_ovfl;
1548 TREE_CHAIN (f_ovfl) = f_gbase;
1549 TREE_CHAIN (f_gbase) = f_fbase;
1550 TREE_CHAIN (f_fbase) = f_gbytes;
1551 TREE_CHAIN (f_gbytes) = f_fbytes;
1552 layout_type (record);
1554 return record;
1557 /* Implement `va_start' for varargs and stdarg. */
1559 static void
1560 visium_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
1562 const CUMULATIVE_ARGS *ca = &crtl->args.info;
1563 int gp_saved = MAX_ARGS_IN_GP_REGISTERS - ca->grcount;
1564 int fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - ca->frcount : 0);
1565 int named_stack_size = ca->stack_words * UNITS_PER_WORD, offset;
1566 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1567 tree ovfl, gbase, gbytes, fbase, fbytes, t;
1569 f_ovfl = TYPE_FIELDS (va_list_type_node);
1570 f_gbase = TREE_CHAIN (f_ovfl);
1571 f_fbase = TREE_CHAIN (f_gbase);
1572 f_gbytes = TREE_CHAIN (f_fbase);
1573 f_fbytes = TREE_CHAIN (f_gbytes);
1574 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1575 gbase = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1576 NULL_TREE);
1577 fbase = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1578 NULL_TREE);
1579 gbytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), valist, f_gbytes,
1580 NULL_TREE);
1581 fbytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), valist, f_fbytes,
1582 NULL_TREE);
1584 /* Store the stacked vararg pointer in the OVFL member. */
1585 t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
1586 t = fold_build_pointer_plus_hwi (t, named_stack_size);
1587 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
1588 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1590 /* Store the base address of the GPR save area into GBASE. */
1591 t = make_tree (TREE_TYPE (gbase), virtual_incoming_args_rtx);
1592 offset = MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD;
1593 t = fold_build_pointer_plus_hwi (t, -offset);
1594 t = build2 (MODIFY_EXPR, TREE_TYPE (gbase), gbase, t);
1595 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1597 /* Store the base address of the FPR save area into FBASE. */
1598 if (fp_saved)
1600 t = make_tree (TREE_TYPE (fbase), virtual_incoming_args_rtx);
1601 offset = gp_saved * UNITS_PER_WORD
1602 + MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE;
1603 t = fold_build_pointer_plus_hwi (t, -offset);
1604 t = build2 (MODIFY_EXPR, TREE_TYPE (fbase), fbase, t);
1605 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1608 /* Fill in the GBYTES member. */
1609 t = build2 (MODIFY_EXPR, TREE_TYPE (gbytes), gbytes,
1610 size_int (gp_saved * UNITS_PER_WORD));
1611 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1613 /* Fill in the FBYTES member. */
1614 t = build2 (MODIFY_EXPR, TREE_TYPE (fbytes),
1615 fbytes, size_int (fp_saved * UNITS_PER_HWFPVALUE));
1616 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1619 /* Implement `va_arg'. */
1621 static tree
1622 visium_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
1623 gimple_seq *post_p)
1625 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1626 tree ovfl, base, bytes;
1627 HOST_WIDE_INT size, rsize;
1628 const bool by_reference_p
1629 = pass_by_reference (NULL, TYPE_MODE (type), type, false);
1630 const bool float_reg_arg_p
1631 = (TARGET_FPU && !by_reference_p
1632 && ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
1633 && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_HWFPVALUE)
1634 || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT
1635 && (GET_MODE_SIZE (TYPE_MODE (type))
1636 <= UNITS_PER_HWFPVALUE * 2))));
1637 const int max_save_area_size
1638 = (float_reg_arg_p ? MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE
1639 : MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD);
1640 tree t, u, offs;
1641 tree lab_false, lab_over, addr;
1642 tree ptrtype = build_pointer_type (type);
1644 if (by_reference_p)
1646 t = visium_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
1647 return build_va_arg_indirect_ref (t);
1650 size = int_size_in_bytes (type);
1651 rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
1652 f_ovfl = TYPE_FIELDS (va_list_type_node);
1653 f_gbase = TREE_CHAIN (f_ovfl);
1654 f_fbase = TREE_CHAIN (f_gbase);
1655 f_gbytes = TREE_CHAIN (f_fbase);
1656 f_fbytes = TREE_CHAIN (f_gbytes);
1658 /* We maintain separate pointers and offsets for floating-point and
1659 general registers, but we need similar code in both cases.
1661 Let:
1663 BYTES be the number of unused bytes in the register save area.
1664 BASE be the base address of the register save area.
1665 OFFS be the current offset into the register save area. Either
1666 MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD - bytes or
1667 MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE - bytes
1668 depending upon whether the argument is in general or floating
1669 registers.
1670 ADDR_RTX be the address of the argument.
1671 RSIZE be the size in bytes of the argument.
1672 OVFL be the pointer to the stack overflow area.
1674 The code we want is:
1676 1: if (bytes >= rsize)
1677 2: {
1678 3: addr_rtx = base + offs;
1679 4: bytes -= rsize;
1680 5: }
1681 6: else
1682 7: {
1683 8: bytes = 0;
1684 9: addr_rtx = ovfl;
1685 10: ovfl += rsize;
1686 11: }
1690 addr = create_tmp_var (ptr_type_node, "addr");
1691 lab_false = create_artificial_label (UNKNOWN_LOCATION);
1692 lab_over = create_artificial_label (UNKNOWN_LOCATION);
1693 if (float_reg_arg_p)
1694 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), unshare_expr (valist),
1695 f_fbytes, NULL_TREE);
1696 else
1697 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), unshare_expr (valist),
1698 f_gbytes, NULL_TREE);
1700 /* [1] Emit code to branch if bytes < rsize. */
1701 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1702 t = build2 (LT_EXPR, boolean_type_node, bytes, t);
1703 u = build1 (GOTO_EXPR, void_type_node, lab_false);
1704 t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
1705 gimplify_and_add (t, pre_p);
1707 /* [3] Emit code for: addr_rtx = base + offs, where
1708 offs = max_save_area_size - bytes. */
1709 t = fold_convert (sizetype, bytes);
1710 offs = build2 (MINUS_EXPR, sizetype, size_int (max_save_area_size), t);
1711 if (float_reg_arg_p)
1712 base = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1713 NULL_TREE);
1714 else
1715 base = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1716 NULL_TREE);
1718 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, offs);
1719 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1720 gimplify_and_add (t, pre_p);
1722 /* [4] Emit code for: bytes -= rsize. */
1723 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1724 t = build2 (MINUS_EXPR, TREE_TYPE (bytes), bytes, t);
1725 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), bytes, t);
1726 gimplify_and_add (t, pre_p);
1728 /* [6] Emit code to branch over the else clause, then the label. */
1729 t = build1 (GOTO_EXPR, void_type_node, lab_over);
1730 gimplify_and_add (t, pre_p);
1731 t = build1 (LABEL_EXPR, void_type_node, lab_false);
1732 gimplify_and_add (t, pre_p);
1734 /* [8] Emit code for: bytes = 0. */
1735 t = fold_convert (TREE_TYPE (bytes), size_int (0));
1736 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), unshare_expr (bytes), t);
1737 gimplify_and_add (t, pre_p);
1739 /* [9] Emit code for: addr_rtx = ovfl. */
1740 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1741 t = build2 (MODIFY_EXPR, void_type_node, addr, ovfl);
1742 gimplify_and_add (t, pre_p);
1744 /* [10] Emit code for: ovfl += rsize. */
1745 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl), ovfl, size_int (rsize));
1746 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), unshare_expr (ovfl), t);
1747 gimplify_and_add (t, pre_p);
1748 t = build1 (LABEL_EXPR, void_type_node, lab_over);
1749 gimplify_and_add (t, pre_p);
1751 /* Emit a big-endian correction if size < UNITS_PER_WORD. */
1752 if (size < UNITS_PER_WORD)
1754 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr), addr,
1755 size_int (UNITS_PER_WORD - size));
1756 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1757 gimplify_and_add (t, pre_p);
1760 addr = fold_convert (ptrtype, addr);
1762 return build_va_arg_indirect_ref (addr);
1765 /* Return true if OP is an offset suitable for use as a displacement in the
1766 address of a memory access in mode MODE. */
1768 static bool
1769 rtx_ok_for_offset_p (machine_mode mode, rtx op)
1771 if (!CONST_INT_P (op) || INTVAL (op) < 0)
1772 return false;
1774 switch (mode)
1776 case E_QImode:
1777 return INTVAL (op) <= 31;
1779 case E_HImode:
1780 return (INTVAL (op) % 2) == 0 && INTVAL (op) < 63;
1782 case E_SImode:
1783 case E_SFmode:
1784 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 127;
1786 case E_DImode:
1787 case E_DFmode:
1788 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 123;
1790 default:
1791 return false;
1795 /* Return whether X is a legitimate memory address for a memory operand
1796 of mode MODE.
1798 Legitimate addresses are defined in two variants: a strict variant
1799 and a non-strict one. The STRICT parameter chooses which variant
1800 is desired by the caller.
1802 The strict variant is used in the reload pass. It must be defined
1803 so that any pseudo-register that has not been allocated a hard
1804 register is considered a memory reference. This is because in
1805 contexts where some kind of register is required, a
1806 pseudo-register with no hard register must be rejected. For
1807 non-hard registers, the strict variant should look up the
1808 `reg_renumber' array; it should then proceed using the hard
1809 register number in the array, or treat the pseudo as a memory
1810 reference if the array holds `-1'.
1812 The non-strict variant is used in other passes. It must be
1813 defined to accept all pseudo-registers in every context where some
1814 kind of register is required. */
1816 static bool
1817 visium_legitimate_address_p (machine_mode mode, rtx x, bool strict)
1819 rtx base;
1820 unsigned int regno;
1822 /* If X is base+disp, check that we have an appropriate offset. */
1823 if (GET_CODE (x) == PLUS)
1825 if (!rtx_ok_for_offset_p (mode, XEXP (x, 1)))
1826 return false;
1827 base = XEXP (x, 0);
1829 else
1830 base = x;
1832 /* Now check the base: it must be either a register or a subreg thereof. */
1833 if (GET_CODE (base) == SUBREG)
1834 base = SUBREG_REG (base);
1835 if (!REG_P (base))
1836 return false;
1838 regno = REGNO (base);
1840 /* For the strict variant, the register must be REGNO_OK_FOR_BASE_P. */
1841 if (strict)
1842 return REGNO_OK_FOR_BASE_P (regno);
1844 /* For the non-strict variant, the register may also be a pseudo. */
1845 return BASE_REGISTER_P (regno) || regno >= FIRST_PSEUDO_REGISTER;
1848 /* Try machine-dependent ways of modifying an illegitimate address
1849 to be legitimate. If we find one, return the new, valid address.
1850 This macro is used in only one place: `memory_address' in explow.c.
1852 OLDX is the address as it was before break_out_memory_refs was called.
1853 In some cases it is useful to look at this to decide what needs to be done.
1855 MODE and WIN are passed so that this macro can use
1856 GO_IF_LEGITIMATE_ADDRESS.
1858 It is always safe for this macro to do nothing. It exists to recognize
1859 opportunities to optimize the output.
1861 For Visium
1863 memory (reg + <out of range int>)
1865 is transformed to
1867 base_int = <out of range int> & ~mask
1868 ptr_reg = reg + base_int
1869 memory (ptr_reg + <out of range int> - base_int)
1871 Thus ptr_reg is a base register for a range of addresses,
1872 which should help CSE.
1874 For a 1 byte reference mask is 0x1f
1875 for a 2 byte reference mask is 0x3f
1876 For a 4 byte reference mask is 0x7f
1878 This reflects the indexing range of the processor.
1880 For a > 4 byte reference the mask is 0x7f provided all of the words
1881 can be accessed with the base address obtained. Otherwise a mask
1882 of 0x3f is used.
1884 On rare occasions an unaligned base register value with an
1885 unaligned offset is generated. Unaligned offsets are left alone for
1886 this reason. */
1888 static rtx
1889 visium_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1890 machine_mode mode)
1892 if (GET_CODE (x) == PLUS
1893 && GET_CODE (XEXP (x, 1)) == CONST_INT
1894 && GET_CODE (XEXP (x, 0)) == REG && mode != BLKmode)
1896 int offset = INTVAL (XEXP (x, 1));
1897 int size = GET_MODE_SIZE (mode);
1898 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1899 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1900 int offset_base = offset & ~mask;
1902 /* Check that all of the words can be accessed. */
1903 if (4 < size && 0x80 < size + offset - offset_base)
1904 offset_base = offset & ~0x3f;
1905 if (offset_base != 0 && offset_base != offset && (offset & mask1) == 0)
1907 rtx ptr_reg = force_reg (Pmode,
1908 gen_rtx_PLUS (Pmode,
1909 XEXP (x, 0),
1910 GEN_INT (offset_base)));
1912 return plus_constant (Pmode, ptr_reg, offset - offset_base);
1916 return x;
1919 /* Perform a similar function to visium_legitimize_address, but this time
1920 for reload. Generating new registers is not an option here. Parts
1921 that need reloading are indicated by calling push_reload. */
1924 visium_legitimize_reload_address (rtx x, machine_mode mode, int opnum,
1925 int type, int ind ATTRIBUTE_UNUSED)
1927 rtx newrtx, tem = NULL_RTX;
1929 if (mode == BLKmode)
1930 return NULL_RTX;
1932 if (optimize && GET_CODE (x) == PLUS)
1933 tem = simplify_binary_operation (PLUS, GET_MODE (x), XEXP (x, 0),
1934 XEXP (x, 1));
1936 newrtx = tem ? tem : x;
1937 if (GET_CODE (newrtx) == PLUS
1938 && GET_CODE (XEXP (newrtx, 1)) == CONST_INT
1939 && GET_CODE (XEXP (newrtx, 0)) == REG
1940 && BASE_REGISTER_P (REGNO (XEXP (newrtx, 0))))
1942 int offset = INTVAL (XEXP (newrtx, 1));
1943 int size = GET_MODE_SIZE (mode);
1944 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1945 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1946 int offset_base = offset & ~mask;
1948 /* Check that all of the words can be accessed. */
1949 if (4 < size && 0x80 < size + offset - offset_base)
1950 offset_base = offset & ~0x3f;
1952 if (offset_base && (offset & mask1) == 0)
1954 rtx temp = gen_rtx_PLUS (Pmode,
1955 XEXP (newrtx, 0), GEN_INT (offset_base));
1957 x = gen_rtx_PLUS (Pmode, temp, GEN_INT (offset - offset_base));
1958 push_reload (XEXP (x, 0), 0, &XEXP (x, 0), 0,
1959 BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum,
1960 (enum reload_type) type);
1961 return x;
1965 return NULL_RTX;
1968 /* Return the cost of moving data of mode MODE from a register in class FROM to
1969 one in class TO. A value of 2 is the default; other values are interpreted
1970 relative to that. */
1972 static int
1973 visium_register_move_cost (machine_mode mode, reg_class_t from,
1974 reg_class_t to)
1976 const int numwords = (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) ? 1 : 2;
1978 if (from == MDB || to == MDB)
1979 return 4;
1980 else if (from == MDC || to == MDC || (from == FP_REGS) != (to == FP_REGS))
1981 return 4 * numwords;
1982 else
1983 return 2 * numwords;
1986 /* Return the cost of moving data of mode MODE between a register of class
1987 CLASS and memory. IN is zero if the value is to be written to memory,
1988 non-zero if it is to be read in. This cost is relative to those in
1989 visium_register_move_cost. */
1991 static int
1992 visium_memory_move_cost (machine_mode mode,
1993 reg_class_t to ATTRIBUTE_UNUSED,
1994 bool in)
1996 /* Moving data in can be from PROM and this is expensive. */
1997 if (in)
1999 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2000 return 7;
2001 else
2002 return 13;
2005 /* Moving data out is mostly to RAM and should be cheaper. */
2006 else
2008 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2009 return 6;
2010 else
2011 return 12;
2015 /* Return the relative costs of expression X. */
2017 static bool
2018 visium_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
2019 int opno ATTRIBUTE_UNUSED, int *total,
2020 bool speed ATTRIBUTE_UNUSED)
2022 int code = GET_CODE (x);
2024 switch (code)
2026 case CONST_INT:
2027 /* Small integers are as cheap as registers. 4-byte values can
2028 be fetched as immediate constants - let's give that the cost
2029 of an extra insn. */
2030 *total = COSTS_N_INSNS (!satisfies_constraint_J (x));
2031 return true;
2033 case CONST:
2034 case LABEL_REF:
2035 case SYMBOL_REF:
2036 *total = COSTS_N_INSNS (2);
2037 return true;
2039 case CONST_DOUBLE:
2041 rtx high, low;
2042 split_double (x, &high, &low);
2043 *total =
2044 COSTS_N_INSNS
2045 (!satisfies_constraint_J (high) + !satisfies_constraint_J (low));
2046 return true;
2049 case MULT:
2050 *total = COSTS_N_INSNS (3);
2051 return false;
2053 case DIV:
2054 case UDIV:
2055 case MOD:
2056 case UMOD:
2057 if (mode == DImode)
2058 *total = COSTS_N_INSNS (64);
2059 else
2060 *total = COSTS_N_INSNS (32);
2061 return false;
2063 case PLUS:
2064 case MINUS:
2065 case NEG:
2066 /* DImode operations are performed directly on the ALU. */
2067 if (mode == DImode)
2068 *total = COSTS_N_INSNS (2);
2069 else
2070 *total = COSTS_N_INSNS (1);
2071 return false;
2073 case ASHIFT:
2074 case ASHIFTRT:
2075 case LSHIFTRT:
2076 /* DImode operations are performed on the EAM instead. */
2077 if (mode == DImode)
2078 *total = COSTS_N_INSNS (3);
2079 else
2080 *total = COSTS_N_INSNS (1);
2081 return false;
2083 case COMPARE:
2084 /* This matches the btst pattern. */
2085 if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT
2086 && XEXP (x, 1) == const0_rtx
2087 && XEXP (XEXP (x, 0), 1) == const1_rtx
2088 && satisfies_constraint_K (XEXP (XEXP (x, 0), 2)))
2089 *total = COSTS_N_INSNS (1);
2090 return false;
2092 default:
2093 return false;
2097 /* Split a double move of OPERANDS in MODE. */
2099 void
2100 visium_split_double_move (rtx *operands, machine_mode mode)
2102 bool swap = false;
2104 /* Check register to register with overlap. */
2105 if (GET_CODE (operands[0]) == REG
2106 && GET_CODE (operands[1]) == REG
2107 && REGNO (operands[0]) == REGNO (operands[1]) + 1)
2108 swap = true;
2110 /* Check memory to register where the base reg overlaps the destination. */
2111 if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == MEM)
2113 rtx op = XEXP (operands[1], 0);
2115 if (GET_CODE (op) == SUBREG)
2116 op = SUBREG_REG (op);
2118 if (GET_CODE (op) == REG && REGNO (op) == REGNO (operands[0]))
2119 swap = true;
2121 if (GET_CODE (op) == PLUS)
2123 rtx x = XEXP (op, 0);
2124 rtx y = XEXP (op, 1);
2126 if (GET_CODE (x) == REG && REGNO (x) == REGNO (operands[0]))
2127 swap = true;
2129 if (GET_CODE (y) == REG && REGNO (y) == REGNO (operands[0]))
2130 swap = true;
2134 if (swap)
2136 operands[2] = operand_subword (operands[0], 1, 1, mode);
2137 operands[3] = operand_subword (operands[1], 1, 1, mode);
2138 operands[4] = operand_subword (operands[0], 0, 1, mode);
2139 operands[5] = operand_subword (operands[1], 0, 1, mode);
2141 else
2143 operands[2] = operand_subword (operands[0], 0, 1, mode);
2144 operands[3] = operand_subword (operands[1], 0, 1, mode);
2145 operands[4] = operand_subword (operands[0], 1, 1, mode);
2146 operands[5] = operand_subword (operands[1], 1, 1, mode);
2150 /* Split a double addition or subtraction of operands. */
2152 void
2153 visium_split_double_add (enum rtx_code code, rtx op0, rtx op1, rtx op2)
2155 rtx op3 = gen_lowpart (SImode, op0);
2156 rtx op4 = gen_lowpart (SImode, op1);
2157 rtx op5;
2158 rtx op6 = gen_highpart (SImode, op0);
2159 rtx op7 = (op1 == const0_rtx ? op1 : gen_highpart (SImode, op1));
2160 rtx op8;
2161 rtx x, pat, flags;
2163 /* If operand #2 is a small constant, then its high part is null. */
2164 if (CONST_INT_P (op2))
2166 HOST_WIDE_INT val = INTVAL (op2);
2168 if (val < 0)
2170 code = (code == MINUS ? PLUS : MINUS);
2171 val = -val;
2174 op5 = gen_int_mode (val, SImode);
2175 op8 = const0_rtx;
2177 else
2179 op5 = gen_lowpart (SImode, op2);
2180 op8 = gen_highpart (SImode, op2);
2183 if (op4 == const0_rtx)
2184 pat = gen_negsi2_insn_set_carry (op3, op5);
2185 else if (code == MINUS)
2186 pat = gen_subsi3_insn_set_carry (op3, op4, op5);
2187 else
2188 pat = gen_addsi3_insn_set_carry (op3, op4, op5);
2189 emit_insn (pat);
2191 /* This is the plus_[plus_]sltu_flags or minus_[minus_]sltu_flags pattern. */
2192 if (op8 == const0_rtx)
2193 x = op7;
2194 else
2195 x = gen_rtx_fmt_ee (code, SImode, op7, op8);
2196 flags = gen_rtx_REG (CCCmode, FLAGS_REGNUM);
2197 x = gen_rtx_fmt_ee (code, SImode, x, gen_rtx_LTU (SImode, flags, const0_rtx));
2198 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2199 XVECEXP (pat, 0, 0) = gen_rtx_SET (op6, x);
2200 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2201 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2202 emit_insn (pat);
2204 visium_flags_exposed = true;
2207 /* Expand a copysign of OPERANDS in MODE. */
2209 void
2210 visium_expand_copysign (rtx *operands, machine_mode mode)
2212 rtx op0 = operands[0];
2213 rtx op1 = operands[1];
2214 rtx op2 = operands[2];
2215 rtx mask = force_reg (SImode, GEN_INT (0x7fffffff));
2216 rtx x;
2218 /* We manually handle SFmode because the abs and neg instructions of
2219 the FPU on the MCM have a non-standard behavior wrt NaNs. */
2220 gcc_assert (mode == SFmode);
2222 /* First get all the non-sign bits of op1. */
2223 if (GET_CODE (op1) == CONST_DOUBLE)
2225 if (real_isneg (CONST_DOUBLE_REAL_VALUE (op1)))
2226 op1 = simplify_unary_operation (ABS, mode, op1, mode);
2227 if (op1 != CONST0_RTX (mode))
2229 long l;
2230 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op1), l);
2231 op1 = force_reg (SImode, gen_int_mode (l, SImode));
2234 else
2236 op1 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op1));
2237 op1 = force_reg (SImode, gen_rtx_AND (SImode, op1, mask));
2240 /* Then get the sign bit of op2. */
2241 mask = force_reg (SImode, gen_rtx_NOT (SImode, mask));
2242 op2 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op2));
2243 op2 = force_reg (SImode, gen_rtx_AND (SImode, op2, mask));
2245 /* Finally OR the two values. */
2246 if (op1 == CONST0_RTX (SFmode))
2247 x = op2;
2248 else
2249 x = force_reg (SImode, gen_rtx_IOR (SImode, op1, op2));
2251 /* And move the result to the destination. */
2252 emit_insn (gen_rtx_SET (op0, gen_lowpart (SFmode, x)));
2255 /* Expand a cstore of OPERANDS in MODE for EQ/NE/LTU/GTU/GEU/LEU. We generate
2256 the result in the C flag and use the ADC/SUBC instructions to write it into
2257 the destination register.
2259 It would also be possible to implement support for LT/GT/LE/GE by means of
2260 the RFLAG instruction followed by some shifts, but this can pessimize the
2261 generated code. */
2263 void
2264 visium_expand_int_cstore (rtx *operands, machine_mode mode)
2266 enum rtx_code code = GET_CODE (operands[1]);
2267 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], sltu;
2268 bool reverse = false;
2270 switch (code)
2272 case EQ:
2273 case NE:
2274 /* We use a special comparison to get the result in the C flag. */
2275 if (op2 != const0_rtx)
2276 op1 = force_reg (mode, gen_rtx_XOR (mode, op1, op2));
2277 op1 = gen_rtx_NOT (mode, op1);
2278 op2 = constm1_rtx;
2279 if (code == EQ)
2280 reverse = true;
2281 break;
2283 case LEU:
2284 case GEU:
2285 /* The result is naturally in the C flag modulo a couple of tricks. */
2286 code = reverse_condition (code);
2287 reverse = true;
2289 /* ... fall through ... */
2291 case LTU:
2292 case GTU:
2293 if (code == GTU)
2295 rtx tmp = op1;
2296 op1 = op2;
2297 op2 = tmp;
2299 break;
2301 default:
2302 gcc_unreachable ();
2305 /* We need either a single ADC or a SUBC and a PLUS. */
2306 sltu = gen_rtx_LTU (SImode, op1, op2);
2308 if (reverse)
2310 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, sltu));
2311 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2313 else
2314 emit_insn (gen_rtx_SET (op0, sltu));
2317 /* Expand a cstore of OPERANDS in MODE for LT/GT/UNGE/UNLE. We generate the
2318 result in the C flag and use the ADC/SUBC instructions to write it into
2319 the destination register. */
2321 void
2322 visium_expand_fp_cstore (rtx *operands,
2323 machine_mode mode ATTRIBUTE_UNUSED)
2325 enum rtx_code code = GET_CODE (operands[1]);
2326 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], slt;
2327 bool reverse = false;
2329 switch (code)
2331 case UNLE:
2332 case UNGE:
2333 /* The result is naturally in the C flag modulo a couple of tricks. */
2334 code = reverse_condition_maybe_unordered (code);
2335 reverse = true;
2337 /* ... fall through ... */
2339 case LT:
2340 case GT:
2341 if (code == GT)
2343 rtx tmp = op1;
2344 op1 = op2;
2345 op2 = tmp;
2347 break;
2349 default:
2350 gcc_unreachable ();
2353 /* We need either a single ADC or a SUBC and a PLUS. */
2354 slt = gen_rtx_LT (SImode, op1, op2);
2356 if (reverse)
2358 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, slt));
2359 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2361 else
2362 emit_insn (gen_rtx_SET (op0, slt));
2365 /* Split a compare-and-store with CODE, operands OP2 and OP3, combined with
2366 operation with OP_CODE, operands OP0 and OP1. */
2368 void
2369 visium_split_cstore (enum rtx_code op_code, rtx op0, rtx op1,
2370 enum rtx_code code, rtx op2, rtx op3)
2372 machine_mode cc_mode = visium_select_cc_mode (code, op2, op3);
2374 /* If a FP cstore was reversed, then it was originally UNGE/UNLE. */
2375 if (cc_mode == CCFPEmode && (op_code == NEG || op_code == MINUS))
2376 cc_mode = CCFPmode;
2378 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2379 rtx x = gen_rtx_COMPARE (cc_mode, op2, op3);
2380 x = gen_rtx_SET (flags, x);
2381 emit_insn (x);
2383 x = gen_rtx_fmt_ee (code, SImode, flags, const0_rtx);
2384 switch (op_code)
2386 case SET:
2387 break;
2388 case NEG:
2389 x = gen_rtx_NEG (SImode, x);
2390 break;
2391 case PLUS:
2392 case MINUS:
2393 x = gen_rtx_fmt_ee (op_code, SImode, op1, x);
2394 break;
2395 default:
2396 gcc_unreachable ();
2399 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2400 XVECEXP (pat, 0, 0) = gen_rtx_SET (op0, x);
2401 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2402 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2403 emit_insn (pat);
2405 visium_flags_exposed = true;
2408 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2409 address SRC_REG to DST with address DST_REG in 4-byte chunks. */
2411 static void
2412 expand_block_move_4 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2414 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2415 unsigned int rem = bytes % 4;
2417 if (TARGET_BMI)
2419 unsigned int i;
2420 rtx insn;
2422 emit_move_insn (regno_reg_rtx[1], dst_reg);
2423 emit_move_insn (regno_reg_rtx[2], src_reg);
2424 emit_move_insn (regno_reg_rtx[3], bytes_rtx);
2426 insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (8));
2427 XVECEXP (insn, 0, 0)
2428 = gen_rtx_SET (replace_equiv_address_nv (dst, regno_reg_rtx[1]),
2429 replace_equiv_address_nv (src, regno_reg_rtx[2]));
2430 XVECEXP (insn, 0, 1) = gen_rtx_USE (VOIDmode, regno_reg_rtx[3]);
2431 for (i = 1; i <= 6; i++)
2432 XVECEXP (insn, 0, 1 + i)
2433 = gen_rtx_CLOBBER (VOIDmode, regno_reg_rtx[i]);
2434 emit_insn (insn);
2436 else
2437 emit_library_call (long_int_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2438 dst_reg, Pmode,
2439 src_reg, Pmode,
2440 convert_to_mode (TYPE_MODE (sizetype),
2441 GEN_INT (bytes >> 2),
2442 TYPE_UNSIGNED (sizetype)),
2443 TYPE_MODE (sizetype));
2444 if (rem == 0)
2445 return;
2447 dst = replace_equiv_address_nv (dst, dst_reg);
2448 src = replace_equiv_address_nv (src, src_reg);
2449 bytes -= rem;
2451 if (rem > 1)
2453 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2454 adjust_address_nv (src, HImode, bytes));
2455 bytes += 2;
2456 rem -= 2;
2459 if (rem > 0)
2460 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2461 adjust_address_nv (src, QImode, bytes));
2464 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2465 address SRC_REG to DST with address DST_REG in 2-bytes chunks. */
2467 static void
2468 expand_block_move_2 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2470 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2471 unsigned int rem = bytes % 2;
2473 emit_library_call (wrd_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2474 dst_reg, Pmode,
2475 src_reg, Pmode,
2476 convert_to_mode (TYPE_MODE (sizetype),
2477 GEN_INT (bytes >> 1),
2478 TYPE_UNSIGNED (sizetype)),
2479 TYPE_MODE (sizetype));
2480 if (rem == 0)
2481 return;
2483 dst = replace_equiv_address_nv (dst, dst_reg);
2484 src = replace_equiv_address_nv (src, src_reg);
2485 bytes -= rem;
2487 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2488 adjust_address_nv (src, QImode, bytes));
2491 /* Generate a call to a library function to move BYTES_RTX bytes from address
2492 SRC_REG to address DST_REG in 1-byte chunks. */
2494 static void
2495 expand_block_move_1 (rtx dst_reg, rtx src_reg, rtx bytes_rtx)
2497 emit_library_call (byt_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2498 dst_reg, Pmode,
2499 src_reg, Pmode,
2500 convert_to_mode (TYPE_MODE (sizetype),
2501 bytes_rtx,
2502 TYPE_UNSIGNED (sizetype)),
2503 TYPE_MODE (sizetype));
2506 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2507 address DST_REG to VALUE_RTX in 4-byte chunks. */
2509 static void
2510 expand_block_set_4 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2512 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2513 unsigned int rem = bytes % 4;
2515 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2516 emit_library_call (long_int_memset_libfunc, LCT_NORMAL, VOIDmode,
2517 dst_reg, Pmode,
2518 value_rtx, Pmode,
2519 convert_to_mode (TYPE_MODE (sizetype),
2520 GEN_INT (bytes >> 2),
2521 TYPE_UNSIGNED (sizetype)),
2522 TYPE_MODE (sizetype));
2523 if (rem == 0)
2524 return;
2526 dst = replace_equiv_address_nv (dst, dst_reg);
2527 bytes -= rem;
2529 if (rem > 1)
2531 if (CONST_INT_P (value_rtx))
2533 const unsigned HOST_WIDE_INT value = UINTVAL (value_rtx) & 0xff;
2534 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2535 gen_int_mode ((value << 8) | value, HImode));
2537 else
2539 rtx temp = convert_to_mode (QImode, value_rtx, 1);
2540 emit_move_insn (adjust_address_nv (dst, QImode, bytes), temp);
2541 emit_move_insn (adjust_address_nv (dst, QImode, bytes + 1), temp);
2543 bytes += 2;
2544 rem -= 2;
2547 if (rem > 0)
2548 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2549 convert_to_mode (QImode, value_rtx, 1));
2552 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2553 address DST_REG to VALUE_RTX in 2-byte chunks. */
2555 static void
2556 expand_block_set_2 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2558 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2559 unsigned int rem = bytes % 2;
2561 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2562 emit_library_call (wrd_memset_libfunc, LCT_NORMAL, VOIDmode,
2563 dst_reg, Pmode,
2564 value_rtx, Pmode,
2565 convert_to_mode (TYPE_MODE (sizetype),
2566 GEN_INT (bytes >> 1),
2567 TYPE_UNSIGNED (sizetype)),
2568 TYPE_MODE (sizetype));
2569 if (rem == 0)
2570 return;
2572 dst = replace_equiv_address_nv (dst, dst_reg);
2573 bytes -= rem;
2575 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2576 convert_to_mode (QImode, value_rtx, 1));
2579 /* Generate a call to a library function to set BYTES_RTX bytes at address
2580 DST_REG to VALUE_RTX in 1-byte chunks. */
2582 static void
2583 expand_block_set_1 (rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2585 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2586 emit_library_call (byt_memset_libfunc, LCT_NORMAL, VOIDmode,
2587 dst_reg, Pmode,
2588 value_rtx, Pmode,
2589 convert_to_mode (TYPE_MODE (sizetype),
2590 bytes_rtx,
2591 TYPE_UNSIGNED (sizetype)),
2592 TYPE_MODE (sizetype));
2595 /* Expand string/block move operations.
2597 operands[0] is the pointer to the destination.
2598 operands[1] is the pointer to the source.
2599 operands[2] is the number of bytes to move.
2600 operands[3] is the alignment.
2602 Return 1 upon success, 0 otherwise. */
2605 visium_expand_block_move (rtx *operands)
2607 rtx dst = operands[0];
2608 rtx src = operands[1];
2609 rtx bytes_rtx = operands[2];
2610 rtx align_rtx = operands[3];
2611 const int align = INTVAL (align_rtx);
2612 rtx dst_reg, src_reg;
2613 tree dst_expr, src_expr;
2615 /* We only handle a fixed number of bytes for now. */
2616 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2617 return 0;
2619 /* Copy the addresses into scratch registers. */
2620 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2621 src_reg = copy_addr_to_reg (XEXP (src, 0));
2623 /* Move the data with the appropriate granularity. */
2624 if (align >= 4)
2625 expand_block_move_4 (dst, dst_reg, src, src_reg, bytes_rtx);
2626 else if (align >= 2)
2627 expand_block_move_2 (dst, dst_reg, src, src_reg, bytes_rtx);
2628 else
2629 expand_block_move_1 (dst_reg, src_reg, bytes_rtx);
2631 /* Since DST and SRC are passed to a libcall, mark the corresponding
2632 tree EXPR as addressable. */
2633 dst_expr = MEM_EXPR (dst);
2634 src_expr = MEM_EXPR (src);
2635 if (dst_expr)
2636 mark_addressable (dst_expr);
2637 if (src_expr)
2638 mark_addressable (src_expr);
2640 return 1;
2643 /* Expand string/block set operations.
2645 operands[0] is the pointer to the destination.
2646 operands[1] is the number of bytes to set.
2647 operands[2] is the source value.
2648 operands[3] is the alignment.
2650 Return 1 upon success, 0 otherwise. */
2653 visium_expand_block_set (rtx *operands)
2655 rtx dst = operands[0];
2656 rtx bytes_rtx = operands[1];
2657 rtx value_rtx = operands[2];
2658 rtx align_rtx = operands[3];
2659 const int align = INTVAL (align_rtx);
2660 rtx dst_reg;
2661 tree dst_expr;
2663 /* We only handle a fixed number of bytes for now. */
2664 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2665 return 0;
2667 /* Copy the address into a scratch register. */
2668 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2670 /* Set the data with the appropriate granularity. */
2671 if (align >= 4)
2672 expand_block_set_4 (dst, dst_reg, value_rtx, bytes_rtx);
2673 else if (align >= 2)
2674 expand_block_set_2 (dst, dst_reg, value_rtx, bytes_rtx);
2675 else
2676 expand_block_set_1 (dst_reg, value_rtx, bytes_rtx);
2678 /* Since DST is passed to a libcall, mark the corresponding
2679 tree EXPR as addressable. */
2680 dst_expr = MEM_EXPR (dst);
2681 if (dst_expr)
2682 mark_addressable (dst_expr);
2684 return 1;
2687 /* Initialize a trampoline. M_TRAMP is an RTX for the memory block for the
2688 trampoline, FNDECL is the FUNCTION_DECL for the nested function and
2689 STATIC_CHAIN is an RTX for the static chain value that should be passed
2690 to the function when it is called. */
2692 static void
2693 visium_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
2695 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2696 rtx addr = XEXP (m_tramp, 0);
2698 /* The trampoline initialization sequence is:
2700 moviu r9,%u FUNCTION
2701 movil r9,%l FUNCTION
2702 moviu r20,%u STATIC
2703 bra tr,r9,r9
2704 movil r20,%l STATIC
2706 We don't use r0 as the destination register of the branch because we want
2707 the Branch Pre-decode Logic of the GR6 to use the Address Load Array to
2708 predict the branch target. */
2710 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 0)),
2711 plus_constant (SImode,
2712 expand_shift (RSHIFT_EXPR, SImode, fnaddr,
2713 16, NULL_RTX, 1),
2714 0x04a90000));
2716 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 4)),
2717 plus_constant (SImode,
2718 expand_and (SImode, fnaddr, GEN_INT (0xffff),
2719 NULL_RTX),
2720 0x04890000));
2722 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 8)),
2723 plus_constant (SImode,
2724 expand_shift (RSHIFT_EXPR, SImode,
2725 static_chain,
2726 16, NULL_RTX, 1),
2727 0x04b40000));
2729 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)),
2730 gen_int_mode (0xff892404, SImode));
2732 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 16)),
2733 plus_constant (SImode,
2734 expand_and (SImode, static_chain,
2735 GEN_INT (0xffff), NULL_RTX),
2736 0x04940000));
2738 emit_library_call (set_trampoline_parity_libfunc, LCT_NORMAL, VOIDmode,
2739 addr, SImode);
2742 /* Return true if the current function must have and use a frame pointer. */
2744 static bool
2745 visium_frame_pointer_required (void)
2747 /* The frame pointer is required if the function isn't leaf to be able to
2748 do manual stack unwinding. */
2749 if (!crtl->is_leaf)
2750 return true;
2752 /* If the stack pointer is dynamically modified in the function, it cannot
2753 serve as the frame pointer. */
2754 if (!crtl->sp_is_unchanging)
2755 return true;
2757 /* If the function receives nonlocal gotos, it needs to save the frame
2758 pointer in the nonlocal_goto_save_area object. */
2759 if (cfun->has_nonlocal_label)
2760 return true;
2762 /* The frame also needs to be established in some special cases. */
2763 if (visium_frame_needed)
2764 return true;
2766 return false;
2769 /* Profiling support. Just a call to MCOUNT is needed. No labelled counter
2770 location is involved. Proper support for __builtin_return_address is also
2771 required, which is fairly straightforward provided a frame gets created. */
2773 void
2774 visium_profile_hook (void)
2776 visium_frame_needed = true;
2777 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "mcount"), LCT_NORMAL,
2778 VOIDmode);
2781 /* A C expression whose value is RTL representing the address in a stack frame
2782 where the pointer to the caller's frame is stored. Assume that FRAMEADDR is
2783 an RTL expression for the address of the stack frame itself.
2785 If you don't define this macro, the default is to return the value of
2786 FRAMEADDR--that is, the stack frame address is also the address of the stack
2787 word that points to the previous frame. */
2790 visium_dynamic_chain_address (rtx frame)
2792 /* This is the default, but we need to make sure the frame gets created. */
2793 visium_frame_needed = true;
2794 return frame;
2797 /* A C expression whose value is RTL representing the value of the return
2798 address for the frame COUNT steps up from the current frame, after the
2799 prologue. FRAMEADDR is the frame pointer of the COUNT frame, or the frame
2800 pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
2801 defined.
2803 The value of the expression must always be the correct address when COUNT is
2804 zero, but may be `NULL_RTX' if there is not way to determine the return
2805 address of other frames. */
2808 visium_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
2810 /* Dont try to compute anything other than frame zero. */
2811 if (count != 0)
2812 return NULL_RTX;
2814 visium_frame_needed = true;
2815 return
2816 gen_frame_mem (Pmode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2819 /* Helper function for EH_RETURN_HANDLER_RTX. Return the RTX representing a
2820 location in which to store the address of an exception handler to which we
2821 should return. */
2824 visium_eh_return_handler_rtx (void)
2826 rtx mem
2827 = gen_frame_mem (SImode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2828 MEM_VOLATILE_P (mem) = 1;
2829 return mem;
2832 static struct machine_function *
2833 visium_init_machine_status (void)
2835 return ggc_cleared_alloc<machine_function> ();
2838 /* The per-function data machinery is needed to indicate when a frame
2839 is required. */
2841 void
2842 visium_init_expanders (void)
2844 init_machine_status = visium_init_machine_status;
2847 /* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE,
2848 return the mode to be used for the comparison. */
2850 machine_mode
2851 visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
2853 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2855 switch (code)
2857 case EQ:
2858 case NE:
2859 case ORDERED:
2860 case UNORDERED:
2861 case UNLT:
2862 case UNLE:
2863 case UNGT:
2864 case UNGE:
2865 return CCFPmode;
2867 case LT:
2868 case LE:
2869 case GT:
2870 case GE:
2871 return CCFPEmode;
2873 /* These 2 comparison codes are not supported. */
2874 case UNEQ:
2875 case LTGT:
2876 default:
2877 gcc_unreachable ();
2881 /* This is for the cmp<mode>_sne pattern. */
2882 if (op1 == constm1_rtx)
2883 return CCCmode;
2885 /* This is for the add<mode>3_insn_set_carry pattern. */
2886 if ((code == LTU || code == GEU)
2887 && GET_CODE (op0) == PLUS
2888 && rtx_equal_p (XEXP (op0, 0), op1))
2889 return CCCmode;
2891 /* This is for the {add,sub,neg}<mode>3_insn_set_overflow pattern. */
2892 if ((code == EQ || code == NE)
2893 && GET_CODE (op1) == UNSPEC
2894 && (XINT (op1, 1) == UNSPEC_ADDV
2895 || XINT (op1, 1) == UNSPEC_SUBV
2896 || XINT (op1, 1) == UNSPEC_NEGV))
2897 return CCVmode;
2899 if (op1 != const0_rtx)
2900 return CCmode;
2902 switch (GET_CODE (op0))
2904 case PLUS:
2905 case MINUS:
2906 case NEG:
2907 case ASHIFT:
2908 case LTU:
2909 case LT:
2910 /* The C and V flags may be set differently from a COMPARE with zero.
2911 The consequence is that a comparison operator testing C or V must
2912 be turned into another operator not testing C or V and yielding
2913 the same result for a comparison with zero. That's possible for
2914 GE/LT which become NC/NS respectively, but not for GT/LE for which
2915 the altered operator doesn't exist on the Visium. */
2916 return CCNZmode;
2918 case ZERO_EXTRACT:
2919 /* This is a btst, the result is in C instead of Z. */
2920 return CCCmode;
2922 case CONST_INT:
2923 /* This is a degenerate case, typically an uninitialized variable. */
2924 gcc_assert (op0 == constm1_rtx);
2926 /* ... fall through ... */
2928 case REG:
2929 case AND:
2930 case IOR:
2931 case XOR:
2932 case NOT:
2933 case ASHIFTRT:
2934 case LSHIFTRT:
2935 case TRUNCATE:
2936 case SIGN_EXTEND:
2937 /* Pretend that the flags are set as for a COMPARE with zero.
2938 That's mostly true, except for the 2 right shift insns that
2939 will set the C flag. But the C flag is relevant only for
2940 the unsigned comparison operators and they are eliminated
2941 when applied to a comparison with zero. */
2942 return CCmode;
2944 default:
2945 gcc_unreachable ();
2949 /* Split a compare-and-branch with CODE, operands OP0 and OP1, and LABEL. */
2951 void
2952 visium_split_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx label)
2954 machine_mode cc_mode = visium_select_cc_mode (code, op0, op1);
2955 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2957 rtx x = gen_rtx_COMPARE (cc_mode, op0, op1);
2958 x = gen_rtx_SET (flags, x);
2959 emit_insn (x);
2961 x = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
2962 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, gen_rtx_LABEL_REF (Pmode, label),
2963 pc_rtx);
2964 x = gen_rtx_SET (pc_rtx, x);
2965 emit_jump_insn (x);
2967 visium_flags_exposed = true;
2970 /* Branch instructions on the Visium.
2972 Setting aside the interrupt-handling specific instructions, the ISA has
2973 two branch instructions: BRR and BRA. The former is used to implement
2974 short branches (+/- 2^17) within functions and its target is encoded in
2975 the instruction. The latter is used to implement all the other types
2976 of control flow changes and its target might not be statically known
2977 or even easily predictable at run time. Here's a complete summary of
2978 the patterns that generate a BRA instruction:
2980 1. Indirect jump
2981 2. Table jump
2982 3. Call
2983 4. Sibling call
2984 5. Return
2985 6. Long branch
2986 7. Trampoline
2988 Among these patterns, only the return (5) and the long branch (6) can be
2989 conditional; all the other patterns are always unconditional.
2991 The following algorithm can be used to identify the pattern for which
2992 the BRA instruction was generated and work out its target:
2994 A. If the source is r21 and the destination is r0, this is a return (5)
2995 and the target is the caller (i.e. the value of r21 on function's
2996 entry).
2998 B. If the source is rN, N != 21 and the destination is r0, this is either
2999 an indirect jump or a table jump (1, 2) and the target is not easily
3000 predictable.
3002 C. If the source is rN, N != 21 and the destination is r21, this is a call
3003 (3) and the target is given by the preceding MOVIL/MOVIU pair for rN,
3004 unless this is an indirect call in which case the target is not easily
3005 predictable.
3007 D. If the source is rN, N != 21 and the destination is also rN, this is
3008 either a sibling call or a trampoline (4, 7) and the target is given
3009 by the preceding MOVIL/MOVIU pair for rN.
3011 E. If the source is r21 and the destination is also r21, this is a long
3012 branch (6) and the target is given by the preceding MOVIL/MOVIU pair
3013 for r21.
3015 The other combinations are not used. This implementation has been devised
3016 to accommodate the branch predictor of the GR6 but is used unconditionally
3017 by the compiler, i.e. including for earlier processors. */
3019 /* Output a conditional/unconditional branch to LABEL. COND is the string
3020 condition. INSN is the instruction. */
3022 static const char *
3023 output_branch (rtx label, const char *cond, rtx_insn *insn)
3025 char str[64];
3026 rtx operands[2];
3028 gcc_assert (cond);
3029 operands[0] = label;
3031 /* If the length of the instruction is greater than 8, then this is a
3032 long branch and we need to work harder to emit it properly. */
3033 if (get_attr_length (insn) > 8)
3035 bool spilled;
3037 /* If the link register has been saved, then we use it. */
3038 if (current_function_saves_lr ())
3040 operands[1] = regno_reg_rtx [LINK_REGNUM];
3041 spilled = false;
3044 /* Or else, if the long-branch register isn't live, we use it. */
3045 else if (!df_regs_ever_live_p (long_branch_regnum))
3047 operands[1] = regno_reg_rtx [long_branch_regnum];
3048 spilled = false;
3051 /* Otherwise, we will use the long-branch register but we need to
3052 spill it to the stack and reload it at the end. We should have
3053 reserved the LR slot for this purpose. */
3054 else
3056 operands[1] = regno_reg_rtx [long_branch_regnum];
3057 spilled = true;
3058 gcc_assert (current_function_has_lr_slot ());
3061 /* First emit the spill to the stack:
3063 insn_in_delay_slot
3064 write.l [1](sp),reg */
3065 if (spilled)
3067 if (final_sequence)
3069 rtx_insn *delay = NEXT_INSN (insn);
3070 int seen;
3071 gcc_assert (delay);
3073 final_scan_insn (delay, asm_out_file, optimize, 0, &seen);
3074 PATTERN (delay) = gen_blockage ();
3075 INSN_CODE (delay) = -1;
3078 if (current_function_saves_fp ())
3079 output_asm_insn ("write.l 1(sp),%1", operands);
3080 else
3081 output_asm_insn ("write.l (sp),%1", operands);
3084 /* Then emit the core sequence:
3086 moviu reg,%u label
3087 movil reg,%l label
3088 bra tr,reg,reg
3090 We don't use r0 as the destination register of the branch because we
3091 want the Branch Pre-decode Logic of the GR6 to use the Address Load
3092 Array to predict the branch target. */
3093 output_asm_insn ("moviu %1,%%u %0", operands);
3094 output_asm_insn ("movil %1,%%l %0", operands);
3095 strcpy (str, "bra ");
3096 strcat (str, cond);
3097 strcat (str, ",%1,%1");
3098 if (!spilled)
3099 strcat (str, "%#");
3100 strcat (str, "\t\t;long branch");
3101 output_asm_insn (str, operands);
3103 /* Finally emit the reload:
3105 read.l reg,[1](sp) */
3106 if (spilled)
3108 if (current_function_saves_fp ())
3109 output_asm_insn (" read.l %1,1(sp)", operands);
3110 else
3111 output_asm_insn (" read.l %1,(sp)", operands);
3115 /* Or else, if the label is PC, then this is a return. */
3116 else if (label == pc_rtx)
3118 strcpy (str, "bra ");
3119 strcat (str, cond);
3120 strcat (str, ",r21,r0%#\t\t;return");
3121 output_asm_insn (str, operands);
3124 /* Otherwise, this is a short branch. */
3125 else
3127 strcpy (str, "brr ");
3128 strcat (str, cond);
3129 strcat (str, ",%0%#");
3130 output_asm_insn (str, operands);
3133 return "";
3136 /* Output an unconditional branch to LABEL. INSN is the instruction. */
3138 const char *
3139 output_ubranch (rtx label, rtx_insn *insn)
3141 return output_branch (label, "tr", insn);
3144 /* Output a conditional branch to LABEL. CODE is the comparison code.
3145 CC_MODE is the mode of the CC register. REVERSED is non-zero if we
3146 should reverse the sense of the comparison. INSN is the instruction. */
3148 const char *
3149 output_cbranch (rtx label, enum rtx_code code, machine_mode cc_mode,
3150 int reversed, rtx_insn *insn)
3152 const char *cond;
3154 if (reversed)
3156 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3157 code = reverse_condition_maybe_unordered (code);
3158 else
3159 code = reverse_condition (code);
3162 switch (code)
3164 case NE:
3165 if (cc_mode == CCCmode)
3166 cond = "cs";
3167 else if (cc_mode == CCVmode)
3168 cond = "os";
3169 else
3170 cond = "ne";
3171 break;
3173 case EQ:
3174 if (cc_mode == CCCmode)
3175 cond = "cc";
3176 else if (cc_mode == CCVmode)
3177 cond = "oc";
3178 else
3179 cond = "eq";
3180 break;
3182 case GE:
3183 if (cc_mode == CCNZmode)
3184 cond = "nc";
3185 else
3186 cond = "ge";
3187 break;
3189 case GT:
3190 cond = "gt";
3191 break;
3193 case LE:
3194 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3195 cond = "ls";
3196 else
3197 cond = "le";
3198 break;
3200 case LT:
3201 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3202 cond = "cs"; /* or "ns" */
3203 else if (cc_mode == CCNZmode)
3204 cond = "ns";
3205 else
3206 cond = "lt";
3207 break;
3209 case GEU:
3210 cond = "cc";
3211 break;
3213 case GTU:
3214 cond = "hi";
3215 break;
3217 case LEU:
3218 cond = "ls";
3219 break;
3221 case LTU:
3222 cond = "cs";
3223 break;
3225 case UNORDERED:
3226 cond = "os";
3227 break;
3229 case ORDERED:
3230 cond = "oc";
3231 break;
3233 case UNGE:
3234 cond = "cc"; /* or "nc" */
3235 break;
3237 case UNGT:
3238 cond = "hi";
3239 break;
3241 case UNLE:
3242 cond = "le";
3243 break;
3245 case UNLT:
3246 cond = "lt";
3247 break;
3249 /* These 2 comparison codes are not supported. */
3250 case UNEQ:
3251 case LTGT:
3252 default:
3253 gcc_unreachable ();
3256 return output_branch (label, cond, insn);
3259 /* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
3261 static bool
3262 visium_print_operand_punct_valid_p (unsigned char code)
3264 return code == '#';
3267 /* Implement TARGET_PRINT_OPERAND. Output to stdio stream FILE the assembler
3268 syntax for an instruction operand OP subject to the modifier LETTER. */
3270 static void
3271 visium_print_operand (FILE *file, rtx op, int letter)
3273 switch (letter)
3275 case '#':
3276 /* Output an insn in a delay slot. */
3277 if (final_sequence)
3278 visium_indent_opcode = 1;
3279 else
3280 fputs ("\n\t nop", file);
3281 return;
3283 case 'b':
3284 /* Print LS 8 bits of operand. */
3285 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xff);
3286 return;
3288 case 'w':
3289 /* Print LS 16 bits of operand. */
3290 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xffff);
3291 return;
3293 case 'u':
3294 /* Print MS 16 bits of operand. */
3295 fprintf (file,
3296 HOST_WIDE_INT_PRINT_UNSIGNED, (UINTVAL (op) >> 16) & 0xffff);
3297 return;
3299 case 'r':
3300 /* It's either a register or zero. */
3301 if (GET_CODE (op) == REG)
3302 fputs (reg_names[REGNO (op)], file);
3303 else
3304 fputs (reg_names[0], file);
3305 return;
3307 case 'f':
3308 /* It's either a FP register or zero. */
3309 if (GET_CODE (op) == REG)
3310 fputs (reg_names[REGNO (op)], file);
3311 else
3312 fputs (reg_names[FP_FIRST_REGNUM], file);
3313 return;
3316 switch (GET_CODE (op))
3318 case REG:
3319 if (letter == 'd')
3320 fputs (reg_names[REGNO (op) + 1], file);
3321 else
3322 fputs (reg_names[REGNO (op)], file);
3323 break;
3325 case SYMBOL_REF:
3326 case LABEL_REF:
3327 case CONST:
3328 output_addr_const (file, op);
3329 break;
3331 case MEM:
3332 visium_print_operand_address (file, GET_MODE (op), XEXP (op, 0));
3333 break;
3335 case CONST_INT:
3336 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
3337 break;
3339 case CODE_LABEL:
3340 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (op));
3341 break;
3343 case HIGH:
3344 visium_print_operand (file, XEXP (op, 1), letter);
3345 break;
3347 default:
3348 fatal_insn ("illegal operand ", op);
3352 /* Implement TARGET_PRINT_OPERAND_ADDRESS. Output to stdio stream FILE the
3353 assembler syntax for an instruction operand that is a memory reference
3354 whose address is ADDR. */
3356 static void
3357 visium_print_operand_address (FILE *file, machine_mode mode, rtx addr)
3359 switch (GET_CODE (addr))
3361 case REG:
3362 case SUBREG:
3363 fprintf (file, "(%s)", reg_names[true_regnum (addr)]);
3364 break;
3366 case PLUS:
3368 rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
3370 switch (GET_CODE (x))
3372 case REG:
3373 case SUBREG:
3374 if (CONST_INT_P (y))
3376 unsigned int regno = true_regnum (x);
3377 HOST_WIDE_INT val = INTVAL (y);
3378 switch (mode)
3380 case E_SImode:
3381 case E_DImode:
3382 case E_SFmode:
3383 case E_DFmode:
3384 val >>= 2;
3385 break;
3387 case E_HImode:
3388 val >>= 1;
3389 break;
3391 case E_QImode:
3392 default:
3393 break;
3395 fprintf (file, HOST_WIDE_INT_PRINT_DEC"(%s)", val,
3396 reg_names[regno]);
3398 else
3399 fatal_insn ("illegal operand address (1)", addr);
3400 break;
3402 default:
3403 if (CONSTANT_P (x) && CONSTANT_P (y))
3404 output_addr_const (file, addr);
3405 else
3406 fatal_insn ("illegal operand address (2)", addr);
3407 break;
3410 break;
3412 case LABEL_REF:
3413 case SYMBOL_REF:
3414 case CONST_INT:
3415 case CONST:
3416 output_addr_const (file, addr);
3417 break;
3419 case NOTE:
3420 if (NOTE_KIND (addr) != NOTE_INSN_DELETED_LABEL)
3421 fatal_insn ("illegal operand address (3)", addr);
3422 break;
3424 case CODE_LABEL:
3425 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (addr));
3426 break;
3428 default:
3429 fatal_insn ("illegal operand address (4)", addr);
3430 break;
3434 /* The Visium stack frames look like:
3436 Before call After call
3437 +-----------------------+ +-----------------------+
3438 | | | |
3439 high | previous | | previous |
3440 mem | frame | | frame |
3441 | | | |
3442 +-----------------------+ +-----------------------+
3443 | | | |
3444 | arguments on stack | | arguments on stack |
3445 | | | |
3446 SP+0->+-----------------------+ +-----------------------+
3447 | reg parm save area, |
3448 | only created for |
3449 | variable argument |
3450 | functions |
3451 +-----------------------+
3453 | register save area |
3455 +-----------------------+
3457 | local variables |
3459 FP+8->+-----------------------+
3460 | return address |
3461 FP+4->+-----------------------+
3462 | previous FP |
3463 FP+0->+-----------------------+
3465 | alloca allocations |
3467 +-----------------------+
3469 low | arguments on stack |
3470 mem | |
3471 SP+0->+-----------------------+
3473 Notes:
3474 1) The "reg parm save area" does not exist for non variable argument fns.
3475 2) The FP register is not saved if `frame_pointer_needed' is zero and it
3476 is not altered in the current function.
3477 3) The return address is not saved if there is no frame pointer and the
3478 current function is leaf.
3479 4) If the return address is not saved and the static chain register is
3480 live in the function, we allocate the return address slot to be able
3481 to spill the register for a long branch. */
3483 /* Define the register classes for local purposes. */
3484 enum reg_type { general, mdb, mdc, floating, last_type};
3486 #define GET_REG_TYPE(regno) \
3487 (GP_REGISTER_P (regno) ? general : \
3488 (regno) == MDB_REGNUM ? mdb : \
3489 (regno) == MDC_REGNUM ? mdc : \
3490 floating)
3492 /* First regno of each register type. */
3493 const int first_regno[last_type] = {0, MDB_REGNUM, MDC_REGNUM, FP_FIRST_REGNUM};
3495 /* Size in bytes of each register type. */
3496 const int reg_type_size[last_type] = {4, 8, 4, 4};
3498 /* Structure to be filled in by visium_compute_frame_size. */
3499 struct visium_frame_info
3501 unsigned int save_area_size; /* # bytes in the reg parm save area. */
3502 unsigned int reg_size1; /* # bytes to store first block of regs. */
3503 unsigned int reg_size2; /* # bytes to store second block of regs. */
3504 unsigned int max_reg1; /* max. regno in first block */
3505 unsigned int var_size; /* # bytes that variables take up. */
3506 unsigned int save_fp; /* Nonzero if fp must be saved. */
3507 unsigned int save_lr; /* Nonzero if lr must be saved. */
3508 unsigned int lr_slot; /* Nonzero if the lr slot is needed. */
3509 unsigned int combine; /* Nonzero if we can combine the allocation of
3510 variables and regs. */
3511 unsigned int interrupt; /* Nonzero if the function is an interrupt
3512 handler. */
3513 unsigned int mask[last_type]; /* Masks of saved regs: gp, mdb, mdc, fp */
3516 /* Current frame information calculated by visium_compute_frame_size. */
3517 static struct visium_frame_info current_frame_info;
3519 /* Accessor for current_frame_info.save_fp. */
3521 static inline bool
3522 current_function_saves_fp (void)
3524 return current_frame_info.save_fp != 0;
3527 /* Accessor for current_frame_info.save_lr. */
3529 static inline bool
3530 current_function_saves_lr (void)
3532 return current_frame_info.save_lr != 0;
3535 /* Accessor for current_frame_info.lr_slot. */
3537 static inline bool
3538 current_function_has_lr_slot (void)
3540 return current_frame_info.lr_slot != 0;
3543 /* Return non-zero if register REGNO needs to be saved in the frame. */
3545 static int
3546 visium_save_reg_p (int interrupt, int regno)
3548 switch (regno)
3550 case HARD_FRAME_POINTER_REGNUM:
3551 /* This register is call-saved but handled specially. */
3552 return 0;
3554 case MDC_REGNUM:
3555 /* This register is fixed but can be modified. */
3556 break;
3558 case 29:
3559 case 30:
3560 /* These registers are fixed and hold the interrupt context. */
3561 return (interrupt != 0);
3563 default:
3564 /* The other fixed registers are either immutable or special. */
3565 if (fixed_regs[regno])
3566 return 0;
3567 break;
3570 if (interrupt)
3572 if (crtl->is_leaf)
3574 if (df_regs_ever_live_p (regno))
3575 return 1;
3577 else if (call_used_regs[regno])
3578 return 1;
3580 /* To save mdb requires two temporary registers. To save mdc or
3581 any of the floating registers requires one temporary
3582 register. If this is an interrupt routine, the temporary
3583 registers need to be saved as well. These temporary registers
3584 are call used, so we only need deal with the case of leaf
3585 functions here. */
3586 if (regno == PROLOGUE_TMP_REGNUM)
3588 if (df_regs_ever_live_p (MDB_REGNUM)
3589 || df_regs_ever_live_p (MDC_REGNUM))
3590 return 1;
3592 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
3593 if (df_regs_ever_live_p (i))
3594 return 1;
3597 else if (regno == PROLOGUE_TMP_REGNUM + 1)
3599 if (df_regs_ever_live_p (MDB_REGNUM))
3600 return 1;
3604 return df_regs_ever_live_p (regno) && !call_used_regs[regno];
3607 /* Compute the frame size required by the function. This function is called
3608 during the reload pass and also by visium_expand_prologue. */
3610 static int
3611 visium_compute_frame_size (int size)
3613 const int save_area_size = visium_reg_parm_save_area_size;
3614 const int var_size = VISIUM_STACK_ALIGN (size);
3615 const int save_fp
3616 = frame_pointer_needed || df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM);
3617 const int save_lr = frame_pointer_needed || !crtl->is_leaf;
3618 const int lr_slot = !save_lr && df_regs_ever_live_p (long_branch_regnum);
3619 const int local_frame_offset
3620 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3621 const int interrupt = visium_interrupt_function_p ();
3622 unsigned int mask[last_type];
3623 int reg_size1 = 0;
3624 int max_reg1 = 0;
3625 int reg_size2 = 0;
3626 int reg_size;
3627 int combine;
3628 int frame_size;
3629 int regno;
3631 memset (mask, 0, last_type * sizeof (unsigned int));
3633 /* The registers may need stacking in 2 blocks since only 32 32-bit words
3634 can be indexed from a given base address. */
3635 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3637 if (visium_save_reg_p (interrupt, regno))
3639 enum reg_type reg_type = GET_REG_TYPE (regno);
3640 int mask_bit = 1 << (regno - first_regno[reg_type]);
3641 int nbytes = reg_type_size[reg_type];
3643 if (reg_size1 + nbytes > 32 * UNITS_PER_WORD)
3644 break;
3646 reg_size1 += nbytes;
3647 max_reg1 = regno;
3648 mask[reg_type] |= mask_bit;
3652 for (regno = max_reg1 + 1; regno < FIRST_PSEUDO_REGISTER; regno++)
3654 if (visium_save_reg_p (interrupt, regno))
3656 enum reg_type reg_type = GET_REG_TYPE (regno);
3657 int mask_bit = 1 << (regno - first_regno[reg_type]);
3658 int nbytes = reg_type_size[reg_type];
3660 reg_size2 += nbytes;
3661 mask[reg_type] |= mask_bit;
3665 reg_size = reg_size2 ? reg_size2 : reg_size1;
3666 combine = (local_frame_offset + var_size + reg_size) <= 32 * UNITS_PER_WORD;
3667 frame_size
3668 = local_frame_offset + var_size + reg_size2 + reg_size1 + save_area_size;
3670 current_frame_info.save_area_size = save_area_size;
3671 current_frame_info.reg_size1 = reg_size1;
3672 current_frame_info.max_reg1 = max_reg1;
3673 current_frame_info.reg_size2 = reg_size2;
3674 current_frame_info.var_size = var_size;
3675 current_frame_info.save_fp = save_fp;
3676 current_frame_info.save_lr = save_lr;
3677 current_frame_info.lr_slot = lr_slot;
3678 current_frame_info.combine = combine;
3679 current_frame_info.interrupt = interrupt;
3681 memcpy (current_frame_info.mask, mask, last_type * sizeof (unsigned int));
3683 return frame_size;
3686 /* Helper function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define
3687 the offset between two registers, one to be eliminated, and the other its
3688 replacement, at the start of a routine. */
3691 visium_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
3693 const int save_fp = current_frame_info.save_fp;
3694 const int save_lr = current_frame_info.save_lr;
3695 const int lr_slot = current_frame_info.lr_slot;
3696 int offset;
3698 if (from == FRAME_POINTER_REGNUM)
3699 offset = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3700 else if (from == ARG_POINTER_REGNUM)
3701 offset = visium_compute_frame_size (get_frame_size ());
3702 else
3703 gcc_unreachable ();
3705 return offset;
3708 /* For an interrupt handler, we may be saving call-clobbered registers.
3709 Say the epilogue uses these in addition to the link register. */
3712 visium_epilogue_uses (int regno)
3714 if (regno == LINK_REGNUM)
3715 return 1;
3717 if (reload_completed)
3719 enum reg_type reg_type = GET_REG_TYPE (regno);
3720 int mask_bit = 1 << (regno - first_regno[reg_type]);
3722 return (current_frame_info.mask[reg_type] & mask_bit) != 0;
3725 return 0;
3728 /* Wrapper around emit_insn that sets RTX_FRAME_RELATED_P on the insn. */
3730 static rtx
3731 emit_frame_insn (rtx x)
3733 x = emit_insn (x);
3734 RTX_FRAME_RELATED_P (x) = 1;
3735 return x;
3738 /* Allocate ALLOC bytes on the stack and save the registers LOW_REGNO to
3739 HIGH_REGNO at OFFSET from the stack pointer. */
3741 static void
3742 visium_save_regs (int alloc, int offset, int low_regno, int high_regno)
3744 /* If this is an interrupt handler function, then mark the register
3745 stores as volatile. This will prevent the instruction scheduler
3746 from scrambling the order of register saves. */
3747 const int volatile_p = current_frame_info.interrupt;
3748 int regno;
3750 /* Allocate the stack space. */
3751 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, stack_pointer_rtx,
3752 GEN_INT (-alloc)));
3754 for (regno = low_regno; regno <= high_regno; regno++)
3756 enum reg_type reg_type = GET_REG_TYPE (regno);
3757 int mask_bit = 1 << (regno - first_regno[reg_type]);
3758 rtx insn;
3760 if (current_frame_info.mask[reg_type] & mask_bit)
3762 offset -= reg_type_size[reg_type];
3763 switch (reg_type)
3765 case general:
3767 rtx mem
3768 = gen_frame_mem (SImode,
3769 plus_constant (Pmode,
3770 stack_pointer_rtx, offset));
3771 MEM_VOLATILE_P (mem) = volatile_p;
3772 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, regno)));
3774 break;
3776 case mdb:
3778 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3779 rtx mem
3780 = gen_frame_mem (DImode,
3781 plus_constant (Pmode,
3782 stack_pointer_rtx, offset));
3783 rtx reg = gen_rtx_REG (DImode, regno);
3784 MEM_VOLATILE_P (mem) = volatile_p;
3785 emit_insn (gen_movdi (tmp, reg));
3786 /* Do not generate CFI if in interrupt handler. */
3787 if (volatile_p)
3788 emit_insn (gen_movdi (mem, tmp));
3789 else
3791 insn = emit_frame_insn (gen_movdi (mem, tmp));
3792 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3793 gen_rtx_SET (mem, reg));
3796 break;
3798 case mdc:
3800 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3801 rtx mem
3802 = gen_frame_mem (SImode,
3803 plus_constant (Pmode,
3804 stack_pointer_rtx, offset));
3805 rtx reg = gen_rtx_REG (SImode, regno);
3806 MEM_VOLATILE_P (mem) = volatile_p;
3807 emit_insn (gen_movsi (tmp, reg));
3808 insn = emit_frame_insn (gen_movsi (mem, tmp));
3809 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3810 gen_rtx_SET (mem, reg));
3812 break;
3814 case floating:
3816 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3817 rtx mem
3818 = gen_frame_mem (SFmode,
3819 plus_constant (Pmode,
3820 stack_pointer_rtx, offset));
3821 rtx reg = gen_rtx_REG (SFmode, regno);
3822 MEM_VOLATILE_P (mem) = volatile_p;
3823 emit_insn (gen_movsf (tmp, reg));
3824 insn = emit_frame_insn (gen_movsf (mem, tmp));
3825 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3826 gen_rtx_SET (mem, reg));
3828 break;
3830 default:
3831 break;
3837 /* This function generates the code for function entry. */
3839 void
3840 visium_expand_prologue (void)
3842 const int frame_size = visium_compute_frame_size (get_frame_size ());
3843 const int save_area_size = current_frame_info.save_area_size;
3844 const int reg_size1 = current_frame_info.reg_size1;
3845 const int max_reg1 = current_frame_info.max_reg1;
3846 const int reg_size2 = current_frame_info.reg_size2;
3847 const int var_size = current_frame_info.var_size;
3848 const int save_fp = current_frame_info.save_fp;
3849 const int save_lr = current_frame_info.save_lr;
3850 const int lr_slot = current_frame_info.lr_slot;
3851 const int local_frame_offset
3852 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3853 const int combine = current_frame_info.combine;
3854 int reg_size;
3855 int first_reg;
3856 int fsize;
3858 /* Save the frame size for future references. */
3859 visium_frame_size = frame_size;
3861 if (flag_stack_usage_info)
3862 current_function_static_stack_size = frame_size;
3864 /* If the registers have to be stacked in 2 blocks, stack the first one. */
3865 if (reg_size2)
3867 visium_save_regs (reg_size1 + save_area_size, reg_size1, 0, max_reg1);
3868 reg_size = reg_size2;
3869 first_reg = max_reg1 + 1;
3870 fsize = local_frame_offset + var_size + reg_size2;
3872 else
3874 reg_size = reg_size1;
3875 first_reg = 0;
3876 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
3879 /* If we can't combine register stacking with variable allocation, partially
3880 allocate and stack the (remaining) registers now. */
3881 if (reg_size && !combine)
3882 visium_save_regs (fsize - local_frame_offset - var_size, reg_size,
3883 first_reg, FIRST_PSEUDO_REGISTER - 1);
3885 /* If we can combine register stacking with variable allocation, fully
3886 allocate and stack the (remaining) registers now. */
3887 if (reg_size && combine)
3888 visium_save_regs (fsize, local_frame_offset + var_size + reg_size,
3889 first_reg, FIRST_PSEUDO_REGISTER - 1);
3891 /* Otherwise space may still need to be allocated for the variables. */
3892 else if (fsize)
3894 const int alloc_size = reg_size ? local_frame_offset + var_size : fsize;
3896 if (alloc_size > 65535)
3898 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM), insn;
3899 emit_insn (gen_movsi (tmp, GEN_INT (alloc_size)));
3900 insn = emit_frame_insn (gen_subsi3_flags (stack_pointer_rtx,
3901 stack_pointer_rtx,
3902 tmp));
3903 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3904 gen_rtx_SET (stack_pointer_rtx,
3905 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3906 GEN_INT (-alloc_size))));
3908 else
3909 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx,
3910 stack_pointer_rtx,
3911 GEN_INT (-alloc_size)));
3914 if (save_fp)
3915 emit_frame_insn (gen_movsi (gen_frame_mem (SImode, stack_pointer_rtx),
3916 hard_frame_pointer_rtx));
3918 if (frame_pointer_needed)
3919 emit_frame_insn (gen_stack_save ());
3921 if (save_lr)
3923 rtx base_rtx, mem;
3925 /* Normally the frame pointer and link register get saved via
3926 write.l (sp),fp
3927 move.l fp,sp
3928 write.l 1(sp),r21
3930 Indexing off sp rather than fp to store the link register
3931 avoids presenting the instruction scheduler with an initial
3932 pipeline hazard. If however the frame is needed for eg.
3933 __builtin_return_address which needs to retrieve the saved
3934 value of the link register from the stack at fp + 4 then
3935 indexing from sp can confuse the dataflow, causing the link
3936 register to be retrieved before it has been saved. */
3937 if (cfun->machine->frame_needed)
3938 base_rtx = hard_frame_pointer_rtx;
3939 else
3940 base_rtx = stack_pointer_rtx;
3942 mem = gen_frame_mem (SImode,
3943 plus_constant (Pmode,
3944 base_rtx, save_fp * UNITS_PER_WORD));
3945 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, LINK_REGNUM)));
3949 static GTY(()) rtx cfa_restores;
3951 /* Queue a REG_CFA_RESTORE note until next stack manipulation insn. */
3953 static void
3954 visium_add_cfa_restore_note (rtx reg)
3956 cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
3959 /* Add queued REG_CFA_RESTORE notes to INSN, if any. */
3961 static void
3962 visium_add_queued_cfa_restore_notes (rtx insn)
3964 rtx last;
3965 if (!cfa_restores)
3966 return;
3967 for (last = cfa_restores; XEXP (last, 1); last = XEXP (last, 1))
3969 XEXP (last, 1) = REG_NOTES (insn);
3970 REG_NOTES (insn) = cfa_restores;
3971 cfa_restores = NULL_RTX;
3974 /* Restore the registers LOW_REGNO to HIGH_REGNO from the save area at OFFSET
3975 from the stack pointer and pop DEALLOC bytes off the stack. */
3977 static void
3978 visium_restore_regs (int dealloc, int offset, int high_regno, int low_regno)
3980 /* If this is an interrupt handler function, then mark the register
3981 restores as volatile. This will prevent the instruction scheduler
3982 from scrambling the order of register restores. */
3983 const int volatile_p = current_frame_info.interrupt;
3984 int r30_offset = -1;
3985 int regno;
3987 for (regno = high_regno; regno >= low_regno; --regno)
3989 enum reg_type reg_type = GET_REG_TYPE (regno);
3990 int mask_bit = 1 << (regno - first_regno[reg_type]);
3992 if (current_frame_info.mask[reg_type] & mask_bit)
3994 switch (reg_type)
3996 case general:
3997 /* Postpone restoring the interrupted context registers
3998 until last, since they need to be preceded by a dsi. */
3999 if (regno == 29)
4001 else if (regno == 30)
4002 r30_offset = offset;
4003 else
4005 rtx mem
4006 = gen_frame_mem (SImode,
4007 plus_constant (Pmode,
4008 stack_pointer_rtx,
4009 offset));
4010 rtx reg = gen_rtx_REG (SImode, regno);
4011 MEM_VOLATILE_P (mem) = volatile_p;
4012 emit_insn (gen_movsi (reg, mem));
4013 visium_add_cfa_restore_note (reg);
4015 break;
4017 case mdb:
4019 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
4020 rtx mem
4021 = gen_frame_mem (DImode,
4022 plus_constant (Pmode,
4023 stack_pointer_rtx, offset));
4024 rtx reg = gen_rtx_REG (DImode, regno);
4025 MEM_VOLATILE_P (mem) = volatile_p;
4026 emit_insn (gen_movdi (tmp, mem));
4027 emit_insn (gen_movdi (reg, tmp));
4028 /* Do not generate CFI if in interrupt handler. */
4029 if (!volatile_p)
4030 visium_add_cfa_restore_note (reg);
4032 break;
4034 case mdc:
4036 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4037 rtx mem
4038 = gen_frame_mem (SImode,
4039 plus_constant (Pmode,
4040 stack_pointer_rtx, offset));
4041 rtx reg = gen_rtx_REG (SImode, regno);
4042 MEM_VOLATILE_P (mem) = volatile_p;
4043 emit_insn (gen_movsi (tmp, mem));
4044 emit_insn (gen_movsi (reg, tmp));
4045 visium_add_cfa_restore_note (reg);
4047 break;
4049 case floating:
4051 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
4052 rtx mem
4053 = gen_frame_mem (SFmode,
4054 plus_constant (Pmode,
4055 stack_pointer_rtx, offset));
4056 rtx reg = gen_rtx_REG (SFmode, regno);
4057 MEM_VOLATILE_P (mem) = volatile_p;
4058 emit_insn (gen_movsf (tmp, mem));
4059 emit_insn (gen_movsf (reg, tmp));
4060 visium_add_cfa_restore_note (reg);
4062 break;
4064 default:
4065 break;
4068 offset += reg_type_size[reg_type];
4072 /* If the interrupted context needs to be restored, precede the
4073 restores of r29 and r30 by a dsi. */
4074 if (r30_offset >= 0)
4076 emit_insn (gen_dsi ());
4077 emit_move_insn (gen_rtx_REG (SImode, 30),
4078 gen_frame_mem (SImode,
4079 plus_constant (Pmode,
4080 stack_pointer_rtx,
4081 r30_offset)));
4082 emit_move_insn (gen_rtx_REG (SImode, 29),
4083 gen_frame_mem (SImode,
4084 plus_constant (Pmode,
4085 stack_pointer_rtx,
4086 r30_offset + 4)));
4089 /* Deallocate the stack space. */
4090 rtx insn = emit_frame_insn (gen_stack_pop (GEN_INT (dealloc)));
4091 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4092 gen_rtx_SET (stack_pointer_rtx,
4093 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4094 GEN_INT (dealloc))));
4095 visium_add_queued_cfa_restore_notes (insn);
4098 /* This function generates the code for function exit. */
4100 void
4101 visium_expand_epilogue (void)
4103 const int save_area_size = current_frame_info.save_area_size;
4104 const int reg_size1 = current_frame_info.reg_size1;
4105 const int max_reg1 = current_frame_info.max_reg1;
4106 const int reg_size2 = current_frame_info.reg_size2;
4107 const int var_size = current_frame_info.var_size;
4108 const int restore_fp = current_frame_info.save_fp;
4109 const int restore_lr = current_frame_info.save_lr;
4110 const int lr_slot = current_frame_info.lr_slot;
4111 const int local_frame_offset
4112 = (restore_fp + restore_lr + lr_slot) * UNITS_PER_WORD;
4113 const int combine = current_frame_info.combine;
4114 int reg_size;
4115 int last_reg;
4116 int fsize;
4118 /* Do not bother restoring the stack pointer if it hasn't been changed in
4119 the function since it was saved _after_ the allocation of the frame. */
4120 if (!crtl->sp_is_unchanging)
4121 emit_insn (gen_stack_restore ());
4123 /* Restore the frame pointer if necessary. The usual code would be:
4125 move.l sp,fp
4126 read.l fp,(sp)
4128 but for the MCM this constitutes a stall/hazard so it is changed to:
4130 move.l sp,fp
4131 read.l fp,(fp)
4133 if the stack pointer has actually been restored. */
4134 if (restore_fp)
4136 rtx src;
4138 if (TARGET_MCM && !crtl->sp_is_unchanging)
4139 src = gen_frame_mem (SImode, hard_frame_pointer_rtx);
4140 else
4141 src = gen_frame_mem (SImode, stack_pointer_rtx);
4143 rtx insn = emit_frame_insn (gen_movsi (hard_frame_pointer_rtx, src));
4144 add_reg_note (insn, REG_CFA_ADJUST_CFA,
4145 gen_rtx_SET (stack_pointer_rtx,
4146 hard_frame_pointer_rtx));
4147 visium_add_cfa_restore_note (hard_frame_pointer_rtx);
4150 /* Restore the link register if necessary. */
4151 if (restore_lr)
4153 rtx mem = gen_frame_mem (SImode,
4154 plus_constant (Pmode,
4155 stack_pointer_rtx,
4156 restore_fp * UNITS_PER_WORD));
4157 rtx reg = gen_rtx_REG (SImode, LINK_REGNUM);
4158 emit_insn (gen_movsi (reg, mem));
4159 visium_add_cfa_restore_note (reg);
4162 /* If we have two blocks of registers, deal with the second one first. */
4163 if (reg_size2)
4165 reg_size = reg_size2;
4166 last_reg = max_reg1 + 1;
4167 fsize = local_frame_offset + var_size + reg_size2;
4169 else
4171 reg_size = reg_size1;
4172 last_reg = 0;
4173 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
4176 /* If the variable allocation could be combined with register stacking,
4177 restore the (remaining) registers and fully deallocate now. */
4178 if (reg_size && combine)
4179 visium_restore_regs (fsize, local_frame_offset + var_size,
4180 FIRST_PSEUDO_REGISTER - 1, last_reg);
4182 /* Otherwise deallocate the variables first. */
4183 else if (fsize)
4185 const int pop_size = reg_size ? local_frame_offset + var_size : fsize;
4186 rtx insn;
4188 if (pop_size > 65535)
4190 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4191 emit_move_insn (tmp, GEN_INT (pop_size));
4192 insn = emit_frame_insn (gen_stack_pop (tmp));
4194 else
4195 insn = emit_frame_insn (gen_stack_pop (GEN_INT (pop_size)));
4196 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4197 gen_rtx_SET (stack_pointer_rtx,
4198 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4199 GEN_INT (pop_size))));
4200 visium_add_queued_cfa_restore_notes (insn);
4203 /* If the variable allocation couldn't be combined with register stacking,
4204 restore the (remaining) registers now and partially deallocate. */
4205 if (reg_size && !combine)
4206 visium_restore_regs (fsize - local_frame_offset - var_size, 0,
4207 FIRST_PSEUDO_REGISTER - 1, last_reg);
4209 /* If the first block of registers has yet to be restored, do it now. */
4210 if (reg_size2)
4211 visium_restore_regs (reg_size1 + save_area_size, 0, max_reg1, 0);
4213 /* If this is an exception return, make the necessary stack adjustment. */
4214 if (crtl->calls_eh_return)
4215 emit_insn (gen_stack_pop (EH_RETURN_STACKADJ_RTX));
4218 /* Return true if it is appropriate to emit `return' instructions in the
4219 body of a function. */
4221 bool
4222 visium_can_use_return_insn_p (void)
4224 return reload_completed
4225 && visium_frame_size == 0
4226 && !visium_interrupt_function_p ();
4229 /* Return the register class required for an intermediate register used to
4230 copy a register of RCLASS from/to X. If no such intermediate register is
4231 required, return NO_REGS. If more than one such intermediate register is
4232 required, describe the one that is closest in the copy chain to the reload
4233 register. */
4235 static reg_class_t
4236 visium_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
4237 reg_class_t rclass,
4238 machine_mode mode ATTRIBUTE_UNUSED,
4239 secondary_reload_info *sri ATTRIBUTE_UNUSED)
4241 int regno = true_regnum (x);
4243 /* For MDB, MDC and FP_REGS, a general register is needed for a move to
4244 or from memory. */
4245 if (regno == -1 && (rclass == MDB || rclass == MDC || rclass == FP_REGS))
4246 return GENERAL_REGS;
4248 /* Moves between MDB, MDC and FP_REGS also require a general register. */
4249 else if (((regno == R_MDB || regno == R_MDC) && rclass == FP_REGS)
4250 || (FP_REGISTER_P (regno) && (rclass == MDB || rclass == MDC)))
4251 return GENERAL_REGS;
4253 /* Finally an (unlikely ?) move between MDB and MDC needs a general reg. */
4254 else if ((regno == R_MDB && rclass == MDC)
4255 || (rclass == MDB && regno == R_MDC))
4256 return GENERAL_REGS;
4258 return NO_REGS;
4261 /* Return true if pseudos that have been assigned to registers of RCLASS
4262 would likely be spilled because registers of RCLASS are needed for
4263 spill registers. */
4265 static bool
4266 visium_class_likely_spilled_p (reg_class_t rclass ATTRIBUTE_UNUSED)
4268 /* Return false for classes R1, R2 and R3, which are intended to be used
4269 only in the source code in conjunction with block move instructions. */
4270 return false;
4273 /* Return the register number if OP is a REG or a SUBREG of a REG, and
4274 INVALID_REGNUM in all the other cases. */
4276 unsigned int
4277 reg_or_subreg_regno (rtx op)
4279 unsigned int regno;
4281 if (GET_CODE (op) == REG)
4282 regno = REGNO (op);
4283 else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
4285 if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
4286 regno = subreg_regno (op);
4287 else
4288 regno = REGNO (SUBREG_REG (op));
4290 else
4291 regno = INVALID_REGNUM;
4293 return regno;
4296 #include "gt-visium.h"