Make more use of end_hard_regno
[official-gcc.git] / gcc / config / visium / visium.c
blobf3016f9bda7467e3c7f00f4baf5865d3f7126da5
1 /* Output routines for Visium.
2 Copyright (C) 2002-2017 Free Software Foundation, Inc.
3 Contributed by C.Nettleton, J.P.Parkes and P.Garbett.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "target.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "gimple-expr.h"
29 #include "df.h"
30 #include "memmodel.h"
31 #include "tm_p.h"
32 #include "stringpool.h"
33 #include "attribs.h"
34 #include "expmed.h"
35 #include "optabs.h"
36 #include "regs.h"
37 #include "emit-rtl.h"
38 #include "recog.h"
39 #include "diagnostic-core.h"
40 #include "alias.h"
41 #include "flags.h"
42 #include "fold-const.h"
43 #include "stor-layout.h"
44 #include "calls.h"
45 #include "varasm.h"
46 #include "output.h"
47 #include "insn-attr.h"
48 #include "explow.h"
49 #include "expr.h"
50 #include "gimplify.h"
51 #include "langhooks.h"
52 #include "reload.h"
53 #include "tm-constrs.h"
54 #include "params.h"
55 #include "tree-pass.h"
56 #include "context.h"
57 #include "builtins.h"
59 /* This file should be included last. */
60 #include "target-def.h"
62 /* Enumeration of indexes into machine_libfunc_table. */
63 enum machine_libfunc_index
65 MLTI_long_int_memcpy,
66 MLTI_wrd_memcpy,
67 MLTI_byt_memcpy,
69 MLTI_long_int_memset,
70 MLTI_wrd_memset,
71 MLTI_byt_memset,
73 MLTI_set_trampoline_parity,
75 MLTI_MAX
78 struct GTY(()) machine_libfuncs
80 rtx table[MLTI_MAX];
83 /* The table of Visium-specific libfuncs. */
84 static GTY(()) struct machine_libfuncs visium_libfuncs;
86 #define vlt visium_libfuncs.table
88 /* Accessor macros for visium_libfuncs. */
89 #define long_int_memcpy_libfunc (vlt[MLTI_long_int_memcpy])
90 #define wrd_memcpy_libfunc (vlt[MLTI_wrd_memcpy])
91 #define byt_memcpy_libfunc (vlt[MLTI_byt_memcpy])
92 #define long_int_memset_libfunc (vlt[MLTI_long_int_memset])
93 #define wrd_memset_libfunc (vlt[MLTI_wrd_memset])
94 #define byt_memset_libfunc (vlt[MLTI_byt_memset])
95 #define set_trampoline_parity_libfunc (vlt[MLTI_set_trampoline_parity])
97 /* Machine specific function data. */
98 struct GTY (()) machine_function
100 /* Size of the frame of the function. */
101 int frame_size;
103 /* Size of the reg parm save area, non-zero only for functions with variable
104 argument list. We cannot use the crtl->args.pretend_args_size machinery
105 for this purpose because this size is added to virtual_incoming_args_rtx
106 to give the location of the first parameter passed by the caller on the
107 stack and virtual_incoming_args_rtx is also the location of the first
108 parameter on the stack. So crtl->args.pretend_args_size can be non-zero
109 only if the first non-register named parameter is not passed entirely on
110 the stack and this runs afoul of the need to have a reg parm save area
111 even with a variable argument list starting on the stack because of the
112 separate handling of general and floating-point registers. */
113 int reg_parm_save_area_size;
115 /* True if we have created an rtx which relies on the frame pointer. */
116 bool frame_needed;
118 /* True if we have exposed the flags register. From this moment on, we
119 cannot generate simple operations for integer registers. We could
120 use reload_completed for this purpose, but this would cripple the
121 postreload CSE and GCSE passes which run before postreload split. */
122 bool flags_exposed;
125 #define visium_frame_size cfun->machine->frame_size
126 #define visium_reg_parm_save_area_size cfun->machine->reg_parm_save_area_size
127 #define visium_frame_needed cfun->machine->frame_needed
128 #define visium_flags_exposed cfun->machine->flags_exposed
130 /* 1 if the next opcode is to be specially indented. */
131 int visium_indent_opcode = 0;
133 /* Register number used for long branches when LR isn't available. It
134 must be a call-used register since it isn't saved on function entry.
135 We do not care whether the branch is predicted or not on the GR6,
136 given how unlikely it is to have a long branch in a leaf function. */
137 static unsigned int long_branch_regnum = 31;
139 static tree visium_handle_interrupt_attr (tree *, tree, tree, int, bool *);
140 static inline bool current_function_saves_fp (void);
141 static inline bool current_function_saves_lr (void);
142 static inline bool current_function_has_lr_slot (void);
144 /* Supported attributes:
145 interrupt -- specifies this function is an interrupt handler. */
146 static const struct attribute_spec visium_attribute_table[] =
148 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
149 affects_type_identity } */
150 {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false},
151 {NULL, 0, 0, false, false, false, NULL, false}
154 static struct machine_function *visium_init_machine_status (void);
156 /* Target hooks and TARGET_INITIALIZER */
158 static bool visium_pass_by_reference (cumulative_args_t, machine_mode,
159 const_tree, bool);
161 static rtx visium_function_arg (cumulative_args_t, machine_mode,
162 const_tree, bool);
164 static void visium_function_arg_advance (cumulative_args_t, machine_mode,
165 const_tree, bool);
167 static bool visium_return_in_memory (const_tree, const_tree fntype);
169 static rtx visium_function_value (const_tree, const_tree fn_decl_or_type,
170 bool);
172 static rtx visium_libcall_value (machine_mode, const_rtx);
174 static void visium_setup_incoming_varargs (cumulative_args_t,
175 machine_mode,
176 tree, int *, int);
178 static void visium_va_start (tree valist, rtx nextarg);
180 static tree visium_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
182 static bool visium_function_ok_for_sibcall (tree, tree);
184 static bool visium_frame_pointer_required (void);
186 static tree visium_build_builtin_va_list (void);
188 static rtx_insn *visium_md_asm_adjust (vec<rtx> &, vec<rtx> &,
189 vec<const char *> &,
190 vec<rtx> &, HARD_REG_SET &);
192 static bool visium_legitimate_constant_p (machine_mode, rtx);
194 static bool visium_legitimate_address_p (machine_mode, rtx, bool);
196 static bool visium_print_operand_punct_valid_p (unsigned char);
197 static void visium_print_operand (FILE *, rtx, int);
198 static void visium_print_operand_address (FILE *, machine_mode, rtx);
200 static void visium_conditional_register_usage (void);
202 static rtx visium_legitimize_address (rtx, rtx, machine_mode);
204 static reg_class_t visium_secondary_reload (bool, rtx, reg_class_t,
205 machine_mode,
206 secondary_reload_info *);
208 static bool visium_class_likely_spilled_p (reg_class_t);
210 static void visium_trampoline_init (rtx, tree, rtx);
212 static int visium_issue_rate (void);
214 static int visium_adjust_priority (rtx_insn *, int);
216 static int visium_adjust_cost (rtx_insn *, int, rtx_insn *, int, unsigned int);
218 static int visium_register_move_cost (machine_mode, reg_class_t,
219 reg_class_t);
221 static int visium_memory_move_cost (machine_mode, reg_class_t, bool);
223 static bool visium_rtx_costs (rtx, machine_mode, int, int, int *, bool);
225 static void visium_option_override (void);
227 static void visium_init_libfuncs (void);
229 static unsigned int visium_reorg (void);
231 static bool visium_hard_regno_mode_ok (unsigned int, machine_mode);
233 static bool visium_modes_tieable_p (machine_mode, machine_mode);
235 /* Setup the global target hooks structure. */
237 #undef TARGET_MAX_ANCHOR_OFFSET
238 #define TARGET_MAX_ANCHOR_OFFSET 31
240 #undef TARGET_PASS_BY_REFERENCE
241 #define TARGET_PASS_BY_REFERENCE visium_pass_by_reference
243 #undef TARGET_FUNCTION_ARG
244 #define TARGET_FUNCTION_ARG visium_function_arg
246 #undef TARGET_FUNCTION_ARG_ADVANCE
247 #define TARGET_FUNCTION_ARG_ADVANCE visium_function_arg_advance
249 #undef TARGET_RETURN_IN_MEMORY
250 #define TARGET_RETURN_IN_MEMORY visium_return_in_memory
252 #undef TARGET_FUNCTION_VALUE
253 #define TARGET_FUNCTION_VALUE visium_function_value
255 #undef TARGET_LIBCALL_VALUE
256 #define TARGET_LIBCALL_VALUE visium_libcall_value
258 #undef TARGET_SETUP_INCOMING_VARARGS
259 #define TARGET_SETUP_INCOMING_VARARGS visium_setup_incoming_varargs
261 #undef TARGET_EXPAND_BUILTIN_VA_START
262 #define TARGET_EXPAND_BUILTIN_VA_START visium_va_start
264 #undef TARGET_BUILD_BUILTIN_VA_LIST
265 #define TARGET_BUILD_BUILTIN_VA_LIST visium_build_builtin_va_list
267 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
268 #define TARGET_GIMPLIFY_VA_ARG_EXPR visium_gimplify_va_arg
270 #undef TARGET_LEGITIMATE_CONSTANT_P
271 #define TARGET_LEGITIMATE_CONSTANT_P visium_legitimate_constant_p
273 #undef TARGET_LRA_P
274 #define TARGET_LRA_P hook_bool_void_false
276 #undef TARGET_LEGITIMATE_ADDRESS_P
277 #define TARGET_LEGITIMATE_ADDRESS_P visium_legitimate_address_p
279 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
280 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P visium_print_operand_punct_valid_p
281 #undef TARGET_PRINT_OPERAND
282 #define TARGET_PRINT_OPERAND visium_print_operand
283 #undef TARGET_PRINT_OPERAND_ADDRESS
284 #define TARGET_PRINT_OPERAND_ADDRESS visium_print_operand_address
286 #undef TARGET_ATTRIBUTE_TABLE
287 #define TARGET_ATTRIBUTE_TABLE visium_attribute_table
289 #undef TARGET_ADDRESS_COST
290 #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
292 #undef TARGET_STRICT_ARGUMENT_NAMING
293 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
295 #undef TARGET_SCHED_ISSUE_RATE
296 #define TARGET_SCHED_ISSUE_RATE visium_issue_rate
298 #undef TARGET_SCHED_ADJUST_PRIORITY
299 #define TARGET_SCHED_ADJUST_PRIORITY visium_adjust_priority
301 #undef TARGET_SCHED_ADJUST_COST
302 #define TARGET_SCHED_ADJUST_COST visium_adjust_cost
304 #undef TARGET_MEMORY_MOVE_COST
305 #define TARGET_MEMORY_MOVE_COST visium_memory_move_cost
307 #undef TARGET_REGISTER_MOVE_COST
308 #define TARGET_REGISTER_MOVE_COST visium_register_move_cost
310 #undef TARGET_RTX_COSTS
311 #define TARGET_RTX_COSTS visium_rtx_costs
313 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
314 #define TARGET_FUNCTION_OK_FOR_SIBCALL visium_function_ok_for_sibcall
316 #undef TARGET_FRAME_POINTER_REQUIRED
317 #define TARGET_FRAME_POINTER_REQUIRED visium_frame_pointer_required
319 #undef TARGET_SECONDARY_RELOAD
320 #define TARGET_SECONDARY_RELOAD visium_secondary_reload
322 #undef TARGET_CLASS_LIKELY_SPILLED_P
323 #define TARGET_CLASS_LIKELY_SPILLED_P visium_class_likely_spilled_p
325 #undef TARGET_LEGITIMIZE_ADDRESS
326 #define TARGET_LEGITIMIZE_ADDRESS visium_legitimize_address
328 #undef TARGET_OPTION_OVERRIDE
329 #define TARGET_OPTION_OVERRIDE visium_option_override
331 #undef TARGET_INIT_LIBFUNCS
332 #define TARGET_INIT_LIBFUNCS visium_init_libfuncs
334 #undef TARGET_CONDITIONAL_REGISTER_USAGE
335 #define TARGET_CONDITIONAL_REGISTER_USAGE visium_conditional_register_usage
337 #undef TARGET_TRAMPOLINE_INIT
338 #define TARGET_TRAMPOLINE_INIT visium_trampoline_init
340 #undef TARGET_MD_ASM_ADJUST
341 #define TARGET_MD_ASM_ADJUST visium_md_asm_adjust
343 #undef TARGET_FLAGS_REGNUM
344 #define TARGET_FLAGS_REGNUM FLAGS_REGNUM
346 #undef TARGET_HARD_REGNO_MODE_OK
347 #define TARGET_HARD_REGNO_MODE_OK visium_hard_regno_mode_ok
349 #undef TARGET_MODES_TIEABLE_P
350 #define TARGET_MODES_TIEABLE_P visium_modes_tieable_p
352 struct gcc_target targetm = TARGET_INITIALIZER;
354 namespace {
356 const pass_data pass_data_visium_reorg =
358 RTL_PASS, /* type */
359 "mach2", /* name */
360 OPTGROUP_NONE, /* optinfo_flags */
361 TV_MACH_DEP, /* tv_id */
362 0, /* properties_required */
363 0, /* properties_provided */
364 0, /* properties_destroyed */
365 0, /* todo_flags_start */
366 0, /* todo_flags_finish */
369 class pass_visium_reorg : public rtl_opt_pass
371 public:
372 pass_visium_reorg(gcc::context *ctxt)
373 : rtl_opt_pass(pass_data_visium_reorg, ctxt)
376 /* opt_pass methods: */
377 virtual unsigned int execute (function *)
379 return visium_reorg ();
382 }; // class pass_work_around_errata
384 } // anon namespace
386 rtl_opt_pass *
387 make_pass_visium_reorg (gcc::context *ctxt)
389 return new pass_visium_reorg (ctxt);
392 /* Options override for Visium. */
394 static void
395 visium_option_override (void)
397 if (flag_pic == 1)
398 warning (OPT_fpic, "-fpic is not supported");
399 if (flag_pic == 2)
400 warning (OPT_fPIC, "-fPIC is not supported");
402 /* MCM is the default in the GR5/GR6 era. */
403 target_flags |= MASK_MCM;
405 /* FPU is the default with MCM, but don't override an explicit option. */
406 if ((target_flags_explicit & MASK_FPU) == 0)
407 target_flags |= MASK_FPU;
409 /* The supervisor mode is the default. */
410 if ((target_flags_explicit & MASK_SV_MODE) == 0)
411 target_flags |= MASK_SV_MODE;
413 /* The GR6 has the Block Move Instructions and an IEEE-compliant FPU. */
414 if (visium_cpu_and_features == PROCESSOR_GR6)
416 target_flags |= MASK_BMI;
417 if (target_flags & MASK_FPU)
418 target_flags |= MASK_FPU_IEEE;
421 /* Set -mtune from -mcpu if not specified. */
422 if (!global_options_set.x_visium_cpu)
423 visium_cpu = visium_cpu_and_features;
425 /* Align functions on 256-byte (32-quadword) for GR5 and 64-byte (8-quadword)
426 boundaries for GR6 so they start a new burst mode window. */
427 if (align_functions == 0)
429 if (visium_cpu == PROCESSOR_GR6)
430 align_functions = 64;
431 else
432 align_functions = 256;
434 /* Allow the size of compilation units to double because of inlining.
435 In practice the global size of the object code is hardly affected
436 because the additional instructions will take up the padding. */
437 maybe_set_param_value (PARAM_INLINE_UNIT_GROWTH, 100,
438 global_options.x_param_values,
439 global_options_set.x_param_values);
442 /* Likewise for loops. */
443 if (align_loops == 0)
445 if (visium_cpu == PROCESSOR_GR6)
446 align_loops = 64;
447 else
449 align_loops = 256;
450 /* But not if they are too far away from a 256-byte boundary. */
451 align_loops_max_skip = 31;
455 /* Align all jumps on quadword boundaries for the burst mode, and even
456 on 8-quadword boundaries for GR6 so they start a new window. */
457 if (align_jumps == 0)
459 if (visium_cpu == PROCESSOR_GR6)
460 align_jumps = 64;
461 else
462 align_jumps = 8;
465 /* We register a machine-specific pass. This pass must be scheduled as
466 late as possible so that we have the (essentially) final form of the
467 insn stream to work on. Registering the pass must be done at start up.
468 It's convenient to do it here. */
469 opt_pass *visium_reorg_pass = make_pass_visium_reorg (g);
470 struct register_pass_info insert_pass_visium_reorg =
472 visium_reorg_pass, /* pass */
473 "dbr", /* reference_pass_name */
474 1, /* ref_pass_instance_number */
475 PASS_POS_INSERT_AFTER /* po_op */
477 register_pass (&insert_pass_visium_reorg);
480 /* Register the Visium-specific libfuncs with the middle-end. */
482 static void
483 visium_init_libfuncs (void)
485 if (!TARGET_BMI)
486 long_int_memcpy_libfunc = init_one_libfunc ("__long_int_memcpy");
487 wrd_memcpy_libfunc = init_one_libfunc ("__wrd_memcpy");
488 byt_memcpy_libfunc = init_one_libfunc ("__byt_memcpy");
490 long_int_memset_libfunc = init_one_libfunc ("__long_int_memset");
491 wrd_memset_libfunc = init_one_libfunc ("__wrd_memset");
492 byt_memset_libfunc = init_one_libfunc ("__byt_memset");
494 set_trampoline_parity_libfunc = init_one_libfunc ("__set_trampoline_parity");
497 /* Return the number of instructions that can issue on the same cycle. */
499 static int
500 visium_issue_rate (void)
502 switch (visium_cpu)
504 case PROCESSOR_GR5:
505 return 1;
507 case PROCESSOR_GR6:
508 return 2;
510 default:
511 gcc_unreachable ();
515 /* Return the adjusted PRIORITY of INSN. */
517 static int
518 visium_adjust_priority (rtx_insn *insn, int priority)
520 /* On the GR5, we slightly increase the priority of writes in order to avoid
521 scheduling a read on the next cycle. This is necessary in addition to the
522 associated insn reservation because there are no data dependencies.
523 We also slightly increase the priority of reads from ROM in order to group
524 them as much as possible. These reads are a bit problematic because they
525 conflict with the instruction fetches, i.e. the data and instruction buses
526 tread on each other's toes when they are executed. */
527 if (visium_cpu == PROCESSOR_GR5
528 && reload_completed
529 && INSN_P (insn)
530 && recog_memoized (insn) >= 0)
532 enum attr_type attr_type = get_attr_type (insn);
533 if (attr_type == TYPE_REG_MEM
534 || (attr_type == TYPE_MEM_REG
535 && MEM_READONLY_P (SET_SRC (PATTERN (insn)))))
536 return priority + 1;
539 return priority;
542 /* Adjust the cost of a scheduling dependency. Return the new cost of
543 a dependency LINK of INSN on DEP_INSN. COST is the current cost. */
545 static int
546 visium_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost,
547 unsigned int)
549 enum attr_type attr_type;
551 /* Don't adjust costs for true dependencies as they are described with
552 bypasses. But we make an exception for the first scheduling pass to
553 help the subsequent postreload compare elimination pass. */
554 if (dep_type == REG_DEP_TRUE)
556 if (!reload_completed
557 && recog_memoized (insn) >= 0
558 && get_attr_type (insn) == TYPE_CMP)
560 rtx pat = PATTERN (insn);
561 gcc_assert (GET_CODE (pat) == SET);
562 rtx src = SET_SRC (pat);
564 /* Only the branches can be modified by the postreload compare
565 elimination pass, not the cstores because they accept only
566 unsigned comparison operators and they are eliminated if
567 one of the operands is zero. */
568 if (GET_CODE (src) == IF_THEN_ELSE
569 && XEXP (XEXP (src, 0), 1) == const0_rtx
570 && recog_memoized (dep_insn) >= 0)
572 enum attr_type dep_attr_type = get_attr_type (dep_insn);
574 /* The logical instructions use CCmode and thus work with any
575 comparison operator, whereas the arithmetic instructions use
576 CCNZmode and thus work with only a small subset. */
577 if (dep_attr_type == TYPE_LOGIC
578 || (dep_attr_type == TYPE_ARITH
579 && visium_nz_comparison_operator (XEXP (src, 0),
580 GET_MODE
581 (XEXP (src, 0)))))
582 return 0;
586 return cost;
589 if (recog_memoized (insn) < 0)
590 return 0;
592 attr_type = get_attr_type (insn);
594 /* Anti dependency: DEP_INSN reads a register that INSN writes some
595 cycles later. */
596 if (dep_type == REG_DEP_ANTI)
598 /* On the GR5, the latency of FP instructions needs to be taken into
599 account for every dependency involving a write. */
600 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
602 /* INSN is FLOAD. */
603 rtx pat = PATTERN (insn);
604 rtx dep_pat = PATTERN (dep_insn);
606 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
607 /* If this happens, we have to extend this to schedule
608 optimally. Return 0 for now. */
609 return 0;
611 if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
613 if (recog_memoized (dep_insn) < 0)
614 return 0;
616 switch (get_attr_type (dep_insn))
618 case TYPE_FDIV:
619 case TYPE_FSQRT:
620 case TYPE_FTOI:
621 case TYPE_ITOF:
622 case TYPE_FP:
623 case TYPE_FMOVE:
624 /* A fload can't be issued until a preceding arithmetic
625 operation has finished if the target of the fload is
626 any of the sources (or destination) of the arithmetic
627 operation. Note that the latency may be (much)
628 greater than this if the preceding instruction
629 concerned is in a queue. */
630 return insn_default_latency (dep_insn);
632 default:
633 return 0;
638 /* On the GR6, we try to make sure that the link register is restored
639 sufficiently ahead of the return as to yield a correct prediction
640 from the branch predictor. By default there is no true dependency
641 but an anti dependency between them, so we simply reuse it. */
642 else if (attr_type == TYPE_RET && visium_cpu == PROCESSOR_GR6)
644 rtx dep_pat = PATTERN (dep_insn);
645 if (GET_CODE (dep_pat) == SET
646 && REG_P (SET_DEST (dep_pat))
647 && REGNO (SET_DEST (dep_pat)) == LINK_REGNUM)
648 return 8;
651 /* For other anti dependencies, the cost is 0. */
652 return 0;
655 /* Output dependency: DEP_INSN writes a register that INSN writes some
656 cycles later. */
657 else if (dep_type == REG_DEP_OUTPUT)
659 /* On the GR5, the latency of FP instructions needs to be taken into
660 account for every dependency involving a write. */
661 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
663 /* INSN is FLOAD. */
664 rtx pat = PATTERN (insn);
665 rtx dep_pat = PATTERN (dep_insn);
667 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
668 /* If this happens, we have to extend this to schedule
669 optimally. Return 0 for now. */
670 return 0;
672 if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat)))
674 if (recog_memoized (dep_insn) < 0)
675 return 0;
677 switch (get_attr_type (dep_insn))
679 case TYPE_FDIV:
680 case TYPE_FSQRT:
681 case TYPE_FTOI:
682 case TYPE_ITOF:
683 case TYPE_FP:
684 case TYPE_FMOVE:
685 /* A fload can't be issued until a preceding arithmetic
686 operation has finished if the target of the fload is
687 the destination of the arithmetic operation. Note that
688 the latency may be (much) greater than this if the
689 preceding instruction concerned is in a queue. */
690 return insn_default_latency (dep_insn);
692 default:
693 return 0;
698 /* For other output dependencies, the cost is 0. */
699 return 0;
702 return 0;
705 /* Handle an "interrupt_handler" attribute; arguments as in
706 struct attribute_spec.handler. */
708 static tree
709 visium_handle_interrupt_attr (tree *node, tree name,
710 tree args ATTRIBUTE_UNUSED,
711 int flags ATTRIBUTE_UNUSED,
712 bool *no_add_attrs)
714 if (TREE_CODE (*node) != FUNCTION_DECL)
716 warning (OPT_Wattributes, "%qE attribute only applies to functions",
717 name);
718 *no_add_attrs = true;
720 else if (!TARGET_SV_MODE)
722 error ("an interrupt handler cannot be compiled with -muser-mode");
723 *no_add_attrs = true;
726 return NULL_TREE;
729 /* Return non-zero if the current function is an interrupt function. */
732 visium_interrupt_function_p (void)
734 return
735 lookup_attribute ("interrupt",
736 DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
739 /* Conditionally modify the settings of the register file. */
741 static void
742 visium_conditional_register_usage (void)
744 /* If the supervisor mode is disabled, mask some general registers. */
745 if (!TARGET_SV_MODE)
747 if (visium_cpu_and_features == PROCESSOR_GR5)
749 fixed_regs[24] = call_used_regs[24] = 1;
750 fixed_regs[25] = call_used_regs[25] = 1;
751 fixed_regs[26] = call_used_regs[26] = 1;
752 fixed_regs[27] = call_used_regs[27] = 1;
753 fixed_regs[28] = call_used_regs[28] = 1;
754 call_really_used_regs[24] = 0;
755 call_really_used_regs[25] = 0;
756 call_really_used_regs[26] = 0;
757 call_really_used_regs[27] = 0;
758 call_really_used_regs[28] = 0;
761 fixed_regs[31] = call_used_regs[31] = 1;
762 call_really_used_regs[31] = 0;
764 /* We also need to change the long-branch register. */
765 if (visium_cpu_and_features == PROCESSOR_GR5)
766 long_branch_regnum = 20;
767 else
768 long_branch_regnum = 28;
771 /* If the FPU is disabled, mask the FP registers. */
772 if (!TARGET_FPU)
774 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
776 fixed_regs[i] = call_used_regs[i] = 1;
777 call_really_used_regs[i] = 0;
782 /* Prepend to CLOBBERS hard registers that are automatically clobbered for
783 an asm We do this for the FLAGS to maintain source compatibility with
784 the original cc0-based compiler. */
786 static rtx_insn *
787 visium_md_asm_adjust (vec<rtx> &/*outputs*/, vec<rtx> &/*inputs*/,
788 vec<const char *> &/*constraints*/,
789 vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs)
791 clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REGNUM));
792 SET_HARD_REG_BIT (clobbered_regs, FLAGS_REGNUM);
793 return NULL;
796 /* Return true if X is a legitimate constant for a MODE immediate operand.
797 X is guaranteed to satisfy the CONSTANT_P predicate. */
799 static bool
800 visium_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED,
801 rtx x ATTRIBUTE_UNUSED)
803 return true;
806 /* Compute the alignment for a variable. The alignment of an aggregate is
807 set to be at least that of a scalar less than or equal to it in size. */
809 unsigned int
810 visium_data_alignment (tree type, unsigned int align)
812 if (AGGREGATE_TYPE_P (type)
813 && TYPE_SIZE (type)
814 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && align < 32)
816 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 32)
817 return 32;
819 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 && align < 16)
820 return 16;
823 return align;
826 /* Helper function for HARD_REGNO_RENAME_OK (FROM, TO). Return non-zero if
827 it is OK to rename a hard register FROM to another hard register TO. */
830 visium_hard_regno_rename_ok (unsigned int from ATTRIBUTE_UNUSED,
831 unsigned int to)
833 /* If the function doesn't save LR, then the long-branch register will be
834 used for long branches so we need to know whether it is live before the
835 frame layout is computed. */
836 if (!current_function_saves_lr () && to == long_branch_regnum)
837 return 0;
839 /* Interrupt functions can only use registers that have already been
840 saved by the prologue, even if they would normally be call-clobbered. */
841 if (crtl->is_leaf
842 && !df_regs_ever_live_p (to)
843 && visium_interrupt_function_p ())
844 return 0;
846 return 1;
849 /* Implement TARGET_HARD_REGNO_MODE_OK.
851 Modes with sizes which cross from the one register class to the
852 other cannot be allowed. Only single floats are allowed in the
853 floating point registers, and only fixed point values in the EAM
854 registers. */
856 static bool
857 visium_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
859 if (GP_REGISTER_P (regno))
860 return GP_REGISTER_P (end_hard_regno (mode, regno) - 1);
862 if (FP_REGISTER_P (regno))
863 return mode == SFmode || (mode == SImode && TARGET_FPU_IEEE);
865 return (GET_MODE_CLASS (mode) == MODE_INT
866 && HARD_REGNO_NREGS (regno, mode) == 1);
869 /* Implement TARGET_MODES_TIEABLE_P. */
871 static bool
872 visium_modes_tieable_p (machine_mode mode1, machine_mode mode2)
874 return (GET_MODE_CLASS (mode1) == MODE_INT
875 && GET_MODE_CLASS (mode2) == MODE_INT);
878 /* Return true if it is ok to do sibling call optimization for the specified
879 call expression EXP. DECL will be the called function, or NULL if this
880 is an indirect call. */
882 static bool
883 visium_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
884 tree exp ATTRIBUTE_UNUSED)
886 return !visium_interrupt_function_p ();
889 /* Prepare operands for a move define_expand in MODE. */
891 void
892 prepare_move_operands (rtx *operands, machine_mode mode)
894 /* If the output is not a register, the input must be. */
895 if (GET_CODE (operands[0]) == MEM && !reg_or_0_operand (operands[1], mode))
896 operands[1] = force_reg (mode, operands[1]);
899 /* Return true if the operands are valid for a simple move insn. */
901 bool
902 ok_for_simple_move_operands (rtx *operands, machine_mode mode)
904 /* One of the operands must be a register. */
905 if (!register_operand (operands[0], mode)
906 && !reg_or_0_operand (operands[1], mode))
907 return false;
909 /* Once the flags are exposed, no simple moves between integer registers. */
910 if (visium_flags_exposed
911 && gpc_reg_operand (operands[0], mode)
912 && gpc_reg_operand (operands[1], mode))
913 return false;
915 return true;
918 /* Return true if the operands are valid for a simple move strict insn. */
920 bool
921 ok_for_simple_move_strict_operands (rtx *operands, machine_mode mode)
923 /* Once the flags are exposed, no simple moves between integer registers.
924 Note that, in QImode only, a zero source counts as an integer register
925 since it will be emitted as r0. */
926 if (visium_flags_exposed
927 && gpc_reg_operand (operands[0], mode)
928 && (gpc_reg_operand (operands[1], mode)
929 || (mode == QImode && operands[1] == const0_rtx)))
930 return false;
932 return true;
935 /* Return true if the operands are valid for a simple arithmetic or logical
936 insn. */
938 bool
939 ok_for_simple_arith_logic_operands (rtx *, machine_mode)
941 /* Once the flags are exposed, no simple arithmetic or logical operations
942 between integer registers. */
943 return !visium_flags_exposed;
946 /* Return non-zero if a branch or call instruction will be emitting a nop
947 into its delay slot. */
950 empty_delay_slot (rtx_insn *insn)
952 rtx seq;
954 /* If no previous instruction (should not happen), return true. */
955 if (PREV_INSN (insn) == NULL)
956 return 1;
958 seq = NEXT_INSN (PREV_INSN (insn));
959 if (GET_CODE (PATTERN (seq)) == SEQUENCE)
960 return 0;
962 return 1;
965 /* Wrapper around single_set which returns the second SET of a pair if the
966 first SET is to the flags register. */
968 static rtx
969 single_set_and_flags (rtx_insn *insn)
971 if (multiple_sets (insn))
973 rtx pat = PATTERN (insn);
974 if (XVECLEN (pat, 0) == 2
975 && GET_CODE (XVECEXP (pat, 0, 0)) == SET
976 && REG_P (SET_DEST (XVECEXP (pat, 0, 0)))
977 && REGNO (SET_DEST (XVECEXP (pat, 0, 0))) == FLAGS_REGNUM)
978 return XVECEXP (pat, 0, 1);
981 return single_set (insn);
984 /* This is called with OUT_INSN an instruction setting a (base) register
985 and IN_INSN a read or a write. Return 1 if these instructions together
986 constitute a pipeline hazard.
988 On the original architecture, a pipeline data hazard occurs when the Dest
989 of one instruction becomes the SrcA for an immediately following READ or
990 WRITE instruction with a non-zero index (indexing occurs at the decode
991 stage and so a NOP must be inserted in-between for this to work).
993 An example is:
995 move.l r2,r1
996 read.l r4,10(r2)
998 On the MCM, the non-zero index condition is lifted but the hazard is
999 patched up by the hardware through the injection of wait states:
1001 move.l r2,r1
1002 read.l r4,(r2)
1004 We nevertheless try to schedule instructions around this. */
1007 gr5_hazard_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
1009 rtx out_set, in_set, dest, memexpr;
1010 unsigned int out_reg, in_reg;
1012 /* A CALL is storage register class, but the link register is of no
1013 interest here. */
1014 if (GET_CODE (out_insn) == CALL_INSN)
1015 return 0;
1017 out_set = single_set_and_flags (out_insn);
1018 dest = SET_DEST (out_set);
1020 /* Should be no stall/hazard if OUT_INSN is MEM := ???. This only
1021 occurs prior to reload. */
1022 if (GET_CODE (dest) == MEM)
1023 return 0;
1025 if (GET_CODE (dest) == STRICT_LOW_PART)
1026 dest = XEXP (dest, 0);
1027 if (GET_CODE (dest) == SUBREG)
1028 dest = SUBREG_REG (dest);
1029 out_reg = REGNO (dest);
1031 in_set = single_set_and_flags (in_insn);
1033 /* If IN_INSN is MEM := MEM, it's the source that counts. */
1034 if (GET_CODE (SET_SRC (in_set)) == MEM)
1035 memexpr = XEXP (SET_SRC (in_set), 0);
1036 else
1037 memexpr = XEXP (SET_DEST (in_set), 0);
1039 if (GET_CODE (memexpr) == PLUS)
1041 memexpr = XEXP (memexpr, 0);
1042 if (GET_CODE (memexpr) == SUBREG)
1043 in_reg = REGNO (SUBREG_REG (memexpr));
1044 else
1045 in_reg = REGNO (memexpr);
1047 if (in_reg == out_reg)
1048 return 1;
1050 else if (TARGET_MCM)
1052 if (GET_CODE (memexpr) == STRICT_LOW_PART)
1053 memexpr = XEXP (memexpr, 0);
1054 if (GET_CODE (memexpr) == SUBREG)
1055 memexpr = SUBREG_REG (memexpr);
1056 in_reg = REGNO (memexpr);
1058 if (in_reg == out_reg)
1059 return 1;
1062 return 0;
1065 /* Return true if INSN is an empty asm instruction. */
1067 static bool
1068 empty_asm_p (rtx insn)
1070 rtx body = PATTERN (insn);
1071 const char *templ;
1073 if (GET_CODE (body) == ASM_INPUT)
1074 templ = XSTR (body, 0);
1075 else if (asm_noperands (body) >= 0)
1076 templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
1077 else
1078 templ = NULL;
1080 return (templ && templ[0] == '\0');
1083 /* Insert a NOP immediately before INSN wherever there is a pipeline hazard.
1084 LAST_REG records the register set in the last insn and LAST_INSN_CALL
1085 records whether the last insn was a call insn. */
1087 static void
1088 gr5_avoid_hazard (rtx_insn *insn, unsigned int *last_reg, bool *last_insn_call)
1090 unsigned int dest_reg = 0;
1091 rtx set;
1093 switch (GET_CODE (insn))
1095 case CALL_INSN:
1096 *last_reg = 0;
1097 *last_insn_call = true;
1098 return;
1100 case JUMP_INSN:
1101 /* If this is an empty asm, just skip it. */
1102 if (!empty_asm_p (insn))
1104 *last_reg = 0;
1105 *last_insn_call = false;
1107 return;
1109 case INSN:
1110 /* If this is an empty asm, just skip it. */
1111 if (empty_asm_p (insn))
1112 return;
1113 break;
1115 default:
1116 return;
1119 set = single_set_and_flags (insn);
1120 if (set != NULL_RTX)
1122 rtx dest = SET_DEST (set);
1123 const bool double_p = GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD;
1124 rtx memrtx = NULL;
1126 if (GET_CODE (SET_SRC (set)) == MEM)
1128 memrtx = XEXP (SET_SRC (set), 0);
1129 if (GET_CODE (dest) == STRICT_LOW_PART)
1130 dest = XEXP (dest, 0);
1131 if (REG_P (dest))
1132 dest_reg = REGNO (dest);
1134 /* If this is a DI or DF mode memory to register
1135 copy, then if rd = rs we get
1137 rs + 1 := 1[rs]
1138 rs := [rs]
1140 otherwise the order is
1142 rd := [rs]
1143 rd + 1 := 1[rs] */
1145 if (double_p)
1147 unsigned int base_reg;
1149 if (GET_CODE (memrtx) == PLUS)
1150 base_reg = REGNO (XEXP (memrtx, 0));
1151 else
1152 base_reg = REGNO (memrtx);
1154 if (dest_reg != base_reg)
1155 dest_reg++;
1159 else if (GET_CODE (dest) == MEM)
1160 memrtx = XEXP (dest, 0);
1162 else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC)
1164 if (GET_CODE (dest) == STRICT_LOW_PART
1165 ||GET_CODE (dest) == ZERO_EXTRACT)
1166 dest = XEXP (dest, 0);
1167 dest_reg = REGNO (dest);
1169 if (GET_CODE (SET_SRC (set)) == REG)
1171 unsigned int srcreg = REGNO (SET_SRC (set));
1173 /* Check for rs := rs, which will be deleted. */
1174 if (srcreg == dest_reg)
1175 return;
1177 /* In the case of a DI or DF mode move from register to
1178 register there is overlap if rd = rs + 1 in which case
1179 the order of the copies is reversed :
1181 rd + 1 := rs + 1;
1182 rd := rs */
1184 if (double_p && dest_reg != srcreg + 1)
1185 dest_reg++;
1189 /* If this is the delay slot of a call insn, any register it sets
1190 is not relevant. */
1191 if (*last_insn_call)
1192 dest_reg = 0;
1194 /* If the previous insn sets the value of a register, and this insn
1195 uses a base register, check for the pipeline hazard where it is
1196 the same register in each case. */
1197 if (*last_reg != 0 && memrtx != NULL_RTX)
1199 unsigned int reg = 0;
1201 /* Check for an index (original architecture). */
1202 if (GET_CODE (memrtx) == PLUS)
1203 reg = REGNO (XEXP (memrtx, 0));
1205 /* Check for an MCM target or rs := [rs], in DI or DF mode. */
1206 else if (TARGET_MCM || (double_p && REGNO (memrtx) == dest_reg))
1207 reg = REGNO (memrtx);
1209 /* Remove any pipeline hazard by inserting a NOP. */
1210 if (reg == *last_reg)
1212 if (dump_file)
1213 fprintf (dump_file,
1214 "inserting nop before insn %d\n", INSN_UID (insn));
1215 emit_insn_after (gen_hazard_nop (), prev_active_insn (insn));
1216 emit_insn_after (gen_blockage (), insn);
1220 *last_reg = dest_reg;
1223 *last_insn_call = false;
1226 /* Go through the instruction stream and insert nops where necessary to avoid
1227 pipeline hazards. There are two cases:
1229 1. On the original architecture, it is invalid to set the value of a
1230 (base) register and then use it in an address with a non-zero index
1231 in the next instruction.
1233 2. On the MCM, setting the value of a (base) register and then using
1234 it in address (including with zero index) in the next instruction
1235 will result in a pipeline stall of 3 cycles. */
1237 static void
1238 gr5_hazard_avoidance (void)
1240 unsigned int last_reg = 0;
1241 bool last_insn_call = false;
1242 rtx_insn *insn;
1244 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1245 if (INSN_P (insn))
1247 rtx pat = PATTERN (insn);
1249 if (GET_CODE (pat) == SEQUENCE)
1251 for (int i = 0; i < XVECLEN (pat, 0); i++)
1252 gr5_avoid_hazard (as_a <rtx_insn *> (XVECEXP (pat, 0, i)),
1253 &last_reg, &last_insn_call);
1256 else if (GET_CODE (insn) == CALL_INSN)
1258 /* This call is going to get a nop in its delay slot. */
1259 last_reg = 0;
1260 last_insn_call = false;
1263 else
1264 gr5_avoid_hazard (insn, &last_reg, &last_insn_call);
1267 else if (GET_CODE (insn) == BARRIER)
1268 last_reg = 0;
1271 /* Perform a target-specific pass over the instruction stream. The compiler
1272 will run it at all optimization levels, just after the point at which it
1273 normally does delayed-branch scheduling. */
1275 static unsigned int
1276 visium_reorg (void)
1278 if (visium_cpu == PROCESSOR_GR5)
1279 gr5_hazard_avoidance ();
1281 return 0;
1283 /* Return true if an argument must be passed by indirect reference. */
1285 static bool
1286 visium_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1287 machine_mode mode ATTRIBUTE_UNUSED,
1288 const_tree type,
1289 bool named ATTRIBUTE_UNUSED)
1291 return type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1294 /* Define how arguments are passed.
1296 A range of general registers and floating registers is available
1297 for passing arguments. When the class of registers which an
1298 argument would normally use is exhausted, that argument, is passed
1299 in the overflow region of the stack. No argument is split between
1300 registers and stack.
1302 Arguments of type float or _Complex float go in FP registers if FP
1303 hardware is available. If there is no FP hardware, arguments of
1304 type float go in general registers. All other arguments are passed
1305 in general registers. */
1307 static rtx
1308 visium_function_arg (cumulative_args_t pcum_v, machine_mode mode,
1309 const_tree type ATTRIBUTE_UNUSED,
1310 bool named ATTRIBUTE_UNUSED)
1312 int size;
1313 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1315 size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1316 if (mode == VOIDmode)
1317 return GEN_INT (0);
1319 /* Scalar or complex single precision floating point arguments are returned
1320 in floating registers. */
1321 if (TARGET_FPU
1322 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1323 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1324 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1325 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1327 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1328 return gen_rtx_REG (mode, FP_ARG_FIRST + ca->frcount);
1329 else
1330 return NULL_RTX;
1333 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1334 return gen_rtx_REG (mode, ca->grcount + GP_ARG_FIRST);
1336 return NULL_RTX;
1339 /* Update the summarizer variable pointed to by PCUM_V to advance past an
1340 argument in the argument list. The values MODE, TYPE and NAMED describe
1341 that argument. Once this is done, the variable CUM is suitable for
1342 analyzing the _following_ argument with visium_function_arg. */
1344 static void
1345 visium_function_arg_advance (cumulative_args_t pcum_v,
1346 machine_mode mode,
1347 const_tree type ATTRIBUTE_UNUSED,
1348 bool named)
1350 int size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1351 int stack_size = 0;
1352 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1354 /* Scalar or complex single precision floating point arguments are returned
1355 in floating registers. */
1356 if (TARGET_FPU
1357 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1358 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1359 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1360 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1362 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1363 ca->frcount += size;
1364 else
1366 stack_size = size;
1367 ca->frcount = MAX_ARGS_IN_FP_REGISTERS;
1370 else
1372 /* Everything else goes in a general register, if enough are
1373 available. */
1374 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1375 ca->grcount += size;
1376 else
1378 stack_size = size;
1379 ca->grcount = MAX_ARGS_IN_GP_REGISTERS;
1383 if (named)
1384 ca->stack_words += stack_size;
1387 /* Specify whether to return the return value in memory. */
1389 static bool
1390 visium_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1392 return (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1395 /* Define how scalar values are returned. */
1397 static rtx
1398 visium_function_value_1 (machine_mode mode)
1400 /* Scalar or complex single precision floating point values
1401 are returned in floating register f1. */
1402 if (TARGET_FPU
1403 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1404 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1405 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1406 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1407 return gen_rtx_REG (mode, FP_RETURN_REGNUM);
1409 /* All others are returned in r1. */
1410 return gen_rtx_REG (mode, RETURN_REGNUM);
1413 /* Return an RTX representing the place where a function returns or receives
1414 a value of data type RET_TYPE. */
1416 static rtx
1417 visium_function_value (const_tree ret_type,
1418 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1419 bool outgoing ATTRIBUTE_UNUSED)
1421 return visium_function_value_1 (TYPE_MODE (ret_type));
1424 /* Return an RTX representing the place where the library function result will
1425 be returned. */
1427 static rtx
1428 visium_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1430 return visium_function_value_1 (mode);
1433 /* Store the anonymous register arguments into the stack so that all the
1434 arguments appear to have been passed consecutively on the stack. */
1436 static void
1437 visium_setup_incoming_varargs (cumulative_args_t pcum_v,
1438 machine_mode mode,
1439 tree type,
1440 int *pretend_size ATTRIBUTE_UNUSED,
1441 int no_rtl)
1443 cumulative_args_t local_args_so_far;
1444 CUMULATIVE_ARGS local_copy;
1445 CUMULATIVE_ARGS *locargs;
1446 int gp_saved, fp_saved, size;
1448 /* Create an internal cumulative_args_t pointer to internally define
1449 storage to ensure calling TARGET_FUNCTION_ARG_ADVANCE does not
1450 make global changes. */
1451 local_args_so_far.p = &local_copy;
1452 locargs = get_cumulative_args (pcum_v);
1454 #if CHECKING_P
1455 local_args_so_far.magic = CUMULATIVE_ARGS_MAGIC;
1456 #endif
1458 local_copy.grcount = locargs->grcount;
1459 local_copy.frcount = locargs->frcount;
1460 local_copy.stack_words = locargs->stack_words;
1462 /* The caller has advanced ARGS_SO_FAR up to, but not beyond, the last named
1463 argument. Advance a local copy of ARGS_SO_FAR past the last "real" named
1464 argument, to find out how many registers are left over. */
1465 TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, mode, type, 1);
1467 /* Find how many registers we need to save. */
1468 locargs = get_cumulative_args (local_args_so_far);
1469 gp_saved = MAX_ARGS_IN_GP_REGISTERS - locargs->grcount;
1470 fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - locargs->frcount : 0);
1471 size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_HWFPVALUE);
1473 if (!no_rtl && size > 0)
1475 /* To avoid negative offsets, which are not valid addressing modes on
1476 the Visium, we create a base register for the pretend args. */
1477 rtx ptr
1478 = force_reg (Pmode,
1479 plus_constant (Pmode, virtual_incoming_args_rtx, -size));
1481 if (gp_saved > 0)
1483 rtx mem
1484 = gen_rtx_MEM (BLKmode,
1485 plus_constant (Pmode,
1486 ptr,
1487 fp_saved * UNITS_PER_HWFPVALUE));
1488 MEM_NOTRAP_P (mem) = 1;
1489 set_mem_alias_set (mem, get_varargs_alias_set ());
1490 move_block_from_reg (locargs->grcount + GP_ARG_FIRST, mem, gp_saved);
1493 if (fp_saved > 0)
1495 rtx mem = gen_rtx_MEM (BLKmode, ptr);
1496 MEM_NOTRAP_P (mem) = 1;
1497 set_mem_alias_set (mem, get_varargs_alias_set ());
1498 gcc_assert (UNITS_PER_WORD == UNITS_PER_HWFPVALUE);
1499 move_block_from_reg (locargs->frcount + FP_ARG_FIRST, mem, fp_saved);
1503 visium_reg_parm_save_area_size = size;
1506 /* Define the `__builtin_va_list' type for the ABI. */
1508 static tree
1509 visium_build_builtin_va_list (void)
1511 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes, record;
1513 record = (*lang_hooks.types.make_type) (RECORD_TYPE);
1514 f_ovfl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1515 get_identifier ("__overflow_argptr"), ptr_type_node);
1516 f_gbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1517 get_identifier ("__gpr_base"), ptr_type_node);
1518 f_fbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1519 get_identifier ("__fpr_base"), ptr_type_node);
1520 f_gbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1521 get_identifier ("__gpr_bytes"),
1522 short_unsigned_type_node);
1523 f_fbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1524 get_identifier ("__fpr_bytes"),
1525 short_unsigned_type_node);
1527 DECL_FIELD_CONTEXT (f_ovfl) = record;
1528 DECL_FIELD_CONTEXT (f_gbase) = record;
1529 DECL_FIELD_CONTEXT (f_fbase) = record;
1530 DECL_FIELD_CONTEXT (f_gbytes) = record;
1531 DECL_FIELD_CONTEXT (f_fbytes) = record;
1532 TYPE_FIELDS (record) = f_ovfl;
1533 TREE_CHAIN (f_ovfl) = f_gbase;
1534 TREE_CHAIN (f_gbase) = f_fbase;
1535 TREE_CHAIN (f_fbase) = f_gbytes;
1536 TREE_CHAIN (f_gbytes) = f_fbytes;
1537 layout_type (record);
1539 return record;
1542 /* Implement `va_start' for varargs and stdarg. */
1544 static void
1545 visium_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
1547 const CUMULATIVE_ARGS *ca = &crtl->args.info;
1548 int gp_saved = MAX_ARGS_IN_GP_REGISTERS - ca->grcount;
1549 int fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - ca->frcount : 0);
1550 int named_stack_size = ca->stack_words * UNITS_PER_WORD, offset;
1551 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1552 tree ovfl, gbase, gbytes, fbase, fbytes, t;
1554 f_ovfl = TYPE_FIELDS (va_list_type_node);
1555 f_gbase = TREE_CHAIN (f_ovfl);
1556 f_fbase = TREE_CHAIN (f_gbase);
1557 f_gbytes = TREE_CHAIN (f_fbase);
1558 f_fbytes = TREE_CHAIN (f_gbytes);
1559 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1560 gbase = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1561 NULL_TREE);
1562 fbase = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1563 NULL_TREE);
1564 gbytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), valist, f_gbytes,
1565 NULL_TREE);
1566 fbytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), valist, f_fbytes,
1567 NULL_TREE);
1569 /* Store the stacked vararg pointer in the OVFL member. */
1570 t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
1571 t = fold_build_pointer_plus_hwi (t, named_stack_size);
1572 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
1573 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1575 /* Store the base address of the GPR save area into GBASE. */
1576 t = make_tree (TREE_TYPE (gbase), virtual_incoming_args_rtx);
1577 offset = MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD;
1578 t = fold_build_pointer_plus_hwi (t, -offset);
1579 t = build2 (MODIFY_EXPR, TREE_TYPE (gbase), gbase, t);
1580 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1582 /* Store the base address of the FPR save area into FBASE. */
1583 if (fp_saved)
1585 t = make_tree (TREE_TYPE (fbase), virtual_incoming_args_rtx);
1586 offset = gp_saved * UNITS_PER_WORD
1587 + MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE;
1588 t = fold_build_pointer_plus_hwi (t, -offset);
1589 t = build2 (MODIFY_EXPR, TREE_TYPE (fbase), fbase, t);
1590 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1593 /* Fill in the GBYTES member. */
1594 t = build2 (MODIFY_EXPR, TREE_TYPE (gbytes), gbytes,
1595 size_int (gp_saved * UNITS_PER_WORD));
1596 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1598 /* Fill in the FBYTES member. */
1599 t = build2 (MODIFY_EXPR, TREE_TYPE (fbytes),
1600 fbytes, size_int (fp_saved * UNITS_PER_HWFPVALUE));
1601 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1604 /* Implement `va_arg'. */
1606 static tree
1607 visium_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
1608 gimple_seq *post_p)
1610 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1611 tree ovfl, base, bytes;
1612 HOST_WIDE_INT size, rsize;
1613 const bool by_reference_p
1614 = pass_by_reference (NULL, TYPE_MODE (type), type, false);
1615 const bool float_reg_arg_p
1616 = (TARGET_FPU && !by_reference_p
1617 && ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
1618 && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_HWFPVALUE)
1619 || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT
1620 && (GET_MODE_SIZE (TYPE_MODE (type))
1621 <= UNITS_PER_HWFPVALUE * 2))));
1622 const int max_save_area_size
1623 = (float_reg_arg_p ? MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE
1624 : MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD);
1625 tree t, u, offs;
1626 tree lab_false, lab_over, addr;
1627 tree ptrtype = build_pointer_type (type);
1629 if (by_reference_p)
1631 t = visium_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
1632 return build_va_arg_indirect_ref (t);
1635 size = int_size_in_bytes (type);
1636 rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
1637 f_ovfl = TYPE_FIELDS (va_list_type_node);
1638 f_gbase = TREE_CHAIN (f_ovfl);
1639 f_fbase = TREE_CHAIN (f_gbase);
1640 f_gbytes = TREE_CHAIN (f_fbase);
1641 f_fbytes = TREE_CHAIN (f_gbytes);
1643 /* We maintain separate pointers and offsets for floating-point and
1644 general registers, but we need similar code in both cases.
1646 Let:
1648 BYTES be the number of unused bytes in the register save area.
1649 BASE be the base address of the register save area.
1650 OFFS be the current offset into the register save area. Either
1651 MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD - bytes or
1652 MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE - bytes
1653 depending upon whether the argument is in general or floating
1654 registers.
1655 ADDR_RTX be the address of the argument.
1656 RSIZE be the size in bytes of the argument.
1657 OVFL be the pointer to the stack overflow area.
1659 The code we want is:
1661 1: if (bytes >= rsize)
1662 2: {
1663 3: addr_rtx = base + offs;
1664 4: bytes -= rsize;
1665 5: }
1666 6: else
1667 7: {
1668 8: bytes = 0;
1669 9: addr_rtx = ovfl;
1670 10: ovfl += rsize;
1671 11: }
1675 addr = create_tmp_var (ptr_type_node, "addr");
1676 lab_false = create_artificial_label (UNKNOWN_LOCATION);
1677 lab_over = create_artificial_label (UNKNOWN_LOCATION);
1678 if (float_reg_arg_p)
1679 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), unshare_expr (valist),
1680 f_fbytes, NULL_TREE);
1681 else
1682 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), unshare_expr (valist),
1683 f_gbytes, NULL_TREE);
1685 /* [1] Emit code to branch if bytes < rsize. */
1686 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1687 t = build2 (LT_EXPR, boolean_type_node, bytes, t);
1688 u = build1 (GOTO_EXPR, void_type_node, lab_false);
1689 t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
1690 gimplify_and_add (t, pre_p);
1692 /* [3] Emit code for: addr_rtx = base + offs, where
1693 offs = max_save_area_size - bytes. */
1694 t = fold_convert (sizetype, bytes);
1695 offs = build2 (MINUS_EXPR, sizetype, size_int (max_save_area_size), t);
1696 if (float_reg_arg_p)
1697 base = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1698 NULL_TREE);
1699 else
1700 base = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1701 NULL_TREE);
1703 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, offs);
1704 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1705 gimplify_and_add (t, pre_p);
1707 /* [4] Emit code for: bytes -= rsize. */
1708 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1709 t = build2 (MINUS_EXPR, TREE_TYPE (bytes), bytes, t);
1710 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), bytes, t);
1711 gimplify_and_add (t, pre_p);
1713 /* [6] Emit code to branch over the else clause, then the label. */
1714 t = build1 (GOTO_EXPR, void_type_node, lab_over);
1715 gimplify_and_add (t, pre_p);
1716 t = build1 (LABEL_EXPR, void_type_node, lab_false);
1717 gimplify_and_add (t, pre_p);
1719 /* [8] Emit code for: bytes = 0. */
1720 t = fold_convert (TREE_TYPE (bytes), size_int (0));
1721 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), unshare_expr (bytes), t);
1722 gimplify_and_add (t, pre_p);
1724 /* [9] Emit code for: addr_rtx = ovfl. */
1725 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1726 t = build2 (MODIFY_EXPR, void_type_node, addr, ovfl);
1727 gimplify_and_add (t, pre_p);
1729 /* [10] Emit code for: ovfl += rsize. */
1730 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl), ovfl, size_int (rsize));
1731 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), unshare_expr (ovfl), t);
1732 gimplify_and_add (t, pre_p);
1733 t = build1 (LABEL_EXPR, void_type_node, lab_over);
1734 gimplify_and_add (t, pre_p);
1736 /* Emit a big-endian correction if size < UNITS_PER_WORD. */
1737 if (size < UNITS_PER_WORD)
1739 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr), addr,
1740 size_int (UNITS_PER_WORD - size));
1741 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1742 gimplify_and_add (t, pre_p);
1745 addr = fold_convert (ptrtype, addr);
1747 return build_va_arg_indirect_ref (addr);
1750 /* Return true if OP is an offset suitable for use as a displacement in the
1751 address of a memory access in mode MODE. */
1753 static bool
1754 rtx_ok_for_offset_p (machine_mode mode, rtx op)
1756 if (!CONST_INT_P (op) || INTVAL (op) < 0)
1757 return false;
1759 switch (mode)
1761 case E_QImode:
1762 return INTVAL (op) <= 31;
1764 case E_HImode:
1765 return (INTVAL (op) % 2) == 0 && INTVAL (op) < 63;
1767 case E_SImode:
1768 case E_SFmode:
1769 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 127;
1771 case E_DImode:
1772 case E_DFmode:
1773 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 123;
1775 default:
1776 return false;
1780 /* Return whether X is a legitimate memory address for a memory operand
1781 of mode MODE.
1783 Legitimate addresses are defined in two variants: a strict variant
1784 and a non-strict one. The STRICT parameter chooses which variant
1785 is desired by the caller.
1787 The strict variant is used in the reload pass. It must be defined
1788 so that any pseudo-register that has not been allocated a hard
1789 register is considered a memory reference. This is because in
1790 contexts where some kind of register is required, a
1791 pseudo-register with no hard register must be rejected. For
1792 non-hard registers, the strict variant should look up the
1793 `reg_renumber' array; it should then proceed using the hard
1794 register number in the array, or treat the pseudo as a memory
1795 reference if the array holds `-1'.
1797 The non-strict variant is used in other passes. It must be
1798 defined to accept all pseudo-registers in every context where some
1799 kind of register is required. */
1801 static bool
1802 visium_legitimate_address_p (machine_mode mode, rtx x, bool strict)
1804 rtx base;
1805 unsigned int regno;
1807 /* If X is base+disp, check that we have an appropriate offset. */
1808 if (GET_CODE (x) == PLUS)
1810 if (!rtx_ok_for_offset_p (mode, XEXP (x, 1)))
1811 return false;
1812 base = XEXP (x, 0);
1814 else
1815 base = x;
1817 /* Now check the base: it must be either a register or a subreg thereof. */
1818 if (GET_CODE (base) == SUBREG)
1819 base = SUBREG_REG (base);
1820 if (!REG_P (base))
1821 return false;
1823 regno = REGNO (base);
1825 /* For the strict variant, the register must be REGNO_OK_FOR_BASE_P. */
1826 if (strict)
1827 return REGNO_OK_FOR_BASE_P (regno);
1829 /* For the non-strict variant, the register may also be a pseudo. */
1830 return BASE_REGISTER_P (regno) || regno >= FIRST_PSEUDO_REGISTER;
1833 /* Try machine-dependent ways of modifying an illegitimate address
1834 to be legitimate. If we find one, return the new, valid address.
1835 This macro is used in only one place: `memory_address' in explow.c.
1837 OLDX is the address as it was before break_out_memory_refs was called.
1838 In some cases it is useful to look at this to decide what needs to be done.
1840 MODE and WIN are passed so that this macro can use
1841 GO_IF_LEGITIMATE_ADDRESS.
1843 It is always safe for this macro to do nothing. It exists to recognize
1844 opportunities to optimize the output.
1846 For Visium
1848 memory (reg + <out of range int>)
1850 is transformed to
1852 base_int = <out of range int> & ~mask
1853 ptr_reg = reg + base_int
1854 memory (ptr_reg + <out of range int> - base_int)
1856 Thus ptr_reg is a base register for a range of addresses,
1857 which should help CSE.
1859 For a 1 byte reference mask is 0x1f
1860 for a 2 byte reference mask is 0x3f
1861 For a 4 byte reference mask is 0x7f
1863 This reflects the indexing range of the processor.
1865 For a > 4 byte reference the mask is 0x7f provided all of the words
1866 can be accessed with the base address obtained. Otherwise a mask
1867 of 0x3f is used.
1869 On rare occasions an unaligned base register value with an
1870 unaligned offset is generated. Unaligned offsets are left alone for
1871 this reason. */
1873 static rtx
1874 visium_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1875 machine_mode mode)
1877 if (GET_CODE (x) == PLUS
1878 && GET_CODE (XEXP (x, 1)) == CONST_INT
1879 && GET_CODE (XEXP (x, 0)) == REG && mode != BLKmode)
1881 int offset = INTVAL (XEXP (x, 1));
1882 int size = GET_MODE_SIZE (mode);
1883 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1884 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1885 int offset_base = offset & ~mask;
1887 /* Check that all of the words can be accessed. */
1888 if (4 < size && 0x80 < size + offset - offset_base)
1889 offset_base = offset & ~0x3f;
1890 if (offset_base != 0 && offset_base != offset && (offset & mask1) == 0)
1892 rtx ptr_reg = force_reg (Pmode,
1893 gen_rtx_PLUS (Pmode,
1894 XEXP (x, 0),
1895 GEN_INT (offset_base)));
1897 return plus_constant (Pmode, ptr_reg, offset - offset_base);
1901 return x;
1904 /* Perform a similar function to visium_legitimize_address, but this time
1905 for reload. Generating new registers is not an option here. Parts
1906 that need reloading are indicated by calling push_reload. */
1909 visium_legitimize_reload_address (rtx x, machine_mode mode, int opnum,
1910 int type, int ind ATTRIBUTE_UNUSED)
1912 rtx newrtx, tem = NULL_RTX;
1914 if (mode == BLKmode)
1915 return NULL_RTX;
1917 if (optimize && GET_CODE (x) == PLUS)
1918 tem = simplify_binary_operation (PLUS, GET_MODE (x), XEXP (x, 0),
1919 XEXP (x, 1));
1921 newrtx = tem ? tem : x;
1922 if (GET_CODE (newrtx) == PLUS
1923 && GET_CODE (XEXP (newrtx, 1)) == CONST_INT
1924 && GET_CODE (XEXP (newrtx, 0)) == REG
1925 && BASE_REGISTER_P (REGNO (XEXP (newrtx, 0))))
1927 int offset = INTVAL (XEXP (newrtx, 1));
1928 int size = GET_MODE_SIZE (mode);
1929 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1930 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1931 int offset_base = offset & ~mask;
1933 /* Check that all of the words can be accessed. */
1934 if (4 < size && 0x80 < size + offset - offset_base)
1935 offset_base = offset & ~0x3f;
1937 if (offset_base && (offset & mask1) == 0)
1939 rtx temp = gen_rtx_PLUS (Pmode,
1940 XEXP (newrtx, 0), GEN_INT (offset_base));
1942 x = gen_rtx_PLUS (Pmode, temp, GEN_INT (offset - offset_base));
1943 push_reload (XEXP (x, 0), 0, &XEXP (x, 0), 0,
1944 BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum,
1945 (enum reload_type) type);
1946 return x;
1950 return NULL_RTX;
1953 /* Return the cost of moving data of mode MODE from a register in class FROM to
1954 one in class TO. A value of 2 is the default; other values are interpreted
1955 relative to that. */
1957 static int
1958 visium_register_move_cost (machine_mode mode, reg_class_t from,
1959 reg_class_t to)
1961 const int numwords = (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) ? 1 : 2;
1963 if (from == MDB || to == MDB)
1964 return 4;
1965 else if (from == MDC || to == MDC || (from == FP_REGS) != (to == FP_REGS))
1966 return 4 * numwords;
1967 else
1968 return 2 * numwords;
1971 /* Return the cost of moving data of mode MODE between a register of class
1972 CLASS and memory. IN is zero if the value is to be written to memory,
1973 non-zero if it is to be read in. This cost is relative to those in
1974 visium_register_move_cost. */
1976 static int
1977 visium_memory_move_cost (machine_mode mode,
1978 reg_class_t to ATTRIBUTE_UNUSED,
1979 bool in)
1981 /* Moving data in can be from PROM and this is expensive. */
1982 if (in)
1984 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
1985 return 7;
1986 else
1987 return 13;
1990 /* Moving data out is mostly to RAM and should be cheaper. */
1991 else
1993 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
1994 return 6;
1995 else
1996 return 12;
2000 /* Return the relative costs of expression X. */
2002 static bool
2003 visium_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
2004 int opno ATTRIBUTE_UNUSED, int *total,
2005 bool speed ATTRIBUTE_UNUSED)
2007 int code = GET_CODE (x);
2009 switch (code)
2011 case CONST_INT:
2012 /* Small integers are as cheap as registers. 4-byte values can
2013 be fetched as immediate constants - let's give that the cost
2014 of an extra insn. */
2015 *total = COSTS_N_INSNS (!satisfies_constraint_J (x));
2016 return true;
2018 case CONST:
2019 case LABEL_REF:
2020 case SYMBOL_REF:
2021 *total = COSTS_N_INSNS (2);
2022 return true;
2024 case CONST_DOUBLE:
2026 rtx high, low;
2027 split_double (x, &high, &low);
2028 *total =
2029 COSTS_N_INSNS
2030 (!satisfies_constraint_J (high) + !satisfies_constraint_J (low));
2031 return true;
2034 case MULT:
2035 *total = COSTS_N_INSNS (3);
2036 return false;
2038 case DIV:
2039 case UDIV:
2040 case MOD:
2041 case UMOD:
2042 if (mode == DImode)
2043 *total = COSTS_N_INSNS (64);
2044 else
2045 *total = COSTS_N_INSNS (32);
2046 return false;
2048 case PLUS:
2049 case MINUS:
2050 case NEG:
2051 /* DImode operations are performed directly on the ALU. */
2052 if (mode == DImode)
2053 *total = COSTS_N_INSNS (2);
2054 else
2055 *total = COSTS_N_INSNS (1);
2056 return false;
2058 case ASHIFT:
2059 case ASHIFTRT:
2060 case LSHIFTRT:
2061 /* DImode operations are performed on the EAM instead. */
2062 if (mode == DImode)
2063 *total = COSTS_N_INSNS (3);
2064 else
2065 *total = COSTS_N_INSNS (1);
2066 return false;
2068 case COMPARE:
2069 /* This matches the btst pattern. */
2070 if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT
2071 && XEXP (x, 1) == const0_rtx
2072 && XEXP (XEXP (x, 0), 1) == const1_rtx
2073 && satisfies_constraint_K (XEXP (XEXP (x, 0), 2)))
2074 *total = COSTS_N_INSNS (1);
2075 return false;
2077 default:
2078 return false;
2082 /* Split a double move of OPERANDS in MODE. */
2084 void
2085 visium_split_double_move (rtx *operands, machine_mode mode)
2087 bool swap = false;
2089 /* Check register to register with overlap. */
2090 if (GET_CODE (operands[0]) == REG
2091 && GET_CODE (operands[1]) == REG
2092 && REGNO (operands[0]) == REGNO (operands[1]) + 1)
2093 swap = true;
2095 /* Check memory to register where the base reg overlaps the destination. */
2096 if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == MEM)
2098 rtx op = XEXP (operands[1], 0);
2100 if (GET_CODE (op) == SUBREG)
2101 op = SUBREG_REG (op);
2103 if (GET_CODE (op) == REG && REGNO (op) == REGNO (operands[0]))
2104 swap = true;
2106 if (GET_CODE (op) == PLUS)
2108 rtx x = XEXP (op, 0);
2109 rtx y = XEXP (op, 1);
2111 if (GET_CODE (x) == REG && REGNO (x) == REGNO (operands[0]))
2112 swap = true;
2114 if (GET_CODE (y) == REG && REGNO (y) == REGNO (operands[0]))
2115 swap = true;
2119 if (swap)
2121 operands[2] = operand_subword (operands[0], 1, 1, mode);
2122 operands[3] = operand_subword (operands[1], 1, 1, mode);
2123 operands[4] = operand_subword (operands[0], 0, 1, mode);
2124 operands[5] = operand_subword (operands[1], 0, 1, mode);
2126 else
2128 operands[2] = operand_subword (operands[0], 0, 1, mode);
2129 operands[3] = operand_subword (operands[1], 0, 1, mode);
2130 operands[4] = operand_subword (operands[0], 1, 1, mode);
2131 operands[5] = operand_subword (operands[1], 1, 1, mode);
2135 /* Split a double addition or subtraction of operands. */
2137 void
2138 visium_split_double_add (enum rtx_code code, rtx op0, rtx op1, rtx op2)
2140 rtx op3 = gen_lowpart (SImode, op0);
2141 rtx op4 = gen_lowpart (SImode, op1);
2142 rtx op5;
2143 rtx op6 = gen_highpart (SImode, op0);
2144 rtx op7 = (op1 == const0_rtx ? op1 : gen_highpart (SImode, op1));
2145 rtx op8;
2146 rtx x, pat, flags;
2148 /* If operand #2 is a small constant, then its high part is null. */
2149 if (CONST_INT_P (op2))
2151 HOST_WIDE_INT val = INTVAL (op2);
2153 if (val < 0)
2155 code = (code == MINUS ? PLUS : MINUS);
2156 val = -val;
2159 op5 = gen_int_mode (val, SImode);
2160 op8 = const0_rtx;
2162 else
2164 op5 = gen_lowpart (SImode, op2);
2165 op8 = gen_highpart (SImode, op2);
2168 if (op4 == const0_rtx)
2169 pat = gen_negsi2_insn_set_carry (op3, op5);
2170 else if (code == MINUS)
2171 pat = gen_subsi3_insn_set_carry (op3, op4, op5);
2172 else
2173 pat = gen_addsi3_insn_set_carry (op3, op4, op5);
2174 emit_insn (pat);
2176 /* This is the plus_[plus_]sltu_flags or minus_[minus_]sltu_flags pattern. */
2177 if (op8 == const0_rtx)
2178 x = op7;
2179 else
2180 x = gen_rtx_fmt_ee (code, SImode, op7, op8);
2181 flags = gen_rtx_REG (CCCmode, FLAGS_REGNUM);
2182 x = gen_rtx_fmt_ee (code, SImode, x, gen_rtx_LTU (SImode, flags, const0_rtx));
2183 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2184 XVECEXP (pat, 0, 0) = gen_rtx_SET (op6, x);
2185 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2186 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2187 emit_insn (pat);
2189 visium_flags_exposed = true;
2192 /* Expand a copysign of OPERANDS in MODE. */
2194 void
2195 visium_expand_copysign (rtx *operands, machine_mode mode)
2197 rtx op0 = operands[0];
2198 rtx op1 = operands[1];
2199 rtx op2 = operands[2];
2200 rtx mask = force_reg (SImode, GEN_INT (0x7fffffff));
2201 rtx x;
2203 /* We manually handle SFmode because the abs and neg instructions of
2204 the FPU on the MCM have a non-standard behavior wrt NaNs. */
2205 gcc_assert (mode == SFmode);
2207 /* First get all the non-sign bits of op1. */
2208 if (GET_CODE (op1) == CONST_DOUBLE)
2210 if (real_isneg (CONST_DOUBLE_REAL_VALUE (op1)))
2211 op1 = simplify_unary_operation (ABS, mode, op1, mode);
2212 if (op1 != CONST0_RTX (mode))
2214 long l;
2215 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op1), l);
2216 op1 = force_reg (SImode, gen_int_mode (l, SImode));
2219 else
2221 op1 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op1));
2222 op1 = force_reg (SImode, gen_rtx_AND (SImode, op1, mask));
2225 /* Then get the sign bit of op2. */
2226 mask = force_reg (SImode, gen_rtx_NOT (SImode, mask));
2227 op2 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op2));
2228 op2 = force_reg (SImode, gen_rtx_AND (SImode, op2, mask));
2230 /* Finally OR the two values. */
2231 if (op1 == CONST0_RTX (SFmode))
2232 x = op2;
2233 else
2234 x = force_reg (SImode, gen_rtx_IOR (SImode, op1, op2));
2236 /* And move the result to the destination. */
2237 emit_insn (gen_rtx_SET (op0, gen_lowpart (SFmode, x)));
2240 /* Expand a cstore of OPERANDS in MODE for EQ/NE/LTU/GTU/GEU/LEU. We generate
2241 the result in the C flag and use the ADC/SUBC instructions to write it into
2242 the destination register.
2244 It would also be possible to implement support for LT/GT/LE/GE by means of
2245 the RFLAG instruction followed by some shifts, but this can pessimize the
2246 generated code. */
2248 void
2249 visium_expand_int_cstore (rtx *operands, machine_mode mode)
2251 enum rtx_code code = GET_CODE (operands[1]);
2252 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], sltu;
2253 bool reverse = false;
2255 switch (code)
2257 case EQ:
2258 case NE:
2259 /* We use a special comparison to get the result in the C flag. */
2260 if (op2 != const0_rtx)
2261 op1 = force_reg (mode, gen_rtx_XOR (mode, op1, op2));
2262 op1 = gen_rtx_NOT (mode, op1);
2263 op2 = constm1_rtx;
2264 if (code == EQ)
2265 reverse = true;
2266 break;
2268 case LEU:
2269 case GEU:
2270 /* The result is naturally in the C flag modulo a couple of tricks. */
2271 code = reverse_condition (code);
2272 reverse = true;
2274 /* ... fall through ... */
2276 case LTU:
2277 case GTU:
2278 if (code == GTU)
2280 rtx tmp = op1;
2281 op1 = op2;
2282 op2 = tmp;
2284 break;
2286 default:
2287 gcc_unreachable ();
2290 /* We need either a single ADC or a SUBC and a PLUS. */
2291 sltu = gen_rtx_LTU (SImode, op1, op2);
2293 if (reverse)
2295 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, sltu));
2296 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2298 else
2299 emit_insn (gen_rtx_SET (op0, sltu));
2302 /* Expand a cstore of OPERANDS in MODE for LT/GT/UNGE/UNLE. We generate the
2303 result in the C flag and use the ADC/SUBC instructions to write it into
2304 the destination register. */
2306 void
2307 visium_expand_fp_cstore (rtx *operands,
2308 machine_mode mode ATTRIBUTE_UNUSED)
2310 enum rtx_code code = GET_CODE (operands[1]);
2311 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], slt;
2312 bool reverse = false;
2314 switch (code)
2316 case UNLE:
2317 case UNGE:
2318 /* The result is naturally in the C flag modulo a couple of tricks. */
2319 code = reverse_condition_maybe_unordered (code);
2320 reverse = true;
2322 /* ... fall through ... */
2324 case LT:
2325 case GT:
2326 if (code == GT)
2328 rtx tmp = op1;
2329 op1 = op2;
2330 op2 = tmp;
2332 break;
2334 default:
2335 gcc_unreachable ();
2338 /* We need either a single ADC or a SUBC and a PLUS. */
2339 slt = gen_rtx_LT (SImode, op1, op2);
2341 if (reverse)
2343 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, slt));
2344 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2346 else
2347 emit_insn (gen_rtx_SET (op0, slt));
2350 /* Split a compare-and-store with CODE, operands OP2 and OP3, combined with
2351 operation with OP_CODE, operands OP0 and OP1. */
2353 void
2354 visium_split_cstore (enum rtx_code op_code, rtx op0, rtx op1,
2355 enum rtx_code code, rtx op2, rtx op3)
2357 machine_mode cc_mode = visium_select_cc_mode (code, op2, op3);
2359 /* If a FP cstore was reversed, then it was originally UNGE/UNLE. */
2360 if (cc_mode == CCFPEmode && (op_code == NEG || op_code == MINUS))
2361 cc_mode = CCFPmode;
2363 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2364 rtx x = gen_rtx_COMPARE (cc_mode, op2, op3);
2365 x = gen_rtx_SET (flags, x);
2366 emit_insn (x);
2368 x = gen_rtx_fmt_ee (code, SImode, flags, const0_rtx);
2369 switch (op_code)
2371 case SET:
2372 break;
2373 case NEG:
2374 x = gen_rtx_NEG (SImode, x);
2375 break;
2376 case PLUS:
2377 case MINUS:
2378 x = gen_rtx_fmt_ee (op_code, SImode, op1, x);
2379 break;
2380 default:
2381 gcc_unreachable ();
2384 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2385 XVECEXP (pat, 0, 0) = gen_rtx_SET (op0, x);
2386 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2387 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2388 emit_insn (pat);
2390 visium_flags_exposed = true;
2393 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2394 address SRC_REG to DST with address DST_REG in 4-byte chunks. */
2396 static void
2397 expand_block_move_4 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2399 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2400 unsigned int rem = bytes % 4;
2402 if (TARGET_BMI)
2404 unsigned int i;
2405 rtx insn;
2407 emit_move_insn (regno_reg_rtx[1], dst_reg);
2408 emit_move_insn (regno_reg_rtx[2], src_reg);
2409 emit_move_insn (regno_reg_rtx[3], bytes_rtx);
2411 insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (8));
2412 XVECEXP (insn, 0, 0)
2413 = gen_rtx_SET (replace_equiv_address_nv (dst, regno_reg_rtx[1]),
2414 replace_equiv_address_nv (src, regno_reg_rtx[2]));
2415 XVECEXP (insn, 0, 1) = gen_rtx_USE (VOIDmode, regno_reg_rtx[3]);
2416 for (i = 1; i <= 6; i++)
2417 XVECEXP (insn, 0, 1 + i)
2418 = gen_rtx_CLOBBER (VOIDmode, regno_reg_rtx[i]);
2419 emit_insn (insn);
2421 else
2422 emit_library_call (long_int_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2423 dst_reg, Pmode,
2424 src_reg, Pmode,
2425 convert_to_mode (TYPE_MODE (sizetype),
2426 GEN_INT (bytes >> 2),
2427 TYPE_UNSIGNED (sizetype)),
2428 TYPE_MODE (sizetype));
2429 if (rem == 0)
2430 return;
2432 dst = replace_equiv_address_nv (dst, dst_reg);
2433 src = replace_equiv_address_nv (src, src_reg);
2434 bytes -= rem;
2436 if (rem > 1)
2438 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2439 adjust_address_nv (src, HImode, bytes));
2440 bytes += 2;
2441 rem -= 2;
2444 if (rem > 0)
2445 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2446 adjust_address_nv (src, QImode, bytes));
2449 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2450 address SRC_REG to DST with address DST_REG in 2-bytes chunks. */
2452 static void
2453 expand_block_move_2 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2455 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2456 unsigned int rem = bytes % 2;
2458 emit_library_call (wrd_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2459 dst_reg, Pmode,
2460 src_reg, Pmode,
2461 convert_to_mode (TYPE_MODE (sizetype),
2462 GEN_INT (bytes >> 1),
2463 TYPE_UNSIGNED (sizetype)),
2464 TYPE_MODE (sizetype));
2465 if (rem == 0)
2466 return;
2468 dst = replace_equiv_address_nv (dst, dst_reg);
2469 src = replace_equiv_address_nv (src, src_reg);
2470 bytes -= rem;
2472 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2473 adjust_address_nv (src, QImode, bytes));
2476 /* Generate a call to a library function to move BYTES_RTX bytes from address
2477 SRC_REG to address DST_REG in 1-byte chunks. */
2479 static void
2480 expand_block_move_1 (rtx dst_reg, rtx src_reg, rtx bytes_rtx)
2482 emit_library_call (byt_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2483 dst_reg, Pmode,
2484 src_reg, Pmode,
2485 convert_to_mode (TYPE_MODE (sizetype),
2486 bytes_rtx,
2487 TYPE_UNSIGNED (sizetype)),
2488 TYPE_MODE (sizetype));
2491 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2492 address DST_REG to VALUE_RTX in 4-byte chunks. */
2494 static void
2495 expand_block_set_4 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2497 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2498 unsigned int rem = bytes % 4;
2500 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2501 emit_library_call (long_int_memset_libfunc, LCT_NORMAL, VOIDmode,
2502 dst_reg, Pmode,
2503 value_rtx, Pmode,
2504 convert_to_mode (TYPE_MODE (sizetype),
2505 GEN_INT (bytes >> 2),
2506 TYPE_UNSIGNED (sizetype)),
2507 TYPE_MODE (sizetype));
2508 if (rem == 0)
2509 return;
2511 dst = replace_equiv_address_nv (dst, dst_reg);
2512 bytes -= rem;
2514 if (rem > 1)
2516 if (CONST_INT_P (value_rtx))
2518 const unsigned HOST_WIDE_INT value = UINTVAL (value_rtx) & 0xff;
2519 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2520 gen_int_mode ((value << 8) | value, HImode));
2522 else
2524 rtx temp = convert_to_mode (QImode, value_rtx, 1);
2525 emit_move_insn (adjust_address_nv (dst, QImode, bytes), temp);
2526 emit_move_insn (adjust_address_nv (dst, QImode, bytes + 1), temp);
2528 bytes += 2;
2529 rem -= 2;
2532 if (rem > 0)
2533 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2534 convert_to_mode (QImode, value_rtx, 1));
2537 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2538 address DST_REG to VALUE_RTX in 2-byte chunks. */
2540 static void
2541 expand_block_set_2 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2543 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2544 unsigned int rem = bytes % 2;
2546 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2547 emit_library_call (wrd_memset_libfunc, LCT_NORMAL, VOIDmode,
2548 dst_reg, Pmode,
2549 value_rtx, Pmode,
2550 convert_to_mode (TYPE_MODE (sizetype),
2551 GEN_INT (bytes >> 1),
2552 TYPE_UNSIGNED (sizetype)),
2553 TYPE_MODE (sizetype));
2554 if (rem == 0)
2555 return;
2557 dst = replace_equiv_address_nv (dst, dst_reg);
2558 bytes -= rem;
2560 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2561 convert_to_mode (QImode, value_rtx, 1));
2564 /* Generate a call to a library function to set BYTES_RTX bytes at address
2565 DST_REG to VALUE_RTX in 1-byte chunks. */
2567 static void
2568 expand_block_set_1 (rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2570 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2571 emit_library_call (byt_memset_libfunc, LCT_NORMAL, VOIDmode,
2572 dst_reg, Pmode,
2573 value_rtx, Pmode,
2574 convert_to_mode (TYPE_MODE (sizetype),
2575 bytes_rtx,
2576 TYPE_UNSIGNED (sizetype)),
2577 TYPE_MODE (sizetype));
2580 /* Expand string/block move operations.
2582 operands[0] is the pointer to the destination.
2583 operands[1] is the pointer to the source.
2584 operands[2] is the number of bytes to move.
2585 operands[3] is the alignment.
2587 Return 1 upon success, 0 otherwise. */
2590 visium_expand_block_move (rtx *operands)
2592 rtx dst = operands[0];
2593 rtx src = operands[1];
2594 rtx bytes_rtx = operands[2];
2595 rtx align_rtx = operands[3];
2596 const int align = INTVAL (align_rtx);
2597 rtx dst_reg, src_reg;
2598 tree dst_expr, src_expr;
2600 /* We only handle a fixed number of bytes for now. */
2601 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2602 return 0;
2604 /* Copy the addresses into scratch registers. */
2605 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2606 src_reg = copy_addr_to_reg (XEXP (src, 0));
2608 /* Move the data with the appropriate granularity. */
2609 if (align >= 4)
2610 expand_block_move_4 (dst, dst_reg, src, src_reg, bytes_rtx);
2611 else if (align >= 2)
2612 expand_block_move_2 (dst, dst_reg, src, src_reg, bytes_rtx);
2613 else
2614 expand_block_move_1 (dst_reg, src_reg, bytes_rtx);
2616 /* Since DST and SRC are passed to a libcall, mark the corresponding
2617 tree EXPR as addressable. */
2618 dst_expr = MEM_EXPR (dst);
2619 src_expr = MEM_EXPR (src);
2620 if (dst_expr)
2621 mark_addressable (dst_expr);
2622 if (src_expr)
2623 mark_addressable (src_expr);
2625 return 1;
2628 /* Expand string/block set operations.
2630 operands[0] is the pointer to the destination.
2631 operands[1] is the number of bytes to set.
2632 operands[2] is the source value.
2633 operands[3] is the alignment.
2635 Return 1 upon success, 0 otherwise. */
2638 visium_expand_block_set (rtx *operands)
2640 rtx dst = operands[0];
2641 rtx bytes_rtx = operands[1];
2642 rtx value_rtx = operands[2];
2643 rtx align_rtx = operands[3];
2644 const int align = INTVAL (align_rtx);
2645 rtx dst_reg;
2646 tree dst_expr;
2648 /* We only handle a fixed number of bytes for now. */
2649 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2650 return 0;
2652 /* Copy the address into a scratch register. */
2653 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2655 /* Set the data with the appropriate granularity. */
2656 if (align >= 4)
2657 expand_block_set_4 (dst, dst_reg, value_rtx, bytes_rtx);
2658 else if (align >= 2)
2659 expand_block_set_2 (dst, dst_reg, value_rtx, bytes_rtx);
2660 else
2661 expand_block_set_1 (dst_reg, value_rtx, bytes_rtx);
2663 /* Since DST is passed to a libcall, mark the corresponding
2664 tree EXPR as addressable. */
2665 dst_expr = MEM_EXPR (dst);
2666 if (dst_expr)
2667 mark_addressable (dst_expr);
2669 return 1;
2672 /* Initialize a trampoline. M_TRAMP is an RTX for the memory block for the
2673 trampoline, FNDECL is the FUNCTION_DECL for the nested function and
2674 STATIC_CHAIN is an RTX for the static chain value that should be passed
2675 to the function when it is called. */
2677 static void
2678 visium_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
2680 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2681 rtx addr = XEXP (m_tramp, 0);
2683 /* The trampoline initialization sequence is:
2685 moviu r9,%u FUNCTION
2686 movil r9,%l FUNCTION
2687 moviu r20,%u STATIC
2688 bra tr,r9,r9
2689 movil r20,%l STATIC
2691 We don't use r0 as the destination register of the branch because we want
2692 the Branch Pre-decode Logic of the GR6 to use the Address Load Array to
2693 predict the branch target. */
2695 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 0)),
2696 plus_constant (SImode,
2697 expand_shift (RSHIFT_EXPR, SImode, fnaddr,
2698 16, NULL_RTX, 1),
2699 0x04a90000));
2701 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 4)),
2702 plus_constant (SImode,
2703 expand_and (SImode, fnaddr, GEN_INT (0xffff),
2704 NULL_RTX),
2705 0x04890000));
2707 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 8)),
2708 plus_constant (SImode,
2709 expand_shift (RSHIFT_EXPR, SImode,
2710 static_chain,
2711 16, NULL_RTX, 1),
2712 0x04b40000));
2714 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)),
2715 gen_int_mode (0xff892404, SImode));
2717 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 16)),
2718 plus_constant (SImode,
2719 expand_and (SImode, static_chain,
2720 GEN_INT (0xffff), NULL_RTX),
2721 0x04940000));
2723 emit_library_call (set_trampoline_parity_libfunc, LCT_NORMAL, VOIDmode,
2724 addr, SImode);
2727 /* Return true if the current function must have and use a frame pointer. */
2729 static bool
2730 visium_frame_pointer_required (void)
2732 /* The frame pointer is required if the function isn't leaf to be able to
2733 do manual stack unwinding. */
2734 if (!crtl->is_leaf)
2735 return true;
2737 /* If the stack pointer is dynamically modified in the function, it cannot
2738 serve as the frame pointer. */
2739 if (!crtl->sp_is_unchanging)
2740 return true;
2742 /* If the function receives nonlocal gotos, it needs to save the frame
2743 pointer in the nonlocal_goto_save_area object. */
2744 if (cfun->has_nonlocal_label)
2745 return true;
2747 /* The frame also needs to be established in some special cases. */
2748 if (visium_frame_needed)
2749 return true;
2751 return false;
2754 /* Profiling support. Just a call to MCOUNT is needed. No labelled counter
2755 location is involved. Proper support for __builtin_return_address is also
2756 required, which is fairly straightforward provided a frame gets created. */
2758 void
2759 visium_profile_hook (void)
2761 visium_frame_needed = true;
2762 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "mcount"), LCT_NORMAL,
2763 VOIDmode);
2766 /* A C expression whose value is RTL representing the address in a stack frame
2767 where the pointer to the caller's frame is stored. Assume that FRAMEADDR is
2768 an RTL expression for the address of the stack frame itself.
2770 If you don't define this macro, the default is to return the value of
2771 FRAMEADDR--that is, the stack frame address is also the address of the stack
2772 word that points to the previous frame. */
2775 visium_dynamic_chain_address (rtx frame)
2777 /* This is the default, but we need to make sure the frame gets created. */
2778 visium_frame_needed = true;
2779 return frame;
2782 /* A C expression whose value is RTL representing the value of the return
2783 address for the frame COUNT steps up from the current frame, after the
2784 prologue. FRAMEADDR is the frame pointer of the COUNT frame, or the frame
2785 pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
2786 defined.
2788 The value of the expression must always be the correct address when COUNT is
2789 zero, but may be `NULL_RTX' if there is not way to determine the return
2790 address of other frames. */
2793 visium_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
2795 /* Dont try to compute anything other than frame zero. */
2796 if (count != 0)
2797 return NULL_RTX;
2799 visium_frame_needed = true;
2800 return
2801 gen_frame_mem (Pmode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2804 /* Helper function for EH_RETURN_HANDLER_RTX. Return the RTX representing a
2805 location in which to store the address of an exception handler to which we
2806 should return. */
2809 visium_eh_return_handler_rtx (void)
2811 rtx mem
2812 = gen_frame_mem (SImode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2813 MEM_VOLATILE_P (mem) = 1;
2814 return mem;
2817 static struct machine_function *
2818 visium_init_machine_status (void)
2820 return ggc_cleared_alloc<machine_function> ();
2823 /* The per-function data machinery is needed to indicate when a frame
2824 is required. */
2826 void
2827 visium_init_expanders (void)
2829 init_machine_status = visium_init_machine_status;
2832 /* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE,
2833 return the mode to be used for the comparison. */
2835 machine_mode
2836 visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
2838 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2840 switch (code)
2842 case EQ:
2843 case NE:
2844 case ORDERED:
2845 case UNORDERED:
2846 case UNLT:
2847 case UNLE:
2848 case UNGT:
2849 case UNGE:
2850 return CCFPmode;
2852 case LT:
2853 case LE:
2854 case GT:
2855 case GE:
2856 return CCFPEmode;
2858 /* These 2 comparison codes are not supported. */
2859 case UNEQ:
2860 case LTGT:
2861 default:
2862 gcc_unreachable ();
2866 /* This is for the cmp<mode>_sne pattern. */
2867 if (op1 == constm1_rtx)
2868 return CCCmode;
2870 /* This is for the add<mode>3_insn_set_carry pattern. */
2871 if ((code == LTU || code == GEU)
2872 && GET_CODE (op0) == PLUS
2873 && rtx_equal_p (XEXP (op0, 0), op1))
2874 return CCCmode;
2876 /* This is for the {add,sub,neg}<mode>3_insn_set_overflow pattern. */
2877 if ((code == EQ || code == NE)
2878 && GET_CODE (op1) == UNSPEC
2879 && (XINT (op1, 1) == UNSPEC_ADDV
2880 || XINT (op1, 1) == UNSPEC_SUBV
2881 || XINT (op1, 1) == UNSPEC_NEGV))
2882 return CCVmode;
2884 if (op1 != const0_rtx)
2885 return CCmode;
2887 switch (GET_CODE (op0))
2889 case PLUS:
2890 case MINUS:
2891 case NEG:
2892 case ASHIFT:
2893 case LTU:
2894 case LT:
2895 /* The C and V flags may be set differently from a COMPARE with zero.
2896 The consequence is that a comparison operator testing C or V must
2897 be turned into another operator not testing C or V and yielding
2898 the same result for a comparison with zero. That's possible for
2899 GE/LT which become NC/NS respectively, but not for GT/LE for which
2900 the altered operator doesn't exist on the Visium. */
2901 return CCNZmode;
2903 case ZERO_EXTRACT:
2904 /* This is a btst, the result is in C instead of Z. */
2905 return CCCmode;
2907 case CONST_INT:
2908 /* This is a degenerate case, typically an uninitialized variable. */
2909 gcc_assert (op0 == constm1_rtx);
2911 /* ... fall through ... */
2913 case REG:
2914 case AND:
2915 case IOR:
2916 case XOR:
2917 case NOT:
2918 case ASHIFTRT:
2919 case LSHIFTRT:
2920 case TRUNCATE:
2921 case SIGN_EXTEND:
2922 /* Pretend that the flags are set as for a COMPARE with zero.
2923 That's mostly true, except for the 2 right shift insns that
2924 will set the C flag. But the C flag is relevant only for
2925 the unsigned comparison operators and they are eliminated
2926 when applied to a comparison with zero. */
2927 return CCmode;
2929 default:
2930 gcc_unreachable ();
2934 /* Split a compare-and-branch with CODE, operands OP0 and OP1, and LABEL. */
2936 void
2937 visium_split_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx label)
2939 machine_mode cc_mode = visium_select_cc_mode (code, op0, op1);
2940 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2942 rtx x = gen_rtx_COMPARE (cc_mode, op0, op1);
2943 x = gen_rtx_SET (flags, x);
2944 emit_insn (x);
2946 x = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
2947 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, gen_rtx_LABEL_REF (Pmode, label),
2948 pc_rtx);
2949 x = gen_rtx_SET (pc_rtx, x);
2950 emit_jump_insn (x);
2952 visium_flags_exposed = true;
2955 /* Branch instructions on the Visium.
2957 Setting aside the interrupt-handling specific instructions, the ISA has
2958 two branch instructions: BRR and BRA. The former is used to implement
2959 short branches (+/- 2^17) within functions and its target is encoded in
2960 the instruction. The latter is used to implement all the other types
2961 of control flow changes and its target might not be statically known
2962 or even easily predictable at run time. Here's a complete summary of
2963 the patterns that generate a BRA instruction:
2965 1. Indirect jump
2966 2. Table jump
2967 3. Call
2968 4. Sibling call
2969 5. Return
2970 6. Long branch
2971 7. Trampoline
2973 Among these patterns, only the return (5) and the long branch (6) can be
2974 conditional; all the other patterns are always unconditional.
2976 The following algorithm can be used to identify the pattern for which
2977 the BRA instruction was generated and work out its target:
2979 A. If the source is r21 and the destination is r0, this is a return (5)
2980 and the target is the caller (i.e. the value of r21 on function's
2981 entry).
2983 B. If the source is rN, N != 21 and the destination is r0, this is either
2984 an indirect jump or a table jump (1, 2) and the target is not easily
2985 predictable.
2987 C. If the source is rN, N != 21 and the destination is r21, this is a call
2988 (3) and the target is given by the preceding MOVIL/MOVIU pair for rN,
2989 unless this is an indirect call in which case the target is not easily
2990 predictable.
2992 D. If the source is rN, N != 21 and the destination is also rN, this is
2993 either a sibling call or a trampoline (4, 7) and the target is given
2994 by the preceding MOVIL/MOVIU pair for rN.
2996 E. If the source is r21 and the destination is also r21, this is a long
2997 branch (6) and the target is given by the preceding MOVIL/MOVIU pair
2998 for r21.
3000 The other combinations are not used. This implementation has been devised
3001 to accommodate the branch predictor of the GR6 but is used unconditionally
3002 by the compiler, i.e. including for earlier processors. */
3004 /* Output a conditional/unconditional branch to LABEL. COND is the string
3005 condition. INSN is the instruction. */
3007 static const char *
3008 output_branch (rtx label, const char *cond, rtx_insn *insn)
3010 char str[64];
3011 rtx operands[2];
3013 gcc_assert (cond);
3014 operands[0] = label;
3016 /* If the length of the instruction is greater than 8, then this is a
3017 long branch and we need to work harder to emit it properly. */
3018 if (get_attr_length (insn) > 8)
3020 bool spilled;
3022 /* If the link register has been saved, then we use it. */
3023 if (current_function_saves_lr ())
3025 operands[1] = regno_reg_rtx [LINK_REGNUM];
3026 spilled = false;
3029 /* Or else, if the long-branch register isn't live, we use it. */
3030 else if (!df_regs_ever_live_p (long_branch_regnum))
3032 operands[1] = regno_reg_rtx [long_branch_regnum];
3033 spilled = false;
3036 /* Otherwise, we will use the long-branch register but we need to
3037 spill it to the stack and reload it at the end. We should have
3038 reserved the LR slot for this purpose. */
3039 else
3041 operands[1] = regno_reg_rtx [long_branch_regnum];
3042 spilled = true;
3043 gcc_assert (current_function_has_lr_slot ());
3046 /* First emit the spill to the stack:
3048 insn_in_delay_slot
3049 write.l [1](sp),reg */
3050 if (spilled)
3052 if (final_sequence)
3054 rtx_insn *delay = NEXT_INSN (insn);
3055 int seen;
3056 gcc_assert (delay);
3058 final_scan_insn (delay, asm_out_file, optimize, 0, &seen);
3059 PATTERN (delay) = gen_blockage ();
3060 INSN_CODE (delay) = -1;
3063 if (current_function_saves_fp ())
3064 output_asm_insn ("write.l 1(sp),%1", operands);
3065 else
3066 output_asm_insn ("write.l (sp),%1", operands);
3069 /* Then emit the core sequence:
3071 moviu reg,%u label
3072 movil reg,%l label
3073 bra tr,reg,reg
3075 We don't use r0 as the destination register of the branch because we
3076 want the Branch Pre-decode Logic of the GR6 to use the Address Load
3077 Array to predict the branch target. */
3078 output_asm_insn ("moviu %1,%%u %0", operands);
3079 output_asm_insn ("movil %1,%%l %0", operands);
3080 strcpy (str, "bra ");
3081 strcat (str, cond);
3082 strcat (str, ",%1,%1");
3083 if (!spilled)
3084 strcat (str, "%#");
3085 strcat (str, "\t\t;long branch");
3086 output_asm_insn (str, operands);
3088 /* Finally emit the reload:
3090 read.l reg,[1](sp) */
3091 if (spilled)
3093 if (current_function_saves_fp ())
3094 output_asm_insn (" read.l %1,1(sp)", operands);
3095 else
3096 output_asm_insn (" read.l %1,(sp)", operands);
3100 /* Or else, if the label is PC, then this is a return. */
3101 else if (label == pc_rtx)
3103 strcpy (str, "bra ");
3104 strcat (str, cond);
3105 strcat (str, ",r21,r0%#\t\t;return");
3106 output_asm_insn (str, operands);
3109 /* Otherwise, this is a short branch. */
3110 else
3112 strcpy (str, "brr ");
3113 strcat (str, cond);
3114 strcat (str, ",%0%#");
3115 output_asm_insn (str, operands);
3118 return "";
3121 /* Output an unconditional branch to LABEL. INSN is the instruction. */
3123 const char *
3124 output_ubranch (rtx label, rtx_insn *insn)
3126 return output_branch (label, "tr", insn);
3129 /* Output a conditional branch to LABEL. CODE is the comparison code.
3130 CC_MODE is the mode of the CC register. REVERSED is non-zero if we
3131 should reverse the sense of the comparison. INSN is the instruction. */
3133 const char *
3134 output_cbranch (rtx label, enum rtx_code code, machine_mode cc_mode,
3135 int reversed, rtx_insn *insn)
3137 const char *cond;
3139 if (reversed)
3141 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3142 code = reverse_condition_maybe_unordered (code);
3143 else
3144 code = reverse_condition (code);
3147 switch (code)
3149 case NE:
3150 if (cc_mode == CCCmode)
3151 cond = "cs";
3152 else if (cc_mode == CCVmode)
3153 cond = "os";
3154 else
3155 cond = "ne";
3156 break;
3158 case EQ:
3159 if (cc_mode == CCCmode)
3160 cond = "cc";
3161 else if (cc_mode == CCVmode)
3162 cond = "oc";
3163 else
3164 cond = "eq";
3165 break;
3167 case GE:
3168 if (cc_mode == CCNZmode)
3169 cond = "nc";
3170 else
3171 cond = "ge";
3172 break;
3174 case GT:
3175 cond = "gt";
3176 break;
3178 case LE:
3179 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3180 cond = "ls";
3181 else
3182 cond = "le";
3183 break;
3185 case LT:
3186 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3187 cond = "cs"; /* or "ns" */
3188 else if (cc_mode == CCNZmode)
3189 cond = "ns";
3190 else
3191 cond = "lt";
3192 break;
3194 case GEU:
3195 cond = "cc";
3196 break;
3198 case GTU:
3199 cond = "hi";
3200 break;
3202 case LEU:
3203 cond = "ls";
3204 break;
3206 case LTU:
3207 cond = "cs";
3208 break;
3210 case UNORDERED:
3211 cond = "os";
3212 break;
3214 case ORDERED:
3215 cond = "oc";
3216 break;
3218 case UNGE:
3219 cond = "cc"; /* or "nc" */
3220 break;
3222 case UNGT:
3223 cond = "hi";
3224 break;
3226 case UNLE:
3227 cond = "le";
3228 break;
3230 case UNLT:
3231 cond = "lt";
3232 break;
3234 /* These 2 comparison codes are not supported. */
3235 case UNEQ:
3236 case LTGT:
3237 default:
3238 gcc_unreachable ();
3241 return output_branch (label, cond, insn);
3244 /* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
3246 static bool
3247 visium_print_operand_punct_valid_p (unsigned char code)
3249 return code == '#';
3252 /* Implement TARGET_PRINT_OPERAND. Output to stdio stream FILE the assembler
3253 syntax for an instruction operand OP subject to the modifier LETTER. */
3255 static void
3256 visium_print_operand (FILE *file, rtx op, int letter)
3258 switch (letter)
3260 case '#':
3261 /* Output an insn in a delay slot. */
3262 if (final_sequence)
3263 visium_indent_opcode = 1;
3264 else
3265 fputs ("\n\t nop", file);
3266 return;
3268 case 'b':
3269 /* Print LS 8 bits of operand. */
3270 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xff);
3271 return;
3273 case 'w':
3274 /* Print LS 16 bits of operand. */
3275 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xffff);
3276 return;
3278 case 'u':
3279 /* Print MS 16 bits of operand. */
3280 fprintf (file,
3281 HOST_WIDE_INT_PRINT_UNSIGNED, (UINTVAL (op) >> 16) & 0xffff);
3282 return;
3284 case 'r':
3285 /* It's either a register or zero. */
3286 if (GET_CODE (op) == REG)
3287 fputs (reg_names[REGNO (op)], file);
3288 else
3289 fputs (reg_names[0], file);
3290 return;
3292 case 'f':
3293 /* It's either a FP register or zero. */
3294 if (GET_CODE (op) == REG)
3295 fputs (reg_names[REGNO (op)], file);
3296 else
3297 fputs (reg_names[FP_FIRST_REGNUM], file);
3298 return;
3301 switch (GET_CODE (op))
3303 case REG:
3304 if (letter == 'd')
3305 fputs (reg_names[REGNO (op) + 1], file);
3306 else
3307 fputs (reg_names[REGNO (op)], file);
3308 break;
3310 case SYMBOL_REF:
3311 case LABEL_REF:
3312 case CONST:
3313 output_addr_const (file, op);
3314 break;
3316 case MEM:
3317 visium_print_operand_address (file, GET_MODE (op), XEXP (op, 0));
3318 break;
3320 case CONST_INT:
3321 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
3322 break;
3324 case CODE_LABEL:
3325 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (op));
3326 break;
3328 case HIGH:
3329 visium_print_operand (file, XEXP (op, 1), letter);
3330 break;
3332 default:
3333 fatal_insn ("illegal operand ", op);
3337 /* Implement TARGET_PRINT_OPERAND_ADDRESS. Output to stdio stream FILE the
3338 assembler syntax for an instruction operand that is a memory reference
3339 whose address is ADDR. */
3341 static void
3342 visium_print_operand_address (FILE *file, machine_mode mode, rtx addr)
3344 switch (GET_CODE (addr))
3346 case REG:
3347 case SUBREG:
3348 fprintf (file, "(%s)", reg_names[true_regnum (addr)]);
3349 break;
3351 case PLUS:
3353 rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
3355 switch (GET_CODE (x))
3357 case REG:
3358 case SUBREG:
3359 if (CONST_INT_P (y))
3361 unsigned int regno = true_regnum (x);
3362 HOST_WIDE_INT val = INTVAL (y);
3363 switch (mode)
3365 case E_SImode:
3366 case E_DImode:
3367 case E_SFmode:
3368 case E_DFmode:
3369 val >>= 2;
3370 break;
3372 case E_HImode:
3373 val >>= 1;
3374 break;
3376 case E_QImode:
3377 default:
3378 break;
3380 fprintf (file, HOST_WIDE_INT_PRINT_DEC"(%s)", val,
3381 reg_names[regno]);
3383 else
3384 fatal_insn ("illegal operand address (1)", addr);
3385 break;
3387 default:
3388 if (CONSTANT_P (x) && CONSTANT_P (y))
3389 output_addr_const (file, addr);
3390 else
3391 fatal_insn ("illegal operand address (2)", addr);
3392 break;
3395 break;
3397 case LABEL_REF:
3398 case SYMBOL_REF:
3399 case CONST_INT:
3400 case CONST:
3401 output_addr_const (file, addr);
3402 break;
3404 case NOTE:
3405 if (NOTE_KIND (addr) != NOTE_INSN_DELETED_LABEL)
3406 fatal_insn ("illegal operand address (3)", addr);
3407 break;
3409 case CODE_LABEL:
3410 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (addr));
3411 break;
3413 default:
3414 fatal_insn ("illegal operand address (4)", addr);
3415 break;
3419 /* The Visium stack frames look like:
3421 Before call After call
3422 +-----------------------+ +-----------------------+
3423 | | | |
3424 high | previous | | previous |
3425 mem | frame | | frame |
3426 | | | |
3427 +-----------------------+ +-----------------------+
3428 | | | |
3429 | arguments on stack | | arguments on stack |
3430 | | | |
3431 SP+0->+-----------------------+ +-----------------------+
3432 | reg parm save area, |
3433 | only created for |
3434 | variable argument |
3435 | functions |
3436 +-----------------------+
3438 | register save area |
3440 +-----------------------+
3442 | local variables |
3444 FP+8->+-----------------------+
3445 | return address |
3446 FP+4->+-----------------------+
3447 | previous FP |
3448 FP+0->+-----------------------+
3450 | alloca allocations |
3452 +-----------------------+
3454 low | arguments on stack |
3455 mem | |
3456 SP+0->+-----------------------+
3458 Notes:
3459 1) The "reg parm save area" does not exist for non variable argument fns.
3460 2) The FP register is not saved if `frame_pointer_needed' is zero and it
3461 is not altered in the current function.
3462 3) The return address is not saved if there is no frame pointer and the
3463 current function is leaf.
3464 4) If the return address is not saved and the static chain register is
3465 live in the function, we allocate the return address slot to be able
3466 to spill the register for a long branch. */
3468 /* Define the register classes for local purposes. */
3469 enum reg_type { general, mdb, mdc, floating, last_type};
3471 #define GET_REG_TYPE(regno) \
3472 (GP_REGISTER_P (regno) ? general : \
3473 (regno) == MDB_REGNUM ? mdb : \
3474 (regno) == MDC_REGNUM ? mdc : \
3475 floating)
3477 /* First regno of each register type. */
3478 const int first_regno[last_type] = {0, MDB_REGNUM, MDC_REGNUM, FP_FIRST_REGNUM};
3480 /* Size in bytes of each register type. */
3481 const int reg_type_size[last_type] = {4, 8, 4, 4};
3483 /* Structure to be filled in by visium_compute_frame_size. */
3484 struct visium_frame_info
3486 unsigned int save_area_size; /* # bytes in the reg parm save area. */
3487 unsigned int reg_size1; /* # bytes to store first block of regs. */
3488 unsigned int reg_size2; /* # bytes to store second block of regs. */
3489 unsigned int max_reg1; /* max. regno in first block */
3490 unsigned int var_size; /* # bytes that variables take up. */
3491 unsigned int save_fp; /* Nonzero if fp must be saved. */
3492 unsigned int save_lr; /* Nonzero if lr must be saved. */
3493 unsigned int lr_slot; /* Nonzero if the lr slot is needed. */
3494 unsigned int combine; /* Nonzero if we can combine the allocation of
3495 variables and regs. */
3496 unsigned int interrupt; /* Nonzero if the function is an interrupt
3497 handler. */
3498 unsigned int mask[last_type]; /* Masks of saved regs: gp, mdb, mdc, fp */
3501 /* Current frame information calculated by visium_compute_frame_size. */
3502 static struct visium_frame_info current_frame_info;
3504 /* Accessor for current_frame_info.save_fp. */
3506 static inline bool
3507 current_function_saves_fp (void)
3509 return current_frame_info.save_fp != 0;
3512 /* Accessor for current_frame_info.save_lr. */
3514 static inline bool
3515 current_function_saves_lr (void)
3517 return current_frame_info.save_lr != 0;
3520 /* Accessor for current_frame_info.lr_slot. */
3522 static inline bool
3523 current_function_has_lr_slot (void)
3525 return current_frame_info.lr_slot != 0;
3528 /* Return non-zero if register REGNO needs to be saved in the frame. */
3530 static int
3531 visium_save_reg_p (int interrupt, int regno)
3533 switch (regno)
3535 case HARD_FRAME_POINTER_REGNUM:
3536 /* This register is call-saved but handled specially. */
3537 return 0;
3539 case MDC_REGNUM:
3540 /* This register is fixed but can be modified. */
3541 break;
3543 case 29:
3544 case 30:
3545 /* These registers are fixed and hold the interrupt context. */
3546 return (interrupt != 0);
3548 default:
3549 /* The other fixed registers are either immutable or special. */
3550 if (fixed_regs[regno])
3551 return 0;
3552 break;
3555 if (interrupt)
3557 if (crtl->is_leaf)
3559 if (df_regs_ever_live_p (regno))
3560 return 1;
3562 else if (call_used_regs[regno])
3563 return 1;
3565 /* To save mdb requires two temporary registers. To save mdc or
3566 any of the floating registers requires one temporary
3567 register. If this is an interrupt routine, the temporary
3568 registers need to be saved as well. These temporary registers
3569 are call used, so we only need deal with the case of leaf
3570 functions here. */
3571 if (regno == PROLOGUE_TMP_REGNUM)
3573 if (df_regs_ever_live_p (MDB_REGNUM)
3574 || df_regs_ever_live_p (MDC_REGNUM))
3575 return 1;
3577 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
3578 if (df_regs_ever_live_p (i))
3579 return 1;
3582 else if (regno == PROLOGUE_TMP_REGNUM + 1)
3584 if (df_regs_ever_live_p (MDB_REGNUM))
3585 return 1;
3589 return df_regs_ever_live_p (regno) && !call_used_regs[regno];
3592 /* Compute the frame size required by the function. This function is called
3593 during the reload pass and also by visium_expand_prologue. */
3595 static int
3596 visium_compute_frame_size (int size)
3598 const int save_area_size = visium_reg_parm_save_area_size;
3599 const int var_size = VISIUM_STACK_ALIGN (size);
3600 const int save_fp
3601 = frame_pointer_needed || df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM);
3602 const int save_lr = frame_pointer_needed || !crtl->is_leaf;
3603 const int lr_slot = !save_lr && df_regs_ever_live_p (long_branch_regnum);
3604 const int local_frame_offset
3605 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3606 const int interrupt = visium_interrupt_function_p ();
3607 unsigned int mask[last_type];
3608 int reg_size1 = 0;
3609 int max_reg1 = 0;
3610 int reg_size2 = 0;
3611 int reg_size;
3612 int combine;
3613 int frame_size;
3614 int regno;
3616 memset (mask, 0, last_type * sizeof (unsigned int));
3618 /* The registers may need stacking in 2 blocks since only 32 32-bit words
3619 can be indexed from a given base address. */
3620 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3622 if (visium_save_reg_p (interrupt, regno))
3624 enum reg_type reg_type = GET_REG_TYPE (regno);
3625 int mask_bit = 1 << (regno - first_regno[reg_type]);
3626 int nbytes = reg_type_size[reg_type];
3628 if (reg_size1 + nbytes > 32 * UNITS_PER_WORD)
3629 break;
3631 reg_size1 += nbytes;
3632 max_reg1 = regno;
3633 mask[reg_type] |= mask_bit;
3637 for (regno = max_reg1 + 1; regno < FIRST_PSEUDO_REGISTER; regno++)
3639 if (visium_save_reg_p (interrupt, regno))
3641 enum reg_type reg_type = GET_REG_TYPE (regno);
3642 int mask_bit = 1 << (regno - first_regno[reg_type]);
3643 int nbytes = reg_type_size[reg_type];
3645 reg_size2 += nbytes;
3646 mask[reg_type] |= mask_bit;
3650 reg_size = reg_size2 ? reg_size2 : reg_size1;
3651 combine = (local_frame_offset + var_size + reg_size) <= 32 * UNITS_PER_WORD;
3652 frame_size
3653 = local_frame_offset + var_size + reg_size2 + reg_size1 + save_area_size;
3655 current_frame_info.save_area_size = save_area_size;
3656 current_frame_info.reg_size1 = reg_size1;
3657 current_frame_info.max_reg1 = max_reg1;
3658 current_frame_info.reg_size2 = reg_size2;
3659 current_frame_info.var_size = var_size;
3660 current_frame_info.save_fp = save_fp;
3661 current_frame_info.save_lr = save_lr;
3662 current_frame_info.lr_slot = lr_slot;
3663 current_frame_info.combine = combine;
3664 current_frame_info.interrupt = interrupt;
3666 memcpy (current_frame_info.mask, mask, last_type * sizeof (unsigned int));
3668 return frame_size;
3671 /* Helper function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define
3672 the offset between two registers, one to be eliminated, and the other its
3673 replacement, at the start of a routine. */
3676 visium_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
3678 const int save_fp = current_frame_info.save_fp;
3679 const int save_lr = current_frame_info.save_lr;
3680 const int lr_slot = current_frame_info.lr_slot;
3681 int offset;
3683 if (from == FRAME_POINTER_REGNUM)
3684 offset = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3685 else if (from == ARG_POINTER_REGNUM)
3686 offset = visium_compute_frame_size (get_frame_size ());
3687 else
3688 gcc_unreachable ();
3690 return offset;
3693 /* For an interrupt handler, we may be saving call-clobbered registers.
3694 Say the epilogue uses these in addition to the link register. */
3697 visium_epilogue_uses (int regno)
3699 if (regno == LINK_REGNUM)
3700 return 1;
3702 if (reload_completed)
3704 enum reg_type reg_type = GET_REG_TYPE (regno);
3705 int mask_bit = 1 << (regno - first_regno[reg_type]);
3707 return (current_frame_info.mask[reg_type] & mask_bit) != 0;
3710 return 0;
3713 /* Wrapper around emit_insn that sets RTX_FRAME_RELATED_P on the insn. */
3715 static rtx
3716 emit_frame_insn (rtx x)
3718 x = emit_insn (x);
3719 RTX_FRAME_RELATED_P (x) = 1;
3720 return x;
3723 /* Allocate ALLOC bytes on the stack and save the registers LOW_REGNO to
3724 HIGH_REGNO at OFFSET from the stack pointer. */
3726 static void
3727 visium_save_regs (int alloc, int offset, int low_regno, int high_regno)
3729 /* If this is an interrupt handler function, then mark the register
3730 stores as volatile. This will prevent the instruction scheduler
3731 from scrambling the order of register saves. */
3732 const int volatile_p = current_frame_info.interrupt;
3733 int regno;
3735 /* Allocate the stack space. */
3736 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, stack_pointer_rtx,
3737 GEN_INT (-alloc)));
3739 for (regno = low_regno; regno <= high_regno; regno++)
3741 enum reg_type reg_type = GET_REG_TYPE (regno);
3742 int mask_bit = 1 << (regno - first_regno[reg_type]);
3743 rtx insn;
3745 if (current_frame_info.mask[reg_type] & mask_bit)
3747 offset -= reg_type_size[reg_type];
3748 switch (reg_type)
3750 case general:
3752 rtx mem
3753 = gen_frame_mem (SImode,
3754 plus_constant (Pmode,
3755 stack_pointer_rtx, offset));
3756 MEM_VOLATILE_P (mem) = volatile_p;
3757 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, regno)));
3759 break;
3761 case mdb:
3763 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3764 rtx mem
3765 = gen_frame_mem (DImode,
3766 plus_constant (Pmode,
3767 stack_pointer_rtx, offset));
3768 rtx reg = gen_rtx_REG (DImode, regno);
3769 MEM_VOLATILE_P (mem) = volatile_p;
3770 emit_insn (gen_movdi (tmp, reg));
3771 /* Do not generate CFI if in interrupt handler. */
3772 if (volatile_p)
3773 emit_insn (gen_movdi (mem, tmp));
3774 else
3776 insn = emit_frame_insn (gen_movdi (mem, tmp));
3777 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3778 gen_rtx_SET (mem, reg));
3781 break;
3783 case mdc:
3785 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3786 rtx mem
3787 = gen_frame_mem (SImode,
3788 plus_constant (Pmode,
3789 stack_pointer_rtx, offset));
3790 rtx reg = gen_rtx_REG (SImode, regno);
3791 MEM_VOLATILE_P (mem) = volatile_p;
3792 emit_insn (gen_movsi (tmp, reg));
3793 insn = emit_frame_insn (gen_movsi (mem, tmp));
3794 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3795 gen_rtx_SET (mem, reg));
3797 break;
3799 case floating:
3801 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3802 rtx mem
3803 = gen_frame_mem (SFmode,
3804 plus_constant (Pmode,
3805 stack_pointer_rtx, offset));
3806 rtx reg = gen_rtx_REG (SFmode, regno);
3807 MEM_VOLATILE_P (mem) = volatile_p;
3808 emit_insn (gen_movsf (tmp, reg));
3809 insn = emit_frame_insn (gen_movsf (mem, tmp));
3810 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3811 gen_rtx_SET (mem, reg));
3813 break;
3815 default:
3816 break;
3822 /* This function generates the code for function entry. */
3824 void
3825 visium_expand_prologue (void)
3827 const int frame_size = visium_compute_frame_size (get_frame_size ());
3828 const int save_area_size = current_frame_info.save_area_size;
3829 const int reg_size1 = current_frame_info.reg_size1;
3830 const int max_reg1 = current_frame_info.max_reg1;
3831 const int reg_size2 = current_frame_info.reg_size2;
3832 const int var_size = current_frame_info.var_size;
3833 const int save_fp = current_frame_info.save_fp;
3834 const int save_lr = current_frame_info.save_lr;
3835 const int lr_slot = current_frame_info.lr_slot;
3836 const int local_frame_offset
3837 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3838 const int combine = current_frame_info.combine;
3839 int reg_size;
3840 int first_reg;
3841 int fsize;
3843 /* Save the frame size for future references. */
3844 visium_frame_size = frame_size;
3846 if (flag_stack_usage_info)
3847 current_function_static_stack_size = frame_size;
3849 /* If the registers have to be stacked in 2 blocks, stack the first one. */
3850 if (reg_size2)
3852 visium_save_regs (reg_size1 + save_area_size, reg_size1, 0, max_reg1);
3853 reg_size = reg_size2;
3854 first_reg = max_reg1 + 1;
3855 fsize = local_frame_offset + var_size + reg_size2;
3857 else
3859 reg_size = reg_size1;
3860 first_reg = 0;
3861 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
3864 /* If we can't combine register stacking with variable allocation, partially
3865 allocate and stack the (remaining) registers now. */
3866 if (reg_size && !combine)
3867 visium_save_regs (fsize - local_frame_offset - var_size, reg_size,
3868 first_reg, FIRST_PSEUDO_REGISTER - 1);
3870 /* If we can combine register stacking with variable allocation, fully
3871 allocate and stack the (remaining) registers now. */
3872 if (reg_size && combine)
3873 visium_save_regs (fsize, local_frame_offset + var_size + reg_size,
3874 first_reg, FIRST_PSEUDO_REGISTER - 1);
3876 /* Otherwise space may still need to be allocated for the variables. */
3877 else if (fsize)
3879 const int alloc_size = reg_size ? local_frame_offset + var_size : fsize;
3881 if (alloc_size > 65535)
3883 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM), insn;
3884 emit_insn (gen_movsi (tmp, GEN_INT (alloc_size)));
3885 insn = emit_frame_insn (gen_subsi3_flags (stack_pointer_rtx,
3886 stack_pointer_rtx,
3887 tmp));
3888 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3889 gen_rtx_SET (stack_pointer_rtx,
3890 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3891 GEN_INT (-alloc_size))));
3893 else
3894 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx,
3895 stack_pointer_rtx,
3896 GEN_INT (-alloc_size)));
3899 if (save_fp)
3900 emit_frame_insn (gen_movsi (gen_frame_mem (SImode, stack_pointer_rtx),
3901 hard_frame_pointer_rtx));
3903 if (frame_pointer_needed)
3904 emit_frame_insn (gen_stack_save ());
3906 if (save_lr)
3908 rtx base_rtx, mem;
3910 /* Normally the frame pointer and link register get saved via
3911 write.l (sp),fp
3912 move.l fp,sp
3913 write.l 1(sp),r21
3915 Indexing off sp rather than fp to store the link register
3916 avoids presenting the instruction scheduler with an initial
3917 pipeline hazard. If however the frame is needed for eg.
3918 __builtin_return_address which needs to retrieve the saved
3919 value of the link register from the stack at fp + 4 then
3920 indexing from sp can confuse the dataflow, causing the link
3921 register to be retrieved before it has been saved. */
3922 if (cfun->machine->frame_needed)
3923 base_rtx = hard_frame_pointer_rtx;
3924 else
3925 base_rtx = stack_pointer_rtx;
3927 mem = gen_frame_mem (SImode,
3928 plus_constant (Pmode,
3929 base_rtx, save_fp * UNITS_PER_WORD));
3930 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, LINK_REGNUM)));
3934 static GTY(()) rtx cfa_restores;
3936 /* Queue a REG_CFA_RESTORE note until next stack manipulation insn. */
3938 static void
3939 visium_add_cfa_restore_note (rtx reg)
3941 cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
3944 /* Add queued REG_CFA_RESTORE notes to INSN, if any. */
3946 static void
3947 visium_add_queued_cfa_restore_notes (rtx insn)
3949 rtx last;
3950 if (!cfa_restores)
3951 return;
3952 for (last = cfa_restores; XEXP (last, 1); last = XEXP (last, 1))
3954 XEXP (last, 1) = REG_NOTES (insn);
3955 REG_NOTES (insn) = cfa_restores;
3956 cfa_restores = NULL_RTX;
3959 /* Restore the registers LOW_REGNO to HIGH_REGNO from the save area at OFFSET
3960 from the stack pointer and pop DEALLOC bytes off the stack. */
3962 static void
3963 visium_restore_regs (int dealloc, int offset, int high_regno, int low_regno)
3965 /* If this is an interrupt handler function, then mark the register
3966 restores as volatile. This will prevent the instruction scheduler
3967 from scrambling the order of register restores. */
3968 const int volatile_p = current_frame_info.interrupt;
3969 int r30_offset = -1;
3970 int regno;
3972 for (regno = high_regno; regno >= low_regno; --regno)
3974 enum reg_type reg_type = GET_REG_TYPE (regno);
3975 int mask_bit = 1 << (regno - first_regno[reg_type]);
3977 if (current_frame_info.mask[reg_type] & mask_bit)
3979 switch (reg_type)
3981 case general:
3982 /* Postpone restoring the interrupted context registers
3983 until last, since they need to be preceded by a dsi. */
3984 if (regno == 29)
3986 else if (regno == 30)
3987 r30_offset = offset;
3988 else
3990 rtx mem
3991 = gen_frame_mem (SImode,
3992 plus_constant (Pmode,
3993 stack_pointer_rtx,
3994 offset));
3995 rtx reg = gen_rtx_REG (SImode, regno);
3996 MEM_VOLATILE_P (mem) = volatile_p;
3997 emit_insn (gen_movsi (reg, mem));
3998 visium_add_cfa_restore_note (reg);
4000 break;
4002 case mdb:
4004 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
4005 rtx mem
4006 = gen_frame_mem (DImode,
4007 plus_constant (Pmode,
4008 stack_pointer_rtx, offset));
4009 rtx reg = gen_rtx_REG (DImode, regno);
4010 MEM_VOLATILE_P (mem) = volatile_p;
4011 emit_insn (gen_movdi (tmp, mem));
4012 emit_insn (gen_movdi (reg, tmp));
4013 /* Do not generate CFI if in interrupt handler. */
4014 if (!volatile_p)
4015 visium_add_cfa_restore_note (reg);
4017 break;
4019 case mdc:
4021 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4022 rtx mem
4023 = gen_frame_mem (SImode,
4024 plus_constant (Pmode,
4025 stack_pointer_rtx, offset));
4026 rtx reg = gen_rtx_REG (SImode, regno);
4027 MEM_VOLATILE_P (mem) = volatile_p;
4028 emit_insn (gen_movsi (tmp, mem));
4029 emit_insn (gen_movsi (reg, tmp));
4030 visium_add_cfa_restore_note (reg);
4032 break;
4034 case floating:
4036 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
4037 rtx mem
4038 = gen_frame_mem (SFmode,
4039 plus_constant (Pmode,
4040 stack_pointer_rtx, offset));
4041 rtx reg = gen_rtx_REG (SFmode, regno);
4042 MEM_VOLATILE_P (mem) = volatile_p;
4043 emit_insn (gen_movsf (tmp, mem));
4044 emit_insn (gen_movsf (reg, tmp));
4045 visium_add_cfa_restore_note (reg);
4047 break;
4049 default:
4050 break;
4053 offset += reg_type_size[reg_type];
4057 /* If the interrupted context needs to be restored, precede the
4058 restores of r29 and r30 by a dsi. */
4059 if (r30_offset >= 0)
4061 emit_insn (gen_dsi ());
4062 emit_move_insn (gen_rtx_REG (SImode, 30),
4063 gen_frame_mem (SImode,
4064 plus_constant (Pmode,
4065 stack_pointer_rtx,
4066 r30_offset)));
4067 emit_move_insn (gen_rtx_REG (SImode, 29),
4068 gen_frame_mem (SImode,
4069 plus_constant (Pmode,
4070 stack_pointer_rtx,
4071 r30_offset + 4)));
4074 /* Deallocate the stack space. */
4075 rtx insn = emit_frame_insn (gen_stack_pop (GEN_INT (dealloc)));
4076 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4077 gen_rtx_SET (stack_pointer_rtx,
4078 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4079 GEN_INT (dealloc))));
4080 visium_add_queued_cfa_restore_notes (insn);
4083 /* This function generates the code for function exit. */
4085 void
4086 visium_expand_epilogue (void)
4088 const int save_area_size = current_frame_info.save_area_size;
4089 const int reg_size1 = current_frame_info.reg_size1;
4090 const int max_reg1 = current_frame_info.max_reg1;
4091 const int reg_size2 = current_frame_info.reg_size2;
4092 const int var_size = current_frame_info.var_size;
4093 const int restore_fp = current_frame_info.save_fp;
4094 const int restore_lr = current_frame_info.save_lr;
4095 const int lr_slot = current_frame_info.lr_slot;
4096 const int local_frame_offset
4097 = (restore_fp + restore_lr + lr_slot) * UNITS_PER_WORD;
4098 const int combine = current_frame_info.combine;
4099 int reg_size;
4100 int last_reg;
4101 int fsize;
4103 /* Do not bother restoring the stack pointer if it hasn't been changed in
4104 the function since it was saved _after_ the allocation of the frame. */
4105 if (!crtl->sp_is_unchanging)
4106 emit_insn (gen_stack_restore ());
4108 /* Restore the frame pointer if necessary. The usual code would be:
4110 move.l sp,fp
4111 read.l fp,(sp)
4113 but for the MCM this constitutes a stall/hazard so it is changed to:
4115 move.l sp,fp
4116 read.l fp,(fp)
4118 if the stack pointer has actually been restored. */
4119 if (restore_fp)
4121 rtx src;
4123 if (TARGET_MCM && !crtl->sp_is_unchanging)
4124 src = gen_frame_mem (SImode, hard_frame_pointer_rtx);
4125 else
4126 src = gen_frame_mem (SImode, stack_pointer_rtx);
4128 rtx insn = emit_frame_insn (gen_movsi (hard_frame_pointer_rtx, src));
4129 add_reg_note (insn, REG_CFA_ADJUST_CFA,
4130 gen_rtx_SET (stack_pointer_rtx,
4131 hard_frame_pointer_rtx));
4132 visium_add_cfa_restore_note (hard_frame_pointer_rtx);
4135 /* Restore the link register if necessary. */
4136 if (restore_lr)
4138 rtx mem = gen_frame_mem (SImode,
4139 plus_constant (Pmode,
4140 stack_pointer_rtx,
4141 restore_fp * UNITS_PER_WORD));
4142 rtx reg = gen_rtx_REG (SImode, LINK_REGNUM);
4143 emit_insn (gen_movsi (reg, mem));
4144 visium_add_cfa_restore_note (reg);
4147 /* If we have two blocks of registers, deal with the second one first. */
4148 if (reg_size2)
4150 reg_size = reg_size2;
4151 last_reg = max_reg1 + 1;
4152 fsize = local_frame_offset + var_size + reg_size2;
4154 else
4156 reg_size = reg_size1;
4157 last_reg = 0;
4158 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
4161 /* If the variable allocation could be combined with register stacking,
4162 restore the (remaining) registers and fully deallocate now. */
4163 if (reg_size && combine)
4164 visium_restore_regs (fsize, local_frame_offset + var_size,
4165 FIRST_PSEUDO_REGISTER - 1, last_reg);
4167 /* Otherwise deallocate the variables first. */
4168 else if (fsize)
4170 const int pop_size = reg_size ? local_frame_offset + var_size : fsize;
4171 rtx insn;
4173 if (pop_size > 65535)
4175 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4176 emit_move_insn (tmp, GEN_INT (pop_size));
4177 insn = emit_frame_insn (gen_stack_pop (tmp));
4179 else
4180 insn = emit_frame_insn (gen_stack_pop (GEN_INT (pop_size)));
4181 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4182 gen_rtx_SET (stack_pointer_rtx,
4183 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4184 GEN_INT (pop_size))));
4185 visium_add_queued_cfa_restore_notes (insn);
4188 /* If the variable allocation couldn't be combined with register stacking,
4189 restore the (remaining) registers now and partially deallocate. */
4190 if (reg_size && !combine)
4191 visium_restore_regs (fsize - local_frame_offset - var_size, 0,
4192 FIRST_PSEUDO_REGISTER - 1, last_reg);
4194 /* If the first block of registers has yet to be restored, do it now. */
4195 if (reg_size2)
4196 visium_restore_regs (reg_size1 + save_area_size, 0, max_reg1, 0);
4198 /* If this is an exception return, make the necessary stack adjustment. */
4199 if (crtl->calls_eh_return)
4200 emit_insn (gen_stack_pop (EH_RETURN_STACKADJ_RTX));
4203 /* Return true if it is appropriate to emit `return' instructions in the
4204 body of a function. */
4206 bool
4207 visium_can_use_return_insn_p (void)
4209 return reload_completed
4210 && visium_frame_size == 0
4211 && !visium_interrupt_function_p ();
4214 /* Return the register class required for an intermediate register used to
4215 copy a register of RCLASS from/to X. If no such intermediate register is
4216 required, return NO_REGS. If more than one such intermediate register is
4217 required, describe the one that is closest in the copy chain to the reload
4218 register. */
4220 static reg_class_t
4221 visium_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
4222 reg_class_t rclass,
4223 machine_mode mode ATTRIBUTE_UNUSED,
4224 secondary_reload_info *sri ATTRIBUTE_UNUSED)
4226 int regno = true_regnum (x);
4228 /* For MDB, MDC and FP_REGS, a general register is needed for a move to
4229 or from memory. */
4230 if (regno == -1 && (rclass == MDB || rclass == MDC || rclass == FP_REGS))
4231 return GENERAL_REGS;
4233 /* Moves between MDB, MDC and FP_REGS also require a general register. */
4234 else if (((regno == R_MDB || regno == R_MDC) && rclass == FP_REGS)
4235 || (FP_REGISTER_P (regno) && (rclass == MDB || rclass == MDC)))
4236 return GENERAL_REGS;
4238 /* Finally an (unlikely ?) move between MDB and MDC needs a general reg. */
4239 else if ((regno == R_MDB && rclass == MDC)
4240 || (rclass == MDB && regno == R_MDC))
4241 return GENERAL_REGS;
4243 return NO_REGS;
4246 /* Return true if pseudos that have been assigned to registers of RCLASS
4247 would likely be spilled because registers of RCLASS are needed for
4248 spill registers. */
4250 static bool
4251 visium_class_likely_spilled_p (reg_class_t rclass ATTRIBUTE_UNUSED)
4253 /* Return false for classes R1, R2 and R3, which are intended to be used
4254 only in the source code in conjunction with block move instructions. */
4255 return false;
4258 /* Return the register number if OP is a REG or a SUBREG of a REG, and
4259 INVALID_REGNUM in all the other cases. */
4261 unsigned int
4262 reg_or_subreg_regno (rtx op)
4264 unsigned int regno;
4266 if (GET_CODE (op) == REG)
4267 regno = REGNO (op);
4268 else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
4270 if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
4271 regno = subreg_regno (op);
4272 else
4273 regno = REGNO (SUBREG_REG (op));
4275 else
4276 regno = INVALID_REGNUM;
4278 return regno;
4281 #include "gt-visium.h"