* config/visium/visium.c (visium_select_cc_mode): Return CCmode
[official-gcc.git] / gcc / config / visium / visium.c
blob3311dd2a349d39fd730cb6000c67d6ab17ad0145
1 /* Output routines for Visium.
2 Copyright (C) 2002-2017 Free Software Foundation, Inc.
3 Contributed by C.Nettleton, J.P.Parkes and P.Garbett.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "target.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "gimple-expr.h"
29 #include "df.h"
30 #include "memmodel.h"
31 #include "tm_p.h"
32 #include "stringpool.h"
33 #include "attribs.h"
34 #include "expmed.h"
35 #include "optabs.h"
36 #include "regs.h"
37 #include "emit-rtl.h"
38 #include "recog.h"
39 #include "diagnostic-core.h"
40 #include "alias.h"
41 #include "flags.h"
42 #include "fold-const.h"
43 #include "stor-layout.h"
44 #include "calls.h"
45 #include "varasm.h"
46 #include "output.h"
47 #include "insn-attr.h"
48 #include "explow.h"
49 #include "expr.h"
50 #include "gimplify.h"
51 #include "langhooks.h"
52 #include "reload.h"
53 #include "tm-constrs.h"
54 #include "params.h"
55 #include "tree-pass.h"
56 #include "context.h"
57 #include "builtins.h"
59 /* This file should be included last. */
60 #include "target-def.h"
62 /* Enumeration of indexes into machine_libfunc_table. */
63 enum machine_libfunc_index
65 MLTI_long_int_memcpy,
66 MLTI_wrd_memcpy,
67 MLTI_byt_memcpy,
69 MLTI_long_int_memset,
70 MLTI_wrd_memset,
71 MLTI_byt_memset,
73 MLTI_set_trampoline_parity,
75 MLTI_MAX
78 struct GTY(()) machine_libfuncs
80 rtx table[MLTI_MAX];
83 /* The table of Visium-specific libfuncs. */
84 static GTY(()) struct machine_libfuncs visium_libfuncs;
86 #define vlt visium_libfuncs.table
88 /* Accessor macros for visium_libfuncs. */
89 #define long_int_memcpy_libfunc (vlt[MLTI_long_int_memcpy])
90 #define wrd_memcpy_libfunc (vlt[MLTI_wrd_memcpy])
91 #define byt_memcpy_libfunc (vlt[MLTI_byt_memcpy])
92 #define long_int_memset_libfunc (vlt[MLTI_long_int_memset])
93 #define wrd_memset_libfunc (vlt[MLTI_wrd_memset])
94 #define byt_memset_libfunc (vlt[MLTI_byt_memset])
95 #define set_trampoline_parity_libfunc (vlt[MLTI_set_trampoline_parity])
97 /* Machine specific function data. */
98 struct GTY (()) machine_function
100 /* Size of the frame of the function. */
101 int frame_size;
103 /* Size of the reg parm save area, non-zero only for functions with variable
104 argument list. We cannot use the crtl->args.pretend_args_size machinery
105 for this purpose because this size is added to virtual_incoming_args_rtx
106 to give the location of the first parameter passed by the caller on the
107 stack and virtual_incoming_args_rtx is also the location of the first
108 parameter on the stack. So crtl->args.pretend_args_size can be non-zero
109 only if the first non-register named parameter is not passed entirely on
110 the stack and this runs afoul of the need to have a reg parm save area
111 even with a variable argument list starting on the stack because of the
112 separate handling of general and floating-point registers. */
113 int reg_parm_save_area_size;
115 /* True if we have created an rtx which relies on the frame pointer. */
116 bool frame_needed;
118 /* True if we have exposed the flags register. From this moment on, we
119 cannot generate simple operations for integer registers. We could
120 use reload_completed for this purpose, but this would cripple the
121 postreload CSE and GCSE passes which run before postreload split. */
122 bool flags_exposed;
125 #define visium_frame_size cfun->machine->frame_size
126 #define visium_reg_parm_save_area_size cfun->machine->reg_parm_save_area_size
127 #define visium_frame_needed cfun->machine->frame_needed
128 #define visium_flags_exposed cfun->machine->flags_exposed
130 /* 1 if the next opcode is to be specially indented. */
131 int visium_indent_opcode = 0;
133 /* Register number used for long branches when LR isn't available. It
134 must be a call-used register since it isn't saved on function entry.
135 We do not care whether the branch is predicted or not on the GR6,
136 given how unlikely it is to have a long branch in a leaf function. */
137 static unsigned int long_branch_regnum = 31;
139 static tree visium_handle_interrupt_attr (tree *, tree, tree, int, bool *);
140 static inline bool current_function_saves_fp (void);
141 static inline bool current_function_saves_lr (void);
142 static inline bool current_function_has_lr_slot (void);
144 /* Supported attributes:
145 interrupt -- specifies this function is an interrupt handler. */
146 static const struct attribute_spec visium_attribute_table[] =
148 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
149 affects_type_identity } */
150 {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false},
151 {NULL, 0, 0, false, false, false, NULL, false}
154 static struct machine_function *visium_init_machine_status (void);
156 /* Target hooks and TARGET_INITIALIZER */
158 static bool visium_pass_by_reference (cumulative_args_t, machine_mode,
159 const_tree, bool);
161 static rtx visium_function_arg (cumulative_args_t, machine_mode,
162 const_tree, bool);
164 static void visium_function_arg_advance (cumulative_args_t, machine_mode,
165 const_tree, bool);
167 static bool visium_return_in_memory (const_tree, const_tree fntype);
169 static rtx visium_function_value (const_tree, const_tree fn_decl_or_type,
170 bool);
172 static rtx visium_libcall_value (machine_mode, const_rtx);
174 static void visium_setup_incoming_varargs (cumulative_args_t,
175 machine_mode,
176 tree, int *, int);
178 static void visium_va_start (tree valist, rtx nextarg);
180 static tree visium_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
182 static bool visium_function_ok_for_sibcall (tree, tree);
184 static bool visium_frame_pointer_required (void);
186 static tree visium_build_builtin_va_list (void);
188 static rtx_insn *visium_md_asm_adjust (vec<rtx> &, vec<rtx> &,
189 vec<const char *> &,
190 vec<rtx> &, HARD_REG_SET &);
192 static bool visium_legitimate_constant_p (machine_mode, rtx);
194 static bool visium_legitimate_address_p (machine_mode, rtx, bool);
196 static bool visium_print_operand_punct_valid_p (unsigned char);
197 static void visium_print_operand (FILE *, rtx, int);
198 static void visium_print_operand_address (FILE *, machine_mode, rtx);
200 static void visium_conditional_register_usage (void);
202 static rtx visium_legitimize_address (rtx, rtx, machine_mode);
204 static reg_class_t visium_secondary_reload (bool, rtx, reg_class_t,
205 machine_mode,
206 secondary_reload_info *);
208 static bool visium_class_likely_spilled_p (reg_class_t);
210 static void visium_trampoline_init (rtx, tree, rtx);
212 static int visium_issue_rate (void);
214 static int visium_adjust_priority (rtx_insn *, int);
216 static int visium_adjust_cost (rtx_insn *, int, rtx_insn *, int, unsigned int);
218 static int visium_register_move_cost (machine_mode, reg_class_t,
219 reg_class_t);
221 static int visium_memory_move_cost (machine_mode, reg_class_t, bool);
223 static bool visium_rtx_costs (rtx, machine_mode, int, int, int *, bool);
225 static void visium_option_override (void);
227 static void visium_init_libfuncs (void);
229 static unsigned int visium_reorg (void);
231 static unsigned int visium_hard_regno_nregs (unsigned int, machine_mode);
233 static bool visium_hard_regno_mode_ok (unsigned int, machine_mode);
235 static bool visium_modes_tieable_p (machine_mode, machine_mode);
237 static bool visium_can_change_mode_class (machine_mode, machine_mode,
238 reg_class_t);
240 static HOST_WIDE_INT visium_constant_alignment (const_tree, HOST_WIDE_INT);
242 /* Setup the global target hooks structure. */
244 #undef TARGET_MAX_ANCHOR_OFFSET
245 #define TARGET_MAX_ANCHOR_OFFSET 31
247 #undef TARGET_PASS_BY_REFERENCE
248 #define TARGET_PASS_BY_REFERENCE visium_pass_by_reference
250 #undef TARGET_FUNCTION_ARG
251 #define TARGET_FUNCTION_ARG visium_function_arg
253 #undef TARGET_FUNCTION_ARG_ADVANCE
254 #define TARGET_FUNCTION_ARG_ADVANCE visium_function_arg_advance
256 #undef TARGET_RETURN_IN_MEMORY
257 #define TARGET_RETURN_IN_MEMORY visium_return_in_memory
259 #undef TARGET_FUNCTION_VALUE
260 #define TARGET_FUNCTION_VALUE visium_function_value
262 #undef TARGET_LIBCALL_VALUE
263 #define TARGET_LIBCALL_VALUE visium_libcall_value
265 #undef TARGET_SETUP_INCOMING_VARARGS
266 #define TARGET_SETUP_INCOMING_VARARGS visium_setup_incoming_varargs
268 #undef TARGET_EXPAND_BUILTIN_VA_START
269 #define TARGET_EXPAND_BUILTIN_VA_START visium_va_start
271 #undef TARGET_BUILD_BUILTIN_VA_LIST
272 #define TARGET_BUILD_BUILTIN_VA_LIST visium_build_builtin_va_list
274 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
275 #define TARGET_GIMPLIFY_VA_ARG_EXPR visium_gimplify_va_arg
277 #undef TARGET_LEGITIMATE_CONSTANT_P
278 #define TARGET_LEGITIMATE_CONSTANT_P visium_legitimate_constant_p
280 #undef TARGET_LRA_P
281 #define TARGET_LRA_P hook_bool_void_false
283 #undef TARGET_LEGITIMATE_ADDRESS_P
284 #define TARGET_LEGITIMATE_ADDRESS_P visium_legitimate_address_p
286 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
287 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P visium_print_operand_punct_valid_p
288 #undef TARGET_PRINT_OPERAND
289 #define TARGET_PRINT_OPERAND visium_print_operand
290 #undef TARGET_PRINT_OPERAND_ADDRESS
291 #define TARGET_PRINT_OPERAND_ADDRESS visium_print_operand_address
293 #undef TARGET_ATTRIBUTE_TABLE
294 #define TARGET_ATTRIBUTE_TABLE visium_attribute_table
296 #undef TARGET_ADDRESS_COST
297 #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
299 #undef TARGET_STRICT_ARGUMENT_NAMING
300 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
302 #undef TARGET_SCHED_ISSUE_RATE
303 #define TARGET_SCHED_ISSUE_RATE visium_issue_rate
305 #undef TARGET_SCHED_ADJUST_PRIORITY
306 #define TARGET_SCHED_ADJUST_PRIORITY visium_adjust_priority
308 #undef TARGET_SCHED_ADJUST_COST
309 #define TARGET_SCHED_ADJUST_COST visium_adjust_cost
311 #undef TARGET_MEMORY_MOVE_COST
312 #define TARGET_MEMORY_MOVE_COST visium_memory_move_cost
314 #undef TARGET_REGISTER_MOVE_COST
315 #define TARGET_REGISTER_MOVE_COST visium_register_move_cost
317 #undef TARGET_RTX_COSTS
318 #define TARGET_RTX_COSTS visium_rtx_costs
320 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
321 #define TARGET_FUNCTION_OK_FOR_SIBCALL visium_function_ok_for_sibcall
323 #undef TARGET_FRAME_POINTER_REQUIRED
324 #define TARGET_FRAME_POINTER_REQUIRED visium_frame_pointer_required
326 #undef TARGET_SECONDARY_RELOAD
327 #define TARGET_SECONDARY_RELOAD visium_secondary_reload
329 #undef TARGET_CLASS_LIKELY_SPILLED_P
330 #define TARGET_CLASS_LIKELY_SPILLED_P visium_class_likely_spilled_p
332 #undef TARGET_LEGITIMIZE_ADDRESS
333 #define TARGET_LEGITIMIZE_ADDRESS visium_legitimize_address
335 #undef TARGET_OPTION_OVERRIDE
336 #define TARGET_OPTION_OVERRIDE visium_option_override
338 #undef TARGET_INIT_LIBFUNCS
339 #define TARGET_INIT_LIBFUNCS visium_init_libfuncs
341 #undef TARGET_CONDITIONAL_REGISTER_USAGE
342 #define TARGET_CONDITIONAL_REGISTER_USAGE visium_conditional_register_usage
344 #undef TARGET_TRAMPOLINE_INIT
345 #define TARGET_TRAMPOLINE_INIT visium_trampoline_init
347 #undef TARGET_MD_ASM_ADJUST
348 #define TARGET_MD_ASM_ADJUST visium_md_asm_adjust
350 #undef TARGET_FLAGS_REGNUM
351 #define TARGET_FLAGS_REGNUM FLAGS_REGNUM
353 #undef TARGET_HARD_REGNO_NREGS
354 #define TARGET_HARD_REGNO_NREGS visium_hard_regno_nregs
356 #undef TARGET_HARD_REGNO_MODE_OK
357 #define TARGET_HARD_REGNO_MODE_OK visium_hard_regno_mode_ok
359 #undef TARGET_MODES_TIEABLE_P
360 #define TARGET_MODES_TIEABLE_P visium_modes_tieable_p
362 #undef TARGET_CAN_CHANGE_MODE_CLASS
363 #define TARGET_CAN_CHANGE_MODE_CLASS visium_can_change_mode_class
365 #undef TARGET_CONSTANT_ALIGNMENT
366 #define TARGET_CONSTANT_ALIGNMENT visium_constant_alignment
368 struct gcc_target targetm = TARGET_INITIALIZER;
370 namespace {
372 const pass_data pass_data_visium_reorg =
374 RTL_PASS, /* type */
375 "mach2", /* name */
376 OPTGROUP_NONE, /* optinfo_flags */
377 TV_MACH_DEP, /* tv_id */
378 0, /* properties_required */
379 0, /* properties_provided */
380 0, /* properties_destroyed */
381 0, /* todo_flags_start */
382 0, /* todo_flags_finish */
385 class pass_visium_reorg : public rtl_opt_pass
387 public:
388 pass_visium_reorg(gcc::context *ctxt)
389 : rtl_opt_pass(pass_data_visium_reorg, ctxt)
392 /* opt_pass methods: */
393 virtual unsigned int execute (function *)
395 return visium_reorg ();
398 }; // class pass_work_around_errata
400 } // anon namespace
402 rtl_opt_pass *
403 make_pass_visium_reorg (gcc::context *ctxt)
405 return new pass_visium_reorg (ctxt);
408 /* Options override for Visium. */
410 static void
411 visium_option_override (void)
413 if (flag_pic == 1)
414 warning (OPT_fpic, "-fpic is not supported");
415 if (flag_pic == 2)
416 warning (OPT_fPIC, "-fPIC is not supported");
418 /* MCM is the default in the GR5/GR6 era. */
419 target_flags |= MASK_MCM;
421 /* FPU is the default with MCM, but don't override an explicit option. */
422 if ((target_flags_explicit & MASK_FPU) == 0)
423 target_flags |= MASK_FPU;
425 /* The supervisor mode is the default. */
426 if ((target_flags_explicit & MASK_SV_MODE) == 0)
427 target_flags |= MASK_SV_MODE;
429 /* The GR6 has the Block Move Instructions and an IEEE-compliant FPU. */
430 if (visium_cpu_and_features == PROCESSOR_GR6)
432 target_flags |= MASK_BMI;
433 if (target_flags & MASK_FPU)
434 target_flags |= MASK_FPU_IEEE;
437 /* Set -mtune from -mcpu if not specified. */
438 if (!global_options_set.x_visium_cpu)
439 visium_cpu = visium_cpu_and_features;
441 /* Align functions on 256-byte (32-quadword) for GR5 and 64-byte (8-quadword)
442 boundaries for GR6 so they start a new burst mode window. */
443 if (align_functions == 0)
445 if (visium_cpu == PROCESSOR_GR6)
446 align_functions = 64;
447 else
448 align_functions = 256;
450 /* Allow the size of compilation units to double because of inlining.
451 In practice the global size of the object code is hardly affected
452 because the additional instructions will take up the padding. */
453 maybe_set_param_value (PARAM_INLINE_UNIT_GROWTH, 100,
454 global_options.x_param_values,
455 global_options_set.x_param_values);
458 /* Likewise for loops. */
459 if (align_loops == 0)
461 if (visium_cpu == PROCESSOR_GR6)
462 align_loops = 64;
463 else
465 align_loops = 256;
466 /* But not if they are too far away from a 256-byte boundary. */
467 align_loops_max_skip = 31;
471 /* Align all jumps on quadword boundaries for the burst mode, and even
472 on 8-quadword boundaries for GR6 so they start a new window. */
473 if (align_jumps == 0)
475 if (visium_cpu == PROCESSOR_GR6)
476 align_jumps = 64;
477 else
478 align_jumps = 8;
481 /* We register a machine-specific pass. This pass must be scheduled as
482 late as possible so that we have the (essentially) final form of the
483 insn stream to work on. Registering the pass must be done at start up.
484 It's convenient to do it here. */
485 opt_pass *visium_reorg_pass = make_pass_visium_reorg (g);
486 struct register_pass_info insert_pass_visium_reorg =
488 visium_reorg_pass, /* pass */
489 "dbr", /* reference_pass_name */
490 1, /* ref_pass_instance_number */
491 PASS_POS_INSERT_AFTER /* po_op */
493 register_pass (&insert_pass_visium_reorg);
496 /* Register the Visium-specific libfuncs with the middle-end. */
498 static void
499 visium_init_libfuncs (void)
501 if (!TARGET_BMI)
502 long_int_memcpy_libfunc = init_one_libfunc ("__long_int_memcpy");
503 wrd_memcpy_libfunc = init_one_libfunc ("__wrd_memcpy");
504 byt_memcpy_libfunc = init_one_libfunc ("__byt_memcpy");
506 long_int_memset_libfunc = init_one_libfunc ("__long_int_memset");
507 wrd_memset_libfunc = init_one_libfunc ("__wrd_memset");
508 byt_memset_libfunc = init_one_libfunc ("__byt_memset");
510 set_trampoline_parity_libfunc = init_one_libfunc ("__set_trampoline_parity");
513 /* Return the number of instructions that can issue on the same cycle. */
515 static int
516 visium_issue_rate (void)
518 switch (visium_cpu)
520 case PROCESSOR_GR5:
521 return 1;
523 case PROCESSOR_GR6:
524 return 2;
526 default:
527 gcc_unreachable ();
531 /* Return the adjusted PRIORITY of INSN. */
533 static int
534 visium_adjust_priority (rtx_insn *insn, int priority)
536 /* On the GR5, we slightly increase the priority of writes in order to avoid
537 scheduling a read on the next cycle. This is necessary in addition to the
538 associated insn reservation because there are no data dependencies.
539 We also slightly increase the priority of reads from ROM in order to group
540 them as much as possible. These reads are a bit problematic because they
541 conflict with the instruction fetches, i.e. the data and instruction buses
542 tread on each other's toes when they are executed. */
543 if (visium_cpu == PROCESSOR_GR5
544 && reload_completed
545 && INSN_P (insn)
546 && recog_memoized (insn) >= 0)
548 enum attr_type attr_type = get_attr_type (insn);
549 if (attr_type == TYPE_REG_MEM
550 || (attr_type == TYPE_MEM_REG
551 && MEM_READONLY_P (SET_SRC (PATTERN (insn)))))
552 return priority + 1;
555 return priority;
558 /* Adjust the cost of a scheduling dependency. Return the new cost of
559 a dependency LINK of INSN on DEP_INSN. COST is the current cost. */
561 static int
562 visium_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost,
563 unsigned int)
565 enum attr_type attr_type;
567 /* Don't adjust costs for true dependencies as they are described with
568 bypasses. But we make an exception for the first scheduling pass to
569 help the subsequent postreload compare elimination pass. */
570 if (dep_type == REG_DEP_TRUE)
572 if (!reload_completed
573 && recog_memoized (insn) >= 0
574 && get_attr_type (insn) == TYPE_CMP)
576 rtx pat = PATTERN (insn);
577 gcc_assert (GET_CODE (pat) == SET);
578 rtx src = SET_SRC (pat);
580 /* Only the branches can be modified by the postreload compare
581 elimination pass, not the cstores because they accept only
582 unsigned comparison operators and they are eliminated if
583 one of the operands is zero. */
584 if (GET_CODE (src) == IF_THEN_ELSE
585 && XEXP (XEXP (src, 0), 1) == const0_rtx
586 && recog_memoized (dep_insn) >= 0)
588 enum attr_type dep_attr_type = get_attr_type (dep_insn);
590 /* The logical instructions use CCmode and thus work with any
591 comparison operator, whereas the arithmetic instructions use
592 CCNZmode and thus work with only a small subset. */
593 if (dep_attr_type == TYPE_LOGIC
594 || (dep_attr_type == TYPE_ARITH
595 && visium_nz_comparison_operator (XEXP (src, 0),
596 GET_MODE
597 (XEXP (src, 0)))))
598 return 0;
602 return cost;
605 if (recog_memoized (insn) < 0)
606 return 0;
608 attr_type = get_attr_type (insn);
610 /* Anti dependency: DEP_INSN reads a register that INSN writes some
611 cycles later. */
612 if (dep_type == REG_DEP_ANTI)
614 /* On the GR5, the latency of FP instructions needs to be taken into
615 account for every dependency involving a write. */
616 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
618 /* INSN is FLOAD. */
619 rtx pat = PATTERN (insn);
620 rtx dep_pat = PATTERN (dep_insn);
622 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
623 /* If this happens, we have to extend this to schedule
624 optimally. Return 0 for now. */
625 return 0;
627 if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
629 if (recog_memoized (dep_insn) < 0)
630 return 0;
632 switch (get_attr_type (dep_insn))
634 case TYPE_FDIV:
635 case TYPE_FSQRT:
636 case TYPE_FTOI:
637 case TYPE_ITOF:
638 case TYPE_FP:
639 case TYPE_FMOVE:
640 /* A fload can't be issued until a preceding arithmetic
641 operation has finished if the target of the fload is
642 any of the sources (or destination) of the arithmetic
643 operation. Note that the latency may be (much)
644 greater than this if the preceding instruction
645 concerned is in a queue. */
646 return insn_default_latency (dep_insn);
648 default:
649 return 0;
654 /* On the GR6, we try to make sure that the link register is restored
655 sufficiently ahead of the return as to yield a correct prediction
656 from the branch predictor. By default there is no true dependency
657 but an anti dependency between them, so we simply reuse it. */
658 else if (attr_type == TYPE_RET && visium_cpu == PROCESSOR_GR6)
660 rtx dep_pat = PATTERN (dep_insn);
661 if (GET_CODE (dep_pat) == SET
662 && REG_P (SET_DEST (dep_pat))
663 && REGNO (SET_DEST (dep_pat)) == LINK_REGNUM)
664 return 8;
667 /* For other anti dependencies, the cost is 0. */
668 return 0;
671 /* Output dependency: DEP_INSN writes a register that INSN writes some
672 cycles later. */
673 else if (dep_type == REG_DEP_OUTPUT)
675 /* On the GR5, the latency of FP instructions needs to be taken into
676 account for every dependency involving a write. */
677 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
679 /* INSN is FLOAD. */
680 rtx pat = PATTERN (insn);
681 rtx dep_pat = PATTERN (dep_insn);
683 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
684 /* If this happens, we have to extend this to schedule
685 optimally. Return 0 for now. */
686 return 0;
688 if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat)))
690 if (recog_memoized (dep_insn) < 0)
691 return 0;
693 switch (get_attr_type (dep_insn))
695 case TYPE_FDIV:
696 case TYPE_FSQRT:
697 case TYPE_FTOI:
698 case TYPE_ITOF:
699 case TYPE_FP:
700 case TYPE_FMOVE:
701 /* A fload can't be issued until a preceding arithmetic
702 operation has finished if the target of the fload is
703 the destination of the arithmetic operation. Note that
704 the latency may be (much) greater than this if the
705 preceding instruction concerned is in a queue. */
706 return insn_default_latency (dep_insn);
708 default:
709 return 0;
714 /* For other output dependencies, the cost is 0. */
715 return 0;
718 return 0;
721 /* Handle an "interrupt_handler" attribute; arguments as in
722 struct attribute_spec.handler. */
724 static tree
725 visium_handle_interrupt_attr (tree *node, tree name,
726 tree args ATTRIBUTE_UNUSED,
727 int flags ATTRIBUTE_UNUSED,
728 bool *no_add_attrs)
730 if (TREE_CODE (*node) != FUNCTION_DECL)
732 warning (OPT_Wattributes, "%qE attribute only applies to functions",
733 name);
734 *no_add_attrs = true;
736 else if (!TARGET_SV_MODE)
738 error ("an interrupt handler cannot be compiled with -muser-mode");
739 *no_add_attrs = true;
742 return NULL_TREE;
745 /* Return non-zero if the current function is an interrupt function. */
748 visium_interrupt_function_p (void)
750 return
751 lookup_attribute ("interrupt",
752 DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
755 /* Conditionally modify the settings of the register file. */
757 static void
758 visium_conditional_register_usage (void)
760 /* If the supervisor mode is disabled, mask some general registers. */
761 if (!TARGET_SV_MODE)
763 if (visium_cpu_and_features == PROCESSOR_GR5)
765 fixed_regs[24] = call_used_regs[24] = 1;
766 fixed_regs[25] = call_used_regs[25] = 1;
767 fixed_regs[26] = call_used_regs[26] = 1;
768 fixed_regs[27] = call_used_regs[27] = 1;
769 fixed_regs[28] = call_used_regs[28] = 1;
770 call_really_used_regs[24] = 0;
771 call_really_used_regs[25] = 0;
772 call_really_used_regs[26] = 0;
773 call_really_used_regs[27] = 0;
774 call_really_used_regs[28] = 0;
777 fixed_regs[31] = call_used_regs[31] = 1;
778 call_really_used_regs[31] = 0;
780 /* We also need to change the long-branch register. */
781 if (visium_cpu_and_features == PROCESSOR_GR5)
782 long_branch_regnum = 20;
783 else
784 long_branch_regnum = 28;
787 /* If the FPU is disabled, mask the FP registers. */
788 if (!TARGET_FPU)
790 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
792 fixed_regs[i] = call_used_regs[i] = 1;
793 call_really_used_regs[i] = 0;
798 /* Prepend to CLOBBERS hard registers that are automatically clobbered for
799 an asm We do this for the FLAGS to maintain source compatibility with
800 the original cc0-based compiler. */
802 static rtx_insn *
803 visium_md_asm_adjust (vec<rtx> &/*outputs*/, vec<rtx> &/*inputs*/,
804 vec<const char *> &/*constraints*/,
805 vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs)
807 clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REGNUM));
808 SET_HARD_REG_BIT (clobbered_regs, FLAGS_REGNUM);
809 return NULL;
812 /* Return true if X is a legitimate constant for a MODE immediate operand.
813 X is guaranteed to satisfy the CONSTANT_P predicate. */
815 static bool
816 visium_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED,
817 rtx x ATTRIBUTE_UNUSED)
819 return true;
822 /* Compute the alignment for a variable. The alignment of an aggregate is
823 set to be at least that of a scalar less than or equal to it in size. */
825 unsigned int
826 visium_data_alignment (tree type, unsigned int align)
828 if (AGGREGATE_TYPE_P (type)
829 && TYPE_SIZE (type)
830 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && align < 32)
832 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 32)
833 return 32;
835 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 && align < 16)
836 return 16;
839 return align;
842 /* Implement TARGET_CONSTANT_ALIGNMENT. */
844 static HOST_WIDE_INT
845 visium_constant_alignment (const_tree exp, HOST_WIDE_INT align)
847 return visium_data_alignment (TREE_TYPE (exp), align);
850 /* Helper function for HARD_REGNO_RENAME_OK (FROM, TO). Return non-zero if
851 it is OK to rename a hard register FROM to another hard register TO. */
854 visium_hard_regno_rename_ok (unsigned int from ATTRIBUTE_UNUSED,
855 unsigned int to)
857 /* If the function doesn't save LR, then the long-branch register will be
858 used for long branches so we need to know whether it is live before the
859 frame layout is computed. */
860 if (!current_function_saves_lr () && to == long_branch_regnum)
861 return 0;
863 /* Interrupt functions can only use registers that have already been
864 saved by the prologue, even if they would normally be call-clobbered. */
865 if (crtl->is_leaf
866 && !df_regs_ever_live_p (to)
867 && visium_interrupt_function_p ())
868 return 0;
870 return 1;
873 /* Implement TARGET_HARD_REGNO_NREGS. */
875 static unsigned int
876 visium_hard_regno_nregs (unsigned int regno, machine_mode mode)
878 if (regno == MDB_REGNUM)
879 return CEIL (GET_MODE_SIZE (mode), 2 * UNITS_PER_WORD);
880 return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
883 /* Implement TARGET_HARD_REGNO_MODE_OK.
885 Modes with sizes which cross from the one register class to the
886 other cannot be allowed. Only single floats are allowed in the
887 floating point registers, and only fixed point values in the EAM
888 registers. */
890 static bool
891 visium_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
893 if (GP_REGISTER_P (regno))
894 return GP_REGISTER_P (end_hard_regno (mode, regno) - 1);
896 if (FP_REGISTER_P (regno))
897 return mode == SFmode || (mode == SImode && TARGET_FPU_IEEE);
899 return (GET_MODE_CLASS (mode) == MODE_INT
900 && visium_hard_regno_nregs (regno, mode) == 1);
903 /* Implement TARGET_MODES_TIEABLE_P. */
905 static bool
906 visium_modes_tieable_p (machine_mode mode1, machine_mode mode2)
908 return (GET_MODE_CLASS (mode1) == MODE_INT
909 && GET_MODE_CLASS (mode2) == MODE_INT);
912 /* Return true if it is ok to do sibling call optimization for the specified
913 call expression EXP. DECL will be the called function, or NULL if this
914 is an indirect call. */
916 static bool
917 visium_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
918 tree exp ATTRIBUTE_UNUSED)
920 return !visium_interrupt_function_p ();
923 /* Prepare operands for a move define_expand in MODE. */
925 void
926 prepare_move_operands (rtx *operands, machine_mode mode)
928 /* If the output is not a register, the input must be. */
929 if (GET_CODE (operands[0]) == MEM && !reg_or_0_operand (operands[1], mode))
930 operands[1] = force_reg (mode, operands[1]);
933 /* Return true if the operands are valid for a simple move insn. */
935 bool
936 ok_for_simple_move_operands (rtx *operands, machine_mode mode)
938 /* One of the operands must be a register. */
939 if (!register_operand (operands[0], mode)
940 && !reg_or_0_operand (operands[1], mode))
941 return false;
943 /* Once the flags are exposed, no simple moves between integer registers. */
944 if (visium_flags_exposed
945 && gpc_reg_operand (operands[0], mode)
946 && gpc_reg_operand (operands[1], mode))
947 return false;
949 return true;
952 /* Return true if the operands are valid for a simple move strict insn. */
954 bool
955 ok_for_simple_move_strict_operands (rtx *operands, machine_mode mode)
957 /* Once the flags are exposed, no simple moves between integer registers.
958 Note that, in QImode only, a zero source counts as an integer register
959 since it will be emitted as r0. */
960 if (visium_flags_exposed
961 && gpc_reg_operand (operands[0], mode)
962 && (gpc_reg_operand (operands[1], mode)
963 || (mode == QImode && operands[1] == const0_rtx)))
964 return false;
966 return true;
969 /* Return true if the operands are valid for a simple arithmetic or logical
970 insn. */
972 bool
973 ok_for_simple_arith_logic_operands (rtx *, machine_mode)
975 /* Once the flags are exposed, no simple arithmetic or logical operations
976 between integer registers. */
977 return !visium_flags_exposed;
980 /* Return non-zero if a branch or call instruction will be emitting a nop
981 into its delay slot. */
984 empty_delay_slot (rtx_insn *insn)
986 rtx seq;
988 /* If no previous instruction (should not happen), return true. */
989 if (PREV_INSN (insn) == NULL)
990 return 1;
992 seq = NEXT_INSN (PREV_INSN (insn));
993 if (GET_CODE (PATTERN (seq)) == SEQUENCE)
994 return 0;
996 return 1;
999 /* Wrapper around single_set which returns the second SET of a pair if the
1000 first SET is to the flags register. */
1002 static rtx
1003 single_set_and_flags (rtx_insn *insn)
1005 if (multiple_sets (insn))
1007 rtx pat = PATTERN (insn);
1008 if (XVECLEN (pat, 0) == 2
1009 && GET_CODE (XVECEXP (pat, 0, 0)) == SET
1010 && REG_P (SET_DEST (XVECEXP (pat, 0, 0)))
1011 && REGNO (SET_DEST (XVECEXP (pat, 0, 0))) == FLAGS_REGNUM)
1012 return XVECEXP (pat, 0, 1);
1015 return single_set (insn);
1018 /* This is called with OUT_INSN an instruction setting a (base) register
1019 and IN_INSN a read or a write. Return 1 if these instructions together
1020 constitute a pipeline hazard.
1022 On the original architecture, a pipeline data hazard occurs when the Dest
1023 of one instruction becomes the SrcA for an immediately following READ or
1024 WRITE instruction with a non-zero index (indexing occurs at the decode
1025 stage and so a NOP must be inserted in-between for this to work).
1027 An example is:
1029 move.l r2,r1
1030 read.l r4,10(r2)
1032 On the MCM, the non-zero index condition is lifted but the hazard is
1033 patched up by the hardware through the injection of wait states:
1035 move.l r2,r1
1036 read.l r4,(r2)
1038 We nevertheless try to schedule instructions around this. */
1041 gr5_hazard_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
1043 rtx out_set, in_set, dest, memexpr;
1044 unsigned int out_reg, in_reg;
1046 /* A CALL is storage register class, but the link register is of no
1047 interest here. */
1048 if (GET_CODE (out_insn) == CALL_INSN)
1049 return 0;
1051 out_set = single_set_and_flags (out_insn);
1052 dest = SET_DEST (out_set);
1054 /* Should be no stall/hazard if OUT_INSN is MEM := ???. This only
1055 occurs prior to reload. */
1056 if (GET_CODE (dest) == MEM)
1057 return 0;
1059 if (GET_CODE (dest) == STRICT_LOW_PART)
1060 dest = XEXP (dest, 0);
1061 if (GET_CODE (dest) == SUBREG)
1062 dest = SUBREG_REG (dest);
1063 out_reg = REGNO (dest);
1065 in_set = single_set_and_flags (in_insn);
1067 /* If IN_INSN is MEM := MEM, it's the source that counts. */
1068 if (GET_CODE (SET_SRC (in_set)) == MEM)
1069 memexpr = XEXP (SET_SRC (in_set), 0);
1070 else
1071 memexpr = XEXP (SET_DEST (in_set), 0);
1073 if (GET_CODE (memexpr) == PLUS)
1075 memexpr = XEXP (memexpr, 0);
1076 if (GET_CODE (memexpr) == SUBREG)
1077 in_reg = REGNO (SUBREG_REG (memexpr));
1078 else
1079 in_reg = REGNO (memexpr);
1081 if (in_reg == out_reg)
1082 return 1;
1084 else if (TARGET_MCM)
1086 if (GET_CODE (memexpr) == STRICT_LOW_PART)
1087 memexpr = XEXP (memexpr, 0);
1088 if (GET_CODE (memexpr) == SUBREG)
1089 memexpr = SUBREG_REG (memexpr);
1090 in_reg = REGNO (memexpr);
1092 if (in_reg == out_reg)
1093 return 1;
1096 return 0;
1099 /* Return true if INSN is an empty asm instruction. */
1101 static bool
1102 empty_asm_p (rtx insn)
1104 rtx body = PATTERN (insn);
1105 const char *templ;
1107 if (GET_CODE (body) == ASM_INPUT)
1108 templ = XSTR (body, 0);
1109 else if (asm_noperands (body) >= 0)
1110 templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
1111 else
1112 templ = NULL;
1114 return (templ && templ[0] == '\0');
1117 /* Insert a NOP immediately before INSN wherever there is a pipeline hazard.
1118 LAST_REG records the register set in the last insn and LAST_INSN_CALL
1119 records whether the last insn was a call insn. */
1121 static void
1122 gr5_avoid_hazard (rtx_insn *insn, unsigned int *last_reg, bool *last_insn_call)
1124 unsigned int dest_reg = 0;
1125 rtx set;
1127 switch (GET_CODE (insn))
1129 case CALL_INSN:
1130 *last_reg = 0;
1131 *last_insn_call = true;
1132 return;
1134 case JUMP_INSN:
1135 /* If this is an empty asm, just skip it. */
1136 if (!empty_asm_p (insn))
1138 *last_reg = 0;
1139 *last_insn_call = false;
1141 return;
1143 case INSN:
1144 /* If this is an empty asm, just skip it. */
1145 if (empty_asm_p (insn))
1146 return;
1147 break;
1149 default:
1150 return;
1153 set = single_set_and_flags (insn);
1154 if (set != NULL_RTX)
1156 rtx dest = SET_DEST (set);
1157 const bool double_p = GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD;
1158 rtx memrtx = NULL;
1160 if (GET_CODE (SET_SRC (set)) == MEM)
1162 memrtx = XEXP (SET_SRC (set), 0);
1163 if (GET_CODE (dest) == STRICT_LOW_PART)
1164 dest = XEXP (dest, 0);
1165 if (REG_P (dest))
1166 dest_reg = REGNO (dest);
1168 /* If this is a DI or DF mode memory to register
1169 copy, then if rd = rs we get
1171 rs + 1 := 1[rs]
1172 rs := [rs]
1174 otherwise the order is
1176 rd := [rs]
1177 rd + 1 := 1[rs] */
1179 if (double_p)
1181 unsigned int base_reg;
1183 if (GET_CODE (memrtx) == PLUS)
1184 base_reg = REGNO (XEXP (memrtx, 0));
1185 else
1186 base_reg = REGNO (memrtx);
1188 if (dest_reg != base_reg)
1189 dest_reg++;
1193 else if (GET_CODE (dest) == MEM)
1194 memrtx = XEXP (dest, 0);
1196 else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC)
1198 if (GET_CODE (dest) == STRICT_LOW_PART
1199 ||GET_CODE (dest) == ZERO_EXTRACT)
1200 dest = XEXP (dest, 0);
1201 dest_reg = REGNO (dest);
1203 if (GET_CODE (SET_SRC (set)) == REG)
1205 unsigned int srcreg = REGNO (SET_SRC (set));
1207 /* Check for rs := rs, which will be deleted. */
1208 if (srcreg == dest_reg)
1209 return;
1211 /* In the case of a DI or DF mode move from register to
1212 register there is overlap if rd = rs + 1 in which case
1213 the order of the copies is reversed :
1215 rd + 1 := rs + 1;
1216 rd := rs */
1218 if (double_p && dest_reg != srcreg + 1)
1219 dest_reg++;
1223 /* If this is the delay slot of a call insn, any register it sets
1224 is not relevant. */
1225 if (*last_insn_call)
1226 dest_reg = 0;
1228 /* If the previous insn sets the value of a register, and this insn
1229 uses a base register, check for the pipeline hazard where it is
1230 the same register in each case. */
1231 if (*last_reg != 0 && memrtx != NULL_RTX)
1233 unsigned int reg = 0;
1235 /* Check for an index (original architecture). */
1236 if (GET_CODE (memrtx) == PLUS)
1237 reg = REGNO (XEXP (memrtx, 0));
1239 /* Check for an MCM target or rs := [rs], in DI or DF mode. */
1240 else if (TARGET_MCM || (double_p && REGNO (memrtx) == dest_reg))
1241 reg = REGNO (memrtx);
1243 /* Remove any pipeline hazard by inserting a NOP. */
1244 if (reg == *last_reg)
1246 if (dump_file)
1247 fprintf (dump_file,
1248 "inserting nop before insn %d\n", INSN_UID (insn));
1249 emit_insn_after (gen_hazard_nop (), prev_active_insn (insn));
1250 emit_insn_after (gen_blockage (), insn);
1254 *last_reg = dest_reg;
1257 *last_insn_call = false;
1260 /* Go through the instruction stream and insert nops where necessary to avoid
1261 pipeline hazards. There are two cases:
1263 1. On the original architecture, it is invalid to set the value of a
1264 (base) register and then use it in an address with a non-zero index
1265 in the next instruction.
1267 2. On the MCM, setting the value of a (base) register and then using
1268 it in address (including with zero index) in the next instruction
1269 will result in a pipeline stall of 3 cycles. */
1271 static void
1272 gr5_hazard_avoidance (void)
1274 unsigned int last_reg = 0;
1275 bool last_insn_call = false;
1276 rtx_insn *insn;
1278 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1279 if (INSN_P (insn))
1281 rtx pat = PATTERN (insn);
1283 if (GET_CODE (pat) == SEQUENCE)
1285 for (int i = 0; i < XVECLEN (pat, 0); i++)
1286 gr5_avoid_hazard (as_a <rtx_insn *> (XVECEXP (pat, 0, i)),
1287 &last_reg, &last_insn_call);
1290 else if (GET_CODE (insn) == CALL_INSN)
1292 /* This call is going to get a nop in its delay slot. */
1293 last_reg = 0;
1294 last_insn_call = false;
1297 else
1298 gr5_avoid_hazard (insn, &last_reg, &last_insn_call);
1301 else if (GET_CODE (insn) == BARRIER)
1302 last_reg = 0;
1305 /* Perform a target-specific pass over the instruction stream. The compiler
1306 will run it at all optimization levels, just after the point at which it
1307 normally does delayed-branch scheduling. */
1309 static unsigned int
1310 visium_reorg (void)
1312 if (visium_cpu == PROCESSOR_GR5)
1313 gr5_hazard_avoidance ();
1315 return 0;
1317 /* Return true if an argument must be passed by indirect reference. */
1319 static bool
1320 visium_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1321 machine_mode mode ATTRIBUTE_UNUSED,
1322 const_tree type,
1323 bool named ATTRIBUTE_UNUSED)
1325 return type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1328 /* Define how arguments are passed.
1330 A range of general registers and floating registers is available
1331 for passing arguments. When the class of registers which an
1332 argument would normally use is exhausted, that argument, is passed
1333 in the overflow region of the stack. No argument is split between
1334 registers and stack.
1336 Arguments of type float or _Complex float go in FP registers if FP
1337 hardware is available. If there is no FP hardware, arguments of
1338 type float go in general registers. All other arguments are passed
1339 in general registers. */
1341 static rtx
1342 visium_function_arg (cumulative_args_t pcum_v, machine_mode mode,
1343 const_tree type ATTRIBUTE_UNUSED,
1344 bool named ATTRIBUTE_UNUSED)
1346 int size;
1347 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1349 size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1350 if (mode == VOIDmode)
1351 return GEN_INT (0);
1353 /* Scalar or complex single precision floating point arguments are returned
1354 in floating registers. */
1355 if (TARGET_FPU
1356 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1357 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1358 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1359 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1361 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1362 return gen_rtx_REG (mode, FP_ARG_FIRST + ca->frcount);
1363 else
1364 return NULL_RTX;
1367 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1368 return gen_rtx_REG (mode, ca->grcount + GP_ARG_FIRST);
1370 return NULL_RTX;
1373 /* Update the summarizer variable pointed to by PCUM_V to advance past an
1374 argument in the argument list. The values MODE, TYPE and NAMED describe
1375 that argument. Once this is done, the variable CUM is suitable for
1376 analyzing the _following_ argument with visium_function_arg. */
1378 static void
1379 visium_function_arg_advance (cumulative_args_t pcum_v,
1380 machine_mode mode,
1381 const_tree type ATTRIBUTE_UNUSED,
1382 bool named)
1384 int size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1385 int stack_size = 0;
1386 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1388 /* Scalar or complex single precision floating point arguments are returned
1389 in floating registers. */
1390 if (TARGET_FPU
1391 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1392 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1393 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1394 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1396 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1397 ca->frcount += size;
1398 else
1400 stack_size = size;
1401 ca->frcount = MAX_ARGS_IN_FP_REGISTERS;
1404 else
1406 /* Everything else goes in a general register, if enough are
1407 available. */
1408 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1409 ca->grcount += size;
1410 else
1412 stack_size = size;
1413 ca->grcount = MAX_ARGS_IN_GP_REGISTERS;
1417 if (named)
1418 ca->stack_words += stack_size;
1421 /* Specify whether to return the return value in memory. */
1423 static bool
1424 visium_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1426 return (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1429 /* Define how scalar values are returned. */
1431 static rtx
1432 visium_function_value_1 (machine_mode mode)
1434 /* Scalar or complex single precision floating point values
1435 are returned in floating register f1. */
1436 if (TARGET_FPU
1437 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1438 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1439 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1440 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1441 return gen_rtx_REG (mode, FP_RETURN_REGNUM);
1443 /* All others are returned in r1. */
1444 return gen_rtx_REG (mode, RETURN_REGNUM);
1447 /* Return an RTX representing the place where a function returns or receives
1448 a value of data type RET_TYPE. */
1450 static rtx
1451 visium_function_value (const_tree ret_type,
1452 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1453 bool outgoing ATTRIBUTE_UNUSED)
1455 return visium_function_value_1 (TYPE_MODE (ret_type));
1458 /* Return an RTX representing the place where the library function result will
1459 be returned. */
1461 static rtx
1462 visium_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1464 return visium_function_value_1 (mode);
1467 /* Store the anonymous register arguments into the stack so that all the
1468 arguments appear to have been passed consecutively on the stack. */
1470 static void
1471 visium_setup_incoming_varargs (cumulative_args_t pcum_v,
1472 machine_mode mode,
1473 tree type,
1474 int *pretend_size ATTRIBUTE_UNUSED,
1475 int no_rtl)
1477 cumulative_args_t local_args_so_far;
1478 CUMULATIVE_ARGS local_copy;
1479 CUMULATIVE_ARGS *locargs;
1480 int gp_saved, fp_saved, size;
1482 /* Create an internal cumulative_args_t pointer to internally define
1483 storage to ensure calling TARGET_FUNCTION_ARG_ADVANCE does not
1484 make global changes. */
1485 local_args_so_far.p = &local_copy;
1486 locargs = get_cumulative_args (pcum_v);
1488 #if CHECKING_P
1489 local_args_so_far.magic = CUMULATIVE_ARGS_MAGIC;
1490 #endif
1492 local_copy.grcount = locargs->grcount;
1493 local_copy.frcount = locargs->frcount;
1494 local_copy.stack_words = locargs->stack_words;
1496 /* The caller has advanced ARGS_SO_FAR up to, but not beyond, the last named
1497 argument. Advance a local copy of ARGS_SO_FAR past the last "real" named
1498 argument, to find out how many registers are left over. */
1499 TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, mode, type, 1);
1501 /* Find how many registers we need to save. */
1502 locargs = get_cumulative_args (local_args_so_far);
1503 gp_saved = MAX_ARGS_IN_GP_REGISTERS - locargs->grcount;
1504 fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - locargs->frcount : 0);
1505 size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_HWFPVALUE);
1507 if (!no_rtl && size > 0)
1509 /* To avoid negative offsets, which are not valid addressing modes on
1510 the Visium, we create a base register for the pretend args. */
1511 rtx ptr
1512 = force_reg (Pmode,
1513 plus_constant (Pmode, virtual_incoming_args_rtx, -size));
1515 if (gp_saved > 0)
1517 rtx mem
1518 = gen_rtx_MEM (BLKmode,
1519 plus_constant (Pmode,
1520 ptr,
1521 fp_saved * UNITS_PER_HWFPVALUE));
1522 MEM_NOTRAP_P (mem) = 1;
1523 set_mem_alias_set (mem, get_varargs_alias_set ());
1524 move_block_from_reg (locargs->grcount + GP_ARG_FIRST, mem, gp_saved);
1527 if (fp_saved > 0)
1529 rtx mem = gen_rtx_MEM (BLKmode, ptr);
1530 MEM_NOTRAP_P (mem) = 1;
1531 set_mem_alias_set (mem, get_varargs_alias_set ());
1532 gcc_assert (UNITS_PER_WORD == UNITS_PER_HWFPVALUE);
1533 move_block_from_reg (locargs->frcount + FP_ARG_FIRST, mem, fp_saved);
1537 visium_reg_parm_save_area_size = size;
1540 /* Define the `__builtin_va_list' type for the ABI. */
1542 static tree
1543 visium_build_builtin_va_list (void)
1545 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes, record;
1547 record = (*lang_hooks.types.make_type) (RECORD_TYPE);
1548 f_ovfl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1549 get_identifier ("__overflow_argptr"), ptr_type_node);
1550 f_gbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1551 get_identifier ("__gpr_base"), ptr_type_node);
1552 f_fbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1553 get_identifier ("__fpr_base"), ptr_type_node);
1554 f_gbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1555 get_identifier ("__gpr_bytes"),
1556 short_unsigned_type_node);
1557 f_fbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1558 get_identifier ("__fpr_bytes"),
1559 short_unsigned_type_node);
1561 DECL_FIELD_CONTEXT (f_ovfl) = record;
1562 DECL_FIELD_CONTEXT (f_gbase) = record;
1563 DECL_FIELD_CONTEXT (f_fbase) = record;
1564 DECL_FIELD_CONTEXT (f_gbytes) = record;
1565 DECL_FIELD_CONTEXT (f_fbytes) = record;
1566 TYPE_FIELDS (record) = f_ovfl;
1567 TREE_CHAIN (f_ovfl) = f_gbase;
1568 TREE_CHAIN (f_gbase) = f_fbase;
1569 TREE_CHAIN (f_fbase) = f_gbytes;
1570 TREE_CHAIN (f_gbytes) = f_fbytes;
1571 layout_type (record);
1573 return record;
1576 /* Implement `va_start' for varargs and stdarg. */
1578 static void
1579 visium_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
1581 const CUMULATIVE_ARGS *ca = &crtl->args.info;
1582 int gp_saved = MAX_ARGS_IN_GP_REGISTERS - ca->grcount;
1583 int fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - ca->frcount : 0);
1584 int named_stack_size = ca->stack_words * UNITS_PER_WORD, offset;
1585 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1586 tree ovfl, gbase, gbytes, fbase, fbytes, t;
1588 f_ovfl = TYPE_FIELDS (va_list_type_node);
1589 f_gbase = TREE_CHAIN (f_ovfl);
1590 f_fbase = TREE_CHAIN (f_gbase);
1591 f_gbytes = TREE_CHAIN (f_fbase);
1592 f_fbytes = TREE_CHAIN (f_gbytes);
1593 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1594 gbase = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1595 NULL_TREE);
1596 fbase = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1597 NULL_TREE);
1598 gbytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), valist, f_gbytes,
1599 NULL_TREE);
1600 fbytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), valist, f_fbytes,
1601 NULL_TREE);
1603 /* Store the stacked vararg pointer in the OVFL member. */
1604 t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
1605 t = fold_build_pointer_plus_hwi (t, named_stack_size);
1606 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
1607 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1609 /* Store the base address of the GPR save area into GBASE. */
1610 t = make_tree (TREE_TYPE (gbase), virtual_incoming_args_rtx);
1611 offset = MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD;
1612 t = fold_build_pointer_plus_hwi (t, -offset);
1613 t = build2 (MODIFY_EXPR, TREE_TYPE (gbase), gbase, t);
1614 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1616 /* Store the base address of the FPR save area into FBASE. */
1617 if (fp_saved)
1619 t = make_tree (TREE_TYPE (fbase), virtual_incoming_args_rtx);
1620 offset = gp_saved * UNITS_PER_WORD
1621 + MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE;
1622 t = fold_build_pointer_plus_hwi (t, -offset);
1623 t = build2 (MODIFY_EXPR, TREE_TYPE (fbase), fbase, t);
1624 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1627 /* Fill in the GBYTES member. */
1628 t = build2 (MODIFY_EXPR, TREE_TYPE (gbytes), gbytes,
1629 size_int (gp_saved * UNITS_PER_WORD));
1630 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1632 /* Fill in the FBYTES member. */
1633 t = build2 (MODIFY_EXPR, TREE_TYPE (fbytes),
1634 fbytes, size_int (fp_saved * UNITS_PER_HWFPVALUE));
1635 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1638 /* Implement `va_arg'. */
1640 static tree
1641 visium_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
1642 gimple_seq *post_p)
1644 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1645 tree ovfl, base, bytes;
1646 HOST_WIDE_INT size, rsize;
1647 const bool by_reference_p
1648 = pass_by_reference (NULL, TYPE_MODE (type), type, false);
1649 const bool float_reg_arg_p
1650 = (TARGET_FPU && !by_reference_p
1651 && ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
1652 && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_HWFPVALUE)
1653 || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT
1654 && (GET_MODE_SIZE (TYPE_MODE (type))
1655 <= UNITS_PER_HWFPVALUE * 2))));
1656 const int max_save_area_size
1657 = (float_reg_arg_p ? MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE
1658 : MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD);
1659 tree t, u, offs;
1660 tree lab_false, lab_over, addr;
1661 tree ptrtype = build_pointer_type (type);
1663 if (by_reference_p)
1665 t = visium_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
1666 return build_va_arg_indirect_ref (t);
1669 size = int_size_in_bytes (type);
1670 rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
1671 f_ovfl = TYPE_FIELDS (va_list_type_node);
1672 f_gbase = TREE_CHAIN (f_ovfl);
1673 f_fbase = TREE_CHAIN (f_gbase);
1674 f_gbytes = TREE_CHAIN (f_fbase);
1675 f_fbytes = TREE_CHAIN (f_gbytes);
1677 /* We maintain separate pointers and offsets for floating-point and
1678 general registers, but we need similar code in both cases.
1680 Let:
1682 BYTES be the number of unused bytes in the register save area.
1683 BASE be the base address of the register save area.
1684 OFFS be the current offset into the register save area. Either
1685 MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD - bytes or
1686 MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE - bytes
1687 depending upon whether the argument is in general or floating
1688 registers.
1689 ADDR_RTX be the address of the argument.
1690 RSIZE be the size in bytes of the argument.
1691 OVFL be the pointer to the stack overflow area.
1693 The code we want is:
1695 1: if (bytes >= rsize)
1696 2: {
1697 3: addr_rtx = base + offs;
1698 4: bytes -= rsize;
1699 5: }
1700 6: else
1701 7: {
1702 8: bytes = 0;
1703 9: addr_rtx = ovfl;
1704 10: ovfl += rsize;
1705 11: }
1709 addr = create_tmp_var (ptr_type_node, "addr");
1710 lab_false = create_artificial_label (UNKNOWN_LOCATION);
1711 lab_over = create_artificial_label (UNKNOWN_LOCATION);
1712 if (float_reg_arg_p)
1713 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), unshare_expr (valist),
1714 f_fbytes, NULL_TREE);
1715 else
1716 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), unshare_expr (valist),
1717 f_gbytes, NULL_TREE);
1719 /* [1] Emit code to branch if bytes < rsize. */
1720 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1721 t = build2 (LT_EXPR, boolean_type_node, bytes, t);
1722 u = build1 (GOTO_EXPR, void_type_node, lab_false);
1723 t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
1724 gimplify_and_add (t, pre_p);
1726 /* [3] Emit code for: addr_rtx = base + offs, where
1727 offs = max_save_area_size - bytes. */
1728 t = fold_convert (sizetype, bytes);
1729 offs = build2 (MINUS_EXPR, sizetype, size_int (max_save_area_size), t);
1730 if (float_reg_arg_p)
1731 base = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1732 NULL_TREE);
1733 else
1734 base = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1735 NULL_TREE);
1737 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, offs);
1738 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1739 gimplify_and_add (t, pre_p);
1741 /* [4] Emit code for: bytes -= rsize. */
1742 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1743 t = build2 (MINUS_EXPR, TREE_TYPE (bytes), bytes, t);
1744 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), bytes, t);
1745 gimplify_and_add (t, pre_p);
1747 /* [6] Emit code to branch over the else clause, then the label. */
1748 t = build1 (GOTO_EXPR, void_type_node, lab_over);
1749 gimplify_and_add (t, pre_p);
1750 t = build1 (LABEL_EXPR, void_type_node, lab_false);
1751 gimplify_and_add (t, pre_p);
1753 /* [8] Emit code for: bytes = 0. */
1754 t = fold_convert (TREE_TYPE (bytes), size_int (0));
1755 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), unshare_expr (bytes), t);
1756 gimplify_and_add (t, pre_p);
1758 /* [9] Emit code for: addr_rtx = ovfl. */
1759 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1760 t = build2 (MODIFY_EXPR, void_type_node, addr, ovfl);
1761 gimplify_and_add (t, pre_p);
1763 /* [10] Emit code for: ovfl += rsize. */
1764 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl), ovfl, size_int (rsize));
1765 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), unshare_expr (ovfl), t);
1766 gimplify_and_add (t, pre_p);
1767 t = build1 (LABEL_EXPR, void_type_node, lab_over);
1768 gimplify_and_add (t, pre_p);
1770 /* Emit a big-endian correction if size < UNITS_PER_WORD. */
1771 if (size < UNITS_PER_WORD)
1773 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr), addr,
1774 size_int (UNITS_PER_WORD - size));
1775 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1776 gimplify_and_add (t, pre_p);
1779 addr = fold_convert (ptrtype, addr);
1781 return build_va_arg_indirect_ref (addr);
1784 /* Return true if OP is an offset suitable for use as a displacement in the
1785 address of a memory access in mode MODE. */
1787 static bool
1788 rtx_ok_for_offset_p (machine_mode mode, rtx op)
1790 if (!CONST_INT_P (op) || INTVAL (op) < 0)
1791 return false;
1793 switch (mode)
1795 case E_QImode:
1796 return INTVAL (op) <= 31;
1798 case E_HImode:
1799 return (INTVAL (op) % 2) == 0 && INTVAL (op) < 63;
1801 case E_SImode:
1802 case E_SFmode:
1803 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 127;
1805 case E_DImode:
1806 case E_DFmode:
1807 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 123;
1809 default:
1810 return false;
1814 /* Return whether X is a legitimate memory address for a memory operand
1815 of mode MODE.
1817 Legitimate addresses are defined in two variants: a strict variant
1818 and a non-strict one. The STRICT parameter chooses which variant
1819 is desired by the caller.
1821 The strict variant is used in the reload pass. It must be defined
1822 so that any pseudo-register that has not been allocated a hard
1823 register is considered a memory reference. This is because in
1824 contexts where some kind of register is required, a
1825 pseudo-register with no hard register must be rejected. For
1826 non-hard registers, the strict variant should look up the
1827 `reg_renumber' array; it should then proceed using the hard
1828 register number in the array, or treat the pseudo as a memory
1829 reference if the array holds `-1'.
1831 The non-strict variant is used in other passes. It must be
1832 defined to accept all pseudo-registers in every context where some
1833 kind of register is required. */
1835 static bool
1836 visium_legitimate_address_p (machine_mode mode, rtx x, bool strict)
1838 rtx base;
1839 unsigned int regno;
1841 /* If X is base+disp, check that we have an appropriate offset. */
1842 if (GET_CODE (x) == PLUS)
1844 if (!rtx_ok_for_offset_p (mode, XEXP (x, 1)))
1845 return false;
1846 base = XEXP (x, 0);
1848 else
1849 base = x;
1851 /* Now check the base: it must be either a register or a subreg thereof. */
1852 if (GET_CODE (base) == SUBREG)
1853 base = SUBREG_REG (base);
1854 if (!REG_P (base))
1855 return false;
1857 regno = REGNO (base);
1859 /* For the strict variant, the register must be REGNO_OK_FOR_BASE_P. */
1860 if (strict)
1861 return REGNO_OK_FOR_BASE_P (regno);
1863 /* For the non-strict variant, the register may also be a pseudo. */
1864 return BASE_REGISTER_P (regno) || regno >= FIRST_PSEUDO_REGISTER;
1867 /* Try machine-dependent ways of modifying an illegitimate address
1868 to be legitimate. If we find one, return the new, valid address.
1869 This macro is used in only one place: `memory_address' in explow.c.
1871 OLDX is the address as it was before break_out_memory_refs was called.
1872 In some cases it is useful to look at this to decide what needs to be done.
1874 MODE and WIN are passed so that this macro can use
1875 GO_IF_LEGITIMATE_ADDRESS.
1877 It is always safe for this macro to do nothing. It exists to recognize
1878 opportunities to optimize the output.
1880 For Visium
1882 memory (reg + <out of range int>)
1884 is transformed to
1886 base_int = <out of range int> & ~mask
1887 ptr_reg = reg + base_int
1888 memory (ptr_reg + <out of range int> - base_int)
1890 Thus ptr_reg is a base register for a range of addresses,
1891 which should help CSE.
1893 For a 1 byte reference mask is 0x1f
1894 for a 2 byte reference mask is 0x3f
1895 For a 4 byte reference mask is 0x7f
1897 This reflects the indexing range of the processor.
1899 For a > 4 byte reference the mask is 0x7f provided all of the words
1900 can be accessed with the base address obtained. Otherwise a mask
1901 of 0x3f is used.
1903 On rare occasions an unaligned base register value with an
1904 unaligned offset is generated. Unaligned offsets are left alone for
1905 this reason. */
1907 static rtx
1908 visium_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1909 machine_mode mode)
1911 if (GET_CODE (x) == PLUS
1912 && GET_CODE (XEXP (x, 1)) == CONST_INT
1913 && GET_CODE (XEXP (x, 0)) == REG && mode != BLKmode)
1915 int offset = INTVAL (XEXP (x, 1));
1916 int size = GET_MODE_SIZE (mode);
1917 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1918 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1919 int offset_base = offset & ~mask;
1921 /* Check that all of the words can be accessed. */
1922 if (4 < size && 0x80 < size + offset - offset_base)
1923 offset_base = offset & ~0x3f;
1924 if (offset_base != 0 && offset_base != offset && (offset & mask1) == 0)
1926 rtx ptr_reg = force_reg (Pmode,
1927 gen_rtx_PLUS (Pmode,
1928 XEXP (x, 0),
1929 GEN_INT (offset_base)));
1931 return plus_constant (Pmode, ptr_reg, offset - offset_base);
1935 return x;
1938 /* Perform a similar function to visium_legitimize_address, but this time
1939 for reload. Generating new registers is not an option here. Parts
1940 that need reloading are indicated by calling push_reload. */
1943 visium_legitimize_reload_address (rtx x, machine_mode mode, int opnum,
1944 int type, int ind ATTRIBUTE_UNUSED)
1946 rtx newrtx, tem = NULL_RTX;
1948 if (mode == BLKmode)
1949 return NULL_RTX;
1951 if (optimize && GET_CODE (x) == PLUS)
1952 tem = simplify_binary_operation (PLUS, GET_MODE (x), XEXP (x, 0),
1953 XEXP (x, 1));
1955 newrtx = tem ? tem : x;
1956 if (GET_CODE (newrtx) == PLUS
1957 && GET_CODE (XEXP (newrtx, 1)) == CONST_INT
1958 && GET_CODE (XEXP (newrtx, 0)) == REG
1959 && BASE_REGISTER_P (REGNO (XEXP (newrtx, 0))))
1961 int offset = INTVAL (XEXP (newrtx, 1));
1962 int size = GET_MODE_SIZE (mode);
1963 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1964 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1965 int offset_base = offset & ~mask;
1967 /* Check that all of the words can be accessed. */
1968 if (4 < size && 0x80 < size + offset - offset_base)
1969 offset_base = offset & ~0x3f;
1971 if (offset_base && (offset & mask1) == 0)
1973 rtx temp = gen_rtx_PLUS (Pmode,
1974 XEXP (newrtx, 0), GEN_INT (offset_base));
1976 x = gen_rtx_PLUS (Pmode, temp, GEN_INT (offset - offset_base));
1977 push_reload (XEXP (x, 0), 0, &XEXP (x, 0), 0,
1978 BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum,
1979 (enum reload_type) type);
1980 return x;
1984 return NULL_RTX;
1987 /* Return the cost of moving data of mode MODE from a register in class FROM to
1988 one in class TO. A value of 2 is the default; other values are interpreted
1989 relative to that. */
1991 static int
1992 visium_register_move_cost (machine_mode mode, reg_class_t from,
1993 reg_class_t to)
1995 const int numwords = (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) ? 1 : 2;
1997 if (from == MDB || to == MDB)
1998 return 4;
1999 else if (from == MDC || to == MDC || (from == FP_REGS) != (to == FP_REGS))
2000 return 4 * numwords;
2001 else
2002 return 2 * numwords;
2005 /* Return the cost of moving data of mode MODE between a register of class
2006 CLASS and memory. IN is zero if the value is to be written to memory,
2007 non-zero if it is to be read in. This cost is relative to those in
2008 visium_register_move_cost. */
2010 static int
2011 visium_memory_move_cost (machine_mode mode,
2012 reg_class_t to ATTRIBUTE_UNUSED,
2013 bool in)
2015 /* Moving data in can be from PROM and this is expensive. */
2016 if (in)
2018 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2019 return 7;
2020 else
2021 return 13;
2024 /* Moving data out is mostly to RAM and should be cheaper. */
2025 else
2027 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2028 return 6;
2029 else
2030 return 12;
2034 /* Return the relative costs of expression X. */
2036 static bool
2037 visium_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
2038 int opno ATTRIBUTE_UNUSED, int *total,
2039 bool speed ATTRIBUTE_UNUSED)
2041 int code = GET_CODE (x);
2043 switch (code)
2045 case CONST_INT:
2046 /* Small integers are as cheap as registers. 4-byte values can
2047 be fetched as immediate constants - let's give that the cost
2048 of an extra insn. */
2049 *total = COSTS_N_INSNS (!satisfies_constraint_J (x));
2050 return true;
2052 case CONST:
2053 case LABEL_REF:
2054 case SYMBOL_REF:
2055 *total = COSTS_N_INSNS (2);
2056 return true;
2058 case CONST_DOUBLE:
2060 rtx high, low;
2061 split_double (x, &high, &low);
2062 *total =
2063 COSTS_N_INSNS
2064 (!satisfies_constraint_J (high) + !satisfies_constraint_J (low));
2065 return true;
2068 case MULT:
2069 *total = COSTS_N_INSNS (3);
2070 return false;
2072 case DIV:
2073 case UDIV:
2074 case MOD:
2075 case UMOD:
2076 if (mode == DImode)
2077 *total = COSTS_N_INSNS (64);
2078 else
2079 *total = COSTS_N_INSNS (32);
2080 return false;
2082 case PLUS:
2083 case MINUS:
2084 case NEG:
2085 /* DImode operations are performed directly on the ALU. */
2086 if (mode == DImode)
2087 *total = COSTS_N_INSNS (2);
2088 else
2089 *total = COSTS_N_INSNS (1);
2090 return false;
2092 case ASHIFT:
2093 case ASHIFTRT:
2094 case LSHIFTRT:
2095 /* DImode operations are performed on the EAM instead. */
2096 if (mode == DImode)
2097 *total = COSTS_N_INSNS (3);
2098 else
2099 *total = COSTS_N_INSNS (1);
2100 return false;
2102 case COMPARE:
2103 /* This matches the btst pattern. */
2104 if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT
2105 && XEXP (x, 1) == const0_rtx
2106 && XEXP (XEXP (x, 0), 1) == const1_rtx
2107 && satisfies_constraint_K (XEXP (XEXP (x, 0), 2)))
2108 *total = COSTS_N_INSNS (1);
2109 return false;
2111 default:
2112 return false;
2116 /* Split a double move of OPERANDS in MODE. */
2118 void
2119 visium_split_double_move (rtx *operands, machine_mode mode)
2121 bool swap = false;
2123 /* Check register to register with overlap. */
2124 if (GET_CODE (operands[0]) == REG
2125 && GET_CODE (operands[1]) == REG
2126 && REGNO (operands[0]) == REGNO (operands[1]) + 1)
2127 swap = true;
2129 /* Check memory to register where the base reg overlaps the destination. */
2130 if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == MEM)
2132 rtx op = XEXP (operands[1], 0);
2134 if (GET_CODE (op) == SUBREG)
2135 op = SUBREG_REG (op);
2137 if (GET_CODE (op) == REG && REGNO (op) == REGNO (operands[0]))
2138 swap = true;
2140 if (GET_CODE (op) == PLUS)
2142 rtx x = XEXP (op, 0);
2143 rtx y = XEXP (op, 1);
2145 if (GET_CODE (x) == REG && REGNO (x) == REGNO (operands[0]))
2146 swap = true;
2148 if (GET_CODE (y) == REG && REGNO (y) == REGNO (operands[0]))
2149 swap = true;
2153 if (swap)
2155 operands[2] = operand_subword (operands[0], 1, 1, mode);
2156 operands[3] = operand_subword (operands[1], 1, 1, mode);
2157 operands[4] = operand_subword (operands[0], 0, 1, mode);
2158 operands[5] = operand_subword (operands[1], 0, 1, mode);
2160 else
2162 operands[2] = operand_subword (operands[0], 0, 1, mode);
2163 operands[3] = operand_subword (operands[1], 0, 1, mode);
2164 operands[4] = operand_subword (operands[0], 1, 1, mode);
2165 operands[5] = operand_subword (operands[1], 1, 1, mode);
2169 /* Split a double addition or subtraction of operands. */
2171 void
2172 visium_split_double_add (enum rtx_code code, rtx op0, rtx op1, rtx op2)
2174 rtx op3 = gen_lowpart (SImode, op0);
2175 rtx op4 = gen_lowpart (SImode, op1);
2176 rtx op5;
2177 rtx op6 = gen_highpart (SImode, op0);
2178 rtx op7 = (op1 == const0_rtx ? op1 : gen_highpart (SImode, op1));
2179 rtx op8;
2180 rtx x, pat, flags;
2182 /* If operand #2 is a small constant, then its high part is null. */
2183 if (CONST_INT_P (op2))
2185 HOST_WIDE_INT val = INTVAL (op2);
2187 if (val < 0)
2189 code = (code == MINUS ? PLUS : MINUS);
2190 val = -val;
2193 op5 = gen_int_mode (val, SImode);
2194 op8 = const0_rtx;
2196 else
2198 op5 = gen_lowpart (SImode, op2);
2199 op8 = gen_highpart (SImode, op2);
2202 if (op4 == const0_rtx)
2203 pat = gen_negsi2_insn_set_carry (op3, op5);
2204 else if (code == MINUS)
2205 pat = gen_subsi3_insn_set_carry (op3, op4, op5);
2206 else
2207 pat = gen_addsi3_insn_set_carry (op3, op4, op5);
2208 emit_insn (pat);
2210 /* This is the plus_[plus_]sltu_flags or minus_[minus_]sltu_flags pattern. */
2211 if (op8 == const0_rtx)
2212 x = op7;
2213 else
2214 x = gen_rtx_fmt_ee (code, SImode, op7, op8);
2215 flags = gen_rtx_REG (CCCmode, FLAGS_REGNUM);
2216 x = gen_rtx_fmt_ee (code, SImode, x, gen_rtx_LTU (SImode, flags, const0_rtx));
2217 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2218 XVECEXP (pat, 0, 0) = gen_rtx_SET (op6, x);
2219 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2220 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2221 emit_insn (pat);
2223 visium_flags_exposed = true;
2226 /* Expand a copysign of OPERANDS in MODE. */
2228 void
2229 visium_expand_copysign (rtx *operands, machine_mode mode)
2231 rtx op0 = operands[0];
2232 rtx op1 = operands[1];
2233 rtx op2 = operands[2];
2234 rtx mask = force_reg (SImode, GEN_INT (0x7fffffff));
2235 rtx x;
2237 /* We manually handle SFmode because the abs and neg instructions of
2238 the FPU on the MCM have a non-standard behavior wrt NaNs. */
2239 gcc_assert (mode == SFmode);
2241 /* First get all the non-sign bits of op1. */
2242 if (GET_CODE (op1) == CONST_DOUBLE)
2244 if (real_isneg (CONST_DOUBLE_REAL_VALUE (op1)))
2245 op1 = simplify_unary_operation (ABS, mode, op1, mode);
2246 if (op1 != CONST0_RTX (mode))
2248 long l;
2249 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op1), l);
2250 op1 = force_reg (SImode, gen_int_mode (l, SImode));
2253 else
2255 op1 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op1));
2256 op1 = force_reg (SImode, gen_rtx_AND (SImode, op1, mask));
2259 /* Then get the sign bit of op2. */
2260 mask = force_reg (SImode, gen_rtx_NOT (SImode, mask));
2261 op2 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op2));
2262 op2 = force_reg (SImode, gen_rtx_AND (SImode, op2, mask));
2264 /* Finally OR the two values. */
2265 if (op1 == CONST0_RTX (SFmode))
2266 x = op2;
2267 else
2268 x = force_reg (SImode, gen_rtx_IOR (SImode, op1, op2));
2270 /* And move the result to the destination. */
2271 emit_insn (gen_rtx_SET (op0, gen_lowpart (SFmode, x)));
2274 /* Expand a cstore of OPERANDS in MODE for EQ/NE/LTU/GTU/GEU/LEU. We generate
2275 the result in the C flag and use the ADC/SUBC instructions to write it into
2276 the destination register.
2278 It would also be possible to implement support for LT/GT/LE/GE by means of
2279 the RFLAG instruction followed by some shifts, but this can pessimize the
2280 generated code. */
2282 void
2283 visium_expand_int_cstore (rtx *operands, machine_mode mode)
2285 enum rtx_code code = GET_CODE (operands[1]);
2286 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], sltu;
2287 bool reverse = false;
2289 switch (code)
2291 case EQ:
2292 case NE:
2293 /* We use a special comparison to get the result in the C flag. */
2294 if (op2 != const0_rtx)
2295 op1 = force_reg (mode, gen_rtx_XOR (mode, op1, op2));
2296 op1 = gen_rtx_NOT (mode, op1);
2297 op2 = constm1_rtx;
2298 if (code == EQ)
2299 reverse = true;
2300 break;
2302 case LEU:
2303 case GEU:
2304 /* The result is naturally in the C flag modulo a couple of tricks. */
2305 code = reverse_condition (code);
2306 reverse = true;
2308 /* ... fall through ... */
2310 case LTU:
2311 case GTU:
2312 if (code == GTU)
2314 rtx tmp = op1;
2315 op1 = op2;
2316 op2 = tmp;
2318 break;
2320 default:
2321 gcc_unreachable ();
2324 /* We need either a single ADC or a SUBC and a PLUS. */
2325 sltu = gen_rtx_LTU (SImode, op1, op2);
2327 if (reverse)
2329 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, sltu));
2330 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2332 else
2333 emit_insn (gen_rtx_SET (op0, sltu));
2336 /* Expand a cstore of OPERANDS in MODE for LT/GT/UNGE/UNLE. We generate the
2337 result in the C flag and use the ADC/SUBC instructions to write it into
2338 the destination register. */
2340 void
2341 visium_expand_fp_cstore (rtx *operands,
2342 machine_mode mode ATTRIBUTE_UNUSED)
2344 enum rtx_code code = GET_CODE (operands[1]);
2345 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], slt;
2346 bool reverse = false;
2348 switch (code)
2350 case UNLE:
2351 case UNGE:
2352 /* The result is naturally in the C flag modulo a couple of tricks. */
2353 code = reverse_condition_maybe_unordered (code);
2354 reverse = true;
2356 /* ... fall through ... */
2358 case LT:
2359 case GT:
2360 if (code == GT)
2362 rtx tmp = op1;
2363 op1 = op2;
2364 op2 = tmp;
2366 break;
2368 default:
2369 gcc_unreachable ();
2372 /* We need either a single ADC or a SUBC and a PLUS. */
2373 slt = gen_rtx_LT (SImode, op1, op2);
2375 if (reverse)
2377 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, slt));
2378 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2380 else
2381 emit_insn (gen_rtx_SET (op0, slt));
2384 /* Split a compare-and-store with CODE, operands OP2 and OP3, combined with
2385 operation with OP_CODE, operands OP0 and OP1. */
2387 void
2388 visium_split_cstore (enum rtx_code op_code, rtx op0, rtx op1,
2389 enum rtx_code code, rtx op2, rtx op3)
2391 machine_mode cc_mode = visium_select_cc_mode (code, op2, op3);
2393 /* If a FP cstore was reversed, then it was originally UNGE/UNLE. */
2394 if (cc_mode == CCFPEmode && (op_code == NEG || op_code == MINUS))
2395 cc_mode = CCFPmode;
2397 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2398 rtx x = gen_rtx_COMPARE (cc_mode, op2, op3);
2399 x = gen_rtx_SET (flags, x);
2400 emit_insn (x);
2402 x = gen_rtx_fmt_ee (code, SImode, flags, const0_rtx);
2403 switch (op_code)
2405 case SET:
2406 break;
2407 case NEG:
2408 x = gen_rtx_NEG (SImode, x);
2409 break;
2410 case PLUS:
2411 case MINUS:
2412 x = gen_rtx_fmt_ee (op_code, SImode, op1, x);
2413 break;
2414 default:
2415 gcc_unreachable ();
2418 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2419 XVECEXP (pat, 0, 0) = gen_rtx_SET (op0, x);
2420 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2421 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2422 emit_insn (pat);
2424 visium_flags_exposed = true;
2427 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2428 address SRC_REG to DST with address DST_REG in 4-byte chunks. */
2430 static void
2431 expand_block_move_4 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2433 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2434 unsigned int rem = bytes % 4;
2436 if (TARGET_BMI)
2438 unsigned int i;
2439 rtx insn;
2441 emit_move_insn (regno_reg_rtx[1], dst_reg);
2442 emit_move_insn (regno_reg_rtx[2], src_reg);
2443 emit_move_insn (regno_reg_rtx[3], bytes_rtx);
2445 insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (8));
2446 XVECEXP (insn, 0, 0)
2447 = gen_rtx_SET (replace_equiv_address_nv (dst, regno_reg_rtx[1]),
2448 replace_equiv_address_nv (src, regno_reg_rtx[2]));
2449 XVECEXP (insn, 0, 1) = gen_rtx_USE (VOIDmode, regno_reg_rtx[3]);
2450 for (i = 1; i <= 6; i++)
2451 XVECEXP (insn, 0, 1 + i)
2452 = gen_rtx_CLOBBER (VOIDmode, regno_reg_rtx[i]);
2453 emit_insn (insn);
2455 else
2456 emit_library_call (long_int_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2457 dst_reg, Pmode,
2458 src_reg, Pmode,
2459 convert_to_mode (TYPE_MODE (sizetype),
2460 GEN_INT (bytes >> 2),
2461 TYPE_UNSIGNED (sizetype)),
2462 TYPE_MODE (sizetype));
2463 if (rem == 0)
2464 return;
2466 dst = replace_equiv_address_nv (dst, dst_reg);
2467 src = replace_equiv_address_nv (src, src_reg);
2468 bytes -= rem;
2470 if (rem > 1)
2472 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2473 adjust_address_nv (src, HImode, bytes));
2474 bytes += 2;
2475 rem -= 2;
2478 if (rem > 0)
2479 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2480 adjust_address_nv (src, QImode, bytes));
2483 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2484 address SRC_REG to DST with address DST_REG in 2-bytes chunks. */
2486 static void
2487 expand_block_move_2 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2489 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2490 unsigned int rem = bytes % 2;
2492 emit_library_call (wrd_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2493 dst_reg, Pmode,
2494 src_reg, Pmode,
2495 convert_to_mode (TYPE_MODE (sizetype),
2496 GEN_INT (bytes >> 1),
2497 TYPE_UNSIGNED (sizetype)),
2498 TYPE_MODE (sizetype));
2499 if (rem == 0)
2500 return;
2502 dst = replace_equiv_address_nv (dst, dst_reg);
2503 src = replace_equiv_address_nv (src, src_reg);
2504 bytes -= rem;
2506 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2507 adjust_address_nv (src, QImode, bytes));
2510 /* Generate a call to a library function to move BYTES_RTX bytes from address
2511 SRC_REG to address DST_REG in 1-byte chunks. */
2513 static void
2514 expand_block_move_1 (rtx dst_reg, rtx src_reg, rtx bytes_rtx)
2516 emit_library_call (byt_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2517 dst_reg, Pmode,
2518 src_reg, Pmode,
2519 convert_to_mode (TYPE_MODE (sizetype),
2520 bytes_rtx,
2521 TYPE_UNSIGNED (sizetype)),
2522 TYPE_MODE (sizetype));
2525 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2526 address DST_REG to VALUE_RTX in 4-byte chunks. */
2528 static void
2529 expand_block_set_4 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2531 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2532 unsigned int rem = bytes % 4;
2534 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2535 emit_library_call (long_int_memset_libfunc, LCT_NORMAL, VOIDmode,
2536 dst_reg, Pmode,
2537 value_rtx, Pmode,
2538 convert_to_mode (TYPE_MODE (sizetype),
2539 GEN_INT (bytes >> 2),
2540 TYPE_UNSIGNED (sizetype)),
2541 TYPE_MODE (sizetype));
2542 if (rem == 0)
2543 return;
2545 dst = replace_equiv_address_nv (dst, dst_reg);
2546 bytes -= rem;
2548 if (rem > 1)
2550 if (CONST_INT_P (value_rtx))
2552 const unsigned HOST_WIDE_INT value = UINTVAL (value_rtx) & 0xff;
2553 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2554 gen_int_mode ((value << 8) | value, HImode));
2556 else
2558 rtx temp = convert_to_mode (QImode, value_rtx, 1);
2559 emit_move_insn (adjust_address_nv (dst, QImode, bytes), temp);
2560 emit_move_insn (adjust_address_nv (dst, QImode, bytes + 1), temp);
2562 bytes += 2;
2563 rem -= 2;
2566 if (rem > 0)
2567 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2568 convert_to_mode (QImode, value_rtx, 1));
2571 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2572 address DST_REG to VALUE_RTX in 2-byte chunks. */
2574 static void
2575 expand_block_set_2 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2577 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2578 unsigned int rem = bytes % 2;
2580 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2581 emit_library_call (wrd_memset_libfunc, LCT_NORMAL, VOIDmode,
2582 dst_reg, Pmode,
2583 value_rtx, Pmode,
2584 convert_to_mode (TYPE_MODE (sizetype),
2585 GEN_INT (bytes >> 1),
2586 TYPE_UNSIGNED (sizetype)),
2587 TYPE_MODE (sizetype));
2588 if (rem == 0)
2589 return;
2591 dst = replace_equiv_address_nv (dst, dst_reg);
2592 bytes -= rem;
2594 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2595 convert_to_mode (QImode, value_rtx, 1));
2598 /* Generate a call to a library function to set BYTES_RTX bytes at address
2599 DST_REG to VALUE_RTX in 1-byte chunks. */
2601 static void
2602 expand_block_set_1 (rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2604 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2605 emit_library_call (byt_memset_libfunc, LCT_NORMAL, VOIDmode,
2606 dst_reg, Pmode,
2607 value_rtx, Pmode,
2608 convert_to_mode (TYPE_MODE (sizetype),
2609 bytes_rtx,
2610 TYPE_UNSIGNED (sizetype)),
2611 TYPE_MODE (sizetype));
2614 /* Expand string/block move operations.
2616 operands[0] is the pointer to the destination.
2617 operands[1] is the pointer to the source.
2618 operands[2] is the number of bytes to move.
2619 operands[3] is the alignment.
2621 Return 1 upon success, 0 otherwise. */
2624 visium_expand_block_move (rtx *operands)
2626 rtx dst = operands[0];
2627 rtx src = operands[1];
2628 rtx bytes_rtx = operands[2];
2629 rtx align_rtx = operands[3];
2630 const int align = INTVAL (align_rtx);
2631 rtx dst_reg, src_reg;
2632 tree dst_expr, src_expr;
2634 /* We only handle a fixed number of bytes for now. */
2635 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2636 return 0;
2638 /* Copy the addresses into scratch registers. */
2639 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2640 src_reg = copy_addr_to_reg (XEXP (src, 0));
2642 /* Move the data with the appropriate granularity. */
2643 if (align >= 4)
2644 expand_block_move_4 (dst, dst_reg, src, src_reg, bytes_rtx);
2645 else if (align >= 2)
2646 expand_block_move_2 (dst, dst_reg, src, src_reg, bytes_rtx);
2647 else
2648 expand_block_move_1 (dst_reg, src_reg, bytes_rtx);
2650 /* Since DST and SRC are passed to a libcall, mark the corresponding
2651 tree EXPR as addressable. */
2652 dst_expr = MEM_EXPR (dst);
2653 src_expr = MEM_EXPR (src);
2654 if (dst_expr)
2655 mark_addressable (dst_expr);
2656 if (src_expr)
2657 mark_addressable (src_expr);
2659 return 1;
2662 /* Expand string/block set operations.
2664 operands[0] is the pointer to the destination.
2665 operands[1] is the number of bytes to set.
2666 operands[2] is the source value.
2667 operands[3] is the alignment.
2669 Return 1 upon success, 0 otherwise. */
2672 visium_expand_block_set (rtx *operands)
2674 rtx dst = operands[0];
2675 rtx bytes_rtx = operands[1];
2676 rtx value_rtx = operands[2];
2677 rtx align_rtx = operands[3];
2678 const int align = INTVAL (align_rtx);
2679 rtx dst_reg;
2680 tree dst_expr;
2682 /* We only handle a fixed number of bytes for now. */
2683 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2684 return 0;
2686 /* Copy the address into a scratch register. */
2687 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2689 /* Set the data with the appropriate granularity. */
2690 if (align >= 4)
2691 expand_block_set_4 (dst, dst_reg, value_rtx, bytes_rtx);
2692 else if (align >= 2)
2693 expand_block_set_2 (dst, dst_reg, value_rtx, bytes_rtx);
2694 else
2695 expand_block_set_1 (dst_reg, value_rtx, bytes_rtx);
2697 /* Since DST is passed to a libcall, mark the corresponding
2698 tree EXPR as addressable. */
2699 dst_expr = MEM_EXPR (dst);
2700 if (dst_expr)
2701 mark_addressable (dst_expr);
2703 return 1;
2706 /* Initialize a trampoline. M_TRAMP is an RTX for the memory block for the
2707 trampoline, FNDECL is the FUNCTION_DECL for the nested function and
2708 STATIC_CHAIN is an RTX for the static chain value that should be passed
2709 to the function when it is called. */
2711 static void
2712 visium_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
2714 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2715 rtx addr = XEXP (m_tramp, 0);
2717 /* The trampoline initialization sequence is:
2719 moviu r9,%u FUNCTION
2720 movil r9,%l FUNCTION
2721 moviu r20,%u STATIC
2722 bra tr,r9,r9
2723 movil r20,%l STATIC
2725 We don't use r0 as the destination register of the branch because we want
2726 the Branch Pre-decode Logic of the GR6 to use the Address Load Array to
2727 predict the branch target. */
2729 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 0)),
2730 plus_constant (SImode,
2731 expand_shift (RSHIFT_EXPR, SImode, fnaddr,
2732 16, NULL_RTX, 1),
2733 0x04a90000));
2735 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 4)),
2736 plus_constant (SImode,
2737 expand_and (SImode, fnaddr, GEN_INT (0xffff),
2738 NULL_RTX),
2739 0x04890000));
2741 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 8)),
2742 plus_constant (SImode,
2743 expand_shift (RSHIFT_EXPR, SImode,
2744 static_chain,
2745 16, NULL_RTX, 1),
2746 0x04b40000));
2748 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)),
2749 gen_int_mode (0xff892404, SImode));
2751 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 16)),
2752 plus_constant (SImode,
2753 expand_and (SImode, static_chain,
2754 GEN_INT (0xffff), NULL_RTX),
2755 0x04940000));
2757 emit_library_call (set_trampoline_parity_libfunc, LCT_NORMAL, VOIDmode,
2758 addr, SImode);
2761 /* Return true if the current function must have and use a frame pointer. */
2763 static bool
2764 visium_frame_pointer_required (void)
2766 /* The frame pointer is required if the function isn't leaf to be able to
2767 do manual stack unwinding. */
2768 if (!crtl->is_leaf)
2769 return true;
2771 /* If the stack pointer is dynamically modified in the function, it cannot
2772 serve as the frame pointer. */
2773 if (!crtl->sp_is_unchanging)
2774 return true;
2776 /* If the function receives nonlocal gotos, it needs to save the frame
2777 pointer in the nonlocal_goto_save_area object. */
2778 if (cfun->has_nonlocal_label)
2779 return true;
2781 /* The frame also needs to be established in some special cases. */
2782 if (visium_frame_needed)
2783 return true;
2785 return false;
2788 /* Profiling support. Just a call to MCOUNT is needed. No labelled counter
2789 location is involved. Proper support for __builtin_return_address is also
2790 required, which is fairly straightforward provided a frame gets created. */
2792 void
2793 visium_profile_hook (void)
2795 visium_frame_needed = true;
2796 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "mcount"), LCT_NORMAL,
2797 VOIDmode);
2800 /* A C expression whose value is RTL representing the address in a stack frame
2801 where the pointer to the caller's frame is stored. Assume that FRAMEADDR is
2802 an RTL expression for the address of the stack frame itself.
2804 If you don't define this macro, the default is to return the value of
2805 FRAMEADDR--that is, the stack frame address is also the address of the stack
2806 word that points to the previous frame. */
2809 visium_dynamic_chain_address (rtx frame)
2811 /* This is the default, but we need to make sure the frame gets created. */
2812 visium_frame_needed = true;
2813 return frame;
2816 /* A C expression whose value is RTL representing the value of the return
2817 address for the frame COUNT steps up from the current frame, after the
2818 prologue. FRAMEADDR is the frame pointer of the COUNT frame, or the frame
2819 pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
2820 defined.
2822 The value of the expression must always be the correct address when COUNT is
2823 zero, but may be `NULL_RTX' if there is not way to determine the return
2824 address of other frames. */
2827 visium_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
2829 /* Dont try to compute anything other than frame zero. */
2830 if (count != 0)
2831 return NULL_RTX;
2833 visium_frame_needed = true;
2834 return
2835 gen_frame_mem (Pmode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2838 /* Helper function for EH_RETURN_HANDLER_RTX. Return the RTX representing a
2839 location in which to store the address of an exception handler to which we
2840 should return. */
2843 visium_eh_return_handler_rtx (void)
2845 rtx mem
2846 = gen_frame_mem (SImode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2847 MEM_VOLATILE_P (mem) = 1;
2848 return mem;
2851 static struct machine_function *
2852 visium_init_machine_status (void)
2854 return ggc_cleared_alloc<machine_function> ();
2857 /* The per-function data machinery is needed to indicate when a frame
2858 is required. */
2860 void
2861 visium_init_expanders (void)
2863 init_machine_status = visium_init_machine_status;
2866 /* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE,
2867 return the mode to be used for the comparison. */
2869 machine_mode
2870 visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
2872 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2874 switch (code)
2876 case EQ:
2877 case NE:
2878 case ORDERED:
2879 case UNORDERED:
2880 case UNLT:
2881 case UNLE:
2882 case UNGT:
2883 case UNGE:
2884 return CCFPmode;
2886 case LT:
2887 case LE:
2888 case GT:
2889 case GE:
2890 return CCFPEmode;
2892 /* These 2 comparison codes are not supported. */
2893 case UNEQ:
2894 case LTGT:
2895 default:
2896 gcc_unreachable ();
2900 /* This is for the cmp<mode>_sne pattern. */
2901 if (op1 == constm1_rtx)
2902 return CCCmode;
2904 /* This is for the add<mode>3_insn_set_carry pattern. */
2905 if ((code == LTU || code == GEU)
2906 && GET_CODE (op0) == PLUS
2907 && rtx_equal_p (XEXP (op0, 0), op1))
2908 return CCCmode;
2910 /* This is for the {add,sub,neg}<mode>3_insn_set_overflow pattern. */
2911 if ((code == EQ || code == NE)
2912 && GET_CODE (op1) == UNSPEC
2913 && (XINT (op1, 1) == UNSPEC_ADDV
2914 || XINT (op1, 1) == UNSPEC_SUBV
2915 || XINT (op1, 1) == UNSPEC_NEGV))
2916 return CCVmode;
2918 if (op1 != const0_rtx)
2919 return CCmode;
2921 switch (GET_CODE (op0))
2923 case PLUS:
2924 case MINUS:
2925 case NEG:
2926 case ASHIFT:
2927 case LTU:
2928 case LT:
2929 /* The C and V flags may be set differently from a COMPARE with zero.
2930 The consequence is that a comparison operator testing C or V must
2931 be turned into another operator not testing C or V and yielding
2932 the same result for a comparison with zero. That's possible for
2933 GE/LT which become NC/NS respectively, but not for GT/LE for which
2934 the altered operator doesn't exist on the Visium. */
2935 return CCNZmode;
2937 case ZERO_EXTRACT:
2938 /* This is a btst, the result is in C instead of Z. */
2939 return CCCmode;
2941 case REG:
2942 case AND:
2943 case IOR:
2944 case XOR:
2945 case NOT:
2946 case ASHIFTRT:
2947 case LSHIFTRT:
2948 case TRUNCATE:
2949 case SIGN_EXTEND:
2950 /* Pretend that the flags are set as for a COMPARE with zero.
2951 That's mostly true, except for the 2 right shift insns that
2952 will set the C flag. But the C flag is relevant only for
2953 the unsigned comparison operators and they are eliminated
2954 when applied to a comparison with zero. */
2955 return CCmode;
2957 /* ??? Cater to the junk RTXes sent by try_merge_compare. */
2958 case ASM_OPERANDS:
2959 case CALL:
2960 case CONST_INT:
2961 case LO_SUM:
2962 case HIGH:
2963 case MEM:
2964 case UNSPEC:
2965 case ZERO_EXTEND:
2966 return CCmode;
2968 default:
2969 gcc_unreachable ();
2973 /* Split a compare-and-branch with CODE, operands OP0 and OP1, and LABEL. */
2975 void
2976 visium_split_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx label)
2978 machine_mode cc_mode = visium_select_cc_mode (code, op0, op1);
2979 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2981 rtx x = gen_rtx_COMPARE (cc_mode, op0, op1);
2982 x = gen_rtx_SET (flags, x);
2983 emit_insn (x);
2985 x = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
2986 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, gen_rtx_LABEL_REF (Pmode, label),
2987 pc_rtx);
2988 x = gen_rtx_SET (pc_rtx, x);
2989 emit_jump_insn (x);
2991 visium_flags_exposed = true;
2994 /* Branch instructions on the Visium.
2996 Setting aside the interrupt-handling specific instructions, the ISA has
2997 two branch instructions: BRR and BRA. The former is used to implement
2998 short branches (+/- 2^17) within functions and its target is encoded in
2999 the instruction. The latter is used to implement all the other types
3000 of control flow changes and its target might not be statically known
3001 or even easily predictable at run time. Here's a complete summary of
3002 the patterns that generate a BRA instruction:
3004 1. Indirect jump
3005 2. Table jump
3006 3. Call
3007 4. Sibling call
3008 5. Return
3009 6. Long branch
3010 7. Trampoline
3012 Among these patterns, only the return (5) and the long branch (6) can be
3013 conditional; all the other patterns are always unconditional.
3015 The following algorithm can be used to identify the pattern for which
3016 the BRA instruction was generated and work out its target:
3018 A. If the source is r21 and the destination is r0, this is a return (5)
3019 and the target is the caller (i.e. the value of r21 on function's
3020 entry).
3022 B. If the source is rN, N != 21 and the destination is r0, this is either
3023 an indirect jump or a table jump (1, 2) and the target is not easily
3024 predictable.
3026 C. If the source is rN, N != 21 and the destination is r21, this is a call
3027 (3) and the target is given by the preceding MOVIL/MOVIU pair for rN,
3028 unless this is an indirect call in which case the target is not easily
3029 predictable.
3031 D. If the source is rN, N != 21 and the destination is also rN, this is
3032 either a sibling call or a trampoline (4, 7) and the target is given
3033 by the preceding MOVIL/MOVIU pair for rN.
3035 E. If the source is r21 and the destination is also r21, this is a long
3036 branch (6) and the target is given by the preceding MOVIL/MOVIU pair
3037 for r21.
3039 The other combinations are not used. This implementation has been devised
3040 to accommodate the branch predictor of the GR6 but is used unconditionally
3041 by the compiler, i.e. including for earlier processors. */
3043 /* Output a conditional/unconditional branch to LABEL. COND is the string
3044 condition. INSN is the instruction. */
3046 static const char *
3047 output_branch (rtx label, const char *cond, rtx_insn *insn)
3049 char str[64];
3050 rtx operands[2];
3052 gcc_assert (cond);
3053 operands[0] = label;
3055 /* If the length of the instruction is greater than 8, then this is a
3056 long branch and we need to work harder to emit it properly. */
3057 if (get_attr_length (insn) > 8)
3059 bool spilled;
3061 /* If the link register has been saved, then we use it. */
3062 if (current_function_saves_lr ())
3064 operands[1] = regno_reg_rtx [LINK_REGNUM];
3065 spilled = false;
3068 /* Or else, if the long-branch register isn't live, we use it. */
3069 else if (!df_regs_ever_live_p (long_branch_regnum))
3071 operands[1] = regno_reg_rtx [long_branch_regnum];
3072 spilled = false;
3075 /* Otherwise, we will use the long-branch register but we need to
3076 spill it to the stack and reload it at the end. We should have
3077 reserved the LR slot for this purpose. */
3078 else
3080 operands[1] = regno_reg_rtx [long_branch_regnum];
3081 spilled = true;
3082 gcc_assert (current_function_has_lr_slot ());
3085 /* First emit the spill to the stack:
3087 insn_in_delay_slot
3088 write.l [1](sp),reg */
3089 if (spilled)
3091 if (final_sequence)
3093 rtx_insn *delay = NEXT_INSN (insn);
3094 int seen;
3095 gcc_assert (delay);
3097 final_scan_insn (delay, asm_out_file, optimize, 0, &seen);
3098 PATTERN (delay) = gen_blockage ();
3099 INSN_CODE (delay) = -1;
3102 if (current_function_saves_fp ())
3103 output_asm_insn ("write.l 1(sp),%1", operands);
3104 else
3105 output_asm_insn ("write.l (sp),%1", operands);
3108 /* Then emit the core sequence:
3110 moviu reg,%u label
3111 movil reg,%l label
3112 bra tr,reg,reg
3114 We don't use r0 as the destination register of the branch because we
3115 want the Branch Pre-decode Logic of the GR6 to use the Address Load
3116 Array to predict the branch target. */
3117 output_asm_insn ("moviu %1,%%u %0", operands);
3118 output_asm_insn ("movil %1,%%l %0", operands);
3119 strcpy (str, "bra ");
3120 strcat (str, cond);
3121 strcat (str, ",%1,%1");
3122 if (!spilled)
3123 strcat (str, "%#");
3124 strcat (str, "\t\t;long branch");
3125 output_asm_insn (str, operands);
3127 /* Finally emit the reload:
3129 read.l reg,[1](sp) */
3130 if (spilled)
3132 if (current_function_saves_fp ())
3133 output_asm_insn (" read.l %1,1(sp)", operands);
3134 else
3135 output_asm_insn (" read.l %1,(sp)", operands);
3139 /* Or else, if the label is PC, then this is a return. */
3140 else if (label == pc_rtx)
3142 strcpy (str, "bra ");
3143 strcat (str, cond);
3144 strcat (str, ",r21,r0%#\t\t;return");
3145 output_asm_insn (str, operands);
3148 /* Otherwise, this is a short branch. */
3149 else
3151 strcpy (str, "brr ");
3152 strcat (str, cond);
3153 strcat (str, ",%0%#");
3154 output_asm_insn (str, operands);
3157 return "";
3160 /* Output an unconditional branch to LABEL. INSN is the instruction. */
3162 const char *
3163 output_ubranch (rtx label, rtx_insn *insn)
3165 return output_branch (label, "tr", insn);
3168 /* Output a conditional branch to LABEL. CODE is the comparison code.
3169 CC_MODE is the mode of the CC register. REVERSED is non-zero if we
3170 should reverse the sense of the comparison. INSN is the instruction. */
3172 const char *
3173 output_cbranch (rtx label, enum rtx_code code, machine_mode cc_mode,
3174 int reversed, rtx_insn *insn)
3176 const char *cond;
3178 if (reversed)
3180 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3181 code = reverse_condition_maybe_unordered (code);
3182 else
3183 code = reverse_condition (code);
3186 switch (code)
3188 case NE:
3189 if (cc_mode == CCCmode)
3190 cond = "cs";
3191 else if (cc_mode == CCVmode)
3192 cond = "os";
3193 else
3194 cond = "ne";
3195 break;
3197 case EQ:
3198 if (cc_mode == CCCmode)
3199 cond = "cc";
3200 else if (cc_mode == CCVmode)
3201 cond = "oc";
3202 else
3203 cond = "eq";
3204 break;
3206 case GE:
3207 if (cc_mode == CCNZmode)
3208 cond = "nc";
3209 else
3210 cond = "ge";
3211 break;
3213 case GT:
3214 cond = "gt";
3215 break;
3217 case LE:
3218 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3219 cond = "ls";
3220 else
3221 cond = "le";
3222 break;
3224 case LT:
3225 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3226 cond = "cs"; /* or "ns" */
3227 else if (cc_mode == CCNZmode)
3228 cond = "ns";
3229 else
3230 cond = "lt";
3231 break;
3233 case GEU:
3234 cond = "cc";
3235 break;
3237 case GTU:
3238 cond = "hi";
3239 break;
3241 case LEU:
3242 cond = "ls";
3243 break;
3245 case LTU:
3246 cond = "cs";
3247 break;
3249 case UNORDERED:
3250 cond = "os";
3251 break;
3253 case ORDERED:
3254 cond = "oc";
3255 break;
3257 case UNGE:
3258 cond = "cc"; /* or "nc" */
3259 break;
3261 case UNGT:
3262 cond = "hi";
3263 break;
3265 case UNLE:
3266 cond = "le";
3267 break;
3269 case UNLT:
3270 cond = "lt";
3271 break;
3273 /* These 2 comparison codes are not supported. */
3274 case UNEQ:
3275 case LTGT:
3276 default:
3277 gcc_unreachable ();
3280 return output_branch (label, cond, insn);
3283 /* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
3285 static bool
3286 visium_print_operand_punct_valid_p (unsigned char code)
3288 return code == '#';
3291 /* Implement TARGET_PRINT_OPERAND. Output to stdio stream FILE the assembler
3292 syntax for an instruction operand OP subject to the modifier LETTER. */
3294 static void
3295 visium_print_operand (FILE *file, rtx op, int letter)
3297 switch (letter)
3299 case '#':
3300 /* Output an insn in a delay slot. */
3301 if (final_sequence)
3302 visium_indent_opcode = 1;
3303 else
3304 fputs ("\n\t nop", file);
3305 return;
3307 case 'b':
3308 /* Print LS 8 bits of operand. */
3309 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xff);
3310 return;
3312 case 'w':
3313 /* Print LS 16 bits of operand. */
3314 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xffff);
3315 return;
3317 case 'u':
3318 /* Print MS 16 bits of operand. */
3319 fprintf (file,
3320 HOST_WIDE_INT_PRINT_UNSIGNED, (UINTVAL (op) >> 16) & 0xffff);
3321 return;
3323 case 'r':
3324 /* It's either a register or zero. */
3325 if (GET_CODE (op) == REG)
3326 fputs (reg_names[REGNO (op)], file);
3327 else
3328 fputs (reg_names[0], file);
3329 return;
3331 case 'f':
3332 /* It's either a FP register or zero. */
3333 if (GET_CODE (op) == REG)
3334 fputs (reg_names[REGNO (op)], file);
3335 else
3336 fputs (reg_names[FP_FIRST_REGNUM], file);
3337 return;
3340 switch (GET_CODE (op))
3342 case REG:
3343 if (letter == 'd')
3344 fputs (reg_names[REGNO (op) + 1], file);
3345 else
3346 fputs (reg_names[REGNO (op)], file);
3347 break;
3349 case SYMBOL_REF:
3350 case LABEL_REF:
3351 case CONST:
3352 output_addr_const (file, op);
3353 break;
3355 case MEM:
3356 visium_print_operand_address (file, GET_MODE (op), XEXP (op, 0));
3357 break;
3359 case CONST_INT:
3360 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
3361 break;
3363 case CODE_LABEL:
3364 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (op));
3365 break;
3367 case HIGH:
3368 visium_print_operand (file, XEXP (op, 1), letter);
3369 break;
3371 default:
3372 fatal_insn ("illegal operand ", op);
3376 /* Implement TARGET_PRINT_OPERAND_ADDRESS. Output to stdio stream FILE the
3377 assembler syntax for an instruction operand that is a memory reference
3378 whose address is ADDR. */
3380 static void
3381 visium_print_operand_address (FILE *file, machine_mode mode, rtx addr)
3383 switch (GET_CODE (addr))
3385 case REG:
3386 case SUBREG:
3387 fprintf (file, "(%s)", reg_names[true_regnum (addr)]);
3388 break;
3390 case PLUS:
3392 rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
3394 switch (GET_CODE (x))
3396 case REG:
3397 case SUBREG:
3398 if (CONST_INT_P (y))
3400 unsigned int regno = true_regnum (x);
3401 HOST_WIDE_INT val = INTVAL (y);
3402 switch (mode)
3404 case E_SImode:
3405 case E_DImode:
3406 case E_SFmode:
3407 case E_DFmode:
3408 val >>= 2;
3409 break;
3411 case E_HImode:
3412 val >>= 1;
3413 break;
3415 case E_QImode:
3416 default:
3417 break;
3419 fprintf (file, HOST_WIDE_INT_PRINT_DEC"(%s)", val,
3420 reg_names[regno]);
3422 else
3423 fatal_insn ("illegal operand address (1)", addr);
3424 break;
3426 default:
3427 if (CONSTANT_P (x) && CONSTANT_P (y))
3428 output_addr_const (file, addr);
3429 else
3430 fatal_insn ("illegal operand address (2)", addr);
3431 break;
3434 break;
3436 case LABEL_REF:
3437 case SYMBOL_REF:
3438 case CONST_INT:
3439 case CONST:
3440 output_addr_const (file, addr);
3441 break;
3443 case NOTE:
3444 if (NOTE_KIND (addr) != NOTE_INSN_DELETED_LABEL)
3445 fatal_insn ("illegal operand address (3)", addr);
3446 break;
3448 case CODE_LABEL:
3449 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (addr));
3450 break;
3452 default:
3453 fatal_insn ("illegal operand address (4)", addr);
3454 break;
3458 /* The Visium stack frames look like:
3460 Before call After call
3461 +-----------------------+ +-----------------------+
3462 | | | |
3463 high | previous | | previous |
3464 mem | frame | | frame |
3465 | | | |
3466 +-----------------------+ +-----------------------+
3467 | | | |
3468 | arguments on stack | | arguments on stack |
3469 | | | |
3470 SP+0->+-----------------------+ +-----------------------+
3471 | reg parm save area, |
3472 | only created for |
3473 | variable argument |
3474 | functions |
3475 +-----------------------+
3477 | register save area |
3479 +-----------------------+
3481 | local variables |
3483 FP+8->+-----------------------+
3484 | return address |
3485 FP+4->+-----------------------+
3486 | previous FP |
3487 FP+0->+-----------------------+
3489 | alloca allocations |
3491 +-----------------------+
3493 low | arguments on stack |
3494 mem | |
3495 SP+0->+-----------------------+
3497 Notes:
3498 1) The "reg parm save area" does not exist for non variable argument fns.
3499 2) The FP register is not saved if `frame_pointer_needed' is zero and it
3500 is not altered in the current function.
3501 3) The return address is not saved if there is no frame pointer and the
3502 current function is leaf.
3503 4) If the return address is not saved and the static chain register is
3504 live in the function, we allocate the return address slot to be able
3505 to spill the register for a long branch. */
3507 /* Define the register classes for local purposes. */
3508 enum reg_type { general, mdb, mdc, floating, last_type};
3510 #define GET_REG_TYPE(regno) \
3511 (GP_REGISTER_P (regno) ? general : \
3512 (regno) == MDB_REGNUM ? mdb : \
3513 (regno) == MDC_REGNUM ? mdc : \
3514 floating)
3516 /* First regno of each register type. */
3517 const int first_regno[last_type] = {0, MDB_REGNUM, MDC_REGNUM, FP_FIRST_REGNUM};
3519 /* Size in bytes of each register type. */
3520 const int reg_type_size[last_type] = {4, 8, 4, 4};
3522 /* Structure to be filled in by visium_compute_frame_size. */
3523 struct visium_frame_info
3525 unsigned int save_area_size; /* # bytes in the reg parm save area. */
3526 unsigned int reg_size1; /* # bytes to store first block of regs. */
3527 unsigned int reg_size2; /* # bytes to store second block of regs. */
3528 unsigned int max_reg1; /* max. regno in first block */
3529 unsigned int var_size; /* # bytes that variables take up. */
3530 unsigned int save_fp; /* Nonzero if fp must be saved. */
3531 unsigned int save_lr; /* Nonzero if lr must be saved. */
3532 unsigned int lr_slot; /* Nonzero if the lr slot is needed. */
3533 unsigned int combine; /* Nonzero if we can combine the allocation of
3534 variables and regs. */
3535 unsigned int interrupt; /* Nonzero if the function is an interrupt
3536 handler. */
3537 unsigned int mask[last_type]; /* Masks of saved regs: gp, mdb, mdc, fp */
3540 /* Current frame information calculated by visium_compute_frame_size. */
3541 static struct visium_frame_info current_frame_info;
3543 /* Accessor for current_frame_info.save_fp. */
3545 static inline bool
3546 current_function_saves_fp (void)
3548 return current_frame_info.save_fp != 0;
3551 /* Accessor for current_frame_info.save_lr. */
3553 static inline bool
3554 current_function_saves_lr (void)
3556 return current_frame_info.save_lr != 0;
3559 /* Accessor for current_frame_info.lr_slot. */
3561 static inline bool
3562 current_function_has_lr_slot (void)
3564 return current_frame_info.lr_slot != 0;
3567 /* Return non-zero if register REGNO needs to be saved in the frame. */
3569 static int
3570 visium_save_reg_p (int interrupt, int regno)
3572 switch (regno)
3574 case HARD_FRAME_POINTER_REGNUM:
3575 /* This register is call-saved but handled specially. */
3576 return 0;
3578 case MDC_REGNUM:
3579 /* This register is fixed but can be modified. */
3580 break;
3582 case 29:
3583 case 30:
3584 /* These registers are fixed and hold the interrupt context. */
3585 return (interrupt != 0);
3587 default:
3588 /* The other fixed registers are either immutable or special. */
3589 if (fixed_regs[regno])
3590 return 0;
3591 break;
3594 if (interrupt)
3596 if (crtl->is_leaf)
3598 if (df_regs_ever_live_p (regno))
3599 return 1;
3601 else if (call_used_regs[regno])
3602 return 1;
3604 /* To save mdb requires two temporary registers. To save mdc or
3605 any of the floating registers requires one temporary
3606 register. If this is an interrupt routine, the temporary
3607 registers need to be saved as well. These temporary registers
3608 are call used, so we only need deal with the case of leaf
3609 functions here. */
3610 if (regno == PROLOGUE_TMP_REGNUM)
3612 if (df_regs_ever_live_p (MDB_REGNUM)
3613 || df_regs_ever_live_p (MDC_REGNUM))
3614 return 1;
3616 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
3617 if (df_regs_ever_live_p (i))
3618 return 1;
3621 else if (regno == PROLOGUE_TMP_REGNUM + 1)
3623 if (df_regs_ever_live_p (MDB_REGNUM))
3624 return 1;
3628 return df_regs_ever_live_p (regno) && !call_used_regs[regno];
3631 /* Compute the frame size required by the function. This function is called
3632 during the reload pass and also by visium_expand_prologue. */
3634 static int
3635 visium_compute_frame_size (int size)
3637 const int save_area_size = visium_reg_parm_save_area_size;
3638 const int var_size = VISIUM_STACK_ALIGN (size);
3639 const int save_fp
3640 = frame_pointer_needed || df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM);
3641 const int save_lr = frame_pointer_needed || !crtl->is_leaf;
3642 const int lr_slot = !save_lr && df_regs_ever_live_p (long_branch_regnum);
3643 const int local_frame_offset
3644 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3645 const int interrupt = visium_interrupt_function_p ();
3646 unsigned int mask[last_type];
3647 int reg_size1 = 0;
3648 int max_reg1 = 0;
3649 int reg_size2 = 0;
3650 int reg_size;
3651 int combine;
3652 int frame_size;
3653 int regno;
3655 memset (mask, 0, last_type * sizeof (unsigned int));
3657 /* The registers may need stacking in 2 blocks since only 32 32-bit words
3658 can be indexed from a given base address. */
3659 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3661 if (visium_save_reg_p (interrupt, regno))
3663 enum reg_type reg_type = GET_REG_TYPE (regno);
3664 int mask_bit = 1 << (regno - first_regno[reg_type]);
3665 int nbytes = reg_type_size[reg_type];
3667 if (reg_size1 + nbytes > 32 * UNITS_PER_WORD)
3668 break;
3670 reg_size1 += nbytes;
3671 max_reg1 = regno;
3672 mask[reg_type] |= mask_bit;
3676 for (regno = max_reg1 + 1; regno < FIRST_PSEUDO_REGISTER; regno++)
3678 if (visium_save_reg_p (interrupt, regno))
3680 enum reg_type reg_type = GET_REG_TYPE (regno);
3681 int mask_bit = 1 << (regno - first_regno[reg_type]);
3682 int nbytes = reg_type_size[reg_type];
3684 reg_size2 += nbytes;
3685 mask[reg_type] |= mask_bit;
3689 reg_size = reg_size2 ? reg_size2 : reg_size1;
3690 combine = (local_frame_offset + var_size + reg_size) <= 32 * UNITS_PER_WORD;
3691 frame_size
3692 = local_frame_offset + var_size + reg_size2 + reg_size1 + save_area_size;
3694 current_frame_info.save_area_size = save_area_size;
3695 current_frame_info.reg_size1 = reg_size1;
3696 current_frame_info.max_reg1 = max_reg1;
3697 current_frame_info.reg_size2 = reg_size2;
3698 current_frame_info.var_size = var_size;
3699 current_frame_info.save_fp = save_fp;
3700 current_frame_info.save_lr = save_lr;
3701 current_frame_info.lr_slot = lr_slot;
3702 current_frame_info.combine = combine;
3703 current_frame_info.interrupt = interrupt;
3705 memcpy (current_frame_info.mask, mask, last_type * sizeof (unsigned int));
3707 return frame_size;
3710 /* Helper function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define
3711 the offset between two registers, one to be eliminated, and the other its
3712 replacement, at the start of a routine. */
3715 visium_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
3717 const int save_fp = current_frame_info.save_fp;
3718 const int save_lr = current_frame_info.save_lr;
3719 const int lr_slot = current_frame_info.lr_slot;
3720 int offset;
3722 if (from == FRAME_POINTER_REGNUM)
3723 offset = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3724 else if (from == ARG_POINTER_REGNUM)
3725 offset = visium_compute_frame_size (get_frame_size ());
3726 else
3727 gcc_unreachable ();
3729 return offset;
3732 /* For an interrupt handler, we may be saving call-clobbered registers.
3733 Say the epilogue uses these in addition to the link register. */
3736 visium_epilogue_uses (int regno)
3738 if (regno == LINK_REGNUM)
3739 return 1;
3741 if (reload_completed)
3743 enum reg_type reg_type = GET_REG_TYPE (regno);
3744 int mask_bit = 1 << (regno - first_regno[reg_type]);
3746 return (current_frame_info.mask[reg_type] & mask_bit) != 0;
3749 return 0;
3752 /* Wrapper around emit_insn that sets RTX_FRAME_RELATED_P on the insn. */
3754 static rtx
3755 emit_frame_insn (rtx x)
3757 x = emit_insn (x);
3758 RTX_FRAME_RELATED_P (x) = 1;
3759 return x;
3762 /* Allocate ALLOC bytes on the stack and save the registers LOW_REGNO to
3763 HIGH_REGNO at OFFSET from the stack pointer. */
3765 static void
3766 visium_save_regs (int alloc, int offset, int low_regno, int high_regno)
3768 /* If this is an interrupt handler function, then mark the register
3769 stores as volatile. This will prevent the instruction scheduler
3770 from scrambling the order of register saves. */
3771 const int volatile_p = current_frame_info.interrupt;
3772 int regno;
3774 /* Allocate the stack space. */
3775 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, stack_pointer_rtx,
3776 GEN_INT (-alloc)));
3778 for (regno = low_regno; regno <= high_regno; regno++)
3780 enum reg_type reg_type = GET_REG_TYPE (regno);
3781 int mask_bit = 1 << (regno - first_regno[reg_type]);
3782 rtx insn;
3784 if (current_frame_info.mask[reg_type] & mask_bit)
3786 offset -= reg_type_size[reg_type];
3787 switch (reg_type)
3789 case general:
3791 rtx mem
3792 = gen_frame_mem (SImode,
3793 plus_constant (Pmode,
3794 stack_pointer_rtx, offset));
3795 MEM_VOLATILE_P (mem) = volatile_p;
3796 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, regno)));
3798 break;
3800 case mdb:
3802 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3803 rtx mem
3804 = gen_frame_mem (DImode,
3805 plus_constant (Pmode,
3806 stack_pointer_rtx, offset));
3807 rtx reg = gen_rtx_REG (DImode, regno);
3808 MEM_VOLATILE_P (mem) = volatile_p;
3809 emit_insn (gen_movdi (tmp, reg));
3810 /* Do not generate CFI if in interrupt handler. */
3811 if (volatile_p)
3812 emit_insn (gen_movdi (mem, tmp));
3813 else
3815 insn = emit_frame_insn (gen_movdi (mem, tmp));
3816 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3817 gen_rtx_SET (mem, reg));
3820 break;
3822 case mdc:
3824 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3825 rtx mem
3826 = gen_frame_mem (SImode,
3827 plus_constant (Pmode,
3828 stack_pointer_rtx, offset));
3829 rtx reg = gen_rtx_REG (SImode, regno);
3830 MEM_VOLATILE_P (mem) = volatile_p;
3831 emit_insn (gen_movsi (tmp, reg));
3832 insn = emit_frame_insn (gen_movsi (mem, tmp));
3833 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3834 gen_rtx_SET (mem, reg));
3836 break;
3838 case floating:
3840 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3841 rtx mem
3842 = gen_frame_mem (SFmode,
3843 plus_constant (Pmode,
3844 stack_pointer_rtx, offset));
3845 rtx reg = gen_rtx_REG (SFmode, regno);
3846 MEM_VOLATILE_P (mem) = volatile_p;
3847 emit_insn (gen_movsf (tmp, reg));
3848 insn = emit_frame_insn (gen_movsf (mem, tmp));
3849 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3850 gen_rtx_SET (mem, reg));
3852 break;
3854 default:
3855 break;
3861 /* This function generates the code for function entry. */
3863 void
3864 visium_expand_prologue (void)
3866 const int frame_size = visium_compute_frame_size (get_frame_size ());
3867 const int save_area_size = current_frame_info.save_area_size;
3868 const int reg_size1 = current_frame_info.reg_size1;
3869 const int max_reg1 = current_frame_info.max_reg1;
3870 const int reg_size2 = current_frame_info.reg_size2;
3871 const int var_size = current_frame_info.var_size;
3872 const int save_fp = current_frame_info.save_fp;
3873 const int save_lr = current_frame_info.save_lr;
3874 const int lr_slot = current_frame_info.lr_slot;
3875 const int local_frame_offset
3876 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3877 const int combine = current_frame_info.combine;
3878 int reg_size;
3879 int first_reg;
3880 int fsize;
3882 /* Save the frame size for future references. */
3883 visium_frame_size = frame_size;
3885 if (flag_stack_usage_info)
3886 current_function_static_stack_size = frame_size;
3888 /* If the registers have to be stacked in 2 blocks, stack the first one. */
3889 if (reg_size2)
3891 visium_save_regs (reg_size1 + save_area_size, reg_size1, 0, max_reg1);
3892 reg_size = reg_size2;
3893 first_reg = max_reg1 + 1;
3894 fsize = local_frame_offset + var_size + reg_size2;
3896 else
3898 reg_size = reg_size1;
3899 first_reg = 0;
3900 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
3903 /* If we can't combine register stacking with variable allocation, partially
3904 allocate and stack the (remaining) registers now. */
3905 if (reg_size && !combine)
3906 visium_save_regs (fsize - local_frame_offset - var_size, reg_size,
3907 first_reg, FIRST_PSEUDO_REGISTER - 1);
3909 /* If we can combine register stacking with variable allocation, fully
3910 allocate and stack the (remaining) registers now. */
3911 if (reg_size && combine)
3912 visium_save_regs (fsize, local_frame_offset + var_size + reg_size,
3913 first_reg, FIRST_PSEUDO_REGISTER - 1);
3915 /* Otherwise space may still need to be allocated for the variables. */
3916 else if (fsize)
3918 const int alloc_size = reg_size ? local_frame_offset + var_size : fsize;
3920 if (alloc_size > 65535)
3922 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM), insn;
3923 emit_insn (gen_movsi (tmp, GEN_INT (alloc_size)));
3924 insn = emit_frame_insn (gen_subsi3_flags (stack_pointer_rtx,
3925 stack_pointer_rtx,
3926 tmp));
3927 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3928 gen_rtx_SET (stack_pointer_rtx,
3929 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3930 GEN_INT (-alloc_size))));
3932 else
3933 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx,
3934 stack_pointer_rtx,
3935 GEN_INT (-alloc_size)));
3938 if (save_fp)
3939 emit_frame_insn (gen_movsi (gen_frame_mem (SImode, stack_pointer_rtx),
3940 hard_frame_pointer_rtx));
3942 if (frame_pointer_needed)
3943 emit_frame_insn (gen_stack_save ());
3945 if (save_lr)
3947 rtx base_rtx, mem;
3949 /* Normally the frame pointer and link register get saved via
3950 write.l (sp),fp
3951 move.l fp,sp
3952 write.l 1(sp),r21
3954 Indexing off sp rather than fp to store the link register
3955 avoids presenting the instruction scheduler with an initial
3956 pipeline hazard. If however the frame is needed for eg.
3957 __builtin_return_address which needs to retrieve the saved
3958 value of the link register from the stack at fp + 4 then
3959 indexing from sp can confuse the dataflow, causing the link
3960 register to be retrieved before it has been saved. */
3961 if (cfun->machine->frame_needed)
3962 base_rtx = hard_frame_pointer_rtx;
3963 else
3964 base_rtx = stack_pointer_rtx;
3966 mem = gen_frame_mem (SImode,
3967 plus_constant (Pmode,
3968 base_rtx, save_fp * UNITS_PER_WORD));
3969 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, LINK_REGNUM)));
3973 static GTY(()) rtx cfa_restores;
3975 /* Queue a REG_CFA_RESTORE note until next stack manipulation insn. */
3977 static void
3978 visium_add_cfa_restore_note (rtx reg)
3980 cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
3983 /* Add queued REG_CFA_RESTORE notes to INSN, if any. */
3985 static void
3986 visium_add_queued_cfa_restore_notes (rtx insn)
3988 rtx last;
3989 if (!cfa_restores)
3990 return;
3991 for (last = cfa_restores; XEXP (last, 1); last = XEXP (last, 1))
3993 XEXP (last, 1) = REG_NOTES (insn);
3994 REG_NOTES (insn) = cfa_restores;
3995 cfa_restores = NULL_RTX;
3998 /* Restore the registers LOW_REGNO to HIGH_REGNO from the save area at OFFSET
3999 from the stack pointer and pop DEALLOC bytes off the stack. */
4001 static void
4002 visium_restore_regs (int dealloc, int offset, int high_regno, int low_regno)
4004 /* If this is an interrupt handler function, then mark the register
4005 restores as volatile. This will prevent the instruction scheduler
4006 from scrambling the order of register restores. */
4007 const int volatile_p = current_frame_info.interrupt;
4008 int r30_offset = -1;
4009 int regno;
4011 for (regno = high_regno; regno >= low_regno; --regno)
4013 enum reg_type reg_type = GET_REG_TYPE (regno);
4014 int mask_bit = 1 << (regno - first_regno[reg_type]);
4016 if (current_frame_info.mask[reg_type] & mask_bit)
4018 switch (reg_type)
4020 case general:
4021 /* Postpone restoring the interrupted context registers
4022 until last, since they need to be preceded by a dsi. */
4023 if (regno == 29)
4025 else if (regno == 30)
4026 r30_offset = offset;
4027 else
4029 rtx mem
4030 = gen_frame_mem (SImode,
4031 plus_constant (Pmode,
4032 stack_pointer_rtx,
4033 offset));
4034 rtx reg = gen_rtx_REG (SImode, regno);
4035 MEM_VOLATILE_P (mem) = volatile_p;
4036 emit_insn (gen_movsi (reg, mem));
4037 visium_add_cfa_restore_note (reg);
4039 break;
4041 case mdb:
4043 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
4044 rtx mem
4045 = gen_frame_mem (DImode,
4046 plus_constant (Pmode,
4047 stack_pointer_rtx, offset));
4048 rtx reg = gen_rtx_REG (DImode, regno);
4049 MEM_VOLATILE_P (mem) = volatile_p;
4050 emit_insn (gen_movdi (tmp, mem));
4051 emit_insn (gen_movdi (reg, tmp));
4052 /* Do not generate CFI if in interrupt handler. */
4053 if (!volatile_p)
4054 visium_add_cfa_restore_note (reg);
4056 break;
4058 case mdc:
4060 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4061 rtx mem
4062 = gen_frame_mem (SImode,
4063 plus_constant (Pmode,
4064 stack_pointer_rtx, offset));
4065 rtx reg = gen_rtx_REG (SImode, regno);
4066 MEM_VOLATILE_P (mem) = volatile_p;
4067 emit_insn (gen_movsi (tmp, mem));
4068 emit_insn (gen_movsi (reg, tmp));
4069 visium_add_cfa_restore_note (reg);
4071 break;
4073 case floating:
4075 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
4076 rtx mem
4077 = gen_frame_mem (SFmode,
4078 plus_constant (Pmode,
4079 stack_pointer_rtx, offset));
4080 rtx reg = gen_rtx_REG (SFmode, regno);
4081 MEM_VOLATILE_P (mem) = volatile_p;
4082 emit_insn (gen_movsf (tmp, mem));
4083 emit_insn (gen_movsf (reg, tmp));
4084 visium_add_cfa_restore_note (reg);
4086 break;
4088 default:
4089 break;
4092 offset += reg_type_size[reg_type];
4096 /* If the interrupted context needs to be restored, precede the
4097 restores of r29 and r30 by a dsi. */
4098 if (r30_offset >= 0)
4100 emit_insn (gen_dsi ());
4101 emit_move_insn (gen_rtx_REG (SImode, 30),
4102 gen_frame_mem (SImode,
4103 plus_constant (Pmode,
4104 stack_pointer_rtx,
4105 r30_offset)));
4106 emit_move_insn (gen_rtx_REG (SImode, 29),
4107 gen_frame_mem (SImode,
4108 plus_constant (Pmode,
4109 stack_pointer_rtx,
4110 r30_offset + 4)));
4113 /* Deallocate the stack space. */
4114 rtx insn = emit_frame_insn (gen_stack_pop (GEN_INT (dealloc)));
4115 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4116 gen_rtx_SET (stack_pointer_rtx,
4117 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4118 GEN_INT (dealloc))));
4119 visium_add_queued_cfa_restore_notes (insn);
4122 /* This function generates the code for function exit. */
4124 void
4125 visium_expand_epilogue (void)
4127 const int save_area_size = current_frame_info.save_area_size;
4128 const int reg_size1 = current_frame_info.reg_size1;
4129 const int max_reg1 = current_frame_info.max_reg1;
4130 const int reg_size2 = current_frame_info.reg_size2;
4131 const int var_size = current_frame_info.var_size;
4132 const int restore_fp = current_frame_info.save_fp;
4133 const int restore_lr = current_frame_info.save_lr;
4134 const int lr_slot = current_frame_info.lr_slot;
4135 const int local_frame_offset
4136 = (restore_fp + restore_lr + lr_slot) * UNITS_PER_WORD;
4137 const int combine = current_frame_info.combine;
4138 int reg_size;
4139 int last_reg;
4140 int fsize;
4142 /* Do not bother restoring the stack pointer if it hasn't been changed in
4143 the function since it was saved _after_ the allocation of the frame. */
4144 if (!crtl->sp_is_unchanging)
4145 emit_insn (gen_stack_restore ());
4147 /* Restore the frame pointer if necessary. The usual code would be:
4149 move.l sp,fp
4150 read.l fp,(sp)
4152 but for the MCM this constitutes a stall/hazard so it is changed to:
4154 move.l sp,fp
4155 read.l fp,(fp)
4157 if the stack pointer has actually been restored. */
4158 if (restore_fp)
4160 rtx src;
4162 if (TARGET_MCM && !crtl->sp_is_unchanging)
4163 src = gen_frame_mem (SImode, hard_frame_pointer_rtx);
4164 else
4165 src = gen_frame_mem (SImode, stack_pointer_rtx);
4167 rtx insn = emit_frame_insn (gen_movsi (hard_frame_pointer_rtx, src));
4168 add_reg_note (insn, REG_CFA_ADJUST_CFA,
4169 gen_rtx_SET (stack_pointer_rtx,
4170 hard_frame_pointer_rtx));
4171 visium_add_cfa_restore_note (hard_frame_pointer_rtx);
4174 /* Restore the link register if necessary. */
4175 if (restore_lr)
4177 rtx mem = gen_frame_mem (SImode,
4178 plus_constant (Pmode,
4179 stack_pointer_rtx,
4180 restore_fp * UNITS_PER_WORD));
4181 rtx reg = gen_rtx_REG (SImode, LINK_REGNUM);
4182 emit_insn (gen_movsi (reg, mem));
4183 visium_add_cfa_restore_note (reg);
4186 /* If we have two blocks of registers, deal with the second one first. */
4187 if (reg_size2)
4189 reg_size = reg_size2;
4190 last_reg = max_reg1 + 1;
4191 fsize = local_frame_offset + var_size + reg_size2;
4193 else
4195 reg_size = reg_size1;
4196 last_reg = 0;
4197 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
4200 /* If the variable allocation could be combined with register stacking,
4201 restore the (remaining) registers and fully deallocate now. */
4202 if (reg_size && combine)
4203 visium_restore_regs (fsize, local_frame_offset + var_size,
4204 FIRST_PSEUDO_REGISTER - 1, last_reg);
4206 /* Otherwise deallocate the variables first. */
4207 else if (fsize)
4209 const int pop_size = reg_size ? local_frame_offset + var_size : fsize;
4210 rtx insn;
4212 if (pop_size > 65535)
4214 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4215 emit_move_insn (tmp, GEN_INT (pop_size));
4216 insn = emit_frame_insn (gen_stack_pop (tmp));
4218 else
4219 insn = emit_frame_insn (gen_stack_pop (GEN_INT (pop_size)));
4220 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4221 gen_rtx_SET (stack_pointer_rtx,
4222 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4223 GEN_INT (pop_size))));
4224 visium_add_queued_cfa_restore_notes (insn);
4227 /* If the variable allocation couldn't be combined with register stacking,
4228 restore the (remaining) registers now and partially deallocate. */
4229 if (reg_size && !combine)
4230 visium_restore_regs (fsize - local_frame_offset - var_size, 0,
4231 FIRST_PSEUDO_REGISTER - 1, last_reg);
4233 /* If the first block of registers has yet to be restored, do it now. */
4234 if (reg_size2)
4235 visium_restore_regs (reg_size1 + save_area_size, 0, max_reg1, 0);
4237 /* If this is an exception return, make the necessary stack adjustment. */
4238 if (crtl->calls_eh_return)
4239 emit_insn (gen_stack_pop (EH_RETURN_STACKADJ_RTX));
4242 /* Return true if it is appropriate to emit `return' instructions in the
4243 body of a function. */
4245 bool
4246 visium_can_use_return_insn_p (void)
4248 return reload_completed
4249 && visium_frame_size == 0
4250 && !visium_interrupt_function_p ();
4253 /* Return the register class required for an intermediate register used to
4254 copy a register of RCLASS from/to X. If no such intermediate register is
4255 required, return NO_REGS. If more than one such intermediate register is
4256 required, describe the one that is closest in the copy chain to the reload
4257 register. */
4259 static reg_class_t
4260 visium_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
4261 reg_class_t rclass,
4262 machine_mode mode ATTRIBUTE_UNUSED,
4263 secondary_reload_info *sri ATTRIBUTE_UNUSED)
4265 int regno = true_regnum (x);
4267 /* For MDB, MDC and FP_REGS, a general register is needed for a move to
4268 or from memory. */
4269 if (regno == -1 && (rclass == MDB || rclass == MDC || rclass == FP_REGS))
4270 return GENERAL_REGS;
4272 /* Moves between MDB, MDC and FP_REGS also require a general register. */
4273 else if (((regno == R_MDB || regno == R_MDC) && rclass == FP_REGS)
4274 || (FP_REGISTER_P (regno) && (rclass == MDB || rclass == MDC)))
4275 return GENERAL_REGS;
4277 /* Finally an (unlikely ?) move between MDB and MDC needs a general reg. */
4278 else if ((regno == R_MDB && rclass == MDC)
4279 || (rclass == MDB && regno == R_MDC))
4280 return GENERAL_REGS;
4282 return NO_REGS;
4285 /* Return true if pseudos that have been assigned to registers of RCLASS
4286 would likely be spilled because registers of RCLASS are needed for
4287 spill registers. */
4289 static bool
4290 visium_class_likely_spilled_p (reg_class_t rclass ATTRIBUTE_UNUSED)
4292 /* Return false for classes R1, R2 and R3, which are intended to be used
4293 only in the source code in conjunction with block move instructions. */
4294 return false;
4297 /* Return the register number if OP is a REG or a SUBREG of a REG, and
4298 INVALID_REGNUM in all the other cases. */
4300 unsigned int
4301 reg_or_subreg_regno (rtx op)
4303 unsigned int regno;
4305 if (GET_CODE (op) == REG)
4306 regno = REGNO (op);
4307 else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
4309 if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
4310 regno = subreg_regno (op);
4311 else
4312 regno = REGNO (SUBREG_REG (op));
4314 else
4315 regno = INVALID_REGNUM;
4317 return regno;
4320 /* Implement TARGET_CAN_CHANGE_MODE_CLASS.
4322 It's not obvious from the documentation of the hook that MDB cannot
4323 change mode. However difficulties arise from expressions of the form
4325 (subreg:SI (reg:DI R_MDB) 0)
4327 There is no way to convert that reference to a single machine
4328 register and, without the following definition, reload will quietly
4329 convert it to
4331 (reg:SI R_MDB). */
4333 static bool
4334 visium_can_change_mode_class (machine_mode from, machine_mode to,
4335 reg_class_t rclass)
4337 return (rclass != MDB || GET_MODE_SIZE (from) == GET_MODE_SIZE (to));
4340 #include "gt-visium.h"