gcc/
[official-gcc.git] / gcc / config / visium / visium.c
blobbac91acc145e75871147363b018b4ff3cd438bc9
1 /* Output routines for Visium.
2 Copyright (C) 2002-2015 Free Software Foundation, Inc.
3 Contributed by C.Nettleton, J.P.Parkes and P.Garbett.
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 "tm.h"
25 #include "hashtab.h"
26 #include "hash-set.h"
27 #include "machmode.h"
28 #include "input.h"
29 #include "statistics.h"
30 #include "vec.h"
31 #include "double-int.h"
32 #include "real.h"
33 #include "fixed-value.h"
34 #include "alias.h"
35 #include "flags.h"
36 #include "symtab.h"
37 #include "tree-core.h"
38 #include "wide-int.h"
39 #include "inchash.h"
40 #include "fold-const.h"
41 #include "tree-check.h"
42 #include "tree.h"
43 #include "stringpool.h"
44 #include "stor-layout.h"
45 #include "calls.h"
46 #include "varasm.h"
47 #include "rtl.h"
48 #include "regs.h"
49 #include "hard-reg-set.h"
50 #include "insn-config.h"
51 #include "conditions.h"
52 #include "output.h"
53 #include "insn-attr.h"
54 #include "function.h"
55 #include "expmed.h"
56 #include "dojump.h"
57 #include "explow.h"
58 #include "emit-rtl.h"
59 #include "stmt.h"
60 #include "expr.h"
61 #include "recog.h"
62 #include "diagnostic-core.h"
63 #include "tm_p.h"
64 #include "ggc.h"
65 #include "optabs.h"
66 #include "target.h"
67 #include "target-def.h"
68 #include "common/common-target.h"
69 #include "predict.h"
70 #include "basic-block.h"
71 #include "gimple-expr.h"
72 #include "gimplify.h"
73 #include "langhooks.h"
74 #include "reload.h"
75 #include "tm-constrs.h"
76 #include "df.h"
77 #include "params.h"
78 #include "errors.h"
79 #include "tree-pass.h"
80 #include "context.h"
81 #include "builtins.h"
83 /* Machine specific function data. */
84 struct GTY (()) machine_function
86 /* Size of the frame of the function. */
87 int frame_size;
89 /* Size of the reg parm save area, non-zero only for functions with variable
90 argument list. We cannot use the crtl->args.pretend_args_size machinery
91 for this purpose because this size is added to virtual_incoming_args_rtx
92 to give the location of the first parameter passed by the caller on the
93 stack and virtual_incoming_args_rtx is also the location of the first
94 parameter on the stack. So crtl->args.pretend_args_size can be non-zero
95 only if the first non-register named parameter is not passed entirely on
96 the stack and this runs afoul of the need to have a reg parm save area
97 even with a variable argument list starting on the stack because of the
98 separate handling of general and floating-point registers. */
99 int reg_parm_save_area_size;
101 /* True if we have created an rtx which relies on the frame pointer. */
102 bool frame_needed;
104 /* True if we have exposed the flags register. From this moment on, we
105 cannot generate simple operations for integer registers. We could
106 use reload_completed for this purpose, but this would cripple the
107 postreload CSE and GCSE passes which run before postreload split. */
108 bool flags_exposed;
111 #define visium_frame_size cfun->machine->frame_size
112 #define visium_reg_parm_save_area_size cfun->machine->reg_parm_save_area_size
113 #define visium_frame_needed cfun->machine->frame_needed
114 #define visium_flags_exposed cfun->machine->flags_exposed
116 /* 1 if the next opcode is to be specially indented. */
117 int visium_indent_opcode = 0;
119 /* Register number used for long branches when LR isn't available. It
120 must be a call-used register since it isn't saved on function entry.
121 We do not care whether the branch is predicted or not on the GR6,
122 given how unlikely it is to have a long branch in a leaf function. */
123 static unsigned int long_branch_regnum = 31;
125 static void visium_output_address (FILE *, enum machine_mode, rtx);
126 static tree visium_handle_interrupt_attr (tree *, tree, tree, int, bool *);
127 static inline bool current_function_saves_fp (void);
128 static inline bool current_function_saves_lr (void);
129 static inline bool current_function_has_lr_slot (void);
131 /* Supported attributes:
132 interrupt -- specifies this function is an interrupt handler. */
133 static const struct attribute_spec visium_attribute_table[] =
135 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
136 affects_type_identity } */
137 {"interrupt", 0, 0, true, false, false, visium_handle_interrupt_attr, false},
138 {NULL, 0, 0, false, false, false, NULL, false}
141 static struct machine_function *visium_init_machine_status (void);
143 /* Target hooks and TARGET_INITIALIZER */
145 static bool visium_pass_by_reference (cumulative_args_t, enum machine_mode,
146 const_tree, bool);
148 static rtx visium_function_arg (cumulative_args_t, enum machine_mode,
149 const_tree, bool);
151 static void visium_function_arg_advance (cumulative_args_t, enum machine_mode,
152 const_tree, bool);
154 static bool visium_return_in_memory (const_tree, const_tree fntype);
156 static rtx visium_function_value (const_tree, const_tree fn_decl_or_type,
157 bool);
159 static rtx visium_libcall_value (enum machine_mode, const_rtx);
161 static void visium_setup_incoming_varargs (cumulative_args_t,
162 enum machine_mode,
163 tree, int *, int);
165 static void visium_va_start (tree valist, rtx nextarg);
167 static tree visium_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
169 static bool visium_function_ok_for_sibcall (tree, tree);
171 static bool visium_frame_pointer_required (void);
173 static tree visium_build_builtin_va_list (void);
175 static tree visium_md_asm_clobbers (tree, tree, tree);
177 static bool visium_legitimate_constant_p (enum machine_mode, rtx);
179 static bool visium_legitimate_address_p (enum machine_mode, rtx, bool);
181 static void visium_conditional_register_usage (void);
183 static rtx visium_legitimize_address (rtx, rtx, enum machine_mode);
185 static reg_class_t visium_secondary_reload (bool, rtx, reg_class_t,
186 enum machine_mode,
187 secondary_reload_info *);
189 static bool visium_class_likely_spilled_p (reg_class_t);
191 static void visium_trampoline_init (rtx, tree, rtx);
193 static int visium_issue_rate (void);
195 static int visium_adjust_priority (rtx_insn *, int);
197 static int visium_adjust_cost (rtx_insn *, rtx, rtx_insn *, int);
199 static int visium_register_move_cost (enum machine_mode, reg_class_t,
200 reg_class_t);
202 static int visium_memory_move_cost (enum machine_mode, reg_class_t, bool);
204 static bool visium_rtx_costs (rtx, int, int, int, int *, bool);
206 static void visium_option_override (void);
208 static unsigned int visium_reorg (void);
210 /* Setup the global target hooks structure. */
212 #undef TARGET_MAX_ANCHOR_OFFSET
213 #define TARGET_MAX_ANCHOR_OFFSET 31
215 #undef TARGET_PASS_BY_REFERENCE
216 #define TARGET_PASS_BY_REFERENCE visium_pass_by_reference
218 #undef TARGET_FUNCTION_ARG
219 #define TARGET_FUNCTION_ARG visium_function_arg
221 #undef TARGET_FUNCTION_ARG_ADVANCE
222 #define TARGET_FUNCTION_ARG_ADVANCE visium_function_arg_advance
224 #undef TARGET_RETURN_IN_MEMORY
225 #define TARGET_RETURN_IN_MEMORY visium_return_in_memory
227 #undef TARGET_FUNCTION_VALUE
228 #define TARGET_FUNCTION_VALUE visium_function_value
230 #undef TARGET_LIBCALL_VALUE
231 #define TARGET_LIBCALL_VALUE visium_libcall_value
233 #undef TARGET_SETUP_INCOMING_VARARGS
234 #define TARGET_SETUP_INCOMING_VARARGS visium_setup_incoming_varargs
236 #undef TARGET_EXPAND_BUILTIN_VA_START
237 #define TARGET_EXPAND_BUILTIN_VA_START visium_va_start
239 #undef TARGET_BUILD_BUILTIN_VA_LIST
240 #define TARGET_BUILD_BUILTIN_VA_LIST visium_build_builtin_va_list
242 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
243 #define TARGET_GIMPLIFY_VA_ARG_EXPR visium_gimplify_va_arg
245 #undef TARGET_LEGITIMATE_CONSTANT_P
246 #define TARGET_LEGITIMATE_CONSTANT_P visium_legitimate_constant_p
248 #undef TARGET_LEGITIMATE_ADDRESS_P
249 #define TARGET_LEGITIMATE_ADDRESS_P visium_legitimate_address_p
251 #undef TARGET_ATTRIBUTE_TABLE
252 #define TARGET_ATTRIBUTE_TABLE visium_attribute_table
254 #undef TARGET_ADDRESS_COST
255 #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
257 #undef TARGET_STRICT_ARGUMENT_NAMING
258 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
260 #undef TARGET_SCHED_ISSUE_RATE
261 #define TARGET_SCHED_ISSUE_RATE visium_issue_rate
263 #undef TARGET_SCHED_ADJUST_PRIORITY
264 #define TARGET_SCHED_ADJUST_PRIORITY visium_adjust_priority
266 #undef TARGET_SCHED_ADJUST_COST
267 #define TARGET_SCHED_ADJUST_COST visium_adjust_cost
269 #undef TARGET_MEMORY_MOVE_COST
270 #define TARGET_MEMORY_MOVE_COST visium_memory_move_cost
272 #undef TARGET_REGISTER_MOVE_COST
273 #define TARGET_REGISTER_MOVE_COST visium_register_move_cost
275 #undef TARGET_RTX_COSTS
276 #define TARGET_RTX_COSTS visium_rtx_costs
278 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
279 #define TARGET_FUNCTION_OK_FOR_SIBCALL visium_function_ok_for_sibcall
281 #undef TARGET_FRAME_POINTER_REQUIRED
282 #define TARGET_FRAME_POINTER_REQUIRED visium_frame_pointer_required
284 #undef TARGET_SECONDARY_RELOAD
285 #define TARGET_SECONDARY_RELOAD visium_secondary_reload
287 #undef TARGET_CLASS_LIKELY_SPILLED_P
288 #define TARGET_CLASS_LIKELY_SPILLED_P visium_class_likely_spilled_p
290 #undef TARGET_LEGITIMIZE_ADDRESS
291 #define TARGET_LEGITIMIZE_ADDRESS visium_legitimize_address
293 #undef TARGET_OPTION_OVERRIDE
294 #define TARGET_OPTION_OVERRIDE visium_option_override
296 #undef TARGET_CONDITIONAL_REGISTER_USAGE
297 #define TARGET_CONDITIONAL_REGISTER_USAGE visium_conditional_register_usage
299 #undef TARGET_TRAMPOLINE_INIT
300 #define TARGET_TRAMPOLINE_INIT visium_trampoline_init
302 #undef TARGET_MD_ASM_CLOBBERS
303 #define TARGET_MD_ASM_CLOBBERS visium_md_asm_clobbers
305 #undef TARGET_FLAGS_REGNUM
306 #define TARGET_FLAGS_REGNUM FLAGS_REGNUM
308 struct gcc_target targetm = TARGET_INITIALIZER;
310 namespace {
312 const pass_data pass_data_visium_reorg =
314 RTL_PASS, /* type */
315 "mach2", /* name */
316 OPTGROUP_NONE, /* optinfo_flags */
317 TV_MACH_DEP, /* tv_id */
318 0, /* properties_required */
319 0, /* properties_provided */
320 0, /* properties_destroyed */
321 0, /* todo_flags_start */
322 0, /* todo_flags_finish */
325 class pass_visium_reorg : public rtl_opt_pass
327 public:
328 pass_visium_reorg(gcc::context *ctxt)
329 : rtl_opt_pass(pass_data_visium_reorg, ctxt)
332 /* opt_pass methods: */
333 virtual unsigned int execute (function *)
335 return visium_reorg ();
338 }; // class pass_work_around_errata
340 } // anon namespace
342 rtl_opt_pass *
343 make_pass_visium_reorg (gcc::context *ctxt)
345 return new pass_visium_reorg (ctxt);
348 /* Options override for Visium. */
350 static void
351 visium_option_override (void)
353 if (flag_pic == 1)
354 warning (OPT_fpic, "-fpic is not supported");
355 if (flag_pic == 2)
356 warning (OPT_fPIC, "-fPIC is not supported");
358 /* MCM is the default in the GR5/GR6 era. */
359 target_flags |= MASK_MCM;
361 /* FPU is the default with MCM, but don't override an explicit option. */
362 if ((target_flags_explicit & MASK_FPU) == 0)
363 target_flags |= MASK_FPU;
365 /* The supervisor mode is the default. */
366 if ((target_flags_explicit & MASK_SV_MODE) == 0)
367 target_flags |= MASK_SV_MODE;
369 /* The GR6 has the Block Move Instructions and an IEEE-compliant FPU. */
370 if (visium_cpu_and_features == PROCESSOR_GR6)
372 target_flags |= MASK_BMI;
373 if (target_flags & MASK_FPU)
374 target_flags |= MASK_FPU_IEEE;
377 /* Set -mtune from -mcpu if not specified. */
378 if (!global_options_set.x_visium_cpu)
379 visium_cpu = visium_cpu_and_features;
381 /* Align functions on 256-byte (32-quadword) for GR5 and 64-byte (8-quadword)
382 boundaries for GR6 so they start a new burst mode window. */
383 if (align_functions == 0)
385 if (visium_cpu == PROCESSOR_GR6)
386 align_functions = 64;
387 else
388 align_functions = 256;
390 /* Allow the size of compilation units to double because of inlining.
391 In practice the global size of the object code is hardly affected
392 because the additional instructions will take up the padding. */
393 maybe_set_param_value (PARAM_INLINE_UNIT_GROWTH, 100,
394 global_options.x_param_values,
395 global_options_set.x_param_values);
398 /* Likewise for loops. */
399 if (align_loops == 0)
401 if (visium_cpu == PROCESSOR_GR6)
402 align_loops = 64;
403 else
405 align_loops = 256;
406 /* But not if they are too far away from a 256-byte boundary. */
407 align_loops_max_skip = 31;
411 /* Align all jumps on quadword boundaries for the burst mode, and even
412 on 8-quadword boundaries for GR6 so they start a new window. */
413 if (align_jumps == 0)
415 if (visium_cpu == PROCESSOR_GR6)
416 align_jumps = 64;
417 else
418 align_jumps = 8;
421 /* We register a machine-specific pass. This pass must be scheduled as
422 late as possible so that we have the (essentially) final form of the
423 insn stream to work on. Registering the pass must be done at start up.
424 It's convenient to do it here. */
425 opt_pass *visium_reorg_pass = make_pass_visium_reorg (g);
426 struct register_pass_info insert_pass_visium_reorg =
428 visium_reorg_pass, /* pass */
429 "dbr", /* reference_pass_name */
430 1, /* ref_pass_instance_number */
431 PASS_POS_INSERT_AFTER /* po_op */
433 register_pass (&insert_pass_visium_reorg);
436 /* Return the number of instructions that can issue on the same cycle. */
438 static int
439 visium_issue_rate (void)
441 switch (visium_cpu)
443 case PROCESSOR_GR5:
444 return 1;
446 case PROCESSOR_GR6:
447 return 2;
449 default:
450 gcc_unreachable ();
454 /* Return the adjusted PRIORITY of INSN. */
456 static int
457 visium_adjust_priority (rtx_insn *insn, int priority)
459 /* On the GR5, we slightly increase the priority of writes in order to avoid
460 scheduling a read on the next cycle. This is necessary in addition to the
461 associated insn reservation because there are no data dependencies.
462 We also slightly increase the priority of reads from ROM in order to group
463 them as much as possible. These reads are a bit problematic because they
464 conflict with the instruction fetches, i.e. the data and instruction buses
465 tread on each other's toes when they are executed. */
466 if (visium_cpu == PROCESSOR_GR5
467 && reload_completed
468 && INSN_P (insn)
469 && recog_memoized (insn) >= 0)
471 enum attr_type attr_type = get_attr_type (insn);
472 if (attr_type == TYPE_REG_MEM
473 || (attr_type == TYPE_MEM_REG
474 && MEM_READONLY_P (SET_SRC (PATTERN (insn)))))
475 return priority + 1;
478 return priority;
481 /* Adjust the cost of a scheduling dependency. Return the new cost of
482 a dependency LINK of INSN on DEP_INSN. COST is the current cost. */
484 static int
485 visium_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, int cost)
487 enum attr_type attr_type;
489 /* Don't adjust costs for true dependencies as they are described with
490 bypasses. But we make an exception for the first scheduling pass to
491 help the subsequent postreload compare elimination pass. */
492 if (REG_NOTE_KIND (link) == REG_DEP_TRUE)
494 if (!reload_completed
495 && recog_memoized (insn) >= 0
496 && get_attr_type (insn) == TYPE_CMP)
498 rtx pat = PATTERN (insn);
499 gcc_assert (GET_CODE (pat) == SET);
500 rtx src = SET_SRC (pat);
502 /* Only the branches can be modified by the postreload compare
503 elimination pass, not the cstores because they accept only
504 unsigned comparison operators and they are eliminated if
505 one of the operands is zero. */
506 if (GET_CODE (src) == IF_THEN_ELSE
507 && XEXP (XEXP (src, 0), 1) == const0_rtx
508 && recog_memoized (dep_insn) >= 0)
510 enum attr_type dep_attr_type = get_attr_type (dep_insn);
512 /* The logical instructions use CCmode and thus work with any
513 comparison operator, whereas the arithmetic instructions use
514 CC_NOOVmode and thus work with only a small subset. */
515 if (dep_attr_type == TYPE_LOGIC
516 || (dep_attr_type == TYPE_ARITH
517 && visium_noov_operator (XEXP (src, 0),
518 GET_MODE (XEXP (src, 0)))))
519 return 0;
523 return cost;
526 if (recog_memoized (insn) < 0)
527 return 0;
529 attr_type = get_attr_type (insn);
531 /* Anti dependency: DEP_INSN reads a register that INSN writes some
532 cycles later. */
533 if (REG_NOTE_KIND (link) == REG_DEP_ANTI)
535 /* On the GR5, the latency of FP instructions needs to be taken into
536 account for every dependency involving a write. */
537 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
539 /* INSN is FLOAD. */
540 rtx pat = PATTERN (insn);
541 rtx dep_pat = PATTERN (dep_insn);
543 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
544 /* If this happens, we have to extend this to schedule
545 optimally. Return 0 for now. */
546 return 0;
548 if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
550 if (recog_memoized (dep_insn) < 0)
551 return 0;
553 switch (get_attr_type (dep_insn))
555 case TYPE_FDIV:
556 case TYPE_FSQRT:
557 case TYPE_FTOI:
558 case TYPE_ITOF:
559 case TYPE_FP:
560 case TYPE_FMOVE:
561 /* A fload can't be issued until a preceding arithmetic
562 operation has finished if the target of the fload is
563 any of the sources (or destination) of the arithmetic
564 operation. Note that the latency may be (much)
565 greater than this if the preceding instruction
566 concerned is in a queue. */
567 return insn_default_latency (dep_insn);
569 default:
570 return 0;
575 /* On the GR6, we try to make sure that the link register is restored
576 sufficiently ahead of the return as to yield a correct prediction
577 from the branch predictor. By default there is no true dependency
578 but an anti dependency between them, so we simply reuse it. */
579 else if (attr_type == TYPE_RET && visium_cpu == PROCESSOR_GR6)
581 rtx dep_pat = PATTERN (dep_insn);
582 if (GET_CODE (dep_pat) == SET
583 && REG_P (SET_DEST (dep_pat))
584 && REGNO (SET_DEST (dep_pat)) == LINK_REGNUM)
585 return 8;
588 /* For other anti dependencies, the cost is 0. */
589 return 0;
592 /* Output dependency: DEP_INSN writes a register that INSN writes some
593 cycles later. */
594 else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
596 /* On the GR5, the latency of FP instructions needs to be taken into
597 account for every dependency involving a write. */
598 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
600 /* INSN is FLOAD. */
601 rtx pat = PATTERN (insn);
602 rtx dep_pat = PATTERN (dep_insn);
604 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
605 /* If this happens, we have to extend this to schedule
606 optimally. Return 0 for now. */
607 return 0;
609 if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat)))
611 if (recog_memoized (dep_insn) < 0)
612 return 0;
614 switch (get_attr_type (dep_insn))
616 case TYPE_FDIV:
617 case TYPE_FSQRT:
618 case TYPE_FTOI:
619 case TYPE_ITOF:
620 case TYPE_FP:
621 case TYPE_FMOVE:
622 /* A fload can't be issued until a preceding arithmetic
623 operation has finished if the target of the fload is
624 the destination of the arithmetic operation. Note that
625 the latency may be (much) greater than this if the
626 preceding instruction concerned is in a queue. */
627 return insn_default_latency (dep_insn);
629 default:
630 return 0;
635 /* For other output dependencies, the cost is 0. */
636 return 0;
639 return 0;
642 /* Handle an "interrupt_handler" attribute; arguments as in
643 struct attribute_spec.handler. */
645 static tree
646 visium_handle_interrupt_attr (tree *node, tree name,
647 tree args ATTRIBUTE_UNUSED,
648 int flags ATTRIBUTE_UNUSED,
649 bool *no_add_attrs)
651 if (TREE_CODE (*node) != FUNCTION_DECL)
653 warning (OPT_Wattributes, "%qE attribute only applies to functions",
654 name);
655 *no_add_attrs = true;
657 else if (!TARGET_SV_MODE)
659 error ("an interrupt handler cannot be compiled with -muser-mode");
660 *no_add_attrs = true;
663 return NULL_TREE;
666 /* Return non-zero if the current function is an interrupt function. */
669 visium_interrupt_function_p (void)
671 return
672 lookup_attribute ("interrupt",
673 DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
676 /* Conditionally modify the settings of the register file. */
678 static void
679 visium_conditional_register_usage (void)
681 /* If the supervisor mode is disabled, mask some general registers. */
682 if (!TARGET_SV_MODE)
684 if (visium_cpu_and_features == PROCESSOR_GR5)
686 fixed_regs[24] = call_used_regs[24] = 1;
687 fixed_regs[25] = call_used_regs[25] = 1;
688 fixed_regs[26] = call_used_regs[26] = 1;
689 fixed_regs[27] = call_used_regs[27] = 1;
690 fixed_regs[28] = call_used_regs[28] = 1;
691 call_really_used_regs[24] = 0;
692 call_really_used_regs[25] = 0;
693 call_really_used_regs[26] = 0;
694 call_really_used_regs[27] = 0;
695 call_really_used_regs[28] = 0;
698 fixed_regs[31] = call_used_regs[31] = 1;
699 call_really_used_regs[31] = 0;
701 /* We also need to change the long-branch register. */
702 if (visium_cpu_and_features == PROCESSOR_GR5)
703 long_branch_regnum = 20;
704 else
705 long_branch_regnum = 28;
708 /* If the FPU is disabled, mask the FP registers. */
709 if (!TARGET_FPU)
711 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
713 fixed_regs[i] = call_used_regs[i] = 1;
714 call_really_used_regs[i] = 0;
719 /* Prepend to CLOBBERS hard registers that are automatically clobbered for
720 an asm We do this for the FLAGS to maintain source compatibility with
721 the original cc0-based compiler. */
723 static tree
724 visium_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED,
725 tree inputs ATTRIBUTE_UNUSED,
726 tree clobbers)
728 const char *flags = reg_names[FLAGS_REGNUM];
729 return tree_cons (NULL_TREE, build_string (strlen (flags), flags), clobbers);
732 /* Return true if X is a legitimate constant for a MODE immediate operand.
733 X is guaranteed to satisfy the CONSTANT_P predicate. */
735 static bool
736 visium_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
737 rtx x ATTRIBUTE_UNUSED)
739 return true;
742 /* Compute the alignment for a variable. The alignment of an aggregate is
743 set to be at least that of a scalar less than or equal to it in size. */
745 unsigned int
746 visium_data_alignment (tree type, unsigned int align)
748 if (AGGREGATE_TYPE_P (type)
749 && TYPE_SIZE (type)
750 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && align < 32)
752 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 32)
753 return 32;
755 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 && align < 16)
756 return 16;
759 return align;
762 /* Helper function for HARD_REGNO_RENAME_OK (FROM, TO). Return non-zero if
763 it is OK to rename a hard register FROM to another hard register TO. */
766 visium_hard_regno_rename_ok (unsigned int from ATTRIBUTE_UNUSED,
767 unsigned int to)
769 /* If the function doesn't save LR, then the long-branch register will be
770 used for long branches so we need to know whether it is live before the
771 frame layout is computed. */
772 if (!current_function_saves_lr () && to == long_branch_regnum)
773 return 0;
775 /* Interrupt functions can only use registers that have already been
776 saved by the prologue, even if they would normally be call-clobbered. */
777 if (crtl->is_leaf
778 && !df_regs_ever_live_p (to)
779 && visium_interrupt_function_p ())
780 return 0;
782 return 1;
785 /* Return true if it is ok to do sibling call optimization for the specified
786 call expression EXP. DECL will be the called function, or NULL if this
787 is an indirect call. */
789 static bool
790 visium_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
791 tree exp ATTRIBUTE_UNUSED)
793 return !visium_interrupt_function_p ();
796 /* Prepare operands for a move define_expand in MODE. */
798 void
799 prepare_move_operands (rtx *operands, enum machine_mode mode)
801 /* If the output is not a register, the input must be. */
802 if (GET_CODE (operands[0]) == MEM && !reg_or_0_operand (operands[1], mode))
803 operands[1] = force_reg (mode, operands[1]);
806 /* Return true if the operands are valid for a simple move insn. */
808 bool
809 ok_for_simple_move_operands (rtx *operands, enum machine_mode mode)
811 /* One of the operands must be a register. */
812 if (!register_operand (operands[0], mode)
813 && !reg_or_0_operand (operands[1], mode))
814 return false;
816 /* Once the flags are exposed, no simple moves between integer registers. */
817 if (visium_flags_exposed
818 && gpc_reg_operand (operands[0], mode)
819 && gpc_reg_operand (operands[1], mode))
820 return false;
822 return true;
825 /* Return true if the operands are valid for a simple move strict insn. */
827 bool
828 ok_for_simple_move_strict_operands (rtx *operands, enum machine_mode mode)
830 /* Once the flags are exposed, no simple moves between integer registers.
831 Note that, in QImode only, a zero source counts as an integer register
832 since it will be emitted as r0. */
833 if (visium_flags_exposed
834 && gpc_reg_operand (operands[0], mode)
835 && (gpc_reg_operand (operands[1], mode)
836 || (mode == QImode && operands[1] == const0_rtx)))
837 return false;
839 return true;
842 /* Return true if the operands are valid for a simple arithmetic or logical
843 insn. */
845 bool
846 ok_for_simple_arith_logic_operands (rtx *, enum machine_mode)
848 /* Once the flags are exposed, no simple arithmetic or logical operations
849 between integer registers. */
850 return !visium_flags_exposed;
853 /* Return non-zero if a branch or call instruction will be emitting a nop
854 into its delay slot. */
857 empty_delay_slot (rtx_insn *insn)
859 rtx seq;
861 /* If no previous instruction (should not happen), return true. */
862 if (PREV_INSN (insn) == NULL)
863 return 1;
865 seq = NEXT_INSN (PREV_INSN (insn));
866 if (GET_CODE (PATTERN (seq)) == SEQUENCE)
867 return 0;
869 return 1;
872 /* Wrapper around single_set which returns the first SET of a pair if the
873 second SET is to the flags register. */
875 static rtx
876 single_set_and_flags (rtx_insn *insn)
878 if (multiple_sets (insn))
880 rtx pat = PATTERN (insn);
881 if (XVECLEN (pat, 0) == 2
882 && GET_CODE (XVECEXP (pat, 0, 1)) == SET
883 && REG_P (SET_DEST (XVECEXP (pat, 0, 1)))
884 && REGNO (SET_DEST (XVECEXP (pat, 0, 1))) == FLAGS_REGNUM)
885 return XVECEXP (pat, 0, 0);
888 return single_set (insn);
891 /* This is called with OUT_INSN an instruction setting a (base) register
892 and IN_INSN a read or a write. Return 1 if these instructions together
893 constitute a pipeline hazard.
895 On the original architecture, a pipeline data hazard occurs when the Dest
896 of one instruction becomes the SrcA for an immediately following READ or
897 WRITE instruction with a non-zero index (indexing occurs at the decode
898 stage and so a NOP must be inserted in-between for this to work).
900 An example is:
902 move.l r2,r1
903 read.l r4,10(r2)
905 On the MCM, the non-zero index condition is lifted but the hazard is
906 patched up by the hardware through the injection of wait states:
908 move.l r2,r1
909 read.l r4,(r2)
911 We nevertheless try to schedule instructions around this. */
914 gr5_hazard_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
916 rtx out_set, in_set, dest, memexpr;
917 unsigned int out_reg, in_reg;
919 /* A CALL is storage register class, but the link register is of no
920 interest here. */
921 if (GET_CODE (out_insn) == CALL_INSN)
922 return 0;
924 out_set = single_set_and_flags (out_insn);
925 dest = SET_DEST (out_set);
927 /* Should be no stall/hazard if OUT_INSN is MEM := ???. This only
928 occurs prior to reload. */
929 if (GET_CODE (dest) == MEM)
930 return 0;
932 if (GET_CODE (dest) == STRICT_LOW_PART)
933 dest = XEXP (dest, 0);
934 if (GET_CODE (dest) == SUBREG)
935 dest = SUBREG_REG (dest);
936 out_reg = REGNO (dest);
938 in_set = single_set_and_flags (in_insn);
940 /* If IN_INSN is MEM := MEM, it's the source that counts. */
941 if (GET_CODE (SET_SRC (in_set)) == MEM)
942 memexpr = XEXP (SET_SRC (in_set), 0);
943 else
944 memexpr = XEXP (SET_DEST (in_set), 0);
946 if (GET_CODE (memexpr) == PLUS)
948 memexpr = XEXP (memexpr, 0);
949 if (GET_CODE (memexpr) == SUBREG)
950 in_reg = REGNO (SUBREG_REG (memexpr));
951 else
952 in_reg = REGNO (memexpr);
954 if (in_reg == out_reg)
955 return 1;
957 else if (TARGET_MCM)
959 if (GET_CODE (memexpr) == STRICT_LOW_PART)
960 memexpr = XEXP (memexpr, 0);
961 if (GET_CODE (memexpr) == SUBREG)
962 memexpr = SUBREG_REG (memexpr);
963 in_reg = REGNO (memexpr);
965 if (in_reg == out_reg)
966 return 1;
969 return 0;
972 /* Return true if INSN is an empty asm instruction. */
974 static bool
975 empty_asm_p (rtx insn)
977 rtx body = PATTERN (insn);
978 const char *templ;
980 if (GET_CODE (body) == ASM_INPUT)
981 templ = XSTR (body, 0);
982 else if (asm_noperands (body) >= 0)
983 templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
984 else
985 templ = NULL;
987 return (templ && templ[0] == '\0');
990 /* Insert a NOP immediately before INSN wherever there is a pipeline hazard.
991 LAST_REG records the register set in the last insn and LAST_INSN_CALL
992 records whether the last insn was a call insn. */
994 static void
995 gr5_avoid_hazard (rtx_insn *insn, unsigned int *last_reg, bool *last_insn_call)
997 unsigned int dest_reg = 0;
998 rtx set;
1000 switch (GET_CODE (insn))
1002 case CALL_INSN:
1003 *last_reg = 0;
1004 *last_insn_call = true;
1005 return;
1007 case JUMP_INSN:
1008 /* If this is an empty asm, just skip it. */
1009 if (!empty_asm_p (insn))
1011 *last_reg = 0;
1012 *last_insn_call = false;
1014 return;
1016 case INSN:
1017 /* If this is an empty asm, just skip it. */
1018 if (empty_asm_p (insn))
1019 return;
1020 break;
1022 default:
1023 return;
1026 set = single_set_and_flags (insn);
1027 if (set != NULL_RTX)
1029 rtx dest = SET_DEST (set);
1030 const bool double_p = GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD;
1031 rtx memrtx = NULL;
1033 if (GET_CODE (SET_SRC (set)) == MEM)
1035 memrtx = XEXP (SET_SRC (set), 0);
1036 if (GET_CODE (dest) == STRICT_LOW_PART)
1037 dest = XEXP (dest, 0);
1038 if (REG_P (dest))
1039 dest_reg = REGNO (dest);
1041 /* If this is a DI or DF mode memory to register
1042 copy, then if rd = rs we get
1044 rs + 1 := 1[rs]
1045 rs := [rs]
1047 otherwise the order is
1049 rd := [rs]
1050 rd + 1 := 1[rs] */
1052 if (double_p)
1054 unsigned int base_reg;
1056 if (GET_CODE (memrtx) == PLUS)
1057 base_reg = REGNO (XEXP (memrtx, 0));
1058 else
1059 base_reg = REGNO (memrtx);
1061 if (dest_reg != base_reg)
1062 dest_reg++;
1066 else if (GET_CODE (dest) == MEM)
1067 memrtx = XEXP (dest, 0);
1069 else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC)
1071 if (GET_CODE (dest) == STRICT_LOW_PART
1072 ||GET_CODE (dest) == ZERO_EXTRACT)
1073 dest = XEXP (dest, 0);
1074 dest_reg = REGNO (dest);
1076 if (GET_CODE (SET_SRC (set)) == REG)
1078 unsigned int srcreg = REGNO (SET_SRC (set));
1080 /* Check for rs := rs, which will be deleted. */
1081 if (srcreg == dest_reg)
1082 return;
1084 /* In the case of a DI or DF mode move from register to
1085 register there is overlap if rd = rs + 1 in which case
1086 the order of the copies is reversed :
1088 rd + 1 := rs + 1;
1089 rd := rs */
1091 if (double_p && dest_reg != srcreg + 1)
1092 dest_reg++;
1096 /* If this is the delay slot of a call insn, any register it sets
1097 is not relevant. */
1098 if (*last_insn_call)
1099 dest_reg = 0;
1101 /* If the previous insn sets the value of a register, and this insn
1102 uses a base register, check for the pipeline hazard where it is
1103 the same register in each case. */
1104 if (*last_reg != 0 && memrtx != NULL_RTX)
1106 unsigned int reg = 0;
1108 /* Check for an index (original architecture). */
1109 if (GET_CODE (memrtx) == PLUS)
1110 reg = REGNO (XEXP (memrtx, 0));
1112 /* Check for an MCM target or rs := [rs], in DI or DF mode. */
1113 else if (TARGET_MCM || (double_p && REGNO (memrtx) == dest_reg))
1114 reg = REGNO (memrtx);
1116 /* Remove any pipeline hazard by inserting a NOP. */
1117 if (reg == *last_reg)
1119 if (dump_file)
1120 fprintf (dump_file,
1121 "inserting nop before insn %d\n", INSN_UID (insn));
1122 emit_insn_after (gen_hazard_nop (), prev_active_insn (insn));
1123 emit_insn_after (gen_blockage (), insn);
1127 *last_reg = dest_reg;
1130 *last_insn_call = false;
1133 /* Go through the instruction stream and insert nops where necessary to avoid
1134 pipeline hazards. There are two cases:
1136 1. On the original architecture, it is invalid to set the value of a
1137 (base) register and then use it in an address with a non-zero index
1138 in the next instruction.
1140 2. On the MCM, setting the value of a (base) register and then using
1141 it in address (including with zero index) in the next instruction
1142 will result in a pipeline stall of 3 cycles. */
1144 static void
1145 gr5_hazard_avoidance (void)
1147 unsigned int last_reg = 0;
1148 bool last_insn_call = false;
1149 rtx_insn *insn;
1151 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1152 if (INSN_P (insn))
1154 rtx pat = PATTERN (insn);
1156 if (GET_CODE (pat) == SEQUENCE)
1158 for (int i = 0; i < XVECLEN (pat, 0); i++)
1159 gr5_avoid_hazard (as_a <rtx_insn *> (XVECEXP (pat, 0, i)),
1160 &last_reg, &last_insn_call);
1163 else if (GET_CODE (insn) == CALL_INSN)
1165 /* This call is going to get a nop in its delay slot. */
1166 last_reg = 0;
1167 last_insn_call = false;
1170 else
1171 gr5_avoid_hazard (insn, &last_reg, &last_insn_call);
1174 else if (GET_CODE (insn) == BARRIER)
1175 last_reg = 0;
1178 /* Perform a target-specific pass over the instruction stream. The compiler
1179 will run it at all optimization levels, just after the point at which it
1180 normally does delayed-branch scheduling. */
1182 static unsigned int
1183 visium_reorg (void)
1185 if (visium_cpu == PROCESSOR_GR5)
1186 gr5_hazard_avoidance ();
1188 return 0;
1190 /* Return true if an argument must be passed by indirect reference. */
1192 static bool
1193 visium_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1194 enum machine_mode mode ATTRIBUTE_UNUSED,
1195 const_tree type,
1196 bool named ATTRIBUTE_UNUSED)
1198 return type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1201 /* Define how arguments are passed.
1203 A range of general registers and floating registers is available
1204 for passing arguments. When the class of registers which an
1205 argument would normally use is exhausted, that argument, is passed
1206 in the overflow region of the stack. No argument is split between
1207 registers and stack.
1209 Arguments of type float or _Complex float go in FP registers if FP
1210 hardware is available. If there is no FP hardware, arguments of
1211 type float go in general registers. All other arguments are passed
1212 in general registers. */
1214 static rtx
1215 visium_function_arg (cumulative_args_t pcum_v, enum machine_mode mode,
1216 const_tree type ATTRIBUTE_UNUSED,
1217 bool named ATTRIBUTE_UNUSED)
1219 int size;
1220 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1222 size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1223 if (mode == VOIDmode)
1224 return GEN_INT (0);
1226 /* Scalar or complex single precision floating point arguments are returned
1227 in floating registers. */
1228 if (TARGET_FPU
1229 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1230 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1231 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1232 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1234 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1235 return gen_rtx_REG (mode, FP_ARG_FIRST + ca->frcount);
1236 else
1237 return NULL_RTX;
1240 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1241 return gen_rtx_REG (mode, ca->grcount + GP_ARG_FIRST);
1243 return NULL_RTX;
1246 /* Update the summarizer variable pointed to by PCUM_V to advance past an
1247 argument in the argument list. The values MODE, TYPE and NAMED describe
1248 that argument. Once this is done, the variable CUM is suitable for
1249 analyzing the _following_ argument with visium_function_arg. */
1251 static void
1252 visium_function_arg_advance (cumulative_args_t pcum_v,
1253 enum machine_mode mode,
1254 const_tree type ATTRIBUTE_UNUSED,
1255 bool named)
1257 int size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1258 int stack_size = 0;
1259 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1261 /* Scalar or complex single precision floating point arguments are returned
1262 in floating registers. */
1263 if (TARGET_FPU
1264 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1265 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1266 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1267 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1269 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1270 ca->frcount += size;
1271 else
1273 stack_size = size;
1274 ca->frcount = MAX_ARGS_IN_FP_REGISTERS;
1277 else
1279 /* Everything else goes in a general register, if enough are
1280 available. */
1281 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1282 ca->grcount += size;
1283 else
1285 stack_size = size;
1286 ca->grcount = MAX_ARGS_IN_GP_REGISTERS;
1290 if (named)
1291 ca->stack_words += stack_size;
1294 /* Specify whether to return the return value in memory. */
1296 static bool
1297 visium_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1299 return (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1302 /* Define how scalar values are returned. */
1304 static rtx
1305 visium_function_value_1 (enum machine_mode mode)
1307 /* Scalar or complex single precision floating point values
1308 are returned in floating register f1. */
1309 if (TARGET_FPU
1310 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1311 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1312 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1313 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1314 return gen_rtx_REG (mode, FP_RETURN_REGNUM);
1316 /* All others are returned in r1. */
1317 return gen_rtx_REG (mode, RETURN_REGNUM);
1320 /* Return an RTX representing the place where a function returns or receives
1321 a value of data type RET_TYPE. */
1323 static rtx
1324 visium_function_value (const_tree ret_type,
1325 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1326 bool outgoing ATTRIBUTE_UNUSED)
1328 return visium_function_value_1 (TYPE_MODE (ret_type));
1331 /* Return an RTX representing the place where the library function result will
1332 be returned. */
1334 static rtx
1335 visium_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1337 return visium_function_value_1 (mode);
1340 /* Store the anonymous register arguments into the stack so that all the
1341 arguments appear to have been passed consecutively on the stack. */
1343 static void
1344 visium_setup_incoming_varargs (cumulative_args_t pcum_v,
1345 enum machine_mode mode,
1346 tree type,
1347 int *pretend_size ATTRIBUTE_UNUSED,
1348 int no_rtl)
1350 cumulative_args_t local_args_so_far;
1351 CUMULATIVE_ARGS local_copy;
1352 CUMULATIVE_ARGS *locargs;
1353 int gp_saved, fp_saved, size;
1355 /* Create an internal cumulative_args_t pointer to internally define
1356 storage to ensure calling TARGET_FUNCTION_ARG_ADVANCE does not
1357 make global changes. */
1358 local_args_so_far.p = &local_copy;
1359 locargs = get_cumulative_args (pcum_v);
1361 #ifdef ENABLE_CHECKING
1362 local_args_so_far.magic = CUMULATIVE_ARGS_MAGIC;
1363 #endif
1365 local_copy.grcount = locargs->grcount;
1366 local_copy.frcount = locargs->frcount;
1367 local_copy.stack_words = locargs->stack_words;
1369 /* The caller has advanced ARGS_SO_FAR up to, but not beyond, the last named
1370 argument. Advance a local copy of ARGS_SO_FAR past the last "real" named
1371 argument, to find out how many registers are left over. */
1372 TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, mode, type, 1);
1374 /* Find how many registers we need to save. */
1375 locargs = get_cumulative_args (local_args_so_far);
1376 gp_saved = MAX_ARGS_IN_GP_REGISTERS - locargs->grcount;
1377 fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - locargs->frcount : 0);
1378 size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_HWFPVALUE);
1380 if (!no_rtl && size > 0)
1382 /* To avoid negative offsets, which are not valid addressing modes on
1383 the Visium, we create a base register for the pretend args. */
1384 rtx ptr
1385 = force_reg (Pmode,
1386 plus_constant (Pmode, virtual_incoming_args_rtx, -size));
1388 if (gp_saved > 0)
1390 rtx mem
1391 = gen_rtx_MEM (BLKmode,
1392 plus_constant (Pmode,
1393 ptr,
1394 fp_saved * UNITS_PER_HWFPVALUE));
1395 MEM_NOTRAP_P (mem) = 1;
1396 set_mem_alias_set (mem, get_varargs_alias_set ());
1397 move_block_from_reg (locargs->grcount + GP_ARG_FIRST, mem, gp_saved);
1400 if (fp_saved > 0)
1402 rtx mem = gen_rtx_MEM (BLKmode, ptr);
1403 MEM_NOTRAP_P (mem) = 1;
1404 set_mem_alias_set (mem, get_varargs_alias_set ());
1405 gcc_assert (UNITS_PER_WORD == UNITS_PER_HWFPVALUE);
1406 move_block_from_reg (locargs->frcount + FP_ARG_FIRST, mem, fp_saved);
1410 visium_reg_parm_save_area_size = size;
1413 /* Define the `__builtin_va_list' type for the ABI. */
1415 static tree
1416 visium_build_builtin_va_list (void)
1418 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes, record;
1420 record = (*lang_hooks.types.make_type) (RECORD_TYPE);
1421 f_ovfl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1422 get_identifier ("__overflow_argptr"), ptr_type_node);
1423 f_gbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1424 get_identifier ("__gpr_base"), ptr_type_node);
1425 f_fbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1426 get_identifier ("__fpr_base"), ptr_type_node);
1427 f_gbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1428 get_identifier ("__gpr_bytes"),
1429 short_unsigned_type_node);
1430 f_fbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1431 get_identifier ("__fpr_bytes"),
1432 short_unsigned_type_node);
1434 DECL_FIELD_CONTEXT (f_ovfl) = record;
1435 DECL_FIELD_CONTEXT (f_gbase) = record;
1436 DECL_FIELD_CONTEXT (f_fbase) = record;
1437 DECL_FIELD_CONTEXT (f_gbytes) = record;
1438 DECL_FIELD_CONTEXT (f_fbytes) = record;
1439 TYPE_FIELDS (record) = f_ovfl;
1440 TREE_CHAIN (f_ovfl) = f_gbase;
1441 TREE_CHAIN (f_gbase) = f_fbase;
1442 TREE_CHAIN (f_fbase) = f_gbytes;
1443 TREE_CHAIN (f_gbytes) = f_fbytes;
1444 layout_type (record);
1446 return record;
1449 /* Implement `va_start' for varargs and stdarg. */
1451 static void
1452 visium_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
1454 const CUMULATIVE_ARGS *ca = &crtl->args.info;
1455 int gp_saved = MAX_ARGS_IN_GP_REGISTERS - ca->grcount;
1456 int fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - ca->frcount : 0);
1457 int named_stack_size = ca->stack_words * UNITS_PER_WORD, offset;
1458 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1459 tree ovfl, gbase, gbytes, fbase, fbytes, t;
1461 f_ovfl = TYPE_FIELDS (va_list_type_node);
1462 f_gbase = TREE_CHAIN (f_ovfl);
1463 f_fbase = TREE_CHAIN (f_gbase);
1464 f_gbytes = TREE_CHAIN (f_fbase);
1465 f_fbytes = TREE_CHAIN (f_gbytes);
1466 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1467 gbase = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1468 NULL_TREE);
1469 fbase = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1470 NULL_TREE);
1471 gbytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), valist, f_gbytes,
1472 NULL_TREE);
1473 fbytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), valist, f_fbytes,
1474 NULL_TREE);
1476 /* Store the stacked vararg pointer in the OVFL member. */
1477 t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
1478 t = fold_build_pointer_plus_hwi (t, named_stack_size);
1479 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
1480 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1482 /* Store the base address of the GPR save area into GBASE. */
1483 t = make_tree (TREE_TYPE (gbase), virtual_incoming_args_rtx);
1484 offset = MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD;
1485 t = fold_build_pointer_plus_hwi (t, -offset);
1486 t = build2 (MODIFY_EXPR, TREE_TYPE (gbase), gbase, t);
1487 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1489 /* Store the base address of the FPR save area into FBASE. */
1490 if (fp_saved)
1492 t = make_tree (TREE_TYPE (fbase), virtual_incoming_args_rtx);
1493 offset = gp_saved * UNITS_PER_WORD
1494 + MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE;
1495 t = fold_build_pointer_plus_hwi (t, -offset);
1496 t = build2 (MODIFY_EXPR, TREE_TYPE (fbase), fbase, t);
1497 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1500 /* Fill in the GBYTES member. */
1501 t = build2 (MODIFY_EXPR, TREE_TYPE (gbytes), gbytes,
1502 size_int (gp_saved * UNITS_PER_WORD));
1503 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1505 /* Fill in the FBYTES member. */
1506 t = build2 (MODIFY_EXPR, TREE_TYPE (fbytes),
1507 fbytes, size_int (fp_saved * UNITS_PER_HWFPVALUE));
1508 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1511 /* Implement `va_arg'. */
1513 static tree
1514 visium_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
1515 gimple_seq *post_p)
1517 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1518 tree ovfl, base, bytes;
1519 HOST_WIDE_INT size, rsize;
1520 const bool by_reference_p
1521 = pass_by_reference (NULL, TYPE_MODE (type), type, false);
1522 const bool float_reg_arg_p
1523 = (TARGET_FPU && !by_reference_p
1524 && ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
1525 && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_HWFPVALUE)
1526 || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT
1527 && (GET_MODE_SIZE (TYPE_MODE (type))
1528 <= UNITS_PER_HWFPVALUE * 2))));
1529 const int max_save_area_size
1530 = (float_reg_arg_p ? MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE
1531 : MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD);
1532 tree t, u, offs;
1533 tree lab_false, lab_over, addr;
1534 tree ptrtype = build_pointer_type (type);
1536 if (by_reference_p)
1538 t = visium_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
1539 return build_va_arg_indirect_ref (t);
1542 size = int_size_in_bytes (type);
1543 rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
1544 f_ovfl = TYPE_FIELDS (va_list_type_node);
1545 f_gbase = TREE_CHAIN (f_ovfl);
1546 f_fbase = TREE_CHAIN (f_gbase);
1547 f_gbytes = TREE_CHAIN (f_fbase);
1548 f_fbytes = TREE_CHAIN (f_gbytes);
1550 /* We maintain separate pointers and offsets for floating-point and
1551 general registers, but we need similar code in both cases.
1553 Let:
1555 BYTES be the number of unused bytes in the register save area.
1556 BASE be the base address of the register save area.
1557 OFFS be the current offset into the register save area. Either
1558 MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD - bytes or
1559 MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE - bytes
1560 depending upon whether the argument is in general or floating
1561 registers.
1562 ADDR_RTX be the address of the argument.
1563 RSIZE be the size in bytes of the argument.
1564 OVFL be the pointer to the stack overflow area.
1566 The code we want is:
1568 1: if (bytes >= rsize)
1569 2: {
1570 3: addr_rtx = base + offs;
1571 4: bytes -= rsize;
1572 5: }
1573 6: else
1574 7: {
1575 8: bytes = 0;
1576 9: addr_rtx = ovfl;
1577 10: ovfl += rsize;
1578 11: }
1582 addr = create_tmp_var (ptr_type_node, "addr");
1583 lab_false = create_artificial_label (UNKNOWN_LOCATION);
1584 lab_over = create_artificial_label (UNKNOWN_LOCATION);
1585 if (float_reg_arg_p)
1586 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), unshare_expr (valist),
1587 f_fbytes, NULL_TREE);
1588 else
1589 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), unshare_expr (valist),
1590 f_gbytes, NULL_TREE);
1592 /* [1] Emit code to branch if bytes < rsize. */
1593 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1594 t = build2 (LT_EXPR, boolean_type_node, bytes, t);
1595 u = build1 (GOTO_EXPR, void_type_node, lab_false);
1596 t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
1597 gimplify_and_add (t, pre_p);
1599 /* [3] Emit code for: addr_rtx = base + offs, where
1600 offs = max_save_area_size - bytes. */
1601 t = fold_convert (sizetype, bytes);
1602 offs = build2 (MINUS_EXPR, sizetype, size_int (max_save_area_size), t);
1603 if (float_reg_arg_p)
1604 base = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1605 NULL_TREE);
1606 else
1607 base = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1608 NULL_TREE);
1610 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, offs);
1611 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1612 gimplify_and_add (t, pre_p);
1614 /* [4] Emit code for: bytes -= rsize. */
1615 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1616 t = build2 (MINUS_EXPR, TREE_TYPE (bytes), bytes, t);
1617 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), bytes, t);
1618 gimplify_and_add (t, pre_p);
1620 /* [6] Emit code to branch over the else clause, then the label. */
1621 t = build1 (GOTO_EXPR, void_type_node, lab_over);
1622 gimplify_and_add (t, pre_p);
1623 t = build1 (LABEL_EXPR, void_type_node, lab_false);
1624 gimplify_and_add (t, pre_p);
1626 /* [8] Emit code for: bytes = 0. */
1627 t = fold_convert (TREE_TYPE (bytes), size_int (0));
1628 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), unshare_expr (bytes), t);
1629 gimplify_and_add (t, pre_p);
1631 /* [9] Emit code for: addr_rtx = ovfl. */
1632 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1633 t = build2 (MODIFY_EXPR, void_type_node, addr, ovfl);
1634 gimplify_and_add (t, pre_p);
1636 /* [10] Emit code for: ovfl += rsize. */
1637 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl), ovfl, size_int (rsize));
1638 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), unshare_expr (ovfl), t);
1639 gimplify_and_add (t, pre_p);
1640 t = build1 (LABEL_EXPR, void_type_node, lab_over);
1641 gimplify_and_add (t, pre_p);
1642 addr = fold_convert (ptrtype, addr);
1644 return build_va_arg_indirect_ref (addr);
1647 /* Return true if OP is an offset suitable for use as a displacement in the
1648 address of a memory access in mode MODE. */
1650 static bool
1651 rtx_ok_for_offset_p (enum machine_mode mode, rtx op)
1653 if (!CONST_INT_P (op) || INTVAL (op) < 0)
1654 return false;
1656 switch (mode)
1658 case QImode:
1659 return INTVAL (op) <= 31;
1661 case HImode:
1662 return (INTVAL (op) % 2) == 0 && INTVAL (op) < 63;
1664 case SImode:
1665 case SFmode:
1666 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 127;
1668 case DImode:
1669 case DFmode:
1670 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 123;
1672 default:
1673 return false;
1677 /* Return whether X is a legitimate memory address for a memory operand
1678 of mode MODE.
1680 Legitimate addresses are defined in two variants: a strict variant
1681 and a non-strict one. The STRICT parameter chooses which variant
1682 is desired by the caller.
1684 The strict variant is used in the reload pass. It must be defined
1685 so that any pseudo-register that has not been allocated a hard
1686 register is considered a memory reference. This is because in
1687 contexts where some kind of register is required, a
1688 pseudo-register with no hard register must be rejected. For
1689 non-hard registers, the strict variant should look up the
1690 `reg_renumber' array; it should then proceed using the hard
1691 register number in the array, or treat the pseudo as a memory
1692 reference if the array holds `-1'.
1694 The non-strict variant is used in other passes. It must be
1695 defined to accept all pseudo-registers in every context where some
1696 kind of register is required. */
1698 static bool
1699 visium_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
1701 rtx base;
1702 unsigned int regno;
1704 /* If X is base+disp, check that we have an appropriate offset. */
1705 if (GET_CODE (x) == PLUS)
1707 if (!rtx_ok_for_offset_p (mode, XEXP (x, 1)))
1708 return false;
1709 base = XEXP (x, 0);
1711 else
1712 base = x;
1714 /* Now check the base: it must be either a register or a subreg thereof. */
1715 if (GET_CODE (base) == SUBREG)
1716 base = SUBREG_REG (base);
1717 if (!REG_P (base))
1718 return false;
1720 regno = REGNO (base);
1722 /* For the strict variant, the register must be REGNO_OK_FOR_BASE_P. */
1723 if (strict)
1724 return REGNO_OK_FOR_BASE_P (regno);
1726 /* For the non-strict variant, the register may also be a pseudo. */
1727 return BASE_REGISTER_P (regno) || regno >= FIRST_PSEUDO_REGISTER;
1730 /* Try machine-dependent ways of modifying an illegitimate address
1731 to be legitimate. If we find one, return the new, valid address.
1732 This macro is used in only one place: `memory_address' in explow.c.
1734 OLDX is the address as it was before break_out_memory_refs was called.
1735 In some cases it is useful to look at this to decide what needs to be done.
1737 MODE and WIN are passed so that this macro can use
1738 GO_IF_LEGITIMATE_ADDRESS.
1740 It is always safe for this macro to do nothing. It exists to recognize
1741 opportunities to optimize the output.
1743 For Visium
1745 memory (reg + <out of range int>)
1747 is transformed to
1749 base_int = <out of range int> & ~mask
1750 ptr_reg = reg + base_int
1751 memory (ptr_reg + <out of range int> - base_int)
1753 Thus ptr_reg is a base register for a range of addresses,
1754 which should help CSE.
1756 For a 1 byte reference mask is 0x1f
1757 for a 2 byte reference mask is 0x3f
1758 For a 4 byte reference mask is 0x7f
1760 This reflects the indexing range of the processor.
1762 For a > 4 byte reference the mask is 0x7f provided all of the words
1763 can be accessed with the base address obtained. Otherwise a mask
1764 of 0x3f is used.
1766 On rare occasions an unaligned base register value with an
1767 unaligned offset is generated. Unaligned offsets are left alone for
1768 this reason. */
1770 static rtx
1771 visium_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1772 enum machine_mode mode)
1774 if (GET_CODE (x) == PLUS
1775 && GET_CODE (XEXP (x, 1)) == CONST_INT
1776 && GET_CODE (XEXP (x, 0)) == REG && mode != BLKmode)
1778 int offset = INTVAL (XEXP (x, 1));
1779 int size = GET_MODE_SIZE (mode);
1780 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1781 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1782 int offset_base = offset & ~mask;
1784 /* Check that all of the words can be accessed. */
1785 if (4 < size && 0x80 < size + offset - offset_base)
1786 offset_base = offset & ~0x3f;
1787 if (offset_base != 0 && offset_base != offset && (offset & mask1) == 0)
1789 rtx ptr_reg = force_reg (Pmode,
1790 gen_rtx_PLUS (Pmode,
1791 XEXP (x, 0),
1792 GEN_INT (offset_base)));
1794 return plus_constant (Pmode, ptr_reg, offset - offset_base);
1798 return x;
1801 /* Perform a similar function to visium_legitimize_address, but this time
1802 for reload. Generating new registers is not an option here. Parts
1803 that need reloading are indicated by calling push_reload. */
1806 visium_legitimize_reload_address (rtx x, enum machine_mode mode, int opnum,
1807 int type, int ind ATTRIBUTE_UNUSED)
1809 rtx newrtx, tem = NULL_RTX;
1811 if (mode == BLKmode)
1812 return NULL_RTX;
1814 if (optimize && GET_CODE (x) == PLUS)
1815 tem = simplify_binary_operation (PLUS, GET_MODE (x), XEXP (x, 0),
1816 XEXP (x, 1));
1818 newrtx = tem ? tem : x;
1819 if (GET_CODE (newrtx) == PLUS
1820 && GET_CODE (XEXP (newrtx, 1)) == CONST_INT
1821 && GET_CODE (XEXP (newrtx, 0)) == REG
1822 && BASE_REGISTER_P (REGNO (XEXP (newrtx, 0))))
1824 int offset = INTVAL (XEXP (newrtx, 1));
1825 int size = GET_MODE_SIZE (mode);
1826 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1827 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1828 int offset_base = offset & ~mask;
1830 /* Check that all of the words can be accessed. */
1831 if (4 < size && 0x80 < size + offset - offset_base)
1832 offset_base = offset & ~0x3f;
1834 if (offset_base && (offset & mask1) == 0)
1836 rtx temp = gen_rtx_PLUS (Pmode,
1837 XEXP (newrtx, 0), GEN_INT (offset_base));
1839 x = gen_rtx_PLUS (Pmode, temp, GEN_INT (offset - offset_base));
1840 push_reload (XEXP (x, 0), 0, &XEXP (x, 0), 0,
1841 BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum,
1842 (enum reload_type) type);
1843 return x;
1847 return NULL_RTX;
1850 /* Return the cost of moving data of mode MODE from a register in class FROM to
1851 one in class TO. A value of 2 is the default; other values are interpreted
1852 relative to that. */
1854 static int
1855 visium_register_move_cost (enum machine_mode mode, reg_class_t from,
1856 reg_class_t to)
1858 const int numwords = (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) ? 1 : 2;
1860 if (from == MDB || to == MDB)
1861 return 4;
1862 else if (from == MDC || to == MDC || (from == FP_REGS) != (to == FP_REGS))
1863 return 4 * numwords;
1864 else
1865 return 2 * numwords;
1868 /* Return the cost of moving data of mode MODE between a register of class
1869 CLASS and memory. IN is zero if the value is to be written to memory,
1870 non-zero if it is to be read in. This cost is relative to those in
1871 visium_register_move_cost. */
1873 static int
1874 visium_memory_move_cost (enum machine_mode mode,
1875 reg_class_t to ATTRIBUTE_UNUSED,
1876 bool in)
1878 /* Moving data in can be from PROM and this is expensive. */
1879 if (in)
1881 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
1882 return 7;
1883 else
1884 return 13;
1887 /* Moving data out is mostly to RAM and should be cheaper. */
1888 else
1890 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
1891 return 6;
1892 else
1893 return 12;
1897 /* Return the relative costs of expression X. */
1899 static bool
1900 visium_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
1901 int opno ATTRIBUTE_UNUSED, int *total,
1902 bool speed ATTRIBUTE_UNUSED)
1904 enum machine_mode mode = GET_MODE (x);
1906 switch (code)
1908 case CONST_INT:
1909 /* Small integers are as cheap as registers. 4-byte values can
1910 be fetched as immediate constants - let's give that the cost
1911 of an extra insn. */
1912 *total = COSTS_N_INSNS (!satisfies_constraint_J (x));
1913 return true;
1915 case CONST:
1916 case LABEL_REF:
1917 case SYMBOL_REF:
1918 *total = COSTS_N_INSNS (2);
1919 return true;
1921 case CONST_DOUBLE:
1923 rtx high, low;
1924 split_double (x, &high, &low);
1925 *total =
1926 COSTS_N_INSNS
1927 (!satisfies_constraint_J (high) + !satisfies_constraint_J (low));
1928 return true;
1931 case MULT:
1932 *total = COSTS_N_INSNS (3);
1933 return false;
1935 case DIV:
1936 case UDIV:
1937 case MOD:
1938 case UMOD:
1939 if (mode == DImode)
1940 *total = COSTS_N_INSNS (64);
1941 else
1942 *total = COSTS_N_INSNS (32);
1943 return false;
1945 case PLUS:
1946 case MINUS:
1947 case NEG:
1948 /* DImode operations are performed directly on the ALU. */
1949 if (mode == DImode)
1950 *total = COSTS_N_INSNS (2);
1951 else
1952 *total = COSTS_N_INSNS (1);
1953 return false;
1955 case ASHIFT:
1956 case ASHIFTRT:
1957 case LSHIFTRT:
1958 /* DImode operations are performed on the EAM instead. */
1959 if (mode == DImode)
1960 *total = COSTS_N_INSNS (3);
1961 else
1962 *total = COSTS_N_INSNS (1);
1963 return false;
1965 case COMPARE:
1966 /* This matches the btst pattern. */
1967 if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT
1968 && XEXP (x, 1) == const0_rtx
1969 && XEXP (XEXP (x, 0), 1) == const1_rtx
1970 && satisfies_constraint_K (XEXP (XEXP (x, 0), 2)))
1971 *total = COSTS_N_INSNS (1);
1972 return false;
1974 default:
1975 return false;
1979 /* Split a double move of OPERANDS in MODE. */
1981 void
1982 split_double_move (rtx *operands, enum machine_mode mode)
1984 bool swap = false;
1986 /* Check register to register with overlap. */
1987 if (GET_CODE (operands[0]) == REG
1988 && GET_CODE (operands[1]) == REG
1989 && REGNO (operands[0]) == REGNO (operands[1]) + 1)
1990 swap = true;
1992 /* Check memory to register where the base reg overlaps the destination. */
1993 if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == MEM)
1995 rtx op = XEXP (operands[1], 0);
1997 if (GET_CODE (op) == SUBREG)
1998 op = SUBREG_REG (op);
2000 if (GET_CODE (op) == REG && REGNO (op) == REGNO (operands[0]))
2001 swap = true;
2003 if (GET_CODE (op) == PLUS)
2005 rtx x = XEXP (op, 0);
2006 rtx y = XEXP (op, 1);
2008 if (GET_CODE (x) == REG && REGNO (x) == REGNO (operands[0]))
2009 swap = true;
2011 if (GET_CODE (y) == REG && REGNO (y) == REGNO (operands[0]))
2012 swap = true;
2016 if (swap)
2018 operands[2] = operand_subword (operands[0], 1, 1, mode);
2019 operands[3] = operand_subword (operands[1], 1, 1, mode);
2020 operands[4] = operand_subword (operands[0], 0, 1, mode);
2021 operands[5] = operand_subword (operands[1], 0, 1, mode);
2023 else
2025 operands[2] = operand_subword (operands[0], 0, 1, mode);
2026 operands[3] = operand_subword (operands[1], 0, 1, mode);
2027 operands[4] = operand_subword (operands[0], 1, 1, mode);
2028 operands[5] = operand_subword (operands[1], 1, 1, mode);
2032 /* Expand a copysign of OPERANDS in MODE. */
2034 void
2035 visium_expand_copysign (rtx *operands, enum machine_mode mode)
2037 rtx dest = operands[0];
2038 rtx op0 = operands[1];
2039 rtx op1 = operands[2];
2040 rtx mask = force_reg (SImode, GEN_INT (0x7fffffff));
2041 rtx x;
2043 /* We manually handle SFmode because the abs and neg instructions of
2044 the FPU on the MCM have a non-standard behavior wrt NaNs. */
2045 gcc_assert (mode == SFmode);
2047 /* First get all the non-sign bits of OP0. */
2048 if (GET_CODE (op0) == CONST_DOUBLE)
2050 if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0)))
2051 op0 = simplify_unary_operation (ABS, mode, op0, mode);
2052 if (op0 != CONST0_RTX (mode))
2054 long l;
2055 REAL_VALUE_TYPE rv;
2056 REAL_VALUE_FROM_CONST_DOUBLE (rv, op0);
2057 REAL_VALUE_TO_TARGET_SINGLE (rv, l);
2058 op0 = force_reg (SImode, GEN_INT (trunc_int_for_mode (l, SImode)));
2061 else
2063 op0 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op0));
2064 op0 = force_reg (SImode, gen_rtx_AND (SImode, op0, mask));
2067 /* Then get the sign bit of OP1. */
2068 mask = force_reg (SImode, gen_rtx_NOT (SImode, mask));
2069 op1 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op1));
2070 op1 = force_reg (SImode, gen_rtx_AND (SImode, op1, mask));
2072 /* Finally OR the two values. */
2073 if (op0 == CONST0_RTX (SFmode))
2074 x = op1;
2075 else
2076 x = force_reg (SImode, gen_rtx_IOR (SImode, op0, op1));
2078 /* And move the result to the destination. */
2079 emit_insn (gen_rtx_SET (dest, gen_lowpart (SFmode, x)));
2082 /* Expand a cstore of OPERANDS in MODE for EQ/NE/LTU/GTU/GEU/LEU. We generate
2083 the result in the C flag and use the ADC/SUBC instructions to write it into
2084 the destination register.
2086 It would also be possible to implement support for LT/GT/LE/GE by means of
2087 the RFLAG instruction followed by some shifts, but this can pessimize the
2088 generated code. */
2090 void
2091 visium_expand_int_cstore (rtx *operands, enum machine_mode mode)
2093 enum rtx_code code = GET_CODE (operands[1]);
2094 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], sltu;
2095 bool reverse = false;
2097 switch (code)
2099 case EQ:
2100 case NE:
2101 /* We use a special comparison to get the result in the C flag. */
2102 if (op2 != const0_rtx)
2103 op1 = force_reg (mode, gen_rtx_XOR (mode, op1, op2));
2104 op1 = gen_rtx_NOT (mode, op1);
2105 op2 = constm1_rtx;
2106 if (code == EQ)
2107 reverse = true;
2108 break;
2110 case LEU:
2111 case GEU:
2112 /* The result is naturally in the C flag modulo a couple of tricks. */
2113 code = reverse_condition (code);
2114 reverse = true;
2116 /* ... fall through ... */
2118 case LTU:
2119 case GTU:
2120 if (code == GTU)
2122 rtx tmp = op1;
2123 op1 = op2;
2124 op2 = tmp;
2126 break;
2128 default:
2129 gcc_unreachable ();
2132 /* We need either a single ADC or a SUBC and a PLUS. */
2133 sltu = gen_rtx_LTU (SImode, op1, op2);
2135 if (reverse)
2137 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, sltu));
2138 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2140 else
2141 emit_insn (gen_rtx_SET (op0, sltu));
2144 /* Expand a cstore of OPERANDS in MODE for LT/GT/UNGE/UNLE. We generate the
2145 result in the C flag and use the ADC/SUBC instructions to write it into
2146 the destination register. */
2148 void
2149 visium_expand_fp_cstore (rtx *operands,
2150 enum machine_mode mode ATTRIBUTE_UNUSED)
2152 enum rtx_code code = GET_CODE (operands[1]);
2153 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], slt;
2154 bool reverse = false;
2156 switch (code)
2158 case UNLE:
2159 case UNGE:
2160 /* The result is naturally in the C flag modulo a couple of tricks. */
2161 code = reverse_condition_maybe_unordered (code);
2162 reverse = true;
2164 /* ... fall through ... */
2166 case LT:
2167 case GT:
2168 if (code == GT)
2170 rtx tmp = op1;
2171 op1 = op2;
2172 op2 = tmp;
2174 break;
2176 default:
2177 gcc_unreachable ();
2180 /* We need either a single ADC or a SUBC and a PLUS. */
2181 slt = gen_rtx_LT (SImode, op1, op2);
2183 if (reverse)
2185 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, slt));
2186 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2188 else
2189 emit_insn (gen_rtx_SET (op0, slt));
2192 /* Split a compare-and-store with CODE, operands OP2 and OP3, combined with
2193 operation with OP_CODE, operands OP0 and OP1. */
2195 void
2196 visium_split_cstore (enum rtx_code op_code, rtx op0, rtx op1,
2197 enum rtx_code code, rtx op2, rtx op3)
2199 enum machine_mode cc_mode = visium_select_cc_mode (code, op2, op3);
2201 /* If a FP cstore was reversed, then it was originally UNGE/UNLE. */
2202 if (cc_mode == CCFPEmode && (op_code == NEG || op_code == MINUS))
2203 cc_mode = CCFPmode;
2205 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2206 rtx x = gen_rtx_COMPARE (cc_mode, op2, op3);
2207 x = gen_rtx_SET (flags, x);
2208 emit_insn (x);
2210 x = gen_rtx_fmt_ee (code, SImode, flags, const0_rtx);
2211 switch (op_code)
2213 case SET:
2214 break;
2215 case NEG:
2216 x = gen_rtx_NEG (SImode, x);
2217 break;
2218 case PLUS:
2219 case MINUS:
2220 x = gen_rtx_fmt_ee (op_code, SImode, op1, x);
2221 break;
2222 default:
2223 gcc_unreachable ();
2226 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2227 XVECEXP (pat, 0, 0) = gen_rtx_SET (op0, x);
2228 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2229 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2230 emit_insn (pat);
2232 visium_flags_exposed = true;
2235 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2236 address SRC_REG to DST with address DST_REG in 4-byte chunks. */
2238 static void
2239 expand_block_move_4 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2241 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__long_int_memcpy");
2242 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2243 unsigned int rem = bytes % 4;
2245 if (TARGET_BMI)
2247 unsigned int i;
2248 rtx insn;
2250 emit_move_insn (regno_reg_rtx[1], dst_reg);
2251 emit_move_insn (regno_reg_rtx[2], src_reg);
2252 emit_move_insn (regno_reg_rtx[3], bytes_rtx);
2254 insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (8));
2255 XVECEXP (insn, 0, 0)
2256 = gen_rtx_SET (replace_equiv_address_nv (dst, regno_reg_rtx[1]),
2257 replace_equiv_address_nv (src, regno_reg_rtx[2]));
2258 XVECEXP (insn, 0, 1) = gen_rtx_USE (VOIDmode, regno_reg_rtx[3]);
2259 for (i = 1; i <= 6; i++)
2260 XVECEXP (insn, 0, 1 + i)
2261 = gen_rtx_CLOBBER (VOIDmode, regno_reg_rtx[i]);
2262 emit_insn (insn);
2264 else
2265 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, src_reg,
2266 Pmode,
2267 convert_to_mode (TYPE_MODE (sizetype),
2268 GEN_INT (bytes >> 2),
2269 TYPE_UNSIGNED (sizetype)),
2270 TYPE_MODE (sizetype));
2271 if (rem == 0)
2272 return;
2274 dst = replace_equiv_address_nv (dst, dst_reg);
2275 src = replace_equiv_address_nv (src, src_reg);
2276 bytes -= rem;
2278 if (rem > 1)
2280 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2281 adjust_address_nv (src, HImode, bytes));
2282 bytes += 2;
2283 rem -= 2;
2286 if (rem > 0)
2287 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2288 adjust_address_nv (src, QImode, bytes));
2291 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2292 address SRC_REG to DST with address DST_REG in 2-bytes chunks. */
2294 static void
2295 expand_block_move_2 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2297 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__wrd_memcpy");
2298 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2299 unsigned int rem = bytes % 2;
2301 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode, src_reg,
2302 Pmode,
2303 convert_to_mode (TYPE_MODE (sizetype),
2304 GEN_INT (bytes >> 1),
2305 TYPE_UNSIGNED (sizetype)),
2306 TYPE_MODE (sizetype));
2307 if (rem == 0)
2308 return;
2310 dst = replace_equiv_address_nv (dst, dst_reg);
2311 src = replace_equiv_address_nv (src, src_reg);
2312 bytes -= rem;
2314 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2315 adjust_address_nv (src, QImode, bytes));
2318 /* Generate a call to a library function to move BYTES_RTX bytes from address
2319 SRC_REG to address DST_REG in 1-byte chunks. */
2321 static void
2322 expand_block_move_1 (rtx dst_reg, rtx src_reg, rtx bytes_rtx)
2324 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__byt_memcpy");
2326 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
2327 src_reg, Pmode,
2328 convert_to_mode (TYPE_MODE (sizetype),
2329 bytes_rtx,
2330 TYPE_UNSIGNED (sizetype)),
2331 TYPE_MODE (sizetype));
2334 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2335 address DST_REG to VALUE_RTX in 4-byte chunks. */
2337 static void
2338 expand_block_set_4 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2340 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__long_int_memset");
2341 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2342 unsigned int rem = bytes % 4;
2344 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2345 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
2346 value_rtx, Pmode,
2347 convert_to_mode (TYPE_MODE (sizetype),
2348 GEN_INT (bytes >> 2),
2349 TYPE_UNSIGNED (sizetype)),
2350 TYPE_MODE (sizetype));
2351 if (rem == 0)
2352 return;
2354 dst = replace_equiv_address_nv (dst, dst_reg);
2355 bytes -= rem;
2357 if (rem > 1)
2359 if (CONST_INT_P (value_rtx))
2361 const unsigned HOST_WIDE_INT value = UINTVAL (value_rtx) & 0xff;
2362 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2363 gen_int_mode ((value << 8) | value, HImode));
2365 else
2367 rtx temp = convert_to_mode (QImode, value_rtx, 1);
2368 emit_move_insn (adjust_address_nv (dst, QImode, bytes), temp);
2369 emit_move_insn (adjust_address_nv (dst, QImode, bytes + 1), temp);
2371 bytes += 2;
2372 rem -= 2;
2375 if (rem > 0)
2376 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2377 convert_to_mode (QImode, value_rtx, 1));
2380 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2381 address DST_REG to VALUE_RTX in 2-byte chunks. */
2383 static void
2384 expand_block_set_2 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2386 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__wrd_memset");
2387 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2388 unsigned int rem = bytes % 2;
2390 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2391 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
2392 value_rtx, Pmode,
2393 convert_to_mode (TYPE_MODE (sizetype),
2394 GEN_INT (bytes >> 1),
2395 TYPE_UNSIGNED (sizetype)),
2396 TYPE_MODE (sizetype));
2397 if (rem == 0)
2398 return;
2400 dst = replace_equiv_address_nv (dst, dst_reg);
2401 bytes -= rem;
2403 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2404 convert_to_mode (QImode, value_rtx, 1));
2407 /* Generate a call to a library function to set BYTES_RTX bytes at address
2408 DST_REG to VALUE_RTX in 1-byte chunks. */
2410 static void
2411 expand_block_set_1 (rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2413 const rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__byt_memset");
2415 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2416 emit_library_call (sym, LCT_NORMAL, VOIDmode, 3, dst_reg, Pmode,
2417 value_rtx, Pmode,
2418 convert_to_mode (TYPE_MODE (sizetype),
2419 bytes_rtx,
2420 TYPE_UNSIGNED (sizetype)),
2421 TYPE_MODE (sizetype));
2424 /* Expand string/block move operations.
2426 operands[0] is the pointer to the destination.
2427 operands[1] is the pointer to the source.
2428 operands[2] is the number of bytes to move.
2429 operands[3] is the alignment.
2431 Return 1 upon success, 0 otherwise. */
2434 visium_expand_block_move (rtx *operands)
2436 rtx dst = operands[0];
2437 rtx src = operands[1];
2438 rtx bytes_rtx = operands[2];
2439 rtx align_rtx = operands[3];
2440 const int align = INTVAL (align_rtx);
2441 rtx dst_reg, src_reg;
2442 tree dst_expr, src_expr;
2444 /* We only handle a fixed number of bytes for now. */
2445 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2446 return 0;
2448 /* Copy the addresses into scratch registers. */
2449 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2450 src_reg = copy_addr_to_reg (XEXP (src, 0));
2452 /* Move the data with the appropriate granularity. */
2453 if (align >= 4)
2454 expand_block_move_4 (dst, dst_reg, src, src_reg, bytes_rtx);
2455 else if (align >= 2)
2456 expand_block_move_2 (dst, dst_reg, src, src_reg, bytes_rtx);
2457 else
2458 expand_block_move_1 (dst_reg, src_reg, bytes_rtx);
2460 /* Since DST and SRC are passed to a libcall, mark the corresponding
2461 tree EXPR as addressable. */
2462 dst_expr = MEM_EXPR (dst);
2463 src_expr = MEM_EXPR (src);
2464 if (dst_expr)
2465 mark_addressable (dst_expr);
2466 if (src_expr)
2467 mark_addressable (src_expr);
2469 return 1;
2472 /* Expand string/block set operations.
2474 operands[0] is the pointer to the destination.
2475 operands[1] is the number of bytes to set.
2476 operands[2] is the source value.
2477 operands[3] is the alignment.
2479 Return 1 upon success, 0 otherwise. */
2482 visium_expand_block_set (rtx *operands)
2484 rtx dst = operands[0];
2485 rtx bytes_rtx = operands[1];
2486 rtx value_rtx = operands[2];
2487 rtx align_rtx = operands[3];
2488 const int align = INTVAL (align_rtx);
2489 rtx dst_reg;
2490 tree dst_expr;
2492 /* We only handle a fixed number of bytes for now. */
2493 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2494 return 0;
2496 /* Copy the address into a scratch register. */
2497 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2499 /* Set the data with the appropriate granularity. */
2500 if (align >= 4)
2501 expand_block_set_4 (dst, dst_reg, value_rtx, bytes_rtx);
2502 else if (align >= 2)
2503 expand_block_set_2 (dst, dst_reg, value_rtx, bytes_rtx);
2504 else
2505 expand_block_set_1 (dst_reg, value_rtx, bytes_rtx);
2507 /* Since DST is passed to a libcall, mark the corresponding
2508 tree EXPR as addressable. */
2509 dst_expr = MEM_EXPR (dst);
2510 if (dst_expr)
2511 mark_addressable (dst_expr);
2513 return 1;
2516 /* Initialize a trampoline. M_TRAMP is an RTX for the memory block for the
2517 trampoline, FNDECL is the FUNCTION_DECL for the nested function and
2518 STATIC_CHAIN is an RTX for the static chain value that should be passed
2519 to the function when it is called. */
2521 static void
2522 visium_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
2524 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2525 rtx addr = XEXP (m_tramp, 0);
2527 /* The trampoline initialization sequence is:
2529 moviu r9,%u FUNCTION
2530 movil r9,%l FUNCTION
2531 moviu r20,%u STATIC
2532 bra tr,r9,r9
2533 movil r20,%l STATIC
2535 We don't use r0 as the destination register of the branch because we want
2536 the Branch Pre-decode Logic of the GR6 to use the Address Load Array to
2537 predict the branch target. */
2539 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 0)),
2540 plus_constant (SImode,
2541 expand_shift (RSHIFT_EXPR, SImode, fnaddr,
2542 16, NULL_RTX, 1),
2543 0x04a90000));
2545 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 4)),
2546 plus_constant (SImode,
2547 expand_and (SImode, fnaddr, GEN_INT (0xffff),
2548 NULL_RTX),
2549 0x04890000));
2551 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 8)),
2552 plus_constant (SImode,
2553 expand_shift (RSHIFT_EXPR, SImode,
2554 static_chain,
2555 16, NULL_RTX, 1),
2556 0x04b40000));
2558 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)),
2559 gen_int_mode (0xff892404, SImode));
2561 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 16)),
2562 plus_constant (SImode,
2563 expand_and (SImode, static_chain,
2564 GEN_INT (0xffff), NULL_RTX),
2565 0x04940000));
2567 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__set_trampoline_parity"),
2568 LCT_NORMAL, VOIDmode, 1, addr, SImode);
2571 /* Return true if the current function must have and use a frame pointer. */
2573 static bool
2574 visium_frame_pointer_required (void)
2576 /* The frame pointer is required if the function isn't leaf to be able to
2577 do manual stack unwinding. */
2578 if (!crtl->is_leaf)
2579 return true;
2581 /* If the stack pointer is dynamically modified in the function, it cannot
2582 serve as the frame pointer. */
2583 if (!crtl->sp_is_unchanging)
2584 return true;
2586 /* If the function receives nonlocal gotos, it needs to save the frame
2587 pointer in the nonlocal_goto_save_area object. */
2588 if (cfun->has_nonlocal_label)
2589 return true;
2591 /* The frame also needs to be established in some special cases. */
2592 if (visium_frame_needed)
2593 return true;
2595 return false;
2598 /* Profiling support. Just a call to MCOUNT is needed. No labelled counter
2599 location is involved. Proper support for __builtin_return_address is also
2600 required, which is fairly straightforward provided a frame gets created. */
2602 void
2603 visium_profile_hook (void)
2605 visium_frame_needed = true;
2606 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "mcount"), LCT_NORMAL,
2607 VOIDmode, 0);
2610 /* A C expression whose value is RTL representing the address in a stack frame
2611 where the pointer to the caller's frame is stored. Assume that FRAMEADDR is
2612 an RTL expression for the address of the stack frame itself.
2614 If you don't define this macro, the default is to return the value of
2615 FRAMEADDR--that is, the stack frame address is also the address of the stack
2616 word that points to the previous frame. */
2619 visium_dynamic_chain_address (rtx frame)
2621 /* This is the default, but we need to make sure the frame gets created. */
2622 visium_frame_needed = true;
2623 return frame;
2626 /* A C expression whose value is RTL representing the value of the return
2627 address for the frame COUNT steps up from the current frame, after the
2628 prologue. FRAMEADDR is the frame pointer of the COUNT frame, or the frame
2629 pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
2630 defined.
2632 The value of the expression must always be the correct address when COUNT is
2633 zero, but may be `NULL_RTX' if there is not way to determine the return
2634 address of other frames. */
2637 visium_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
2639 /* Dont try to compute anything other than frame zero. */
2640 if (count != 0)
2641 return NULL_RTX;
2643 visium_frame_needed = true;
2644 return
2645 gen_frame_mem (Pmode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2648 /* Helper function for EH_RETURN_HANDLER_RTX. Return the RTX representing a
2649 location in which to store the address of an exception handler to which we
2650 should return. */
2653 visium_eh_return_handler_rtx (void)
2655 rtx mem
2656 = gen_frame_mem (SImode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2657 MEM_VOLATILE_P (mem) = 1;
2658 return mem;
2661 static struct machine_function *
2662 visium_init_machine_status (void)
2664 return ggc_cleared_alloc<machine_function> ();
2667 /* The per-function data machinery is needed to indicate when a frame
2668 is required. */
2670 void
2671 visium_init_expanders (void)
2673 init_machine_status = visium_init_machine_status;
2676 /* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE,
2677 return the mode to be used for the comparison. */
2679 enum machine_mode
2680 visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
2682 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2684 switch (code)
2686 case EQ:
2687 case NE:
2688 case ORDERED:
2689 case UNORDERED:
2690 case UNLT:
2691 case UNLE:
2692 case UNGT:
2693 case UNGE:
2694 return CCFPmode;
2696 case LT:
2697 case LE:
2698 case GT:
2699 case GE:
2700 return CCFPEmode;
2702 /* These 2 comparison codes are not supported. */
2703 case UNEQ:
2704 case LTGT:
2705 default:
2706 gcc_unreachable ();
2710 if (op1 != const0_rtx)
2711 return CCmode;
2713 switch (GET_CODE (op0))
2715 case PLUS:
2716 case MINUS:
2717 case NEG:
2718 case ASHIFT:
2719 case LTU:
2720 case LT:
2721 /* The V flag may be set differently from a COMPARE with zero.
2722 The consequence is that a comparison operator testing V must
2723 be turned into another operator not testing V and yielding
2724 the same result for a comparison with zero. That's possible
2725 for GE/LT which become NC/NS respectively, but not for GT/LE
2726 for which the altered operator doesn't exist on the Visium. */
2727 return CC_NOOVmode;
2729 case ZERO_EXTRACT:
2730 /* This is a btst, the result is in C instead of Z. */
2731 return CC_BTSTmode;
2733 case CONST_INT:
2734 /* This is a degenerate case, typically an uninitialized variable. */
2735 gcc_assert (op0 == constm1_rtx);
2736 case REG:
2737 case AND:
2738 case IOR:
2739 case XOR:
2740 case NOT:
2741 case ASHIFTRT:
2742 case LSHIFTRT:
2743 case TRUNCATE:
2744 case SIGN_EXTEND:
2745 /* Pretend that the flags are set as for a COMPARE with zero.
2746 That's mostly true, except for the 2 right shift insns that
2747 will set the C flag. But the C flag is relevant only for
2748 the unsigned comparison operators and they are eliminated
2749 when applied to a comparison with zero. */
2750 return CCmode;
2752 default:
2753 gcc_unreachable ();
2757 /* Split a compare-and-branch with CODE, operands OP0 and OP1, and LABEL. */
2759 void
2760 visium_split_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx label)
2762 enum machine_mode cc_mode = visium_select_cc_mode (code, op0, op1);
2763 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2765 rtx x = gen_rtx_COMPARE (cc_mode, op0, op1);
2766 x = gen_rtx_SET (flags, x);
2767 emit_insn (x);
2769 x = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
2770 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, gen_rtx_LABEL_REF (Pmode, label),
2771 pc_rtx);
2772 x = gen_rtx_SET (pc_rtx, x);
2773 emit_jump_insn (x);
2775 visium_flags_exposed = true;
2778 /* Branch instructions on the Visium.
2780 Setting aside the interrupt-handling specific instructions, the ISA has
2781 two branch instructions: BRR and BRA. The former is used to implement
2782 short branches (+/- 2^17) within functions and its target is encoded in
2783 the instruction. The latter is used to implement all the other types
2784 of control flow changes and its target might not be statically known
2785 or even easily predictable at run time. Here's a complete summary of
2786 the patterns that generate a BRA instruction:
2788 1. Indirect jump
2789 2. Table jump
2790 3. Call
2791 4. Sibling call
2792 5. Return
2793 6. Long branch
2794 7. Trampoline
2796 Among these patterns, only the return (5) and the long branch (6) can be
2797 conditional; all the other patterns are always unconditional.
2799 The following algorithm can be used to identify the pattern for which
2800 the BRA instruction was generated and work out its target:
2802 A. If the source is r21 and the destination is r0, this is a return (5)
2803 and the target is the caller (i.e. the value of r21 on function's
2804 entry).
2806 B. If the source is rN, N != 21 and the destination is r0, this is either
2807 an indirect jump or a table jump (1, 2) and the target is not easily
2808 predictable.
2810 C. If the source is rN, N != 21 and the destination is r21, this is a call
2811 (3) and the target is given by the preceding MOVIL/MOVIU pair for rN,
2812 unless this is an indirect call in which case the target is not easily
2813 predictable.
2815 D. If the source is rN, N != 21 and the destination is also rN, this is
2816 either a sibling call or a trampoline (4, 7) and the target is given
2817 by the preceding MOVIL/MOVIU pair for rN.
2819 E. If the source is r21 and the destination is also r21, this is a long
2820 branch (6) and the target is given by the preceding MOVIL/MOVIU pair
2821 for r21.
2823 The other combinations are not used. This implementation has been devised
2824 to accommodate the branch predictor of the GR6 but is used unconditionally
2825 by the compiler, i.e. including for earlier processors. */
2827 /* Output a conditional/unconditional branch to LABEL. COND is the string
2828 condition. INSN is the instruction. */
2830 static const char *
2831 output_branch (rtx label, const char *cond, rtx_insn *insn)
2833 char str[64];
2834 rtx operands[2];
2836 gcc_assert (cond);
2837 operands[0] = label;
2839 /* If the length of the instruction is greater than 8, then this is a
2840 long branch and we need to work harder to emit it properly. */
2841 if (get_attr_length (insn) > 8)
2843 bool spilled;
2845 /* If the link register has been saved, then we use it. */
2846 if (current_function_saves_lr ())
2848 operands[1] = regno_reg_rtx [LINK_REGNUM];
2849 spilled = false;
2852 /* Or else, if the long-branch register isn't live, we use it. */
2853 else if (!df_regs_ever_live_p (long_branch_regnum))
2855 operands[1] = regno_reg_rtx [long_branch_regnum];
2856 spilled = false;
2859 /* Otherwise, we will use the long-branch register but we need to
2860 spill it to the stack and reload it at the end. We should have
2861 reserved the LR slot for this purpose. */
2862 else
2864 operands[1] = regno_reg_rtx [long_branch_regnum];
2865 spilled = true;
2866 gcc_assert (current_function_has_lr_slot ());
2869 /* First emit the spill to the stack:
2871 insn_in_delay_slot
2872 write.l [1](sp),reg */
2873 if (spilled)
2875 if (final_sequence)
2877 rtx_insn *delay = NEXT_INSN (insn);
2878 int seen;
2879 gcc_assert (delay);
2881 final_scan_insn (delay, asm_out_file, optimize, 0, &seen);
2882 PATTERN (delay) = gen_blockage ();
2883 INSN_CODE (delay) = -1;
2886 if (current_function_saves_fp ())
2887 output_asm_insn ("write.l 1(sp),%1", operands);
2888 else
2889 output_asm_insn ("write.l (sp),%1", operands);
2892 /* Then emit the core sequence:
2894 moviu reg,%u label
2895 movil reg,%l label
2896 bra tr,reg,reg
2898 We don't use r0 as the destination register of the branch because we
2899 want the Branch Pre-decode Logic of the GR6 to use the Address Load
2900 Array to predict the branch target. */
2901 output_asm_insn ("moviu %1,%%u %0", operands);
2902 output_asm_insn ("movil %1,%%l %0", operands);
2903 strcpy (str, "bra ");
2904 strcat (str, cond);
2905 strcat (str, ",%1,%1");
2906 if (!spilled)
2907 strcat (str, "%#");
2908 strcat (str, "\t\t;long branch");
2909 output_asm_insn (str, operands);
2911 /* Finally emit the reload:
2913 read.l reg,[1](sp) */
2914 if (spilled)
2916 if (current_function_saves_fp ())
2917 output_asm_insn (" read.l %1,1(sp)", operands);
2918 else
2919 output_asm_insn (" read.l %1,(sp)", operands);
2923 /* Or else, if the label is PC, then this is a return. */
2924 else if (label == pc_rtx)
2926 strcpy (str, "bra ");
2927 strcat (str, cond);
2928 strcat (str, ",r21,r0%#\t\t;return");
2929 output_asm_insn (str, operands);
2932 /* Otherwise, this is a short branch. */
2933 else
2935 strcpy (str, "brr ");
2936 strcat (str, cond);
2937 strcat (str, ",%0%#");
2938 output_asm_insn (str, operands);
2941 return "";
2944 /* Output an unconditional branch to LABEL. INSN is the instruction. */
2946 const char *
2947 output_ubranch (rtx label, rtx_insn *insn)
2949 return output_branch (label, "tr", insn);
2952 /* Output a conditional branch to LABEL. CODE is the comparison code.
2953 CC_MODE is the mode of the CC register. REVERSED is non-zero if we
2954 should reverse the sense of the comparison. INSN is the instruction. */
2956 const char *
2957 output_cbranch (rtx label, enum rtx_code code, enum machine_mode cc_mode,
2958 int reversed, rtx_insn *insn)
2960 const char *cond;
2962 if (reversed)
2964 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
2965 code = reverse_condition_maybe_unordered (code);
2966 else
2967 code = reverse_condition (code);
2970 switch (code)
2972 case NE:
2973 if (cc_mode == CC_BTSTmode)
2974 cond = "cs";
2975 else
2976 cond = "ne";
2977 break;
2979 case EQ:
2980 if (cc_mode == CC_BTSTmode)
2981 cond = "cc";
2982 else
2983 cond = "eq";
2984 break;
2986 case GE:
2987 if (cc_mode == CC_NOOVmode)
2988 cond = "nc";
2989 else
2990 cond = "ge";
2991 break;
2993 case GT:
2994 cond = "gt";
2995 break;
2997 case LE:
2998 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
2999 cond = "ls";
3000 else
3001 cond = "le";
3002 break;
3004 case LT:
3005 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3006 cond = "ns";
3007 else if (cc_mode == CC_NOOVmode)
3008 cond = "ns";
3009 else
3010 cond = "lt";
3011 break;
3013 case GEU:
3014 cond = "cc";
3015 break;
3017 case GTU:
3018 cond = "hi";
3019 break;
3021 case LEU:
3022 cond = "ls";
3023 break;
3025 case LTU:
3026 cond = "cs";
3027 break;
3029 case UNORDERED:
3030 cond = "os";
3031 break;
3033 case ORDERED:
3034 cond = "oc";
3035 break;
3037 case UNGE:
3038 cond = "nc";
3039 break;
3041 case UNGT:
3042 cond = "hi";
3043 break;
3045 case UNLE:
3046 cond = "le";
3047 break;
3049 case UNLT:
3050 cond = "lt";
3051 break;
3053 /* These 2 comparison codes are not supported. */
3054 case UNEQ:
3055 case LTGT:
3056 default:
3057 gcc_unreachable ();
3060 return output_branch (label, cond, insn);
3063 /* Helper function for PRINT_OPERAND (STREAM, X, CODE). Output to stdio
3064 stream FILE the assembler syntax for an instruction operand OP subject
3065 to the modifier LETTER. */
3067 void
3068 print_operand (FILE *file, rtx op, int letter)
3070 switch (letter)
3072 case '#':
3073 /* Output an insn in a delay slot. */
3074 if (final_sequence)
3075 visium_indent_opcode = 1;
3076 else
3077 fputs ("\n\t nop", file);
3078 return;
3080 case 'b':
3081 /* Print LS 8 bits of operand. */
3082 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xff);
3083 return;
3085 case 'w':
3086 /* Print LS 16 bits of operand. */
3087 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xffff);
3088 return;
3090 case 'u':
3091 /* Print MS 16 bits of operand. */
3092 fprintf (file,
3093 HOST_WIDE_INT_PRINT_UNSIGNED, (UINTVAL (op) >> 16) & 0xffff);
3094 return;
3096 case 'r':
3097 /* It's either a register or zero. */
3098 if (GET_CODE (op) == REG)
3099 fputs (reg_names[REGNO (op)], file);
3100 else
3101 fputs (reg_names[0], file);
3102 return;
3104 case 'f':
3105 /* It's either a FP register or zero. */
3106 if (GET_CODE (op) == REG)
3107 fputs (reg_names[REGNO (op)], file);
3108 else
3109 fputs (reg_names[FP_FIRST_REGNUM], file);
3110 return;
3113 switch (GET_CODE (op))
3115 case REG:
3116 if (letter == 'd')
3117 fputs (reg_names[REGNO (op) + 1], file);
3118 else
3119 fputs (reg_names[REGNO (op)], file);
3120 break;
3122 case SYMBOL_REF:
3123 case LABEL_REF:
3124 case CONST:
3125 output_addr_const (file, op);
3126 break;
3128 case MEM:
3129 visium_output_address (file, GET_MODE (op), XEXP (op, 0));
3130 break;
3132 case CONST_INT:
3133 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
3134 break;
3136 case CODE_LABEL:
3137 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (op));
3138 break;
3140 case HIGH:
3141 print_operand (file, XEXP (op, 1), letter);
3142 break;
3144 default:
3145 fatal_insn ("illegal operand ", op);
3149 /* Output to stdio stream FILE the assembler syntax for an instruction operand
3150 that is a memory reference in MODE and whose address is ADDR. */
3152 static void
3153 visium_output_address (FILE *file, enum machine_mode mode, rtx addr)
3155 switch (GET_CODE (addr))
3157 case REG:
3158 case SUBREG:
3159 fprintf (file, "(%s)", reg_names[true_regnum (addr)]);
3160 break;
3162 case PLUS:
3164 rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
3166 switch (GET_CODE (x))
3168 case REG:
3169 case SUBREG:
3170 if (CONST_INT_P (y))
3172 unsigned int regno = true_regnum (x);
3173 HOST_WIDE_INT val = INTVAL (y);
3174 switch (mode)
3176 case SImode:
3177 case DImode:
3178 case SFmode:
3179 case DFmode:
3180 val >>= 2;
3181 break;
3183 case HImode:
3184 val >>= 1;
3185 break;
3187 case QImode:
3188 default:
3189 break;
3191 fprintf (file, HOST_WIDE_INT_PRINT_DEC"(%s)", val,
3192 reg_names[regno]);
3194 else
3195 fatal_insn ("illegal operand address (1)", addr);
3196 break;
3198 default:
3199 if (CONSTANT_P (x) && CONSTANT_P (y))
3200 output_addr_const (file, addr);
3201 else
3202 fatal_insn ("illegal operand address (2)", addr);
3203 break;
3206 break;
3208 case LABEL_REF:
3209 case SYMBOL_REF:
3210 case CONST_INT:
3211 case CONST:
3212 output_addr_const (file, addr);
3213 break;
3215 case NOTE:
3216 if (NOTE_KIND (addr) != NOTE_INSN_DELETED_LABEL)
3217 fatal_insn ("illegal operand address (3)", addr);
3218 break;
3220 case CODE_LABEL:
3221 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (addr));
3222 break;
3224 default:
3225 fatal_insn ("illegal operand address (4)", addr);
3226 break;
3230 /* Helper function for PRINT_OPERAND_ADDRESS (STREAM, X). Output to stdio
3231 stream FILE the assembler syntax for an instruction operand that is a
3232 memory reference whose address is ADDR. */
3234 void
3235 print_operand_address (FILE *file, rtx addr)
3237 visium_output_address (file, QImode, addr);
3240 /* The Visium stack frames look like:
3242 Before call After call
3243 +-----------------------+ +-----------------------+
3244 | | | |
3245 high | previous | | previous |
3246 mem | frame | | frame |
3247 | | | |
3248 +-----------------------+ +-----------------------+
3249 | | | |
3250 | arguments on stack | | arguments on stack |
3251 | | | |
3252 SP+0->+-----------------------+ +-----------------------+
3253 | reg parm save area, |
3254 | only created for |
3255 | variable argument |
3256 | functions |
3257 +-----------------------+
3259 | register save area |
3261 +-----------------------+
3263 | local variables |
3265 FP+8->+-----------------------+
3266 | return address |
3267 FP+4->+-----------------------+
3268 | previous FP |
3269 FP+0->+-----------------------+
3271 | alloca allocations |
3273 +-----------------------+
3275 low | arguments on stack |
3276 mem | |
3277 SP+0->+-----------------------+
3279 Notes:
3280 1) The "reg parm save area" does not exist for non variable argument fns.
3281 2) The FP register is not saved if `frame_pointer_needed' is zero and it
3282 is not altered in the current function.
3283 3) The return address is not saved if there is no frame pointer and the
3284 current function is leaf.
3285 4) If the return address is not saved and the static chain register is
3286 live in the function, we allocate the return address slot to be able
3287 to spill the register for a long branch. */
3289 /* Define the register classes for local purposes. */
3290 enum reg_type { general, mdb, mdc, floating, last_type};
3292 #define GET_REG_TYPE(regno) \
3293 (GP_REGISTER_P (regno) ? general : \
3294 (regno) == MDB_REGNUM ? mdb : \
3295 (regno) == MDC_REGNUM ? mdc : \
3296 floating)
3298 /* First regno of each register type. */
3299 const int first_regno[last_type] = {0, MDB_REGNUM, MDC_REGNUM, FP_FIRST_REGNUM};
3301 /* Size in bytes of each register type. */
3302 const int reg_type_size[last_type] = {4, 8, 4, 4};
3304 /* Structure to be filled in by visium_compute_frame_size. */
3305 struct visium_frame_info
3307 unsigned int save_area_size; /* # bytes in the reg parm save area. */
3308 unsigned int reg_size1; /* # bytes to store first block of regs. */
3309 unsigned int reg_size2; /* # bytes to store second block of regs. */
3310 unsigned int max_reg1; /* max. regno in first block */
3311 unsigned int var_size; /* # bytes that variables take up. */
3312 unsigned int save_fp; /* Nonzero if fp must be saved. */
3313 unsigned int save_lr; /* Nonzero if lr must be saved. */
3314 unsigned int lr_slot; /* Nonzero if the lr slot is needed. */
3315 unsigned int combine; /* Nonzero if we can combine the allocation of
3316 variables and regs. */
3317 unsigned int interrupt; /* Nonzero if the function is an interrupt
3318 handler. */
3319 unsigned int mask[last_type]; /* Masks of saved regs: gp, mdb, mdc, fp */
3322 /* Current frame information calculated by visium_compute_frame_size. */
3323 static struct visium_frame_info current_frame_info;
3325 /* Accessor for current_frame_info.save_fp. */
3327 static inline bool
3328 current_function_saves_fp (void)
3330 return current_frame_info.save_fp != 0;
3333 /* Accessor for current_frame_info.save_lr. */
3335 static inline bool
3336 current_function_saves_lr (void)
3338 return current_frame_info.save_lr != 0;
3341 /* Accessor for current_frame_info.lr_slot. */
3343 static inline bool
3344 current_function_has_lr_slot (void)
3346 return current_frame_info.lr_slot != 0;
3349 /* Return non-zero if register REGNO needs to be saved in the frame. */
3351 static int
3352 visium_save_reg_p (int interrupt, int regno)
3354 switch (regno)
3356 case HARD_FRAME_POINTER_REGNUM:
3357 /* This register is call-saved but handled specially. */
3358 return 0;
3360 case MDC_REGNUM:
3361 /* This register is fixed but can be modified. */
3362 break;
3364 case 29:
3365 case 30:
3366 /* These registers are fixed and hold the interrupt context. */
3367 return (interrupt != 0);
3369 default:
3370 /* The other fixed registers are either immutable or special. */
3371 if (fixed_regs[regno])
3372 return 0;
3373 break;
3376 if (interrupt)
3378 if (crtl->is_leaf)
3380 if (df_regs_ever_live_p (regno))
3381 return 1;
3383 else if (call_used_regs[regno])
3384 return 1;
3386 /* To save mdb requires two temporary registers. To save mdc or
3387 any of the floating registers requires one temporary
3388 register. If this is an interrupt routine, the temporary
3389 registers need to be saved as well. These temporary registers
3390 are call used, so we only need deal with the case of leaf
3391 functions here. */
3392 if (regno == PROLOGUE_TMP_REGNUM)
3394 if (df_regs_ever_live_p (MDB_REGNUM)
3395 || df_regs_ever_live_p (MDC_REGNUM))
3396 return 1;
3398 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
3399 if (df_regs_ever_live_p (i))
3400 return 1;
3403 else if (regno == PROLOGUE_TMP_REGNUM + 1)
3405 if (df_regs_ever_live_p (MDB_REGNUM))
3406 return 1;
3410 return df_regs_ever_live_p (regno) && !call_used_regs[regno];
3413 /* Compute the frame size required by the function. This function is called
3414 during the reload pass and also by visium_expand_prologue. */
3416 static int
3417 visium_compute_frame_size (int size)
3419 const int save_area_size = visium_reg_parm_save_area_size;
3420 const int var_size = VISIUM_STACK_ALIGN (size);
3421 const int save_fp
3422 = frame_pointer_needed || df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM);
3423 const int save_lr = frame_pointer_needed || !crtl->is_leaf;
3424 const int lr_slot = !save_lr && df_regs_ever_live_p (long_branch_regnum);
3425 const int local_frame_offset
3426 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3427 const int interrupt = visium_interrupt_function_p ();
3428 unsigned int mask[last_type];
3429 int reg_size1 = 0;
3430 int max_reg1 = 0;
3431 int reg_size2 = 0;
3432 int reg_size;
3433 int combine;
3434 int frame_size;
3435 int regno;
3437 memset (mask, 0, last_type * sizeof (unsigned int));
3439 /* The registers may need stacking in 2 blocks since only 32 32-bit words
3440 can be indexed from a given base address. */
3441 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3443 if (visium_save_reg_p (interrupt, regno))
3445 enum reg_type reg_type = GET_REG_TYPE (regno);
3446 int mask_bit = 1 << (regno - first_regno[reg_type]);
3447 int nbytes = reg_type_size[reg_type];
3449 if (reg_size1 + nbytes > 32 * UNITS_PER_WORD)
3450 break;
3452 reg_size1 += nbytes;
3453 max_reg1 = regno;
3454 mask[reg_type] |= mask_bit;
3458 for (regno = max_reg1 + 1; regno < FIRST_PSEUDO_REGISTER; regno++)
3460 if (visium_save_reg_p (interrupt, regno))
3462 enum reg_type reg_type = GET_REG_TYPE (regno);
3463 int mask_bit = 1 << (regno - first_regno[reg_type]);
3464 int nbytes = reg_type_size[reg_type];
3466 reg_size2 += nbytes;
3467 mask[reg_type] |= mask_bit;
3471 reg_size = reg_size2 ? reg_size2 : reg_size1;
3472 combine = (local_frame_offset + var_size + reg_size) <= 32 * UNITS_PER_WORD;
3473 frame_size
3474 = local_frame_offset + var_size + reg_size2 + reg_size1 + save_area_size;
3476 current_frame_info.save_area_size = save_area_size;
3477 current_frame_info.reg_size1 = reg_size1;
3478 current_frame_info.max_reg1 = max_reg1;
3479 current_frame_info.reg_size2 = reg_size2;
3480 current_frame_info.var_size = var_size;
3481 current_frame_info.save_fp = save_fp;
3482 current_frame_info.save_lr = save_lr;
3483 current_frame_info.lr_slot = lr_slot;
3484 current_frame_info.combine = combine;
3485 current_frame_info.interrupt = interrupt;
3487 memcpy (current_frame_info.mask, mask, last_type * sizeof (unsigned int));
3489 return frame_size;
3492 /* Helper function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define
3493 the offset between two registers, one to be eliminated, and the other its
3494 replacement, at the start of a routine. */
3497 visium_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
3499 const int frame_size = visium_compute_frame_size (get_frame_size ());
3500 const int save_fp = current_frame_info.save_fp;
3501 const int save_lr = current_frame_info.save_lr;
3502 const int lr_slot = current_frame_info.lr_slot;
3503 const int local_frame_offset
3504 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3505 int offset;
3507 if (from == FRAME_POINTER_REGNUM)
3508 offset = local_frame_offset;
3509 else if (from == ARG_POINTER_REGNUM)
3510 offset = frame_size;
3511 else
3512 gcc_unreachable ();
3514 return offset;
3517 /* For an interrupt handler, we may be saving call-clobbered registers.
3518 Say the epilogue uses these in addition to the link register. */
3521 visium_epilogue_uses (int regno)
3523 if (regno == LINK_REGNUM)
3524 return 1;
3526 if (reload_completed)
3528 enum reg_type reg_type = GET_REG_TYPE (regno);
3529 int mask_bit = 1 << (regno - first_regno[reg_type]);
3531 return (current_frame_info.mask[reg_type] & mask_bit) != 0;
3534 return 0;
3537 /* Wrapper around emit_insn that sets RTX_FRAME_RELATED_P on the insn. */
3539 static rtx
3540 emit_frame_insn (rtx x)
3542 x = emit_insn (x);
3543 RTX_FRAME_RELATED_P (x) = 1;
3544 return x;
3547 /* Allocate ALLOC bytes on the stack and save the registers LOW_REGNO to
3548 HIGH_REGNO at OFFSET from the stack pointer. */
3550 static void
3551 visium_save_regs (int alloc, int offset, int low_regno, int high_regno)
3553 /* If this is an interrupt handler function, then mark the register
3554 stores as volatile. This will prevent the instruction scheduler
3555 from scrambling the order of register saves. */
3556 const int volatile_p = current_frame_info.interrupt;
3557 int regno;
3559 /* Allocate the stack space. */
3560 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, stack_pointer_rtx,
3561 GEN_INT (-alloc)));
3563 for (regno = low_regno; regno <= high_regno; regno++)
3565 enum reg_type reg_type = GET_REG_TYPE (regno);
3566 int mask_bit = 1 << (regno - first_regno[reg_type]);
3567 rtx insn;
3569 if (current_frame_info.mask[reg_type] & mask_bit)
3571 offset -= reg_type_size[reg_type];
3572 switch (reg_type)
3574 case general:
3576 rtx mem
3577 = gen_frame_mem (SImode,
3578 plus_constant (Pmode,
3579 stack_pointer_rtx, offset));
3580 MEM_VOLATILE_P (mem) = volatile_p;
3581 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, regno)));
3583 break;
3585 case mdb:
3587 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3588 rtx mem
3589 = gen_frame_mem (DImode,
3590 plus_constant (Pmode,
3591 stack_pointer_rtx, offset));
3592 rtx reg = gen_rtx_REG (DImode, regno);
3593 MEM_VOLATILE_P (mem) = volatile_p;
3594 emit_insn (gen_movdi (tmp, reg));
3595 /* Do not generate CFI if in interrupt handler. */
3596 if (volatile_p)
3597 emit_insn (gen_movdi (mem, tmp));
3598 else
3600 insn = emit_frame_insn (gen_movdi (mem, tmp));
3601 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3602 gen_rtx_SET (mem, reg));
3605 break;
3607 case mdc:
3609 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3610 rtx mem
3611 = gen_frame_mem (SImode,
3612 plus_constant (Pmode,
3613 stack_pointer_rtx, offset));
3614 rtx reg = gen_rtx_REG (SImode, regno);
3615 MEM_VOLATILE_P (mem) = volatile_p;
3616 emit_insn (gen_movsi (tmp, reg));
3617 insn = emit_frame_insn (gen_movsi (mem, tmp));
3618 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3619 gen_rtx_SET (mem, reg));
3621 break;
3623 case floating:
3625 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3626 rtx mem
3627 = gen_frame_mem (SFmode,
3628 plus_constant (Pmode,
3629 stack_pointer_rtx, offset));
3630 rtx reg = gen_rtx_REG (SFmode, regno);
3631 MEM_VOLATILE_P (mem) = volatile_p;
3632 emit_insn (gen_movsf (tmp, reg));
3633 insn = emit_frame_insn (gen_movsf (mem, tmp));
3634 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3635 gen_rtx_SET (mem, reg));
3637 break;
3639 default:
3640 break;
3646 /* This function generates the code for function entry. */
3648 void
3649 visium_expand_prologue (void)
3651 const int frame_size = visium_compute_frame_size (get_frame_size ());
3652 const int save_area_size = current_frame_info.save_area_size;
3653 const int reg_size1 = current_frame_info.reg_size1;
3654 const int max_reg1 = current_frame_info.max_reg1;
3655 const int reg_size2 = current_frame_info.reg_size2;
3656 const int var_size = current_frame_info.var_size;
3657 const int save_fp = current_frame_info.save_fp;
3658 const int save_lr = current_frame_info.save_lr;
3659 const int lr_slot = current_frame_info.lr_slot;
3660 const int local_frame_offset
3661 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3662 const int combine = current_frame_info.combine;
3663 int reg_size;
3664 int first_reg;
3665 int fsize;
3667 /* Save the frame size for future references. */
3668 visium_frame_size = frame_size;
3670 if (flag_stack_usage_info)
3671 current_function_static_stack_size = frame_size;
3673 /* If the registers have to be stacked in 2 blocks, stack the first one. */
3674 if (reg_size2)
3676 visium_save_regs (reg_size1 + save_area_size, reg_size1, 0, max_reg1);
3677 reg_size = reg_size2;
3678 first_reg = max_reg1 + 1;
3679 fsize = local_frame_offset + var_size + reg_size2;
3681 else
3683 reg_size = reg_size1;
3684 first_reg = 0;
3685 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
3688 /* If we can't combine register stacking with variable allocation, partially
3689 allocate and stack the (remaining) registers now. */
3690 if (reg_size && !combine)
3691 visium_save_regs (fsize - local_frame_offset - var_size, reg_size,
3692 first_reg, FIRST_PSEUDO_REGISTER - 1);
3694 /* If we can combine register stacking with variable allocation, fully
3695 allocate and stack the (remaining) registers now. */
3696 if (reg_size && combine)
3697 visium_save_regs (fsize, local_frame_offset + var_size + reg_size,
3698 first_reg, FIRST_PSEUDO_REGISTER - 1);
3700 /* Otherwise space may still need to be allocated for the variables. */
3701 else if (fsize)
3703 const int alloc_size = reg_size ? local_frame_offset + var_size : fsize;
3705 if (alloc_size > 65535)
3707 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM), insn;
3708 emit_insn (gen_movsi (tmp, GEN_INT (alloc_size)));
3709 insn = emit_frame_insn (gen_subsi3_flags (stack_pointer_rtx,
3710 stack_pointer_rtx,
3711 tmp));
3712 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3713 gen_rtx_SET (stack_pointer_rtx,
3714 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3715 GEN_INT (-alloc_size))));
3717 else
3718 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx,
3719 stack_pointer_rtx,
3720 GEN_INT (-alloc_size)));
3723 if (save_fp)
3724 emit_frame_insn (gen_movsi (gen_frame_mem (SImode, stack_pointer_rtx),
3725 hard_frame_pointer_rtx));
3727 if (frame_pointer_needed)
3728 emit_frame_insn (gen_stack_save ());
3730 if (save_lr)
3732 rtx base_rtx, mem;
3734 /* Normally the frame pointer and link register get saved via
3735 write.l (sp),fp
3736 move.l fp,sp
3737 write.l 1(sp),r21
3739 Indexing off sp rather than fp to store the link register
3740 avoids presenting the instruction scheduler with an initial
3741 pipeline hazard. If however the frame is needed for eg.
3742 __builtin_return_address which needs to retrieve the saved
3743 value of the link register from the stack at fp + 4 then
3744 indexing from sp can confuse the dataflow, causing the link
3745 register to be retrieved before it has been saved. */
3746 if (cfun->machine->frame_needed)
3747 base_rtx = hard_frame_pointer_rtx;
3748 else
3749 base_rtx = stack_pointer_rtx;
3751 mem = gen_frame_mem (SImode,
3752 plus_constant (Pmode,
3753 base_rtx, save_fp * UNITS_PER_WORD));
3754 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, LINK_REGNUM)));
3758 static GTY(()) rtx cfa_restores;
3760 /* Queue a REG_CFA_RESTORE note until next stack manipulation insn. */
3762 static void
3763 visium_add_cfa_restore_note (rtx reg)
3765 cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
3768 /* Add queued REG_CFA_RESTORE notes to INSN, if any. */
3770 static void
3771 visium_add_queued_cfa_restore_notes (rtx insn)
3773 rtx last;
3774 if (!cfa_restores)
3775 return;
3776 for (last = cfa_restores; XEXP (last, 1); last = XEXP (last, 1))
3778 XEXP (last, 1) = REG_NOTES (insn);
3779 REG_NOTES (insn) = cfa_restores;
3780 cfa_restores = NULL_RTX;
3783 /* Restore the registers LOW_REGNO to HIGH_REGNO from the save area at OFFSET
3784 from the stack pointer and pop DEALLOC bytes off the stack. */
3786 static void
3787 visium_restore_regs (int dealloc, int offset, int high_regno, int low_regno)
3789 /* If this is an interrupt handler function, then mark the register
3790 restores as volatile. This will prevent the instruction scheduler
3791 from scrambling the order of register restores. */
3792 const int volatile_p = current_frame_info.interrupt;
3793 int r30_offset = -1;
3794 int regno;
3796 for (regno = high_regno; regno >= low_regno; --regno)
3798 enum reg_type reg_type = GET_REG_TYPE (regno);
3799 int mask_bit = 1 << (regno - first_regno[reg_type]);
3801 if (current_frame_info.mask[reg_type] & mask_bit)
3803 switch (reg_type)
3805 case general:
3806 /* Postpone restoring the interrupted context registers
3807 until last, since they need to be preceded by a dsi. */
3808 if (regno == 29)
3810 else if (regno == 30)
3811 r30_offset = offset;
3812 else
3814 rtx mem
3815 = gen_frame_mem (SImode,
3816 plus_constant (Pmode,
3817 stack_pointer_rtx,
3818 offset));
3819 rtx reg = gen_rtx_REG (SImode, regno);
3820 MEM_VOLATILE_P (mem) = volatile_p;
3821 emit_insn (gen_movsi (reg, mem));
3822 visium_add_cfa_restore_note (reg);
3824 break;
3826 case mdb:
3828 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3829 rtx mem
3830 = gen_frame_mem (DImode,
3831 plus_constant (Pmode,
3832 stack_pointer_rtx, offset));
3833 rtx reg = gen_rtx_REG (DImode, regno);
3834 MEM_VOLATILE_P (mem) = volatile_p;
3835 emit_insn (gen_movdi (tmp, mem));
3836 emit_insn (gen_movdi (reg, tmp));
3837 /* Do not generate CFI if in interrupt handler. */
3838 if (!volatile_p)
3839 visium_add_cfa_restore_note (reg);
3841 break;
3843 case mdc:
3845 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3846 rtx mem
3847 = gen_frame_mem (SImode,
3848 plus_constant (Pmode,
3849 stack_pointer_rtx, offset));
3850 rtx reg = gen_rtx_REG (SImode, regno);
3851 MEM_VOLATILE_P (mem) = volatile_p;
3852 emit_insn (gen_movsi (tmp, mem));
3853 emit_insn (gen_movsi (reg, tmp));
3854 visium_add_cfa_restore_note (reg);
3856 break;
3858 case floating:
3860 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3861 rtx mem
3862 = gen_frame_mem (SFmode,
3863 plus_constant (Pmode,
3864 stack_pointer_rtx, offset));
3865 rtx reg = gen_rtx_REG (SFmode, regno);
3866 MEM_VOLATILE_P (mem) = volatile_p;
3867 emit_insn (gen_movsf (tmp, mem));
3868 emit_insn (gen_movsf (reg, tmp));
3869 visium_add_cfa_restore_note (reg);
3871 break;
3873 default:
3874 break;
3877 offset += reg_type_size[reg_type];
3881 /* If the interrupted context needs to be restored, precede the
3882 restores of r29 and r30 by a dsi. */
3883 if (r30_offset >= 0)
3885 emit_insn (gen_dsi ());
3886 emit_move_insn (gen_rtx_REG (SImode, 30),
3887 gen_frame_mem (SImode,
3888 plus_constant (Pmode,
3889 stack_pointer_rtx,
3890 r30_offset)));
3891 emit_move_insn (gen_rtx_REG (SImode, 29),
3892 gen_frame_mem (SImode,
3893 plus_constant (Pmode,
3894 stack_pointer_rtx,
3895 r30_offset + 4)));
3898 /* Deallocate the stack space. */
3899 rtx insn = emit_frame_insn (gen_stack_pop (GEN_INT (dealloc)));
3900 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3901 gen_rtx_SET (stack_pointer_rtx,
3902 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3903 GEN_INT (dealloc))));
3904 visium_add_queued_cfa_restore_notes (insn);
3907 /* This function generates the code for function exit. */
3909 void
3910 visium_expand_epilogue (void)
3912 const int save_area_size = current_frame_info.save_area_size;
3913 const int reg_size1 = current_frame_info.reg_size1;
3914 const int max_reg1 = current_frame_info.max_reg1;
3915 const int reg_size2 = current_frame_info.reg_size2;
3916 const int var_size = current_frame_info.var_size;
3917 const int restore_fp = current_frame_info.save_fp;
3918 const int restore_lr = current_frame_info.save_lr;
3919 const int lr_slot = current_frame_info.lr_slot;
3920 const int local_frame_offset
3921 = (restore_fp + restore_lr + lr_slot) * UNITS_PER_WORD;
3922 const int combine = current_frame_info.combine;
3923 int reg_size;
3924 int last_reg;
3925 int fsize;
3927 /* Do not bother restoring the stack pointer if it hasn't been changed in
3928 the function since it was saved _after_ the allocation of the frame. */
3929 if (!crtl->sp_is_unchanging)
3930 emit_insn (gen_stack_restore ());
3932 /* Restore the frame pointer if necessary. The usual code would be:
3934 move.l sp,fp
3935 read.l fp,(sp)
3937 but for the MCM this constitutes a stall/hazard so it is changed to:
3939 move.l sp,fp
3940 read.l fp,(fp)
3942 if the stack pointer has actually been restored. */
3943 if (restore_fp)
3945 rtx src;
3947 if (TARGET_MCM && !crtl->sp_is_unchanging)
3948 src = gen_frame_mem (SImode, hard_frame_pointer_rtx);
3949 else
3950 src = gen_frame_mem (SImode, stack_pointer_rtx);
3952 rtx insn = emit_frame_insn (gen_movsi (hard_frame_pointer_rtx, src));
3953 add_reg_note (insn, REG_CFA_ADJUST_CFA,
3954 gen_rtx_SET (stack_pointer_rtx,
3955 hard_frame_pointer_rtx));
3956 visium_add_cfa_restore_note (hard_frame_pointer_rtx);
3959 /* Restore the link register if necessary. */
3960 if (restore_lr)
3962 rtx mem = gen_frame_mem (SImode,
3963 plus_constant (Pmode,
3964 stack_pointer_rtx,
3965 restore_fp * UNITS_PER_WORD));
3966 rtx reg = gen_rtx_REG (SImode, LINK_REGNUM);
3967 emit_insn (gen_movsi (reg, mem));
3968 visium_add_cfa_restore_note (reg);
3971 /* If we have two blocks of registers, deal with the second one first. */
3972 if (reg_size2)
3974 reg_size = reg_size2;
3975 last_reg = max_reg1 + 1;
3976 fsize = local_frame_offset + var_size + reg_size2;
3978 else
3980 reg_size = reg_size1;
3981 last_reg = 0;
3982 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
3985 /* If the variable allocation could be combined with register stacking,
3986 restore the (remaining) registers and fully deallocate now. */
3987 if (reg_size && combine)
3988 visium_restore_regs (fsize, local_frame_offset + var_size,
3989 FIRST_PSEUDO_REGISTER - 1, last_reg);
3991 /* Otherwise deallocate the variables first. */
3992 else if (fsize)
3994 const int pop_size = reg_size ? local_frame_offset + var_size : fsize;
3995 rtx insn;
3997 if (pop_size > 65535)
3999 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4000 emit_move_insn (tmp, GEN_INT (pop_size));
4001 insn = emit_frame_insn (gen_stack_pop (tmp));
4003 else
4004 insn = emit_frame_insn (gen_stack_pop (GEN_INT (pop_size)));
4005 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4006 gen_rtx_SET (stack_pointer_rtx,
4007 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4008 GEN_INT (pop_size))));
4009 visium_add_queued_cfa_restore_notes (insn);
4012 /* If the variable allocation couldn't be combined with register stacking,
4013 restore the (remaining) registers now and partially deallocate. */
4014 if (reg_size && !combine)
4015 visium_restore_regs (fsize - local_frame_offset - var_size, 0,
4016 FIRST_PSEUDO_REGISTER - 1, last_reg);
4018 /* If the first block of registers has yet to be restored, do it now. */
4019 if (reg_size2)
4020 visium_restore_regs (reg_size1 + save_area_size, 0, max_reg1, 0);
4022 /* If this is an exception return, make the necessary stack adjustment. */
4023 if (crtl->calls_eh_return)
4024 emit_insn (gen_stack_pop (EH_RETURN_STACKADJ_RTX));
4027 /* Return true if it is appropriate to emit `return' instructions in the
4028 body of a function. */
4030 bool
4031 visium_can_use_return_insn_p (void)
4033 return reload_completed
4034 && visium_frame_size == 0
4035 && !visium_interrupt_function_p ();
4038 /* Return the register class required for an intermediate register used to
4039 copy a register of RCLASS from/to X. If no such intermediate register is
4040 required, return NO_REGS. If more than one such intermediate register is
4041 required, describe the one that is closest in the copy chain to the reload
4042 register. */
4044 static reg_class_t
4045 visium_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
4046 reg_class_t rclass,
4047 enum machine_mode mode ATTRIBUTE_UNUSED,
4048 secondary_reload_info *sri ATTRIBUTE_UNUSED)
4050 int regno = true_regnum (x);
4052 /* For MDB, MDC and FP_REGS, a general register is needed for a move to
4053 or from memory. */
4054 if (regno == -1 && (rclass == MDB || rclass == MDC || rclass == FP_REGS))
4055 return GENERAL_REGS;
4057 /* Moves between MDB, MDC and FP_REGS also require a general register. */
4058 else if (((regno == R_MDB || regno == R_MDC) && rclass == FP_REGS)
4059 || (FP_REGISTER_P (regno) && (rclass == MDB || rclass == MDC)))
4060 return GENERAL_REGS;
4062 /* Finally an (unlikely ?) move between MDB and MDC needs a general reg. */
4063 else if ((regno == R_MDB && rclass == MDC)
4064 || (rclass == MDB && regno == R_MDC))
4065 return GENERAL_REGS;
4067 return NO_REGS;
4070 /* Return true if pseudos that have been assigned to registers of RCLASS
4071 would likely be spilled because registers of RCLASS are needed for
4072 spill registers. */
4074 static bool
4075 visium_class_likely_spilled_p (reg_class_t rclass ATTRIBUTE_UNUSED)
4077 /* Return false for classes R1, R2 and R3, which are intended to be used
4078 only in the source code in conjunction with block move instructions. */
4079 return false;
4082 /* Return the register number if OP is a REG or a SUBREG of a REG, and
4083 INVALID_REGNUM in all the other cases. */
4085 unsigned int
4086 reg_or_subreg_regno (rtx op)
4088 unsigned int regno;
4090 if (GET_CODE (op) == REG)
4091 regno = REGNO (op);
4092 else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
4094 if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
4095 regno = subreg_regno (op);
4096 else
4097 regno = REGNO (SUBREG_REG (op));
4099 else
4100 regno = INVALID_REGNUM;
4102 return regno;
4105 #include "gt-visium.h"