]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/visium/visium.c
Move MEMMODEL_* from coretypes.h to memmodel.h
[thirdparty/gcc.git] / gcc / config / visium / visium.c
CommitLineData
0969ec7d 1/* Output routines for Visium.
818ab71a 2 Copyright (C) 2002-2016 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
157static bool visium_pass_by_reference (cumulative_args_t, enum machine_mode,
158 const_tree, bool);
159
160static rtx visium_function_arg (cumulative_args_t, enum machine_mode,
161 const_tree, bool);
162
163static void visium_function_arg_advance (cumulative_args_t, enum machine_mode,
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
171static rtx visium_libcall_value (enum machine_mode, const_rtx);
172
173static void visium_setup_incoming_varargs (cumulative_args_t,
174 enum machine_mode,
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
EB
190
191static bool visium_legitimate_constant_p (enum machine_mode, rtx);
192
193static bool visium_legitimate_address_p (enum machine_mode, rtx, bool);
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
201static rtx visium_legitimize_address (rtx, rtx, enum machine_mode);
202
203static reg_class_t visium_secondary_reload (bool, rtx, reg_class_t,
204 enum machine_mode,
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
EB
216
217static int visium_register_move_cost (enum machine_mode, reg_class_t,
218 reg_class_t);
219
220static int visium_memory_move_cost (enum machine_mode, reg_class_t, bool);
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
789visium_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
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
852prepare_move_operands (rtx *operands, enum machine_mode mode)
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
862ok_for_simple_move_operands (rtx *operands, enum machine_mode mode)
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
881ok_for_simple_move_strict_operands (rtx *operands, enum machine_mode mode)
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
899ok_for_simple_arith_logic_operands (rtx *, enum machine_mode)
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
925/* Wrapper around single_set which returns the first SET of a pair if the
926 second SET is to the flags register. */
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
935 && GET_CODE (XVECEXP (pat, 0, 1)) == SET
936 && REG_P (SET_DEST (XVECEXP (pat, 0, 1)))
937 && REGNO (SET_DEST (XVECEXP (pat, 0, 1))) == FLAGS_REGNUM)
938 return XVECEXP (pat, 0, 0);
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,
1247 enum machine_mode mode ATTRIBUTE_UNUSED,
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
1268visium_function_arg (cumulative_args_t pcum_v, enum machine_mode mode,
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,
1306 enum machine_mode mode,
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
1358visium_function_value_1 (enum machine_mode mode)
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
1388visium_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
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,
1398 enum machine_mode mode,
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
1714rtx_ok_for_offset_p (enum machine_mode mode, rtx op)
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
1762visium_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
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,
1835 enum machine_mode mode)
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
1869visium_legitimize_reload_address (rtx x, enum machine_mode mode, int opnum,
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
1918visium_register_move_cost (enum machine_mode mode, reg_class_t from,
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
1937visium_memory_move_cost (enum machine_mode mode,
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
a8345bfd 2045visium_split_double_move (rtx *operands, enum 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
2155visium_expand_copysign (rtx *operands, enum machine_mode mode)
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
2209visium_expand_int_cstore (rtx *operands, enum machine_mode mode)
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,
2268 enum machine_mode mode ATTRIBUTE_UNUSED)
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{
2317 enum machine_mode cc_mode = visium_select_cc_mode (code, op2, op3);
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
2795enum machine_mode
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
0969ec7d
EB
2836 if (op1 != const0_rtx)
2837 return CCmode;
2838
2839 switch (GET_CODE (op0))
2840 {
2841 case PLUS:
2842 case MINUS:
2843 case NEG:
2844 case ASHIFT:
2845 case LTU:
2846 case LT:
8d946ecc
EB
2847 /* The C and V flags may be set differently from a COMPARE with zero.
2848 The consequence is that a comparison operator testing C or V must
2849 be turned into another operator not testing C or V and yielding
2850 the same result for a comparison with zero. That's possible for
2851 GE/LT which become NC/NS respectively, but not for GT/LE for which
2852 the altered operator doesn't exist on the Visium. */
2853 return CCNZmode;
0969ec7d
EB
2854
2855 case ZERO_EXTRACT:
2856 /* This is a btst, the result is in C instead of Z. */
8d946ecc 2857 return CCCmode;
0969ec7d
EB
2858
2859 case CONST_INT:
2860 /* This is a degenerate case, typically an uninitialized variable. */
2861 gcc_assert (op0 == constm1_rtx);
95842021
EB
2862
2863 /* ... fall through ... */
2864
0969ec7d
EB
2865 case REG:
2866 case AND:
2867 case IOR:
2868 case XOR:
2869 case NOT:
2870 case ASHIFTRT:
2871 case LSHIFTRT:
2872 case TRUNCATE:
2873 case SIGN_EXTEND:
2874 /* Pretend that the flags are set as for a COMPARE with zero.
2875 That's mostly true, except for the 2 right shift insns that
2876 will set the C flag. But the C flag is relevant only for
2877 the unsigned comparison operators and they are eliminated
2878 when applied to a comparison with zero. */
2879 return CCmode;
2880
2881 default:
2882 gcc_unreachable ();
2883 }
2884}
2885
2886/* Split a compare-and-branch with CODE, operands OP0 and OP1, and LABEL. */
2887
2888void
2889visium_split_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx label)
2890{
2891 enum machine_mode cc_mode = visium_select_cc_mode (code, op0, op1);
2892 rtx flags = gen_rtx_REG (cc_mode, FLAGS_REGNUM);
2893
2894 rtx x = gen_rtx_COMPARE (cc_mode, op0, op1);
f7df4a84 2895 x = gen_rtx_SET (flags, x);
0969ec7d
EB
2896 emit_insn (x);
2897
2898 x = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
2899 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, gen_rtx_LABEL_REF (Pmode, label),
2900 pc_rtx);
f7df4a84 2901 x = gen_rtx_SET (pc_rtx, x);
0969ec7d
EB
2902 emit_jump_insn (x);
2903
2904 visium_flags_exposed = true;
2905}
2906
2907/* Branch instructions on the Visium.
2908
2909 Setting aside the interrupt-handling specific instructions, the ISA has
2910 two branch instructions: BRR and BRA. The former is used to implement
2911 short branches (+/- 2^17) within functions and its target is encoded in
2912 the instruction. The latter is used to implement all the other types
2913 of control flow changes and its target might not be statically known
2914 or even easily predictable at run time. Here's a complete summary of
2915 the patterns that generate a BRA instruction:
2916
2917 1. Indirect jump
2918 2. Table jump
2919 3. Call
2920 4. Sibling call
2921 5. Return
2922 6. Long branch
2923 7. Trampoline
2924
2925 Among these patterns, only the return (5) and the long branch (6) can be
2926 conditional; all the other patterns are always unconditional.
2927
2928 The following algorithm can be used to identify the pattern for which
2929 the BRA instruction was generated and work out its target:
2930
2931 A. If the source is r21 and the destination is r0, this is a return (5)
2932 and the target is the caller (i.e. the value of r21 on function's
2933 entry).
2934
2935 B. If the source is rN, N != 21 and the destination is r0, this is either
2936 an indirect jump or a table jump (1, 2) and the target is not easily
2937 predictable.
2938
2939 C. If the source is rN, N != 21 and the destination is r21, this is a call
2940 (3) and the target is given by the preceding MOVIL/MOVIU pair for rN,
2941 unless this is an indirect call in which case the target is not easily
2942 predictable.
2943
2944 D. If the source is rN, N != 21 and the destination is also rN, this is
2945 either a sibling call or a trampoline (4, 7) and the target is given
2946 by the preceding MOVIL/MOVIU pair for rN.
2947
2948 E. If the source is r21 and the destination is also r21, this is a long
2949 branch (6) and the target is given by the preceding MOVIL/MOVIU pair
2950 for r21.
2951
2952 The other combinations are not used. This implementation has been devised
2953 to accommodate the branch predictor of the GR6 but is used unconditionally
2954 by the compiler, i.e. including for earlier processors. */
2955
2956/* Output a conditional/unconditional branch to LABEL. COND is the string
2957 condition. INSN is the instruction. */
2958
2959static const char *
2960output_branch (rtx label, const char *cond, rtx_insn *insn)
2961{
2962 char str[64];
2963 rtx operands[2];
2964
2965 gcc_assert (cond);
2966 operands[0] = label;
2967
2968 /* If the length of the instruction is greater than 8, then this is a
2969 long branch and we need to work harder to emit it properly. */
2970 if (get_attr_length (insn) > 8)
2971 {
2972 bool spilled;
2973
2974 /* If the link register has been saved, then we use it. */
2975 if (current_function_saves_lr ())
2976 {
2977 operands[1] = regno_reg_rtx [LINK_REGNUM];
2978 spilled = false;
2979 }
2980
2981 /* Or else, if the long-branch register isn't live, we use it. */
2982 else if (!df_regs_ever_live_p (long_branch_regnum))
2983 {
2984 operands[1] = regno_reg_rtx [long_branch_regnum];
2985 spilled = false;
2986 }
2987
2988 /* Otherwise, we will use the long-branch register but we need to
2989 spill it to the stack and reload it at the end. We should have
2990 reserved the LR slot for this purpose. */
2991 else
2992 {
2993 operands[1] = regno_reg_rtx [long_branch_regnum];
2994 spilled = true;
2995 gcc_assert (current_function_has_lr_slot ());
2996 }
2997
2998 /* First emit the spill to the stack:
2999
3000 insn_in_delay_slot
3001 write.l [1](sp),reg */
3002 if (spilled)
3003 {
3004 if (final_sequence)
3005 {
3006 rtx_insn *delay = NEXT_INSN (insn);
3007 int seen;
3008 gcc_assert (delay);
3009
3010 final_scan_insn (delay, asm_out_file, optimize, 0, &seen);
3011 PATTERN (delay) = gen_blockage ();
3012 INSN_CODE (delay) = -1;
3013 }
3014
3015 if (current_function_saves_fp ())
3016 output_asm_insn ("write.l 1(sp),%1", operands);
3017 else
3018 output_asm_insn ("write.l (sp),%1", operands);
3019 }
3020
3021 /* Then emit the core sequence:
3022
3023 moviu reg,%u label
3024 movil reg,%l label
3025 bra tr,reg,reg
3026
3027 We don't use r0 as the destination register of the branch because we
3028 want the Branch Pre-decode Logic of the GR6 to use the Address Load
3029 Array to predict the branch target. */
3030 output_asm_insn ("moviu %1,%%u %0", operands);
3031 output_asm_insn ("movil %1,%%l %0", operands);
3032 strcpy (str, "bra ");
3033 strcat (str, cond);
3034 strcat (str, ",%1,%1");
3035 if (!spilled)
3036 strcat (str, "%#");
3037 strcat (str, "\t\t;long branch");
3038 output_asm_insn (str, operands);
3039
3040 /* Finally emit the reload:
3041
3042 read.l reg,[1](sp) */
3043 if (spilled)
3044 {
3045 if (current_function_saves_fp ())
3046 output_asm_insn (" read.l %1,1(sp)", operands);
3047 else
3048 output_asm_insn (" read.l %1,(sp)", operands);
3049 }
3050 }
3051
3052 /* Or else, if the label is PC, then this is a return. */
3053 else if (label == pc_rtx)
3054 {
3055 strcpy (str, "bra ");
3056 strcat (str, cond);
3057 strcat (str, ",r21,r0%#\t\t;return");
3058 output_asm_insn (str, operands);
3059 }
3060
3061 /* Otherwise, this is a short branch. */
3062 else
3063 {
3064 strcpy (str, "brr ");
3065 strcat (str, cond);
3066 strcat (str, ",%0%#");
3067 output_asm_insn (str, operands);
3068 }
3069
3070 return "";
3071}
3072
3073/* Output an unconditional branch to LABEL. INSN is the instruction. */
3074
3075const char *
3076output_ubranch (rtx label, rtx_insn *insn)
3077{
3078 return output_branch (label, "tr", insn);
3079}
3080
3081/* Output a conditional branch to LABEL. CODE is the comparison code.
3082 CC_MODE is the mode of the CC register. REVERSED is non-zero if we
3083 should reverse the sense of the comparison. INSN is the instruction. */
3084
3085const char *
3086output_cbranch (rtx label, enum rtx_code code, enum machine_mode cc_mode,
3087 int reversed, rtx_insn *insn)
3088{
3089 const char *cond;
3090
3091 if (reversed)
3092 {
3093 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3094 code = reverse_condition_maybe_unordered (code);
3095 else
3096 code = reverse_condition (code);
3097 }
3098
3099 switch (code)
3100 {
3101 case NE:
8d946ecc 3102 if (cc_mode == CCCmode)
0969ec7d
EB
3103 cond = "cs";
3104 else
3105 cond = "ne";
3106 break;
3107
3108 case EQ:
8d946ecc 3109 if (cc_mode == CCCmode)
0969ec7d
EB
3110 cond = "cc";
3111 else
3112 cond = "eq";
3113 break;
3114
3115 case GE:
8d946ecc 3116 if (cc_mode == CCNZmode)
0969ec7d
EB
3117 cond = "nc";
3118 else
3119 cond = "ge";
3120 break;
3121
3122 case GT:
3123 cond = "gt";
3124 break;
3125
3126 case LE:
3127 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
3128 cond = "ls";
3129 else
3130 cond = "le";
3131 break;
3132
3133 case LT:
3134 if (cc_mode == CCFPmode || cc_mode == CCFPEmode)
8d946ecc
EB
3135 cond = "cs"; /* or "ns" */
3136 else if (cc_mode == CCNZmode)
0969ec7d
EB
3137 cond = "ns";
3138 else
3139 cond = "lt";
3140 break;
3141
3142 case GEU:
3143 cond = "cc";
3144 break;
3145
3146 case GTU:
3147 cond = "hi";
3148 break;
3149
3150 case LEU:
3151 cond = "ls";
3152 break;
3153
3154 case LTU:
3155 cond = "cs";
3156 break;
3157
3158 case UNORDERED:
3159 cond = "os";
3160 break;
3161
3162 case ORDERED:
3163 cond = "oc";
3164 break;
3165
3166 case UNGE:
8d946ecc 3167 cond = "cc"; /* or "nc" */
0969ec7d
EB
3168 break;
3169
3170 case UNGT:
3171 cond = "hi";
3172 break;
3173
3174 case UNLE:
3175 cond = "le";
3176 break;
3177
3178 case UNLT:
3179 cond = "lt";
3180 break;
3181
3182 /* These 2 comparison codes are not supported. */
3183 case UNEQ:
3184 case LTGT:
3185 default:
3186 gcc_unreachable ();
3187 }
3188
3189 return output_branch (label, cond, insn);
3190}
3191
01e83ff2 3192/* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
0969ec7d 3193
01e83ff2
EB
3194static bool
3195visium_print_operand_punct_valid_p (unsigned char code)
3196{
3197 return code == '#';
3198}
3199
3200/* Implement TARGET_PRINT_OPERAND. Output to stdio stream FILE the assembler
3201 syntax for an instruction operand OP subject to the modifier LETTER. */
3202
3203static void
3204visium_print_operand (FILE *file, rtx op, int letter)
0969ec7d
EB
3205{
3206 switch (letter)
3207 {
3208 case '#':
3209 /* Output an insn in a delay slot. */
3210 if (final_sequence)
3211 visium_indent_opcode = 1;
3212 else
3213 fputs ("\n\t nop", file);
3214 return;
3215
3216 case 'b':
3217 /* Print LS 8 bits of operand. */
3218 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xff);
3219 return;
3220
3221 case 'w':
3222 /* Print LS 16 bits of operand. */
3223 fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, UINTVAL (op) & 0xffff);
3224 return;
3225
3226 case 'u':
3227 /* Print MS 16 bits of operand. */
3228 fprintf (file,
3229 HOST_WIDE_INT_PRINT_UNSIGNED, (UINTVAL (op) >> 16) & 0xffff);
3230 return;
3231
3232 case 'r':
3233 /* It's either a register or zero. */
3234 if (GET_CODE (op) == REG)
3235 fputs (reg_names[REGNO (op)], file);
3236 else
3237 fputs (reg_names[0], file);
3238 return;
3239
3240 case 'f':
3241 /* It's either a FP register or zero. */
3242 if (GET_CODE (op) == REG)
3243 fputs (reg_names[REGNO (op)], file);
3244 else
3245 fputs (reg_names[FP_FIRST_REGNUM], file);
3246 return;
3247 }
3248
3249 switch (GET_CODE (op))
3250 {
3251 case REG:
3252 if (letter == 'd')
3253 fputs (reg_names[REGNO (op) + 1], file);
3254 else
3255 fputs (reg_names[REGNO (op)], file);
3256 break;
3257
3258 case SYMBOL_REF:
3259 case LABEL_REF:
3260 case CONST:
3261 output_addr_const (file, op);
3262 break;
3263
3264 case MEM:
01e83ff2 3265 visium_print_operand_address (file, GET_MODE (op), XEXP (op, 0));
0969ec7d
EB
3266 break;
3267
3268 case CONST_INT:
3269 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (op));
3270 break;
3271
3272 case CODE_LABEL:
3273 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (op));
3274 break;
3275
3276 case HIGH:
01e83ff2 3277 visium_print_operand (file, XEXP (op, 1), letter);
0969ec7d
EB
3278 break;
3279
3280 default:
3281 fatal_insn ("illegal operand ", op);
3282 }
3283}
3284
01e83ff2
EB
3285/* Implement TARGET_PRINT_OPERAND_ADDRESS. Output to stdio stream FILE the
3286 assembler syntax for an instruction operand that is a memory reference
3287 whose address is ADDR. */
0969ec7d
EB
3288
3289static void
01e83ff2 3290visium_print_operand_address (FILE *file, enum machine_mode mode, rtx addr)
0969ec7d
EB
3291{
3292 switch (GET_CODE (addr))
3293 {
3294 case REG:
3295 case SUBREG:
3296 fprintf (file, "(%s)", reg_names[true_regnum (addr)]);
3297 break;
3298
3299 case PLUS:
3300 {
3301 rtx x = XEXP (addr, 0), y = XEXP (addr, 1);
3302
3303 switch (GET_CODE (x))
3304 {
3305 case REG:
3306 case SUBREG:
3307 if (CONST_INT_P (y))
3308 {
3309 unsigned int regno = true_regnum (x);
3310 HOST_WIDE_INT val = INTVAL (y);
3311 switch (mode)
3312 {
3313 case SImode:
3314 case DImode:
3315 case SFmode:
3316 case DFmode:
3317 val >>= 2;
3318 break;
3319
3320 case HImode:
3321 val >>= 1;
3322 break;
3323
3324 case QImode:
3325 default:
3326 break;
3327 }
3328 fprintf (file, HOST_WIDE_INT_PRINT_DEC"(%s)", val,
3329 reg_names[regno]);
3330 }
3331 else
3332 fatal_insn ("illegal operand address (1)", addr);
3333 break;
3334
3335 default:
3336 if (CONSTANT_P (x) && CONSTANT_P (y))
3337 output_addr_const (file, addr);
3338 else
3339 fatal_insn ("illegal operand address (2)", addr);
3340 break;
3341 }
3342 }
3343 break;
3344
3345 case LABEL_REF:
3346 case SYMBOL_REF:
3347 case CONST_INT:
3348 case CONST:
3349 output_addr_const (file, addr);
3350 break;
3351
3352 case NOTE:
3353 if (NOTE_KIND (addr) != NOTE_INSN_DELETED_LABEL)
3354 fatal_insn ("illegal operand address (3)", addr);
3355 break;
3356
3357 case CODE_LABEL:
3358 asm_fprintf (file, "%LL%d", CODE_LABEL_NUMBER (addr));
3359 break;
3360
3361 default:
3362 fatal_insn ("illegal operand address (4)", addr);
3363 break;
3364 }
3365}
3366
0969ec7d
EB
3367/* The Visium stack frames look like:
3368
3369 Before call After call
3370 +-----------------------+ +-----------------------+
3371 | | | |
3372 high | previous | | previous |
3373 mem | frame | | frame |
3374 | | | |
3375 +-----------------------+ +-----------------------+
3376 | | | |
3377 | arguments on stack | | arguments on stack |
3378 | | | |
3379 SP+0->+-----------------------+ +-----------------------+
3380 | reg parm save area, |
3381 | only created for |
3382 | variable argument |
3383 | functions |
3384 +-----------------------+
3385 | |
3386 | register save area |
3387 | |
3388 +-----------------------+
3389 | |
3390 | local variables |
3391 | |
3392 FP+8->+-----------------------+
3393 | return address |
3394 FP+4->+-----------------------+
3395 | previous FP |
3396 FP+0->+-----------------------+
3397 | |
3398 | alloca allocations |
3399 | |
3400 +-----------------------+
3401 | |
3402 low | arguments on stack |
3403 mem | |
3404 SP+0->+-----------------------+
3405
3406 Notes:
3407 1) The "reg parm save area" does not exist for non variable argument fns.
3408 2) The FP register is not saved if `frame_pointer_needed' is zero and it
3409 is not altered in the current function.
3410 3) The return address is not saved if there is no frame pointer and the
3411 current function is leaf.
3412 4) If the return address is not saved and the static chain register is
3413 live in the function, we allocate the return address slot to be able
3414 to spill the register for a long branch. */
3415
3416/* Define the register classes for local purposes. */
3417enum reg_type { general, mdb, mdc, floating, last_type};
3418
3419#define GET_REG_TYPE(regno) \
3420 (GP_REGISTER_P (regno) ? general : \
3421 (regno) == MDB_REGNUM ? mdb : \
3422 (regno) == MDC_REGNUM ? mdc : \
3423 floating)
3424
3425/* First regno of each register type. */
3426const int first_regno[last_type] = {0, MDB_REGNUM, MDC_REGNUM, FP_FIRST_REGNUM};
3427
3428/* Size in bytes of each register type. */
3429const int reg_type_size[last_type] = {4, 8, 4, 4};
3430
3431/* Structure to be filled in by visium_compute_frame_size. */
3432struct visium_frame_info
3433{
3434 unsigned int save_area_size; /* # bytes in the reg parm save area. */
3435 unsigned int reg_size1; /* # bytes to store first block of regs. */
3436 unsigned int reg_size2; /* # bytes to store second block of regs. */
3437 unsigned int max_reg1; /* max. regno in first block */
3438 unsigned int var_size; /* # bytes that variables take up. */
3439 unsigned int save_fp; /* Nonzero if fp must be saved. */
3440 unsigned int save_lr; /* Nonzero if lr must be saved. */
3441 unsigned int lr_slot; /* Nonzero if the lr slot is needed. */
3442 unsigned int combine; /* Nonzero if we can combine the allocation of
3443 variables and regs. */
3444 unsigned int interrupt; /* Nonzero if the function is an interrupt
3445 handler. */
3446 unsigned int mask[last_type]; /* Masks of saved regs: gp, mdb, mdc, fp */
3447};
3448
3449/* Current frame information calculated by visium_compute_frame_size. */
3450static struct visium_frame_info current_frame_info;
3451
3452/* Accessor for current_frame_info.save_fp. */
3453
3454static inline bool
3455current_function_saves_fp (void)
3456{
3457 return current_frame_info.save_fp != 0;
3458}
3459
3460/* Accessor for current_frame_info.save_lr. */
3461
3462static inline bool
3463current_function_saves_lr (void)
3464{
3465 return current_frame_info.save_lr != 0;
3466}
3467
3468/* Accessor for current_frame_info.lr_slot. */
3469
3470static inline bool
3471current_function_has_lr_slot (void)
3472{
3473 return current_frame_info.lr_slot != 0;
3474}
3475
3476/* Return non-zero if register REGNO needs to be saved in the frame. */
3477
3478static int
3479visium_save_reg_p (int interrupt, int regno)
3480{
3481 switch (regno)
3482 {
3483 case HARD_FRAME_POINTER_REGNUM:
3484 /* This register is call-saved but handled specially. */
3485 return 0;
3486
3487 case MDC_REGNUM:
3488 /* This register is fixed but can be modified. */
3489 break;
3490
3491 case 29:
3492 case 30:
3493 /* These registers are fixed and hold the interrupt context. */
3494 return (interrupt != 0);
3495
3496 default:
3497 /* The other fixed registers are either immutable or special. */
3498 if (fixed_regs[regno])
3499 return 0;
3500 break;
3501 }
3502
3503 if (interrupt)
3504 {
3505 if (crtl->is_leaf)
3506 {
3507 if (df_regs_ever_live_p (regno))
3508 return 1;
3509 }
3510 else if (call_used_regs[regno])
3511 return 1;
3512
3513 /* To save mdb requires two temporary registers. To save mdc or
3514 any of the floating registers requires one temporary
3515 register. If this is an interrupt routine, the temporary
3516 registers need to be saved as well. These temporary registers
3517 are call used, so we only need deal with the case of leaf
3518 functions here. */
3519 if (regno == PROLOGUE_TMP_REGNUM)
3520 {
3521 if (df_regs_ever_live_p (MDB_REGNUM)
3522 || df_regs_ever_live_p (MDC_REGNUM))
3523 return 1;
3524
3525 for (int i = FP_FIRST_REGNUM; i <= FP_LAST_REGNUM; i++)
3526 if (df_regs_ever_live_p (i))
3527 return 1;
3528 }
3529
3530 else if (regno == PROLOGUE_TMP_REGNUM + 1)
3531 {
3532 if (df_regs_ever_live_p (MDB_REGNUM))
3533 return 1;
3534 }
3535 }
3536
3537 return df_regs_ever_live_p (regno) && !call_used_regs[regno];
3538}
3539
3540/* Compute the frame size required by the function. This function is called
3541 during the reload pass and also by visium_expand_prologue. */
3542
3543static int
3544visium_compute_frame_size (int size)
3545{
3546 const int save_area_size = visium_reg_parm_save_area_size;
3547 const int var_size = VISIUM_STACK_ALIGN (size);
3548 const int save_fp
3549 = frame_pointer_needed || df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM);
3550 const int save_lr = frame_pointer_needed || !crtl->is_leaf;
3551 const int lr_slot = !save_lr && df_regs_ever_live_p (long_branch_regnum);
3552 const int local_frame_offset
3553 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3554 const int interrupt = visium_interrupt_function_p ();
3555 unsigned int mask[last_type];
3556 int reg_size1 = 0;
3557 int max_reg1 = 0;
3558 int reg_size2 = 0;
3559 int reg_size;
3560 int combine;
3561 int frame_size;
3562 int regno;
3563
3564 memset (mask, 0, last_type * sizeof (unsigned int));
3565
3566 /* The registers may need stacking in 2 blocks since only 32 32-bit words
3567 can be indexed from a given base address. */
3568 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3569 {
3570 if (visium_save_reg_p (interrupt, regno))
3571 {
3572 enum reg_type reg_type = GET_REG_TYPE (regno);
3573 int mask_bit = 1 << (regno - first_regno[reg_type]);
3574 int nbytes = reg_type_size[reg_type];
3575
3576 if (reg_size1 + nbytes > 32 * UNITS_PER_WORD)
3577 break;
3578
3579 reg_size1 += nbytes;
3580 max_reg1 = regno;
3581 mask[reg_type] |= mask_bit;
3582 }
3583 }
3584
3585 for (regno = max_reg1 + 1; regno < FIRST_PSEUDO_REGISTER; regno++)
3586 {
3587 if (visium_save_reg_p (interrupt, regno))
3588 {
3589 enum reg_type reg_type = GET_REG_TYPE (regno);
3590 int mask_bit = 1 << (regno - first_regno[reg_type]);
3591 int nbytes = reg_type_size[reg_type];
3592
3593 reg_size2 += nbytes;
3594 mask[reg_type] |= mask_bit;
3595 }
3596 }
3597
3598 reg_size = reg_size2 ? reg_size2 : reg_size1;
3599 combine = (local_frame_offset + var_size + reg_size) <= 32 * UNITS_PER_WORD;
3600 frame_size
3601 = local_frame_offset + var_size + reg_size2 + reg_size1 + save_area_size;
3602
3603 current_frame_info.save_area_size = save_area_size;
3604 current_frame_info.reg_size1 = reg_size1;
3605 current_frame_info.max_reg1 = max_reg1;
3606 current_frame_info.reg_size2 = reg_size2;
3607 current_frame_info.var_size = var_size;
3608 current_frame_info.save_fp = save_fp;
3609 current_frame_info.save_lr = save_lr;
3610 current_frame_info.lr_slot = lr_slot;
3611 current_frame_info.combine = combine;
3612 current_frame_info.interrupt = interrupt;
3613
3614 memcpy (current_frame_info.mask, mask, last_type * sizeof (unsigned int));
3615
3616 return frame_size;
3617}
3618
3619/* Helper function for INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET). Define
3620 the offset between two registers, one to be eliminated, and the other its
3621 replacement, at the start of a routine. */
3622
3623int
3624visium_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
3625{
0969ec7d
EB
3626 const int save_fp = current_frame_info.save_fp;
3627 const int save_lr = current_frame_info.save_lr;
3628 const int lr_slot = current_frame_info.lr_slot;
0969ec7d
EB
3629 int offset;
3630
3631 if (from == FRAME_POINTER_REGNUM)
d5cf3d8d 3632 offset = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
0969ec7d 3633 else if (from == ARG_POINTER_REGNUM)
d5cf3d8d 3634 offset = visium_compute_frame_size (get_frame_size ());
0969ec7d
EB
3635 else
3636 gcc_unreachable ();
3637
3638 return offset;
3639}
3640
3641/* For an interrupt handler, we may be saving call-clobbered registers.
3642 Say the epilogue uses these in addition to the link register. */
3643
3644int
3645visium_epilogue_uses (int regno)
3646{
3647 if (regno == LINK_REGNUM)
3648 return 1;
3649
3650 if (reload_completed)
3651 {
3652 enum reg_type reg_type = GET_REG_TYPE (regno);
3653 int mask_bit = 1 << (regno - first_regno[reg_type]);
3654
3655 return (current_frame_info.mask[reg_type] & mask_bit) != 0;
3656 }
3657
3658 return 0;
3659}
3660
3661/* Wrapper around emit_insn that sets RTX_FRAME_RELATED_P on the insn. */
3662
3663static rtx
3664emit_frame_insn (rtx x)
3665{
3666 x = emit_insn (x);
3667 RTX_FRAME_RELATED_P (x) = 1;
3668 return x;
3669}
3670
3671/* Allocate ALLOC bytes on the stack and save the registers LOW_REGNO to
3672 HIGH_REGNO at OFFSET from the stack pointer. */
3673
3674static void
3675visium_save_regs (int alloc, int offset, int low_regno, int high_regno)
3676{
3677 /* If this is an interrupt handler function, then mark the register
3678 stores as volatile. This will prevent the instruction scheduler
3679 from scrambling the order of register saves. */
3680 const int volatile_p = current_frame_info.interrupt;
3681 int regno;
3682
3683 /* Allocate the stack space. */
3684 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx, stack_pointer_rtx,
3685 GEN_INT (-alloc)));
3686
3687 for (regno = low_regno; regno <= high_regno; regno++)
3688 {
3689 enum reg_type reg_type = GET_REG_TYPE (regno);
3690 int mask_bit = 1 << (regno - first_regno[reg_type]);
3691 rtx insn;
3692
3693 if (current_frame_info.mask[reg_type] & mask_bit)
3694 {
3695 offset -= reg_type_size[reg_type];
3696 switch (reg_type)
3697 {
3698 case general:
3699 {
3700 rtx mem
3701 = gen_frame_mem (SImode,
3702 plus_constant (Pmode,
3703 stack_pointer_rtx, offset));
3704 MEM_VOLATILE_P (mem) = volatile_p;
3705 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, regno)));
3706 }
3707 break;
3708
3709 case mdb:
3710 {
3711 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3712 rtx mem
3713 = gen_frame_mem (DImode,
3714 plus_constant (Pmode,
3715 stack_pointer_rtx, offset));
3716 rtx reg = gen_rtx_REG (DImode, regno);
3717 MEM_VOLATILE_P (mem) = volatile_p;
3718 emit_insn (gen_movdi (tmp, reg));
3719 /* Do not generate CFI if in interrupt handler. */
3720 if (volatile_p)
3721 emit_insn (gen_movdi (mem, tmp));
3722 else
3723 {
3724 insn = emit_frame_insn (gen_movdi (mem, tmp));
3725 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
f7df4a84 3726 gen_rtx_SET (mem, reg));
0969ec7d
EB
3727 }
3728 }
3729 break;
3730
3731 case mdc:
3732 {
3733 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3734 rtx mem
3735 = gen_frame_mem (SImode,
3736 plus_constant (Pmode,
3737 stack_pointer_rtx, offset));
3738 rtx reg = gen_rtx_REG (SImode, regno);
3739 MEM_VOLATILE_P (mem) = volatile_p;
3740 emit_insn (gen_movsi (tmp, reg));
3741 insn = emit_frame_insn (gen_movsi (mem, tmp));
3742 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
f7df4a84 3743 gen_rtx_SET (mem, reg));
0969ec7d
EB
3744 }
3745 break;
3746
3747 case floating:
3748 {
3749 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3750 rtx mem
3751 = gen_frame_mem (SFmode,
3752 plus_constant (Pmode,
3753 stack_pointer_rtx, offset));
3754 rtx reg = gen_rtx_REG (SFmode, regno);
3755 MEM_VOLATILE_P (mem) = volatile_p;
3756 emit_insn (gen_movsf (tmp, reg));
3757 insn = emit_frame_insn (gen_movsf (mem, tmp));
3758 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
f7df4a84 3759 gen_rtx_SET (mem, reg));
0969ec7d
EB
3760 }
3761 break;
3762
3763 default:
3764 break;
3765 }
3766 }
3767 }
3768}
3769
3770/* This function generates the code for function entry. */
3771
3772void
3773visium_expand_prologue (void)
3774{
3775 const int frame_size = visium_compute_frame_size (get_frame_size ());
3776 const int save_area_size = current_frame_info.save_area_size;
3777 const int reg_size1 = current_frame_info.reg_size1;
3778 const int max_reg1 = current_frame_info.max_reg1;
3779 const int reg_size2 = current_frame_info.reg_size2;
3780 const int var_size = current_frame_info.var_size;
3781 const int save_fp = current_frame_info.save_fp;
3782 const int save_lr = current_frame_info.save_lr;
3783 const int lr_slot = current_frame_info.lr_slot;
3784 const int local_frame_offset
3785 = (save_fp + save_lr + lr_slot) * UNITS_PER_WORD;
3786 const int combine = current_frame_info.combine;
3787 int reg_size;
3788 int first_reg;
3789 int fsize;
3790
3791 /* Save the frame size for future references. */
3792 visium_frame_size = frame_size;
3793
3794 if (flag_stack_usage_info)
3795 current_function_static_stack_size = frame_size;
3796
3797 /* If the registers have to be stacked in 2 blocks, stack the first one. */
3798 if (reg_size2)
3799 {
3800 visium_save_regs (reg_size1 + save_area_size, reg_size1, 0, max_reg1);
3801 reg_size = reg_size2;
3802 first_reg = max_reg1 + 1;
3803 fsize = local_frame_offset + var_size + reg_size2;
3804 }
3805 else
3806 {
3807 reg_size = reg_size1;
3808 first_reg = 0;
3809 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
3810 }
3811
3812 /* If we can't combine register stacking with variable allocation, partially
3813 allocate and stack the (remaining) registers now. */
3814 if (reg_size && !combine)
3815 visium_save_regs (fsize - local_frame_offset - var_size, reg_size,
3816 first_reg, FIRST_PSEUDO_REGISTER - 1);
3817
3818 /* If we can combine register stacking with variable allocation, fully
3819 allocate and stack the (remaining) registers now. */
3820 if (reg_size && combine)
3821 visium_save_regs (fsize, local_frame_offset + var_size + reg_size,
3822 first_reg, FIRST_PSEUDO_REGISTER - 1);
3823
3824 /* Otherwise space may still need to be allocated for the variables. */
3825 else if (fsize)
3826 {
3827 const int alloc_size = reg_size ? local_frame_offset + var_size : fsize;
3828
3829 if (alloc_size > 65535)
3830 {
3831 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM), insn;
3832 emit_insn (gen_movsi (tmp, GEN_INT (alloc_size)));
3833 insn = emit_frame_insn (gen_subsi3_flags (stack_pointer_rtx,
3834 stack_pointer_rtx,
3835 tmp));
3836 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
f7df4a84 3837 gen_rtx_SET (stack_pointer_rtx,
0969ec7d
EB
3838 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3839 GEN_INT (-alloc_size))));
3840 }
3841 else
3842 emit_frame_insn (gen_addsi3_flags (stack_pointer_rtx,
3843 stack_pointer_rtx,
3844 GEN_INT (-alloc_size)));
3845 }
3846
3847 if (save_fp)
3848 emit_frame_insn (gen_movsi (gen_frame_mem (SImode, stack_pointer_rtx),
3849 hard_frame_pointer_rtx));
3850
3851 if (frame_pointer_needed)
3852 emit_frame_insn (gen_stack_save ());
3853
3854 if (save_lr)
3855 {
3856 rtx base_rtx, mem;
3857
3858 /* Normally the frame pointer and link register get saved via
3859 write.l (sp),fp
3860 move.l fp,sp
3861 write.l 1(sp),r21
3862
3863 Indexing off sp rather than fp to store the link register
3864 avoids presenting the instruction scheduler with an initial
3865 pipeline hazard. If however the frame is needed for eg.
3866 __builtin_return_address which needs to retrieve the saved
3867 value of the link register from the stack at fp + 4 then
3868 indexing from sp can confuse the dataflow, causing the link
3869 register to be retrieved before it has been saved. */
3870 if (cfun->machine->frame_needed)
3871 base_rtx = hard_frame_pointer_rtx;
3872 else
3873 base_rtx = stack_pointer_rtx;
3874
3875 mem = gen_frame_mem (SImode,
3876 plus_constant (Pmode,
3877 base_rtx, save_fp * UNITS_PER_WORD));
3878 emit_frame_insn (gen_movsi (mem, gen_rtx_REG (SImode, LINK_REGNUM)));
3879 }
3880}
3881
3882static GTY(()) rtx cfa_restores;
3883
3884/* Queue a REG_CFA_RESTORE note until next stack manipulation insn. */
3885
3886static void
3887visium_add_cfa_restore_note (rtx reg)
3888{
3889 cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
3890}
3891
3892/* Add queued REG_CFA_RESTORE notes to INSN, if any. */
3893
3894static void
3895visium_add_queued_cfa_restore_notes (rtx insn)
3896{
3897 rtx last;
3898 if (!cfa_restores)
3899 return;
3900 for (last = cfa_restores; XEXP (last, 1); last = XEXP (last, 1))
3901 ;
3902 XEXP (last, 1) = REG_NOTES (insn);
3903 REG_NOTES (insn) = cfa_restores;
3904 cfa_restores = NULL_RTX;
3905}
3906
3907/* Restore the registers LOW_REGNO to HIGH_REGNO from the save area at OFFSET
3908 from the stack pointer and pop DEALLOC bytes off the stack. */
3909
3910static void
3911visium_restore_regs (int dealloc, int offset, int high_regno, int low_regno)
3912{
3913 /* If this is an interrupt handler function, then mark the register
3914 restores as volatile. This will prevent the instruction scheduler
3915 from scrambling the order of register restores. */
3916 const int volatile_p = current_frame_info.interrupt;
3917 int r30_offset = -1;
3918 int regno;
3919
3920 for (regno = high_regno; regno >= low_regno; --regno)
3921 {
3922 enum reg_type reg_type = GET_REG_TYPE (regno);
3923 int mask_bit = 1 << (regno - first_regno[reg_type]);
3924
3925 if (current_frame_info.mask[reg_type] & mask_bit)
3926 {
3927 switch (reg_type)
3928 {
3929 case general:
3930 /* Postpone restoring the interrupted context registers
3931 until last, since they need to be preceded by a dsi. */
3932 if (regno == 29)
3933 ;
3934 else if (regno == 30)
3935 r30_offset = offset;
3936 else
3937 {
3938 rtx mem
3939 = gen_frame_mem (SImode,
3940 plus_constant (Pmode,
3941 stack_pointer_rtx,
3942 offset));
3943 rtx reg = gen_rtx_REG (SImode, regno);
3944 MEM_VOLATILE_P (mem) = volatile_p;
3945 emit_insn (gen_movsi (reg, mem));
3946 visium_add_cfa_restore_note (reg);
3947 }
3948 break;
3949
3950 case mdb:
3951 {
3952 rtx tmp = gen_rtx_REG (DImode, PROLOGUE_TMP_REGNUM);
3953 rtx mem
3954 = gen_frame_mem (DImode,
3955 plus_constant (Pmode,
3956 stack_pointer_rtx, offset));
3957 rtx reg = gen_rtx_REG (DImode, regno);
3958 MEM_VOLATILE_P (mem) = volatile_p;
3959 emit_insn (gen_movdi (tmp, mem));
3960 emit_insn (gen_movdi (reg, tmp));
3961 /* Do not generate CFI if in interrupt handler. */
3962 if (!volatile_p)
3963 visium_add_cfa_restore_note (reg);
3964 }
3965 break;
3966
3967 case mdc:
3968 {
3969 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
3970 rtx mem
3971 = gen_frame_mem (SImode,
3972 plus_constant (Pmode,
3973 stack_pointer_rtx, offset));
3974 rtx reg = gen_rtx_REG (SImode, regno);
3975 MEM_VOLATILE_P (mem) = volatile_p;
3976 emit_insn (gen_movsi (tmp, mem));
3977 emit_insn (gen_movsi (reg, tmp));
3978 visium_add_cfa_restore_note (reg);
3979 }
3980 break;
3981
3982 case floating:
3983 {
3984 rtx tmp = gen_rtx_REG (SFmode, PROLOGUE_TMP_REGNUM);
3985 rtx mem
3986 = gen_frame_mem (SFmode,
3987 plus_constant (Pmode,
3988 stack_pointer_rtx, offset));
3989 rtx reg = gen_rtx_REG (SFmode, regno);
3990 MEM_VOLATILE_P (mem) = volatile_p;
3991 emit_insn (gen_movsf (tmp, mem));
3992 emit_insn (gen_movsf (reg, tmp));
3993 visium_add_cfa_restore_note (reg);
3994 }
3995 break;
3996
3997 default:
3998 break;
3999 }
4000
4001 offset += reg_type_size[reg_type];
4002 }
4003 }
4004
4005 /* If the interrupted context needs to be restored, precede the
4006 restores of r29 and r30 by a dsi. */
4007 if (r30_offset >= 0)
4008 {
4009 emit_insn (gen_dsi ());
4010 emit_move_insn (gen_rtx_REG (SImode, 30),
4011 gen_frame_mem (SImode,
4012 plus_constant (Pmode,
4013 stack_pointer_rtx,
4014 r30_offset)));
4015 emit_move_insn (gen_rtx_REG (SImode, 29),
4016 gen_frame_mem (SImode,
4017 plus_constant (Pmode,
4018 stack_pointer_rtx,
4019 r30_offset + 4)));
4020 }
4021
4022 /* Deallocate the stack space. */
4023 rtx insn = emit_frame_insn (gen_stack_pop (GEN_INT (dealloc)));
4024 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
f7df4a84 4025 gen_rtx_SET (stack_pointer_rtx,
0969ec7d
EB
4026 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4027 GEN_INT (dealloc))));
4028 visium_add_queued_cfa_restore_notes (insn);
4029}
4030
4031/* This function generates the code for function exit. */
4032
4033void
4034visium_expand_epilogue (void)
4035{
4036 const int save_area_size = current_frame_info.save_area_size;
4037 const int reg_size1 = current_frame_info.reg_size1;
4038 const int max_reg1 = current_frame_info.max_reg1;
4039 const int reg_size2 = current_frame_info.reg_size2;
4040 const int var_size = current_frame_info.var_size;
4041 const int restore_fp = current_frame_info.save_fp;
4042 const int restore_lr = current_frame_info.save_lr;
4043 const int lr_slot = current_frame_info.lr_slot;
4044 const int local_frame_offset
4045 = (restore_fp + restore_lr + lr_slot) * UNITS_PER_WORD;
4046 const int combine = current_frame_info.combine;
4047 int reg_size;
4048 int last_reg;
4049 int fsize;
4050
4051 /* Do not bother restoring the stack pointer if it hasn't been changed in
4052 the function since it was saved _after_ the allocation of the frame. */
4053 if (!crtl->sp_is_unchanging)
4054 emit_insn (gen_stack_restore ());
4055
4056 /* Restore the frame pointer if necessary. The usual code would be:
4057
4058 move.l sp,fp
4059 read.l fp,(sp)
4060
4061 but for the MCM this constitutes a stall/hazard so it is changed to:
4062
4063 move.l sp,fp
4064 read.l fp,(fp)
4065
4066 if the stack pointer has actually been restored. */
4067 if (restore_fp)
4068 {
4069 rtx src;
4070
4071 if (TARGET_MCM && !crtl->sp_is_unchanging)
4072 src = gen_frame_mem (SImode, hard_frame_pointer_rtx);
4073 else
4074 src = gen_frame_mem (SImode, stack_pointer_rtx);
4075
4076 rtx insn = emit_frame_insn (gen_movsi (hard_frame_pointer_rtx, src));
4077 add_reg_note (insn, REG_CFA_ADJUST_CFA,
f7df4a84 4078 gen_rtx_SET (stack_pointer_rtx,
0969ec7d
EB
4079 hard_frame_pointer_rtx));
4080 visium_add_cfa_restore_note (hard_frame_pointer_rtx);
4081 }
4082
4083 /* Restore the link register if necessary. */
4084 if (restore_lr)
4085 {
4086 rtx mem = gen_frame_mem (SImode,
4087 plus_constant (Pmode,
4088 stack_pointer_rtx,
4089 restore_fp * UNITS_PER_WORD));
4090 rtx reg = gen_rtx_REG (SImode, LINK_REGNUM);
4091 emit_insn (gen_movsi (reg, mem));
4092 visium_add_cfa_restore_note (reg);
4093 }
4094
4095 /* If we have two blocks of registers, deal with the second one first. */
4096 if (reg_size2)
4097 {
4098 reg_size = reg_size2;
4099 last_reg = max_reg1 + 1;
4100 fsize = local_frame_offset + var_size + reg_size2;
4101 }
4102 else
4103 {
4104 reg_size = reg_size1;
4105 last_reg = 0;
4106 fsize = local_frame_offset + var_size + reg_size1 + save_area_size;
4107 }
4108
4109 /* If the variable allocation could be combined with register stacking,
4110 restore the (remaining) registers and fully deallocate now. */
4111 if (reg_size && combine)
4112 visium_restore_regs (fsize, local_frame_offset + var_size,
4113 FIRST_PSEUDO_REGISTER - 1, last_reg);
4114
4115 /* Otherwise deallocate the variables first. */
4116 else if (fsize)
4117 {
4118 const int pop_size = reg_size ? local_frame_offset + var_size : fsize;
4119 rtx insn;
4120
4121 if (pop_size > 65535)
4122 {
4123 rtx tmp = gen_rtx_REG (SImode, PROLOGUE_TMP_REGNUM);
4124 emit_move_insn (tmp, GEN_INT (pop_size));
4125 insn = emit_frame_insn (gen_stack_pop (tmp));
4126 }
4127 else
4128 insn = emit_frame_insn (gen_stack_pop (GEN_INT (pop_size)));
4129 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
f7df4a84 4130 gen_rtx_SET (stack_pointer_rtx,
0969ec7d
EB
4131 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
4132 GEN_INT (pop_size))));
4133 visium_add_queued_cfa_restore_notes (insn);
4134 }
4135
4136 /* If the variable allocation couldn't be combined with register stacking,
4137 restore the (remaining) registers now and partially deallocate. */
4138 if (reg_size && !combine)
4139 visium_restore_regs (fsize - local_frame_offset - var_size, 0,
4140 FIRST_PSEUDO_REGISTER - 1, last_reg);
4141
4142 /* If the first block of registers has yet to be restored, do it now. */
4143 if (reg_size2)
4144 visium_restore_regs (reg_size1 + save_area_size, 0, max_reg1, 0);
4145
4146 /* If this is an exception return, make the necessary stack adjustment. */
4147 if (crtl->calls_eh_return)
4148 emit_insn (gen_stack_pop (EH_RETURN_STACKADJ_RTX));
4149}
4150
4151/* Return true if it is appropriate to emit `return' instructions in the
4152 body of a function. */
4153
4154bool
4155visium_can_use_return_insn_p (void)
4156{
4157 return reload_completed
4158 && visium_frame_size == 0
4159 && !visium_interrupt_function_p ();
4160}
4161
4162/* Return the register class required for an intermediate register used to
4163 copy a register of RCLASS from/to X. If no such intermediate register is
4164 required, return NO_REGS. If more than one such intermediate register is
4165 required, describe the one that is closest in the copy chain to the reload
4166 register. */
4167
4168static reg_class_t
4169visium_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x,
4170 reg_class_t rclass,
4171 enum machine_mode mode ATTRIBUTE_UNUSED,
4172 secondary_reload_info *sri ATTRIBUTE_UNUSED)
4173{
4174 int regno = true_regnum (x);
4175
4176 /* For MDB, MDC and FP_REGS, a general register is needed for a move to
4177 or from memory. */
4178 if (regno == -1 && (rclass == MDB || rclass == MDC || rclass == FP_REGS))
4179 return GENERAL_REGS;
4180
4181 /* Moves between MDB, MDC and FP_REGS also require a general register. */
4182 else if (((regno == R_MDB || regno == R_MDC) && rclass == FP_REGS)
4183 || (FP_REGISTER_P (regno) && (rclass == MDB || rclass == MDC)))
4184 return GENERAL_REGS;
4185
4186 /* Finally an (unlikely ?) move between MDB and MDC needs a general reg. */
4187 else if ((regno == R_MDB && rclass == MDC)
4188 || (rclass == MDB && regno == R_MDC))
4189 return GENERAL_REGS;
4190
4191 return NO_REGS;
4192}
4193
4194/* Return true if pseudos that have been assigned to registers of RCLASS
4195 would likely be spilled because registers of RCLASS are needed for
4196 spill registers. */
4197
4198static bool
4199visium_class_likely_spilled_p (reg_class_t rclass ATTRIBUTE_UNUSED)
4200{
4201 /* Return false for classes R1, R2 and R3, which are intended to be used
4202 only in the source code in conjunction with block move instructions. */
4203 return false;
4204}
4205
4206/* Return the register number if OP is a REG or a SUBREG of a REG, and
4207 INVALID_REGNUM in all the other cases. */
4208
4209unsigned int
4210reg_or_subreg_regno (rtx op)
4211{
4212 unsigned int regno;
4213
4214 if (GET_CODE (op) == REG)
4215 regno = REGNO (op);
4216 else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
4217 {
4218 if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
4219 regno = subreg_regno (op);
4220 else
4221 regno = REGNO (SUBREG_REG (op));
4222 }
4223 else
4224 regno = INVALID_REGNUM;
4225
4226 return regno;
4227}
4228
4229#include "gt-visium.h"