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