Add assember CFI directives to millicode division and remainder routines.
[official-gcc.git] / gcc / config / visium / visium.cc
blobec4c2e9ae5cb0b5322b731d6bd6ed65964c17b0b
1 /* Output routines for Visium.
2 Copyright (C) 2002-2023 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 #define IN_TARGET_CODE 1
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "backend.h"
27 #include "target.h"
28 #include "rtl.h"
29 #include "tree.h"
30 #include "gimple-expr.h"
31 #include "df.h"
32 #include "memmodel.h"
33 #include "tm_p.h"
34 #include "stringpool.h"
35 #include "attribs.h"
36 #include "expmed.h"
37 #include "optabs.h"
38 #include "regs.h"
39 #include "emit-rtl.h"
40 #include "recog.h"
41 #include "diagnostic-core.h"
42 #include "alias.h"
43 #include "flags.h"
44 #include "fold-const.h"
45 #include "stor-layout.h"
46 #include "calls.h"
47 #include "varasm.h"
48 #include "output.h"
49 #include "insn-attr.h"
50 #include "explow.h"
51 #include "expr.h"
52 #include "gimplify.h"
53 #include "langhooks.h"
54 #include "reload.h"
55 #include "tm-constrs.h"
56 #include "tree-pass.h"
57 #include "context.h"
58 #include "builtins.h"
59 #include "opts.h"
61 /* This file should be included last. */
62 #include "target-def.h"
64 /* Enumeration of indexes into machine_libfunc_table. */
65 enum machine_libfunc_index
67 MLTI_long_int_memcpy,
68 MLTI_wrd_memcpy,
69 MLTI_byt_memcpy,
71 MLTI_long_int_memset,
72 MLTI_wrd_memset,
73 MLTI_byt_memset,
75 MLTI_set_trampoline_parity,
77 MLTI_MAX
80 struct GTY(()) machine_libfuncs
82 rtx table[MLTI_MAX];
85 /* The table of Visium-specific libfuncs. */
86 static GTY(()) struct machine_libfuncs visium_libfuncs;
88 #define vlt visium_libfuncs.table
90 /* Accessor macros for visium_libfuncs. */
91 #define long_int_memcpy_libfunc (vlt[MLTI_long_int_memcpy])
92 #define wrd_memcpy_libfunc (vlt[MLTI_wrd_memcpy])
93 #define byt_memcpy_libfunc (vlt[MLTI_byt_memcpy])
94 #define long_int_memset_libfunc (vlt[MLTI_long_int_memset])
95 #define wrd_memset_libfunc (vlt[MLTI_wrd_memset])
96 #define byt_memset_libfunc (vlt[MLTI_byt_memset])
97 #define set_trampoline_parity_libfunc (vlt[MLTI_set_trampoline_parity])
99 /* Machine specific function data. */
100 struct GTY (()) machine_function
102 /* Size of the frame of the function. */
103 int frame_size;
105 /* Size of the reg parm save area, non-zero only for functions with variable
106 argument list. We cannot use the crtl->args.pretend_args_size machinery
107 for this purpose because this size is added to virtual_incoming_args_rtx
108 to give the location of the first parameter passed by the caller on the
109 stack and virtual_incoming_args_rtx is also the location of the first
110 parameter on the stack. So crtl->args.pretend_args_size can be non-zero
111 only if the first non-register named parameter is not passed entirely on
112 the stack and this runs afoul of the need to have a reg parm save area
113 even with a variable argument list starting on the stack because of the
114 separate handling of general and floating-point registers. */
115 int reg_parm_save_area_size;
117 /* True if we have created an rtx which relies on the frame pointer. */
118 bool frame_needed;
120 /* True if we have exposed the flags register. From this moment on, we
121 cannot generate simple operations for integer registers. We could
122 use reload_completed for this purpose, but this would cripple the
123 postreload CSE and GCSE passes which run before postreload split. */
124 bool flags_exposed;
127 #define visium_frame_size cfun->machine->frame_size
128 #define visium_reg_parm_save_area_size cfun->machine->reg_parm_save_area_size
129 #define visium_frame_needed cfun->machine->frame_needed
130 #define visium_flags_exposed cfun->machine->flags_exposed
132 /* 1 if the next opcode is to be specially indented. */
133 int visium_indent_opcode = 0;
135 /* Register number used for long branches when LR isn't available. It
136 must be a call-used register since it isn't saved on function entry.
137 We do not care whether the branch is predicted or not on the GR6,
138 given how unlikely it is to have a long branch in a leaf function. */
139 static unsigned int long_branch_regnum = 31;
141 static tree visium_handle_interrupt_attr (tree *, tree, tree, int, bool *);
142 static inline bool current_function_saves_fp (void);
143 static inline bool current_function_saves_lr (void);
144 static inline bool current_function_has_lr_slot (void);
146 /* Supported attributes:
147 interrupt -- specifies this function is an interrupt handler. */
148 static const struct attribute_spec visium_attribute_table[] =
150 /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
151 affects_type_identity, handler, exclude } */
152 { "interrupt", 0, 0, true, false, false, false, visium_handle_interrupt_attr,
153 NULL},
154 { NULL, 0, 0, false, false, false, false, NULL, NULL },
157 static struct machine_function *visium_init_machine_status (void);
159 /* Target hooks and TARGET_INITIALIZER */
161 static bool visium_pass_by_reference (cumulative_args_t,
162 const function_arg_info &);
164 static rtx visium_function_arg (cumulative_args_t, const function_arg_info &);
166 static void visium_function_arg_advance (cumulative_args_t,
167 const function_arg_info &);
169 static bool visium_return_in_memory (const_tree, const_tree fntype);
171 static rtx visium_function_value (const_tree, const_tree fn_decl_or_type,
172 bool);
174 static rtx visium_libcall_value (machine_mode, const_rtx);
176 static void visium_setup_incoming_varargs (cumulative_args_t,
177 const function_arg_info &,
178 int *, int);
180 static void visium_va_start (tree valist, rtx nextarg);
182 static tree visium_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
184 static bool visium_function_ok_for_sibcall (tree, tree);
186 static bool visium_frame_pointer_required (void);
188 static tree visium_build_builtin_va_list (void);
190 static rtx_insn *visium_md_asm_adjust (vec<rtx> &, vec<rtx> &,
191 vec<machine_mode> &,
192 vec<const char *> &, vec<rtx> &,
193 HARD_REG_SET &, location_t);
195 static bool visium_legitimate_constant_p (machine_mode, rtx);
197 static bool visium_legitimate_address_p (machine_mode, rtx, bool);
199 static bool visium_print_operand_punct_valid_p (unsigned char);
200 static void visium_print_operand (FILE *, rtx, int);
201 static void visium_print_operand_address (FILE *, machine_mode, rtx);
203 static void visium_conditional_register_usage (void);
205 static rtx visium_legitimize_address (rtx, rtx, machine_mode);
207 static reg_class_t visium_secondary_reload (bool, rtx, reg_class_t,
208 machine_mode,
209 secondary_reload_info *);
211 static bool visium_class_likely_spilled_p (reg_class_t);
213 static void visium_trampoline_init (rtx, tree, rtx);
215 static int visium_issue_rate (void);
217 static int visium_adjust_priority (rtx_insn *, int);
219 static int visium_adjust_cost (rtx_insn *, int, rtx_insn *, int, unsigned int);
221 static int visium_register_move_cost (machine_mode, reg_class_t,
222 reg_class_t);
224 static int visium_memory_move_cost (machine_mode, reg_class_t, bool);
226 static bool visium_rtx_costs (rtx, machine_mode, int, int, int *, bool);
228 static void visium_option_override (void);
230 static void visium_init_libfuncs (void);
232 static unsigned int visium_reorg (void);
234 static unsigned int visium_hard_regno_nregs (unsigned int, machine_mode);
236 static bool visium_hard_regno_mode_ok (unsigned int, machine_mode);
238 static bool visium_modes_tieable_p (machine_mode, machine_mode);
240 static bool visium_can_change_mode_class (machine_mode, machine_mode,
241 reg_class_t);
243 static HOST_WIDE_INT visium_constant_alignment (const_tree, HOST_WIDE_INT);
245 /* Setup the global target hooks structure. */
247 #undef TARGET_MAX_ANCHOR_OFFSET
248 #define TARGET_MAX_ANCHOR_OFFSET 31
250 #undef TARGET_PASS_BY_REFERENCE
251 #define TARGET_PASS_BY_REFERENCE visium_pass_by_reference
253 #undef TARGET_FUNCTION_ARG
254 #define TARGET_FUNCTION_ARG visium_function_arg
256 #undef TARGET_FUNCTION_ARG_ADVANCE
257 #define TARGET_FUNCTION_ARG_ADVANCE visium_function_arg_advance
259 #undef TARGET_RETURN_IN_MEMORY
260 #define TARGET_RETURN_IN_MEMORY visium_return_in_memory
262 #undef TARGET_FUNCTION_VALUE
263 #define TARGET_FUNCTION_VALUE visium_function_value
265 #undef TARGET_LIBCALL_VALUE
266 #define TARGET_LIBCALL_VALUE visium_libcall_value
268 #undef TARGET_SETUP_INCOMING_VARARGS
269 #define TARGET_SETUP_INCOMING_VARARGS visium_setup_incoming_varargs
271 #undef TARGET_EXPAND_BUILTIN_VA_START
272 #define TARGET_EXPAND_BUILTIN_VA_START visium_va_start
274 #undef TARGET_BUILD_BUILTIN_VA_LIST
275 #define TARGET_BUILD_BUILTIN_VA_LIST visium_build_builtin_va_list
277 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
278 #define TARGET_GIMPLIFY_VA_ARG_EXPR visium_gimplify_va_arg
280 #undef TARGET_LEGITIMATE_CONSTANT_P
281 #define TARGET_LEGITIMATE_CONSTANT_P visium_legitimate_constant_p
283 #undef TARGET_LRA_P
284 #define TARGET_LRA_P hook_bool_void_false
286 #undef TARGET_LEGITIMATE_ADDRESS_P
287 #define TARGET_LEGITIMATE_ADDRESS_P visium_legitimate_address_p
289 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
290 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P visium_print_operand_punct_valid_p
292 #undef TARGET_PRINT_OPERAND
293 #define TARGET_PRINT_OPERAND visium_print_operand
295 #undef TARGET_PRINT_OPERAND_ADDRESS
296 #define TARGET_PRINT_OPERAND_ADDRESS visium_print_operand_address
298 #undef TARGET_ATTRIBUTE_TABLE
299 #define TARGET_ATTRIBUTE_TABLE visium_attribute_table
301 #undef TARGET_ADDRESS_COST
302 #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
304 #undef TARGET_STRICT_ARGUMENT_NAMING
305 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
307 #undef TARGET_SCHED_ISSUE_RATE
308 #define TARGET_SCHED_ISSUE_RATE visium_issue_rate
310 #undef TARGET_SCHED_ADJUST_PRIORITY
311 #define TARGET_SCHED_ADJUST_PRIORITY visium_adjust_priority
313 #undef TARGET_SCHED_ADJUST_COST
314 #define TARGET_SCHED_ADJUST_COST visium_adjust_cost
316 #undef TARGET_MEMORY_MOVE_COST
317 #define TARGET_MEMORY_MOVE_COST visium_memory_move_cost
319 #undef TARGET_REGISTER_MOVE_COST
320 #define TARGET_REGISTER_MOVE_COST visium_register_move_cost
322 #undef TARGET_RTX_COSTS
323 #define TARGET_RTX_COSTS visium_rtx_costs
325 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
326 #define TARGET_FUNCTION_OK_FOR_SIBCALL visium_function_ok_for_sibcall
328 #undef TARGET_FRAME_POINTER_REQUIRED
329 #define TARGET_FRAME_POINTER_REQUIRED visium_frame_pointer_required
331 #undef TARGET_SECONDARY_RELOAD
332 #define TARGET_SECONDARY_RELOAD visium_secondary_reload
334 #undef TARGET_CLASS_LIKELY_SPILLED_P
335 #define TARGET_CLASS_LIKELY_SPILLED_P visium_class_likely_spilled_p
337 #undef TARGET_LEGITIMIZE_ADDRESS
338 #define TARGET_LEGITIMIZE_ADDRESS visium_legitimize_address
340 #undef TARGET_OPTION_OVERRIDE
341 #define TARGET_OPTION_OVERRIDE visium_option_override
343 #undef TARGET_INIT_LIBFUNCS
344 #define TARGET_INIT_LIBFUNCS visium_init_libfuncs
346 #undef TARGET_CONDITIONAL_REGISTER_USAGE
347 #define TARGET_CONDITIONAL_REGISTER_USAGE visium_conditional_register_usage
349 #undef TARGET_TRAMPOLINE_INIT
350 #define TARGET_TRAMPOLINE_INIT visium_trampoline_init
352 #undef TARGET_MD_ASM_ADJUST
353 #define TARGET_MD_ASM_ADJUST visium_md_asm_adjust
355 #undef TARGET_FLAGS_REGNUM
356 #define TARGET_FLAGS_REGNUM FLAGS_REGNUM
358 #undef TARGET_HARD_REGNO_NREGS
359 #define TARGET_HARD_REGNO_NREGS visium_hard_regno_nregs
361 #undef TARGET_HARD_REGNO_MODE_OK
362 #define TARGET_HARD_REGNO_MODE_OK visium_hard_regno_mode_ok
364 #undef TARGET_MODES_TIEABLE_P
365 #define TARGET_MODES_TIEABLE_P visium_modes_tieable_p
367 #undef TARGET_CAN_CHANGE_MODE_CLASS
368 #define TARGET_CAN_CHANGE_MODE_CLASS visium_can_change_mode_class
370 #undef TARGET_CONSTANT_ALIGNMENT
371 #define TARGET_CONSTANT_ALIGNMENT visium_constant_alignment
373 #undef TARGET_HAVE_SPECULATION_SAFE_VALUE
374 #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
376 struct gcc_target targetm = TARGET_INITIALIZER;
378 namespace {
380 const pass_data pass_data_visium_reorg =
382 RTL_PASS, /* type */
383 "mach2", /* name */
384 OPTGROUP_NONE, /* optinfo_flags */
385 TV_MACH_DEP, /* tv_id */
386 0, /* properties_required */
387 0, /* properties_provided */
388 0, /* properties_destroyed */
389 0, /* todo_flags_start */
390 0, /* todo_flags_finish */
393 class pass_visium_reorg : public rtl_opt_pass
395 public:
396 pass_visium_reorg(gcc::context *ctxt)
397 : rtl_opt_pass(pass_data_visium_reorg, ctxt)
400 /* opt_pass methods: */
401 virtual unsigned int execute (function *)
403 return visium_reorg ();
406 }; // class pass_work_around_errata
408 } // anon namespace
410 rtl_opt_pass *
411 make_pass_visium_reorg (gcc::context *ctxt)
413 return new pass_visium_reorg (ctxt);
416 /* Options override for Visium. */
418 static void
419 visium_option_override (void)
421 if (flag_pic == 1)
422 warning (OPT_fpic, "%<-fpic%> is not supported");
423 if (flag_pic == 2)
424 warning (OPT_fPIC, "%<-fPIC%> is not supported");
426 /* MCM is the default in the GR5/GR6 era. */
427 target_flags |= MASK_MCM;
429 /* FPU is the default with MCM, but don't override an explicit option. */
430 if ((target_flags_explicit & MASK_FPU) == 0)
431 target_flags |= MASK_FPU;
433 /* The supervisor mode is the default. */
434 if ((target_flags_explicit & MASK_SV_MODE) == 0)
435 target_flags |= MASK_SV_MODE;
437 /* The GR6 has the Block Move Instructions and an IEEE-compliant FPU. */
438 if (visium_cpu_and_features == PROCESSOR_GR6)
440 target_flags |= MASK_BMI;
441 if (target_flags & MASK_FPU)
442 target_flags |= MASK_FPU_IEEE;
445 /* Set -mtune from -mcpu if not specified. */
446 if (!OPTION_SET_P (visium_cpu))
447 visium_cpu = visium_cpu_and_features;
449 /* Align functions on 256-byte (32-quadword) for GR5 and 64-byte (8-quadword)
450 boundaries for GR6 so they start a new burst mode window. */
451 if (flag_align_functions && !str_align_functions)
453 if (visium_cpu == PROCESSOR_GR6)
454 str_align_functions = "64";
455 else
456 str_align_functions = "256";
458 /* Allow the size of compilation units to double because of inlining.
459 In practice the global size of the object code is hardly affected
460 because the additional instructions will take up the padding. */
461 SET_OPTION_IF_UNSET (&global_options, &global_options_set,
462 param_inline_unit_growth, 100);
465 /* Likewise for loops. */
466 if (flag_align_loops && !str_align_loops)
468 if (visium_cpu == PROCESSOR_GR6)
469 str_align_loops = "64";
470 else
472 /* But not if they are too far away from a 256-byte boundary. */
473 str_align_loops = "256:32:8";
477 /* Align all jumps on quadword boundaries for the burst mode, and even
478 on 8-quadword boundaries for GR6 so they start a new window. */
479 if (flag_align_jumps && !str_align_jumps)
481 if (visium_cpu == PROCESSOR_GR6)
482 str_align_jumps = "64";
483 else
484 str_align_jumps = "8";
488 /* Register the Visium-specific libfuncs with the middle-end. */
490 static void
491 visium_init_libfuncs (void)
493 if (!TARGET_BMI)
494 long_int_memcpy_libfunc = init_one_libfunc ("__long_int_memcpy");
495 wrd_memcpy_libfunc = init_one_libfunc ("__wrd_memcpy");
496 byt_memcpy_libfunc = init_one_libfunc ("__byt_memcpy");
498 long_int_memset_libfunc = init_one_libfunc ("__long_int_memset");
499 wrd_memset_libfunc = init_one_libfunc ("__wrd_memset");
500 byt_memset_libfunc = init_one_libfunc ("__byt_memset");
502 set_trampoline_parity_libfunc = init_one_libfunc ("__set_trampoline_parity");
505 /* Return the number of instructions that can issue on the same cycle. */
507 static int
508 visium_issue_rate (void)
510 switch (visium_cpu)
512 case PROCESSOR_GR5:
513 return 1;
515 case PROCESSOR_GR6:
516 return 2;
518 default:
519 gcc_unreachable ();
523 /* Return the adjusted PRIORITY of INSN. */
525 static int
526 visium_adjust_priority (rtx_insn *insn, int priority)
528 /* On the GR5, we slightly increase the priority of writes in order to avoid
529 scheduling a read on the next cycle. This is necessary in addition to the
530 associated insn reservation because there are no data dependencies.
531 We also slightly increase the priority of reads from ROM in order to group
532 them as much as possible. These reads are a bit problematic because they
533 conflict with the instruction fetches, i.e. the data and instruction buses
534 tread on each other's toes when they are executed. */
535 if (visium_cpu == PROCESSOR_GR5
536 && reload_completed
537 && INSN_P (insn)
538 && recog_memoized (insn) >= 0)
540 enum attr_type attr_type = get_attr_type (insn);
541 if (attr_type == TYPE_REG_MEM
542 || (attr_type == TYPE_MEM_REG
543 && MEM_READONLY_P (SET_SRC (PATTERN (insn)))))
544 return priority + 1;
547 return priority;
550 /* Adjust the cost of a scheduling dependency. Return the new cost of
551 a dependency LINK of INSN on DEP_INSN. COST is the current cost. */
553 static int
554 visium_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost,
555 unsigned int)
557 enum attr_type attr_type;
559 /* Don't adjust costs for true dependencies as they are described with
560 bypasses. But we make an exception for the first scheduling pass to
561 help the subsequent postreload compare elimination pass. */
562 if (dep_type == REG_DEP_TRUE)
564 if (!reload_completed
565 && recog_memoized (insn) >= 0
566 && get_attr_type (insn) == TYPE_CMP)
568 rtx pat = PATTERN (insn);
569 gcc_assert (GET_CODE (pat) == SET);
570 rtx src = SET_SRC (pat);
572 /* Only the branches can be modified by the postreload compare
573 elimination pass, not the cstores because they accept only
574 unsigned comparison operators and they are eliminated if
575 one of the operands is zero. */
576 if (GET_CODE (src) == IF_THEN_ELSE
577 && XEXP (XEXP (src, 0), 1) == const0_rtx
578 && recog_memoized (dep_insn) >= 0)
580 enum attr_type dep_attr_type = get_attr_type (dep_insn);
582 /* The logical instructions use CCmode and thus work with any
583 comparison operator, whereas the arithmetic instructions use
584 CCNZmode and thus work with only a small subset. */
585 if (dep_attr_type == TYPE_LOGIC
586 || (dep_attr_type == TYPE_ARITH
587 && visium_nz_comparison_operator (XEXP (src, 0),
588 GET_MODE
589 (XEXP (src, 0)))))
590 return 0;
594 return cost;
597 if (recog_memoized (insn) < 0)
598 return 0;
600 attr_type = get_attr_type (insn);
602 /* Anti dependency: DEP_INSN reads a register that INSN writes some
603 cycles later. */
604 if (dep_type == REG_DEP_ANTI)
606 /* On the GR5, the latency of FP instructions needs to be taken into
607 account for every dependency involving a write. */
608 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
610 /* INSN is FLOAD. */
611 rtx pat = PATTERN (insn);
612 rtx dep_pat = PATTERN (dep_insn);
614 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
615 /* If this happens, we have to extend this to schedule
616 optimally. Return 0 for now. */
617 return 0;
619 if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
621 if (recog_memoized (dep_insn) < 0)
622 return 0;
624 switch (get_attr_type (dep_insn))
626 case TYPE_FDIV:
627 case TYPE_FSQRT:
628 case TYPE_FTOI:
629 case TYPE_ITOF:
630 case TYPE_FP:
631 case TYPE_FMOVE:
632 /* A fload can't be issued until a preceding arithmetic
633 operation has finished if the target of the fload is
634 any of the sources (or destination) of the arithmetic
635 operation. Note that the latency may be (much)
636 greater than this if the preceding instruction
637 concerned is in a queue. */
638 return insn_default_latency (dep_insn);
640 default:
641 return 0;
646 /* On the GR6, we try to make sure that the link register is restored
647 sufficiently ahead of the return as to yield a correct prediction
648 from the branch predictor. By default there is no true dependency
649 but an anti dependency between them, so we simply reuse it. */
650 else if (attr_type == TYPE_RET && visium_cpu == PROCESSOR_GR6)
652 rtx dep_pat = PATTERN (dep_insn);
653 if (GET_CODE (dep_pat) == SET
654 && REG_P (SET_DEST (dep_pat))
655 && REGNO (SET_DEST (dep_pat)) == LINK_REGNUM)
656 return 8;
659 /* For other anti dependencies, the cost is 0. */
660 return 0;
663 /* Output dependency: DEP_INSN writes a register that INSN writes some
664 cycles later. */
665 else if (dep_type == REG_DEP_OUTPUT)
667 /* On the GR5, the latency of FP instructions needs to be taken into
668 account for every dependency involving a write. */
669 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
671 /* INSN is FLOAD. */
672 rtx pat = PATTERN (insn);
673 rtx dep_pat = PATTERN (dep_insn);
675 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
676 /* If this happens, we have to extend this to schedule
677 optimally. Return 0 for now. */
678 return 0;
680 if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat)))
682 if (recog_memoized (dep_insn) < 0)
683 return 0;
685 switch (get_attr_type (dep_insn))
687 case TYPE_FDIV:
688 case TYPE_FSQRT:
689 case TYPE_FTOI:
690 case TYPE_ITOF:
691 case TYPE_FP:
692 case TYPE_FMOVE:
693 /* A fload can't be issued until a preceding arithmetic
694 operation has finished if the target of the fload is
695 the destination of the arithmetic operation. Note that
696 the latency may be (much) greater than this if the
697 preceding instruction concerned is in a queue. */
698 return insn_default_latency (dep_insn);
700 default:
701 return 0;
706 /* For other output dependencies, the cost is 0. */
707 return 0;
710 return 0;
713 /* Handle an "interrupt_handler" attribute; arguments as in
714 struct attribute_spec.handler. */
716 static tree
717 visium_handle_interrupt_attr (tree *node, tree name,
718 tree args ATTRIBUTE_UNUSED,
719 int flags ATTRIBUTE_UNUSED,
720 bool *no_add_attrs)
722 if (TREE_CODE (*node) != FUNCTION_DECL)
724 warning (OPT_Wattributes, "%qE attribute only applies to functions",
725 name);
726 *no_add_attrs = true;
728 else if (!TARGET_SV_MODE)
730 error ("an interrupt handler cannot be compiled with %<-muser-mode%>");
731 *no_add_attrs = true;
734 return NULL_TREE;
737 /* Return non-zero if the current function is an interrupt function. */
740 visium_interrupt_function_p (void)
742 return
743 lookup_attribute ("interrupt",
744 DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
747 /* Conditionally modify the settings of the register file. */
749 static void
750 visium_conditional_register_usage (void)
752 /* If the supervisor mode is disabled, mask some general registers. */
753 if (!TARGET_SV_MODE)
755 if (visium_cpu_and_features == PROCESSOR_GR5)
757 fixed_regs[24] = 1;
758 fixed_regs[25] = 1;
759 fixed_regs[26] = 1;
760 fixed_regs[27] = 1;
761 fixed_regs[28] = 1;
762 call_used_regs[24] = 0;
763 call_used_regs[25] = 0;
764 call_used_regs[26] = 0;
765 call_used_regs[27] = 0;
766 call_used_regs[28] = 0;
769 fixed_regs[31] = 1;
770 call_used_regs[31] = 0;
772 /* We also need to change the long-branch register. */
773 if (visium_cpu_and_features == PROCESSOR_GR5)
774 long_branch_regnum = 20;
775 else
776 long_branch_regnum = 28;
779 /* If the FPU is disabled, mask the FP registers. */
780 if (!TARGET_FPU)
782 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
784 fixed_regs[i] = 1;
785 call_used_regs[i] = 0;
790 /* Prepend to CLOBBERS hard registers that are automatically clobbered for
791 an asm We do this for the FLAGS to maintain source compatibility with
792 the original cc0-based compiler. */
794 static rtx_insn *
795 visium_md_asm_adjust (vec<rtx> & /*outputs*/, vec<rtx> & /*inputs*/,
796 vec<machine_mode> & /*input_modes*/,
797 vec<const char *> & /*constraints*/, vec<rtx> &clobbers,
798 HARD_REG_SET &clobbered_regs, location_t /*loc*/)
800 clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REGNUM));
801 SET_HARD_REG_BIT (clobbered_regs, FLAGS_REGNUM);
802 return NULL;
805 /* Return true if X is a legitimate constant for a MODE immediate operand.
806 X is guaranteed to satisfy the CONSTANT_P predicate. */
808 static bool
809 visium_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED,
810 rtx x ATTRIBUTE_UNUSED)
812 return true;
815 /* Compute the alignment for a variable. The alignment of an aggregate is
816 set to be at least that of a scalar less than or equal to it in size. */
818 unsigned int
819 visium_data_alignment (tree type, unsigned int align)
821 if (AGGREGATE_TYPE_P (type)
822 && TYPE_SIZE (type)
823 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && align < 32)
825 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 32)
826 return 32;
828 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 && align < 16)
829 return 16;
832 return align;
835 /* Implement TARGET_CONSTANT_ALIGNMENT. */
837 static HOST_WIDE_INT
838 visium_constant_alignment (const_tree exp, HOST_WIDE_INT align)
840 return visium_data_alignment (TREE_TYPE (exp), align);
843 /* Helper function for HARD_REGNO_RENAME_OK (FROM, TO). Return non-zero if
844 it is OK to rename a hard register FROM to another hard register TO. */
847 visium_hard_regno_rename_ok (unsigned int from ATTRIBUTE_UNUSED,
848 unsigned int to)
850 /* If the function doesn't save LR, then the long-branch register will be
851 used for long branches so we need to know whether it is live before the
852 frame layout is computed. */
853 if (!current_function_saves_lr () && to == long_branch_regnum)
854 return 0;
856 /* Interrupt functions can only use registers that have already been
857 saved by the prologue, even if they would normally be call-clobbered. */
858 if (crtl->is_leaf
859 && !df_regs_ever_live_p (to)
860 && visium_interrupt_function_p ())
861 return 0;
863 return 1;
866 /* Implement TARGET_HARD_REGNO_NREGS. */
868 static unsigned int
869 visium_hard_regno_nregs (unsigned int regno, machine_mode mode)
871 if (regno == MDB_REGNUM)
872 return CEIL (GET_MODE_SIZE (mode), 2 * UNITS_PER_WORD);
873 return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
876 /* Implement TARGET_HARD_REGNO_MODE_OK.
878 Modes with sizes which cross from the one register class to the
879 other cannot be allowed. Only single floats are allowed in the
880 floating point registers, and only fixed point values in the EAM
881 registers. */
883 static bool
884 visium_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
886 if (GP_REGISTER_P (regno))
887 return GP_REGISTER_P (end_hard_regno (mode, regno) - 1);
889 if (FP_REGISTER_P (regno))
890 return mode == SFmode || (mode == SImode && TARGET_FPU_IEEE);
892 return (GET_MODE_CLASS (mode) == MODE_INT
893 && visium_hard_regno_nregs (regno, mode) == 1);
896 /* Implement TARGET_MODES_TIEABLE_P. */
898 static bool
899 visium_modes_tieable_p (machine_mode mode1, machine_mode mode2)
901 return (GET_MODE_CLASS (mode1) == MODE_INT
902 && GET_MODE_CLASS (mode2) == MODE_INT);
905 /* Return true if it is ok to do sibling call optimization for the specified
906 call expression EXP. DECL will be the called function, or NULL if this
907 is an indirect call. */
909 static bool
910 visium_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
911 tree exp ATTRIBUTE_UNUSED)
913 return !visium_interrupt_function_p ();
916 /* Prepare operands for a move define_expand in MODE. */
918 void
919 prepare_move_operands (rtx *operands, machine_mode mode)
921 /* If the output is not a register, the input must be. */
922 if (GET_CODE (operands[0]) == MEM && !reg_or_0_operand (operands[1], mode))
923 operands[1] = force_reg (mode, operands[1]);
926 /* Return true if the operands are valid for a simple move insn. */
928 bool
929 ok_for_simple_move_operands (rtx *operands, machine_mode mode)
931 /* One of the operands must be a register. */
932 if (!register_operand (operands[0], mode)
933 && !reg_or_0_operand (operands[1], mode))
934 return false;
936 /* Once the flags are exposed, no simple moves between integer registers. */
937 if (visium_flags_exposed
938 && gpc_reg_operand (operands[0], mode)
939 && gpc_reg_operand (operands[1], mode))
940 return false;
942 return true;
945 /* Return true if the operands are valid for a simple move strict insn. */
947 bool
948 ok_for_simple_move_strict_operands (rtx *operands, machine_mode mode)
950 /* Once the flags are exposed, no simple moves between integer registers.
951 Note that, in QImode only, a zero source counts as an integer register
952 since it will be emitted as r0. */
953 if (visium_flags_exposed
954 && gpc_reg_operand (operands[0], mode)
955 && (gpc_reg_operand (operands[1], mode)
956 || (mode == QImode && operands[1] == const0_rtx)))
957 return false;
959 return true;
962 /* Return true if the operands are valid for a simple arithmetic or logical
963 insn. */
965 bool
966 ok_for_simple_arith_logic_operands (rtx *, machine_mode)
968 /* Once the flags are exposed, no simple arithmetic or logical operations
969 between integer registers. */
970 return !visium_flags_exposed;
973 /* Return non-zero if a branch or call instruction will be emitting a nop
974 into its delay slot. */
977 empty_delay_slot (rtx_insn *insn)
979 rtx seq;
981 /* If no previous instruction (should not happen), return true. */
982 if (PREV_INSN (insn) == NULL)
983 return 1;
985 seq = NEXT_INSN (PREV_INSN (insn));
986 if (GET_CODE (PATTERN (seq)) == SEQUENCE)
987 return 0;
989 return 1;
992 /* Wrapper around single_set which returns the second SET of a pair if the
993 first SET is to the flags register. */
995 static rtx
996 single_set_and_flags (rtx_insn *insn)
998 if (multiple_sets (insn))
1000 rtx pat = PATTERN (insn);
1001 if (XVECLEN (pat, 0) == 2
1002 && GET_CODE (XVECEXP (pat, 0, 0)) == SET
1003 && REG_P (SET_DEST (XVECEXP (pat, 0, 0)))
1004 && REGNO (SET_DEST (XVECEXP (pat, 0, 0))) == FLAGS_REGNUM)
1005 return XVECEXP (pat, 0, 1);
1008 return single_set (insn);
1011 /* This is called with OUT_INSN an instruction setting a (base) register
1012 and IN_INSN a read or a write. Return 1 if these instructions together
1013 constitute a pipeline hazard.
1015 On the original architecture, a pipeline data hazard occurs when the Dest
1016 of one instruction becomes the SrcA for an immediately following READ or
1017 WRITE instruction with a non-zero index (indexing occurs at the decode
1018 stage and so a NOP must be inserted in-between for this to work).
1020 An example is:
1022 move.l r2,r1
1023 read.l r4,10(r2)
1025 On the MCM, the non-zero index condition is lifted but the hazard is
1026 patched up by the hardware through the injection of wait states:
1028 move.l r2,r1
1029 read.l r4,(r2)
1031 We nevertheless try to schedule instructions around this. */
1034 gr5_hazard_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
1036 rtx out_set, in_set, dest, memexpr;
1037 unsigned int out_reg, in_reg;
1039 /* A CALL is storage register class, but the link register is of no
1040 interest here. */
1041 if (GET_CODE (out_insn) == CALL_INSN)
1042 return 0;
1044 out_set = single_set_and_flags (out_insn);
1045 dest = SET_DEST (out_set);
1047 /* Should be no stall/hazard if OUT_INSN is MEM := ???. This only
1048 occurs prior to reload. */
1049 if (GET_CODE (dest) == MEM)
1050 return 0;
1052 if (GET_CODE (dest) == STRICT_LOW_PART)
1053 dest = XEXP (dest, 0);
1054 if (GET_CODE (dest) == SUBREG)
1055 dest = SUBREG_REG (dest);
1056 out_reg = REGNO (dest);
1058 in_set = single_set_and_flags (in_insn);
1060 /* If IN_INSN is MEM := MEM, it's the source that counts. */
1061 if (GET_CODE (SET_SRC (in_set)) == MEM)
1062 memexpr = XEXP (SET_SRC (in_set), 0);
1063 else
1064 memexpr = XEXP (SET_DEST (in_set), 0);
1066 if (GET_CODE (memexpr) == PLUS)
1068 memexpr = XEXP (memexpr, 0);
1069 if (GET_CODE (memexpr) == SUBREG)
1070 in_reg = REGNO (SUBREG_REG (memexpr));
1071 else
1072 in_reg = REGNO (memexpr);
1074 if (in_reg == out_reg)
1075 return 1;
1077 else if (TARGET_MCM)
1079 if (GET_CODE (memexpr) == STRICT_LOW_PART)
1080 memexpr = XEXP (memexpr, 0);
1081 if (GET_CODE (memexpr) == SUBREG)
1082 memexpr = SUBREG_REG (memexpr);
1083 in_reg = REGNO (memexpr);
1085 if (in_reg == out_reg)
1086 return 1;
1089 return 0;
1092 /* Return true if INSN is an empty asm instruction. */
1094 static bool
1095 empty_asm_p (rtx insn)
1097 rtx body = PATTERN (insn);
1098 const char *templ;
1100 if (GET_CODE (body) == ASM_INPUT)
1101 templ = XSTR (body, 0);
1102 else if (asm_noperands (body) >= 0)
1103 templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
1104 else
1105 templ = NULL;
1107 return (templ && templ[0] == '\0');
1110 /* Insert a NOP immediately before INSN wherever there is a pipeline hazard.
1111 LAST_REG records the register set in the last insn and LAST_INSN_CALL
1112 records whether the last insn was a call insn. */
1114 static void
1115 gr5_avoid_hazard (rtx_insn *insn, unsigned int *last_reg, bool *last_insn_call)
1117 unsigned int dest_reg = 0;
1118 rtx set;
1120 switch (GET_CODE (insn))
1122 case CALL_INSN:
1123 *last_reg = 0;
1124 *last_insn_call = true;
1125 return;
1127 case JUMP_INSN:
1128 /* If this is an empty asm, just skip it. */
1129 if (!empty_asm_p (insn))
1131 *last_reg = 0;
1132 *last_insn_call = false;
1134 return;
1136 case INSN:
1137 /* If this is an empty asm, just skip it. */
1138 if (empty_asm_p (insn))
1139 return;
1140 break;
1142 default:
1143 return;
1146 set = single_set_and_flags (insn);
1147 if (set != NULL_RTX)
1149 rtx dest = SET_DEST (set);
1150 const bool double_p = GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD;
1151 rtx memrtx = NULL;
1153 if (GET_CODE (SET_SRC (set)) == MEM)
1155 memrtx = XEXP (SET_SRC (set), 0);
1156 if (GET_CODE (dest) == STRICT_LOW_PART)
1157 dest = XEXP (dest, 0);
1158 if (REG_P (dest))
1159 dest_reg = REGNO (dest);
1161 /* If this is a DI or DF mode memory to register
1162 copy, then if rd = rs we get
1164 rs + 1 := 1[rs]
1165 rs := [rs]
1167 otherwise the order is
1169 rd := [rs]
1170 rd + 1 := 1[rs] */
1172 if (double_p)
1174 unsigned int base_reg;
1176 if (GET_CODE (memrtx) == PLUS)
1177 base_reg = REGNO (XEXP (memrtx, 0));
1178 else
1179 base_reg = REGNO (memrtx);
1181 if (dest_reg != base_reg)
1182 dest_reg++;
1186 else if (GET_CODE (dest) == MEM)
1187 memrtx = XEXP (dest, 0);
1189 else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC)
1191 if (GET_CODE (dest) == STRICT_LOW_PART
1192 ||GET_CODE (dest) == ZERO_EXTRACT)
1193 dest = XEXP (dest, 0);
1194 dest_reg = REGNO (dest);
1196 if (GET_CODE (SET_SRC (set)) == REG)
1198 unsigned int srcreg = REGNO (SET_SRC (set));
1200 /* Check for rs := rs, which will be deleted. */
1201 if (srcreg == dest_reg)
1202 return;
1204 /* In the case of a DI or DF mode move from register to
1205 register there is overlap if rd = rs + 1 in which case
1206 the order of the copies is reversed :
1208 rd + 1 := rs + 1;
1209 rd := rs */
1211 if (double_p && dest_reg != srcreg + 1)
1212 dest_reg++;
1216 /* If this is the delay slot of a call insn, any register it sets
1217 is not relevant. */
1218 if (*last_insn_call)
1219 dest_reg = 0;
1221 /* If the previous insn sets the value of a register, and this insn
1222 uses a base register, check for the pipeline hazard where it is
1223 the same register in each case. */
1224 if (*last_reg != 0 && memrtx != NULL_RTX)
1226 unsigned int reg = 0;
1228 /* Check for an index (original architecture). */
1229 if (GET_CODE (memrtx) == PLUS)
1230 reg = REGNO (XEXP (memrtx, 0));
1232 /* Check for an MCM target or rs := [rs], in DI or DF mode. */
1233 else if (TARGET_MCM || (double_p && REGNO (memrtx) == dest_reg))
1234 reg = REGNO (memrtx);
1236 /* Remove any pipeline hazard by inserting a NOP. */
1237 if (reg == *last_reg)
1239 if (dump_file)
1240 fprintf (dump_file,
1241 "inserting nop before insn %d\n", INSN_UID (insn));
1242 emit_insn_after (gen_hazard_nop (), prev_active_insn (insn));
1243 emit_insn_after (gen_blockage (), insn);
1247 *last_reg = dest_reg;
1250 *last_insn_call = false;
1253 /* Go through the instruction stream and insert nops where necessary to avoid
1254 pipeline hazards. There are two cases:
1256 1. On the original architecture, it is invalid to set the value of a
1257 (base) register and then use it in an address with a non-zero index
1258 in the next instruction.
1260 2. On the MCM, setting the value of a (base) register and then using
1261 it in address (including with zero index) in the next instruction
1262 will result in a pipeline stall of 3 cycles. */
1264 static void
1265 gr5_hazard_avoidance (void)
1267 unsigned int last_reg = 0;
1268 bool last_insn_call = false;
1269 rtx_insn *insn;
1271 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1272 if (INSN_P (insn))
1274 rtx pat = PATTERN (insn);
1276 if (GET_CODE (pat) == SEQUENCE)
1278 for (int i = 0; i < XVECLEN (pat, 0); i++)
1279 gr5_avoid_hazard (as_a <rtx_insn *> (XVECEXP (pat, 0, i)),
1280 &last_reg, &last_insn_call);
1283 else if (GET_CODE (insn) == CALL_INSN)
1285 /* This call is going to get a nop in its delay slot. */
1286 last_reg = 0;
1287 last_insn_call = false;
1290 else
1291 gr5_avoid_hazard (insn, &last_reg, &last_insn_call);
1294 else if (GET_CODE (insn) == BARRIER)
1295 last_reg = 0;
1298 /* Perform a target-specific pass over the instruction stream. The compiler
1299 will run it at all optimization levels, just after the point at which it
1300 normally does delayed-branch scheduling. */
1302 static unsigned int
1303 visium_reorg (void)
1305 if (visium_cpu == PROCESSOR_GR5)
1306 gr5_hazard_avoidance ();
1308 return 0;
1310 /* Return true if an argument must be passed by indirect reference. */
1312 static bool
1313 visium_pass_by_reference (cumulative_args_t, const function_arg_info &arg)
1315 tree type = arg.type;
1316 return type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1319 /* Define how arguments are passed.
1321 A range of general registers and floating registers is available
1322 for passing arguments. When the class of registers which an
1323 argument would normally use is exhausted, that argument, is passed
1324 in the overflow region of the stack. No argument is split between
1325 registers and stack.
1327 Arguments of type float or _Complex float go in FP registers if FP
1328 hardware is available. If there is no FP hardware, arguments of
1329 type float go in general registers. All other arguments are passed
1330 in general registers. */
1332 static rtx
1333 visium_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
1335 int size;
1336 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1338 size = (GET_MODE_SIZE (arg.mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1339 if (arg.end_marker_p ())
1340 return GEN_INT (0);
1342 /* Scalar or complex single precision floating point arguments are returned
1343 in floating registers. */
1344 if (TARGET_FPU
1345 && ((GET_MODE_CLASS (arg.mode) == MODE_FLOAT
1346 && GET_MODE_SIZE (arg.mode) <= UNITS_PER_HWFPVALUE)
1347 || (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT
1348 && GET_MODE_SIZE (arg.mode) <= UNITS_PER_HWFPVALUE * 2)))
1350 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1351 return gen_rtx_REG (arg.mode, FP_ARG_FIRST + ca->frcount);
1352 else
1353 return NULL_RTX;
1356 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1357 return gen_rtx_REG (arg.mode, ca->grcount + GP_ARG_FIRST);
1359 return NULL_RTX;
1362 /* Update the summarizer variable pointed to by PCUM_V to advance past
1363 argument ARG. Once this is done, the variable CUM is suitable for
1364 analyzing the _following_ argument with visium_function_arg. */
1366 static void
1367 visium_function_arg_advance (cumulative_args_t pcum_v,
1368 const function_arg_info &arg)
1370 int size = (GET_MODE_SIZE (arg.mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1371 int stack_size = 0;
1372 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1374 /* Scalar or complex single precision floating point arguments are returned
1375 in floating registers. */
1376 if (TARGET_FPU
1377 && ((GET_MODE_CLASS (arg.mode) == MODE_FLOAT
1378 && GET_MODE_SIZE (arg.mode) <= UNITS_PER_HWFPVALUE)
1379 || (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT
1380 && GET_MODE_SIZE (arg.mode) <= UNITS_PER_HWFPVALUE * 2)))
1382 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1383 ca->frcount += size;
1384 else
1386 stack_size = size;
1387 ca->frcount = MAX_ARGS_IN_FP_REGISTERS;
1390 else
1392 /* Everything else goes in a general register, if enough are
1393 available. */
1394 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1395 ca->grcount += size;
1396 else
1398 stack_size = size;
1399 ca->grcount = MAX_ARGS_IN_GP_REGISTERS;
1403 if (arg.named)
1404 ca->stack_words += stack_size;
1407 /* Specify whether to return the return value in memory. */
1409 static bool
1410 visium_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1412 return (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1415 /* Define how scalar values are returned. */
1417 static rtx
1418 visium_function_value_1 (machine_mode mode)
1420 /* Scalar or complex single precision floating point values
1421 are returned in floating register f1. */
1422 if (TARGET_FPU
1423 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1424 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1425 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1426 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1427 return gen_rtx_REG (mode, FP_RETURN_REGNUM);
1429 /* All others are returned in r1. */
1430 return gen_rtx_REG (mode, RETURN_REGNUM);
1433 /* Return an RTX representing the place where a function returns or receives
1434 a value of data type RET_TYPE. */
1436 static rtx
1437 visium_function_value (const_tree ret_type,
1438 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1439 bool outgoing ATTRIBUTE_UNUSED)
1441 return visium_function_value_1 (TYPE_MODE (ret_type));
1444 /* Return an RTX representing the place where the library function result will
1445 be returned. */
1447 static rtx
1448 visium_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1450 return visium_function_value_1 (mode);
1453 /* Store the anonymous register arguments into the stack so that all the
1454 arguments appear to have been passed consecutively on the stack. */
1456 static void
1457 visium_setup_incoming_varargs (cumulative_args_t pcum_v,
1458 const function_arg_info &arg,
1459 int *pretend_size ATTRIBUTE_UNUSED,
1460 int no_rtl)
1462 cumulative_args_t local_args_so_far;
1463 CUMULATIVE_ARGS local_copy;
1464 CUMULATIVE_ARGS *locargs;
1465 int gp_saved, fp_saved, size;
1467 /* Create an internal cumulative_args_t pointer to internally define
1468 storage to ensure calling TARGET_FUNCTION_ARG_ADVANCE does not
1469 make global changes. */
1470 local_args_so_far.p = &local_copy;
1471 locargs = get_cumulative_args (pcum_v);
1473 #if CHECKING_P
1474 local_args_so_far.magic = CUMULATIVE_ARGS_MAGIC;
1475 #endif
1477 local_copy.grcount = locargs->grcount;
1478 local_copy.frcount = locargs->frcount;
1479 local_copy.stack_words = locargs->stack_words;
1481 /* The caller has advanced ARGS_SO_FAR up to, but not beyond, the last named
1482 argument. Advance a local copy of ARGS_SO_FAR past the last "real" named
1483 argument, to find out how many registers are left over. */
1484 if (!TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (current_function_decl)))
1485 TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, arg);
1487 /* Find how many registers we need to save. */
1488 locargs = get_cumulative_args (local_args_so_far);
1489 gp_saved = MAX_ARGS_IN_GP_REGISTERS - locargs->grcount;
1490 fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - locargs->frcount : 0);
1491 size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_HWFPVALUE);
1493 if (!no_rtl && size > 0)
1495 /* To avoid negative offsets, which are not valid addressing modes on
1496 the Visium, we create a base register for the pretend args. */
1497 rtx ptr
1498 = force_reg (Pmode,
1499 plus_constant (Pmode, virtual_incoming_args_rtx, -size));
1501 if (gp_saved > 0)
1503 rtx mem
1504 = gen_rtx_MEM (BLKmode,
1505 plus_constant (Pmode,
1506 ptr,
1507 fp_saved * UNITS_PER_HWFPVALUE));
1508 MEM_NOTRAP_P (mem) = 1;
1509 set_mem_alias_set (mem, get_varargs_alias_set ());
1510 move_block_from_reg (locargs->grcount + GP_ARG_FIRST, mem, gp_saved);
1513 if (fp_saved > 0)
1515 rtx mem = gen_rtx_MEM (BLKmode, ptr);
1516 MEM_NOTRAP_P (mem) = 1;
1517 set_mem_alias_set (mem, get_varargs_alias_set ());
1518 gcc_assert (UNITS_PER_WORD == UNITS_PER_HWFPVALUE);
1519 move_block_from_reg (locargs->frcount + FP_ARG_FIRST, mem, fp_saved);
1523 visium_reg_parm_save_area_size = size;
1526 /* Define the `__builtin_va_list' type for the ABI. */
1528 static tree
1529 visium_build_builtin_va_list (void)
1531 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes, record;
1533 record = (*lang_hooks.types.make_type) (RECORD_TYPE);
1534 f_ovfl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1535 get_identifier ("__overflow_argptr"), ptr_type_node);
1536 f_gbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1537 get_identifier ("__gpr_base"), ptr_type_node);
1538 f_fbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1539 get_identifier ("__fpr_base"), ptr_type_node);
1540 f_gbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1541 get_identifier ("__gpr_bytes"),
1542 short_unsigned_type_node);
1543 f_fbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1544 get_identifier ("__fpr_bytes"),
1545 short_unsigned_type_node);
1547 DECL_FIELD_CONTEXT (f_ovfl) = record;
1548 DECL_FIELD_CONTEXT (f_gbase) = record;
1549 DECL_FIELD_CONTEXT (f_fbase) = record;
1550 DECL_FIELD_CONTEXT (f_gbytes) = record;
1551 DECL_FIELD_CONTEXT (f_fbytes) = record;
1552 TYPE_FIELDS (record) = f_ovfl;
1553 TREE_CHAIN (f_ovfl) = f_gbase;
1554 TREE_CHAIN (f_gbase) = f_fbase;
1555 TREE_CHAIN (f_fbase) = f_gbytes;
1556 TREE_CHAIN (f_gbytes) = f_fbytes;
1557 layout_type (record);
1559 return record;
1562 /* Implement `va_start' for varargs and stdarg. */
1564 static void
1565 visium_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
1567 const CUMULATIVE_ARGS *ca = &crtl->args.info;
1568 int gp_saved = MAX_ARGS_IN_GP_REGISTERS - ca->grcount;
1569 int fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - ca->frcount : 0);
1570 int named_stack_size = ca->stack_words * UNITS_PER_WORD, offset;
1571 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1572 tree ovfl, gbase, gbytes, fbase, fbytes, t;
1574 f_ovfl = TYPE_FIELDS (va_list_type_node);
1575 f_gbase = TREE_CHAIN (f_ovfl);
1576 f_fbase = TREE_CHAIN (f_gbase);
1577 f_gbytes = TREE_CHAIN (f_fbase);
1578 f_fbytes = TREE_CHAIN (f_gbytes);
1579 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1580 gbase = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1581 NULL_TREE);
1582 fbase = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1583 NULL_TREE);
1584 gbytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), valist, f_gbytes,
1585 NULL_TREE);
1586 fbytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), valist, f_fbytes,
1587 NULL_TREE);
1589 /* Store the stacked vararg pointer in the OVFL member. */
1590 t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
1591 t = fold_build_pointer_plus_hwi (t, named_stack_size);
1592 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
1593 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1595 /* Store the base address of the GPR save area into GBASE. */
1596 t = make_tree (TREE_TYPE (gbase), virtual_incoming_args_rtx);
1597 offset = MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD;
1598 t = fold_build_pointer_plus_hwi (t, -offset);
1599 t = build2 (MODIFY_EXPR, TREE_TYPE (gbase), gbase, t);
1600 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1602 /* Store the base address of the FPR save area into FBASE. */
1603 if (fp_saved)
1605 t = make_tree (TREE_TYPE (fbase), virtual_incoming_args_rtx);
1606 offset = gp_saved * UNITS_PER_WORD
1607 + MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE;
1608 t = fold_build_pointer_plus_hwi (t, -offset);
1609 t = build2 (MODIFY_EXPR, TREE_TYPE (fbase), fbase, t);
1610 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1613 /* Fill in the GBYTES member. */
1614 t = build2 (MODIFY_EXPR, TREE_TYPE (gbytes), gbytes,
1615 size_int (gp_saved * UNITS_PER_WORD));
1616 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1618 /* Fill in the FBYTES member. */
1619 t = build2 (MODIFY_EXPR, TREE_TYPE (fbytes),
1620 fbytes, size_int (fp_saved * UNITS_PER_HWFPVALUE));
1621 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1624 /* Implement `va_arg'. */
1626 static tree
1627 visium_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
1628 gimple_seq *post_p)
1630 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1631 tree ovfl, base, bytes;
1632 HOST_WIDE_INT size, rsize;
1633 const bool by_reference_p = pass_va_arg_by_reference (type);
1634 const bool float_reg_arg_p
1635 = (TARGET_FPU && !by_reference_p
1636 && ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
1637 && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_HWFPVALUE)
1638 || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT
1639 && (GET_MODE_SIZE (TYPE_MODE (type))
1640 <= UNITS_PER_HWFPVALUE * 2))));
1641 const int max_save_area_size
1642 = (float_reg_arg_p ? MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE
1643 : MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD);
1644 tree t, u, offs;
1645 tree lab_false, lab_over, addr;
1646 tree ptrtype = build_pointer_type (type);
1648 if (by_reference_p)
1650 t = visium_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
1651 return build_va_arg_indirect_ref (t);
1654 size = int_size_in_bytes (type);
1655 rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
1656 f_ovfl = TYPE_FIELDS (va_list_type_node);
1657 f_gbase = TREE_CHAIN (f_ovfl);
1658 f_fbase = TREE_CHAIN (f_gbase);
1659 f_gbytes = TREE_CHAIN (f_fbase);
1660 f_fbytes = TREE_CHAIN (f_gbytes);
1662 /* We maintain separate pointers and offsets for floating-point and
1663 general registers, but we need similar code in both cases.
1665 Let:
1667 BYTES be the number of unused bytes in the register save area.
1668 BASE be the base address of the register save area.
1669 OFFS be the current offset into the register save area. Either
1670 MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD - bytes or
1671 MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE - bytes
1672 depending upon whether the argument is in general or floating
1673 registers.
1674 ADDR_RTX be the address of the argument.
1675 RSIZE be the size in bytes of the argument.
1676 OVFL be the pointer to the stack overflow area.
1678 The code we want is:
1680 1: if (bytes >= rsize)
1681 2: {
1682 3: addr_rtx = base + offs;
1683 4: bytes -= rsize;
1684 5: }
1685 6: else
1686 7: {
1687 8: bytes = 0;
1688 9: addr_rtx = ovfl;
1689 10: ovfl += rsize;
1690 11: }
1694 addr = create_tmp_var (ptr_type_node, "addr");
1695 lab_false = create_artificial_label (UNKNOWN_LOCATION);
1696 lab_over = create_artificial_label (UNKNOWN_LOCATION);
1697 if (float_reg_arg_p)
1698 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), unshare_expr (valist),
1699 f_fbytes, NULL_TREE);
1700 else
1701 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), unshare_expr (valist),
1702 f_gbytes, NULL_TREE);
1704 /* [1] Emit code to branch if bytes < rsize. */
1705 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1706 t = build2 (LT_EXPR, boolean_type_node, bytes, t);
1707 u = build1 (GOTO_EXPR, void_type_node, lab_false);
1708 t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
1709 gimplify_and_add (t, pre_p);
1711 /* [3] Emit code for: addr_rtx = base + offs, where
1712 offs = max_save_area_size - bytes. */
1713 t = fold_convert (sizetype, bytes);
1714 offs = build2 (MINUS_EXPR, sizetype, size_int (max_save_area_size), t);
1715 if (float_reg_arg_p)
1716 base = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1717 NULL_TREE);
1718 else
1719 base = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1720 NULL_TREE);
1722 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, offs);
1723 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1724 gimplify_and_add (t, pre_p);
1726 /* [4] Emit code for: bytes -= rsize. */
1727 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1728 t = build2 (MINUS_EXPR, TREE_TYPE (bytes), bytes, t);
1729 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), bytes, t);
1730 gimplify_and_add (t, pre_p);
1732 /* [6] Emit code to branch over the else clause, then the label. */
1733 t = build1 (GOTO_EXPR, void_type_node, lab_over);
1734 gimplify_and_add (t, pre_p);
1735 t = build1 (LABEL_EXPR, void_type_node, lab_false);
1736 gimplify_and_add (t, pre_p);
1738 /* [8] Emit code for: bytes = 0. */
1739 t = fold_convert (TREE_TYPE (bytes), size_int (0));
1740 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), unshare_expr (bytes), t);
1741 gimplify_and_add (t, pre_p);
1743 /* [9] Emit code for: addr_rtx = ovfl. */
1744 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1745 t = build2 (MODIFY_EXPR, void_type_node, addr, ovfl);
1746 gimplify_and_add (t, pre_p);
1748 /* [10] Emit code for: ovfl += rsize. */
1749 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl), ovfl, size_int (rsize));
1750 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), unshare_expr (ovfl), t);
1751 gimplify_and_add (t, pre_p);
1752 t = build1 (LABEL_EXPR, void_type_node, lab_over);
1753 gimplify_and_add (t, pre_p);
1755 /* Emit a big-endian correction if size < UNITS_PER_WORD. */
1756 if (size < UNITS_PER_WORD)
1758 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr), addr,
1759 size_int (UNITS_PER_WORD - size));
1760 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1761 gimplify_and_add (t, pre_p);
1764 addr = fold_convert (ptrtype, addr);
1766 return build_va_arg_indirect_ref (addr);
1769 /* Return true if OP is an offset suitable for use as a displacement in the
1770 address of a memory access in mode MODE. */
1772 static bool
1773 rtx_ok_for_offset_p (machine_mode mode, rtx op)
1775 if (!CONST_INT_P (op) || INTVAL (op) < 0)
1776 return false;
1778 switch (mode)
1780 case E_QImode:
1781 return INTVAL (op) <= 31;
1783 case E_HImode:
1784 return (INTVAL (op) % 2) == 0 && INTVAL (op) < 63;
1786 case E_SImode:
1787 case E_SFmode:
1788 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 127;
1790 case E_DImode:
1791 case E_DFmode:
1792 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 123;
1794 default:
1795 return false;
1799 /* Return whether X is a legitimate memory address for a memory operand
1800 of mode MODE.
1802 Legitimate addresses are defined in two variants: a strict variant
1803 and a non-strict one. The STRICT parameter chooses which variant
1804 is desired by the caller.
1806 The strict variant is used in the reload pass. It must be defined
1807 so that any pseudo-register that has not been allocated a hard
1808 register is considered a memory reference. This is because in
1809 contexts where some kind of register is required, a
1810 pseudo-register with no hard register must be rejected. For
1811 non-hard registers, the strict variant should look up the
1812 `reg_renumber' array; it should then proceed using the hard
1813 register number in the array, or treat the pseudo as a memory
1814 reference if the array holds `-1'.
1816 The non-strict variant is used in other passes. It must be
1817 defined to accept all pseudo-registers in every context where some
1818 kind of register is required. */
1820 static bool
1821 visium_legitimate_address_p (machine_mode mode, rtx x, bool strict)
1823 rtx base;
1824 unsigned int regno;
1826 /* If X is base+disp, check that we have an appropriate offset. */
1827 if (GET_CODE (x) == PLUS)
1829 if (!rtx_ok_for_offset_p (mode, XEXP (x, 1)))
1830 return false;
1831 base = XEXP (x, 0);
1833 else
1834 base = x;
1836 /* Now check the base: it must be either a register or a subreg thereof. */
1837 if (GET_CODE (base) == SUBREG)
1838 base = SUBREG_REG (base);
1839 if (!REG_P (base))
1840 return false;
1842 regno = REGNO (base);
1844 /* For the strict variant, the register must be REGNO_OK_FOR_BASE_P. */
1845 if (strict)
1846 return REGNO_OK_FOR_BASE_P (regno);
1848 /* For the non-strict variant, the register may also be a pseudo. */
1849 return BASE_REGISTER_P (regno) || regno >= FIRST_PSEUDO_REGISTER;
1852 /* Try machine-dependent ways of modifying an illegitimate address
1853 to be legitimate. If we find one, return the new, valid address.
1854 This macro is used in only one place: `memory_address' in explow.cc.
1856 OLDX is the address as it was before break_out_memory_refs was called.
1857 In some cases it is useful to look at this to decide what needs to be done.
1859 MODE and WIN are passed so that this macro can use
1860 GO_IF_LEGITIMATE_ADDRESS.
1862 It is always safe for this macro to do nothing. It exists to recognize
1863 opportunities to optimize the output.
1865 For Visium
1867 memory (reg + <out of range int>)
1869 is transformed to
1871 base_int = <out of range int> & ~mask
1872 ptr_reg = reg + base_int
1873 memory (ptr_reg + <out of range int> - base_int)
1875 Thus ptr_reg is a base register for a range of addresses,
1876 which should help CSE.
1878 For a 1 byte reference mask is 0x1f
1879 for a 2 byte reference mask is 0x3f
1880 For a 4 byte reference mask is 0x7f
1882 This reflects the indexing range of the processor.
1884 For a > 4 byte reference the mask is 0x7f provided all of the words
1885 can be accessed with the base address obtained. Otherwise a mask
1886 of 0x3f is used.
1888 On rare occasions an unaligned base register value with an
1889 unaligned offset is generated. Unaligned offsets are left alone for
1890 this reason. */
1892 static rtx
1893 visium_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1894 machine_mode mode)
1896 if (GET_CODE (x) == PLUS
1897 && GET_CODE (XEXP (x, 1)) == CONST_INT
1898 && GET_CODE (XEXP (x, 0)) == REG && mode != BLKmode)
1900 int offset = INTVAL (XEXP (x, 1));
1901 int size = GET_MODE_SIZE (mode);
1902 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1903 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1904 int offset_base = offset & ~mask;
1906 /* Check that all of the words can be accessed. */
1907 if (size > 4 && size + offset - offset_base > 0x80)
1908 offset_base = offset & ~0x3f;
1909 if (offset_base != 0 && offset_base != offset && (offset & mask1) == 0)
1911 rtx ptr_reg = force_reg (Pmode,
1912 gen_rtx_PLUS (Pmode,
1913 XEXP (x, 0),
1914 GEN_INT (offset_base)));
1916 return plus_constant (Pmode, ptr_reg, offset - offset_base);
1920 return x;
1923 /* Perform a similar function to visium_legitimize_address, but this time
1924 for reload. Generating new registers is not an option here. Parts
1925 that need reloading are indicated by calling push_reload. */
1928 visium_legitimize_reload_address (rtx x, machine_mode mode, int opnum,
1929 int type, int ind ATTRIBUTE_UNUSED)
1931 rtx newrtx, tem = NULL_RTX;
1933 if (mode == BLKmode)
1934 return NULL_RTX;
1936 if (optimize && GET_CODE (x) == PLUS)
1937 tem = simplify_binary_operation (PLUS, GET_MODE (x), XEXP (x, 0),
1938 XEXP (x, 1));
1940 newrtx = tem ? tem : x;
1941 if (GET_CODE (newrtx) == PLUS
1942 && GET_CODE (XEXP (newrtx, 1)) == CONST_INT
1943 && GET_CODE (XEXP (newrtx, 0)) == REG
1944 && BASE_REGISTER_P (REGNO (XEXP (newrtx, 0))))
1946 int offset = INTVAL (XEXP (newrtx, 1));
1947 int size = GET_MODE_SIZE (mode);
1948 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1949 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1950 int offset_base = offset & ~mask;
1952 /* Check that all of the words can be accessed. */
1953 if (size > 4 && size + offset - offset_base > 0x80)
1954 offset_base = offset & ~0x3f;
1956 if (offset_base && (offset & mask1) == 0)
1958 rtx temp = gen_rtx_PLUS (Pmode,
1959 XEXP (newrtx, 0), GEN_INT (offset_base));
1961 x = gen_rtx_PLUS (Pmode, temp, GEN_INT (offset - offset_base));
1962 push_reload (XEXP (x, 0), 0, &XEXP (x, 0), 0,
1963 BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum,
1964 (enum reload_type) type);
1965 return x;
1969 return NULL_RTX;
1972 /* Return the cost of moving data of mode MODE from a register in class FROM to
1973 one in class TO. A value of 2 is the default; other values are interpreted
1974 relative to that. */
1976 static int
1977 visium_register_move_cost (machine_mode mode, reg_class_t from,
1978 reg_class_t to)
1980 const int numwords = (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) ? 1 : 2;
1982 if (from == MDB || to == MDB)
1983 return 4;
1984 else if (from == MDC || to == MDC || (from == FP_REGS) != (to == FP_REGS))
1985 return 4 * numwords;
1986 else
1987 return 2 * numwords;
1990 /* Return the cost of moving data of mode MODE between a register of class
1991 CLASS and memory. IN is zero if the value is to be written to memory,
1992 non-zero if it is to be read in. This cost is relative to those in
1993 visium_register_move_cost. */
1995 static int
1996 visium_memory_move_cost (machine_mode mode,
1997 reg_class_t to ATTRIBUTE_UNUSED,
1998 bool in)
2000 /* Moving data in can be from PROM and this is expensive. */
2001 if (in)
2003 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2004 return 7;
2005 else
2006 return 13;
2009 /* Moving data out is mostly to RAM and should be cheaper. */
2010 else
2012 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2013 return 6;
2014 else
2015 return 12;
2019 /* Return the relative costs of expression X. */
2021 static bool
2022 visium_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
2023 int opno ATTRIBUTE_UNUSED, int *total,
2024 bool speed ATTRIBUTE_UNUSED)
2026 int code = GET_CODE (x);
2028 switch (code)
2030 case CONST_INT:
2031 /* Small integers are as cheap as registers. 4-byte values can
2032 be fetched as immediate constants - let's give that the cost
2033 of an extra insn. */
2034 *total = COSTS_N_INSNS (!satisfies_constraint_J (x));
2035 return true;
2037 case CONST:
2038 case LABEL_REF:
2039 case SYMBOL_REF:
2040 *total = COSTS_N_INSNS (2);
2041 return true;
2043 case CONST_DOUBLE:
2045 rtx high, low;
2046 split_double (x, &high, &low);
2047 *total =
2048 COSTS_N_INSNS
2049 (!satisfies_constraint_J (high) + !satisfies_constraint_J (low));
2050 return true;
2053 case MULT:
2054 *total = COSTS_N_INSNS (3);
2055 return false;
2057 case DIV:
2058 case UDIV:
2059 case MOD:
2060 case UMOD:
2061 if (mode == DImode)
2062 *total = COSTS_N_INSNS (64);
2063 else
2064 *total = COSTS_N_INSNS (32);
2065 return false;
2067 case PLUS:
2068 case MINUS:
2069 case NEG:
2070 /* DImode operations are performed directly on the ALU. */
2071 if (mode == DImode)
2072 *total = COSTS_N_INSNS (2);
2073 else
2074 *total = COSTS_N_INSNS (1);
2075 return false;
2077 case ASHIFT:
2078 case ASHIFTRT:
2079 case LSHIFTRT:
2080 /* DImode operations are performed on the EAM instead. */
2081 if (mode == DImode)
2082 *total = COSTS_N_INSNS (3);
2083 else
2084 *total = COSTS_N_INSNS (1);
2085 return false;
2087 case COMPARE:
2088 /* This matches the btst pattern. */
2089 if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT
2090 && XEXP (x, 1) == const0_rtx
2091 && XEXP (XEXP (x, 0), 1) == const1_rtx
2092 && satisfies_constraint_K (XEXP (XEXP (x, 0), 2)))
2093 *total = COSTS_N_INSNS (1);
2094 return false;
2096 default:
2097 return false;
2101 /* Split a double move of OPERANDS in MODE. */
2103 void
2104 visium_split_double_move (rtx *operands, machine_mode mode)
2106 bool swap = false;
2108 /* Check register to register with overlap. */
2109 if (GET_CODE (operands[0]) == REG
2110 && GET_CODE (operands[1]) == REG
2111 && REGNO (operands[0]) == REGNO (operands[1]) + 1)
2112 swap = true;
2114 /* Check memory to register where the base reg overlaps the destination. */
2115 if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == MEM)
2117 rtx op = XEXP (operands[1], 0);
2119 if (GET_CODE (op) == SUBREG)
2120 op = SUBREG_REG (op);
2122 if (GET_CODE (op) == REG && REGNO (op) == REGNO (operands[0]))
2123 swap = true;
2125 if (GET_CODE (op) == PLUS)
2127 rtx x = XEXP (op, 0);
2128 rtx y = XEXP (op, 1);
2130 if (GET_CODE (x) == REG && REGNO (x) == REGNO (operands[0]))
2131 swap = true;
2133 if (GET_CODE (y) == REG && REGNO (y) == REGNO (operands[0]))
2134 swap = true;
2138 if (swap)
2140 operands[2] = operand_subword (operands[0], 1, 1, mode);
2141 operands[3] = operand_subword (operands[1], 1, 1, mode);
2142 operands[4] = operand_subword (operands[0], 0, 1, mode);
2143 operands[5] = operand_subword (operands[1], 0, 1, mode);
2145 else
2147 operands[2] = operand_subword (operands[0], 0, 1, mode);
2148 operands[3] = operand_subword (operands[1], 0, 1, mode);
2149 operands[4] = operand_subword (operands[0], 1, 1, mode);
2150 operands[5] = operand_subword (operands[1], 1, 1, mode);
2154 /* Split a double addition or subtraction of operands. */
2156 void
2157 visium_split_double_add (enum rtx_code code, rtx op0, rtx op1, rtx op2)
2159 rtx op3 = gen_lowpart (SImode, op0);
2160 rtx op4 = gen_lowpart (SImode, op1);
2161 rtx op5;
2162 rtx op6 = gen_highpart (SImode, op0);
2163 rtx op7 = (op1 == const0_rtx ? op1 : gen_highpart (SImode, op1));
2164 rtx op8;
2165 rtx x, pat, flags;
2167 /* If operand #2 is a small constant, then its high part is null. */
2168 if (CONST_INT_P (op2))
2170 HOST_WIDE_INT val = INTVAL (op2);
2172 if (val < 0)
2174 code = (code == MINUS ? PLUS : MINUS);
2175 val = -val;
2178 op5 = gen_int_mode (val, SImode);
2179 op8 = const0_rtx;
2181 else
2183 op5 = gen_lowpart (SImode, op2);
2184 op8 = gen_highpart (SImode, op2);
2187 if (op4 == const0_rtx)
2188 pat = gen_negsi2_insn_set_carry (op3, op5);
2189 else if (code == MINUS)
2190 pat = gen_subsi3_insn_set_carry (op3, op4, op5);
2191 else
2192 pat = gen_addsi3_insn_set_carry (op3, op4, op5);
2193 emit_insn (pat);
2195 /* This is the plus_[plus_]sltu_flags or minus_[minus_]sltu_flags pattern. */
2196 if (op8 == const0_rtx)
2197 x = op7;
2198 else
2199 x = gen_rtx_fmt_ee (code, SImode, op7, op8);
2200 flags = gen_rtx_REG (CCCmode, FLAGS_REGNUM);
2201 x = gen_rtx_fmt_ee (code, SImode, x, gen_rtx_LTU (SImode, flags, const0_rtx));
2202 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2203 XVECEXP (pat, 0, 0) = gen_rtx_SET (op6, x);
2204 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2205 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2206 emit_insn (pat);
2208 visium_flags_exposed = true;
2211 /* Expand a copysign of OPERANDS in MODE. */
2213 void
2214 visium_expand_copysign (rtx *operands, machine_mode mode)
2216 rtx op0 = operands[0];
2217 rtx op1 = operands[1];
2218 rtx op2 = operands[2];
2219 rtx mask = force_reg (SImode, GEN_INT (0x7fffffff));
2220 rtx x;
2222 /* We manually handle SFmode because the abs and neg instructions of
2223 the FPU on the MCM have a non-standard behavior wrt NaNs. */
2224 gcc_assert (mode == SFmode);
2226 /* First get all the non-sign bits of op1. */
2227 if (GET_CODE (op1) == CONST_DOUBLE)
2229 if (real_isneg (CONST_DOUBLE_REAL_VALUE (op1)))
2230 op1 = simplify_unary_operation (ABS, mode, op1, mode);
2231 if (op1 != CONST0_RTX (mode))
2233 long l;
2234 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op1), l);
2235 op1 = force_reg (SImode, gen_int_mode (l, SImode));
2238 else
2240 op1 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op1));
2241 op1 = force_reg (SImode, gen_rtx_AND (SImode, op1, mask));
2244 /* Then get the sign bit of op2. */
2245 mask = force_reg (SImode, gen_rtx_NOT (SImode, mask));
2246 op2 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op2));
2247 op2 = force_reg (SImode, gen_rtx_AND (SImode, op2, mask));
2249 /* Finally OR the two values. */
2250 if (op1 == CONST0_RTX (SFmode))
2251 x = op2;
2252 else
2253 x = force_reg (SImode, gen_rtx_IOR (SImode, op1, op2));
2255 /* And move the result to the destination. */
2256 emit_insn (gen_rtx_SET (op0, gen_lowpart (SFmode, x)));
2259 /* Expand a cstore of OPERANDS in MODE for EQ/NE/LTU/GTU/GEU/LEU. We generate
2260 the result in the C flag and use the ADC/SUBC instructions to write it into
2261 the destination register.
2263 It would also be possible to implement support for LT/GT/LE/GE by means of
2264 the RFLAG instruction followed by some shifts, but this can pessimize the
2265 generated code. */
2267 void
2268 visium_expand_int_cstore (rtx *operands, machine_mode mode)
2270 enum rtx_code code = GET_CODE (operands[1]);
2271 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], sltu;
2272 bool reverse = false;
2274 switch (code)
2276 case EQ:
2277 case NE:
2278 /* We use a special comparison to get the result in the C flag. */
2279 if (op2 != const0_rtx)
2280 op1 = force_reg (mode, gen_rtx_XOR (mode, op1, op2));
2281 op1 = gen_rtx_NOT (mode, op1);
2282 op2 = constm1_rtx;
2283 if (code == EQ)
2284 reverse = true;
2285 break;
2287 case LEU:
2288 case GEU:
2289 /* The result is naturally in the C flag modulo a couple of tricks. */
2290 code = reverse_condition (code);
2291 reverse = true;
2293 /* ... fall through ... */
2295 case LTU:
2296 case GTU:
2297 if (code == GTU)
2299 rtx tmp = op1;
2300 op1 = op2;
2301 op2 = tmp;
2303 break;
2305 default:
2306 gcc_unreachable ();
2309 /* We need either a single ADC or a SUBC and a PLUS. */
2310 sltu = gen_rtx_LTU (SImode, op1, op2);
2312 if (reverse)
2314 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, sltu));
2315 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2317 else
2318 emit_insn (gen_rtx_SET (op0, sltu));
2321 /* Expand a cstore of OPERANDS in MODE for LT/GT/UNGE/UNLE. We generate the
2322 result in the C flag and use the ADC/SUBC instructions to write it into
2323 the destination register. */
2325 void
2326 visium_expand_fp_cstore (rtx *operands,
2327 machine_mode mode ATTRIBUTE_UNUSED)
2329 enum rtx_code code = GET_CODE (operands[1]);
2330 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], slt;
2331 bool reverse = false;
2333 switch (code)
2335 case UNLE:
2336 case UNGE:
2337 /* The result is naturally in the C flag modulo a couple of tricks. */
2338 code = reverse_condition_maybe_unordered (code);
2339 reverse = true;
2341 /* ... fall through ... */
2343 case LT:
2344 case GT:
2345 if (code == GT)
2347 rtx tmp = op1;
2348 op1 = op2;
2349 op2 = tmp;
2351 break;
2353 default:
2354 gcc_unreachable ();
2357 /* We need either a single ADC or a SUBC and a PLUS. */
2358 slt = gen_rtx_LT (SImode, op1, op2);
2360 if (reverse)
2362 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, slt));
2363 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2365 else
2366 emit_insn (gen_rtx_SET (op0, slt));
2369 /* Split a compare-and-store with CODE, operands OP2 and OP3, combined with
2370 operation with OP_CODE, operands OP0 and OP1. */
2372 void
2373 visium_split_cstore (enum rtx_code op_code, rtx op0, rtx op1,
2374 enum rtx_code code, rtx op2, rtx op3)
2376 machine_mode cc_mode = visium_select_cc_mode (code, op2, op3);
2378 /* If a FP cstore was reversed, then it was originally UNGE/UNLE. */
2379 if (cc_mode == CCFPEmode && (op_code == NEG || op_code == MINUS))
2380 cc_mode = CCFPmode;
2382 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2383 rtx x = gen_rtx_COMPARE (cc_mode, op2, op3);
2384 x = gen_rtx_SET (flags, x);
2385 emit_insn (x);
2387 x = gen_rtx_fmt_ee (code, SImode, flags, const0_rtx);
2388 switch (op_code)
2390 case SET:
2391 break;
2392 case NEG:
2393 x = gen_rtx_NEG (SImode, x);
2394 break;
2395 case PLUS:
2396 case MINUS:
2397 x = gen_rtx_fmt_ee (op_code, SImode, op1, x);
2398 break;
2399 default:
2400 gcc_unreachable ();
2403 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2404 XVECEXP (pat, 0, 0) = gen_rtx_SET (op0, x);
2405 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2406 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2407 emit_insn (pat);
2409 visium_flags_exposed = true;
2412 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2413 address SRC_REG to DST with address DST_REG in 4-byte chunks. */
2415 static void
2416 expand_block_move_4 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2418 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2419 unsigned int rem = bytes % 4;
2421 if (TARGET_BMI)
2423 unsigned int i;
2424 rtx insn;
2426 emit_move_insn (regno_reg_rtx[1], dst_reg);
2427 emit_move_insn (regno_reg_rtx[2], src_reg);
2428 emit_move_insn (regno_reg_rtx[3], bytes_rtx);
2430 insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (8));
2431 XVECEXP (insn, 0, 0)
2432 = gen_rtx_SET (replace_equiv_address_nv (dst, regno_reg_rtx[1]),
2433 replace_equiv_address_nv (src, regno_reg_rtx[2]));
2434 XVECEXP (insn, 0, 1) = gen_rtx_USE (VOIDmode, regno_reg_rtx[3]);
2435 for (i = 1; i <= 6; i++)
2436 XVECEXP (insn, 0, 1 + i)
2437 = gen_rtx_CLOBBER (VOIDmode, regno_reg_rtx[i]);
2438 emit_insn (insn);
2440 else
2441 emit_library_call (long_int_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2442 dst_reg, Pmode,
2443 src_reg, Pmode,
2444 convert_to_mode (TYPE_MODE (sizetype),
2445 GEN_INT (bytes >> 2),
2446 TYPE_UNSIGNED (sizetype)),
2447 TYPE_MODE (sizetype));
2448 if (rem == 0)
2449 return;
2451 dst = replace_equiv_address_nv (dst, dst_reg);
2452 src = replace_equiv_address_nv (src, src_reg);
2453 bytes -= rem;
2455 if (rem > 1)
2457 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2458 adjust_address_nv (src, HImode, bytes));
2459 bytes += 2;
2460 rem -= 2;
2463 if (rem > 0)
2464 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2465 adjust_address_nv (src, QImode, bytes));
2468 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2469 address SRC_REG to DST with address DST_REG in 2-bytes chunks. */
2471 static void
2472 expand_block_move_2 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2474 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2475 unsigned int rem = bytes % 2;
2477 emit_library_call (wrd_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2478 dst_reg, Pmode,
2479 src_reg, Pmode,
2480 convert_to_mode (TYPE_MODE (sizetype),
2481 GEN_INT (bytes >> 1),
2482 TYPE_UNSIGNED (sizetype)),
2483 TYPE_MODE (sizetype));
2484 if (rem == 0)
2485 return;
2487 dst = replace_equiv_address_nv (dst, dst_reg);
2488 src = replace_equiv_address_nv (src, src_reg);
2489 bytes -= rem;
2491 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2492 adjust_address_nv (src, QImode, bytes));
2495 /* Generate a call to a library function to move BYTES_RTX bytes from address
2496 SRC_REG to address DST_REG in 1-byte chunks. */
2498 static void
2499 expand_block_move_1 (rtx dst_reg, rtx src_reg, rtx bytes_rtx)
2501 emit_library_call (byt_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2502 dst_reg, Pmode,
2503 src_reg, Pmode,
2504 convert_to_mode (TYPE_MODE (sizetype),
2505 bytes_rtx,
2506 TYPE_UNSIGNED (sizetype)),
2507 TYPE_MODE (sizetype));
2510 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2511 address DST_REG to VALUE_RTX in 4-byte chunks. */
2513 static void
2514 expand_block_set_4 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2516 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2517 unsigned int rem = bytes % 4;
2519 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2520 emit_library_call (long_int_memset_libfunc, LCT_NORMAL, VOIDmode,
2521 dst_reg, Pmode,
2522 value_rtx, Pmode,
2523 convert_to_mode (TYPE_MODE (sizetype),
2524 GEN_INT (bytes >> 2),
2525 TYPE_UNSIGNED (sizetype)),
2526 TYPE_MODE (sizetype));
2527 if (rem == 0)
2528 return;
2530 dst = replace_equiv_address_nv (dst, dst_reg);
2531 bytes -= rem;
2533 if (rem > 1)
2535 if (CONST_INT_P (value_rtx))
2537 const unsigned HOST_WIDE_INT value = UINTVAL (value_rtx) & 0xff;
2538 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2539 gen_int_mode ((value << 8) | value, HImode));
2541 else
2543 rtx temp = convert_to_mode (QImode, value_rtx, 1);
2544 emit_move_insn (adjust_address_nv (dst, QImode, bytes), temp);
2545 emit_move_insn (adjust_address_nv (dst, QImode, bytes + 1), temp);
2547 bytes += 2;
2548 rem -= 2;
2551 if (rem > 0)
2552 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2553 convert_to_mode (QImode, value_rtx, 1));
2556 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2557 address DST_REG to VALUE_RTX in 2-byte chunks. */
2559 static void
2560 expand_block_set_2 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2562 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2563 unsigned int rem = bytes % 2;
2565 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2566 emit_library_call (wrd_memset_libfunc, LCT_NORMAL, VOIDmode,
2567 dst_reg, Pmode,
2568 value_rtx, Pmode,
2569 convert_to_mode (TYPE_MODE (sizetype),
2570 GEN_INT (bytes >> 1),
2571 TYPE_UNSIGNED (sizetype)),
2572 TYPE_MODE (sizetype));
2573 if (rem == 0)
2574 return;
2576 dst = replace_equiv_address_nv (dst, dst_reg);
2577 bytes -= rem;
2579 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2580 convert_to_mode (QImode, value_rtx, 1));
2583 /* Generate a call to a library function to set BYTES_RTX bytes at address
2584 DST_REG to VALUE_RTX in 1-byte chunks. */
2586 static void
2587 expand_block_set_1 (rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2589 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2590 emit_library_call (byt_memset_libfunc, LCT_NORMAL, VOIDmode,
2591 dst_reg, Pmode,
2592 value_rtx, Pmode,
2593 convert_to_mode (TYPE_MODE (sizetype),
2594 bytes_rtx,
2595 TYPE_UNSIGNED (sizetype)),
2596 TYPE_MODE (sizetype));
2599 /* Expand string/block move operations.
2601 operands[0] is the pointer to the destination.
2602 operands[1] is the pointer to the source.
2603 operands[2] is the number of bytes to move.
2604 operands[3] is the alignment.
2606 Return 1 upon success, 0 otherwise. */
2609 visium_expand_block_move (rtx *operands)
2611 rtx dst = operands[0];
2612 rtx src = operands[1];
2613 rtx bytes_rtx = operands[2];
2614 rtx align_rtx = operands[3];
2615 const int align = INTVAL (align_rtx);
2616 rtx dst_reg, src_reg;
2617 tree dst_expr, src_expr;
2619 /* We only handle a fixed number of bytes for now. */
2620 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2621 return 0;
2623 /* Copy the addresses into scratch registers. */
2624 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2625 src_reg = copy_addr_to_reg (XEXP (src, 0));
2627 /* Move the data with the appropriate granularity. */
2628 if (align >= 4)
2629 expand_block_move_4 (dst, dst_reg, src, src_reg, bytes_rtx);
2630 else if (align >= 2)
2631 expand_block_move_2 (dst, dst_reg, src, src_reg, bytes_rtx);
2632 else
2633 expand_block_move_1 (dst_reg, src_reg, bytes_rtx);
2635 /* Since DST and SRC are passed to a libcall, mark the corresponding
2636 tree EXPR as addressable. */
2637 dst_expr = MEM_EXPR (dst);
2638 src_expr = MEM_EXPR (src);
2639 if (dst_expr)
2640 mark_addressable (dst_expr);
2641 if (src_expr)
2642 mark_addressable (src_expr);
2644 return 1;
2647 /* Expand string/block set operations.
2649 operands[0] is the pointer to the destination.
2650 operands[1] is the number of bytes to set.
2651 operands[2] is the source value.
2652 operands[3] is the alignment.
2654 Return 1 upon success, 0 otherwise. */
2657 visium_expand_block_set (rtx *operands)
2659 rtx dst = operands[0];
2660 rtx bytes_rtx = operands[1];
2661 rtx value_rtx = operands[2];
2662 rtx align_rtx = operands[3];
2663 const int align = INTVAL (align_rtx);
2664 rtx dst_reg;
2665 tree dst_expr;
2667 /* We only handle a fixed number of bytes for now. */
2668 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2669 return 0;
2671 /* Copy the address into a scratch register. */
2672 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2674 /* Set the data with the appropriate granularity. */
2675 if (align >= 4)
2676 expand_block_set_4 (dst, dst_reg, value_rtx, bytes_rtx);
2677 else if (align >= 2)
2678 expand_block_set_2 (dst, dst_reg, value_rtx, bytes_rtx);
2679 else
2680 expand_block_set_1 (dst_reg, value_rtx, bytes_rtx);
2682 /* Since DST is passed to a libcall, mark the corresponding
2683 tree EXPR as addressable. */
2684 dst_expr = MEM_EXPR (dst);
2685 if (dst_expr)
2686 mark_addressable (dst_expr);
2688 return 1;
2691 /* Initialize a trampoline. M_TRAMP is an RTX for the memory block for the
2692 trampoline, FNDECL is the FUNCTION_DECL for the nested function and
2693 STATIC_CHAIN is an RTX for the static chain value that should be passed
2694 to the function when it is called. */
2696 static void
2697 visium_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
2699 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2700 rtx addr = XEXP (m_tramp, 0);
2702 /* The trampoline initialization sequence is:
2704 moviu r9,%u FUNCTION
2705 movil r9,%l FUNCTION
2706 [nop]
2707 moviu r20,%u STATIC
2708 bra tr,r9,r9
2709 movil r20,%l STATIC
2711 We don't use r0 as the destination register of the branch because we want
2712 the Branch Pre-decode Logic of the GR6 to use the Address Load Array to
2713 predict the branch target. */
2715 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 0)),
2716 plus_constant (SImode,
2717 expand_shift (RSHIFT_EXPR, SImode, fnaddr,
2718 16, NULL_RTX, 1),
2719 0x04a90000));
2721 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 4)),
2722 plus_constant (SImode,
2723 expand_and (SImode, fnaddr, GEN_INT (0xffff),
2724 NULL_RTX),
2725 0x04890000));
2727 if (visium_cpu == PROCESSOR_GR6)
2729 /* For the GR6, the BRA insn must be aligned on a 64-bit boundary. */
2730 gcc_assert (TRAMPOLINE_ALIGNMENT >= 64);
2731 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)),
2732 gen_int_mode (0, SImode));
2735 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 8)),
2736 plus_constant (SImode,
2737 expand_shift (RSHIFT_EXPR, SImode,
2738 static_chain,
2739 16, NULL_RTX, 1),
2740 0x04b40000));
2742 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)),
2743 gen_int_mode (0xff892404, SImode));
2745 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 16)),
2746 plus_constant (SImode,
2747 expand_and (SImode, static_chain,
2748 GEN_INT (0xffff), NULL_RTX),
2749 0x04940000));
2751 emit_library_call (set_trampoline_parity_libfunc, LCT_NORMAL, VOIDmode,
2752 addr, SImode);
2755 /* Return true if the current function must have and use a frame pointer. */
2757 static bool
2758 visium_frame_pointer_required (void)
2760 /* The frame pointer is required if the function isn't leaf to be able to
2761 do manual stack unwinding. */
2762 if (!crtl->is_leaf)
2763 return true;
2765 /* If the stack pointer is dynamically modified in the function, it cannot
2766 serve as the frame pointer. */
2767 if (!crtl->sp_is_unchanging)
2768 return true;
2770 /* If the function receives nonlocal gotos, it needs to save the frame
2771 pointer in the nonlocal_goto_save_area object. */
2772 if (cfun->has_nonlocal_label)
2773 return true;
2775 /* The frame also needs to be established in some special cases. */
2776 if (visium_frame_needed)
2777 return true;
2779 return false;
2782 /* Profiling support. Just a call to MCOUNT is needed. No labelled counter
2783 location is involved. Proper support for __builtin_return_address is also
2784 required, which is fairly straightforward provided a frame gets created. */
2786 void
2787 visium_profile_hook (void)
2789 visium_frame_needed = true;
2790 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "mcount"), LCT_NORMAL,
2791 VOIDmode);
2794 /* A C expression whose value is RTL representing the address in a stack frame
2795 where the pointer to the caller's frame is stored. Assume that FRAMEADDR is
2796 an RTL expression for the address of the stack frame itself.
2798 If you don't define this macro, the default is to return the value of
2799 FRAMEADDR--that is, the stack frame address is also the address of the stack
2800 word that points to the previous frame. */
2803 visium_dynamic_chain_address (rtx frame)
2805 /* This is the default, but we need to make sure the frame gets created. */
2806 visium_frame_needed = true;
2807 return frame;
2810 /* A C expression whose value is RTL representing the value of the return
2811 address for the frame COUNT steps up from the current frame, after the
2812 prologue. FRAMEADDR is the frame pointer of the COUNT frame, or the frame
2813 pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
2814 defined.
2816 The value of the expression must always be the correct address when COUNT is
2817 zero, but may be `NULL_RTX' if there is not way to determine the return
2818 address of other frames. */
2821 visium_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
2823 /* Dont try to compute anything other than frame zero. */
2824 if (count != 0)
2825 return NULL_RTX;
2827 visium_frame_needed = true;
2828 return
2829 gen_frame_mem (Pmode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2832 /* Helper function for EH_RETURN_HANDLER_RTX. Return the RTX representing a
2833 location in which to store the address of an exception handler to which we
2834 should return. */
2837 visium_eh_return_handler_rtx (void)
2839 rtx mem
2840 = gen_frame_mem (SImode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2841 MEM_VOLATILE_P (mem) = 1;
2842 return mem;
2845 static struct machine_function *
2846 visium_init_machine_status (void)
2848 return ggc_cleared_alloc<machine_function> ();
2851 /* The per-function data machinery is needed to indicate when a frame
2852 is required. */
2854 void
2855 visium_init_expanders (void)
2857 init_machine_status = visium_init_machine_status;
2860 /* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE,
2861 return the mode to be used for the comparison. */
2863 machine_mode
2864 visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
2866 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2868 switch (code)
2870 case EQ:
2871 case NE:
2872 case ORDERED:
2873 case UNORDERED:
2874 case UNLT:
2875 case UNLE:
2876 case UNGT:
2877 case UNGE:
2878 return CCFPmode;
2880 case LT:
2881 case LE:
2882 case GT:
2883 case GE:
2884 return CCFPEmode;
2886 /* These 2 comparison codes are not supported. */
2887 case UNEQ:
2888 case LTGT:
2889 default:
2890 gcc_unreachable ();
2894 /* This is for the cmp<mode>_sne pattern. */
2895 if (op1 == constm1_rtx)
2896 return CCCmode;
2898 /* This is for the add<mode>3_insn_set_carry pattern. */
2899 if ((code == LTU || code == GEU)
2900 && GET_CODE (op0) == PLUS
2901 && rtx_equal_p (XEXP (op0, 0), op1))
2902 return CCCmode;
2904 /* This is for the {add,sub,neg}<mode>3_insn_set_overflow pattern. */
2905 if ((code == EQ || code == NE)
2906 && GET_CODE (op1) == UNSPEC
2907 && (XINT (op1, 1) == UNSPEC_ADDV
2908 || XINT (op1, 1) == UNSPEC_SUBV
2909 || XINT (op1, 1) == UNSPEC_NEGV))
2910 return CCVmode;
2912 if (op1 != const0_rtx)
2913 return CCmode;
2915 switch (GET_CODE (op0))
2917 case PLUS:
2918 case MINUS:
2919 case NEG:
2920 case ASHIFT:
2921 case LTU:
2922 case LT:
2923 /* The C and V flags may be set differently from a COMPARE with zero.
2924 The consequence is that a comparison operator testing C or V must
2925 be turned into another operator not testing C or V and yielding
2926 the same result for a comparison with zero. That's possible for
2927 GE/LT which become NC/NS respectively, but not for GT/LE for which
2928 the altered operator doesn't exist on the Visium. */
2929 return CCNZmode;
2931 case ZERO_EXTRACT:
2932 /* This is a btst, the result is in C instead of Z. */
2933 return CCCmode;
2935 case REG:
2936 case AND:
2937 case IOR:
2938 case XOR:
2939 case NOT:
2940 case ASHIFTRT:
2941 case LSHIFTRT:
2942 case TRUNCATE:
2943 case SIGN_EXTEND:
2944 /* Pretend that the flags are set as for a COMPARE with zero.
2945 That's mostly true, except for the 2 right shift insns that
2946 will set the C flag. But the C flag is relevant only for
2947 the unsigned comparison operators and they are eliminated
2948 when applied to a comparison with zero. */
2949 return CCmode;
2951 /* ??? Cater to the junk RTXes sent by try_merge_compare. */
2952 case ASM_OPERANDS:
2953 case CALL:
2954 case CONST_INT:
2955 case LO_SUM:
2956 case HIGH:
2957 case MEM:
2958 case UNSPEC:
2959 case ZERO_EXTEND:
2960 return CCmode;
2962 default:
2963 gcc_unreachable ();
2967 /* Split a compare-and-branch with CODE, operands OP0 and OP1, and LABEL. */
2969 void
2970 visium_split_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx label)
2972 machine_mode cc_mode = visium_select_cc_mode (code, op0, op1);
2973 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2975 rtx x = gen_rtx_COMPARE (cc_mode, op0, op1);
2976 x = gen_rtx_SET (flags, x);
2977 emit_insn (x);
2979 x = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
2980 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, gen_rtx_LABEL_REF (Pmode, label),
2981 pc_rtx);
2982 x = gen_rtx_SET (pc_rtx, x);
2983 emit_jump_insn (x);
2985 visium_flags_exposed = true;
2988 /* Branch instructions on the Visium.
2990 Setting aside the interrupt-handling specific instructions, the ISA has
2991 two branch instructions: BRR and BRA. The former is used to implement
2992 short branches (+/- 2^17) within functions and its target is encoded in
2993 the instruction. The latter is used to implement all the other types
2994 of control flow changes and its target might not be statically known
2995 or even easily predictable at run time. Here's a complete summary of
2996 the patterns that generate a BRA instruction:
2998 1. Indirect jump
2999 2. Table jump
3000 3. Call
3001 4. Sibling call
3002 5. Return
3003 6. Long branch
3004 7. Trampoline
3006 Among these patterns, only the return (5) and the long branch (6) can be
3007 conditional; all the other patterns are always unconditional.
3009 The following algorithm can be used to identify the pattern for which
3010 the BRA instruction was generated and work out its target:
3012 A. If the source is r21 and the destination is r0, this is a return (5)
3013 and the target is the caller (i.e. the value of r21 on function's
3014 entry).
3016 B. If the source is rN, N != 21 and the destination is r0, this is either
3017 an indirect jump or a table jump (1, 2) and the target is not easily
3018 predictable.
3020 C. If the source is rN, N != 21 and the destination is r21, this is a call
3021 (3) and the target is given by the preceding MOVIL/MOVIU pair for rN,
3022 unless this is an indirect call in which case the target is not easily
3023 predictable.
3025 D. If the source is rN, N != 21 and the destination is also rN, this is
3026 either a sibling call or a trampoline (4, 7) and the target is given
3027 by the preceding MOVIL/MOVIU pair for rN.
3029 E. If the source is r21 and the destination is also r21, this is a long
3030 branch (6) and the target is given by the preceding MOVIL/MOVIU pair
3031 for r21.
3033 The other combinations are not used. This implementation has been devised
3034 to accommodate the branch predictor of the GR6 but is used unconditionally
3035 by the compiler, i.e. including for earlier processors. */
3037 /* Output a conditional/unconditional branch to LABEL. COND is the string
3038 condition. INSN is the instruction. */
3040 static const char *
3041 output_branch (rtx label, const char *cond, rtx_insn *insn)
3043 char str[64];
3044 rtx operands[2];
3046 gcc_assert (cond);
3047 operands[0] = label;
3049 /* If the length of the instruction is greater than 12, then this is a
3050 long branch and we need to work harder to emit it properly. */
3051 if (get_attr_length (insn) > 12)
3053 bool spilled;
3055 /* If the link register has been saved, then we use it. */
3056 if (current_function_saves_lr ())
3058 operands[1] = regno_reg_rtx [LINK_REGNUM];
3059 spilled = false;
3062 /* Or else, if the long-branch register isn't live, we use it. */
3063 else if (!df_regs_ever_live_p (long_branch_regnum))
3065 operands[1] = regno_reg_rtx [long_branch_regnum];
3066 spilled = false;
3069 /* Otherwise, we will use the long-branch register but we need to
3070 spill it to the stack and reload it at the end. We should have
3071 reserved the LR slot for this purpose. */
3072 else
3074 operands[1] = regno_reg_rtx [long_branch_regnum];
3075 spilled = true;
3076 gcc_assert (current_function_has_lr_slot ());
3079 /* First emit the spill to the stack:
3081 insn_in_delay_slot
3082 write.l [1](sp),reg */
3083 if (spilled)
3085 if (final_sequence)
3087 rtx_insn *delay = NEXT_INSN (insn);
3088 gcc_assert (delay);
3090 final_scan_insn (delay, asm_out_file, optimize, 0, NULL);
3091 PATTERN (delay) = gen_blockage ();
3092 INSN_CODE (delay) = -1;
3095 if (current_function_saves_fp ())
3096 output_asm_insn ("write.l 1(sp),%1", operands);
3097 else
3098 output_asm_insn ("write.l (sp),%1", operands);
3101 /* Then emit the core sequence:
3103 moviu reg,%u label
3104 movil reg,%l label
3105 bra tr,reg,reg
3107 We don't use r0 as the destination register of the branch because we
3108 want the Branch Pre-decode Logic of the GR6 to use the Address Load
3109 Array to predict the branch target. */
3110 output_asm_insn ("moviu %1,%%u %0", operands);
3111 output_asm_insn ("movil %1,%%l %0", operands);
3112 strcpy (str, "bra ");
3113 strcat (str, cond);
3114 strcat (str, ",%1,%1");
3115 if (!spilled)
3116 strcat (str, "%#");
3117 strcat (str, "\t\t;long branch");
3118 output_asm_insn (str, operands);
3120 /* Finally emit the reload:
3122 read.l reg,[1](sp) */
3123 if (spilled)
3125 if (current_function_saves_fp ())
3126 output_asm_insn (" read.l %1,1(sp)", operands);
3127 else
3128 output_asm_insn (" read.l %1,(sp)", operands);
3132 /* Or else, if the label is PC, then this is a return. */
3133 else if (label == pc_rtx)
3135 strcpy (str, "bra ");
3136 strcat (str, cond);
3137 strcat (str, ",r21,r0%#\t\t;return");
3138 output_asm_insn (str, operands);
3141 /* Otherwise, this is a short branch. */
3142 else
3144 strcpy (str, "brr ");
3145 strcat (str, cond);
3146 strcat (str, ",%0%#");
3147 output_asm_insn (str, operands);
3150 return "";
3153 /* Output an unconditional branch to LABEL. INSN is the instruction. */
3155 const char *
3156 output_ubranch (rtx label, rtx_insn *insn)
3158 return output_branch (label, "tr", insn);
3161 /* Output a conditional branch to LABEL. CODE is the comparison code.
3162 CC_MODE is the mode of the CC register. REVERSED is non-zero if we
3163 should reverse the sense of the comparison. INSN is the instruction. */
3165 const char *
3166 output_cbranch (rtx label, enum rtx_code code, machine_mode cc_mode,
3167 int reversed, rtx_insn *insn)
3169 const char *cond;
3171 if (reversed)
3173 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3174 code = reverse_condition_maybe_unordered (code);
3175 else
3176 code = reverse_condition (code);
3179 switch (code)
3181 case NE:
3182 if (cc_mode == CCCmode)
3183 cond = "cs";
3184 else if (cc_mode == CCVmode)
3185 cond = "os";
3186 else
3187 cond = "ne";
3188 break;
3190 case EQ:
3191 if (cc_mode == CCCmode)
3192 cond = "cc";
3193 else if (cc_mode == CCVmode)
3194 cond = "oc";
3195 else
3196 cond = "eq";
3197 break;
3199 case GE:
3200 if (cc_mode == CCNZmode)
3201 cond = "nc";
3202 else
3203 cond = "ge";
3204 break;
3206 case GT:
3207 cond = "gt";
3208 break;
3210 case LE:
3211 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3212 cond = "ls";
3213 else
3214 cond = "le";
3215 break;
3217 case LT:
3218 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3219 cond = "cs"; /* or "ns" */
3220 else if (cc_mode == CCNZmode)
3221 cond = "ns";
3222 else
3223 cond = "lt";
3224 break;
3226 case GEU:
3227 cond = "cc";
3228 break;
3230 case GTU:
3231 cond = "hi";
3232 break;
3234 case LEU:
3235 cond = "ls";
3236 break;
3238 case LTU:
3239 cond = "cs";
3240 break;
3242 case UNORDERED:
3243 cond = "os";
3244 break;
3246 case ORDERED:
3247 cond = "oc";
3248 break;
3250 case UNGE:
3251 cond = "cc"; /* or "nc" */
3252 break;
3254 case UNGT:
3255 cond = "hi";
3256 break;
3258 case UNLE:
3259 cond = "le";
3260 break;
3262 case UNLT:
3263 cond = "lt";
3264 break;
3266 /* These 2 comparison codes are not supported. */
3267 case UNEQ:
3268 case LTGT:
3269 default:
3270 gcc_unreachable ();
3273 return output_branch (label, cond, insn);
3276 /* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
3278 static bool
3279 visium_print_operand_punct_valid_p (unsigned char code)
3281 return code == '#';
3284 /* Implement TARGET_PRINT_OPERAND. Output to stdio stream FILE the assembler
3285 syntax for an instruction operand OP subject to the modifier LETTER. */
3287 static void
3288 visium_print_operand (FILE *file, rtx op, int letter)
3290 switch (letter)
3292 case '#':
3293 /* Output an insn in a delay slot. */
3294 if (final_sequence)
3295 visium_indent_opcode = 1;
3296 else
3297 fputs ("\n\t nop", file);
3298 return;
3300 case 'b':
3301 /* Print LS 8 bits of operand. */
3302 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xff);
3303 return;
3305 case 'w':
3306 /* Print LS 16 bits of operand. */
3307 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xffff);
3308 return;
3310 case 'u':
3311 /* Print MS 16 bits of operand. */
3312 fprintf (file,
3313 HOST_WIDE_INT_PRINT_UNSIGNED, (UINTVAL (op) >> 16) & 0xffff);
3314 return;
3316 case 'r':
3317 /* It's either a register or zero. */
3318 if (GET_CODE (op) == REG)
3319 fputs (reg_names[REGNO (op)], file);
3320 else
3321 fputs (reg_names[0], file);
3322 return;
3324 case 'f':
3325 /* It's either a FP register or zero. */
3326 if (GET_CODE (op) == REG)
3327 fputs (reg_names[REGNO (op)], file);
3328 else
3329 fputs (reg_names[FP_FIRST_REGNUM], file);
3330 return;
3333 switch (GET_CODE (op))
3335 case REG:
3336 if (letter == 'd')
3337 fputs (reg_names[REGNO (op) + 1], file);
3338 else
3339 fputs (reg_names[REGNO (op)], file);
3340 break;
3342 case SYMBOL_REF:
3343 case LABEL_REF:
3344 case CONST:
3345 output_addr_const (file, op);
3346 break;
3348 case MEM:
3349 visium_print_operand_address (file, GET_MODE (op), XEXP (op, 0));
3350 break;
3352 case CONST_INT:
3353 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
3354 break;
3356 case CODE_LABEL:
3357 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (op));
3358 break;
3360 case HIGH:
3361 visium_print_operand (file, XEXP (op, 1), letter);
3362 break;
3364 default:
3365 fatal_insn ("illegal operand ", op);
3369 /* Implement TARGET_PRINT_OPERAND_ADDRESS. Output to stdio stream FILE the
3370 assembler syntax for an instruction operand that is a memory reference
3371 whose address is ADDR. */
3373 static void
3374 visium_print_operand_address (FILE *file, machine_mode mode, rtx addr)
3376 switch (GET_CODE (addr))
3378 case REG:
3379 case SUBREG:
3380 fprintf (file, "(%s)", reg_names[true_regnum (addr)]);
3381 break;
3383 case PLUS:
3385 rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
3387 switch (GET_CODE (x))
3389 case REG:
3390 case SUBREG:
3391 if (CONST_INT_P (y))
3393 unsigned int regno = true_regnum (x);
3394 HOST_WIDE_INT val = INTVAL (y);
3395 switch (mode)
3397 case E_SImode:
3398 case E_DImode:
3399 case E_SFmode:
3400 case E_DFmode:
3401 val >>= 2;
3402 break;
3404 case E_HImode:
3405 val >>= 1;
3406 break;
3408 case E_QImode:
3409 default:
3410 break;
3412 fprintf (file, HOST_WIDE_INT_PRINT_DEC"(%s)", val,
3413 reg_names[regno]);
3415 else
3416 fatal_insn ("illegal operand address (1)", addr);
3417 break;
3419 default:
3420 if (CONSTANT_P (x) && CONSTANT_P (y))
3421 output_addr_const (file, addr);
3422 else
3423 fatal_insn ("illegal operand address (2)", addr);
3424 break;
3427 break;
3429 case LABEL_REF:
3430 case SYMBOL_REF:
3431 case CONST_INT:
3432 case CONST:
3433 output_addr_const (file, addr);
3434 break;
3436 case NOTE:
3437 if (NOTE_KIND (addr) != NOTE_INSN_DELETED_LABEL)
3438 fatal_insn ("illegal operand address (3)", addr);
3439 break;
3441 case CODE_LABEL:
3442 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (addr));
3443 break;
3445 default:
3446 fatal_insn ("illegal operand address (4)", addr);
3447 break;
3451 /* The Visium stack frames look like:
3453 Before call After call
3454 +-----------------------+ +-----------------------+
3455 | | | |
3456 high | previous | | previous |
3457 mem | frame | | frame |
3458 | | | |
3459 +-----------------------+ +-----------------------+
3460 | | | |
3461 | arguments on stack | | arguments on stack |
3462 | | | |
3463 SP+0->+-----------------------+ +-----------------------+
3464 | reg parm save area, |
3465 | only created for |
3466 | variable argument |
3467 | functions |
3468 +-----------------------+
3470 | register save area |
3472 +-----------------------+
3474 | local variables |
3476 FP+8->+-----------------------+
3477 | return address |
3478 FP+4->+-----------------------+
3479 | previous FP |
3480 FP+0->+-----------------------+
3482 | alloca allocations |
3484 +-----------------------+
3486 low | arguments on stack |
3487 mem | |
3488 SP+0->+-----------------------+
3490 Notes:
3491 1) The "reg parm save area" does not exist for non variable argument fns.
3492 2) The FP register is not saved if `frame_pointer_needed' is zero and it
3493 is not altered in the current function.
3494 3) The return address is not saved if there is no frame pointer and the
3495 current function is leaf.
3496 4) If the return address is not saved and the static chain register is
3497 live in the function, we allocate the return address slot to be able
3498 to spill the register for a long branch. */
3500 /* Define the register classes for local purposes. */
3501 enum reg_type { general, mdb, mdc, floating, last_type};
3503 #define GET_REG_TYPE(regno) \
3504 (GP_REGISTER_P (regno) ? general : \
3505 (regno) == MDB_REGNUM ? mdb : \
3506 (regno) == MDC_REGNUM ? mdc : \
3507 floating)
3509 /* First regno of each register type. */
3510 const int first_regno[last_type] = {0, MDB_REGNUM, MDC_REGNUM, FP_FIRST_REGNUM};
3512 /* Size in bytes of each register type. */
3513 const int reg_type_size[last_type] = {4, 8, 4, 4};
3515 /* Structure to be filled in by visium_compute_frame_size. */
3516 struct visium_frame_info
3518 unsigned int save_area_size; /* # bytes in the reg parm save area. */
3519 unsigned int reg_size1; /* # bytes to store first block of regs. */
3520 unsigned int reg_size2; /* # bytes to store second block of regs. */
3521 unsigned int max_reg1; /* max. regno in first block */
3522 unsigned int var_size; /* # bytes that variables take up. */
3523 unsigned int save_fp; /* Nonzero if fp must be saved. */
3524 unsigned int save_lr; /* Nonzero if lr must be saved. */
3525 unsigned int lr_slot; /* Nonzero if the lr slot is needed. */
3526 unsigned int combine; /* Nonzero if we can combine the allocation of
3527 variables and regs. */
3528 unsigned int interrupt; /* Nonzero if the function is an interrupt
3529 handler. */
3530 unsigned int mask[last_type]; /* Masks of saved regs: gp, mdb, mdc, fp */
3533 /* Current frame information calculated by visium_compute_frame_size. */
3534 static struct visium_frame_info current_frame_info;
3536 /* Accessor for current_frame_info.save_fp. */
3538 static inline bool
3539 current_function_saves_fp (void)
3541 return current_frame_info.save_fp != 0;
3544 /* Accessor for current_frame_info.save_lr. */
3546 static inline bool
3547 current_function_saves_lr (void)
3549 return current_frame_info.save_lr != 0;
3552 /* Accessor for current_frame_info.lr_slot. */
3554 static inline bool
3555 current_function_has_lr_slot (void)
3557 return current_frame_info.lr_slot != 0;
3560 /* Return non-zero if register REGNO needs to be saved in the frame. */
3562 static int
3563 visium_save_reg_p (int interrupt, int regno)
3565 switch (regno)
3567 case HARD_FRAME_POINTER_REGNUM:
3568 /* This register is call-saved but handled specially. */
3569 return 0;
3571 case MDC_REGNUM:
3572 /* This register is fixed but can be modified. */
3573 break;
3575 case 29:
3576 case 30:
3577 /* These registers are fixed and hold the interrupt context. */
3578 return (interrupt != 0);
3580 default:
3581 /* The other fixed registers are either immutable or special. */
3582 if (fixed_regs[regno])
3583 return 0;
3584 break;
3587 if (interrupt)
3589 if (crtl->is_leaf)
3591 if (df_regs_ever_live_p (regno))
3592 return 1;
3594 else if (call_used_or_fixed_reg_p (regno))
3595 return 1;
3597 /* To save mdb requires two temporary registers. To save mdc or
3598 any of the floating registers requires one temporary
3599 register. If this is an interrupt routine, the temporary
3600 registers need to be saved as well. These temporary registers
3601 are call used, so we only need deal with the case of leaf
3602 functions here. */
3603 if (regno == PROLOGUE_TMP_REGNUM)
3605 if (df_regs_ever_live_p (MDB_REGNUM)
3606 || df_regs_ever_live_p (MDC_REGNUM))
3607 return 1;
3609 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
3610 if (df_regs_ever_live_p (i))
3611 return 1;
3614 else if (regno == PROLOGUE_TMP_REGNUM + 1)
3616 if (df_regs_ever_live_p (MDB_REGNUM))
3617 return 1;
3621 return df_regs_ever_live_p (regno) && !call_used_or_fixed_reg_p (regno);
3624 /* Compute the frame size required by the function. This function is called
3625 during the reload pass and also by visium_expand_prologue. */
3627 static int
3628 visium_compute_frame_size (int size)
3630 const int save_area_size = visium_reg_parm_save_area_size;
3631 const int var_size = VISIUM_STACK_ALIGN (size);
3632 const int save_fp
3633 = frame_pointer_needed || df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM);
3634 const int save_lr = frame_pointer_needed || !crtl->is_leaf;
3635 const int lr_slot = !save_lr && df_regs_ever_live_p (long_branch_regnum);
3636 const int local_frame_offset
3637 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3638 const int interrupt = visium_interrupt_function_p ();
3639 unsigned int mask[last_type];
3640 int reg_size1 = 0;
3641 int max_reg1 = 0;
3642 int reg_size2 = 0;
3643 int reg_size;
3644 int combine;
3645 int frame_size;
3646 int regno;
3648 memset (mask, 0, last_type * sizeof (unsigned int));
3650 /* The registers may need stacking in 2 blocks since only 32 32-bit words
3651 can be indexed from a given base address. */
3652 for (regno = 0; 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 if (reg_size1 + nbytes > 32 * UNITS_PER_WORD)
3661 break;
3663 reg_size1 += nbytes;
3664 max_reg1 = regno;
3665 mask[reg_type] |= mask_bit;
3669 for (regno = max_reg1 + 1; regno < FIRST_PSEUDO_REGISTER; regno++)
3671 if (visium_save_reg_p (interrupt, regno))
3673 enum reg_type reg_type = GET_REG_TYPE (regno);
3674 int mask_bit = 1 << (regno - first_regno[reg_type]);
3675 int nbytes = reg_type_size[reg_type];
3677 reg_size2 += nbytes;
3678 mask[reg_type] |= mask_bit;
3682 reg_size = reg_size2 ? reg_size2 : reg_size1;
3683 combine = (local_frame_offset + var_size + reg_size) <= 32 * UNITS_PER_WORD;
3684 frame_size
3685 = local_frame_offset + var_size + reg_size2 + reg_size1 + save_area_size;
3687 current_frame_info.save_area_size = save_area_size;
3688 current_frame_info.reg_size1 = reg_size1;
3689 current_frame_info.max_reg1 = max_reg1;
3690 current_frame_info.reg_size2 = reg_size2;
3691 current_frame_info.var_size = var_size;
3692 current_frame_info.save_fp = save_fp;
3693 current_frame_info.save_lr = save_lr;
3694 current_frame_info.lr_slot = lr_slot;
3695 current_frame_info.combine = combine;
3696 current_frame_info.interrupt = interrupt;
3698 memcpy (current_frame_info.mask, mask, last_type * sizeof (unsigned int));
3700 return frame_size;
3703 /* Helper function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define
3704 the offset between two registers, one to be eliminated, and the other its
3705 replacement, at the start of a routine. */
3708 visium_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
3710 const int save_fp = current_frame_info.save_fp;
3711 const int save_lr = current_frame_info.save_lr;
3712 const int lr_slot = current_frame_info.lr_slot;
3713 int offset;
3715 if (from == FRAME_POINTER_REGNUM)
3716 offset = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3717 else if (from == ARG_POINTER_REGNUM)
3718 offset = visium_compute_frame_size (get_frame_size ());
3719 else
3720 gcc_unreachable ();
3722 return offset;
3725 /* For an interrupt handler, we may be saving call-clobbered registers.
3726 Say the epilogue uses these in addition to the link register. */
3729 visium_epilogue_uses (int regno)
3731 if (regno == LINK_REGNUM)
3732 return 1;
3734 if (reload_completed)
3736 enum reg_type reg_type = GET_REG_TYPE (regno);
3737 int mask_bit = 1 << (regno - first_regno[reg_type]);
3739 return (current_frame_info.mask[reg_type] & mask_bit) != 0;
3742 return 0;
3745 /* Wrapper around emit_insn that sets RTX_FRAME_RELATED_P on the insn. */
3747 static rtx
3748 emit_frame_insn (rtx x)
3750 x = emit_insn (x);
3751 RTX_FRAME_RELATED_P (x) = 1;
3752 return x;
3755 /* Allocate ALLOC bytes on the stack and save the registers LOW_REGNO to
3756 HIGH_REGNO at OFFSET from the stack pointer. */
3758 static void
3759 visium_save_regs (int alloc, int offset, int low_regno, int high_regno)
3761 /* If this is an interrupt handler function, then mark the register
3762 stores as volatile. This will prevent the instruction scheduler
3763 from scrambling the order of register saves. */
3764 const int volatile_p = current_frame_info.interrupt;
3765 int regno;
3767 /* Allocate the stack space. */
3768 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, stack_pointer_rtx,
3769 GEN_INT (-alloc)));
3771 for (regno = low_regno; regno <= high_regno; regno++)
3773 enum reg_type reg_type = GET_REG_TYPE (regno);
3774 int mask_bit = 1 << (regno - first_regno[reg_type]);
3775 rtx insn;
3777 if (current_frame_info.mask[reg_type] & mask_bit)
3779 offset -= reg_type_size[reg_type];
3780 switch (reg_type)
3782 case general:
3784 rtx mem
3785 = gen_frame_mem (SImode,
3786 plus_constant (Pmode,
3787 stack_pointer_rtx, offset));
3788 MEM_VOLATILE_P (mem) = volatile_p;
3789 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, regno)));
3791 break;
3793 case mdb:
3795 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3796 rtx mem
3797 = gen_frame_mem (DImode,
3798 plus_constant (Pmode,
3799 stack_pointer_rtx, offset));
3800 rtx reg = gen_rtx_REG (DImode, regno);
3801 MEM_VOLATILE_P (mem) = volatile_p;
3802 emit_insn (gen_movdi (tmp, reg));
3803 /* Do not generate CFI if in interrupt handler. */
3804 if (volatile_p)
3805 emit_insn (gen_movdi (mem, tmp));
3806 else
3808 insn = emit_frame_insn (gen_movdi (mem, tmp));
3809 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3810 gen_rtx_SET (mem, reg));
3813 break;
3815 case mdc:
3817 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3818 rtx mem
3819 = gen_frame_mem (SImode,
3820 plus_constant (Pmode,
3821 stack_pointer_rtx, offset));
3822 rtx reg = gen_rtx_REG (SImode, regno);
3823 MEM_VOLATILE_P (mem) = volatile_p;
3824 emit_insn (gen_movsi (tmp, reg));
3825 insn = emit_frame_insn (gen_movsi (mem, tmp));
3826 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3827 gen_rtx_SET (mem, reg));
3829 break;
3831 case floating:
3833 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3834 rtx mem
3835 = gen_frame_mem (SFmode,
3836 plus_constant (Pmode,
3837 stack_pointer_rtx, offset));
3838 rtx reg = gen_rtx_REG (SFmode, regno);
3839 MEM_VOLATILE_P (mem) = volatile_p;
3840 emit_insn (gen_movsf (tmp, reg));
3841 insn = emit_frame_insn (gen_movsf (mem, tmp));
3842 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3843 gen_rtx_SET (mem, reg));
3845 break;
3847 default:
3848 break;
3854 /* This function generates the code for function entry. */
3856 void
3857 visium_expand_prologue (void)
3859 const int frame_size = visium_compute_frame_size (get_frame_size ());
3860 const int save_area_size = current_frame_info.save_area_size;
3861 const int reg_size1 = current_frame_info.reg_size1;
3862 const int max_reg1 = current_frame_info.max_reg1;
3863 const int reg_size2 = current_frame_info.reg_size2;
3864 const int var_size = current_frame_info.var_size;
3865 const int save_fp = current_frame_info.save_fp;
3866 const int save_lr = current_frame_info.save_lr;
3867 const int lr_slot = current_frame_info.lr_slot;
3868 const int local_frame_offset
3869 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3870 const int combine = current_frame_info.combine;
3871 int reg_size;
3872 int first_reg;
3873 int fsize;
3875 /* Save the frame size for future references. */
3876 visium_frame_size = frame_size;
3878 if (flag_stack_usage_info)
3879 current_function_static_stack_size = frame_size;
3881 /* If the registers have to be stacked in 2 blocks, stack the first one. */
3882 if (reg_size2)
3884 visium_save_regs (reg_size1 + save_area_size, reg_size1, 0, max_reg1);
3885 reg_size = reg_size2;
3886 first_reg = max_reg1 + 1;
3887 fsize = local_frame_offset + var_size + reg_size2;
3889 else
3891 reg_size = reg_size1;
3892 first_reg = 0;
3893 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
3896 /* If we can't combine register stacking with variable allocation, partially
3897 allocate and stack the (remaining) registers now. */
3898 if (reg_size && !combine)
3899 visium_save_regs (fsize - local_frame_offset - var_size, reg_size,
3900 first_reg, FIRST_PSEUDO_REGISTER - 1);
3902 /* If we can combine register stacking with variable allocation, fully
3903 allocate and stack the (remaining) registers now. */
3904 if (reg_size && combine)
3905 visium_save_regs (fsize, local_frame_offset + var_size + reg_size,
3906 first_reg, FIRST_PSEUDO_REGISTER - 1);
3908 /* Otherwise space may still need to be allocated for the variables. */
3909 else if (fsize)
3911 const int alloc_size = reg_size ? local_frame_offset + var_size : fsize;
3913 if (alloc_size > 65535)
3915 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM), insn;
3916 emit_insn (gen_movsi (tmp, GEN_INT (alloc_size)));
3917 insn = emit_frame_insn (gen_subsi3_flags (stack_pointer_rtx,
3918 stack_pointer_rtx,
3919 tmp));
3920 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3921 gen_rtx_SET (stack_pointer_rtx,
3922 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3923 GEN_INT (-alloc_size))));
3925 else
3926 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx,
3927 stack_pointer_rtx,
3928 GEN_INT (-alloc_size)));
3931 if (save_fp)
3932 emit_frame_insn (gen_movsi (gen_frame_mem (SImode, stack_pointer_rtx),
3933 hard_frame_pointer_rtx));
3935 if (frame_pointer_needed)
3936 emit_frame_insn (gen_stack_save ());
3938 if (save_lr)
3940 rtx base_rtx, mem;
3942 /* Normally the frame pointer and link register get saved via
3943 write.l (sp),fp
3944 move.l fp,sp
3945 write.l 1(sp),r21
3947 Indexing off sp rather than fp to store the link register
3948 avoids presenting the instruction scheduler with an initial
3949 pipeline hazard. If however the frame is needed for eg.
3950 __builtin_return_address which needs to retrieve the saved
3951 value of the link register from the stack at fp + 4 then
3952 indexing from sp can confuse the dataflow, causing the link
3953 register to be retrieved before it has been saved. */
3954 if (cfun->machine->frame_needed)
3955 base_rtx = hard_frame_pointer_rtx;
3956 else
3957 base_rtx = stack_pointer_rtx;
3959 mem = gen_frame_mem (SImode,
3960 plus_constant (Pmode,
3961 base_rtx, save_fp * UNITS_PER_WORD));
3962 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, LINK_REGNUM)));
3966 static GTY(()) rtx cfa_restores;
3968 /* Queue a REG_CFA_RESTORE note until next stack manipulation insn. */
3970 static void
3971 visium_add_cfa_restore_note (rtx reg)
3973 cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
3976 /* Add queued REG_CFA_RESTORE notes to INSN, if any. */
3978 static void
3979 visium_add_queued_cfa_restore_notes (rtx insn)
3981 rtx last;
3982 if (!cfa_restores)
3983 return;
3984 for (last = cfa_restores; XEXP (last, 1); last = XEXP (last, 1))
3986 XEXP (last, 1) = REG_NOTES (insn);
3987 REG_NOTES (insn) = cfa_restores;
3988 cfa_restores = NULL_RTX;
3991 /* Restore the registers LOW_REGNO to HIGH_REGNO from the save area at OFFSET
3992 from the stack pointer and pop DEALLOC bytes off the stack. */
3994 static void
3995 visium_restore_regs (int dealloc, int offset, int high_regno, int low_regno)
3997 /* If this is an interrupt handler function, then mark the register
3998 restores as volatile. This will prevent the instruction scheduler
3999 from scrambling the order of register restores. */
4000 const int volatile_p = current_frame_info.interrupt;
4001 int r30_offset = -1;
4002 int regno;
4004 for (regno = high_regno; regno >= low_regno; --regno)
4006 enum reg_type reg_type = GET_REG_TYPE (regno);
4007 int mask_bit = 1 << (regno - first_regno[reg_type]);
4009 if (current_frame_info.mask[reg_type] & mask_bit)
4011 switch (reg_type)
4013 case general:
4014 /* Postpone restoring the interrupted context registers
4015 until last, since they need to be preceded by a dsi. */
4016 if (regno == 29)
4018 else if (regno == 30)
4019 r30_offset = offset;
4020 else
4022 rtx mem
4023 = gen_frame_mem (SImode,
4024 plus_constant (Pmode,
4025 stack_pointer_rtx,
4026 offset));
4027 rtx reg = gen_rtx_REG (SImode, regno);
4028 MEM_VOLATILE_P (mem) = volatile_p;
4029 emit_insn (gen_movsi (reg, mem));
4030 visium_add_cfa_restore_note (reg);
4032 break;
4034 case mdb:
4036 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
4037 rtx mem
4038 = gen_frame_mem (DImode,
4039 plus_constant (Pmode,
4040 stack_pointer_rtx, offset));
4041 rtx reg = gen_rtx_REG (DImode, regno);
4042 MEM_VOLATILE_P (mem) = volatile_p;
4043 emit_insn (gen_movdi (tmp, mem));
4044 emit_insn (gen_movdi (reg, tmp));
4045 /* Do not generate CFI if in interrupt handler. */
4046 if (!volatile_p)
4047 visium_add_cfa_restore_note (reg);
4049 break;
4051 case mdc:
4053 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4054 rtx mem
4055 = gen_frame_mem (SImode,
4056 plus_constant (Pmode,
4057 stack_pointer_rtx, offset));
4058 rtx reg = gen_rtx_REG (SImode, regno);
4059 MEM_VOLATILE_P (mem) = volatile_p;
4060 emit_insn (gen_movsi (tmp, mem));
4061 emit_insn (gen_movsi (reg, tmp));
4062 visium_add_cfa_restore_note (reg);
4064 break;
4066 case floating:
4068 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
4069 rtx mem
4070 = gen_frame_mem (SFmode,
4071 plus_constant (Pmode,
4072 stack_pointer_rtx, offset));
4073 rtx reg = gen_rtx_REG (SFmode, regno);
4074 MEM_VOLATILE_P (mem) = volatile_p;
4075 emit_insn (gen_movsf (tmp, mem));
4076 emit_insn (gen_movsf (reg, tmp));
4077 visium_add_cfa_restore_note (reg);
4079 break;
4081 default:
4082 break;
4085 offset += reg_type_size[reg_type];
4089 /* If the interrupted context needs to be restored, precede the
4090 restores of r29 and r30 by a dsi. */
4091 if (r30_offset >= 0)
4093 emit_insn (gen_dsi ());
4094 emit_move_insn (gen_rtx_REG (SImode, 30),
4095 gen_frame_mem (SImode,
4096 plus_constant (Pmode,
4097 stack_pointer_rtx,
4098 r30_offset)));
4099 emit_move_insn (gen_rtx_REG (SImode, 29),
4100 gen_frame_mem (SImode,
4101 plus_constant (Pmode,
4102 stack_pointer_rtx,
4103 r30_offset + 4)));
4106 /* Deallocate the stack space. */
4107 rtx insn = emit_frame_insn (gen_stack_pop (GEN_INT (dealloc)));
4108 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4109 gen_rtx_SET (stack_pointer_rtx,
4110 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4111 GEN_INT (dealloc))));
4112 visium_add_queued_cfa_restore_notes (insn);
4115 /* This function generates the code for function exit. */
4117 void
4118 visium_expand_epilogue (void)
4120 const int save_area_size = current_frame_info.save_area_size;
4121 const int reg_size1 = current_frame_info.reg_size1;
4122 const int max_reg1 = current_frame_info.max_reg1;
4123 const int reg_size2 = current_frame_info.reg_size2;
4124 const int var_size = current_frame_info.var_size;
4125 const int restore_fp = current_frame_info.save_fp;
4126 const int restore_lr = current_frame_info.save_lr;
4127 const int lr_slot = current_frame_info.lr_slot;
4128 const int local_frame_offset
4129 = (restore_fp + restore_lr + lr_slot) * UNITS_PER_WORD;
4130 const int combine = current_frame_info.combine;
4131 int reg_size;
4132 int last_reg;
4133 int fsize;
4135 /* Do not bother restoring the stack pointer if it hasn't been changed in
4136 the function since it was saved _after_ the allocation of the frame. */
4137 if (!crtl->sp_is_unchanging)
4138 emit_insn (gen_stack_restore ());
4140 /* Restore the frame pointer if necessary. The usual code would be:
4142 move.l sp,fp
4143 read.l fp,(sp)
4145 but for the MCM this constitutes a stall/hazard so it is changed to:
4147 move.l sp,fp
4148 read.l fp,(fp)
4150 if the stack pointer has actually been restored. */
4151 if (restore_fp)
4153 rtx src;
4155 if (TARGET_MCM && !crtl->sp_is_unchanging)
4156 src = gen_frame_mem (SImode, hard_frame_pointer_rtx);
4157 else
4158 src = gen_frame_mem (SImode, stack_pointer_rtx);
4160 rtx insn = emit_frame_insn (gen_movsi (hard_frame_pointer_rtx, src));
4161 add_reg_note (insn, REG_CFA_ADJUST_CFA,
4162 gen_rtx_SET (stack_pointer_rtx,
4163 hard_frame_pointer_rtx));
4164 visium_add_cfa_restore_note (hard_frame_pointer_rtx);
4167 /* Restore the link register if necessary. */
4168 if (restore_lr)
4170 rtx mem = gen_frame_mem (SImode,
4171 plus_constant (Pmode,
4172 stack_pointer_rtx,
4173 restore_fp * UNITS_PER_WORD));
4174 rtx reg = gen_rtx_REG (SImode, LINK_REGNUM);
4175 emit_insn (gen_movsi (reg, mem));
4176 visium_add_cfa_restore_note (reg);
4179 /* If we have two blocks of registers, deal with the second one first. */
4180 if (reg_size2)
4182 reg_size = reg_size2;
4183 last_reg = max_reg1 + 1;
4184 fsize = local_frame_offset + var_size + reg_size2;
4186 else
4188 reg_size = reg_size1;
4189 last_reg = 0;
4190 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
4193 /* If the variable allocation could be combined with register stacking,
4194 restore the (remaining) registers and fully deallocate now. */
4195 if (reg_size && combine)
4196 visium_restore_regs (fsize, local_frame_offset + var_size,
4197 FIRST_PSEUDO_REGISTER - 1, last_reg);
4199 /* Otherwise deallocate the variables first. */
4200 else if (fsize)
4202 const int pop_size = reg_size ? local_frame_offset + var_size : fsize;
4203 rtx insn;
4205 if (pop_size > 65535)
4207 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4208 emit_move_insn (tmp, GEN_INT (pop_size));
4209 insn = emit_frame_insn (gen_stack_pop (tmp));
4211 else
4212 insn = emit_frame_insn (gen_stack_pop (GEN_INT (pop_size)));
4213 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4214 gen_rtx_SET (stack_pointer_rtx,
4215 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4216 GEN_INT (pop_size))));
4217 visium_add_queued_cfa_restore_notes (insn);
4220 /* If the variable allocation couldn't be combined with register stacking,
4221 restore the (remaining) registers now and partially deallocate. */
4222 if (reg_size && !combine)
4223 visium_restore_regs (fsize - local_frame_offset - var_size, 0,
4224 FIRST_PSEUDO_REGISTER - 1, last_reg);
4226 /* If the first block of registers has yet to be restored, do it now. */
4227 if (reg_size2)
4228 visium_restore_regs (reg_size1 + save_area_size, 0, max_reg1, 0);
4230 /* If this is an exception return, make the necessary stack adjustment. */
4231 if (crtl->calls_eh_return)
4232 emit_insn (gen_stack_pop (EH_RETURN_STACKADJ_RTX));
4235 /* Return true if it is appropriate to emit `return' instructions in the
4236 body of a function. */
4238 bool
4239 visium_can_use_return_insn_p (void)
4241 return reload_completed
4242 && visium_frame_size == 0
4243 && !visium_interrupt_function_p ();
4246 /* Return the register class required for an intermediate register used to
4247 copy a register of RCLASS from/to X. If no such intermediate register is
4248 required, return NO_REGS. If more than one such intermediate register is
4249 required, describe the one that is closest in the copy chain to the reload
4250 register. */
4252 static reg_class_t
4253 visium_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
4254 reg_class_t rclass,
4255 machine_mode mode ATTRIBUTE_UNUSED,
4256 secondary_reload_info *sri ATTRIBUTE_UNUSED)
4258 int regno = true_regnum (x);
4260 /* For MDB, MDC and FP_REGS, a general register is needed for a move to
4261 or from memory. */
4262 if (regno == -1 && (rclass == MDB || rclass == MDC || rclass == FP_REGS))
4263 return GENERAL_REGS;
4265 /* Moves between MDB, MDC and FP_REGS also require a general register. */
4266 else if (((regno == R_MDB || regno == R_MDC) && rclass == FP_REGS)
4267 || (FP_REGISTER_P (regno) && (rclass == MDB || rclass == MDC)))
4268 return GENERAL_REGS;
4270 /* Finally an (unlikely ?) move between MDB and MDC needs a general reg. */
4271 else if ((regno == R_MDB && rclass == MDC)
4272 || (rclass == MDB && regno == R_MDC))
4273 return GENERAL_REGS;
4275 return NO_REGS;
4278 /* Return true if pseudos that have been assigned to registers of RCLASS
4279 would likely be spilled because registers of RCLASS are needed for
4280 spill registers. */
4282 static bool
4283 visium_class_likely_spilled_p (reg_class_t rclass ATTRIBUTE_UNUSED)
4285 /* Return false for classes R1, R2 and R3, which are intended to be used
4286 only in the source code in conjunction with block move instructions. */
4287 return false;
4290 /* Return the register number if OP is a REG or a SUBREG of a REG, and
4291 INVALID_REGNUM in all the other cases. */
4293 unsigned int
4294 reg_or_subreg_regno (rtx op)
4296 unsigned int regno;
4298 if (GET_CODE (op) == REG)
4299 regno = REGNO (op);
4300 else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
4302 if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
4303 regno = subreg_regno (op);
4304 else
4305 regno = REGNO (SUBREG_REG (op));
4307 else
4308 regno = INVALID_REGNUM;
4310 return regno;
4313 /* Implement TARGET_CAN_CHANGE_MODE_CLASS.
4315 It's not obvious from the documentation of the hook that MDB cannot
4316 change mode. However difficulties arise from expressions of the form
4318 (subreg:SI (reg:DI R_MDB) 0)
4320 There is no way to convert that reference to a single machine
4321 register and, without the following definition, reload will quietly
4322 convert it to
4324 (reg:SI R_MDB). */
4326 static bool
4327 visium_can_change_mode_class (machine_mode from, machine_mode to,
4328 reg_class_t rclass)
4330 return (rclass != MDB || GET_MODE_SIZE (from) == GET_MODE_SIZE (to));
4333 #include "gt-visium.h"