]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/visium/visium.c
Update copyright years.
[thirdparty/gcc.git] / gcc / config / visium / visium.c
1 /* Output routines for Visium.
2 Copyright (C) 2002-2022 Free Software Foundation, Inc.
3 Contributed by C.Nettleton, J.P.Parkes and P.Garbett.
4
5 This file is part of GCC.
6
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.
11
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.
16
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/>. */
20
21 #define IN_TARGET_CODE 1
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "backend.h"
27 #include "target.h"
28 #include "rtl.h"
29 #include "tree.h"
30 #include "gimple-expr.h"
31 #include "df.h"
32 #include "memmodel.h"
33 #include "tm_p.h"
34 #include "stringpool.h"
35 #include "attribs.h"
36 #include "expmed.h"
37 #include "optabs.h"
38 #include "regs.h"
39 #include "emit-rtl.h"
40 #include "recog.h"
41 #include "diagnostic-core.h"
42 #include "alias.h"
43 #include "flags.h"
44 #include "fold-const.h"
45 #include "stor-layout.h"
46 #include "calls.h"
47 #include "varasm.h"
48 #include "output.h"
49 #include "insn-attr.h"
50 #include "explow.h"
51 #include "expr.h"
52 #include "gimplify.h"
53 #include "langhooks.h"
54 #include "reload.h"
55 #include "tm-constrs.h"
56 #include "tree-pass.h"
57 #include "context.h"
58 #include "builtins.h"
59 #include "opts.h"
60
61 /* This file should be included last. */
62 #include "target-def.h"
63
64 /* Enumeration of indexes into machine_libfunc_table. */
65 enum machine_libfunc_index
66 {
67 MLTI_long_int_memcpy,
68 MLTI_wrd_memcpy,
69 MLTI_byt_memcpy,
70
71 MLTI_long_int_memset,
72 MLTI_wrd_memset,
73 MLTI_byt_memset,
74
75 MLTI_set_trampoline_parity,
76
77 MLTI_MAX
78 };
79
80 struct GTY(()) machine_libfuncs
81 {
82 rtx table[MLTI_MAX];
83 };
84
85 /* The table of Visium-specific libfuncs. */
86 static GTY(()) struct machine_libfuncs visium_libfuncs;
87
88 #define vlt visium_libfuncs.table
89
90 /* Accessor macros for visium_libfuncs. */
91 #define long_int_memcpy_libfunc (vlt[MLTI_long_int_memcpy])
92 #define wrd_memcpy_libfunc (vlt[MLTI_wrd_memcpy])
93 #define byt_memcpy_libfunc (vlt[MLTI_byt_memcpy])
94 #define long_int_memset_libfunc (vlt[MLTI_long_int_memset])
95 #define wrd_memset_libfunc (vlt[MLTI_wrd_memset])
96 #define byt_memset_libfunc (vlt[MLTI_byt_memset])
97 #define set_trampoline_parity_libfunc (vlt[MLTI_set_trampoline_parity])
98
99 /* Machine specific function data. */
100 struct GTY (()) machine_function
101 {
102 /* Size of the frame of the function. */
103 int frame_size;
104
105 /* Size of the reg parm save area, non-zero only for functions with variable
106 argument list. We cannot use the crtl->args.pretend_args_size machinery
107 for this purpose because this size is added to virtual_incoming_args_rtx
108 to give the location of the first parameter passed by the caller on the
109 stack and virtual_incoming_args_rtx is also the location of the first
110 parameter on the stack. So crtl->args.pretend_args_size can be non-zero
111 only if the first non-register named parameter is not passed entirely on
112 the stack and this runs afoul of the need to have a reg parm save area
113 even with a variable argument list starting on the stack because of the
114 separate handling of general and floating-point registers. */
115 int reg_parm_save_area_size;
116
117 /* True if we have created an rtx which relies on the frame pointer. */
118 bool frame_needed;
119
120 /* True if we have exposed the flags register. From this moment on, we
121 cannot generate simple operations for integer registers. We could
122 use reload_completed for this purpose, but this would cripple the
123 postreload CSE and GCSE passes which run before postreload split. */
124 bool flags_exposed;
125 };
126
127 #define visium_frame_size cfun->machine->frame_size
128 #define visium_reg_parm_save_area_size cfun->machine->reg_parm_save_area_size
129 #define visium_frame_needed cfun->machine->frame_needed
130 #define visium_flags_exposed cfun->machine->flags_exposed
131
132 /* 1 if the next opcode is to be specially indented. */
133 int visium_indent_opcode = 0;
134
135 /* Register number used for long branches when LR isn't available. It
136 must be a call-used register since it isn't saved on function entry.
137 We do not care whether the branch is predicted or not on the GR6,
138 given how unlikely it is to have a long branch in a leaf function. */
139 static unsigned int long_branch_regnum = 31;
140
141 static tree visium_handle_interrupt_attr (tree *, tree, tree, int, bool *);
142 static inline bool current_function_saves_fp (void);
143 static inline bool current_function_saves_lr (void);
144 static inline bool current_function_has_lr_slot (void);
145
146 /* Supported attributes:
147 interrupt -- specifies this function is an interrupt handler. */
148 static const struct attribute_spec visium_attribute_table[] =
149 {
150 /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
151 affects_type_identity, handler, exclude } */
152 { "interrupt", 0, 0, true, false, false, false, visium_handle_interrupt_attr,
153 NULL},
154 { NULL, 0, 0, false, false, false, false, NULL, NULL },
155 };
156
157 static struct machine_function *visium_init_machine_status (void);
158
159 /* Target hooks and TARGET_INITIALIZER */
160
161 static bool visium_pass_by_reference (cumulative_args_t,
162 const function_arg_info &);
163
164 static rtx visium_function_arg (cumulative_args_t, const function_arg_info &);
165
166 static void visium_function_arg_advance (cumulative_args_t,
167 const function_arg_info &);
168
169 static bool visium_return_in_memory (const_tree, const_tree fntype);
170
171 static rtx visium_function_value (const_tree, const_tree fn_decl_or_type,
172 bool);
173
174 static rtx visium_libcall_value (machine_mode, const_rtx);
175
176 static void visium_setup_incoming_varargs (cumulative_args_t,
177 const function_arg_info &,
178 int *, int);
179
180 static void visium_va_start (tree valist, rtx nextarg);
181
182 static tree visium_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
183
184 static bool visium_function_ok_for_sibcall (tree, tree);
185
186 static bool visium_frame_pointer_required (void);
187
188 static tree visium_build_builtin_va_list (void);
189
190 static rtx_insn *visium_md_asm_adjust (vec<rtx> &, vec<rtx> &,
191 vec<machine_mode> &,
192 vec<const char *> &, vec<rtx> &,
193 HARD_REG_SET &, location_t);
194
195 static bool visium_legitimate_constant_p (machine_mode, rtx);
196
197 static bool visium_legitimate_address_p (machine_mode, rtx, bool);
198
199 static bool visium_print_operand_punct_valid_p (unsigned char);
200 static void visium_print_operand (FILE *, rtx, int);
201 static void visium_print_operand_address (FILE *, machine_mode, rtx);
202
203 static void visium_conditional_register_usage (void);
204
205 static rtx visium_legitimize_address (rtx, rtx, machine_mode);
206
207 static reg_class_t visium_secondary_reload (bool, rtx, reg_class_t,
208 machine_mode,
209 secondary_reload_info *);
210
211 static bool visium_class_likely_spilled_p (reg_class_t);
212
213 static void visium_trampoline_init (rtx, tree, rtx);
214
215 static int visium_issue_rate (void);
216
217 static int visium_adjust_priority (rtx_insn *, int);
218
219 static int visium_adjust_cost (rtx_insn *, int, rtx_insn *, int, unsigned int);
220
221 static int visium_register_move_cost (machine_mode, reg_class_t,
222 reg_class_t);
223
224 static int visium_memory_move_cost (machine_mode, reg_class_t, bool);
225
226 static bool visium_rtx_costs (rtx, machine_mode, int, int, int *, bool);
227
228 static void visium_option_override (void);
229
230 static void visium_init_libfuncs (void);
231
232 static unsigned int visium_reorg (void);
233
234 static unsigned int visium_hard_regno_nregs (unsigned int, machine_mode);
235
236 static bool visium_hard_regno_mode_ok (unsigned int, machine_mode);
237
238 static bool visium_modes_tieable_p (machine_mode, machine_mode);
239
240 static bool visium_can_change_mode_class (machine_mode, machine_mode,
241 reg_class_t);
242
243 static HOST_WIDE_INT visium_constant_alignment (const_tree, HOST_WIDE_INT);
244
245 /* Setup the global target hooks structure. */
246
247 #undef TARGET_MAX_ANCHOR_OFFSET
248 #define TARGET_MAX_ANCHOR_OFFSET 31
249
250 #undef TARGET_PASS_BY_REFERENCE
251 #define TARGET_PASS_BY_REFERENCE visium_pass_by_reference
252
253 #undef TARGET_FUNCTION_ARG
254 #define TARGET_FUNCTION_ARG visium_function_arg
255
256 #undef TARGET_FUNCTION_ARG_ADVANCE
257 #define TARGET_FUNCTION_ARG_ADVANCE visium_function_arg_advance
258
259 #undef TARGET_RETURN_IN_MEMORY
260 #define TARGET_RETURN_IN_MEMORY visium_return_in_memory
261
262 #undef TARGET_FUNCTION_VALUE
263 #define TARGET_FUNCTION_VALUE visium_function_value
264
265 #undef TARGET_LIBCALL_VALUE
266 #define TARGET_LIBCALL_VALUE visium_libcall_value
267
268 #undef TARGET_SETUP_INCOMING_VARARGS
269 #define TARGET_SETUP_INCOMING_VARARGS visium_setup_incoming_varargs
270
271 #undef TARGET_EXPAND_BUILTIN_VA_START
272 #define TARGET_EXPAND_BUILTIN_VA_START visium_va_start
273
274 #undef TARGET_BUILD_BUILTIN_VA_LIST
275 #define TARGET_BUILD_BUILTIN_VA_LIST visium_build_builtin_va_list
276
277 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
278 #define TARGET_GIMPLIFY_VA_ARG_EXPR visium_gimplify_va_arg
279
280 #undef TARGET_LEGITIMATE_CONSTANT_P
281 #define TARGET_LEGITIMATE_CONSTANT_P visium_legitimate_constant_p
282
283 #undef TARGET_LRA_P
284 #define TARGET_LRA_P hook_bool_void_false
285
286 #undef TARGET_LEGITIMATE_ADDRESS_P
287 #define TARGET_LEGITIMATE_ADDRESS_P visium_legitimate_address_p
288
289 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
290 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P visium_print_operand_punct_valid_p
291
292 #undef TARGET_PRINT_OPERAND
293 #define TARGET_PRINT_OPERAND visium_print_operand
294
295 #undef TARGET_PRINT_OPERAND_ADDRESS
296 #define TARGET_PRINT_OPERAND_ADDRESS visium_print_operand_address
297
298 #undef TARGET_ATTRIBUTE_TABLE
299 #define TARGET_ATTRIBUTE_TABLE visium_attribute_table
300
301 #undef TARGET_ADDRESS_COST
302 #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
303
304 #undef TARGET_STRICT_ARGUMENT_NAMING
305 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
306
307 #undef TARGET_SCHED_ISSUE_RATE
308 #define TARGET_SCHED_ISSUE_RATE visium_issue_rate
309
310 #undef TARGET_SCHED_ADJUST_PRIORITY
311 #define TARGET_SCHED_ADJUST_PRIORITY visium_adjust_priority
312
313 #undef TARGET_SCHED_ADJUST_COST
314 #define TARGET_SCHED_ADJUST_COST visium_adjust_cost
315
316 #undef TARGET_MEMORY_MOVE_COST
317 #define TARGET_MEMORY_MOVE_COST visium_memory_move_cost
318
319 #undef TARGET_REGISTER_MOVE_COST
320 #define TARGET_REGISTER_MOVE_COST visium_register_move_cost
321
322 #undef TARGET_RTX_COSTS
323 #define TARGET_RTX_COSTS visium_rtx_costs
324
325 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
326 #define TARGET_FUNCTION_OK_FOR_SIBCALL visium_function_ok_for_sibcall
327
328 #undef TARGET_FRAME_POINTER_REQUIRED
329 #define TARGET_FRAME_POINTER_REQUIRED visium_frame_pointer_required
330
331 #undef TARGET_SECONDARY_RELOAD
332 #define TARGET_SECONDARY_RELOAD visium_secondary_reload
333
334 #undef TARGET_CLASS_LIKELY_SPILLED_P
335 #define TARGET_CLASS_LIKELY_SPILLED_P visium_class_likely_spilled_p
336
337 #undef TARGET_LEGITIMIZE_ADDRESS
338 #define TARGET_LEGITIMIZE_ADDRESS visium_legitimize_address
339
340 #undef TARGET_OPTION_OVERRIDE
341 #define TARGET_OPTION_OVERRIDE visium_option_override
342
343 #undef TARGET_INIT_LIBFUNCS
344 #define TARGET_INIT_LIBFUNCS visium_init_libfuncs
345
346 #undef TARGET_CONDITIONAL_REGISTER_USAGE
347 #define TARGET_CONDITIONAL_REGISTER_USAGE visium_conditional_register_usage
348
349 #undef TARGET_TRAMPOLINE_INIT
350 #define TARGET_TRAMPOLINE_INIT visium_trampoline_init
351
352 #undef TARGET_MD_ASM_ADJUST
353 #define TARGET_MD_ASM_ADJUST visium_md_asm_adjust
354
355 #undef TARGET_FLAGS_REGNUM
356 #define TARGET_FLAGS_REGNUM FLAGS_REGNUM
357
358 #undef TARGET_HARD_REGNO_NREGS
359 #define TARGET_HARD_REGNO_NREGS visium_hard_regno_nregs
360
361 #undef TARGET_HARD_REGNO_MODE_OK
362 #define TARGET_HARD_REGNO_MODE_OK visium_hard_regno_mode_ok
363
364 #undef TARGET_MODES_TIEABLE_P
365 #define TARGET_MODES_TIEABLE_P visium_modes_tieable_p
366
367 #undef TARGET_CAN_CHANGE_MODE_CLASS
368 #define TARGET_CAN_CHANGE_MODE_CLASS visium_can_change_mode_class
369
370 #undef TARGET_CONSTANT_ALIGNMENT
371 #define TARGET_CONSTANT_ALIGNMENT visium_constant_alignment
372
373 #undef TARGET_HAVE_SPECULATION_SAFE_VALUE
374 #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
375
376 struct gcc_target targetm = TARGET_INITIALIZER;
377
378 namespace {
379
380 const pass_data pass_data_visium_reorg =
381 {
382 RTL_PASS, /* type */
383 "mach2", /* name */
384 OPTGROUP_NONE, /* optinfo_flags */
385 TV_MACH_DEP, /* tv_id */
386 0, /* properties_required */
387 0, /* properties_provided */
388 0, /* properties_destroyed */
389 0, /* todo_flags_start */
390 0, /* todo_flags_finish */
391 };
392
393 class pass_visium_reorg : public rtl_opt_pass
394 {
395 public:
396 pass_visium_reorg(gcc::context *ctxt)
397 : rtl_opt_pass(pass_data_visium_reorg, ctxt)
398 {}
399
400 /* opt_pass methods: */
401 virtual unsigned int execute (function *)
402 {
403 return visium_reorg ();
404 }
405
406 }; // class pass_work_around_errata
407
408 } // anon namespace
409
410 rtl_opt_pass *
411 make_pass_visium_reorg (gcc::context *ctxt)
412 {
413 return new pass_visium_reorg (ctxt);
414 }
415
416 /* Options override for Visium. */
417
418 static void
419 visium_option_override (void)
420 {
421 if (flag_pic == 1)
422 warning (OPT_fpic, "%<-fpic%> is not supported");
423 if (flag_pic == 2)
424 warning (OPT_fPIC, "%<-fPIC%> is not supported");
425
426 /* MCM is the default in the GR5/GR6 era. */
427 target_flags |= MASK_MCM;
428
429 /* FPU is the default with MCM, but don't override an explicit option. */
430 if ((target_flags_explicit & MASK_FPU) == 0)
431 target_flags |= MASK_FPU;
432
433 /* The supervisor mode is the default. */
434 if ((target_flags_explicit & MASK_SV_MODE) == 0)
435 target_flags |= MASK_SV_MODE;
436
437 /* The GR6 has the Block Move Instructions and an IEEE-compliant FPU. */
438 if (visium_cpu_and_features == PROCESSOR_GR6)
439 {
440 target_flags |= MASK_BMI;
441 if (target_flags & MASK_FPU)
442 target_flags |= MASK_FPU_IEEE;
443 }
444
445 /* Set -mtune from -mcpu if not specified. */
446 if (!OPTION_SET_P (visium_cpu))
447 visium_cpu = visium_cpu_and_features;
448
449 /* Align functions on 256-byte (32-quadword) for GR5 and 64-byte (8-quadword)
450 boundaries for GR6 so they start a new burst mode window. */
451 if (flag_align_functions && !str_align_functions)
452 {
453 if (visium_cpu == PROCESSOR_GR6)
454 str_align_functions = "64";
455 else
456 str_align_functions = "256";
457
458 /* Allow the size of compilation units to double because of inlining.
459 In practice the global size of the object code is hardly affected
460 because the additional instructions will take up the padding. */
461 SET_OPTION_IF_UNSET (&global_options, &global_options_set,
462 param_inline_unit_growth, 100);
463 }
464
465 /* Likewise for loops. */
466 if (flag_align_loops && !str_align_loops)
467 {
468 if (visium_cpu == PROCESSOR_GR6)
469 str_align_loops = "64";
470 else
471 {
472 /* But not if they are too far away from a 256-byte boundary. */
473 str_align_loops = "256:32:8";
474 }
475 }
476
477 /* Align all jumps on quadword boundaries for the burst mode, and even
478 on 8-quadword boundaries for GR6 so they start a new window. */
479 if (flag_align_jumps && !str_align_jumps)
480 {
481 if (visium_cpu == PROCESSOR_GR6)
482 str_align_jumps = "64";
483 else
484 str_align_jumps = "8";
485 }
486 }
487
488 /* Register the Visium-specific libfuncs with the middle-end. */
489
490 static void
491 visium_init_libfuncs (void)
492 {
493 if (!TARGET_BMI)
494 long_int_memcpy_libfunc = init_one_libfunc ("__long_int_memcpy");
495 wrd_memcpy_libfunc = init_one_libfunc ("__wrd_memcpy");
496 byt_memcpy_libfunc = init_one_libfunc ("__byt_memcpy");
497
498 long_int_memset_libfunc = init_one_libfunc ("__long_int_memset");
499 wrd_memset_libfunc = init_one_libfunc ("__wrd_memset");
500 byt_memset_libfunc = init_one_libfunc ("__byt_memset");
501
502 set_trampoline_parity_libfunc = init_one_libfunc ("__set_trampoline_parity");
503 }
504
505 /* Return the number of instructions that can issue on the same cycle. */
506
507 static int
508 visium_issue_rate (void)
509 {
510 switch (visium_cpu)
511 {
512 case PROCESSOR_GR5:
513 return 1;
514
515 case PROCESSOR_GR6:
516 return 2;
517
518 default:
519 gcc_unreachable ();
520 }
521 }
522
523 /* Return the adjusted PRIORITY of INSN. */
524
525 static int
526 visium_adjust_priority (rtx_insn *insn, int priority)
527 {
528 /* On the GR5, we slightly increase the priority of writes in order to avoid
529 scheduling a read on the next cycle. This is necessary in addition to the
530 associated insn reservation because there are no data dependencies.
531 We also slightly increase the priority of reads from ROM in order to group
532 them as much as possible. These reads are a bit problematic because they
533 conflict with the instruction fetches, i.e. the data and instruction buses
534 tread on each other's toes when they are executed. */
535 if (visium_cpu == PROCESSOR_GR5
536 && reload_completed
537 && INSN_P (insn)
538 && recog_memoized (insn) >= 0)
539 {
540 enum attr_type attr_type = get_attr_type (insn);
541 if (attr_type == TYPE_REG_MEM
542 || (attr_type == TYPE_MEM_REG
543 && MEM_READONLY_P (SET_SRC (PATTERN (insn)))))
544 return priority + 1;
545 }
546
547 return priority;
548 }
549
550 /* Adjust the cost of a scheduling dependency. Return the new cost of
551 a dependency LINK of INSN on DEP_INSN. COST is the current cost. */
552
553 static int
554 visium_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost,
555 unsigned int)
556 {
557 enum attr_type attr_type;
558
559 /* Don't adjust costs for true dependencies as they are described with
560 bypasses. But we make an exception for the first scheduling pass to
561 help the subsequent postreload compare elimination pass. */
562 if (dep_type == REG_DEP_TRUE)
563 {
564 if (!reload_completed
565 && recog_memoized (insn) >= 0
566 && get_attr_type (insn) == TYPE_CMP)
567 {
568 rtx pat = PATTERN (insn);
569 gcc_assert (GET_CODE (pat) == SET);
570 rtx src = SET_SRC (pat);
571
572 /* Only the branches can be modified by the postreload compare
573 elimination pass, not the cstores because they accept only
574 unsigned comparison operators and they are eliminated if
575 one of the operands is zero. */
576 if (GET_CODE (src) == IF_THEN_ELSE
577 && XEXP (XEXP (src, 0), 1) == const0_rtx
578 && recog_memoized (dep_insn) >= 0)
579 {
580 enum attr_type dep_attr_type = get_attr_type (dep_insn);
581
582 /* The logical instructions use CCmode and thus work with any
583 comparison operator, whereas the arithmetic instructions use
584 CCNZmode and thus work with only a small subset. */
585 if (dep_attr_type == TYPE_LOGIC
586 || (dep_attr_type == TYPE_ARITH
587 && visium_nz_comparison_operator (XEXP (src, 0),
588 GET_MODE
589 (XEXP (src, 0)))))
590 return 0;
591 }
592 }
593
594 return cost;
595 }
596
597 if (recog_memoized (insn) < 0)
598 return 0;
599
600 attr_type = get_attr_type (insn);
601
602 /* Anti dependency: DEP_INSN reads a register that INSN writes some
603 cycles later. */
604 if (dep_type == REG_DEP_ANTI)
605 {
606 /* On the GR5, the latency of FP instructions needs to be taken into
607 account for every dependency involving a write. */
608 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
609 {
610 /* INSN is FLOAD. */
611 rtx pat = PATTERN (insn);
612 rtx dep_pat = PATTERN (dep_insn);
613
614 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
615 /* If this happens, we have to extend this to schedule
616 optimally. Return 0 for now. */
617 return 0;
618
619 if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat)))
620 {
621 if (recog_memoized (dep_insn) < 0)
622 return 0;
623
624 switch (get_attr_type (dep_insn))
625 {
626 case TYPE_FDIV:
627 case TYPE_FSQRT:
628 case TYPE_FTOI:
629 case TYPE_ITOF:
630 case TYPE_FP:
631 case TYPE_FMOVE:
632 /* A fload can't be issued until a preceding arithmetic
633 operation has finished if the target of the fload is
634 any of the sources (or destination) of the arithmetic
635 operation. Note that the latency may be (much)
636 greater than this if the preceding instruction
637 concerned is in a queue. */
638 return insn_default_latency (dep_insn);
639
640 default:
641 return 0;
642 }
643 }
644 }
645
646 /* On the GR6, we try to make sure that the link register is restored
647 sufficiently ahead of the return as to yield a correct prediction
648 from the branch predictor. By default there is no true dependency
649 but an anti dependency between them, so we simply reuse it. */
650 else if (attr_type == TYPE_RET && visium_cpu == PROCESSOR_GR6)
651 {
652 rtx dep_pat = PATTERN (dep_insn);
653 if (GET_CODE (dep_pat) == SET
654 && REG_P (SET_DEST (dep_pat))
655 && REGNO (SET_DEST (dep_pat)) == LINK_REGNUM)
656 return 8;
657 }
658
659 /* For other anti dependencies, the cost is 0. */
660 return 0;
661 }
662
663 /* Output dependency: DEP_INSN writes a register that INSN writes some
664 cycles later. */
665 else if (dep_type == REG_DEP_OUTPUT)
666 {
667 /* On the GR5, the latency of FP instructions needs to be taken into
668 account for every dependency involving a write. */
669 if (attr_type == TYPE_REG_FP && visium_cpu == PROCESSOR_GR5)
670 {
671 /* INSN is FLOAD. */
672 rtx pat = PATTERN (insn);
673 rtx dep_pat = PATTERN (dep_insn);
674
675 if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
676 /* If this happens, we have to extend this to schedule
677 optimally. Return 0 for now. */
678 return 0;
679
680 if (reg_mentioned_p (SET_DEST (pat), SET_DEST (dep_pat)))
681 {
682 if (recog_memoized (dep_insn) < 0)
683 return 0;
684
685 switch (get_attr_type (dep_insn))
686 {
687 case TYPE_FDIV:
688 case TYPE_FSQRT:
689 case TYPE_FTOI:
690 case TYPE_ITOF:
691 case TYPE_FP:
692 case TYPE_FMOVE:
693 /* A fload can't be issued until a preceding arithmetic
694 operation has finished if the target of the fload is
695 the destination of the arithmetic operation. Note that
696 the latency may be (much) greater than this if the
697 preceding instruction concerned is in a queue. */
698 return insn_default_latency (dep_insn);
699
700 default:
701 return 0;
702 }
703 }
704 }
705
706 /* For other output dependencies, the cost is 0. */
707 return 0;
708 }
709
710 return 0;
711 }
712
713 /* Handle an "interrupt_handler" attribute; arguments as in
714 struct attribute_spec.handler. */
715
716 static tree
717 visium_handle_interrupt_attr (tree *node, tree name,
718 tree args ATTRIBUTE_UNUSED,
719 int flags ATTRIBUTE_UNUSED,
720 bool *no_add_attrs)
721 {
722 if (TREE_CODE (*node) != FUNCTION_DECL)
723 {
724 warning (OPT_Wattributes, "%qE attribute only applies to functions",
725 name);
726 *no_add_attrs = true;
727 }
728 else if (!TARGET_SV_MODE)
729 {
730 error ("an interrupt handler cannot be compiled with %<-muser-mode%>");
731 *no_add_attrs = true;
732 }
733
734 return NULL_TREE;
735 }
736
737 /* Return non-zero if the current function is an interrupt function. */
738
739 int
740 visium_interrupt_function_p (void)
741 {
742 return
743 lookup_attribute ("interrupt",
744 DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
745 }
746
747 /* Conditionally modify the settings of the register file. */
748
749 static void
750 visium_conditional_register_usage (void)
751 {
752 /* If the supervisor mode is disabled, mask some general registers. */
753 if (!TARGET_SV_MODE)
754 {
755 if (visium_cpu_and_features == PROCESSOR_GR5)
756 {
757 fixed_regs[24] = 1;
758 fixed_regs[25] = 1;
759 fixed_regs[26] = 1;
760 fixed_regs[27] = 1;
761 fixed_regs[28] = 1;
762 call_used_regs[24] = 0;
763 call_used_regs[25] = 0;
764 call_used_regs[26] = 0;
765 call_used_regs[27] = 0;
766 call_used_regs[28] = 0;
767 }
768
769 fixed_regs[31] = 1;
770 call_used_regs[31] = 0;
771
772 /* We also need to change the long-branch register. */
773 if (visium_cpu_and_features == PROCESSOR_GR5)
774 long_branch_regnum = 20;
775 else
776 long_branch_regnum = 28;
777 }
778
779 /* If the FPU is disabled, mask the FP registers. */
780 if (!TARGET_FPU)
781 {
782 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
783 {
784 fixed_regs[i] = 1;
785 call_used_regs[i] = 0;
786 }
787 }
788 }
789
790 /* Prepend to CLOBBERS hard registers that are automatically clobbered for
791 an asm We do this for the FLAGS to maintain source compatibility with
792 the original cc0-based compiler. */
793
794 static rtx_insn *
795 visium_md_asm_adjust (vec<rtx> & /*outputs*/, vec<rtx> & /*inputs*/,
796 vec<machine_mode> & /*input_modes*/,
797 vec<const char *> & /*constraints*/, vec<rtx> &clobbers,
798 HARD_REG_SET &clobbered_regs, location_t /*loc*/)
799 {
800 clobbers.safe_push (gen_rtx_REG (CCmode, FLAGS_REGNUM));
801 SET_HARD_REG_BIT (clobbered_regs, FLAGS_REGNUM);
802 return NULL;
803 }
804
805 /* Return true if X is a legitimate constant for a MODE immediate operand.
806 X is guaranteed to satisfy the CONSTANT_P predicate. */
807
808 static bool
809 visium_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED,
810 rtx x ATTRIBUTE_UNUSED)
811 {
812 return true;
813 }
814
815 /* Compute the alignment for a variable. The alignment of an aggregate is
816 set to be at least that of a scalar less than or equal to it in size. */
817
818 unsigned int
819 visium_data_alignment (tree type, unsigned int align)
820 {
821 if (AGGREGATE_TYPE_P (type)
822 && TYPE_SIZE (type)
823 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && align < 32)
824 {
825 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 32)
826 return 32;
827
828 if (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 && align < 16)
829 return 16;
830 }
831
832 return align;
833 }
834
835 /* Implement TARGET_CONSTANT_ALIGNMENT. */
836
837 static HOST_WIDE_INT
838 visium_constant_alignment (const_tree exp, HOST_WIDE_INT align)
839 {
840 return visium_data_alignment (TREE_TYPE (exp), align);
841 }
842
843 /* Helper function for HARD_REGNO_RENAME_OK (FROM, TO). Return non-zero if
844 it is OK to rename a hard register FROM to another hard register TO. */
845
846 int
847 visium_hard_regno_rename_ok (unsigned int from ATTRIBUTE_UNUSED,
848 unsigned int to)
849 {
850 /* If the function doesn't save LR, then the long-branch register will be
851 used for long branches so we need to know whether it is live before the
852 frame layout is computed. */
853 if (!current_function_saves_lr () && to == long_branch_regnum)
854 return 0;
855
856 /* Interrupt functions can only use registers that have already been
857 saved by the prologue, even if they would normally be call-clobbered. */
858 if (crtl->is_leaf
859 && !df_regs_ever_live_p (to)
860 && visium_interrupt_function_p ())
861 return 0;
862
863 return 1;
864 }
865
866 /* Implement TARGET_HARD_REGNO_NREGS. */
867
868 static unsigned int
869 visium_hard_regno_nregs (unsigned int regno, machine_mode mode)
870 {
871 if (regno == MDB_REGNUM)
872 return CEIL (GET_MODE_SIZE (mode), 2 * UNITS_PER_WORD);
873 return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
874 }
875
876 /* Implement TARGET_HARD_REGNO_MODE_OK.
877
878 Modes with sizes which cross from the one register class to the
879 other cannot be allowed. Only single floats are allowed in the
880 floating point registers, and only fixed point values in the EAM
881 registers. */
882
883 static bool
884 visium_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
885 {
886 if (GP_REGISTER_P (regno))
887 return GP_REGISTER_P (end_hard_regno (mode, regno) - 1);
888
889 if (FP_REGISTER_P (regno))
890 return mode == SFmode || (mode == SImode && TARGET_FPU_IEEE);
891
892 return (GET_MODE_CLASS (mode) == MODE_INT
893 && visium_hard_regno_nregs (regno, mode) == 1);
894 }
895
896 /* Implement TARGET_MODES_TIEABLE_P. */
897
898 static bool
899 visium_modes_tieable_p (machine_mode mode1, machine_mode mode2)
900 {
901 return (GET_MODE_CLASS (mode1) == MODE_INT
902 && GET_MODE_CLASS (mode2) == MODE_INT);
903 }
904
905 /* Return true if it is ok to do sibling call optimization for the specified
906 call expression EXP. DECL will be the called function, or NULL if this
907 is an indirect call. */
908
909 static bool
910 visium_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
911 tree exp ATTRIBUTE_UNUSED)
912 {
913 return !visium_interrupt_function_p ();
914 }
915
916 /* Prepare operands for a move define_expand in MODE. */
917
918 void
919 prepare_move_operands (rtx *operands, machine_mode mode)
920 {
921 /* If the output is not a register, the input must be. */
922 if (GET_CODE (operands[0]) == MEM && !reg_or_0_operand (operands[1], mode))
923 operands[1] = force_reg (mode, operands[1]);
924 }
925
926 /* Return true if the operands are valid for a simple move insn. */
927
928 bool
929 ok_for_simple_move_operands (rtx *operands, machine_mode mode)
930 {
931 /* One of the operands must be a register. */
932 if (!register_operand (operands[0], mode)
933 && !reg_or_0_operand (operands[1], mode))
934 return false;
935
936 /* Once the flags are exposed, no simple moves between integer registers. */
937 if (visium_flags_exposed
938 && gpc_reg_operand (operands[0], mode)
939 && gpc_reg_operand (operands[1], mode))
940 return false;
941
942 return true;
943 }
944
945 /* Return true if the operands are valid for a simple move strict insn. */
946
947 bool
948 ok_for_simple_move_strict_operands (rtx *operands, machine_mode mode)
949 {
950 /* Once the flags are exposed, no simple moves between integer registers.
951 Note that, in QImode only, a zero source counts as an integer register
952 since it will be emitted as r0. */
953 if (visium_flags_exposed
954 && gpc_reg_operand (operands[0], mode)
955 && (gpc_reg_operand (operands[1], mode)
956 || (mode == QImode && operands[1] == const0_rtx)))
957 return false;
958
959 return true;
960 }
961
962 /* Return true if the operands are valid for a simple arithmetic or logical
963 insn. */
964
965 bool
966 ok_for_simple_arith_logic_operands (rtx *, machine_mode)
967 {
968 /* Once the flags are exposed, no simple arithmetic or logical operations
969 between integer registers. */
970 return !visium_flags_exposed;
971 }
972
973 /* Return non-zero if a branch or call instruction will be emitting a nop
974 into its delay slot. */
975
976 int
977 empty_delay_slot (rtx_insn *insn)
978 {
979 rtx seq;
980
981 /* If no previous instruction (should not happen), return true. */
982 if (PREV_INSN (insn) == NULL)
983 return 1;
984
985 seq = NEXT_INSN (PREV_INSN (insn));
986 if (GET_CODE (PATTERN (seq)) == SEQUENCE)
987 return 0;
988
989 return 1;
990 }
991
992 /* Wrapper around single_set which returns the second SET of a pair if the
993 first SET is to the flags register. */
994
995 static rtx
996 single_set_and_flags (rtx_insn *insn)
997 {
998 if (multiple_sets (insn))
999 {
1000 rtx pat = PATTERN (insn);
1001 if (XVECLEN (pat, 0) == 2
1002 && GET_CODE (XVECEXP (pat, 0, 0)) == SET
1003 && REG_P (SET_DEST (XVECEXP (pat, 0, 0)))
1004 && REGNO (SET_DEST (XVECEXP (pat, 0, 0))) == FLAGS_REGNUM)
1005 return XVECEXP (pat, 0, 1);
1006 }
1007
1008 return single_set (insn);
1009 }
1010
1011 /* This is called with OUT_INSN an instruction setting a (base) register
1012 and IN_INSN a read or a write. Return 1 if these instructions together
1013 constitute a pipeline hazard.
1014
1015 On the original architecture, a pipeline data hazard occurs when the Dest
1016 of one instruction becomes the SrcA for an immediately following READ or
1017 WRITE instruction with a non-zero index (indexing occurs at the decode
1018 stage and so a NOP must be inserted in-between for this to work).
1019
1020 An example is:
1021
1022 move.l r2,r1
1023 read.l r4,10(r2)
1024
1025 On the MCM, the non-zero index condition is lifted but the hazard is
1026 patched up by the hardware through the injection of wait states:
1027
1028 move.l r2,r1
1029 read.l r4,(r2)
1030
1031 We nevertheless try to schedule instructions around this. */
1032
1033 int
1034 gr5_hazard_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
1035 {
1036 rtx out_set, in_set, dest, memexpr;
1037 unsigned int out_reg, in_reg;
1038
1039 /* A CALL is storage register class, but the link register is of no
1040 interest here. */
1041 if (GET_CODE (out_insn) == CALL_INSN)
1042 return 0;
1043
1044 out_set = single_set_and_flags (out_insn);
1045 dest = SET_DEST (out_set);
1046
1047 /* Should be no stall/hazard if OUT_INSN is MEM := ???. This only
1048 occurs prior to reload. */
1049 if (GET_CODE (dest) == MEM)
1050 return 0;
1051
1052 if (GET_CODE (dest) == STRICT_LOW_PART)
1053 dest = XEXP (dest, 0);
1054 if (GET_CODE (dest) == SUBREG)
1055 dest = SUBREG_REG (dest);
1056 out_reg = REGNO (dest);
1057
1058 in_set = single_set_and_flags (in_insn);
1059
1060 /* If IN_INSN is MEM := MEM, it's the source that counts. */
1061 if (GET_CODE (SET_SRC (in_set)) == MEM)
1062 memexpr = XEXP (SET_SRC (in_set), 0);
1063 else
1064 memexpr = XEXP (SET_DEST (in_set), 0);
1065
1066 if (GET_CODE (memexpr) == PLUS)
1067 {
1068 memexpr = XEXP (memexpr, 0);
1069 if (GET_CODE (memexpr) == SUBREG)
1070 in_reg = REGNO (SUBREG_REG (memexpr));
1071 else
1072 in_reg = REGNO (memexpr);
1073
1074 if (in_reg == out_reg)
1075 return 1;
1076 }
1077 else if (TARGET_MCM)
1078 {
1079 if (GET_CODE (memexpr) == STRICT_LOW_PART)
1080 memexpr = XEXP (memexpr, 0);
1081 if (GET_CODE (memexpr) == SUBREG)
1082 memexpr = SUBREG_REG (memexpr);
1083 in_reg = REGNO (memexpr);
1084
1085 if (in_reg == out_reg)
1086 return 1;
1087 }
1088
1089 return 0;
1090 }
1091
1092 /* Return true if INSN is an empty asm instruction. */
1093
1094 static bool
1095 empty_asm_p (rtx insn)
1096 {
1097 rtx body = PATTERN (insn);
1098 const char *templ;
1099
1100 if (GET_CODE (body) == ASM_INPUT)
1101 templ = XSTR (body, 0);
1102 else if (asm_noperands (body) >= 0)
1103 templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
1104 else
1105 templ = NULL;
1106
1107 return (templ && templ[0] == '\0');
1108 }
1109
1110 /* Insert a NOP immediately before INSN wherever there is a pipeline hazard.
1111 LAST_REG records the register set in the last insn and LAST_INSN_CALL
1112 records whether the last insn was a call insn. */
1113
1114 static void
1115 gr5_avoid_hazard (rtx_insn *insn, unsigned int *last_reg, bool *last_insn_call)
1116 {
1117 unsigned int dest_reg = 0;
1118 rtx set;
1119
1120 switch (GET_CODE (insn))
1121 {
1122 case CALL_INSN:
1123 *last_reg = 0;
1124 *last_insn_call = true;
1125 return;
1126
1127 case JUMP_INSN:
1128 /* If this is an empty asm, just skip it. */
1129 if (!empty_asm_p (insn))
1130 {
1131 *last_reg = 0;
1132 *last_insn_call = false;
1133 }
1134 return;
1135
1136 case INSN:
1137 /* If this is an empty asm, just skip it. */
1138 if (empty_asm_p (insn))
1139 return;
1140 break;
1141
1142 default:
1143 return;
1144 }
1145
1146 set = single_set_and_flags (insn);
1147 if (set != NULL_RTX)
1148 {
1149 rtx dest = SET_DEST (set);
1150 const bool double_p = GET_MODE_SIZE (GET_MODE (dest)) > UNITS_PER_WORD;
1151 rtx memrtx = NULL;
1152
1153 if (GET_CODE (SET_SRC (set)) == MEM)
1154 {
1155 memrtx = XEXP (SET_SRC (set), 0);
1156 if (GET_CODE (dest) == STRICT_LOW_PART)
1157 dest = XEXP (dest, 0);
1158 if (REG_P (dest))
1159 dest_reg = REGNO (dest);
1160
1161 /* If this is a DI or DF mode memory to register
1162 copy, then if rd = rs we get
1163
1164 rs + 1 := 1[rs]
1165 rs := [rs]
1166
1167 otherwise the order is
1168
1169 rd := [rs]
1170 rd + 1 := 1[rs] */
1171
1172 if (double_p)
1173 {
1174 unsigned int base_reg;
1175
1176 if (GET_CODE (memrtx) == PLUS)
1177 base_reg = REGNO (XEXP (memrtx, 0));
1178 else
1179 base_reg = REGNO (memrtx);
1180
1181 if (dest_reg != base_reg)
1182 dest_reg++;
1183 }
1184 }
1185
1186 else if (GET_CODE (dest) == MEM)
1187 memrtx = XEXP (dest, 0);
1188
1189 else if (GET_MODE_CLASS (GET_MODE (dest)) != MODE_CC)
1190 {
1191 if (GET_CODE (dest) == STRICT_LOW_PART
1192 ||GET_CODE (dest) == ZERO_EXTRACT)
1193 dest = XEXP (dest, 0);
1194 dest_reg = REGNO (dest);
1195
1196 if (GET_CODE (SET_SRC (set)) == REG)
1197 {
1198 unsigned int srcreg = REGNO (SET_SRC (set));
1199
1200 /* Check for rs := rs, which will be deleted. */
1201 if (srcreg == dest_reg)
1202 return;
1203
1204 /* In the case of a DI or DF mode move from register to
1205 register there is overlap if rd = rs + 1 in which case
1206 the order of the copies is reversed :
1207
1208 rd + 1 := rs + 1;
1209 rd := rs */
1210
1211 if (double_p && dest_reg != srcreg + 1)
1212 dest_reg++;
1213 }
1214 }
1215
1216 /* If this is the delay slot of a call insn, any register it sets
1217 is not relevant. */
1218 if (*last_insn_call)
1219 dest_reg = 0;
1220
1221 /* If the previous insn sets the value of a register, and this insn
1222 uses a base register, check for the pipeline hazard where it is
1223 the same register in each case. */
1224 if (*last_reg != 0 && memrtx != NULL_RTX)
1225 {
1226 unsigned int reg = 0;
1227
1228 /* Check for an index (original architecture). */
1229 if (GET_CODE (memrtx) == PLUS)
1230 reg = REGNO (XEXP (memrtx, 0));
1231
1232 /* Check for an MCM target or rs := [rs], in DI or DF mode. */
1233 else if (TARGET_MCM || (double_p && REGNO (memrtx) == dest_reg))
1234 reg = REGNO (memrtx);
1235
1236 /* Remove any pipeline hazard by inserting a NOP. */
1237 if (reg == *last_reg)
1238 {
1239 if (dump_file)
1240 fprintf (dump_file,
1241 "inserting nop before insn %d\n", INSN_UID (insn));
1242 emit_insn_after (gen_hazard_nop (), prev_active_insn (insn));
1243 emit_insn_after (gen_blockage (), insn);
1244 }
1245 }
1246
1247 *last_reg = dest_reg;
1248 }
1249
1250 *last_insn_call = false;
1251 }
1252
1253 /* Go through the instruction stream and insert nops where necessary to avoid
1254 pipeline hazards. There are two cases:
1255
1256 1. On the original architecture, it is invalid to set the value of a
1257 (base) register and then use it in an address with a non-zero index
1258 in the next instruction.
1259
1260 2. On the MCM, setting the value of a (base) register and then using
1261 it in address (including with zero index) in the next instruction
1262 will result in a pipeline stall of 3 cycles. */
1263
1264 static void
1265 gr5_hazard_avoidance (void)
1266 {
1267 unsigned int last_reg = 0;
1268 bool last_insn_call = false;
1269 rtx_insn *insn;
1270
1271 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1272 if (INSN_P (insn))
1273 {
1274 rtx pat = PATTERN (insn);
1275
1276 if (GET_CODE (pat) == SEQUENCE)
1277 {
1278 for (int i = 0; i < XVECLEN (pat, 0); i++)
1279 gr5_avoid_hazard (as_a <rtx_insn *> (XVECEXP (pat, 0, i)),
1280 &last_reg, &last_insn_call);
1281 }
1282
1283 else if (GET_CODE (insn) == CALL_INSN)
1284 {
1285 /* This call is going to get a nop in its delay slot. */
1286 last_reg = 0;
1287 last_insn_call = false;
1288 }
1289
1290 else
1291 gr5_avoid_hazard (insn, &last_reg, &last_insn_call);
1292 }
1293
1294 else if (GET_CODE (insn) == BARRIER)
1295 last_reg = 0;
1296 }
1297
1298 /* Perform a target-specific pass over the instruction stream. The compiler
1299 will run it at all optimization levels, just after the point at which it
1300 normally does delayed-branch scheduling. */
1301
1302 static unsigned int
1303 visium_reorg (void)
1304 {
1305 if (visium_cpu == PROCESSOR_GR5)
1306 gr5_hazard_avoidance ();
1307
1308 return 0;
1309 }
1310 /* Return true if an argument must be passed by indirect reference. */
1311
1312 static bool
1313 visium_pass_by_reference (cumulative_args_t, const function_arg_info &arg)
1314 {
1315 tree type = arg.type;
1316 return type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1317 }
1318
1319 /* Define how arguments are passed.
1320
1321 A range of general registers and floating registers is available
1322 for passing arguments. When the class of registers which an
1323 argument would normally use is exhausted, that argument, is passed
1324 in the overflow region of the stack. No argument is split between
1325 registers and stack.
1326
1327 Arguments of type float or _Complex float go in FP registers if FP
1328 hardware is available. If there is no FP hardware, arguments of
1329 type float go in general registers. All other arguments are passed
1330 in general registers. */
1331
1332 static rtx
1333 visium_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg)
1334 {
1335 int size;
1336 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1337
1338 size = (GET_MODE_SIZE (arg.mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1339 if (arg.end_marker_p ())
1340 return GEN_INT (0);
1341
1342 /* Scalar or complex single precision floating point arguments are returned
1343 in floating registers. */
1344 if (TARGET_FPU
1345 && ((GET_MODE_CLASS (arg.mode) == MODE_FLOAT
1346 && GET_MODE_SIZE (arg.mode) <= UNITS_PER_HWFPVALUE)
1347 || (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT
1348 && GET_MODE_SIZE (arg.mode) <= UNITS_PER_HWFPVALUE * 2)))
1349 {
1350 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1351 return gen_rtx_REG (arg.mode, FP_ARG_FIRST + ca->frcount);
1352 else
1353 return NULL_RTX;
1354 }
1355
1356 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1357 return gen_rtx_REG (arg.mode, ca->grcount + GP_ARG_FIRST);
1358
1359 return NULL_RTX;
1360 }
1361
1362 /* Update the summarizer variable pointed to by PCUM_V to advance past
1363 argument ARG. Once this is done, the variable CUM is suitable for
1364 analyzing the _following_ argument with visium_function_arg. */
1365
1366 static void
1367 visium_function_arg_advance (cumulative_args_t pcum_v,
1368 const function_arg_info &arg)
1369 {
1370 int size = (GET_MODE_SIZE (arg.mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1371 int stack_size = 0;
1372 CUMULATIVE_ARGS *ca = get_cumulative_args (pcum_v);
1373
1374 /* Scalar or complex single precision floating point arguments are returned
1375 in floating registers. */
1376 if (TARGET_FPU
1377 && ((GET_MODE_CLASS (arg.mode) == MODE_FLOAT
1378 && GET_MODE_SIZE (arg.mode) <= UNITS_PER_HWFPVALUE)
1379 || (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT
1380 && GET_MODE_SIZE (arg.mode) <= UNITS_PER_HWFPVALUE * 2)))
1381 {
1382 if (ca->frcount + size <= MAX_ARGS_IN_FP_REGISTERS)
1383 ca->frcount += size;
1384 else
1385 {
1386 stack_size = size;
1387 ca->frcount = MAX_ARGS_IN_FP_REGISTERS;
1388 }
1389 }
1390 else
1391 {
1392 /* Everything else goes in a general register, if enough are
1393 available. */
1394 if (ca->grcount + size <= MAX_ARGS_IN_GP_REGISTERS)
1395 ca->grcount += size;
1396 else
1397 {
1398 stack_size = size;
1399 ca->grcount = MAX_ARGS_IN_GP_REGISTERS;
1400 }
1401 }
1402
1403 if (arg.named)
1404 ca->stack_words += stack_size;
1405 }
1406
1407 /* Specify whether to return the return value in memory. */
1408
1409 static bool
1410 visium_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1411 {
1412 return (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE);
1413 }
1414
1415 /* Define how scalar values are returned. */
1416
1417 static rtx
1418 visium_function_value_1 (machine_mode mode)
1419 {
1420 /* Scalar or complex single precision floating point values
1421 are returned in floating register f1. */
1422 if (TARGET_FPU
1423 && ((GET_MODE_CLASS (mode) == MODE_FLOAT
1424 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE)
1425 || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
1426 && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2)))
1427 return gen_rtx_REG (mode, FP_RETURN_REGNUM);
1428
1429 /* All others are returned in r1. */
1430 return gen_rtx_REG (mode, RETURN_REGNUM);
1431 }
1432
1433 /* Return an RTX representing the place where a function returns or receives
1434 a value of data type RET_TYPE. */
1435
1436 static rtx
1437 visium_function_value (const_tree ret_type,
1438 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1439 bool outgoing ATTRIBUTE_UNUSED)
1440 {
1441 return visium_function_value_1 (TYPE_MODE (ret_type));
1442 }
1443
1444 /* Return an RTX representing the place where the library function result will
1445 be returned. */
1446
1447 static rtx
1448 visium_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1449 {
1450 return visium_function_value_1 (mode);
1451 }
1452
1453 /* Store the anonymous register arguments into the stack so that all the
1454 arguments appear to have been passed consecutively on the stack. */
1455
1456 static void
1457 visium_setup_incoming_varargs (cumulative_args_t pcum_v,
1458 const function_arg_info &arg,
1459 int *pretend_size ATTRIBUTE_UNUSED,
1460 int no_rtl)
1461 {
1462 cumulative_args_t local_args_so_far;
1463 CUMULATIVE_ARGS local_copy;
1464 CUMULATIVE_ARGS *locargs;
1465 int gp_saved, fp_saved, size;
1466
1467 /* Create an internal cumulative_args_t pointer to internally define
1468 storage to ensure calling TARGET_FUNCTION_ARG_ADVANCE does not
1469 make global changes. */
1470 local_args_so_far.p = &local_copy;
1471 locargs = get_cumulative_args (pcum_v);
1472
1473 #if CHECKING_P
1474 local_args_so_far.magic = CUMULATIVE_ARGS_MAGIC;
1475 #endif
1476
1477 local_copy.grcount = locargs->grcount;
1478 local_copy.frcount = locargs->frcount;
1479 local_copy.stack_words = locargs->stack_words;
1480
1481 /* The caller has advanced ARGS_SO_FAR up to, but not beyond, the last named
1482 argument. Advance a local copy of ARGS_SO_FAR past the last "real" named
1483 argument, to find out how many registers are left over. */
1484 TARGET_FUNCTION_ARG_ADVANCE (local_args_so_far, arg);
1485
1486 /* Find how many registers we need to save. */
1487 locargs = get_cumulative_args (local_args_so_far);
1488 gp_saved = MAX_ARGS_IN_GP_REGISTERS - locargs->grcount;
1489 fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - locargs->frcount : 0);
1490 size = (gp_saved * UNITS_PER_WORD) + (fp_saved * UNITS_PER_HWFPVALUE);
1491
1492 if (!no_rtl && size > 0)
1493 {
1494 /* To avoid negative offsets, which are not valid addressing modes on
1495 the Visium, we create a base register for the pretend args. */
1496 rtx ptr
1497 = force_reg (Pmode,
1498 plus_constant (Pmode, virtual_incoming_args_rtx, -size));
1499
1500 if (gp_saved > 0)
1501 {
1502 rtx mem
1503 = gen_rtx_MEM (BLKmode,
1504 plus_constant (Pmode,
1505 ptr,
1506 fp_saved * UNITS_PER_HWFPVALUE));
1507 MEM_NOTRAP_P (mem) = 1;
1508 set_mem_alias_set (mem, get_varargs_alias_set ());
1509 move_block_from_reg (locargs->grcount + GP_ARG_FIRST, mem, gp_saved);
1510 }
1511
1512 if (fp_saved > 0)
1513 {
1514 rtx mem = gen_rtx_MEM (BLKmode, ptr);
1515 MEM_NOTRAP_P (mem) = 1;
1516 set_mem_alias_set (mem, get_varargs_alias_set ());
1517 gcc_assert (UNITS_PER_WORD == UNITS_PER_HWFPVALUE);
1518 move_block_from_reg (locargs->frcount + FP_ARG_FIRST, mem, fp_saved);
1519 }
1520 }
1521
1522 visium_reg_parm_save_area_size = size;
1523 }
1524
1525 /* Define the `__builtin_va_list' type for the ABI. */
1526
1527 static tree
1528 visium_build_builtin_va_list (void)
1529 {
1530 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes, record;
1531
1532 record = (*lang_hooks.types.make_type) (RECORD_TYPE);
1533 f_ovfl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1534 get_identifier ("__overflow_argptr"), ptr_type_node);
1535 f_gbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1536 get_identifier ("__gpr_base"), ptr_type_node);
1537 f_fbase = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1538 get_identifier ("__fpr_base"), ptr_type_node);
1539 f_gbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1540 get_identifier ("__gpr_bytes"),
1541 short_unsigned_type_node);
1542 f_fbytes = build_decl (BUILTINS_LOCATION, FIELD_DECL,
1543 get_identifier ("__fpr_bytes"),
1544 short_unsigned_type_node);
1545
1546 DECL_FIELD_CONTEXT (f_ovfl) = record;
1547 DECL_FIELD_CONTEXT (f_gbase) = record;
1548 DECL_FIELD_CONTEXT (f_fbase) = record;
1549 DECL_FIELD_CONTEXT (f_gbytes) = record;
1550 DECL_FIELD_CONTEXT (f_fbytes) = record;
1551 TYPE_FIELDS (record) = f_ovfl;
1552 TREE_CHAIN (f_ovfl) = f_gbase;
1553 TREE_CHAIN (f_gbase) = f_fbase;
1554 TREE_CHAIN (f_fbase) = f_gbytes;
1555 TREE_CHAIN (f_gbytes) = f_fbytes;
1556 layout_type (record);
1557
1558 return record;
1559 }
1560
1561 /* Implement `va_start' for varargs and stdarg. */
1562
1563 static void
1564 visium_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
1565 {
1566 const CUMULATIVE_ARGS *ca = &crtl->args.info;
1567 int gp_saved = MAX_ARGS_IN_GP_REGISTERS - ca->grcount;
1568 int fp_saved = (TARGET_FPU ? MAX_ARGS_IN_FP_REGISTERS - ca->frcount : 0);
1569 int named_stack_size = ca->stack_words * UNITS_PER_WORD, offset;
1570 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1571 tree ovfl, gbase, gbytes, fbase, fbytes, t;
1572
1573 f_ovfl = TYPE_FIELDS (va_list_type_node);
1574 f_gbase = TREE_CHAIN (f_ovfl);
1575 f_fbase = TREE_CHAIN (f_gbase);
1576 f_gbytes = TREE_CHAIN (f_fbase);
1577 f_fbytes = TREE_CHAIN (f_gbytes);
1578 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1579 gbase = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1580 NULL_TREE);
1581 fbase = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1582 NULL_TREE);
1583 gbytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), valist, f_gbytes,
1584 NULL_TREE);
1585 fbytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), valist, f_fbytes,
1586 NULL_TREE);
1587
1588 /* Store the stacked vararg pointer in the OVFL member. */
1589 t = make_tree (TREE_TYPE (ovfl), virtual_incoming_args_rtx);
1590 t = fold_build_pointer_plus_hwi (t, named_stack_size);
1591 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
1592 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1593
1594 /* Store the base address of the GPR save area into GBASE. */
1595 t = make_tree (TREE_TYPE (gbase), virtual_incoming_args_rtx);
1596 offset = MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD;
1597 t = fold_build_pointer_plus_hwi (t, -offset);
1598 t = build2 (MODIFY_EXPR, TREE_TYPE (gbase), gbase, t);
1599 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1600
1601 /* Store the base address of the FPR save area into FBASE. */
1602 if (fp_saved)
1603 {
1604 t = make_tree (TREE_TYPE (fbase), virtual_incoming_args_rtx);
1605 offset = gp_saved * UNITS_PER_WORD
1606 + MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE;
1607 t = fold_build_pointer_plus_hwi (t, -offset);
1608 t = build2 (MODIFY_EXPR, TREE_TYPE (fbase), fbase, t);
1609 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1610 }
1611
1612 /* Fill in the GBYTES member. */
1613 t = build2 (MODIFY_EXPR, TREE_TYPE (gbytes), gbytes,
1614 size_int (gp_saved * UNITS_PER_WORD));
1615 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1616
1617 /* Fill in the FBYTES member. */
1618 t = build2 (MODIFY_EXPR, TREE_TYPE (fbytes),
1619 fbytes, size_int (fp_saved * UNITS_PER_HWFPVALUE));
1620 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1621 }
1622
1623 /* Implement `va_arg'. */
1624
1625 static tree
1626 visium_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
1627 gimple_seq *post_p)
1628 {
1629 tree f_ovfl, f_gbase, f_fbase, f_gbytes, f_fbytes;
1630 tree ovfl, base, bytes;
1631 HOST_WIDE_INT size, rsize;
1632 const bool by_reference_p = pass_va_arg_by_reference (type);
1633 const bool float_reg_arg_p
1634 = (TARGET_FPU && !by_reference_p
1635 && ((GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
1636 && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_HWFPVALUE)
1637 || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT
1638 && (GET_MODE_SIZE (TYPE_MODE (type))
1639 <= UNITS_PER_HWFPVALUE * 2))));
1640 const int max_save_area_size
1641 = (float_reg_arg_p ? MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE
1642 : MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD);
1643 tree t, u, offs;
1644 tree lab_false, lab_over, addr;
1645 tree ptrtype = build_pointer_type (type);
1646
1647 if (by_reference_p)
1648 {
1649 t = visium_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
1650 return build_va_arg_indirect_ref (t);
1651 }
1652
1653 size = int_size_in_bytes (type);
1654 rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
1655 f_ovfl = TYPE_FIELDS (va_list_type_node);
1656 f_gbase = TREE_CHAIN (f_ovfl);
1657 f_fbase = TREE_CHAIN (f_gbase);
1658 f_gbytes = TREE_CHAIN (f_fbase);
1659 f_fbytes = TREE_CHAIN (f_gbytes);
1660
1661 /* We maintain separate pointers and offsets for floating-point and
1662 general registers, but we need similar code in both cases.
1663
1664 Let:
1665
1666 BYTES be the number of unused bytes in the register save area.
1667 BASE be the base address of the register save area.
1668 OFFS be the current offset into the register save area. Either
1669 MAX_ARGS_IN_GP_REGISTERS * UNITS_PER_WORD - bytes or
1670 MAX_ARGS_IN_FP_REGISTERS * UNITS_PER_HWFPVALUE - bytes
1671 depending upon whether the argument is in general or floating
1672 registers.
1673 ADDR_RTX be the address of the argument.
1674 RSIZE be the size in bytes of the argument.
1675 OVFL be the pointer to the stack overflow area.
1676
1677 The code we want is:
1678
1679 1: if (bytes >= rsize)
1680 2: {
1681 3: addr_rtx = base + offs;
1682 4: bytes -= rsize;
1683 5: }
1684 6: else
1685 7: {
1686 8: bytes = 0;
1687 9: addr_rtx = ovfl;
1688 10: ovfl += rsize;
1689 11: }
1690
1691 */
1692
1693 addr = create_tmp_var (ptr_type_node, "addr");
1694 lab_false = create_artificial_label (UNKNOWN_LOCATION);
1695 lab_over = create_artificial_label (UNKNOWN_LOCATION);
1696 if (float_reg_arg_p)
1697 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_fbytes), unshare_expr (valist),
1698 f_fbytes, NULL_TREE);
1699 else
1700 bytes = build3 (COMPONENT_REF, TREE_TYPE (f_gbytes), unshare_expr (valist),
1701 f_gbytes, NULL_TREE);
1702
1703 /* [1] Emit code to branch if bytes < rsize. */
1704 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1705 t = build2 (LT_EXPR, boolean_type_node, bytes, t);
1706 u = build1 (GOTO_EXPR, void_type_node, lab_false);
1707 t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
1708 gimplify_and_add (t, pre_p);
1709
1710 /* [3] Emit code for: addr_rtx = base + offs, where
1711 offs = max_save_area_size - bytes. */
1712 t = fold_convert (sizetype, bytes);
1713 offs = build2 (MINUS_EXPR, sizetype, size_int (max_save_area_size), t);
1714 if (float_reg_arg_p)
1715 base = build3 (COMPONENT_REF, TREE_TYPE (f_fbase), valist, f_fbase,
1716 NULL_TREE);
1717 else
1718 base = build3 (COMPONENT_REF, TREE_TYPE (f_gbase), valist, f_gbase,
1719 NULL_TREE);
1720
1721 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), base, offs);
1722 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1723 gimplify_and_add (t, pre_p);
1724
1725 /* [4] Emit code for: bytes -= rsize. */
1726 t = fold_convert (TREE_TYPE (bytes), size_int (rsize));
1727 t = build2 (MINUS_EXPR, TREE_TYPE (bytes), bytes, t);
1728 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), bytes, t);
1729 gimplify_and_add (t, pre_p);
1730
1731 /* [6] Emit code to branch over the else clause, then the label. */
1732 t = build1 (GOTO_EXPR, void_type_node, lab_over);
1733 gimplify_and_add (t, pre_p);
1734 t = build1 (LABEL_EXPR, void_type_node, lab_false);
1735 gimplify_and_add (t, pre_p);
1736
1737 /* [8] Emit code for: bytes = 0. */
1738 t = fold_convert (TREE_TYPE (bytes), size_int (0));
1739 t = build2 (MODIFY_EXPR, TREE_TYPE (bytes), unshare_expr (bytes), t);
1740 gimplify_and_add (t, pre_p);
1741
1742 /* [9] Emit code for: addr_rtx = ovfl. */
1743 ovfl = build3 (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
1744 t = build2 (MODIFY_EXPR, void_type_node, addr, ovfl);
1745 gimplify_and_add (t, pre_p);
1746
1747 /* [10] Emit code for: ovfl += rsize. */
1748 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovfl), ovfl, size_int (rsize));
1749 t = build2 (MODIFY_EXPR, TREE_TYPE (ovfl), unshare_expr (ovfl), t);
1750 gimplify_and_add (t, pre_p);
1751 t = build1 (LABEL_EXPR, void_type_node, lab_over);
1752 gimplify_and_add (t, pre_p);
1753
1754 /* Emit a big-endian correction if size < UNITS_PER_WORD. */
1755 if (size < UNITS_PER_WORD)
1756 {
1757 t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr), addr,
1758 size_int (UNITS_PER_WORD - size));
1759 t = build2 (MODIFY_EXPR, void_type_node, addr, t);
1760 gimplify_and_add (t, pre_p);
1761 }
1762
1763 addr = fold_convert (ptrtype, addr);
1764
1765 return build_va_arg_indirect_ref (addr);
1766 }
1767
1768 /* Return true if OP is an offset suitable for use as a displacement in the
1769 address of a memory access in mode MODE. */
1770
1771 static bool
1772 rtx_ok_for_offset_p (machine_mode mode, rtx op)
1773 {
1774 if (!CONST_INT_P (op) || INTVAL (op) < 0)
1775 return false;
1776
1777 switch (mode)
1778 {
1779 case E_QImode:
1780 return INTVAL (op) <= 31;
1781
1782 case E_HImode:
1783 return (INTVAL (op) % 2) == 0 && INTVAL (op) < 63;
1784
1785 case E_SImode:
1786 case E_SFmode:
1787 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 127;
1788
1789 case E_DImode:
1790 case E_DFmode:
1791 return (INTVAL (op) % 4) == 0 && INTVAL (op) < 123;
1792
1793 default:
1794 return false;
1795 }
1796 }
1797
1798 /* Return whether X is a legitimate memory address for a memory operand
1799 of mode MODE.
1800
1801 Legitimate addresses are defined in two variants: a strict variant
1802 and a non-strict one. The STRICT parameter chooses which variant
1803 is desired by the caller.
1804
1805 The strict variant is used in the reload pass. It must be defined
1806 so that any pseudo-register that has not been allocated a hard
1807 register is considered a memory reference. This is because in
1808 contexts where some kind of register is required, a
1809 pseudo-register with no hard register must be rejected. For
1810 non-hard registers, the strict variant should look up the
1811 `reg_renumber' array; it should then proceed using the hard
1812 register number in the array, or treat the pseudo as a memory
1813 reference if the array holds `-1'.
1814
1815 The non-strict variant is used in other passes. It must be
1816 defined to accept all pseudo-registers in every context where some
1817 kind of register is required. */
1818
1819 static bool
1820 visium_legitimate_address_p (machine_mode mode, rtx x, bool strict)
1821 {
1822 rtx base;
1823 unsigned int regno;
1824
1825 /* If X is base+disp, check that we have an appropriate offset. */
1826 if (GET_CODE (x) == PLUS)
1827 {
1828 if (!rtx_ok_for_offset_p (mode, XEXP (x, 1)))
1829 return false;
1830 base = XEXP (x, 0);
1831 }
1832 else
1833 base = x;
1834
1835 /* Now check the base: it must be either a register or a subreg thereof. */
1836 if (GET_CODE (base) == SUBREG)
1837 base = SUBREG_REG (base);
1838 if (!REG_P (base))
1839 return false;
1840
1841 regno = REGNO (base);
1842
1843 /* For the strict variant, the register must be REGNO_OK_FOR_BASE_P. */
1844 if (strict)
1845 return REGNO_OK_FOR_BASE_P (regno);
1846
1847 /* For the non-strict variant, the register may also be a pseudo. */
1848 return BASE_REGISTER_P (regno) || regno >= FIRST_PSEUDO_REGISTER;
1849 }
1850
1851 /* Try machine-dependent ways of modifying an illegitimate address
1852 to be legitimate. If we find one, return the new, valid address.
1853 This macro is used in only one place: `memory_address' in explow.c.
1854
1855 OLDX is the address as it was before break_out_memory_refs was called.
1856 In some cases it is useful to look at this to decide what needs to be done.
1857
1858 MODE and WIN are passed so that this macro can use
1859 GO_IF_LEGITIMATE_ADDRESS.
1860
1861 It is always safe for this macro to do nothing. It exists to recognize
1862 opportunities to optimize the output.
1863
1864 For Visium
1865
1866 memory (reg + <out of range int>)
1867
1868 is transformed to
1869
1870 base_int = <out of range int> & ~mask
1871 ptr_reg = reg + base_int
1872 memory (ptr_reg + <out of range int> - base_int)
1873
1874 Thus ptr_reg is a base register for a range of addresses,
1875 which should help CSE.
1876
1877 For a 1 byte reference mask is 0x1f
1878 for a 2 byte reference mask is 0x3f
1879 For a 4 byte reference mask is 0x7f
1880
1881 This reflects the indexing range of the processor.
1882
1883 For a > 4 byte reference the mask is 0x7f provided all of the words
1884 can be accessed with the base address obtained. Otherwise a mask
1885 of 0x3f is used.
1886
1887 On rare occasions an unaligned base register value with an
1888 unaligned offset is generated. Unaligned offsets are left alone for
1889 this reason. */
1890
1891 static rtx
1892 visium_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1893 machine_mode mode)
1894 {
1895 if (GET_CODE (x) == PLUS
1896 && GET_CODE (XEXP (x, 1)) == CONST_INT
1897 && GET_CODE (XEXP (x, 0)) == REG && mode != BLKmode)
1898 {
1899 int offset = INTVAL (XEXP (x, 1));
1900 int size = GET_MODE_SIZE (mode);
1901 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1902 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1903 int offset_base = offset & ~mask;
1904
1905 /* Check that all of the words can be accessed. */
1906 if (size > 4 && size + offset - offset_base > 0x80)
1907 offset_base = offset & ~0x3f;
1908 if (offset_base != 0 && offset_base != offset && (offset & mask1) == 0)
1909 {
1910 rtx ptr_reg = force_reg (Pmode,
1911 gen_rtx_PLUS (Pmode,
1912 XEXP (x, 0),
1913 GEN_INT (offset_base)));
1914
1915 return plus_constant (Pmode, ptr_reg, offset - offset_base);
1916 }
1917 }
1918
1919 return x;
1920 }
1921
1922 /* Perform a similar function to visium_legitimize_address, but this time
1923 for reload. Generating new registers is not an option here. Parts
1924 that need reloading are indicated by calling push_reload. */
1925
1926 rtx
1927 visium_legitimize_reload_address (rtx x, machine_mode mode, int opnum,
1928 int type, int ind ATTRIBUTE_UNUSED)
1929 {
1930 rtx newrtx, tem = NULL_RTX;
1931
1932 if (mode == BLKmode)
1933 return NULL_RTX;
1934
1935 if (optimize && GET_CODE (x) == PLUS)
1936 tem = simplify_binary_operation (PLUS, GET_MODE (x), XEXP (x, 0),
1937 XEXP (x, 1));
1938
1939 newrtx = tem ? tem : x;
1940 if (GET_CODE (newrtx) == PLUS
1941 && GET_CODE (XEXP (newrtx, 1)) == CONST_INT
1942 && GET_CODE (XEXP (newrtx, 0)) == REG
1943 && BASE_REGISTER_P (REGNO (XEXP (newrtx, 0))))
1944 {
1945 int offset = INTVAL (XEXP (newrtx, 1));
1946 int size = GET_MODE_SIZE (mode);
1947 int mask = (size == 1 ? 0x1f : (size == 2 ? 0x3f : 0x7f));
1948 int mask1 = (size == 1 ? 0 : (size == 2 ? 1 : 3));
1949 int offset_base = offset & ~mask;
1950
1951 /* Check that all of the words can be accessed. */
1952 if (size > 4 && size + offset - offset_base > 0x80)
1953 offset_base = offset & ~0x3f;
1954
1955 if (offset_base && (offset & mask1) == 0)
1956 {
1957 rtx temp = gen_rtx_PLUS (Pmode,
1958 XEXP (newrtx, 0), GEN_INT (offset_base));
1959
1960 x = gen_rtx_PLUS (Pmode, temp, GEN_INT (offset - offset_base));
1961 push_reload (XEXP (x, 0), 0, &XEXP (x, 0), 0,
1962 BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum,
1963 (enum reload_type) type);
1964 return x;
1965 }
1966 }
1967
1968 return NULL_RTX;
1969 }
1970
1971 /* Return the cost of moving data of mode MODE from a register in class FROM to
1972 one in class TO. A value of 2 is the default; other values are interpreted
1973 relative to that. */
1974
1975 static int
1976 visium_register_move_cost (machine_mode mode, reg_class_t from,
1977 reg_class_t to)
1978 {
1979 const int numwords = (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) ? 1 : 2;
1980
1981 if (from == MDB || to == MDB)
1982 return 4;
1983 else if (from == MDC || to == MDC || (from == FP_REGS) != (to == FP_REGS))
1984 return 4 * numwords;
1985 else
1986 return 2 * numwords;
1987 }
1988
1989 /* Return the cost of moving data of mode MODE between a register of class
1990 CLASS and memory. IN is zero if the value is to be written to memory,
1991 non-zero if it is to be read in. This cost is relative to those in
1992 visium_register_move_cost. */
1993
1994 static int
1995 visium_memory_move_cost (machine_mode mode,
1996 reg_class_t to ATTRIBUTE_UNUSED,
1997 bool in)
1998 {
1999 /* Moving data in can be from PROM and this is expensive. */
2000 if (in)
2001 {
2002 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2003 return 7;
2004 else
2005 return 13;
2006 }
2007
2008 /* Moving data out is mostly to RAM and should be cheaper. */
2009 else
2010 {
2011 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
2012 return 6;
2013 else
2014 return 12;
2015 }
2016 }
2017
2018 /* Return the relative costs of expression X. */
2019
2020 static bool
2021 visium_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
2022 int opno ATTRIBUTE_UNUSED, int *total,
2023 bool speed ATTRIBUTE_UNUSED)
2024 {
2025 int code = GET_CODE (x);
2026
2027 switch (code)
2028 {
2029 case CONST_INT:
2030 /* Small integers are as cheap as registers. 4-byte values can
2031 be fetched as immediate constants - let's give that the cost
2032 of an extra insn. */
2033 *total = COSTS_N_INSNS (!satisfies_constraint_J (x));
2034 return true;
2035
2036 case CONST:
2037 case LABEL_REF:
2038 case SYMBOL_REF:
2039 *total = COSTS_N_INSNS (2);
2040 return true;
2041
2042 case CONST_DOUBLE:
2043 {
2044 rtx high, low;
2045 split_double (x, &high, &low);
2046 *total =
2047 COSTS_N_INSNS
2048 (!satisfies_constraint_J (high) + !satisfies_constraint_J (low));
2049 return true;
2050 }
2051
2052 case MULT:
2053 *total = COSTS_N_INSNS (3);
2054 return false;
2055
2056 case DIV:
2057 case UDIV:
2058 case MOD:
2059 case UMOD:
2060 if (mode == DImode)
2061 *total = COSTS_N_INSNS (64);
2062 else
2063 *total = COSTS_N_INSNS (32);
2064 return false;
2065
2066 case PLUS:
2067 case MINUS:
2068 case NEG:
2069 /* DImode operations are performed directly on the ALU. */
2070 if (mode == DImode)
2071 *total = COSTS_N_INSNS (2);
2072 else
2073 *total = COSTS_N_INSNS (1);
2074 return false;
2075
2076 case ASHIFT:
2077 case ASHIFTRT:
2078 case LSHIFTRT:
2079 /* DImode operations are performed on the EAM instead. */
2080 if (mode == DImode)
2081 *total = COSTS_N_INSNS (3);
2082 else
2083 *total = COSTS_N_INSNS (1);
2084 return false;
2085
2086 case COMPARE:
2087 /* This matches the btst pattern. */
2088 if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT
2089 && XEXP (x, 1) == const0_rtx
2090 && XEXP (XEXP (x, 0), 1) == const1_rtx
2091 && satisfies_constraint_K (XEXP (XEXP (x, 0), 2)))
2092 *total = COSTS_N_INSNS (1);
2093 return false;
2094
2095 default:
2096 return false;
2097 }
2098 }
2099
2100 /* Split a double move of OPERANDS in MODE. */
2101
2102 void
2103 visium_split_double_move (rtx *operands, machine_mode mode)
2104 {
2105 bool swap = false;
2106
2107 /* Check register to register with overlap. */
2108 if (GET_CODE (operands[0]) == REG
2109 && GET_CODE (operands[1]) == REG
2110 && REGNO (operands[0]) == REGNO (operands[1]) + 1)
2111 swap = true;
2112
2113 /* Check memory to register where the base reg overlaps the destination. */
2114 if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == MEM)
2115 {
2116 rtx op = XEXP (operands[1], 0);
2117
2118 if (GET_CODE (op) == SUBREG)
2119 op = SUBREG_REG (op);
2120
2121 if (GET_CODE (op) == REG && REGNO (op) == REGNO (operands[0]))
2122 swap = true;
2123
2124 if (GET_CODE (op) == PLUS)
2125 {
2126 rtx x = XEXP (op, 0);
2127 rtx y = XEXP (op, 1);
2128
2129 if (GET_CODE (x) == REG && REGNO (x) == REGNO (operands[0]))
2130 swap = true;
2131
2132 if (GET_CODE (y) == REG && REGNO (y) == REGNO (operands[0]))
2133 swap = true;
2134 }
2135 }
2136
2137 if (swap)
2138 {
2139 operands[2] = operand_subword (operands[0], 1, 1, mode);
2140 operands[3] = operand_subword (operands[1], 1, 1, mode);
2141 operands[4] = operand_subword (operands[0], 0, 1, mode);
2142 operands[5] = operand_subword (operands[1], 0, 1, mode);
2143 }
2144 else
2145 {
2146 operands[2] = operand_subword (operands[0], 0, 1, mode);
2147 operands[3] = operand_subword (operands[1], 0, 1, mode);
2148 operands[4] = operand_subword (operands[0], 1, 1, mode);
2149 operands[5] = operand_subword (operands[1], 1, 1, mode);
2150 }
2151 }
2152
2153 /* Split a double addition or subtraction of operands. */
2154
2155 void
2156 visium_split_double_add (enum rtx_code code, rtx op0, rtx op1, rtx op2)
2157 {
2158 rtx op3 = gen_lowpart (SImode, op0);
2159 rtx op4 = gen_lowpart (SImode, op1);
2160 rtx op5;
2161 rtx op6 = gen_highpart (SImode, op0);
2162 rtx op7 = (op1 == const0_rtx ? op1 : gen_highpart (SImode, op1));
2163 rtx op8;
2164 rtx x, pat, flags;
2165
2166 /* If operand #2 is a small constant, then its high part is null. */
2167 if (CONST_INT_P (op2))
2168 {
2169 HOST_WIDE_INT val = INTVAL (op2);
2170
2171 if (val < 0)
2172 {
2173 code = (code == MINUS ? PLUS : MINUS);
2174 val = -val;
2175 }
2176
2177 op5 = gen_int_mode (val, SImode);
2178 op8 = const0_rtx;
2179 }
2180 else
2181 {
2182 op5 = gen_lowpart (SImode, op2);
2183 op8 = gen_highpart (SImode, op2);
2184 }
2185
2186 if (op4 == const0_rtx)
2187 pat = gen_negsi2_insn_set_carry (op3, op5);
2188 else if (code == MINUS)
2189 pat = gen_subsi3_insn_set_carry (op3, op4, op5);
2190 else
2191 pat = gen_addsi3_insn_set_carry (op3, op4, op5);
2192 emit_insn (pat);
2193
2194 /* This is the plus_[plus_]sltu_flags or minus_[minus_]sltu_flags pattern. */
2195 if (op8 == const0_rtx)
2196 x = op7;
2197 else
2198 x = gen_rtx_fmt_ee (code, SImode, op7, op8);
2199 flags = gen_rtx_REG (CCCmode, FLAGS_REGNUM);
2200 x = gen_rtx_fmt_ee (code, SImode, x, gen_rtx_LTU (SImode, flags, const0_rtx));
2201 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2202 XVECEXP (pat, 0, 0) = gen_rtx_SET (op6, x);
2203 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2204 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2205 emit_insn (pat);
2206
2207 visium_flags_exposed = true;
2208 }
2209
2210 /* Expand a copysign of OPERANDS in MODE. */
2211
2212 void
2213 visium_expand_copysign (rtx *operands, machine_mode mode)
2214 {
2215 rtx op0 = operands[0];
2216 rtx op1 = operands[1];
2217 rtx op2 = operands[2];
2218 rtx mask = force_reg (SImode, GEN_INT (0x7fffffff));
2219 rtx x;
2220
2221 /* We manually handle SFmode because the abs and neg instructions of
2222 the FPU on the MCM have a non-standard behavior wrt NaNs. */
2223 gcc_assert (mode == SFmode);
2224
2225 /* First get all the non-sign bits of op1. */
2226 if (GET_CODE (op1) == CONST_DOUBLE)
2227 {
2228 if (real_isneg (CONST_DOUBLE_REAL_VALUE (op1)))
2229 op1 = simplify_unary_operation (ABS, mode, op1, mode);
2230 if (op1 != CONST0_RTX (mode))
2231 {
2232 long l;
2233 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op1), l);
2234 op1 = force_reg (SImode, gen_int_mode (l, SImode));
2235 }
2236 }
2237 else
2238 {
2239 op1 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op1));
2240 op1 = force_reg (SImode, gen_rtx_AND (SImode, op1, mask));
2241 }
2242
2243 /* Then get the sign bit of op2. */
2244 mask = force_reg (SImode, gen_rtx_NOT (SImode, mask));
2245 op2 = copy_to_mode_reg (SImode, gen_lowpart (SImode, op2));
2246 op2 = force_reg (SImode, gen_rtx_AND (SImode, op2, mask));
2247
2248 /* Finally OR the two values. */
2249 if (op1 == CONST0_RTX (SFmode))
2250 x = op2;
2251 else
2252 x = force_reg (SImode, gen_rtx_IOR (SImode, op1, op2));
2253
2254 /* And move the result to the destination. */
2255 emit_insn (gen_rtx_SET (op0, gen_lowpart (SFmode, x)));
2256 }
2257
2258 /* Expand a cstore of OPERANDS in MODE for EQ/NE/LTU/GTU/GEU/LEU. We generate
2259 the result in the C flag and use the ADC/SUBC instructions to write it into
2260 the destination register.
2261
2262 It would also be possible to implement support for LT/GT/LE/GE by means of
2263 the RFLAG instruction followed by some shifts, but this can pessimize the
2264 generated code. */
2265
2266 void
2267 visium_expand_int_cstore (rtx *operands, machine_mode mode)
2268 {
2269 enum rtx_code code = GET_CODE (operands[1]);
2270 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], sltu;
2271 bool reverse = false;
2272
2273 switch (code)
2274 {
2275 case EQ:
2276 case NE:
2277 /* We use a special comparison to get the result in the C flag. */
2278 if (op2 != const0_rtx)
2279 op1 = force_reg (mode, gen_rtx_XOR (mode, op1, op2));
2280 op1 = gen_rtx_NOT (mode, op1);
2281 op2 = constm1_rtx;
2282 if (code == EQ)
2283 reverse = true;
2284 break;
2285
2286 case LEU:
2287 case GEU:
2288 /* The result is naturally in the C flag modulo a couple of tricks. */
2289 code = reverse_condition (code);
2290 reverse = true;
2291
2292 /* ... fall through ... */
2293
2294 case LTU:
2295 case GTU:
2296 if (code == GTU)
2297 {
2298 rtx tmp = op1;
2299 op1 = op2;
2300 op2 = tmp;
2301 }
2302 break;
2303
2304 default:
2305 gcc_unreachable ();
2306 }
2307
2308 /* We need either a single ADC or a SUBC and a PLUS. */
2309 sltu = gen_rtx_LTU (SImode, op1, op2);
2310
2311 if (reverse)
2312 {
2313 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, sltu));
2314 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2315 }
2316 else
2317 emit_insn (gen_rtx_SET (op0, sltu));
2318 }
2319
2320 /* Expand a cstore of OPERANDS in MODE for LT/GT/UNGE/UNLE. We generate the
2321 result in the C flag and use the ADC/SUBC instructions to write it into
2322 the destination register. */
2323
2324 void
2325 visium_expand_fp_cstore (rtx *operands,
2326 machine_mode mode ATTRIBUTE_UNUSED)
2327 {
2328 enum rtx_code code = GET_CODE (operands[1]);
2329 rtx op0 = operands[0], op1 = operands[2], op2 = operands[3], slt;
2330 bool reverse = false;
2331
2332 switch (code)
2333 {
2334 case UNLE:
2335 case UNGE:
2336 /* The result is naturally in the C flag modulo a couple of tricks. */
2337 code = reverse_condition_maybe_unordered (code);
2338 reverse = true;
2339
2340 /* ... fall through ... */
2341
2342 case LT:
2343 case GT:
2344 if (code == GT)
2345 {
2346 rtx tmp = op1;
2347 op1 = op2;
2348 op2 = tmp;
2349 }
2350 break;
2351
2352 default:
2353 gcc_unreachable ();
2354 }
2355
2356 /* We need either a single ADC or a SUBC and a PLUS. */
2357 slt = gen_rtx_LT (SImode, op1, op2);
2358
2359 if (reverse)
2360 {
2361 rtx tmp = copy_to_mode_reg (SImode, gen_rtx_NEG (SImode, slt));
2362 emit_insn (gen_add3_insn (op0, tmp, const1_rtx));
2363 }
2364 else
2365 emit_insn (gen_rtx_SET (op0, slt));
2366 }
2367
2368 /* Split a compare-and-store with CODE, operands OP2 and OP3, combined with
2369 operation with OP_CODE, operands OP0 and OP1. */
2370
2371 void
2372 visium_split_cstore (enum rtx_code op_code, rtx op0, rtx op1,
2373 enum rtx_code code, rtx op2, rtx op3)
2374 {
2375 machine_mode cc_mode = visium_select_cc_mode (code, op2, op3);
2376
2377 /* If a FP cstore was reversed, then it was originally UNGE/UNLE. */
2378 if (cc_mode == CCFPEmode && (op_code == NEG || op_code == MINUS))
2379 cc_mode = CCFPmode;
2380
2381 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2382 rtx x = gen_rtx_COMPARE (cc_mode, op2, op3);
2383 x = gen_rtx_SET (flags, x);
2384 emit_insn (x);
2385
2386 x = gen_rtx_fmt_ee (code, SImode, flags, const0_rtx);
2387 switch (op_code)
2388 {
2389 case SET:
2390 break;
2391 case NEG:
2392 x = gen_rtx_NEG (SImode, x);
2393 break;
2394 case PLUS:
2395 case MINUS:
2396 x = gen_rtx_fmt_ee (op_code, SImode, op1, x);
2397 break;
2398 default:
2399 gcc_unreachable ();
2400 }
2401
2402 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
2403 XVECEXP (pat, 0, 0) = gen_rtx_SET (op0, x);
2404 flags = gen_rtx_REG (CCmode, FLAGS_REGNUM);
2405 XVECEXP (pat, 0, 1) = gen_rtx_CLOBBER (VOIDmode, flags);
2406 emit_insn (pat);
2407
2408 visium_flags_exposed = true;
2409 }
2410
2411 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2412 address SRC_REG to DST with address DST_REG in 4-byte chunks. */
2413
2414 static void
2415 expand_block_move_4 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2416 {
2417 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2418 unsigned int rem = bytes % 4;
2419
2420 if (TARGET_BMI)
2421 {
2422 unsigned int i;
2423 rtx insn;
2424
2425 emit_move_insn (regno_reg_rtx[1], dst_reg);
2426 emit_move_insn (regno_reg_rtx[2], src_reg);
2427 emit_move_insn (regno_reg_rtx[3], bytes_rtx);
2428
2429 insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (8));
2430 XVECEXP (insn, 0, 0)
2431 = gen_rtx_SET (replace_equiv_address_nv (dst, regno_reg_rtx[1]),
2432 replace_equiv_address_nv (src, regno_reg_rtx[2]));
2433 XVECEXP (insn, 0, 1) = gen_rtx_USE (VOIDmode, regno_reg_rtx[3]);
2434 for (i = 1; i <= 6; i++)
2435 XVECEXP (insn, 0, 1 + i)
2436 = gen_rtx_CLOBBER (VOIDmode, regno_reg_rtx[i]);
2437 emit_insn (insn);
2438 }
2439 else
2440 emit_library_call (long_int_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2441 dst_reg, Pmode,
2442 src_reg, Pmode,
2443 convert_to_mode (TYPE_MODE (sizetype),
2444 GEN_INT (bytes >> 2),
2445 TYPE_UNSIGNED (sizetype)),
2446 TYPE_MODE (sizetype));
2447 if (rem == 0)
2448 return;
2449
2450 dst = replace_equiv_address_nv (dst, dst_reg);
2451 src = replace_equiv_address_nv (src, src_reg);
2452 bytes -= rem;
2453
2454 if (rem > 1)
2455 {
2456 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2457 adjust_address_nv (src, HImode, bytes));
2458 bytes += 2;
2459 rem -= 2;
2460 }
2461
2462 if (rem > 0)
2463 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2464 adjust_address_nv (src, QImode, bytes));
2465 }
2466
2467 /* Generate a call to a library function to move BYTES_RTX bytes from SRC with
2468 address SRC_REG to DST with address DST_REG in 2-bytes chunks. */
2469
2470 static void
2471 expand_block_move_2 (rtx dst, rtx dst_reg, rtx src, rtx src_reg, rtx bytes_rtx)
2472 {
2473 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2474 unsigned int rem = bytes % 2;
2475
2476 emit_library_call (wrd_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2477 dst_reg, Pmode,
2478 src_reg, Pmode,
2479 convert_to_mode (TYPE_MODE (sizetype),
2480 GEN_INT (bytes >> 1),
2481 TYPE_UNSIGNED (sizetype)),
2482 TYPE_MODE (sizetype));
2483 if (rem == 0)
2484 return;
2485
2486 dst = replace_equiv_address_nv (dst, dst_reg);
2487 src = replace_equiv_address_nv (src, src_reg);
2488 bytes -= rem;
2489
2490 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2491 adjust_address_nv (src, QImode, bytes));
2492 }
2493
2494 /* Generate a call to a library function to move BYTES_RTX bytes from address
2495 SRC_REG to address DST_REG in 1-byte chunks. */
2496
2497 static void
2498 expand_block_move_1 (rtx dst_reg, rtx src_reg, rtx bytes_rtx)
2499 {
2500 emit_library_call (byt_memcpy_libfunc, LCT_NORMAL, VOIDmode,
2501 dst_reg, Pmode,
2502 src_reg, Pmode,
2503 convert_to_mode (TYPE_MODE (sizetype),
2504 bytes_rtx,
2505 TYPE_UNSIGNED (sizetype)),
2506 TYPE_MODE (sizetype));
2507 }
2508
2509 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2510 address DST_REG to VALUE_RTX in 4-byte chunks. */
2511
2512 static void
2513 expand_block_set_4 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2514 {
2515 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2516 unsigned int rem = bytes % 4;
2517
2518 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2519 emit_library_call (long_int_memset_libfunc, LCT_NORMAL, VOIDmode,
2520 dst_reg, Pmode,
2521 value_rtx, Pmode,
2522 convert_to_mode (TYPE_MODE (sizetype),
2523 GEN_INT (bytes >> 2),
2524 TYPE_UNSIGNED (sizetype)),
2525 TYPE_MODE (sizetype));
2526 if (rem == 0)
2527 return;
2528
2529 dst = replace_equiv_address_nv (dst, dst_reg);
2530 bytes -= rem;
2531
2532 if (rem > 1)
2533 {
2534 if (CONST_INT_P (value_rtx))
2535 {
2536 const unsigned HOST_WIDE_INT value = UINTVAL (value_rtx) & 0xff;
2537 emit_move_insn (adjust_address_nv (dst, HImode, bytes),
2538 gen_int_mode ((value << 8) | value, HImode));
2539 }
2540 else
2541 {
2542 rtx temp = convert_to_mode (QImode, value_rtx, 1);
2543 emit_move_insn (adjust_address_nv (dst, QImode, bytes), temp);
2544 emit_move_insn (adjust_address_nv (dst, QImode, bytes + 1), temp);
2545 }
2546 bytes += 2;
2547 rem -= 2;
2548 }
2549
2550 if (rem > 0)
2551 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2552 convert_to_mode (QImode, value_rtx, 1));
2553 }
2554
2555 /* Generate a call to a library function to set BYTES_RTX bytes of DST with
2556 address DST_REG to VALUE_RTX in 2-byte chunks. */
2557
2558 static void
2559 expand_block_set_2 (rtx dst, rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2560 {
2561 unsigned HOST_WIDE_INT bytes = UINTVAL (bytes_rtx);
2562 unsigned int rem = bytes % 2;
2563
2564 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2565 emit_library_call (wrd_memset_libfunc, LCT_NORMAL, VOIDmode,
2566 dst_reg, Pmode,
2567 value_rtx, Pmode,
2568 convert_to_mode (TYPE_MODE (sizetype),
2569 GEN_INT (bytes >> 1),
2570 TYPE_UNSIGNED (sizetype)),
2571 TYPE_MODE (sizetype));
2572 if (rem == 0)
2573 return;
2574
2575 dst = replace_equiv_address_nv (dst, dst_reg);
2576 bytes -= rem;
2577
2578 emit_move_insn (adjust_address_nv (dst, QImode, bytes),
2579 convert_to_mode (QImode, value_rtx, 1));
2580 }
2581
2582 /* Generate a call to a library function to set BYTES_RTX bytes at address
2583 DST_REG to VALUE_RTX in 1-byte chunks. */
2584
2585 static void
2586 expand_block_set_1 (rtx dst_reg, rtx value_rtx, rtx bytes_rtx)
2587 {
2588 value_rtx = convert_to_mode (Pmode, value_rtx, 1);
2589 emit_library_call (byt_memset_libfunc, LCT_NORMAL, VOIDmode,
2590 dst_reg, Pmode,
2591 value_rtx, Pmode,
2592 convert_to_mode (TYPE_MODE (sizetype),
2593 bytes_rtx,
2594 TYPE_UNSIGNED (sizetype)),
2595 TYPE_MODE (sizetype));
2596 }
2597
2598 /* Expand string/block move operations.
2599
2600 operands[0] is the pointer to the destination.
2601 operands[1] is the pointer to the source.
2602 operands[2] is the number of bytes to move.
2603 operands[3] is the alignment.
2604
2605 Return 1 upon success, 0 otherwise. */
2606
2607 int
2608 visium_expand_block_move (rtx *operands)
2609 {
2610 rtx dst = operands[0];
2611 rtx src = operands[1];
2612 rtx bytes_rtx = operands[2];
2613 rtx align_rtx = operands[3];
2614 const int align = INTVAL (align_rtx);
2615 rtx dst_reg, src_reg;
2616 tree dst_expr, src_expr;
2617
2618 /* We only handle a fixed number of bytes for now. */
2619 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2620 return 0;
2621
2622 /* Copy the addresses into scratch registers. */
2623 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2624 src_reg = copy_addr_to_reg (XEXP (src, 0));
2625
2626 /* Move the data with the appropriate granularity. */
2627 if (align >= 4)
2628 expand_block_move_4 (dst, dst_reg, src, src_reg, bytes_rtx);
2629 else if (align >= 2)
2630 expand_block_move_2 (dst, dst_reg, src, src_reg, bytes_rtx);
2631 else
2632 expand_block_move_1 (dst_reg, src_reg, bytes_rtx);
2633
2634 /* Since DST and SRC are passed to a libcall, mark the corresponding
2635 tree EXPR as addressable. */
2636 dst_expr = MEM_EXPR (dst);
2637 src_expr = MEM_EXPR (src);
2638 if (dst_expr)
2639 mark_addressable (dst_expr);
2640 if (src_expr)
2641 mark_addressable (src_expr);
2642
2643 return 1;
2644 }
2645
2646 /* Expand string/block set operations.
2647
2648 operands[0] is the pointer to the destination.
2649 operands[1] is the number of bytes to set.
2650 operands[2] is the source value.
2651 operands[3] is the alignment.
2652
2653 Return 1 upon success, 0 otherwise. */
2654
2655 int
2656 visium_expand_block_set (rtx *operands)
2657 {
2658 rtx dst = operands[0];
2659 rtx bytes_rtx = operands[1];
2660 rtx value_rtx = operands[2];
2661 rtx align_rtx = operands[3];
2662 const int align = INTVAL (align_rtx);
2663 rtx dst_reg;
2664 tree dst_expr;
2665
2666 /* We only handle a fixed number of bytes for now. */
2667 if (!CONST_INT_P (bytes_rtx) || INTVAL (bytes_rtx) <= 0)
2668 return 0;
2669
2670 /* Copy the address into a scratch register. */
2671 dst_reg = copy_addr_to_reg (XEXP (dst, 0));
2672
2673 /* Set the data with the appropriate granularity. */
2674 if (align >= 4)
2675 expand_block_set_4 (dst, dst_reg, value_rtx, bytes_rtx);
2676 else if (align >= 2)
2677 expand_block_set_2 (dst, dst_reg, value_rtx, bytes_rtx);
2678 else
2679 expand_block_set_1 (dst_reg, value_rtx, bytes_rtx);
2680
2681 /* Since DST is passed to a libcall, mark the corresponding
2682 tree EXPR as addressable. */
2683 dst_expr = MEM_EXPR (dst);
2684 if (dst_expr)
2685 mark_addressable (dst_expr);
2686
2687 return 1;
2688 }
2689
2690 /* Initialize a trampoline. M_TRAMP is an RTX for the memory block for the
2691 trampoline, FNDECL is the FUNCTION_DECL for the nested function and
2692 STATIC_CHAIN is an RTX for the static chain value that should be passed
2693 to the function when it is called. */
2694
2695 static void
2696 visium_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
2697 {
2698 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2699 rtx addr = XEXP (m_tramp, 0);
2700
2701 /* The trampoline initialization sequence is:
2702
2703 moviu r9,%u FUNCTION
2704 movil r9,%l FUNCTION
2705 [nop]
2706 moviu r20,%u STATIC
2707 bra tr,r9,r9
2708 movil r20,%l STATIC
2709
2710 We don't use r0 as the destination register of the branch because we want
2711 the Branch Pre-decode Logic of the GR6 to use the Address Load Array to
2712 predict the branch target. */
2713
2714 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 0)),
2715 plus_constant (SImode,
2716 expand_shift (RSHIFT_EXPR, SImode, fnaddr,
2717 16, NULL_RTX, 1),
2718 0x04a90000));
2719
2720 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 4)),
2721 plus_constant (SImode,
2722 expand_and (SImode, fnaddr, GEN_INT (0xffff),
2723 NULL_RTX),
2724 0x04890000));
2725
2726 if (visium_cpu == PROCESSOR_GR6)
2727 {
2728 /* For the GR6, the BRA insn must be aligned on a 64-bit boundary. */
2729 gcc_assert (TRAMPOLINE_ALIGNMENT >= 64);
2730 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)),
2731 gen_int_mode (0, SImode));
2732 }
2733
2734 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 8)),
2735 plus_constant (SImode,
2736 expand_shift (RSHIFT_EXPR, SImode,
2737 static_chain,
2738 16, NULL_RTX, 1),
2739 0x04b40000));
2740
2741 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 12)),
2742 gen_int_mode (0xff892404, SImode));
2743
2744 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, addr, 16)),
2745 plus_constant (SImode,
2746 expand_and (SImode, static_chain,
2747 GEN_INT (0xffff), NULL_RTX),
2748 0x04940000));
2749
2750 emit_library_call (set_trampoline_parity_libfunc, LCT_NORMAL, VOIDmode,
2751 addr, SImode);
2752 }
2753
2754 /* Return true if the current function must have and use a frame pointer. */
2755
2756 static bool
2757 visium_frame_pointer_required (void)
2758 {
2759 /* The frame pointer is required if the function isn't leaf to be able to
2760 do manual stack unwinding. */
2761 if (!crtl->is_leaf)
2762 return true;
2763
2764 /* If the stack pointer is dynamically modified in the function, it cannot
2765 serve as the frame pointer. */
2766 if (!crtl->sp_is_unchanging)
2767 return true;
2768
2769 /* If the function receives nonlocal gotos, it needs to save the frame
2770 pointer in the nonlocal_goto_save_area object. */
2771 if (cfun->has_nonlocal_label)
2772 return true;
2773
2774 /* The frame also needs to be established in some special cases. */
2775 if (visium_frame_needed)
2776 return true;
2777
2778 return false;
2779 }
2780
2781 /* Profiling support. Just a call to MCOUNT is needed. No labelled counter
2782 location is involved. Proper support for __builtin_return_address is also
2783 required, which is fairly straightforward provided a frame gets created. */
2784
2785 void
2786 visium_profile_hook (void)
2787 {
2788 visium_frame_needed = true;
2789 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "mcount"), LCT_NORMAL,
2790 VOIDmode);
2791 }
2792
2793 /* A C expression whose value is RTL representing the address in a stack frame
2794 where the pointer to the caller's frame is stored. Assume that FRAMEADDR is
2795 an RTL expression for the address of the stack frame itself.
2796
2797 If you don't define this macro, the default is to return the value of
2798 FRAMEADDR--that is, the stack frame address is also the address of the stack
2799 word that points to the previous frame. */
2800
2801 rtx
2802 visium_dynamic_chain_address (rtx frame)
2803 {
2804 /* This is the default, but we need to make sure the frame gets created. */
2805 visium_frame_needed = true;
2806 return frame;
2807 }
2808
2809 /* A C expression whose value is RTL representing the value of the return
2810 address for the frame COUNT steps up from the current frame, after the
2811 prologue. FRAMEADDR is the frame pointer of the COUNT frame, or the frame
2812 pointer of the COUNT - 1 frame if `RETURN_ADDR_IN_PREVIOUS_FRAME' is
2813 defined.
2814
2815 The value of the expression must always be the correct address when COUNT is
2816 zero, but may be `NULL_RTX' if there is not way to determine the return
2817 address of other frames. */
2818
2819 rtx
2820 visium_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
2821 {
2822 /* Dont try to compute anything other than frame zero. */
2823 if (count != 0)
2824 return NULL_RTX;
2825
2826 visium_frame_needed = true;
2827 return
2828 gen_frame_mem (Pmode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2829 }
2830
2831 /* Helper function for EH_RETURN_HANDLER_RTX. Return the RTX representing a
2832 location in which to store the address of an exception handler to which we
2833 should return. */
2834
2835 rtx
2836 visium_eh_return_handler_rtx (void)
2837 {
2838 rtx mem
2839 = gen_frame_mem (SImode, plus_constant (Pmode, hard_frame_pointer_rtx, 4));
2840 MEM_VOLATILE_P (mem) = 1;
2841 return mem;
2842 }
2843
2844 static struct machine_function *
2845 visium_init_machine_status (void)
2846 {
2847 return ggc_cleared_alloc<machine_function> ();
2848 }
2849
2850 /* The per-function data machinery is needed to indicate when a frame
2851 is required. */
2852
2853 void
2854 visium_init_expanders (void)
2855 {
2856 init_machine_status = visium_init_machine_status;
2857 }
2858
2859 /* Given a comparison code (EQ, NE, etc.) and the operands of a COMPARE,
2860 return the mode to be used for the comparison. */
2861
2862 machine_mode
2863 visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
2864 {
2865 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2866 {
2867 switch (code)
2868 {
2869 case EQ:
2870 case NE:
2871 case ORDERED:
2872 case UNORDERED:
2873 case UNLT:
2874 case UNLE:
2875 case UNGT:
2876 case UNGE:
2877 return CCFPmode;
2878
2879 case LT:
2880 case LE:
2881 case GT:
2882 case GE:
2883 return CCFPEmode;
2884
2885 /* These 2 comparison codes are not supported. */
2886 case UNEQ:
2887 case LTGT:
2888 default:
2889 gcc_unreachable ();
2890 }
2891 }
2892
2893 /* This is for the cmp<mode>_sne pattern. */
2894 if (op1 == constm1_rtx)
2895 return CCCmode;
2896
2897 /* This is for the add<mode>3_insn_set_carry pattern. */
2898 if ((code == LTU || code == GEU)
2899 && GET_CODE (op0) == PLUS
2900 && rtx_equal_p (XEXP (op0, 0), op1))
2901 return CCCmode;
2902
2903 /* This is for the {add,sub,neg}<mode>3_insn_set_overflow pattern. */
2904 if ((code == EQ || code == NE)
2905 && GET_CODE (op1) == UNSPEC
2906 && (XINT (op1, 1) == UNSPEC_ADDV
2907 || XINT (op1, 1) == UNSPEC_SUBV
2908 || XINT (op1, 1) == UNSPEC_NEGV))
2909 return CCVmode;
2910
2911 if (op1 != const0_rtx)
2912 return CCmode;
2913
2914 switch (GET_CODE (op0))
2915 {
2916 case PLUS:
2917 case MINUS:
2918 case NEG:
2919 case ASHIFT:
2920 case LTU:
2921 case LT:
2922 /* The C and V flags may be set differently from a COMPARE with zero.
2923 The consequence is that a comparison operator testing C or V must
2924 be turned into another operator not testing C or V and yielding
2925 the same result for a comparison with zero. That's possible for
2926 GE/LT which become NC/NS respectively, but not for GT/LE for which
2927 the altered operator doesn't exist on the Visium. */
2928 return CCNZmode;
2929
2930 case ZERO_EXTRACT:
2931 /* This is a btst, the result is in C instead of Z. */
2932 return CCCmode;
2933
2934 case REG:
2935 case AND:
2936 case IOR:
2937 case XOR:
2938 case NOT:
2939 case ASHIFTRT:
2940 case LSHIFTRT:
2941 case TRUNCATE:
2942 case SIGN_EXTEND:
2943 /* Pretend that the flags are set as for a COMPARE with zero.
2944 That's mostly true, except for the 2 right shift insns that
2945 will set the C flag. But the C flag is relevant only for
2946 the unsigned comparison operators and they are eliminated
2947 when applied to a comparison with zero. */
2948 return CCmode;
2949
2950 /* ??? Cater to the junk RTXes sent by try_merge_compare. */
2951 case ASM_OPERANDS:
2952 case CALL:
2953 case CONST_INT:
2954 case LO_SUM:
2955 case HIGH:
2956 case MEM:
2957 case UNSPEC:
2958 case ZERO_EXTEND:
2959 return CCmode;
2960
2961 default:
2962 gcc_unreachable ();
2963 }
2964 }
2965
2966 /* Split a compare-and-branch with CODE, operands OP0 and OP1, and LABEL. */
2967
2968 void
2969 visium_split_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx label)
2970 {
2971 machine_mode cc_mode = visium_select_cc_mode (code, op0, op1);
2972 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2973
2974 rtx x = gen_rtx_COMPARE (cc_mode, op0, op1);
2975 x = gen_rtx_SET (flags, x);
2976 emit_insn (x);
2977
2978 x = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
2979 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, gen_rtx_LABEL_REF (Pmode, label),
2980 pc_rtx);
2981 x = gen_rtx_SET (pc_rtx, x);
2982 emit_jump_insn (x);
2983
2984 visium_flags_exposed = true;
2985 }
2986
2987 /* Branch instructions on the Visium.
2988
2989 Setting aside the interrupt-handling specific instructions, the ISA has
2990 two branch instructions: BRR and BRA. The former is used to implement
2991 short branches (+/- 2^17) within functions and its target is encoded in
2992 the instruction. The latter is used to implement all the other types
2993 of control flow changes and its target might not be statically known
2994 or even easily predictable at run time. Here's a complete summary of
2995 the patterns that generate a BRA instruction:
2996
2997 1. Indirect jump
2998 2. Table jump
2999 3. Call
3000 4. Sibling call
3001 5. Return
3002 6. Long branch
3003 7. Trampoline
3004
3005 Among these patterns, only the return (5) and the long branch (6) can be
3006 conditional; all the other patterns are always unconditional.
3007
3008 The following algorithm can be used to identify the pattern for which
3009 the BRA instruction was generated and work out its target:
3010
3011 A. If the source is r21 and the destination is r0, this is a return (5)
3012 and the target is the caller (i.e. the value of r21 on function's
3013 entry).
3014
3015 B. If the source is rN, N != 21 and the destination is r0, this is either
3016 an indirect jump or a table jump (1, 2) and the target is not easily
3017 predictable.
3018
3019 C. If the source is rN, N != 21 and the destination is r21, this is a call
3020 (3) and the target is given by the preceding MOVIL/MOVIU pair for rN,
3021 unless this is an indirect call in which case the target is not easily
3022 predictable.
3023
3024 D. If the source is rN, N != 21 and the destination is also rN, this is
3025 either a sibling call or a trampoline (4, 7) and the target is given
3026 by the preceding MOVIL/MOVIU pair for rN.
3027
3028 E. If the source is r21 and the destination is also r21, this is a long
3029 branch (6) and the target is given by the preceding MOVIL/MOVIU pair
3030 for r21.
3031
3032 The other combinations are not used. This implementation has been devised
3033 to accommodate the branch predictor of the GR6 but is used unconditionally
3034 by the compiler, i.e. including for earlier processors. */
3035
3036 /* Output a conditional/unconditional branch to LABEL. COND is the string
3037 condition. INSN is the instruction. */
3038
3039 static const char *
3040 output_branch (rtx label, const char *cond, rtx_insn *insn)
3041 {
3042 char str[64];
3043 rtx operands[2];
3044
3045 gcc_assert (cond);
3046 operands[0] = label;
3047
3048 /* If the length of the instruction is greater than 12, then this is a
3049 long branch and we need to work harder to emit it properly. */
3050 if (get_attr_length (insn) > 12)
3051 {
3052 bool spilled;
3053
3054 /* If the link register has been saved, then we use it. */
3055 if (current_function_saves_lr ())
3056 {
3057 operands[1] = regno_reg_rtx [LINK_REGNUM];
3058 spilled = false;
3059 }
3060
3061 /* Or else, if the long-branch register isn't live, we use it. */
3062 else if (!df_regs_ever_live_p (long_branch_regnum))
3063 {
3064 operands[1] = regno_reg_rtx [long_branch_regnum];
3065 spilled = false;
3066 }
3067
3068 /* Otherwise, we will use the long-branch register but we need to
3069 spill it to the stack and reload it at the end. We should have
3070 reserved the LR slot for this purpose. */
3071 else
3072 {
3073 operands[1] = regno_reg_rtx [long_branch_regnum];
3074 spilled = true;
3075 gcc_assert (current_function_has_lr_slot ());
3076 }
3077
3078 /* First emit the spill to the stack:
3079
3080 insn_in_delay_slot
3081 write.l [1](sp),reg */
3082 if (spilled)
3083 {
3084 if (final_sequence)
3085 {
3086 rtx_insn *delay = NEXT_INSN (insn);
3087 gcc_assert (delay);
3088
3089 final_scan_insn (delay, asm_out_file, optimize, 0, NULL);
3090 PATTERN (delay) = gen_blockage ();
3091 INSN_CODE (delay) = -1;
3092 }
3093
3094 if (current_function_saves_fp ())
3095 output_asm_insn ("write.l 1(sp),%1", operands);
3096 else
3097 output_asm_insn ("write.l (sp),%1", operands);
3098 }
3099
3100 /* Then emit the core sequence:
3101
3102 moviu reg,%u label
3103 movil reg,%l label
3104 bra tr,reg,reg
3105
3106 We don't use r0 as the destination register of the branch because we
3107 want the Branch Pre-decode Logic of the GR6 to use the Address Load
3108 Array to predict the branch target. */
3109 output_asm_insn ("moviu %1,%%u %0", operands);
3110 output_asm_insn ("movil %1,%%l %0", operands);
3111 strcpy (str, "bra ");
3112 strcat (str, cond);
3113 strcat (str, ",%1,%1");
3114 if (!spilled)
3115 strcat (str, "%#");
3116 strcat (str, "\t\t;long branch");
3117 output_asm_insn (str, operands);
3118
3119 /* Finally emit the reload:
3120
3121 read.l reg,[1](sp) */
3122 if (spilled)
3123 {
3124 if (current_function_saves_fp ())
3125 output_asm_insn (" read.l %1,1(sp)", operands);
3126 else
3127 output_asm_insn (" read.l %1,(sp)", operands);
3128 }
3129 }
3130
3131 /* Or else, if the label is PC, then this is a return. */
3132 else if (label == pc_rtx)
3133 {
3134 strcpy (str, "bra ");
3135 strcat (str, cond);
3136 strcat (str, ",r21,r0%#\t\t;return");
3137 output_asm_insn (str, operands);
3138 }
3139
3140 /* Otherwise, this is a short branch. */
3141 else
3142 {
3143 strcpy (str, "brr ");
3144 strcat (str, cond);
3145 strcat (str, ",%0%#");
3146 output_asm_insn (str, operands);
3147 }
3148
3149 return "";
3150 }
3151
3152 /* Output an unconditional branch to LABEL. INSN is the instruction. */
3153
3154 const char *
3155 output_ubranch (rtx label, rtx_insn *insn)
3156 {
3157 return output_branch (label, "tr", insn);
3158 }
3159
3160 /* Output a conditional branch to LABEL. CODE is the comparison code.
3161 CC_MODE is the mode of the CC register. REVERSED is non-zero if we
3162 should reverse the sense of the comparison. INSN is the instruction. */
3163
3164 const char *
3165 output_cbranch (rtx label, enum rtx_code code, machine_mode cc_mode,
3166 int reversed, rtx_insn *insn)
3167 {
3168 const char *cond;
3169
3170 if (reversed)
3171 {
3172 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3173 code = reverse_condition_maybe_unordered (code);
3174 else
3175 code = reverse_condition (code);
3176 }
3177
3178 switch (code)
3179 {
3180 case NE:
3181 if (cc_mode == CCCmode)
3182 cond = "cs";
3183 else if (cc_mode == CCVmode)
3184 cond = "os";
3185 else
3186 cond = "ne";
3187 break;
3188
3189 case EQ:
3190 if (cc_mode == CCCmode)
3191 cond = "cc";
3192 else if (cc_mode == CCVmode)
3193 cond = "oc";
3194 else
3195 cond = "eq";
3196 break;
3197
3198 case GE:
3199 if (cc_mode == CCNZmode)
3200 cond = "nc";
3201 else
3202 cond = "ge";
3203 break;
3204
3205 case GT:
3206 cond = "gt";
3207 break;
3208
3209 case LE:
3210 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3211 cond = "ls";
3212 else
3213 cond = "le";
3214 break;
3215
3216 case LT:
3217 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3218 cond = "cs"; /* or "ns" */
3219 else if (cc_mode == CCNZmode)
3220 cond = "ns";
3221 else
3222 cond = "lt";
3223 break;
3224
3225 case GEU:
3226 cond = "cc";
3227 break;
3228
3229 case GTU:
3230 cond = "hi";
3231 break;
3232
3233 case LEU:
3234 cond = "ls";
3235 break;
3236
3237 case LTU:
3238 cond = "cs";
3239 break;
3240
3241 case UNORDERED:
3242 cond = "os";
3243 break;
3244
3245 case ORDERED:
3246 cond = "oc";
3247 break;
3248
3249 case UNGE:
3250 cond = "cc"; /* or "nc" */
3251 break;
3252
3253 case UNGT:
3254 cond = "hi";
3255 break;
3256
3257 case UNLE:
3258 cond = "le";
3259 break;
3260
3261 case UNLT:
3262 cond = "lt";
3263 break;
3264
3265 /* These 2 comparison codes are not supported. */
3266 case UNEQ:
3267 case LTGT:
3268 default:
3269 gcc_unreachable ();
3270 }
3271
3272 return output_branch (label, cond, insn);
3273 }
3274
3275 /* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
3276
3277 static bool
3278 visium_print_operand_punct_valid_p (unsigned char code)
3279 {
3280 return code == '#';
3281 }
3282
3283 /* Implement TARGET_PRINT_OPERAND. Output to stdio stream FILE the assembler
3284 syntax for an instruction operand OP subject to the modifier LETTER. */
3285
3286 static void
3287 visium_print_operand (FILE *file, rtx op, int letter)
3288 {
3289 switch (letter)
3290 {
3291 case '#':
3292 /* Output an insn in a delay slot. */
3293 if (final_sequence)
3294 visium_indent_opcode = 1;
3295 else
3296 fputs ("\n\t nop", file);
3297 return;
3298
3299 case 'b':
3300 /* Print LS 8 bits of operand. */
3301 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xff);
3302 return;
3303
3304 case 'w':
3305 /* Print LS 16 bits of operand. */
3306 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xffff);
3307 return;
3308
3309 case 'u':
3310 /* Print MS 16 bits of operand. */
3311 fprintf (file,
3312 HOST_WIDE_INT_PRINT_UNSIGNED, (UINTVAL (op) >> 16) & 0xffff);
3313 return;
3314
3315 case 'r':
3316 /* It's either a register or zero. */
3317 if (GET_CODE (op) == REG)
3318 fputs (reg_names[REGNO (op)], file);
3319 else
3320 fputs (reg_names[0], file);
3321 return;
3322
3323 case 'f':
3324 /* It's either a FP register or zero. */
3325 if (GET_CODE (op) == REG)
3326 fputs (reg_names[REGNO (op)], file);
3327 else
3328 fputs (reg_names[FP_FIRST_REGNUM], file);
3329 return;
3330 }
3331
3332 switch (GET_CODE (op))
3333 {
3334 case REG:
3335 if (letter == 'd')
3336 fputs (reg_names[REGNO (op) + 1], file);
3337 else
3338 fputs (reg_names[REGNO (op)], file);
3339 break;
3340
3341 case SYMBOL_REF:
3342 case LABEL_REF:
3343 case CONST:
3344 output_addr_const (file, op);
3345 break;
3346
3347 case MEM:
3348 visium_print_operand_address (file, GET_MODE (op), XEXP (op, 0));
3349 break;
3350
3351 case CONST_INT:
3352 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
3353 break;
3354
3355 case CODE_LABEL:
3356 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (op));
3357 break;
3358
3359 case HIGH:
3360 visium_print_operand (file, XEXP (op, 1), letter);
3361 break;
3362
3363 default:
3364 fatal_insn ("illegal operand ", op);
3365 }
3366 }
3367
3368 /* Implement TARGET_PRINT_OPERAND_ADDRESS. Output to stdio stream FILE the
3369 assembler syntax for an instruction operand that is a memory reference
3370 whose address is ADDR. */
3371
3372 static void
3373 visium_print_operand_address (FILE *file, machine_mode mode, rtx addr)
3374 {
3375 switch (GET_CODE (addr))
3376 {
3377 case REG:
3378 case SUBREG:
3379 fprintf (file, "(%s)", reg_names[true_regnum (addr)]);
3380 break;
3381
3382 case PLUS:
3383 {
3384 rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
3385
3386 switch (GET_CODE (x))
3387 {
3388 case REG:
3389 case SUBREG:
3390 if (CONST_INT_P (y))
3391 {
3392 unsigned int regno = true_regnum (x);
3393 HOST_WIDE_INT val = INTVAL (y);
3394 switch (mode)
3395 {
3396 case E_SImode:
3397 case E_DImode:
3398 case E_SFmode:
3399 case E_DFmode:
3400 val >>= 2;
3401 break;
3402
3403 case E_HImode:
3404 val >>= 1;
3405 break;
3406
3407 case E_QImode:
3408 default:
3409 break;
3410 }
3411 fprintf (file, HOST_WIDE_INT_PRINT_DEC"(%s)", val,
3412 reg_names[regno]);
3413 }
3414 else
3415 fatal_insn ("illegal operand address (1)", addr);
3416 break;
3417
3418 default:
3419 if (CONSTANT_P (x) && CONSTANT_P (y))
3420 output_addr_const (file, addr);
3421 else
3422 fatal_insn ("illegal operand address (2)", addr);
3423 break;
3424 }
3425 }
3426 break;
3427
3428 case LABEL_REF:
3429 case SYMBOL_REF:
3430 case CONST_INT:
3431 case CONST:
3432 output_addr_const (file, addr);
3433 break;
3434
3435 case NOTE:
3436 if (NOTE_KIND (addr) != NOTE_INSN_DELETED_LABEL)
3437 fatal_insn ("illegal operand address (3)", addr);
3438 break;
3439
3440 case CODE_LABEL:
3441 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (addr));
3442 break;
3443
3444 default:
3445 fatal_insn ("illegal operand address (4)", addr);
3446 break;
3447 }
3448 }
3449
3450 /* The Visium stack frames look like:
3451
3452 Before call After call
3453 +-----------------------+ +-----------------------+
3454 | | | |
3455 high | previous | | previous |
3456 mem | frame | | frame |
3457 | | | |
3458 +-----------------------+ +-----------------------+
3459 | | | |
3460 | arguments on stack | | arguments on stack |
3461 | | | |
3462 SP+0->+-----------------------+ +-----------------------+
3463 | reg parm save area, |
3464 | only created for |
3465 | variable argument |
3466 | functions |
3467 +-----------------------+
3468 | |
3469 | register save area |
3470 | |
3471 +-----------------------+
3472 | |
3473 | local variables |
3474 | |
3475 FP+8->+-----------------------+
3476 | return address |
3477 FP+4->+-----------------------+
3478 | previous FP |
3479 FP+0->+-----------------------+
3480 | |
3481 | alloca allocations |
3482 | |
3483 +-----------------------+
3484 | |
3485 low | arguments on stack |
3486 mem | |
3487 SP+0->+-----------------------+
3488
3489 Notes:
3490 1) The "reg parm save area" does not exist for non variable argument fns.
3491 2) The FP register is not saved if `frame_pointer_needed' is zero and it
3492 is not altered in the current function.
3493 3) The return address is not saved if there is no frame pointer and the
3494 current function is leaf.
3495 4) If the return address is not saved and the static chain register is
3496 live in the function, we allocate the return address slot to be able
3497 to spill the register for a long branch. */
3498
3499 /* Define the register classes for local purposes. */
3500 enum reg_type { general, mdb, mdc, floating, last_type};
3501
3502 #define GET_REG_TYPE(regno) \
3503 (GP_REGISTER_P (regno) ? general : \
3504 (regno) == MDB_REGNUM ? mdb : \
3505 (regno) == MDC_REGNUM ? mdc : \
3506 floating)
3507
3508 /* First regno of each register type. */
3509 const int first_regno[last_type] = {0, MDB_REGNUM, MDC_REGNUM, FP_FIRST_REGNUM};
3510
3511 /* Size in bytes of each register type. */
3512 const int reg_type_size[last_type] = {4, 8, 4, 4};
3513
3514 /* Structure to be filled in by visium_compute_frame_size. */
3515 struct visium_frame_info
3516 {
3517 unsigned int save_area_size; /* # bytes in the reg parm save area. */
3518 unsigned int reg_size1; /* # bytes to store first block of regs. */
3519 unsigned int reg_size2; /* # bytes to store second block of regs. */
3520 unsigned int max_reg1; /* max. regno in first block */
3521 unsigned int var_size; /* # bytes that variables take up. */
3522 unsigned int save_fp; /* Nonzero if fp must be saved. */
3523 unsigned int save_lr; /* Nonzero if lr must be saved. */
3524 unsigned int lr_slot; /* Nonzero if the lr slot is needed. */
3525 unsigned int combine; /* Nonzero if we can combine the allocation of
3526 variables and regs. */
3527 unsigned int interrupt; /* Nonzero if the function is an interrupt
3528 handler. */
3529 unsigned int mask[last_type]; /* Masks of saved regs: gp, mdb, mdc, fp */
3530 };
3531
3532 /* Current frame information calculated by visium_compute_frame_size. */
3533 static struct visium_frame_info current_frame_info;
3534
3535 /* Accessor for current_frame_info.save_fp. */
3536
3537 static inline bool
3538 current_function_saves_fp (void)
3539 {
3540 return current_frame_info.save_fp != 0;
3541 }
3542
3543 /* Accessor for current_frame_info.save_lr. */
3544
3545 static inline bool
3546 current_function_saves_lr (void)
3547 {
3548 return current_frame_info.save_lr != 0;
3549 }
3550
3551 /* Accessor for current_frame_info.lr_slot. */
3552
3553 static inline bool
3554 current_function_has_lr_slot (void)
3555 {
3556 return current_frame_info.lr_slot != 0;
3557 }
3558
3559 /* Return non-zero if register REGNO needs to be saved in the frame. */
3560
3561 static int
3562 visium_save_reg_p (int interrupt, int regno)
3563 {
3564 switch (regno)
3565 {
3566 case HARD_FRAME_POINTER_REGNUM:
3567 /* This register is call-saved but handled specially. */
3568 return 0;
3569
3570 case MDC_REGNUM:
3571 /* This register is fixed but can be modified. */
3572 break;
3573
3574 case 29:
3575 case 30:
3576 /* These registers are fixed and hold the interrupt context. */
3577 return (interrupt != 0);
3578
3579 default:
3580 /* The other fixed registers are either immutable or special. */
3581 if (fixed_regs[regno])
3582 return 0;
3583 break;
3584 }
3585
3586 if (interrupt)
3587 {
3588 if (crtl->is_leaf)
3589 {
3590 if (df_regs_ever_live_p (regno))
3591 return 1;
3592 }
3593 else if (call_used_or_fixed_reg_p (regno))
3594 return 1;
3595
3596 /* To save mdb requires two temporary registers. To save mdc or
3597 any of the floating registers requires one temporary
3598 register. If this is an interrupt routine, the temporary
3599 registers need to be saved as well. These temporary registers
3600 are call used, so we only need deal with the case of leaf
3601 functions here. */
3602 if (regno == PROLOGUE_TMP_REGNUM)
3603 {
3604 if (df_regs_ever_live_p (MDB_REGNUM)
3605 || df_regs_ever_live_p (MDC_REGNUM))
3606 return 1;
3607
3608 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
3609 if (df_regs_ever_live_p (i))
3610 return 1;
3611 }
3612
3613 else if (regno == PROLOGUE_TMP_REGNUM + 1)
3614 {
3615 if (df_regs_ever_live_p (MDB_REGNUM))
3616 return 1;
3617 }
3618 }
3619
3620 return df_regs_ever_live_p (regno) && !call_used_or_fixed_reg_p (regno);
3621 }
3622
3623 /* Compute the frame size required by the function. This function is called
3624 during the reload pass and also by visium_expand_prologue. */
3625
3626 static int
3627 visium_compute_frame_size (int size)
3628 {
3629 const int save_area_size = visium_reg_parm_save_area_size;
3630 const int var_size = VISIUM_STACK_ALIGN (size);
3631 const int save_fp
3632 = frame_pointer_needed || df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM);
3633 const int save_lr = frame_pointer_needed || !crtl->is_leaf;
3634 const int lr_slot = !save_lr && df_regs_ever_live_p (long_branch_regnum);
3635 const int local_frame_offset
3636 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3637 const int interrupt = visium_interrupt_function_p ();
3638 unsigned int mask[last_type];
3639 int reg_size1 = 0;
3640 int max_reg1 = 0;
3641 int reg_size2 = 0;
3642 int reg_size;
3643 int combine;
3644 int frame_size;
3645 int regno;
3646
3647 memset (mask, 0, last_type * sizeof (unsigned int));
3648
3649 /* The registers may need stacking in 2 blocks since only 32 32-bit words
3650 can be indexed from a given base address. */
3651 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3652 {
3653 if (visium_save_reg_p (interrupt, regno))
3654 {
3655 enum reg_type reg_type = GET_REG_TYPE (regno);
3656 int mask_bit = 1 << (regno - first_regno[reg_type]);
3657 int nbytes = reg_type_size[reg_type];
3658
3659 if (reg_size1 + nbytes > 32 * UNITS_PER_WORD)
3660 break;
3661
3662 reg_size1 += nbytes;
3663 max_reg1 = regno;
3664 mask[reg_type] |= mask_bit;
3665 }
3666 }
3667
3668 for (regno = max_reg1 + 1; regno < FIRST_PSEUDO_REGISTER; regno++)
3669 {
3670 if (visium_save_reg_p (interrupt, regno))
3671 {
3672 enum reg_type reg_type = GET_REG_TYPE (regno);
3673 int mask_bit = 1 << (regno - first_regno[reg_type]);
3674 int nbytes = reg_type_size[reg_type];
3675
3676 reg_size2 += nbytes;
3677 mask[reg_type] |= mask_bit;
3678 }
3679 }
3680
3681 reg_size = reg_size2 ? reg_size2 : reg_size1;
3682 combine = (local_frame_offset + var_size + reg_size) <= 32 * UNITS_PER_WORD;
3683 frame_size
3684 = local_frame_offset + var_size + reg_size2 + reg_size1 + save_area_size;
3685
3686 current_frame_info.save_area_size = save_area_size;
3687 current_frame_info.reg_size1 = reg_size1;
3688 current_frame_info.max_reg1 = max_reg1;
3689 current_frame_info.reg_size2 = reg_size2;
3690 current_frame_info.var_size = var_size;
3691 current_frame_info.save_fp = save_fp;
3692 current_frame_info.save_lr = save_lr;
3693 current_frame_info.lr_slot = lr_slot;
3694 current_frame_info.combine = combine;
3695 current_frame_info.interrupt = interrupt;
3696
3697 memcpy (current_frame_info.mask, mask, last_type * sizeof (unsigned int));
3698
3699 return frame_size;
3700 }
3701
3702 /* Helper function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define
3703 the offset between two registers, one to be eliminated, and the other its
3704 replacement, at the start of a routine. */
3705
3706 int
3707 visium_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
3708 {
3709 const int save_fp = current_frame_info.save_fp;
3710 const int save_lr = current_frame_info.save_lr;
3711 const int lr_slot = current_frame_info.lr_slot;
3712 int offset;
3713
3714 if (from == FRAME_POINTER_REGNUM)
3715 offset = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3716 else if (from == ARG_POINTER_REGNUM)
3717 offset = visium_compute_frame_size (get_frame_size ());
3718 else
3719 gcc_unreachable ();
3720
3721 return offset;
3722 }
3723
3724 /* For an interrupt handler, we may be saving call-clobbered registers.
3725 Say the epilogue uses these in addition to the link register. */
3726
3727 int
3728 visium_epilogue_uses (int regno)
3729 {
3730 if (regno == LINK_REGNUM)
3731 return 1;
3732
3733 if (reload_completed)
3734 {
3735 enum reg_type reg_type = GET_REG_TYPE (regno);
3736 int mask_bit = 1 << (regno - first_regno[reg_type]);
3737
3738 return (current_frame_info.mask[reg_type] & mask_bit) != 0;
3739 }
3740
3741 return 0;
3742 }
3743
3744 /* Wrapper around emit_insn that sets RTX_FRAME_RELATED_P on the insn. */
3745
3746 static rtx
3747 emit_frame_insn (rtx x)
3748 {
3749 x = emit_insn (x);
3750 RTX_FRAME_RELATED_P (x) = 1;
3751 return x;
3752 }
3753
3754 /* Allocate ALLOC bytes on the stack and save the registers LOW_REGNO to
3755 HIGH_REGNO at OFFSET from the stack pointer. */
3756
3757 static void
3758 visium_save_regs (int alloc, int offset, int low_regno, int high_regno)
3759 {
3760 /* If this is an interrupt handler function, then mark the register
3761 stores as volatile. This will prevent the instruction scheduler
3762 from scrambling the order of register saves. */
3763 const int volatile_p = current_frame_info.interrupt;
3764 int regno;
3765
3766 /* Allocate the stack space. */
3767 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, stack_pointer_rtx,
3768 GEN_INT (-alloc)));
3769
3770 for (regno = low_regno; regno <= high_regno; regno++)
3771 {
3772 enum reg_type reg_type = GET_REG_TYPE (regno);
3773 int mask_bit = 1 << (regno - first_regno[reg_type]);
3774 rtx insn;
3775
3776 if (current_frame_info.mask[reg_type] & mask_bit)
3777 {
3778 offset -= reg_type_size[reg_type];
3779 switch (reg_type)
3780 {
3781 case general:
3782 {
3783 rtx mem
3784 = gen_frame_mem (SImode,
3785 plus_constant (Pmode,
3786 stack_pointer_rtx, offset));
3787 MEM_VOLATILE_P (mem) = volatile_p;
3788 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, regno)));
3789 }
3790 break;
3791
3792 case mdb:
3793 {
3794 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3795 rtx mem
3796 = gen_frame_mem (DImode,
3797 plus_constant (Pmode,
3798 stack_pointer_rtx, offset));
3799 rtx reg = gen_rtx_REG (DImode, regno);
3800 MEM_VOLATILE_P (mem) = volatile_p;
3801 emit_insn (gen_movdi (tmp, reg));
3802 /* Do not generate CFI if in interrupt handler. */
3803 if (volatile_p)
3804 emit_insn (gen_movdi (mem, tmp));
3805 else
3806 {
3807 insn = emit_frame_insn (gen_movdi (mem, tmp));
3808 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3809 gen_rtx_SET (mem, reg));
3810 }
3811 }
3812 break;
3813
3814 case mdc:
3815 {
3816 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3817 rtx mem
3818 = gen_frame_mem (SImode,
3819 plus_constant (Pmode,
3820 stack_pointer_rtx, offset));
3821 rtx reg = gen_rtx_REG (SImode, regno);
3822 MEM_VOLATILE_P (mem) = volatile_p;
3823 emit_insn (gen_movsi (tmp, reg));
3824 insn = emit_frame_insn (gen_movsi (mem, tmp));
3825 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3826 gen_rtx_SET (mem, reg));
3827 }
3828 break;
3829
3830 case floating:
3831 {
3832 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3833 rtx mem
3834 = gen_frame_mem (SFmode,
3835 plus_constant (Pmode,
3836 stack_pointer_rtx, offset));
3837 rtx reg = gen_rtx_REG (SFmode, regno);
3838 MEM_VOLATILE_P (mem) = volatile_p;
3839 emit_insn (gen_movsf (tmp, reg));
3840 insn = emit_frame_insn (gen_movsf (mem, tmp));
3841 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3842 gen_rtx_SET (mem, reg));
3843 }
3844 break;
3845
3846 default:
3847 break;
3848 }
3849 }
3850 }
3851 }
3852
3853 /* This function generates the code for function entry. */
3854
3855 void
3856 visium_expand_prologue (void)
3857 {
3858 const int frame_size = visium_compute_frame_size (get_frame_size ());
3859 const int save_area_size = current_frame_info.save_area_size;
3860 const int reg_size1 = current_frame_info.reg_size1;
3861 const int max_reg1 = current_frame_info.max_reg1;
3862 const int reg_size2 = current_frame_info.reg_size2;
3863 const int var_size = current_frame_info.var_size;
3864 const int save_fp = current_frame_info.save_fp;
3865 const int save_lr = current_frame_info.save_lr;
3866 const int lr_slot = current_frame_info.lr_slot;
3867 const int local_frame_offset
3868 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3869 const int combine = current_frame_info.combine;
3870 int reg_size;
3871 int first_reg;
3872 int fsize;
3873
3874 /* Save the frame size for future references. */
3875 visium_frame_size = frame_size;
3876
3877 if (flag_stack_usage_info)
3878 current_function_static_stack_size = frame_size;
3879
3880 /* If the registers have to be stacked in 2 blocks, stack the first one. */
3881 if (reg_size2)
3882 {
3883 visium_save_regs (reg_size1 + save_area_size, reg_size1, 0, max_reg1);
3884 reg_size = reg_size2;
3885 first_reg = max_reg1 + 1;
3886 fsize = local_frame_offset + var_size + reg_size2;
3887 }
3888 else
3889 {
3890 reg_size = reg_size1;
3891 first_reg = 0;
3892 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
3893 }
3894
3895 /* If we can't combine register stacking with variable allocation, partially
3896 allocate and stack the (remaining) registers now. */
3897 if (reg_size && !combine)
3898 visium_save_regs (fsize - local_frame_offset - var_size, reg_size,
3899 first_reg, FIRST_PSEUDO_REGISTER - 1);
3900
3901 /* If we can combine register stacking with variable allocation, fully
3902 allocate and stack the (remaining) registers now. */
3903 if (reg_size && combine)
3904 visium_save_regs (fsize, local_frame_offset + var_size + reg_size,
3905 first_reg, FIRST_PSEUDO_REGISTER - 1);
3906
3907 /* Otherwise space may still need to be allocated for the variables. */
3908 else if (fsize)
3909 {
3910 const int alloc_size = reg_size ? local_frame_offset + var_size : fsize;
3911
3912 if (alloc_size > 65535)
3913 {
3914 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM), insn;
3915 emit_insn (gen_movsi (tmp, GEN_INT (alloc_size)));
3916 insn = emit_frame_insn (gen_subsi3_flags (stack_pointer_rtx,
3917 stack_pointer_rtx,
3918 tmp));
3919 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
3920 gen_rtx_SET (stack_pointer_rtx,
3921 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3922 GEN_INT (-alloc_size))));
3923 }
3924 else
3925 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx,
3926 stack_pointer_rtx,
3927 GEN_INT (-alloc_size)));
3928 }
3929
3930 if (save_fp)
3931 emit_frame_insn (gen_movsi (gen_frame_mem (SImode, stack_pointer_rtx),
3932 hard_frame_pointer_rtx));
3933
3934 if (frame_pointer_needed)
3935 emit_frame_insn (gen_stack_save ());
3936
3937 if (save_lr)
3938 {
3939 rtx base_rtx, mem;
3940
3941 /* Normally the frame pointer and link register get saved via
3942 write.l (sp),fp
3943 move.l fp,sp
3944 write.l 1(sp),r21
3945
3946 Indexing off sp rather than fp to store the link register
3947 avoids presenting the instruction scheduler with an initial
3948 pipeline hazard. If however the frame is needed for eg.
3949 __builtin_return_address which needs to retrieve the saved
3950 value of the link register from the stack at fp + 4 then
3951 indexing from sp can confuse the dataflow, causing the link
3952 register to be retrieved before it has been saved. */
3953 if (cfun->machine->frame_needed)
3954 base_rtx = hard_frame_pointer_rtx;
3955 else
3956 base_rtx = stack_pointer_rtx;
3957
3958 mem = gen_frame_mem (SImode,
3959 plus_constant (Pmode,
3960 base_rtx, save_fp * UNITS_PER_WORD));
3961 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, LINK_REGNUM)));
3962 }
3963 }
3964
3965 static GTY(()) rtx cfa_restores;
3966
3967 /* Queue a REG_CFA_RESTORE note until next stack manipulation insn. */
3968
3969 static void
3970 visium_add_cfa_restore_note (rtx reg)
3971 {
3972 cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
3973 }
3974
3975 /* Add queued REG_CFA_RESTORE notes to INSN, if any. */
3976
3977 static void
3978 visium_add_queued_cfa_restore_notes (rtx insn)
3979 {
3980 rtx last;
3981 if (!cfa_restores)
3982 return;
3983 for (last = cfa_restores; XEXP (last, 1); last = XEXP (last, 1))
3984 ;
3985 XEXP (last, 1) = REG_NOTES (insn);
3986 REG_NOTES (insn) = cfa_restores;
3987 cfa_restores = NULL_RTX;
3988 }
3989
3990 /* Restore the registers LOW_REGNO to HIGH_REGNO from the save area at OFFSET
3991 from the stack pointer and pop DEALLOC bytes off the stack. */
3992
3993 static void
3994 visium_restore_regs (int dealloc, int offset, int high_regno, int low_regno)
3995 {
3996 /* If this is an interrupt handler function, then mark the register
3997 restores as volatile. This will prevent the instruction scheduler
3998 from scrambling the order of register restores. */
3999 const int volatile_p = current_frame_info.interrupt;
4000 int r30_offset = -1;
4001 int regno;
4002
4003 for (regno = high_regno; regno >= low_regno; --regno)
4004 {
4005 enum reg_type reg_type = GET_REG_TYPE (regno);
4006 int mask_bit = 1 << (regno - first_regno[reg_type]);
4007
4008 if (current_frame_info.mask[reg_type] & mask_bit)
4009 {
4010 switch (reg_type)
4011 {
4012 case general:
4013 /* Postpone restoring the interrupted context registers
4014 until last, since they need to be preceded by a dsi. */
4015 if (regno == 29)
4016 ;
4017 else if (regno == 30)
4018 r30_offset = offset;
4019 else
4020 {
4021 rtx mem
4022 = gen_frame_mem (SImode,
4023 plus_constant (Pmode,
4024 stack_pointer_rtx,
4025 offset));
4026 rtx reg = gen_rtx_REG (SImode, regno);
4027 MEM_VOLATILE_P (mem) = volatile_p;
4028 emit_insn (gen_movsi (reg, mem));
4029 visium_add_cfa_restore_note (reg);
4030 }
4031 break;
4032
4033 case mdb:
4034 {
4035 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
4036 rtx mem
4037 = gen_frame_mem (DImode,
4038 plus_constant (Pmode,
4039 stack_pointer_rtx, offset));
4040 rtx reg = gen_rtx_REG (DImode, regno);
4041 MEM_VOLATILE_P (mem) = volatile_p;
4042 emit_insn (gen_movdi (tmp, mem));
4043 emit_insn (gen_movdi (reg, tmp));
4044 /* Do not generate CFI if in interrupt handler. */
4045 if (!volatile_p)
4046 visium_add_cfa_restore_note (reg);
4047 }
4048 break;
4049
4050 case mdc:
4051 {
4052 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4053 rtx mem
4054 = gen_frame_mem (SImode,
4055 plus_constant (Pmode,
4056 stack_pointer_rtx, offset));
4057 rtx reg = gen_rtx_REG (SImode, regno);
4058 MEM_VOLATILE_P (mem) = volatile_p;
4059 emit_insn (gen_movsi (tmp, mem));
4060 emit_insn (gen_movsi (reg, tmp));
4061 visium_add_cfa_restore_note (reg);
4062 }
4063 break;
4064
4065 case floating:
4066 {
4067 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
4068 rtx mem
4069 = gen_frame_mem (SFmode,
4070 plus_constant (Pmode,
4071 stack_pointer_rtx, offset));
4072 rtx reg = gen_rtx_REG (SFmode, regno);
4073 MEM_VOLATILE_P (mem) = volatile_p;
4074 emit_insn (gen_movsf (tmp, mem));
4075 emit_insn (gen_movsf (reg, tmp));
4076 visium_add_cfa_restore_note (reg);
4077 }
4078 break;
4079
4080 default:
4081 break;
4082 }
4083
4084 offset += reg_type_size[reg_type];
4085 }
4086 }
4087
4088 /* If the interrupted context needs to be restored, precede the
4089 restores of r29 and r30 by a dsi. */
4090 if (r30_offset >= 0)
4091 {
4092 emit_insn (gen_dsi ());
4093 emit_move_insn (gen_rtx_REG (SImode, 30),
4094 gen_frame_mem (SImode,
4095 plus_constant (Pmode,
4096 stack_pointer_rtx,
4097 r30_offset)));
4098 emit_move_insn (gen_rtx_REG (SImode, 29),
4099 gen_frame_mem (SImode,
4100 plus_constant (Pmode,
4101 stack_pointer_rtx,
4102 r30_offset + 4)));
4103 }
4104
4105 /* Deallocate the stack space. */
4106 rtx insn = emit_frame_insn (gen_stack_pop (GEN_INT (dealloc)));
4107 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4108 gen_rtx_SET (stack_pointer_rtx,
4109 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4110 GEN_INT (dealloc))));
4111 visium_add_queued_cfa_restore_notes (insn);
4112 }
4113
4114 /* This function generates the code for function exit. */
4115
4116 void
4117 visium_expand_epilogue (void)
4118 {
4119 const int save_area_size = current_frame_info.save_area_size;
4120 const int reg_size1 = current_frame_info.reg_size1;
4121 const int max_reg1 = current_frame_info.max_reg1;
4122 const int reg_size2 = current_frame_info.reg_size2;
4123 const int var_size = current_frame_info.var_size;
4124 const int restore_fp = current_frame_info.save_fp;
4125 const int restore_lr = current_frame_info.save_lr;
4126 const int lr_slot = current_frame_info.lr_slot;
4127 const int local_frame_offset
4128 = (restore_fp + restore_lr + lr_slot) * UNITS_PER_WORD;
4129 const int combine = current_frame_info.combine;
4130 int reg_size;
4131 int last_reg;
4132 int fsize;
4133
4134 /* Do not bother restoring the stack pointer if it hasn't been changed in
4135 the function since it was saved _after_ the allocation of the frame. */
4136 if (!crtl->sp_is_unchanging)
4137 emit_insn (gen_stack_restore ());
4138
4139 /* Restore the frame pointer if necessary. The usual code would be:
4140
4141 move.l sp,fp
4142 read.l fp,(sp)
4143
4144 but for the MCM this constitutes a stall/hazard so it is changed to:
4145
4146 move.l sp,fp
4147 read.l fp,(fp)
4148
4149 if the stack pointer has actually been restored. */
4150 if (restore_fp)
4151 {
4152 rtx src;
4153
4154 if (TARGET_MCM && !crtl->sp_is_unchanging)
4155 src = gen_frame_mem (SImode, hard_frame_pointer_rtx);
4156 else
4157 src = gen_frame_mem (SImode, stack_pointer_rtx);
4158
4159 rtx insn = emit_frame_insn (gen_movsi (hard_frame_pointer_rtx, src));
4160 add_reg_note (insn, REG_CFA_ADJUST_CFA,
4161 gen_rtx_SET (stack_pointer_rtx,
4162 hard_frame_pointer_rtx));
4163 visium_add_cfa_restore_note (hard_frame_pointer_rtx);
4164 }
4165
4166 /* Restore the link register if necessary. */
4167 if (restore_lr)
4168 {
4169 rtx mem = gen_frame_mem (SImode,
4170 plus_constant (Pmode,
4171 stack_pointer_rtx,
4172 restore_fp * UNITS_PER_WORD));
4173 rtx reg = gen_rtx_REG (SImode, LINK_REGNUM);
4174 emit_insn (gen_movsi (reg, mem));
4175 visium_add_cfa_restore_note (reg);
4176 }
4177
4178 /* If we have two blocks of registers, deal with the second one first. */
4179 if (reg_size2)
4180 {
4181 reg_size = reg_size2;
4182 last_reg = max_reg1 + 1;
4183 fsize = local_frame_offset + var_size + reg_size2;
4184 }
4185 else
4186 {
4187 reg_size = reg_size1;
4188 last_reg = 0;
4189 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
4190 }
4191
4192 /* If the variable allocation could be combined with register stacking,
4193 restore the (remaining) registers and fully deallocate now. */
4194 if (reg_size && combine)
4195 visium_restore_regs (fsize, local_frame_offset + var_size,
4196 FIRST_PSEUDO_REGISTER - 1, last_reg);
4197
4198 /* Otherwise deallocate the variables first. */
4199 else if (fsize)
4200 {
4201 const int pop_size = reg_size ? local_frame_offset + var_size : fsize;
4202 rtx insn;
4203
4204 if (pop_size > 65535)
4205 {
4206 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4207 emit_move_insn (tmp, GEN_INT (pop_size));
4208 insn = emit_frame_insn (gen_stack_pop (tmp));
4209 }
4210 else
4211 insn = emit_frame_insn (gen_stack_pop (GEN_INT (pop_size)));
4212 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
4213 gen_rtx_SET (stack_pointer_rtx,
4214 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4215 GEN_INT (pop_size))));
4216 visium_add_queued_cfa_restore_notes (insn);
4217 }
4218
4219 /* If the variable allocation couldn't be combined with register stacking,
4220 restore the (remaining) registers now and partially deallocate. */
4221 if (reg_size && !combine)
4222 visium_restore_regs (fsize - local_frame_offset - var_size, 0,
4223 FIRST_PSEUDO_REGISTER - 1, last_reg);
4224
4225 /* If the first block of registers has yet to be restored, do it now. */
4226 if (reg_size2)
4227 visium_restore_regs (reg_size1 + save_area_size, 0, max_reg1, 0);
4228
4229 /* If this is an exception return, make the necessary stack adjustment. */
4230 if (crtl->calls_eh_return)
4231 emit_insn (gen_stack_pop (EH_RETURN_STACKADJ_RTX));
4232 }
4233
4234 /* Return true if it is appropriate to emit `return' instructions in the
4235 body of a function. */
4236
4237 bool
4238 visium_can_use_return_insn_p (void)
4239 {
4240 return reload_completed
4241 && visium_frame_size == 0
4242 && !visium_interrupt_function_p ();
4243 }
4244
4245 /* Return the register class required for an intermediate register used to
4246 copy a register of RCLASS from/to X. If no such intermediate register is
4247 required, return NO_REGS. If more than one such intermediate register is
4248 required, describe the one that is closest in the copy chain to the reload
4249 register. */
4250
4251 static reg_class_t
4252 visium_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
4253 reg_class_t rclass,
4254 machine_mode mode ATTRIBUTE_UNUSED,
4255 secondary_reload_info *sri ATTRIBUTE_UNUSED)
4256 {
4257 int regno = true_regnum (x);
4258
4259 /* For MDB, MDC and FP_REGS, a general register is needed for a move to
4260 or from memory. */
4261 if (regno == -1 && (rclass == MDB || rclass == MDC || rclass == FP_REGS))
4262 return GENERAL_REGS;
4263
4264 /* Moves between MDB, MDC and FP_REGS also require a general register. */
4265 else if (((regno == R_MDB || regno == R_MDC) && rclass == FP_REGS)
4266 || (FP_REGISTER_P (regno) && (rclass == MDB || rclass == MDC)))
4267 return GENERAL_REGS;
4268
4269 /* Finally an (unlikely ?) move between MDB and MDC needs a general reg. */
4270 else if ((regno == R_MDB && rclass == MDC)
4271 || (rclass == MDB && regno == R_MDC))
4272 return GENERAL_REGS;
4273
4274 return NO_REGS;
4275 }
4276
4277 /* Return true if pseudos that have been assigned to registers of RCLASS
4278 would likely be spilled because registers of RCLASS are needed for
4279 spill registers. */
4280
4281 static bool
4282 visium_class_likely_spilled_p (reg_class_t rclass ATTRIBUTE_UNUSED)
4283 {
4284 /* Return false for classes R1, R2 and R3, which are intended to be used
4285 only in the source code in conjunction with block move instructions. */
4286 return false;
4287 }
4288
4289 /* Return the register number if OP is a REG or a SUBREG of a REG, and
4290 INVALID_REGNUM in all the other cases. */
4291
4292 unsigned int
4293 reg_or_subreg_regno (rtx op)
4294 {
4295 unsigned int regno;
4296
4297 if (GET_CODE (op) == REG)
4298 regno = REGNO (op);
4299 else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
4300 {
4301 if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
4302 regno = subreg_regno (op);
4303 else
4304 regno = REGNO (SUBREG_REG (op));
4305 }
4306 else
4307 regno = INVALID_REGNUM;
4308
4309 return regno;
4310 }
4311
4312 /* Implement TARGET_CAN_CHANGE_MODE_CLASS.
4313
4314 It's not obvious from the documentation of the hook that MDB cannot
4315 change mode. However difficulties arise from expressions of the form
4316
4317 (subreg:SI (reg:DI R_MDB) 0)
4318
4319 There is no way to convert that reference to a single machine
4320 register and, without the following definition, reload will quietly
4321 convert it to
4322
4323 (reg:SI R_MDB). */
4324
4325 static bool
4326 visium_can_change_mode_class (machine_mode from, machine_mode to,
4327 reg_class_t rclass)
4328 {
4329 return (rclass != MDB || GET_MODE_SIZE (from) == GET_MODE_SIZE (to));
4330 }
4331
4332 #include "gt-visium.h"