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