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