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