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