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