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