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