1 /* Subroutines used for code generation on the Tilera TILEPro.
2    Copyright (C) 2011-2021 Free Software Foundation, Inc.
3    Contributed by Walter Lee (walt@tilera.com)
4 
5    This file is part of GCC.
6 
7    GCC is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published
9    by the Free Software Foundation; either version 3, or (at your
10    option) any later version.
11 
12    GCC is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15    License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GCC; see the file COPYING3.  If not see
19    <http://www.gnu.org/licenses/>.  */
20 
21 #define IN_TARGET_CODE 1
22 
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "backend.h"
27 #include "target.h"
28 #include "rtl.h"
29 #include "tree.h"
30 #include "gimple.h"
31 #include "df.h"
32 #include "memmodel.h"
33 #include "tm_p.h"
34 #include "stringpool.h"
35 #include "attribs.h"
36 #include "expmed.h"
37 #include "optabs.h"
38 #include "regs.h"
39 #include "emit-rtl.h"
40 #include "recog.h"
41 #include "diagnostic.h"
42 #include "output.h"
43 #include "insn-attr.h"
44 #include "alias.h"
45 #include "explow.h"
46 #include "calls.h"
47 #include "varasm.h"
48 #include "expr.h"
49 #include "langhooks.h"
50 #include "cfgrtl.h"
51 #include "tm-constrs.h"
52 #include "dwarf2.h"
53 #include "fold-const.h"
54 #include "stor-layout.h"
55 #include "gimplify.h"
56 #include "tilepro-builtins.h"
57 #include "tilepro-multiply.h"
58 #include "builtins.h"
59 
60 /* This file should be included last.  */
61 #include "target-def.h"
62 
63 /* SYMBOL_REF for GOT */
64 static GTY(()) rtx g_got_symbol = NULL;
65 
66 /* Report whether we're printing out the first address fragment of a
67    POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
68    TARGET_PRINT_OPERAND_ADDRESS.  */
69 static bool output_memory_autoinc_first;
70 
71 
72 
73 /* Option handling  */
74 
75 /* Implement TARGET_OPTION_OVERRIDE.  */
76 static void
tilepro_option_override(void)77 tilepro_option_override (void)
78 {
79   /* When modulo scheduling is enabled, we still rely on regular
80      scheduler for bundling.  */
81   if (flag_modulo_sched)
82     flag_resched_modulo_sched = 1;
83 }
84 
85 
86 
87 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P.  */
88 static bool
tilepro_scalar_mode_supported_p(scalar_mode mode)89 tilepro_scalar_mode_supported_p (scalar_mode mode)
90 {
91   switch (mode)
92     {
93     case E_QImode:
94     case E_HImode:
95     case E_SImode:
96     case E_DImode:
97       return true;
98 
99     case E_SFmode:
100     case E_DFmode:
101       return true;
102 
103     default:
104       return false;
105     }
106 }
107 
108 
109 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P.  */
110 static bool
tile_vector_mode_supported_p(machine_mode mode)111 tile_vector_mode_supported_p (machine_mode mode)
112 {
113   return mode == V4QImode || mode == V2HImode;
114 }
115 
116 
117 /* Implement TARGET_CANNOT_FORCE_CONST_MEM.  */
118 static bool
tilepro_cannot_force_const_mem(machine_mode mode ATTRIBUTE_UNUSED,rtx x ATTRIBUTE_UNUSED)119 tilepro_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED,
120 				rtx x ATTRIBUTE_UNUSED)
121 {
122   return true;
123 }
124 
125 
126 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
127 static bool
tilepro_function_ok_for_sibcall(tree decl,tree exp ATTRIBUTE_UNUSED)128 tilepro_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
129 {
130   return decl != NULL;
131 }
132 
133 
134 /* Implement TARGET_PASS_BY_REFERENCE.  Variable sized types are
135    passed by reference.  */
136 static bool
tilepro_pass_by_reference(cumulative_args_t,const function_arg_info & arg)137 tilepro_pass_by_reference (cumulative_args_t, const function_arg_info &arg)
138 {
139   return (arg.type
140 	  && TYPE_SIZE (arg.type)
141 	  && TREE_CODE (TYPE_SIZE (arg.type)) != INTEGER_CST);
142 }
143 
144 
145 /* Implement TARGET_RETURN_IN_MEMORY.  */
146 static bool
tilepro_return_in_memory(const_tree type,const_tree fndecl ATTRIBUTE_UNUSED)147 tilepro_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
148 {
149   return !IN_RANGE (int_size_in_bytes (type),
150 		    0, TILEPRO_NUM_RETURN_REGS * UNITS_PER_WORD);
151 }
152 
153 
154 /* Implement TARGET_FUNCTION_ARG_BOUNDARY.  */
155 static unsigned int
tilepro_function_arg_boundary(machine_mode mode,const_tree type)156 tilepro_function_arg_boundary (machine_mode mode, const_tree type)
157 {
158   unsigned int alignment;
159 
160   alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode);
161   if (alignment < PARM_BOUNDARY)
162     alignment = PARM_BOUNDARY;
163   if (alignment > STACK_BOUNDARY)
164     alignment = STACK_BOUNDARY;
165   return alignment;
166 }
167 
168 
169 /* Implement TARGET_FUNCTION_ARG.  */
170 static rtx
tilepro_function_arg(cumulative_args_t cum_v,const function_arg_info & arg)171 tilepro_function_arg (cumulative_args_t cum_v, const function_arg_info &arg)
172 {
173   CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
174   int byte_size = arg.promoted_size_in_bytes ();
175   bool doubleword_aligned_p;
176 
177   if (cum >= TILEPRO_NUM_ARG_REGS)
178     return NULL_RTX;
179 
180   /* See whether the argument has doubleword alignment.  */
181   doubleword_aligned_p =
182     tilepro_function_arg_boundary (arg.mode, arg.type) > BITS_PER_WORD;
183 
184   if (doubleword_aligned_p)
185     cum += cum & 1;
186 
187   /* The ABI does not allow parameters to be passed partially in reg
188      and partially in stack.  */
189   if ((cum + (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
190       > TILEPRO_NUM_ARG_REGS)
191     return NULL_RTX;
192 
193   return gen_rtx_REG (arg.mode, cum);
194 }
195 
196 
197 /* Implement TARGET_FUNCTION_ARG_ADVANCE.  */
198 static void
tilepro_function_arg_advance(cumulative_args_t cum_v,const function_arg_info & arg)199 tilepro_function_arg_advance (cumulative_args_t cum_v,
200 			      const function_arg_info &arg)
201 {
202   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
203 
204   int byte_size = arg.promoted_size_in_bytes ();
205   int word_size = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
206   bool doubleword_aligned_p;
207 
208   /* See whether the argument has doubleword alignment.  */
209   doubleword_aligned_p =
210     tilepro_function_arg_boundary (arg.mode, arg.type) > BITS_PER_WORD;
211 
212   if (doubleword_aligned_p)
213     *cum += *cum & 1;
214 
215   /* If the current argument does not fit in the pretend_args space,
216      skip over it.  */
217   if (*cum < TILEPRO_NUM_ARG_REGS
218       && *cum + word_size > TILEPRO_NUM_ARG_REGS)
219     *cum = TILEPRO_NUM_ARG_REGS;
220 
221   *cum += word_size;
222 }
223 
224 
225 /* Implement TARGET_FUNCTION_VALUE.  */
226 static rtx
tilepro_function_value(const_tree valtype,const_tree fn_decl_or_type,bool outgoing ATTRIBUTE_UNUSED)227 tilepro_function_value (const_tree valtype, const_tree fn_decl_or_type,
228 			bool outgoing ATTRIBUTE_UNUSED)
229 {
230   machine_mode mode;
231   int unsigned_p;
232 
233   mode = TYPE_MODE (valtype);
234   unsigned_p = TYPE_UNSIGNED (valtype);
235 
236   mode = promote_function_mode (valtype, mode, &unsigned_p,
237 				fn_decl_or_type, 1);
238 
239   return gen_rtx_REG (mode, 0);
240 }
241 
242 
243 /* Implement TARGET_LIBCALL_VALUE.  */
244 static rtx
tilepro_libcall_value(machine_mode mode,const_rtx fun ATTRIBUTE_UNUSED)245 tilepro_libcall_value (machine_mode mode,
246 		       const_rtx fun ATTRIBUTE_UNUSED)
247 {
248   return gen_rtx_REG (mode, 0);
249 }
250 
251 
252 /* Implement FUNCTION_VALUE_REGNO_P.  */
253 static bool
tilepro_function_value_regno_p(const unsigned int regno)254 tilepro_function_value_regno_p (const unsigned int regno)
255 {
256   return regno < TILEPRO_NUM_RETURN_REGS;
257 }
258 
259 
260 /* Implement TARGET_BUILD_BUILTIN_VA_LIST.  */
261 static tree
tilepro_build_builtin_va_list(void)262 tilepro_build_builtin_va_list (void)
263 {
264   tree f_args, f_skip, record, type_decl;
265   bool owp;
266 
267   record = lang_hooks.types.make_type (RECORD_TYPE);
268 
269   type_decl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
270 			  get_identifier ("__va_list_tag"), record);
271 
272   f_args = build_decl (BUILTINS_LOCATION, FIELD_DECL,
273 		       get_identifier ("__args"), ptr_type_node);
274   f_skip = build_decl (BUILTINS_LOCATION, FIELD_DECL,
275 		       get_identifier ("__skip"), ptr_type_node);
276 
277   DECL_FIELD_CONTEXT (f_args) = record;
278 
279   DECL_FIELD_CONTEXT (f_skip) = record;
280 
281   TREE_CHAIN (record) = type_decl;
282   TYPE_NAME (record) = type_decl;
283   TYPE_FIELDS (record) = f_args;
284   TREE_CHAIN (f_args) = f_skip;
285 
286   /* We know this is being padded and we want it too.  It is an
287      internal type so hide the warnings from the user.  */
288   owp = warn_padded;
289   warn_padded = false;
290 
291   layout_type (record);
292 
293   warn_padded = owp;
294 
295   /* The correct type is an array type of one element.  */
296   return record;
297 }
298 
299 
300 /* Implement TARGET_EXPAND_BUILTIN_VA_START.  */
301 static void
tilepro_va_start(tree valist,rtx nextarg ATTRIBUTE_UNUSED)302 tilepro_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
303 {
304   tree f_args, f_skip;
305   tree args, skip, t;
306 
307   f_args = TYPE_FIELDS (TREE_TYPE (valist));
308   f_skip = TREE_CHAIN (f_args);
309 
310   args =
311     build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
312   skip =
313     build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
314 
315   /* Find the __args area.  */
316   t = make_tree (TREE_TYPE (args), virtual_incoming_args_rtx);
317   t = fold_build_pointer_plus_hwi (t,
318 				   UNITS_PER_WORD *
319 				   (crtl->args.info - TILEPRO_NUM_ARG_REGS));
320 
321   if (crtl->args.pretend_args_size > 0)
322     t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
323 
324   t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t);
325   TREE_SIDE_EFFECTS (t) = 1;
326   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
327 
328   /* Find the __skip area.  */
329   t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx);
330   t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
331   t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t);
332   TREE_SIDE_EFFECTS (t) = 1;
333   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
334 }
335 
336 
337 /* Implement TARGET_SETUP_INCOMING_VARARGS.  */
338 static void
tilepro_setup_incoming_varargs(cumulative_args_t cum,const function_arg_info & arg,int * pretend_args,int no_rtl)339 tilepro_setup_incoming_varargs (cumulative_args_t cum,
340 				const function_arg_info &arg,
341 				int *pretend_args, int no_rtl)
342 {
343   CUMULATIVE_ARGS local_cum = *get_cumulative_args (cum);
344   int first_reg;
345 
346   /* The caller has advanced CUM up to, but not beyond, the last named
347      argument.  Advance a local copy of CUM past the last "real" named
348      argument, to find out how many registers are left over.  */
349   targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum), arg);
350   first_reg = local_cum;
351 
352   if (local_cum < TILEPRO_NUM_ARG_REGS)
353     {
354       *pretend_args = UNITS_PER_WORD * (TILEPRO_NUM_ARG_REGS - first_reg);
355 
356       if (!no_rtl)
357 	{
358 	  alias_set_type set = get_varargs_alias_set ();
359 	  rtx tmp =
360 	    gen_rtx_MEM (BLKmode, plus_constant (Pmode, \
361 						 virtual_incoming_args_rtx,
362 						 -STACK_POINTER_OFFSET -
363 						 UNITS_PER_WORD *
364 						 (TILEPRO_NUM_ARG_REGS -
365 						  first_reg)));
366 	  MEM_NOTRAP_P (tmp) = 1;
367 	  set_mem_alias_set (tmp, set);
368 	  move_block_from_reg (first_reg, tmp,
369 			       TILEPRO_NUM_ARG_REGS - first_reg);
370 	}
371     }
372   else
373     *pretend_args = 0;
374 }
375 
376 
377 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR.  Gimplify va_arg by updating
378    the va_list structure VALIST as required to retrieve an argument of
379    type TYPE, and returning that argument.
380 
381    ret = va_arg(VALIST, TYPE);
382 
383    generates code equivalent to:
384 
385     paddedsize = (sizeof(TYPE) + 3) & -4;
386     if ((VALIST.__args + paddedsize > VALIST.__skip)
387 	& (VALIST.__args <= VALIST.__skip))
388       addr = VALIST.__skip + STACK_POINTER_OFFSET;
389     else
390       addr = VALIST.__args;
391     VALIST.__args = addr + paddedsize;
392     ret = *(TYPE *)addr;                                          */
393 static tree
tilepro_gimplify_va_arg_expr(tree valist,tree type,gimple_seq * pre_p,gimple_seq * post_p ATTRIBUTE_UNUSED)394 tilepro_gimplify_va_arg_expr (tree valist, tree type, gimple_seq * pre_p,
395 			      gimple_seq * post_p ATTRIBUTE_UNUSED)
396 {
397   tree f_args, f_skip;
398   tree args, skip;
399   HOST_WIDE_INT size, rsize;
400   tree addr, tmp;
401   bool pass_by_reference_p;
402 
403   f_args = TYPE_FIELDS (va_list_type_node);
404   f_skip = TREE_CHAIN (f_args);
405 
406   args =
407     build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
408   skip =
409     build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
410 
411   addr = create_tmp_var (ptr_type_node, "va_arg");
412 
413   /* if an object is dynamically sized, a pointer to it is passed
414      instead of the object itself.  */
415   pass_by_reference_p = pass_va_arg_by_reference (type);
416 
417   if (pass_by_reference_p)
418     type = build_pointer_type (type);
419 
420   size = int_size_in_bytes (type);
421   rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD;
422 
423   /* If the alignment of the type is greater than the default for a
424      parameter, align to STACK_BOUNDARY.  */
425   if (TYPE_ALIGN (type) > PARM_BOUNDARY)
426     {
427       /* Assert the only case we generate code for: when
428          stack boundary = 2 * parm boundary.  */
429       gcc_assert (STACK_BOUNDARY == PARM_BOUNDARY * 2);
430 
431       tmp = build2 (BIT_AND_EXPR, sizetype,
432 		    fold_convert (sizetype, unshare_expr (args)),
433 		    size_int (PARM_BOUNDARY / 8));
434       tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node,
435 		    unshare_expr (args), tmp);
436 
437       gimplify_assign (unshare_expr (args), tmp, pre_p);
438     }
439 
440   /* Build conditional expression to calculate addr. The expression
441      will be gimplified later.  */
442   tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize);
443   tmp = build2 (TRUTH_AND_EXPR, boolean_type_node,
444 		build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)),
445 		build2 (LE_EXPR, boolean_type_node, unshare_expr (args),
446 			unshare_expr (skip)));
447 
448   tmp = build3 (COND_EXPR, ptr_type_node, tmp,
449 		build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip),
450 			size_int (STACK_POINTER_OFFSET)),
451 		unshare_expr (args));
452 
453   gimplify_assign (addr, tmp, pre_p);
454 
455   /* Update VALIST.__args.  */
456   tmp = fold_build_pointer_plus_hwi (addr, rsize);
457   gimplify_assign (unshare_expr (args), tmp, pre_p);
458 
459   addr = fold_convert (build_pointer_type (type), addr);
460 
461   if (pass_by_reference_p)
462     addr = build_va_arg_indirect_ref (addr);
463 
464   return build_va_arg_indirect_ref (addr);
465 }
466 
467 
468 
469 /* Implement TARGET_RTX_COSTS.  */
470 static bool
tilepro_rtx_costs(rtx x,machine_mode mode,int outer_code,int opno,int * total,bool speed)471 tilepro_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno,
472 		   int *total, bool speed)
473 {
474   int code = GET_CODE (x);
475 
476   switch (code)
477     {
478     case CONST_INT:
479       /* If this is an 8-bit constant, return zero since it can be
480          used nearly anywhere with no cost.  If it is a valid operand
481          for an ADD or AND, likewise return 0 if we know it will be
482          used in that context.  Otherwise, return 2 since it might be
483          used there later.  All other constants take at least two
484          insns.  */
485       if (satisfies_constraint_I (x))
486 	{
487 	  *total = 0;
488 	  return true;
489 	}
490       else if (outer_code == PLUS && add_operand (x, VOIDmode))
491 	{
492 	  /* Slightly penalize large constants even though we can add
493 	     them in one instruction, because it forces the use of
494 	     2-wide bundling mode.  */
495 	  *total = 1;
496 	  return true;
497 	}
498       else if (move_operand (x, SImode))
499 	{
500 	  /* We can materialize in one move.  */
501 	  *total = COSTS_N_INSNS (1);
502 	  return true;
503 	}
504       else
505 	{
506 	  /* We can materialize in two moves.  */
507 	  *total = COSTS_N_INSNS (2);
508 	  return true;
509 	}
510 
511       return false;
512 
513     case CONST:
514     case LABEL_REF:
515     case SYMBOL_REF:
516       *total = COSTS_N_INSNS (2);
517       return true;
518 
519     case CONST_DOUBLE:
520       *total = COSTS_N_INSNS (4);
521       return true;
522 
523     case HIGH:
524       *total = 0;
525       return true;
526 
527     case MEM:
528       /* If outer-code was a sign or zero extension, a cost of
529          COSTS_N_INSNS (1) was already added in, so account for
530          that.  */
531       if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND)
532 	*total = COSTS_N_INSNS (1);
533       else
534 	*total = COSTS_N_INSNS (2);
535       return true;
536 
537     case PLUS:
538       /* Convey that s[123]a are efficient.  */
539       if (GET_CODE (XEXP (x, 0)) == MULT
540 	  && cint_248_operand (XEXP (XEXP (x, 0), 1), VOIDmode))
541 	{
542 	  *total = (rtx_cost (XEXP (XEXP (x, 0), 0), mode,
543 			      (enum rtx_code) outer_code, opno, speed)
544 		    + rtx_cost (XEXP (x, 1), mode,
545 				(enum rtx_code) outer_code, opno, speed)
546 		    + COSTS_N_INSNS (1));
547 	  return true;
548 	}
549       return false;
550 
551     case MULT:
552       *total = COSTS_N_INSNS (2);
553       return false;
554 
555     case SIGN_EXTEND:
556     case ZERO_EXTEND:
557       if (outer_code == MULT)
558 	*total = 0;
559       else
560 	*total = COSTS_N_INSNS (1);
561       return false;
562 
563     case DIV:
564     case UDIV:
565     case MOD:
566     case UMOD:
567       /* These are handled by software and are very expensive.  */
568       *total = COSTS_N_INSNS (100);
569       return false;
570 
571     case UNSPEC:
572     case UNSPEC_VOLATILE:
573       {
574 	int num = XINT (x, 1);
575 
576 	if (num <= TILEPRO_LAST_LATENCY_1_INSN)
577 	  *total = COSTS_N_INSNS (1);
578 	else if (num <= TILEPRO_LAST_LATENCY_2_INSN)
579 	  *total = COSTS_N_INSNS (2);
580 	else if (num > TILEPRO_LAST_LATENCY_INSN)
581 	  {
582 	    if (outer_code == PLUS)
583 	      *total = 0;
584 	    else
585 	      *total = COSTS_N_INSNS (1);
586 	  }
587 	else
588 	  {
589 	    switch (num)
590 	      {
591 	      case UNSPEC_BLOCKAGE:
592 	      case UNSPEC_NETWORK_BARRIER:
593 		*total = 0;
594 		break;
595 
596 	      case UNSPEC_LNK_AND_LABEL:
597 	      case UNSPEC_MF:
598 	      case UNSPEC_NETWORK_RECEIVE:
599 	      case UNSPEC_NETWORK_SEND:
600 	      case UNSPEC_TLS_GD_ADD:
601 		*total = COSTS_N_INSNS (1);
602 		break;
603 
604 	      case UNSPEC_TLS_IE_LOAD:
605 		*total = COSTS_N_INSNS (2);
606 		break;
607 
608 	      case UNSPEC_SP_SET:
609 		*total = COSTS_N_INSNS (3);
610 		break;
611 
612 	      case UNSPEC_SP_TEST:
613 		*total = COSTS_N_INSNS (4);
614 		break;
615 
616 	      case UNSPEC_LATENCY_L2:
617 		*total = COSTS_N_INSNS (8);
618 		break;
619 
620 	      case UNSPEC_TLS_GD_CALL:
621 		*total = COSTS_N_INSNS (30);
622 		break;
623 
624 	      case UNSPEC_LATENCY_MISS:
625 		*total = COSTS_N_INSNS (80);
626 		break;
627 
628 	      default:
629 		*total = COSTS_N_INSNS (1);
630 	      }
631 	  }
632 	return true;
633       }
634 
635     default:
636       return false;
637     }
638 }
639 
640 
641 
642 /* Returns an SImode integer rtx with value VAL.  */
643 static rtx
gen_int_si(HOST_WIDE_INT val)644 gen_int_si (HOST_WIDE_INT val)
645 {
646   return gen_int_mode (val, SImode);
647 }
648 
649 
650 /* Create a temporary variable to hold a partial result, to enable
651    CSE.  */
652 static rtx
create_temp_reg_if_possible(machine_mode mode,rtx default_reg)653 create_temp_reg_if_possible (machine_mode mode, rtx default_reg)
654 {
655   return can_create_pseudo_p ()? gen_reg_rtx (mode) : default_reg;
656 }
657 
658 
659 /* Functions to save and restore machine-specific function data.  */
660 static struct machine_function *
tilepro_init_machine_status(void)661 tilepro_init_machine_status (void)
662 {
663   return ggc_cleared_alloc<machine_function> ();
664 }
665 
666 
667 /* Do anything needed before RTL is emitted for each function.  */
668 void
tilepro_init_expanders(void)669 tilepro_init_expanders (void)
670 {
671   /* Arrange to initialize and mark the machine per-function
672      status.  */
673   init_machine_status = tilepro_init_machine_status;
674 
675   if (cfun && cfun->machine && flag_pic)
676     {
677       static int label_num = 0;
678 
679       char text_label_name[32];
680 
681       struct machine_function *machine = cfun->machine;
682 
683       ASM_GENERATE_INTERNAL_LABEL (text_label_name, "L_PICLNK", label_num++);
684 
685       machine->text_label_symbol =
686 	gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (text_label_name));
687 
688       machine->text_label_rtx =
689 	gen_rtx_REG (Pmode, TILEPRO_PIC_TEXT_LABEL_REGNUM);
690 
691       machine->got_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
692 
693       machine->calls_tls_get_addr = false;
694     }
695 }
696 
697 
698 /* Return true if X contains a thread-local symbol.  */
699 static bool
tilepro_tls_referenced_p(rtx x)700 tilepro_tls_referenced_p (rtx x)
701 {
702   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
703     x = XEXP (XEXP (x, 0), 0);
704 
705   if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
706     return true;
707 
708   /* That's all we handle in tilepro_legitimize_tls_address for
709      now.  */
710   return false;
711 }
712 
713 
714 /* Return true if X requires a scratch register.  It is given that
715    flag_pic is on and that X satisfies CONSTANT_P.  */
716 static int
tilepro_pic_address_needs_scratch(rtx x)717 tilepro_pic_address_needs_scratch (rtx x)
718 {
719   if (GET_CODE (x) == CONST
720       && GET_CODE (XEXP (x, 0)) == PLUS
721       && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
722 	  || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
723       && CONST_INT_P (XEXP (XEXP (x, 0), 1)))
724     return true;
725 
726   return false;
727 }
728 
729 
730 /* Implement TARGET_LEGITIMATE_CONSTANT_P.  This is all constants for
731    which we are willing to load the value into a register via a move
732    pattern.  TLS cannot be treated as a constant because it can
733    include a function call.  */
734 static bool
tilepro_legitimate_constant_p(machine_mode mode ATTRIBUTE_UNUSED,rtx x)735 tilepro_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
736 {
737   switch (GET_CODE (x))
738     {
739     case CONST:
740     case SYMBOL_REF:
741       return !tilepro_tls_referenced_p (x);
742 
743     default:
744       return true;
745     }
746 }
747 
748 
749 /* Return true if the constant value X is a legitimate general operand
750    when generating PIC code.  It is given that flag_pic is on and that
751    X satisfies CONSTANT_P.  */
752 bool
tilepro_legitimate_pic_operand_p(rtx x)753 tilepro_legitimate_pic_operand_p (rtx x)
754 {
755   if (tilepro_pic_address_needs_scratch (x))
756     return false;
757 
758   if (tilepro_tls_referenced_p (x))
759     return false;
760 
761   return true;
762 }
763 
764 
765 /* Return true if the rtx X can be used as an address operand.  */
766 static bool
tilepro_legitimate_address_p(machine_mode ARG_UNUSED (mode),rtx x,bool strict)767 tilepro_legitimate_address_p (machine_mode ARG_UNUSED (mode), rtx x,
768 			      bool strict)
769 {
770   if (GET_CODE (x) == SUBREG)
771     x = SUBREG_REG (x);
772 
773   switch (GET_CODE (x))
774     {
775     case POST_INC:
776     case POST_DEC:
777       if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
778 	return false;
779 
780       x = XEXP (x, 0);
781       break;
782 
783     case POST_MODIFY:
784       if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
785 	return false;
786 
787       if (GET_CODE (XEXP (x, 1)) != PLUS)
788 	return false;
789 
790       if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
791 	return false;
792 
793       if (!satisfies_constraint_I (XEXP (XEXP (x, 1), 1)))
794 	return false;
795 
796       x = XEXP (x, 0);
797       break;
798 
799     case REG:
800       break;
801 
802     default:
803       return false;
804     }
805 
806   /* Check if x is a valid reg.  */
807   if (!REG_P (x))
808     return false;
809 
810   if (strict)
811     return REGNO_OK_FOR_BASE_P (REGNO (x));
812   else
813     return true;
814 }
815 
816 
817 /* Return the rtx containing SYMBOL_REF to the text label.  */
818 static rtx
tilepro_text_label_symbol(void)819 tilepro_text_label_symbol (void)
820 {
821   return cfun->machine->text_label_symbol;
822 }
823 
824 
825 /* Return the register storing the value of the text label.  */
826 static rtx
tilepro_text_label_rtx(void)827 tilepro_text_label_rtx (void)
828 {
829   return cfun->machine->text_label_rtx;
830 }
831 
832 
833 /* Return the register storing the value of the global offset
834    table.  */
835 static rtx
tilepro_got_rtx(void)836 tilepro_got_rtx (void)
837 {
838   return cfun->machine->got_rtx;
839 }
840 
841 
842 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_.  */
843 static rtx
tilepro_got_symbol(void)844 tilepro_got_symbol (void)
845 {
846   if (g_got_symbol == NULL)
847     g_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
848 
849   return g_got_symbol;
850 }
851 
852 
853 /* Return a reference to the got to be used by tls references.  */
854 static rtx
tilepro_tls_got(void)855 tilepro_tls_got (void)
856 {
857   rtx temp;
858   if (flag_pic)
859     {
860       crtl->uses_pic_offset_table = 1;
861       return tilepro_got_rtx ();
862     }
863 
864   temp = gen_reg_rtx (Pmode);
865   emit_move_insn (temp, tilepro_got_symbol ());
866 
867   return temp;
868 }
869 
870 
871 /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
872    this (thread-local) address.  */
873 static rtx
tilepro_legitimize_tls_address(rtx addr)874 tilepro_legitimize_tls_address (rtx addr)
875 {
876   rtx ret;
877 
878   gcc_assert (can_create_pseudo_p ());
879 
880   if (GET_CODE (addr) == SYMBOL_REF)
881     switch (SYMBOL_REF_TLS_MODEL (addr))
882       {
883       case TLS_MODEL_GLOBAL_DYNAMIC:
884       case TLS_MODEL_LOCAL_DYNAMIC:
885 	{
886 	  rtx r0, temp1, temp2, temp3, got;
887 	  rtx_insn *last;
888 
889 	  ret = gen_reg_rtx (Pmode);
890 	  r0 = gen_rtx_REG (Pmode, 0);
891 	  temp1 = gen_reg_rtx (Pmode);
892 	  temp2 = gen_reg_rtx (Pmode);
893 	  temp3 = gen_reg_rtx (Pmode);
894 
895 	  got = tilepro_tls_got ();
896 	  emit_insn (gen_tls_gd_addhi (temp1, got, addr));
897 	  emit_insn (gen_tls_gd_addlo (temp2, temp1, addr));
898 	  emit_move_insn (r0, temp2);
899 	  emit_insn (gen_tls_gd_call (addr));
900 	  emit_move_insn (temp3, r0);
901 	  last = emit_insn (gen_tls_gd_add (ret, temp3, addr));
902 	  set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
903 	  break;
904 	}
905       case TLS_MODEL_INITIAL_EXEC:
906 	{
907 	  rtx temp1, temp2, temp3, got;
908 	  rtx_insn *last;
909 
910 	  ret = gen_reg_rtx (Pmode);
911 	  temp1 = gen_reg_rtx (Pmode);
912 	  temp2 = gen_reg_rtx (Pmode);
913 	  temp3 = gen_reg_rtx (Pmode);
914 
915 	  got = tilepro_tls_got ();
916 	  emit_insn (gen_tls_ie_addhi (temp1, got, addr));
917 	  emit_insn (gen_tls_ie_addlo (temp2, temp1, addr));
918 	  emit_insn (gen_tls_ie_load (temp3, temp2, addr));
919 	  last =
920 	    emit_move_insn(ret,
921 			   gen_rtx_PLUS (Pmode,
922 					 gen_rtx_REG (Pmode,
923 						      THREAD_POINTER_REGNUM),
924 					 temp3));
925 	  set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
926 	  break;
927 	}
928       case TLS_MODEL_LOCAL_EXEC:
929 	{
930 	  rtx temp1;
931 	  rtx_insn *last;
932 
933 	  ret = gen_reg_rtx (Pmode);
934 	  temp1 = gen_reg_rtx (Pmode);
935 
936 	  emit_insn (gen_tls_le_addhi (temp1,
937 				       gen_rtx_REG (Pmode,
938 						    THREAD_POINTER_REGNUM),
939 				       addr));
940 	  last = emit_insn (gen_tls_le_addlo (ret, temp1, addr));
941 	  set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
942 	  break;
943 	}
944       default:
945 	gcc_unreachable ();
946       }
947   else if (GET_CODE (addr) == CONST)
948     {
949       rtx base, offset;
950 
951       gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
952 
953       base = tilepro_legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
954       offset = XEXP (XEXP (addr, 0), 1);
955 
956       base = force_operand (base, NULL_RTX);
957       ret = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
958     }
959   else
960     gcc_unreachable ();
961 
962   return ret;
963 }
964 
965 
966 /* Legitimize PIC addresses.  If the address is already
967    position-independent, we return ORIG.  Newly generated
968    position-independent addresses go into a reg.  This is REG if
969    nonzero, otherwise we allocate register(s) as necessary.  */
970 static rtx
tilepro_legitimize_pic_address(rtx orig,machine_mode mode ATTRIBUTE_UNUSED,rtx reg)971 tilepro_legitimize_pic_address (rtx orig,
972 				machine_mode mode ATTRIBUTE_UNUSED,
973 				rtx reg)
974 {
975   if (GET_CODE (orig) == SYMBOL_REF)
976     {
977       rtx address, pic_ref;
978 
979       if (reg == 0)
980 	{
981 	  gcc_assert (can_create_pseudo_p ());
982 	  reg = gen_reg_rtx (Pmode);
983 	}
984 
985       if (SYMBOL_REF_LOCAL_P (orig))
986 	{
987 	  /* If not during reload, allocate another temp reg here for
988 	     loading in the address, so that these instructions can be
989 	     optimized properly.  */
990 	  rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
991 	  rtx text_label_symbol = tilepro_text_label_symbol ();
992 	  rtx text_label_rtx = tilepro_text_label_rtx ();
993 
994 	  emit_insn (gen_addli_pcrel (temp_reg, text_label_rtx, orig,
995 				      text_label_symbol));
996 	  emit_insn (gen_auli_pcrel (temp_reg, temp_reg, orig,
997 				     text_label_symbol));
998 
999 	  /* Note: this is conservative.  We use the text_label but we
1000 	     don't use the pic_offset_table.  However, in some cases
1001 	     we may need the pic_offset_table (see
1002 	     tilepro_fixup_pcrel_references).  */
1003 	  crtl->uses_pic_offset_table = 1;
1004 
1005 	  address = temp_reg;
1006 
1007 	  emit_move_insn (reg, address);
1008 	  return reg;
1009 	}
1010       else
1011 	{
1012 	  /* If not during reload, allocate another temp reg here for
1013 	     loading in the address, so that these instructions can be
1014 	     optimized properly.  */
1015 	  rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
1016 
1017 	  gcc_assert (flag_pic);
1018 	  if (flag_pic == 1)
1019 	    {
1020 	      emit_insn (gen_add_got16 (temp_reg,
1021 					tilepro_got_rtx (), orig));
1022 	    }
1023 	  else
1024 	    {
1025 	      rtx temp_reg2 = create_temp_reg_if_possible (Pmode, reg);
1026 	      emit_insn (gen_addhi_got32 (temp_reg2,
1027 					  tilepro_got_rtx (), orig));
1028 	      emit_insn (gen_addlo_got32 (temp_reg, temp_reg2, orig));
1029 	    }
1030 
1031 	  address = temp_reg;
1032 
1033 	  pic_ref = gen_const_mem (Pmode, address);
1034 	  crtl->uses_pic_offset_table = 1;
1035 	  emit_move_insn (reg, pic_ref);
1036 	  /* The following put a REG_EQUAL note on this insn, so that
1037 	     it can be optimized by loop.  But it causes the label to
1038 	     be optimized away.  */
1039 	  /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1040 	  return reg;
1041 	}
1042     }
1043   else if (GET_CODE (orig) == CONST)
1044     {
1045       rtx base, offset;
1046 
1047       if (GET_CODE (XEXP (orig, 0)) == PLUS
1048 	  && XEXP (XEXP (orig, 0), 0) == tilepro_got_rtx ())
1049 	return orig;
1050 
1051       if (reg == 0)
1052 	{
1053 	  gcc_assert (can_create_pseudo_p ());
1054 	  reg = gen_reg_rtx (Pmode);
1055 	}
1056 
1057       gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
1058       base = tilepro_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode,
1059 					     reg);
1060       offset =
1061 	tilepro_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
1062 					base == reg ? 0 : reg);
1063 
1064       if (CONST_INT_P (offset))
1065 	{
1066 	  if (can_create_pseudo_p ())
1067 	    offset = force_reg (Pmode, offset);
1068 	  else
1069 	    /* If we reach here, then something is seriously
1070 	       wrong.  */
1071 	    gcc_unreachable ();
1072 	}
1073 
1074       if (can_create_pseudo_p ())
1075 	return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
1076       else
1077 	gcc_unreachable ();
1078     }
1079   else if (GET_CODE (orig) == LABEL_REF)
1080     {
1081       rtx address, temp_reg;
1082       rtx text_label_symbol;
1083       rtx text_label_rtx;
1084 
1085       if (reg == 0)
1086 	{
1087 	  gcc_assert (can_create_pseudo_p ());
1088 	  reg = gen_reg_rtx (Pmode);
1089 	}
1090 
1091       /* If not during reload, allocate another temp reg here for
1092          loading in the address, so that these instructions can be
1093          optimized properly.  */
1094       temp_reg = create_temp_reg_if_possible (Pmode, reg);
1095       text_label_symbol = tilepro_text_label_symbol ();
1096       text_label_rtx = tilepro_text_label_rtx ();
1097 
1098       emit_insn (gen_addli_pcrel (temp_reg, text_label_rtx, orig,
1099 				  text_label_symbol));
1100       emit_insn (gen_auli_pcrel (temp_reg, temp_reg, orig,
1101 				 text_label_symbol));
1102 
1103       /* Note: this is conservative.  We use the text_label but we
1104          don't use the pic_offset_table.  */
1105       crtl->uses_pic_offset_table = 1;
1106 
1107       address = temp_reg;
1108 
1109       emit_move_insn (reg, address);
1110 
1111       return reg;
1112     }
1113 
1114   return orig;
1115 }
1116 
1117 
1118 /* Implement TARGET_LEGITIMIZE_ADDRESS.  */
1119 static rtx
tilepro_legitimize_address(rtx x,rtx oldx ATTRIBUTE_UNUSED,machine_mode mode)1120 tilepro_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1121 			    machine_mode mode)
1122 {
1123   if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
1124       && symbolic_operand (x, Pmode) && tilepro_tls_referenced_p (x))
1125     {
1126       return tilepro_legitimize_tls_address (x);
1127     }
1128   else if (flag_pic)
1129     {
1130       return tilepro_legitimize_pic_address (x, mode, 0);
1131     }
1132   else
1133     return x;
1134 }
1135 
1136 
1137 /* Implement TARGET_DELEGITIMIZE_ADDRESS.  */
1138 static rtx
tilepro_delegitimize_address(rtx x)1139 tilepro_delegitimize_address (rtx x)
1140 {
1141   x = delegitimize_mem_from_attrs (x);
1142 
1143   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC)
1144     {
1145       switch (XINT (XEXP (x, 0), 1))
1146 	{
1147 	case UNSPEC_PCREL_SYM:
1148 	case UNSPEC_GOT16_SYM:
1149 	case UNSPEC_GOT32_SYM:
1150 	case UNSPEC_TLS_GD:
1151 	case UNSPEC_TLS_IE:
1152 	  x = XVECEXP (XEXP (x, 0), 0, 0);
1153 	  break;
1154 	}
1155     }
1156 
1157   return x;
1158 }
1159 
1160 
1161 /* Emit code to load the PIC register.  */
1162 static void
load_pic_register(bool delay_pic_helper ATTRIBUTE_UNUSED)1163 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED)
1164 {
1165   int orig_flag_pic = flag_pic;
1166 
1167   rtx got_symbol = tilepro_got_symbol ();
1168   rtx text_label_symbol = tilepro_text_label_symbol ();
1169   rtx text_label_rtx = tilepro_text_label_rtx ();
1170   flag_pic = 0;
1171 
1172   emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol));
1173 
1174   emit_insn (gen_addli_pcrel (tilepro_got_rtx (),
1175 			      text_label_rtx, got_symbol, text_label_symbol));
1176 
1177   emit_insn (gen_auli_pcrel (tilepro_got_rtx (),
1178 			     tilepro_got_rtx (),
1179 			     got_symbol, text_label_symbol));
1180 
1181   flag_pic = orig_flag_pic;
1182 
1183   /* Need to emit this whether or not we obey regdecls, since
1184      setjmp/longjmp can cause life info to screw up.  ??? In the case
1185      where we don't obey regdecls, this is not sufficient since we may
1186      not fall out the bottom.  */
1187   emit_use (tilepro_got_rtx ());
1188 }
1189 
1190 
1191 /* Return the simd variant of the constant NUM of mode MODE, by
1192    replicating it to fill an interger of mode SImode.  NUM is first
1193    truncated to fit in MODE.  */
1194 rtx
tilepro_simd_int(rtx num,machine_mode mode)1195 tilepro_simd_int (rtx num, machine_mode mode)
1196 {
1197   HOST_WIDE_INT n = 0;
1198 
1199   gcc_assert (CONST_INT_P (num));
1200 
1201   n = INTVAL (num);
1202 
1203   switch (mode)
1204     {
1205     case E_QImode:
1206       n = 0x01010101 * (n & 0x000000FF);
1207       break;
1208     case E_HImode:
1209       n = 0x00010001 * (n & 0x0000FFFF);
1210       break;
1211     case E_SImode:
1212       break;
1213     case E_DImode:
1214       break;
1215     default:
1216       gcc_unreachable ();
1217     }
1218 
1219   return gen_int_si (n);
1220 }
1221 
1222 
1223 /* Split one or more DImode RTL references into pairs of SImode
1224    references.  The RTL can be REG, offsettable MEM, integer constant,
1225    or CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL
1226    to split and "num" is its length.  lo_half and hi_half are output
1227    arrays that parallel "operands".  */
1228 void
split_di(rtx operands[],int num,rtx lo_half[],rtx hi_half[])1229 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1230 {
1231   while (num--)
1232     {
1233       rtx op = operands[num];
1234 
1235       /* simplify_subreg refuse to split volatile memory addresses,
1236          but we still have to handle it.  */
1237       if (MEM_P (op))
1238 	{
1239 	  lo_half[num] = adjust_address (op, SImode, 0);
1240 	  hi_half[num] = adjust_address (op, SImode, 4);
1241 	}
1242       else
1243 	{
1244 	  lo_half[num] = simplify_gen_subreg (SImode, op,
1245 					      GET_MODE (op) == VOIDmode
1246 					      ? DImode : GET_MODE (op), 0);
1247 	  hi_half[num] = simplify_gen_subreg (SImode, op,
1248 					      GET_MODE (op) == VOIDmode
1249 					      ? DImode : GET_MODE (op), 4);
1250 	}
1251     }
1252 }
1253 
1254 
1255 /* Returns true iff val can be moved into a register in one
1256    instruction.  And if it can, it emits the code to move the
1257    constant.
1258 
1259    If three_wide_only is true, this insists on an instruction that
1260    works in a bundle containing three instructions.  */
1261 static bool
expand_set_cint32_one_inst(rtx dest_reg,HOST_WIDE_INT val,bool three_wide_only)1262 expand_set_cint32_one_inst (rtx dest_reg,
1263 			    HOST_WIDE_INT val, bool three_wide_only)
1264 {
1265   val = trunc_int_for_mode (val, SImode);
1266 
1267   if (val == trunc_int_for_mode (val, QImode))
1268     {
1269       /* Success! */
1270       emit_move_insn (dest_reg, GEN_INT (val));
1271       return true;
1272     }
1273   else if (!three_wide_only)
1274     {
1275       rtx imm_op = GEN_INT (val);
1276 
1277       if (satisfies_constraint_J (imm_op)
1278 	  || satisfies_constraint_K (imm_op)
1279 	  || satisfies_constraint_N (imm_op)
1280 	  || satisfies_constraint_P (imm_op))
1281 	{
1282 	  emit_move_insn (dest_reg, imm_op);
1283 	  return true;
1284 	}
1285     }
1286 
1287   return false;
1288 }
1289 
1290 
1291 /* Implement SImode rotatert.  */
1292 static HOST_WIDE_INT
rotate_right(HOST_WIDE_INT n,int count)1293 rotate_right (HOST_WIDE_INT n, int count)
1294 {
1295   unsigned HOST_WIDE_INT x = n & 0xFFFFFFFF;
1296   if (count == 0)
1297     return x;
1298   return ((x >> count) | (x << (32 - count))) & 0xFFFFFFFF;
1299 }
1300 
1301 
1302 /* Return true iff n contains exactly one contiguous sequence of 1
1303    bits, possibly wrapping around from high bits to low bits.  */
1304 bool
tilepro_bitfield_operand_p(HOST_WIDE_INT n,int * first_bit,int * last_bit)1305 tilepro_bitfield_operand_p (HOST_WIDE_INT n, int *first_bit, int *last_bit)
1306 {
1307   int i;
1308 
1309   if (n == 0)
1310     return false;
1311 
1312   for (i = 0; i < 32; i++)
1313     {
1314       unsigned HOST_WIDE_INT x = rotate_right (n, i);
1315       if (!(x & 1))
1316 	continue;
1317 
1318       /* See if x is a power of two minus one, i.e. only consecutive 1
1319          bits starting from bit 0.  */
1320       if ((x & (x + 1)) == 0)
1321 	{
1322 	  if (first_bit != NULL)
1323 	    *first_bit = i;
1324 	  if (last_bit != NULL)
1325 	    *last_bit = (i + exact_log2 (x ^ (x >> 1))) & 31;
1326 
1327 	  return true;
1328 	}
1329     }
1330 
1331   return false;
1332 }
1333 
1334 
1335 /* Create code to move the CONST_INT value in src_val to dest_reg.  */
1336 static void
expand_set_cint32(rtx dest_reg,rtx src_val)1337 expand_set_cint32 (rtx dest_reg, rtx src_val)
1338 {
1339   HOST_WIDE_INT val;
1340   int leading_zeroes, trailing_zeroes;
1341   int lower, upper;
1342   int three_wide_only;
1343   rtx temp;
1344 
1345   gcc_assert (CONST_INT_P (src_val));
1346   val = trunc_int_for_mode (INTVAL (src_val), SImode);
1347 
1348   /* See if we can generate the constant in one instruction.  */
1349   if (expand_set_cint32_one_inst (dest_reg, val, false))
1350     return;
1351 
1352   /* Create a temporary variable to hold a partial result, to enable
1353      CSE.  */
1354   temp = create_temp_reg_if_possible (SImode, dest_reg);
1355 
1356   leading_zeroes = 31 - floor_log2 (val & 0xFFFFFFFF);
1357   trailing_zeroes = exact_log2 (val & -val);
1358 
1359   lower = trunc_int_for_mode (val, HImode);
1360   upper = trunc_int_for_mode ((val - lower) >> 16, HImode);
1361 
1362   /* First try all three-wide instructions that generate a constant
1363      (i.e. movei) followed by various shifts and rotates. If none of
1364      those work, try various two-wide ways of generating a constant
1365      followed by various shifts and rotates.  */
1366   for (three_wide_only = 1; three_wide_only >= 0; three_wide_only--)
1367     {
1368       int count;
1369 
1370       if (expand_set_cint32_one_inst (temp, val >> trailing_zeroes,
1371 				      three_wide_only))
1372 	{
1373 	  /* 0xFFFFA500 becomes:
1374 	     movei temp, 0xFFFFFFA5
1375 	     shli dest, temp, 8  */
1376 	  emit_move_insn (dest_reg,
1377 			  gen_rtx_ASHIFT (SImode, temp,
1378 					  GEN_INT (trailing_zeroes)));
1379 	  return;
1380 	}
1381 
1382       if (expand_set_cint32_one_inst (temp, val << leading_zeroes,
1383 				      three_wide_only))
1384 	{
1385 	  /* 0x7FFFFFFF becomes:
1386 	     movei temp, -2
1387 	     shri dest, temp, 1  */
1388 	  emit_move_insn (dest_reg,
1389 			  gen_rtx_LSHIFTRT (SImode, temp,
1390 					    GEN_INT (leading_zeroes)));
1391 	  return;
1392 	}
1393 
1394       /* Try rotating a one-instruction immediate, since rotate is
1395          3-wide.  */
1396       for (count = 1; count < 32; count++)
1397 	{
1398 	  HOST_WIDE_INT r = rotate_right (val, count);
1399 	  if (expand_set_cint32_one_inst (temp, r, three_wide_only))
1400 	    {
1401 	      /* 0xFFA5FFFF becomes:
1402 	         movei temp, 0xFFFFFFA5
1403 	         rli dest, temp, 16  */
1404 	      emit_move_insn (dest_reg,
1405 			      gen_rtx_ROTATE (SImode, temp, GEN_INT (count)));
1406 	      return;
1407 	    }
1408 	}
1409 
1410       if (lower == trunc_int_for_mode (lower, QImode))
1411 	{
1412 	  /* We failed to use two 3-wide instructions, but the low 16
1413 	     bits are a small number so just use a 2-wide + 3-wide
1414 	     auli + addi pair rather than anything more exotic.
1415 
1416 	     0x12340056 becomes:
1417 	     auli temp, zero, 0x1234
1418 	     addi dest, temp, 0x56  */
1419 	  break;
1420 	}
1421     }
1422 
1423   /* Fallback case: use a auli + addli/addi pair.  */
1424   emit_move_insn (temp, GEN_INT (upper << 16));
1425   emit_move_insn (dest_reg, (gen_rtx_PLUS (SImode, temp, GEN_INT (lower))));
1426 }
1427 
1428 
1429 /* Load OP1, a 32-bit constant, into OP0, a register.  We know it
1430    can't be done in one insn when we get here, the move expander
1431    guarantees this.  */
1432 void
tilepro_expand_set_const32(rtx op0,rtx op1)1433 tilepro_expand_set_const32 (rtx op0, rtx op1)
1434 {
1435   machine_mode mode = GET_MODE (op0);
1436   rtx temp;
1437 
1438   if (CONST_INT_P (op1))
1439     {
1440       /* TODO: I don't know if we want to split large constants now,
1441          or wait until later (with a define_split).
1442 
1443          Does splitting early help CSE?  Does it harm other
1444          optimizations that might fold loads? */
1445       expand_set_cint32 (op0, op1);
1446     }
1447   else
1448     {
1449       temp = create_temp_reg_if_possible (mode, op0);
1450 
1451       /* A symbol, emit in the traditional way.  */
1452       emit_move_insn (temp, gen_rtx_HIGH (mode, op1));
1453       emit_move_insn (op0, gen_rtx_LO_SUM (mode, temp, op1));
1454     }
1455 }
1456 
1457 
1458 /* Expand a move instruction.  Return true if all work is done.  */
1459 bool
tilepro_expand_mov(machine_mode mode,rtx * operands)1460 tilepro_expand_mov (machine_mode mode, rtx *operands)
1461 {
1462   /* Handle sets of MEM first.  */
1463   if (MEM_P (operands[0]))
1464     {
1465       if (can_create_pseudo_p ())
1466 	operands[0] = validize_mem (operands[0]);
1467 
1468       if (reg_or_0_operand (operands[1], mode))
1469 	return false;
1470 
1471       if (!reload_in_progress)
1472 	operands[1] = force_reg (mode, operands[1]);
1473     }
1474 
1475   /* Fixup TLS cases.  */
1476   if (CONSTANT_P (operands[1]) && tilepro_tls_referenced_p (operands[1]))
1477     {
1478       operands[1] = tilepro_legitimize_tls_address (operands[1]);
1479       return false;
1480     }
1481 
1482   /* Fixup PIC cases.  */
1483   if (flag_pic && CONSTANT_P (operands[1]))
1484     {
1485       if (tilepro_pic_address_needs_scratch (operands[1]))
1486 	operands[1] = tilepro_legitimize_pic_address (operands[1], mode, 0);
1487 
1488       if (symbolic_operand (operands[1], mode))
1489 	{
1490 	  operands[1] = tilepro_legitimize_pic_address (operands[1],
1491 							mode,
1492 							(reload_in_progress ?
1493 							 operands[0] :
1494 							 NULL_RTX));
1495 	  return false;
1496 	}
1497     }
1498 
1499   /* Fixup for UNSPEC addresses.  */
1500   if (flag_pic
1501       && GET_CODE (operands[1]) == HIGH
1502       && GET_CODE (XEXP (operands[1], 0)) == CONST
1503       && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == UNSPEC)
1504     {
1505       rtx unspec = XEXP (XEXP (operands[1], 0), 0);
1506       int unspec_num = XINT (unspec, 1);
1507       if (unspec_num == UNSPEC_PCREL_SYM)
1508 	{
1509 	  emit_insn (gen_auli_pcrel (operands[0], const0_rtx,
1510 				     XVECEXP (unspec, 0, 0),
1511 				     XVECEXP (unspec, 0, 1)));
1512 	  return true;
1513 	}
1514       else if (flag_pic == 2 && unspec_num == UNSPEC_GOT32_SYM)
1515 	{
1516 	  emit_insn (gen_addhi_got32 (operands[0], const0_rtx,
1517 				      XVECEXP (unspec, 0, 0)));
1518 	  return true;
1519 	}
1520       else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_GD)
1521 	{
1522 	  emit_insn (gen_tls_gd_addhi (operands[0], const0_rtx,
1523 				       XVECEXP (unspec, 0, 0)));
1524 	  return true;
1525 	}
1526       else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_IE)
1527 	{
1528 	  emit_insn (gen_tls_ie_addhi (operands[0], const0_rtx,
1529 				       XVECEXP (unspec, 0, 0)));
1530 	  return true;
1531 	}
1532       else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_LE)
1533 	{
1534 	  emit_insn (gen_tls_le_addhi (operands[0], const0_rtx,
1535 				       XVECEXP (unspec, 0, 0)));
1536 	  return true;
1537 	}
1538     }
1539 
1540   /* Accept non-constants and valid constants unmodified.  */
1541   if (!CONSTANT_P (operands[1])
1542       || GET_CODE (operands[1]) == HIGH || move_operand (operands[1], mode))
1543     return false;
1544 
1545   /* Split large integers.  */
1546   if (GET_MODE_SIZE (mode) <= 4)
1547     {
1548       tilepro_expand_set_const32 (operands[0], operands[1]);
1549       return true;
1550     }
1551 
1552   return false;
1553 }
1554 
1555 
1556 /* Expand the "insv" pattern.  */
1557 void
tilepro_expand_insv(rtx operands[4])1558 tilepro_expand_insv (rtx operands[4])
1559 {
1560   rtx first_rtx = operands[2];
1561   HOST_WIDE_INT first = INTVAL (first_rtx);
1562   HOST_WIDE_INT width = INTVAL (operands[1]);
1563   rtx v = operands[3];
1564 
1565   /* Shift the inserted bits into position.  */
1566   if (first != 0)
1567     {
1568       if (CONST_INT_P (v))
1569 	{
1570 	  /* Shift the constant into mm position.  */
1571 	  v = gen_int_si (INTVAL (v) << first);
1572 	}
1573       else
1574 	{
1575 	  /* Shift over the value to be inserted.  */
1576 	  rtx tmp = gen_reg_rtx (SImode);
1577 	  emit_insn (gen_ashlsi3 (tmp, v, first_rtx));
1578 	  v = tmp;
1579 	}
1580     }
1581 
1582   /* Insert the shifted bits using an 'mm' insn.  */
1583   emit_insn (gen_insn_mm (operands[0], v, operands[0], first_rtx,
1584 			  GEN_INT (first + width - 1)));
1585 }
1586 
1587 
1588 /* Expand unaligned loads.  */
1589 void
tilepro_expand_unaligned_load(rtx dest_reg,rtx mem,HOST_WIDE_INT bitsize,HOST_WIDE_INT bit_offset,bool sign)1590 tilepro_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize,
1591 			       HOST_WIDE_INT bit_offset, bool sign)
1592 {
1593   machine_mode mode;
1594   rtx addr_lo, addr_hi;
1595   rtx mem_lo, mem_hi, hi;
1596   rtx mema, wide_result;
1597   int last_byte_offset;
1598   HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1599 
1600   mode = GET_MODE (dest_reg);
1601 
1602   hi = gen_reg_rtx (mode);
1603 
1604   if (bitsize == 2 * BITS_PER_UNIT && (bit_offset % BITS_PER_UNIT) == 0)
1605     {
1606       rtx lo;
1607 
1608       /* When just loading a two byte value, we can load the two bytes
1609          individually and combine them efficiently.  */
1610 
1611       mem_lo = adjust_address (mem, QImode, byte_offset);
1612       mem_hi = adjust_address (mem, QImode, byte_offset + 1);
1613 
1614       lo = gen_reg_rtx (mode);
1615       emit_insn (gen_zero_extendqisi2 (lo, mem_lo));
1616 
1617       if (sign)
1618 	{
1619 	  rtx tmp = gen_reg_rtx (mode);
1620 
1621 	  /* Do a signed load of the second byte then shift and OR it
1622 	     in.  */
1623 	  emit_insn (gen_extendqisi2 (gen_lowpart (SImode, hi), mem_hi));
1624 	  emit_insn (gen_ashlsi3 (gen_lowpart (SImode, tmp),
1625 				  gen_lowpart (SImode, hi), GEN_INT (8)));
1626 	  emit_insn (gen_iorsi3 (gen_lowpart (SImode, dest_reg),
1627 				 gen_lowpart (SImode, lo),
1628 				 gen_lowpart (SImode, tmp)));
1629 	}
1630       else
1631 	{
1632 	  /* Do two unsigned loads and use intlb to interleave
1633 	     them.  */
1634 	  emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, hi), mem_hi));
1635 	  emit_insn (gen_insn_intlb (gen_lowpart (SImode, dest_reg),
1636 				     gen_lowpart (SImode, hi),
1637 				     gen_lowpart (SImode, lo)));
1638 	}
1639 
1640       return;
1641     }
1642 
1643   mema = XEXP (mem, 0);
1644 
1645   /* AND addresses cannot be in any alias set, since they may
1646      implicitly alias surrounding code.  Ideally we'd have some alias
1647      set that covered all types except those with alignment 8 or
1648      higher.  */
1649   addr_lo = force_reg (Pmode, plus_constant (Pmode, mema, byte_offset));
1650   mem_lo = change_address (mem, mode,
1651 			   gen_rtx_AND (Pmode, addr_lo, GEN_INT (-4)));
1652   set_mem_alias_set (mem_lo, 0);
1653 
1654   /* Load the high word at an address that will not fault if the low
1655      address is aligned and at the very end of a page.  */
1656   last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT;
1657   addr_hi = force_reg (Pmode, plus_constant (Pmode, mema, last_byte_offset));
1658   mem_hi = change_address (mem, mode,
1659 			   gen_rtx_AND (Pmode, addr_hi, GEN_INT (-4)));
1660   set_mem_alias_set (mem_hi, 0);
1661 
1662   if (bitsize == 32)
1663     {
1664       addr_lo = make_safe_from (addr_lo, dest_reg);
1665       wide_result = dest_reg;
1666     }
1667   else
1668     {
1669       wide_result = gen_reg_rtx (mode);
1670     }
1671 
1672   /* Load hi first in case dest_reg is used in mema.  */
1673   emit_move_insn (hi, mem_hi);
1674   emit_move_insn (wide_result, mem_lo);
1675 
1676   emit_insn (gen_insn_dword_align (gen_lowpart (SImode, wide_result),
1677 				   gen_lowpart (SImode, wide_result),
1678 				   gen_lowpart (SImode, hi), addr_lo));
1679 
1680   if (bitsize != 32)
1681     {
1682       rtx extracted =
1683 	extract_bit_field (gen_lowpart (SImode, wide_result),
1684 			   bitsize, bit_offset % BITS_PER_UNIT,
1685 			   !sign, gen_lowpart (SImode, dest_reg),
1686 			   SImode, SImode, false, NULL);
1687 
1688       if (extracted != dest_reg)
1689 	emit_move_insn (dest_reg, gen_lowpart (SImode, extracted));
1690     }
1691 }
1692 
1693 
1694 /* Expand unaligned stores.  */
1695 static void
tilepro_expand_unaligned_store(rtx mem,rtx src,HOST_WIDE_INT bitsize,HOST_WIDE_INT bit_offset)1696 tilepro_expand_unaligned_store (rtx mem, rtx src, HOST_WIDE_INT bitsize,
1697 				HOST_WIDE_INT bit_offset)
1698 {
1699   HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1700   HOST_WIDE_INT bytesize = bitsize / BITS_PER_UNIT;
1701   HOST_WIDE_INT shift_amt;
1702   HOST_WIDE_INT i;
1703   rtx mem_addr;
1704   rtx store_val;
1705 
1706   for (i = 0, shift_amt = 0; i < bytesize; i++, shift_amt += BITS_PER_UNIT)
1707     {
1708       mem_addr = adjust_address (mem, QImode, byte_offset + i);
1709 
1710       if (shift_amt)
1711 	{
1712 	  store_val = expand_simple_binop (SImode, LSHIFTRT,
1713 					   gen_lowpart (SImode, src),
1714 					   GEN_INT (shift_amt), NULL, 1,
1715 					   OPTAB_LIB_WIDEN);
1716 	  store_val = gen_lowpart (QImode, store_val);
1717 	}
1718       else
1719 	{
1720 	  store_val = gen_lowpart (QImode, src);
1721 	}
1722 
1723       emit_move_insn (mem_addr, store_val);
1724     }
1725 }
1726 
1727 
1728 /* Implement the movmisalign patterns.  One of the operands is a
1729    memory that is not naturally aligned.  Emit instructions to load
1730    it.  */
1731 void
tilepro_expand_movmisalign(machine_mode mode,rtx * operands)1732 tilepro_expand_movmisalign (machine_mode mode, rtx *operands)
1733 {
1734   if (MEM_P (operands[1]))
1735     {
1736       rtx tmp;
1737 
1738       if (register_operand (operands[0], mode))
1739 	tmp = operands[0];
1740       else
1741 	tmp = gen_reg_rtx (mode);
1742 
1743       tilepro_expand_unaligned_load (tmp, operands[1],
1744 				     GET_MODE_BITSIZE (mode), 0, true);
1745 
1746       if (tmp != operands[0])
1747 	emit_move_insn (operands[0], tmp);
1748     }
1749   else if (MEM_P (operands[0]))
1750     {
1751       if (!reg_or_0_operand (operands[1], mode))
1752 	operands[1] = force_reg (mode, operands[1]);
1753 
1754       tilepro_expand_unaligned_store (operands[0], operands[1],
1755 				      GET_MODE_BITSIZE (mode), 0);
1756     }
1757   else
1758     gcc_unreachable ();
1759 }
1760 
1761 
1762 /* Implement the addsi3 pattern.  */
1763 bool
tilepro_expand_addsi(rtx op0,rtx op1,rtx op2)1764 tilepro_expand_addsi (rtx op0, rtx op1, rtx op2)
1765 {
1766   rtx temp;
1767   HOST_WIDE_INT n;
1768   HOST_WIDE_INT high;
1769 
1770   /* Skip anything that only takes one instruction.  */
1771   if (add_operand (op2, SImode))
1772     return false;
1773 
1774   /* We can only optimize ints here (it should be impossible to get
1775      here with any other type, but it is harmless to check.  */
1776   if (!CONST_INT_P (op2))
1777     return false;
1778 
1779   temp = create_temp_reg_if_possible (SImode, op0);
1780   n = INTVAL (op2);
1781   high = (n + (n & 0x8000)) & ~0xffff;
1782 
1783   emit_move_insn (temp, gen_rtx_PLUS (SImode, op1, gen_int_si (high)));
1784   emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, gen_int_si (n - high)));
1785 
1786   return true;
1787 }
1788 
1789 
1790 /* Implement the allocate_stack pattern (alloca).  */
1791 void
tilepro_allocate_stack(rtx op0,rtx op1)1792 tilepro_allocate_stack (rtx op0, rtx op1)
1793 {
1794   /* Technically the correct way to initialize chain_loc is with
1795    * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
1796    * sets the alias_set to that of a frame reference.  Some of our
1797    * tests rely on some unsafe assumption about when the chaining
1798    * update is done, we need to be conservative about reordering the
1799    * chaining instructions.
1800    */
1801   rtx fp_addr = gen_reg_rtx (Pmode);
1802   rtx fp_value = gen_reg_rtx (Pmode);
1803   rtx fp_loc;
1804 
1805   emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1806 					 GEN_INT (UNITS_PER_WORD)));
1807 
1808   fp_loc = gen_frame_mem (Pmode, fp_addr);
1809 
1810   emit_move_insn (fp_value, fp_loc);
1811 
1812   op1 = force_reg (Pmode, op1);
1813 
1814   emit_move_insn (stack_pointer_rtx,
1815 		  gen_rtx_MINUS (Pmode, stack_pointer_rtx, op1));
1816 
1817   emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1818 					 GEN_INT (UNITS_PER_WORD)));
1819 
1820   fp_loc = gen_frame_mem (Pmode, fp_addr);
1821 
1822   emit_move_insn (fp_loc, fp_value);
1823 
1824   emit_move_insn (op0, virtual_stack_dynamic_rtx);
1825 }
1826 
1827 
1828 
1829 /* Multiplies */
1830 
1831 /* Returns the insn_code in ENTRY.  */
1832 static enum insn_code
tilepro_multiply_get_opcode(const struct tilepro_multiply_insn_seq_entry * entry)1833 tilepro_multiply_get_opcode (const struct tilepro_multiply_insn_seq_entry
1834 			     *entry)
1835 {
1836   return tilepro_multiply_insn_seq_decode_opcode[entry->compressed_opcode];
1837 }
1838 
1839 
1840 /* Returns the length of the 'op' array.  */
1841 static int
tilepro_multiply_get_num_ops(const struct tilepro_multiply_insn_seq * seq)1842 tilepro_multiply_get_num_ops (const struct tilepro_multiply_insn_seq *seq)
1843 {
1844   /* The array either uses all of its allocated slots or is terminated
1845      by a bogus opcode. Either way, the array size is the index of the
1846      last valid opcode plus one.  */
1847   int i;
1848   for (i = tilepro_multiply_insn_seq_MAX_OPERATIONS - 1; i >= 0; i--)
1849     if (tilepro_multiply_get_opcode (&seq->op[i]) != CODE_FOR_nothing)
1850       return i + 1;
1851 
1852   /* An empty array is not allowed.  */
1853   gcc_unreachable ();
1854 }
1855 
1856 
1857 /* We precompute a number of expression trees for multiplying by
1858    constants.  This generates code for such an expression tree by
1859    walking through the nodes in the tree (which are conveniently
1860    pre-linearized) and emitting an instruction for each one.  */
1861 static void
tilepro_expand_constant_multiply_given_sequence(rtx result,rtx src,const struct tilepro_multiply_insn_seq * seq)1862 tilepro_expand_constant_multiply_given_sequence (rtx result, rtx src,
1863 						 const struct
1864 						 tilepro_multiply_insn_seq
1865 						 *seq)
1866 {
1867   int i;
1868   int num_ops;
1869 
1870   /* Keep track of the subexpressions computed so far, so later
1871      instructions can refer to them.  We seed the array with zero and
1872      the value being multiplied.  */
1873   int num_subexprs = 2;
1874   rtx subexprs[tilepro_multiply_insn_seq_MAX_OPERATIONS + 2];
1875   subexprs[0] = const0_rtx;
1876   subexprs[1] = src;
1877 
1878   /* Determine how many instructions we are going to generate.  */
1879   num_ops = tilepro_multiply_get_num_ops (seq);
1880   gcc_assert (num_ops > 0
1881 	      && num_ops <= tilepro_multiply_insn_seq_MAX_OPERATIONS);
1882 
1883   for (i = 0; i < num_ops; i++)
1884     {
1885       const struct tilepro_multiply_insn_seq_entry *entry = &seq->op[i];
1886 
1887       /* Figure out where to store the output of this instruction.  */
1888       const bool is_last_op = (i + 1 == num_ops);
1889       rtx out = is_last_op ? result : gen_reg_rtx (SImode);
1890 
1891       enum insn_code opcode = tilepro_multiply_get_opcode (entry);
1892       if (opcode == CODE_FOR_ashlsi3)
1893 	{
1894 	  /* Handle shift by immediate. This is a special case because
1895 	     the meaning of the second operand is a constant shift
1896 	     count rather than an operand index.  */
1897 
1898 	  /* Make sure the shift count is in range. Zero should not
1899 	     happen.  */
1900 	  const int shift_count = entry->rhs;
1901 	  gcc_assert (shift_count > 0 && shift_count < 32);
1902 
1903 	  /* Emit the actual instruction.  */
1904 	  emit_insn (GEN_FCN (opcode)
1905 		     (out, subexprs[entry->lhs],
1906 		      gen_rtx_CONST_INT (SImode, shift_count)));
1907 	}
1908       else
1909 	{
1910 	  /* Handle a normal two-operand instruction, such as add or
1911 	     s1a.  */
1912 
1913 	  /* Make sure we are referring to a previously computed
1914 	     subexpression.  */
1915 	  gcc_assert (entry->rhs < num_subexprs);
1916 
1917 	  /* Emit the actual instruction.  */
1918 	  emit_insn (GEN_FCN (opcode)
1919 		     (out, subexprs[entry->lhs], subexprs[entry->rhs]));
1920 	}
1921 
1922       /* Record this subexpression for use by later expressions.  */
1923       subexprs[num_subexprs++] = out;
1924     }
1925 }
1926 
1927 
1928 /* bsearch helper function.  */
1929 static int
tilepro_compare_multipliers(const void * key,const void * t)1930 tilepro_compare_multipliers (const void *key, const void *t)
1931 {
1932   return *(const int *) key -
1933     ((const struct tilepro_multiply_insn_seq *) t)->multiplier;
1934 }
1935 
1936 
1937 /* Returns the tilepro_multiply_insn_seq for multiplier, or NULL if
1938    none exists.  */
1939 static const struct tilepro_multiply_insn_seq *
tilepro_find_multiply_insn_seq_for_constant(int multiplier)1940 tilepro_find_multiply_insn_seq_for_constant (int multiplier)
1941 {
1942   return ((const struct tilepro_multiply_insn_seq *)
1943 	  bsearch (&multiplier, tilepro_multiply_insn_seq_table,
1944 		   tilepro_multiply_insn_seq_table_size,
1945 		   sizeof tilepro_multiply_insn_seq_table[0],
1946 		   tilepro_compare_multipliers));
1947 }
1948 
1949 
1950 /* Try to a expand constant multiply in SImode by looking it up in a
1951    precompiled table.  OP0 is the result operand, OP1 is the source
1952    operand, and MULTIPLIER is the value of the constant.  Return true
1953    if it succeeds.  */
1954 static bool
tilepro_expand_const_mulsi(rtx op0,rtx op1,int multiplier)1955 tilepro_expand_const_mulsi (rtx op0, rtx op1, int multiplier)
1956 {
1957   /* See if we have precomputed an efficient way to multiply by this
1958      constant.  */
1959   const struct tilepro_multiply_insn_seq *seq =
1960     tilepro_find_multiply_insn_seq_for_constant (multiplier);
1961   if (seq != NULL)
1962     {
1963       tilepro_expand_constant_multiply_given_sequence (op0, op1, seq);
1964       return true;
1965     }
1966   else
1967     return false;
1968 }
1969 
1970 
1971 /* Expand the mulsi pattern.  */
1972 bool
tilepro_expand_mulsi(rtx op0,rtx op1,rtx op2)1973 tilepro_expand_mulsi (rtx op0, rtx op1, rtx op2)
1974 {
1975   if (CONST_INT_P (op2))
1976     {
1977       HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), SImode);
1978       return tilepro_expand_const_mulsi (op0, op1, n);
1979     }
1980   return false;
1981 }
1982 
1983 
1984 /* Expand a high multiply pattern in SImode.  RESULT, OP1, OP2 are the
1985    operands, and SIGN is true if it's a signed multiply, and false if
1986    it's an unsigned multiply.  */
1987 static void
tilepro_expand_high_multiply(rtx result,rtx op1,rtx op2,bool sign)1988 tilepro_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign)
1989 {
1990   rtx tmp0 = gen_reg_rtx (SImode);
1991   rtx tmp1 = gen_reg_rtx (SImode);
1992   rtx tmp2 = gen_reg_rtx (SImode);
1993   rtx tmp3 = gen_reg_rtx (SImode);
1994   rtx tmp4 = gen_reg_rtx (SImode);
1995   rtx tmp5 = gen_reg_rtx (SImode);
1996   rtx tmp6 = gen_reg_rtx (SImode);
1997   rtx tmp7 = gen_reg_rtx (SImode);
1998   rtx tmp8 = gen_reg_rtx (SImode);
1999   rtx tmp9 = gen_reg_rtx (SImode);
2000   rtx tmp10 = gen_reg_rtx (SImode);
2001   rtx tmp11 = gen_reg_rtx (SImode);
2002   rtx tmp12 = gen_reg_rtx (SImode);
2003   rtx tmp13 = gen_reg_rtx (SImode);
2004   rtx result_lo = gen_reg_rtx (SImode);
2005 
2006   if (sign)
2007     {
2008       emit_insn (gen_insn_mulhl_su (tmp0, op1, op2));
2009       emit_insn (gen_insn_mulhl_su (tmp1, op2, op1));
2010       emit_insn (gen_insn_mulll_uu (tmp2, op1, op2));
2011       emit_insn (gen_insn_mulhh_ss (tmp3, op1, op2));
2012     }
2013   else
2014     {
2015       emit_insn (gen_insn_mulhl_uu (tmp0, op1, op2));
2016       emit_insn (gen_insn_mulhl_uu (tmp1, op2, op1));
2017       emit_insn (gen_insn_mulll_uu (tmp2, op1, op2));
2018       emit_insn (gen_insn_mulhh_uu (tmp3, op1, op2));
2019     }
2020 
2021   emit_move_insn (tmp4, (gen_rtx_ASHIFT (SImode, tmp0, GEN_INT (16))));
2022 
2023   emit_move_insn (tmp5, (gen_rtx_ASHIFT (SImode, tmp1, GEN_INT (16))));
2024 
2025   emit_move_insn (tmp6, (gen_rtx_PLUS (SImode, tmp4, tmp5)));
2026   emit_move_insn (result_lo, (gen_rtx_PLUS (SImode, tmp2, tmp6)));
2027 
2028   emit_move_insn (tmp7, gen_rtx_LTU (SImode, tmp6, tmp4));
2029   emit_move_insn (tmp8, gen_rtx_LTU (SImode, result_lo, tmp2));
2030 
2031   if (sign)
2032     {
2033       emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (SImode, tmp0, GEN_INT (16))));
2034       emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (SImode, tmp1, GEN_INT (16))));
2035     }
2036   else
2037     {
2038       emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (SImode, tmp0, GEN_INT (16))));
2039       emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (SImode, tmp1, GEN_INT (16))));
2040     }
2041 
2042   emit_move_insn (tmp11, (gen_rtx_PLUS (SImode, tmp3, tmp7)));
2043   emit_move_insn (tmp12, (gen_rtx_PLUS (SImode, tmp8, tmp9)));
2044   emit_move_insn (tmp13, (gen_rtx_PLUS (SImode, tmp11, tmp12)));
2045   emit_move_insn (result, (gen_rtx_PLUS (SImode, tmp13, tmp10)));
2046 }
2047 
2048 
2049 /* Implement smulsi3_highpart.  */
2050 void
tilepro_expand_smulsi3_highpart(rtx op0,rtx op1,rtx op2)2051 tilepro_expand_smulsi3_highpart (rtx op0, rtx op1, rtx op2)
2052 {
2053   tilepro_expand_high_multiply (op0, op1, op2, true);
2054 }
2055 
2056 
2057 /* Implement umulsi3_highpart.  */
2058 void
tilepro_expand_umulsi3_highpart(rtx op0,rtx op1,rtx op2)2059 tilepro_expand_umulsi3_highpart (rtx op0, rtx op1, rtx op2)
2060 {
2061   tilepro_expand_high_multiply (op0, op1, op2, false);
2062 }
2063 
2064 
2065 
2066 /* Compare and branches  */
2067 
2068 /* Helper function to handle DImode for tilepro_emit_setcc_internal.  */
2069 static bool
tilepro_emit_setcc_internal_di(rtx res,enum rtx_code code,rtx op0,rtx op1)2070 tilepro_emit_setcc_internal_di (rtx res, enum rtx_code code, rtx op0, rtx op1)
2071 {
2072   rtx operands[2], lo_half[2], hi_half[2];
2073   rtx tmp, tmp0, tmp1, tmp2;
2074   bool swap = false;
2075 
2076   /* Reduce the number of cases we need to handle by reversing the
2077      operands.  */
2078   switch (code)
2079     {
2080     case EQ:
2081     case NE:
2082     case LE:
2083     case LT:
2084     case LEU:
2085     case LTU:
2086       /* We handle these compares directly.  */
2087       break;
2088 
2089     case GE:
2090     case GT:
2091     case GEU:
2092     case GTU:
2093       /* Reverse the operands.  */
2094       swap = true;
2095       break;
2096 
2097     default:
2098       /* We should not have called this with any other code.  */
2099       gcc_unreachable ();
2100     }
2101 
2102   if (swap)
2103     {
2104       code = swap_condition (code);
2105       tmp = op0, op0 = op1, op1 = tmp;
2106     }
2107 
2108   operands[0] = op0;
2109   operands[1] = op1;
2110 
2111   split_di (operands, 2, lo_half, hi_half);
2112 
2113   if (!reg_or_0_operand (lo_half[0], SImode))
2114     lo_half[0] = force_reg (SImode, lo_half[0]);
2115 
2116   if (!reg_or_0_operand (hi_half[0], SImode))
2117     hi_half[0] = force_reg (SImode, hi_half[0]);
2118 
2119   if (!CONST_INT_P (lo_half[1]) && !register_operand (lo_half[1], SImode))
2120     lo_half[1] = force_reg (SImode, lo_half[1]);
2121 
2122   if (!CONST_INT_P (hi_half[1]) && !register_operand (hi_half[1], SImode))
2123     hi_half[1] = force_reg (SImode, hi_half[1]);
2124 
2125   tmp0 = gen_reg_rtx (SImode);
2126   tmp1 = gen_reg_rtx (SImode);
2127   tmp2 = gen_reg_rtx (SImode);
2128 
2129   switch (code)
2130     {
2131     case EQ:
2132       emit_insn (gen_insn_seq (tmp0, lo_half[0], lo_half[1]));
2133       emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2134       emit_insn (gen_andsi3 (res, tmp0, tmp1));
2135       return true;
2136     case NE:
2137       emit_insn (gen_insn_sne (tmp0, lo_half[0], lo_half[1]));
2138       emit_insn (gen_insn_sne (tmp1, hi_half[0], hi_half[1]));
2139       emit_insn (gen_iorsi3 (res, tmp0, tmp1));
2140       return true;
2141     case LE:
2142       emit_insn (gen_insn_slte (tmp0, hi_half[0], hi_half[1]));
2143       emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2144       emit_insn (gen_insn_slte_u (tmp2, lo_half[0], lo_half[1]));
2145       emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2146       return true;
2147     case LT:
2148       if (operands[1] == const0_rtx)
2149 	{
2150 	  emit_insn (gen_lshrsi3 (res, hi_half[0], GEN_INT (31)));
2151 	  return true;
2152 	}
2153       else
2154 	{
2155 	  emit_insn (gen_insn_slt (tmp0, hi_half[0], hi_half[1]));
2156 	  emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2157 	  emit_insn (gen_insn_slt_u (tmp2, lo_half[0], lo_half[1]));
2158 	  emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2159 	}
2160       return true;
2161     case LEU:
2162       emit_insn (gen_insn_slte_u (tmp0, hi_half[0], hi_half[1]));
2163       emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2164       emit_insn (gen_insn_slte_u (tmp2, lo_half[0], lo_half[1]));
2165       emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2166       return true;
2167     case LTU:
2168       emit_insn (gen_insn_slt_u (tmp0, hi_half[0], hi_half[1]));
2169       emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2170       emit_insn (gen_insn_slt_u (tmp2, lo_half[0], lo_half[1]));
2171       emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2172       return true;
2173     default:
2174       gcc_unreachable ();
2175     }
2176 
2177   return false;
2178 }
2179 
2180 
2181 /* Certain simplifications can be done to make invalid setcc
2182    operations valid.  Return the final comparison, or NULL if we can't
2183    work.  */
2184 static bool
tilepro_emit_setcc_internal(rtx res,enum rtx_code code,rtx op0,rtx op1,machine_mode cmp_mode)2185 tilepro_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1,
2186 			     machine_mode cmp_mode)
2187 {
2188   rtx tmp;
2189   bool swap = false;
2190 
2191   if (cmp_mode == DImode)
2192     {
2193       return tilepro_emit_setcc_internal_di (res, code, op0, op1);
2194     }
2195 
2196   /* The general case: fold the comparison code to the types of
2197      compares that we have, choosing the branch as necessary.  */
2198 
2199   switch (code)
2200     {
2201     case EQ:
2202     case NE:
2203     case LE:
2204     case LT:
2205     case LEU:
2206     case LTU:
2207       /* We have these compares.  */
2208       break;
2209 
2210     case GE:
2211     case GT:
2212     case GEU:
2213     case GTU:
2214       /* We do not have these compares, so we reverse the
2215          operands.  */
2216       swap = true;
2217       break;
2218 
2219     default:
2220       /* We should not have called this with any other code.  */
2221       gcc_unreachable ();
2222     }
2223 
2224   if (swap)
2225     {
2226       code = swap_condition (code);
2227       tmp = op0, op0 = op1, op1 = tmp;
2228     }
2229 
2230   if (!reg_or_0_operand (op0, SImode))
2231     op0 = force_reg (SImode, op0);
2232 
2233   if (!CONST_INT_P (op1) && !register_operand (op1, SImode))
2234     op1 = force_reg (SImode, op1);
2235 
2236   /* Return the setcc comparison.  */
2237   emit_insn (gen_rtx_SET (res, gen_rtx_fmt_ee (code, SImode, op0, op1)));
2238 
2239   return true;
2240 }
2241 
2242 
2243 /* Implement cstore patterns.  */
2244 bool
tilepro_emit_setcc(rtx operands[],machine_mode cmp_mode)2245 tilepro_emit_setcc (rtx operands[], machine_mode cmp_mode)
2246 {
2247   return
2248     tilepro_emit_setcc_internal (operands[0], GET_CODE (operands[1]),
2249 				 operands[2], operands[3], cmp_mode);
2250 }
2251 
2252 
2253 /* Return whether CODE is a signed comparison.  */
2254 static bool
signed_compare_p(enum rtx_code code)2255 signed_compare_p (enum rtx_code code)
2256 {
2257   return (code == EQ || code == NE || code == LT || code == LE
2258 	  || code == GT || code == GE);
2259 }
2260 
2261 
2262 /* Generate the comparison for an SImode conditional branch.  */
2263 static rtx
tilepro_emit_cc_test(enum rtx_code code,rtx op0,rtx op1,machine_mode cmp_mode,bool eq_ne_only)2264 tilepro_emit_cc_test (enum rtx_code code, rtx op0, rtx op1,
2265 		      machine_mode cmp_mode, bool eq_ne_only)
2266 {
2267   enum rtx_code branch_code;
2268   rtx temp;
2269 
2270   /* Check for a compare against zero using a comparison we can do
2271      directly.  */
2272   if (cmp_mode != DImode
2273       && op1 == const0_rtx
2274       && (code == EQ || code == NE
2275 	  || (!eq_ne_only && signed_compare_p (code))))
2276     {
2277       op0 = force_reg (SImode, op0);
2278       return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx);
2279     }
2280 
2281   /* The general case: fold the comparison code to the types of
2282      compares that we have, choosing the branch as necessary.  */
2283   switch (code)
2284     {
2285     case EQ:
2286     case LE:
2287     case LT:
2288     case LEU:
2289     case LTU:
2290       /* We have these compares.  */
2291       branch_code = NE;
2292       break;
2293 
2294     case NE:
2295     case GE:
2296     case GT:
2297     case GEU:
2298     case GTU:
2299       /* These must be reversed (except NE, but let's
2300          canonicalize).  */
2301       code = reverse_condition (code);
2302       branch_code = EQ;
2303       break;
2304 
2305     default:
2306       gcc_unreachable ();
2307     }
2308 
2309   if (cmp_mode != DImode
2310       && CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU))
2311     {
2312       HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op1), SImode);
2313 
2314       switch (code)
2315 	{
2316 	case EQ:
2317 	  /* Subtract off the value we want to compare against and see
2318 	     if we get zero.  This is cheaper than creating a constant
2319 	     in a register. Except that subtracting -128 is more
2320 	     expensive than seqi to -128, so we leave that alone.  */
2321 	  /* ??? Don't do this when comparing against symbols,
2322 	     otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2323 	     0), which will be declared false out of hand (at least
2324 	     for non-weak).  */
2325 	  if (!(symbolic_operand (op0, VOIDmode)
2326 		|| (REG_P (op0) && REG_POINTER (op0))))
2327 	    {
2328 	      /* To compare against MIN_INT, we add MIN_INT and check
2329 	         for 0.  */
2330 	      HOST_WIDE_INT add;
2331 	      if (n != -2147483647 - 1)
2332 		add = -n;
2333 	      else
2334 		add = n;
2335 
2336 	      op0 = force_reg (SImode, op0);
2337 	      temp = gen_reg_rtx (SImode);
2338 	      emit_insn (gen_addsi3 (temp, op0, gen_int_si (add)));
2339 	      return gen_rtx_fmt_ee (reverse_condition (branch_code),
2340 				     VOIDmode, temp, const0_rtx);
2341 	    }
2342 	  break;
2343 
2344 	case LEU:
2345 	  if (n == -1)
2346 	    break;
2347 	  /* FALLTHRU */
2348 
2349 	case LTU:
2350 	  /* Change ((unsigned)x < 0x1000) into !((unsigned)x >> 12),
2351 	     etc.  */
2352 	  {
2353 	    int first = exact_log2 (code == LTU ? n : n + 1);
2354 	    if (first != -1)
2355 	      {
2356 		op0 = force_reg (SImode, op0);
2357 		temp = gen_reg_rtx (SImode);
2358 		emit_move_insn (temp,
2359 				gen_rtx_LSHIFTRT (SImode, op0,
2360 						  gen_int_si (first)));
2361 		return gen_rtx_fmt_ee (reverse_condition (branch_code),
2362 				       VOIDmode, temp, const0_rtx);
2363 	      }
2364 	  }
2365 	  break;
2366 
2367 	default:
2368 	  break;
2369 	}
2370     }
2371 
2372   /* Compute a flag saying whether we should branch.  */
2373   temp = gen_reg_rtx (SImode);
2374   tilepro_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2375 
2376   /* Return the branch comparison.  */
2377   return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx);
2378 }
2379 
2380 
2381 /* Generate the comparison for a conditional branch.  */
2382 void
tilepro_emit_conditional_branch(rtx operands[],machine_mode cmp_mode)2383 tilepro_emit_conditional_branch (rtx operands[], machine_mode cmp_mode)
2384 {
2385   rtx cmp_rtx =
2386     tilepro_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2],
2387 			  cmp_mode, false);
2388   rtx branch_rtx = gen_rtx_SET (pc_rtx,
2389 				gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx,
2390 						      gen_rtx_LABEL_REF
2391 						      (VOIDmode,
2392 						       operands[3]),
2393 						      pc_rtx));
2394   emit_jump_insn (branch_rtx);
2395 }
2396 
2397 
2398 /* Implement the movsicc pattern.  */
2399 rtx
tilepro_emit_conditional_move(rtx cmp)2400 tilepro_emit_conditional_move (rtx cmp)
2401 {
2402   return
2403     tilepro_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1),
2404 			  GET_MODE (XEXP (cmp, 0)), true);
2405 }
2406 
2407 
2408 /* Return true if INSN is annotated with a REG_BR_PROB note that
2409    indicates it's a branch that's predicted taken.  */
2410 static bool
cbranch_predicted_p(rtx_insn * insn)2411 cbranch_predicted_p (rtx_insn *insn)
2412 {
2413   rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2414 
2415   if (x)
2416     {
2417       return profile_probability::from_reg_br_prob_note (XINT (x, 0))
2418 	     >= profile_probability::even ();
2419     }
2420 
2421   return false;
2422 }
2423 
2424 
2425 /* Output assembly code for a specific branch instruction, appending
2426    the branch prediction flag to the opcode if appropriate.  */
2427 static const char *
tilepro_output_simple_cbranch_with_opcode(rtx_insn * insn,const char * opcode,int regop,bool netreg_p,bool reverse_predicted)2428 tilepro_output_simple_cbranch_with_opcode (rtx_insn *insn, const char *opcode,
2429 					   int regop, bool netreg_p,
2430 					   bool reverse_predicted)
2431 {
2432   static char buf[64];
2433   sprintf (buf, "%s%s\t%%%c%d, %%l0", opcode,
2434 	   (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "",
2435 	   netreg_p ? 'N' : 'r', regop);
2436   return buf;
2437 }
2438 
2439 
2440 /* Output assembly code for a specific branch instruction, appending
2441    the branch prediction flag to the opcode if appropriate.  */
2442 const char *
tilepro_output_cbranch_with_opcode(rtx_insn * insn,rtx * operands,const char * opcode,const char * rev_opcode,int regop,bool netreg_p)2443 tilepro_output_cbranch_with_opcode (rtx_insn *insn, rtx *operands,
2444 				    const char *opcode,
2445 				    const char *rev_opcode,
2446 				    int regop, bool netreg_p)
2447 {
2448   const char *branch_if_false;
2449   rtx taken, not_taken;
2450   bool is_simple_branch;
2451 
2452   gcc_assert (LABEL_P (operands[0]));
2453 
2454   is_simple_branch = true;
2455   if (INSN_ADDRESSES_SET_P ())
2456     {
2457       int from_addr = INSN_ADDRESSES (INSN_UID (insn));
2458       int to_addr = INSN_ADDRESSES (INSN_UID (operands[0]));
2459       int delta = to_addr - from_addr;
2460       is_simple_branch = IN_RANGE (delta, -524288, 524280);
2461     }
2462 
2463   if (is_simple_branch)
2464     {
2465       /* Just a simple conditional branch.  */
2466       return
2467 	tilepro_output_simple_cbranch_with_opcode (insn, opcode, regop,
2468 						   netreg_p, false);
2469     }
2470 
2471   /* Generate a reversed branch around a direct jump.  This fallback
2472      does not use branch-likely instructions.  */
2473   not_taken = gen_label_rtx ();
2474   taken = operands[0];
2475 
2476   /* Generate the reversed branch to NOT_TAKEN.  */
2477   operands[0] = not_taken;
2478   branch_if_false =
2479     tilepro_output_simple_cbranch_with_opcode (insn, rev_opcode, regop,
2480 					       netreg_p, true);
2481   output_asm_insn (branch_if_false, operands);
2482 
2483   output_asm_insn ("j\t%l0", &taken);
2484 
2485   /* Output NOT_TAKEN.  */
2486   targetm.asm_out.internal_label (asm_out_file, "L",
2487 				  CODE_LABEL_NUMBER (not_taken));
2488   return "";
2489 }
2490 
2491 
2492 /* Output assembly code for a conditional branch instruction.  */
2493 const char *
tilepro_output_cbranch(rtx_insn * insn,rtx * operands,bool reversed)2494 tilepro_output_cbranch (rtx_insn *insn, rtx *operands, bool reversed)
2495 {
2496   enum rtx_code code = GET_CODE (operands[1]);
2497   const char *opcode;
2498   const char *rev_opcode;
2499 
2500   if (reversed)
2501     code = reverse_condition (code);
2502 
2503   switch (code)
2504     {
2505     case NE:
2506       opcode = "bnz";
2507       rev_opcode = "bz";
2508       break;
2509     case EQ:
2510       opcode = "bz";
2511       rev_opcode = "bnz";
2512       break;
2513     case GE:
2514       opcode = "bgez";
2515       rev_opcode = "blz";
2516       break;
2517     case GT:
2518       opcode = "bgz";
2519       rev_opcode = "blez";
2520       break;
2521     case LE:
2522       opcode = "blez";
2523       rev_opcode = "bgz";
2524       break;
2525     case LT:
2526       opcode = "blz";
2527       rev_opcode = "bgez";
2528       break;
2529     default:
2530       gcc_unreachable ();
2531     }
2532 
2533   return
2534     tilepro_output_cbranch_with_opcode (insn, operands, opcode, rev_opcode,
2535 					2, false);
2536 }
2537 
2538 
2539 /* Implement the tablejump pattern.  */
2540 void
tilepro_expand_tablejump(rtx op0,rtx op1)2541 tilepro_expand_tablejump (rtx op0, rtx op1)
2542 {
2543   if (flag_pic)
2544     {
2545       rtx table = gen_rtx_LABEL_REF (Pmode, op1);
2546       rtx temp = gen_reg_rtx (Pmode);
2547       rtx text_label_symbol = tilepro_text_label_symbol ();
2548       rtx text_label_rtx = tilepro_text_label_rtx ();
2549 
2550       emit_insn (gen_addli_pcrel (temp, text_label_rtx,
2551 				  table, text_label_symbol));
2552       emit_insn (gen_auli_pcrel (temp, temp, table, text_label_symbol));
2553       emit_move_insn (temp,
2554 		      gen_rtx_PLUS (Pmode,
2555 				    convert_to_mode (Pmode, op0, false),
2556 				    temp));
2557       op0 = temp;
2558     }
2559 
2560   emit_jump_insn (gen_tablejump_aux (op0, op1));
2561 }
2562 
2563 
2564 /* Expand a builtin vector binary op, by calling gen function GEN with
2565    operands in the proper modes.  DEST is converted to DEST_MODE, and
2566    src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE.  */
2567 void
tilepro_expand_builtin_vector_binop(rtx (* gen)(rtx,rtx,rtx),machine_mode dest_mode,rtx dest,machine_mode src_mode,rtx src0,rtx src1,bool do_src1)2568 tilepro_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx),
2569 				     machine_mode dest_mode,
2570 				     rtx dest,
2571 				     machine_mode src_mode,
2572 				     rtx src0, rtx src1, bool do_src1)
2573 {
2574   dest = gen_lowpart (dest_mode, dest);
2575 
2576   if (src0 == const0_rtx)
2577     src0 = CONST0_RTX (src_mode);
2578   else
2579     src0 = gen_lowpart (src_mode, src0);
2580 
2581   if (do_src1)
2582     {
2583       if (src1 == const0_rtx)
2584 	src1 = CONST0_RTX (src_mode);
2585       else
2586 	src1 = gen_lowpart (src_mode, src1);
2587     }
2588 
2589   emit_insn ((*gen) (dest, src0, src1));
2590 }
2591 
2592 
2593 
2594 /* Intrinsics  */
2595 
2596 struct tile_builtin_info
2597 {
2598   enum insn_code icode;
2599   tree fndecl;
2600 };
2601 
2602 static struct tile_builtin_info tilepro_builtin_info[TILEPRO_BUILTIN_max] = {
2603   { CODE_FOR_addsi3,                    NULL }, /* add */
2604   { CODE_FOR_insn_addb,                 NULL }, /* addb */
2605   { CODE_FOR_insn_addbs_u,              NULL }, /* addbs_u */
2606   { CODE_FOR_insn_addh,                 NULL }, /* addh */
2607   { CODE_FOR_insn_addhs,                NULL }, /* addhs */
2608   { CODE_FOR_insn_addib,                NULL }, /* addib */
2609   { CODE_FOR_insn_addih,                NULL }, /* addih */
2610   { CODE_FOR_insn_addlis,               NULL }, /* addlis */
2611   { CODE_FOR_ssaddsi3,                  NULL }, /* adds */
2612   { CODE_FOR_insn_adiffb_u,             NULL }, /* adiffb_u */
2613   { CODE_FOR_insn_adiffh,               NULL }, /* adiffh */
2614   { CODE_FOR_andsi3,                    NULL }, /* and */
2615   { CODE_FOR_insn_auli,                 NULL }, /* auli */
2616   { CODE_FOR_insn_avgb_u,               NULL }, /* avgb_u */
2617   { CODE_FOR_insn_avgh,                 NULL }, /* avgh */
2618   { CODE_FOR_insn_bitx,                 NULL }, /* bitx */
2619   { CODE_FOR_bswapsi2,                  NULL }, /* bytex */
2620   { CODE_FOR_clzsi2,                    NULL }, /* clz */
2621   { CODE_FOR_insn_crc32_32,             NULL }, /* crc32_32 */
2622   { CODE_FOR_insn_crc32_8,              NULL }, /* crc32_8 */
2623   { CODE_FOR_ctzsi2,                    NULL }, /* ctz */
2624   { CODE_FOR_insn_drain,                NULL }, /* drain */
2625   { CODE_FOR_insn_dtlbpr,               NULL }, /* dtlbpr */
2626   { CODE_FOR_insn_dword_align,          NULL }, /* dword_align */
2627   { CODE_FOR_insn_finv,                 NULL }, /* finv */
2628   { CODE_FOR_insn_flush,                NULL }, /* flush */
2629   { CODE_FOR_insn_fnop,                 NULL }, /* fnop */
2630   { CODE_FOR_insn_icoh,                 NULL }, /* icoh */
2631   { CODE_FOR_insn_ill,                  NULL }, /* ill */
2632   { CODE_FOR_insn_info,                 NULL }, /* info */
2633   { CODE_FOR_insn_infol,                NULL }, /* infol */
2634   { CODE_FOR_insn_inthb,                NULL }, /* inthb */
2635   { CODE_FOR_insn_inthh,                NULL }, /* inthh */
2636   { CODE_FOR_insn_intlb,                NULL }, /* intlb */
2637   { CODE_FOR_insn_intlh,                NULL }, /* intlh */
2638   { CODE_FOR_insn_inv,                  NULL }, /* inv */
2639   { CODE_FOR_insn_lb,                   NULL }, /* lb */
2640   { CODE_FOR_insn_lb_u,                 NULL }, /* lb_u */
2641   { CODE_FOR_insn_lh,                   NULL }, /* lh */
2642   { CODE_FOR_insn_lh_u,                 NULL }, /* lh_u */
2643   { CODE_FOR_insn_lnk,                  NULL }, /* lnk */
2644   { CODE_FOR_insn_lw,                   NULL }, /* lw */
2645   { CODE_FOR_insn_lw_na,                NULL }, /* lw_na */
2646   { CODE_FOR_insn_lb_L2,                NULL }, /* lb_L2 */
2647   { CODE_FOR_insn_lb_u_L2,              NULL }, /* lb_u_L2 */
2648   { CODE_FOR_insn_lh_L2,                NULL }, /* lh_L2 */
2649   { CODE_FOR_insn_lh_u_L2,              NULL }, /* lh_u_L2 */
2650   { CODE_FOR_insn_lw_L2,                NULL }, /* lw_L2 */
2651   { CODE_FOR_insn_lw_na_L2,             NULL }, /* lw_na_L2 */
2652   { CODE_FOR_insn_lb_miss,              NULL }, /* lb_miss */
2653   { CODE_FOR_insn_lb_u_miss,            NULL }, /* lb_u_miss */
2654   { CODE_FOR_insn_lh_miss,              NULL }, /* lh_miss */
2655   { CODE_FOR_insn_lh_u_miss,            NULL }, /* lh_u_miss */
2656   { CODE_FOR_insn_lw_miss,              NULL }, /* lw_miss */
2657   { CODE_FOR_insn_lw_na_miss,           NULL }, /* lw_na_miss */
2658   { CODE_FOR_insn_maxb_u,               NULL }, /* maxb_u */
2659   { CODE_FOR_insn_maxh,                 NULL }, /* maxh */
2660   { CODE_FOR_insn_maxib_u,              NULL }, /* maxib_u */
2661   { CODE_FOR_insn_maxih,                NULL }, /* maxih */
2662   { CODE_FOR_memory_barrier,            NULL }, /* mf */
2663   { CODE_FOR_insn_mfspr,                NULL }, /* mfspr */
2664   { CODE_FOR_insn_minb_u,               NULL }, /* minb_u */
2665   { CODE_FOR_insn_minh,                 NULL }, /* minh */
2666   { CODE_FOR_insn_minib_u,              NULL }, /* minib_u */
2667   { CODE_FOR_insn_minih,                NULL }, /* minih */
2668   { CODE_FOR_insn_mm,                   NULL }, /* mm */
2669   { CODE_FOR_insn_mnz,                  NULL }, /* mnz */
2670   { CODE_FOR_insn_mnzb,                 NULL }, /* mnzb */
2671   { CODE_FOR_insn_mnzh,                 NULL }, /* mnzh */
2672   { CODE_FOR_movsi,                     NULL }, /* move */
2673   { CODE_FOR_insn_movelis,              NULL }, /* movelis */
2674   { CODE_FOR_insn_mtspr,                NULL }, /* mtspr */
2675   { CODE_FOR_insn_mulhh_ss,             NULL }, /* mulhh_ss */
2676   { CODE_FOR_insn_mulhh_su,             NULL }, /* mulhh_su */
2677   { CODE_FOR_insn_mulhh_uu,             NULL }, /* mulhh_uu */
2678   { CODE_FOR_insn_mulhha_ss,            NULL }, /* mulhha_ss */
2679   { CODE_FOR_insn_mulhha_su,            NULL }, /* mulhha_su */
2680   { CODE_FOR_insn_mulhha_uu,            NULL }, /* mulhha_uu */
2681   { CODE_FOR_insn_mulhhsa_uu,           NULL }, /* mulhhsa_uu */
2682   { CODE_FOR_insn_mulhl_ss,             NULL }, /* mulhl_ss */
2683   { CODE_FOR_insn_mulhl_su,             NULL }, /* mulhl_su */
2684   { CODE_FOR_insn_mulhl_us,             NULL }, /* mulhl_us */
2685   { CODE_FOR_insn_mulhl_uu,             NULL }, /* mulhl_uu */
2686   { CODE_FOR_insn_mulhla_ss,            NULL }, /* mulhla_ss */
2687   { CODE_FOR_insn_mulhla_su,            NULL }, /* mulhla_su */
2688   { CODE_FOR_insn_mulhla_us,            NULL }, /* mulhla_us */
2689   { CODE_FOR_insn_mulhla_uu,            NULL }, /* mulhla_uu */
2690   { CODE_FOR_insn_mulhlsa_uu,           NULL }, /* mulhlsa_uu */
2691   { CODE_FOR_insn_mulll_ss,             NULL }, /* mulll_ss */
2692   { CODE_FOR_insn_mulll_su,             NULL }, /* mulll_su */
2693   { CODE_FOR_insn_mulll_uu,             NULL }, /* mulll_uu */
2694   { CODE_FOR_insn_mullla_ss,            NULL }, /* mullla_ss */
2695   { CODE_FOR_insn_mullla_su,            NULL }, /* mullla_su */
2696   { CODE_FOR_insn_mullla_uu,            NULL }, /* mullla_uu */
2697   { CODE_FOR_insn_mulllsa_uu,           NULL }, /* mulllsa_uu */
2698   { CODE_FOR_insn_mvnz,                 NULL }, /* mvnz */
2699   { CODE_FOR_insn_mvz,                  NULL }, /* mvz */
2700   { CODE_FOR_insn_mz,                   NULL }, /* mz */
2701   { CODE_FOR_insn_mzb,                  NULL }, /* mzb */
2702   { CODE_FOR_insn_mzh,                  NULL }, /* mzh */
2703   { CODE_FOR_insn_nap,                  NULL }, /* nap */
2704   { CODE_FOR_nop,                       NULL }, /* nop */
2705   { CODE_FOR_insn_nor,                  NULL }, /* nor */
2706   { CODE_FOR_iorsi3,                    NULL }, /* or */
2707   { CODE_FOR_insn_packbs_u,             NULL }, /* packbs_u */
2708   { CODE_FOR_insn_packhb,               NULL }, /* packhb */
2709   { CODE_FOR_insn_packhs,               NULL }, /* packhs */
2710   { CODE_FOR_insn_packlb,               NULL }, /* packlb */
2711   { CODE_FOR_popcountsi2,               NULL }, /* pcnt */
2712   { CODE_FOR_insn_prefetch,             NULL }, /* prefetch */
2713   { CODE_FOR_insn_prefetch_L1,          NULL }, /* prefetch_L1 */
2714   { CODE_FOR_rotlsi3,                   NULL }, /* rl */
2715   { CODE_FOR_insn_s1a,                  NULL }, /* s1a */
2716   { CODE_FOR_insn_s2a,                  NULL }, /* s2a */
2717   { CODE_FOR_insn_s3a,                  NULL }, /* s3a */
2718   { CODE_FOR_insn_sadab_u,              NULL }, /* sadab_u */
2719   { CODE_FOR_insn_sadah,                NULL }, /* sadah */
2720   { CODE_FOR_insn_sadah_u,              NULL }, /* sadah_u */
2721   { CODE_FOR_insn_sadb_u,               NULL }, /* sadb_u */
2722   { CODE_FOR_insn_sadh,                 NULL }, /* sadh */
2723   { CODE_FOR_insn_sadh_u,               NULL }, /* sadh_u */
2724   { CODE_FOR_insn_sb,                   NULL }, /* sb */
2725   { CODE_FOR_insn_seq,                  NULL }, /* seq */
2726   { CODE_FOR_insn_seqb,                 NULL }, /* seqb */
2727   { CODE_FOR_insn_seqh,                 NULL }, /* seqh */
2728   { CODE_FOR_insn_seqib,                NULL }, /* seqib */
2729   { CODE_FOR_insn_seqih,                NULL }, /* seqih */
2730   { CODE_FOR_insn_sh,                   NULL }, /* sh */
2731   { CODE_FOR_ashlsi3,                   NULL }, /* shl */
2732   { CODE_FOR_insn_shlb,                 NULL }, /* shlb */
2733   { CODE_FOR_insn_shlh,                 NULL }, /* shlh */
2734   { CODE_FOR_insn_shlb,                 NULL }, /* shlib */
2735   { CODE_FOR_insn_shlh,                 NULL }, /* shlih */
2736   { CODE_FOR_lshrsi3,                   NULL }, /* shr */
2737   { CODE_FOR_insn_shrb,                 NULL }, /* shrb */
2738   { CODE_FOR_insn_shrh,                 NULL }, /* shrh */
2739   { CODE_FOR_insn_shrb,                 NULL }, /* shrib */
2740   { CODE_FOR_insn_shrh,                 NULL }, /* shrih */
2741   { CODE_FOR_insn_slt,                  NULL }, /* slt */
2742   { CODE_FOR_insn_slt_u,                NULL }, /* slt_u */
2743   { CODE_FOR_insn_sltb,                 NULL }, /* sltb */
2744   { CODE_FOR_insn_sltb_u,               NULL }, /* sltb_u */
2745   { CODE_FOR_insn_slte,                 NULL }, /* slte */
2746   { CODE_FOR_insn_slte_u,               NULL }, /* slte_u */
2747   { CODE_FOR_insn_slteb,                NULL }, /* slteb */
2748   { CODE_FOR_insn_slteb_u,              NULL }, /* slteb_u */
2749   { CODE_FOR_insn_slteh,                NULL }, /* slteh */
2750   { CODE_FOR_insn_slteh_u,              NULL }, /* slteh_u */
2751   { CODE_FOR_insn_slth,                 NULL }, /* slth */
2752   { CODE_FOR_insn_slth_u,               NULL }, /* slth_u */
2753   { CODE_FOR_insn_sltib,                NULL }, /* sltib */
2754   { CODE_FOR_insn_sltib_u,              NULL }, /* sltib_u */
2755   { CODE_FOR_insn_sltih,                NULL }, /* sltih */
2756   { CODE_FOR_insn_sltih_u,              NULL }, /* sltih_u */
2757   { CODE_FOR_insn_sne,                  NULL }, /* sne */
2758   { CODE_FOR_insn_sneb,                 NULL }, /* sneb */
2759   { CODE_FOR_insn_sneh,                 NULL }, /* sneh */
2760   { CODE_FOR_ashrsi3,                   NULL }, /* sra */
2761   { CODE_FOR_insn_srab,                 NULL }, /* srab */
2762   { CODE_FOR_insn_srah,                 NULL }, /* srah */
2763   { CODE_FOR_insn_srab,                 NULL }, /* sraib */
2764   { CODE_FOR_insn_srah,                 NULL }, /* sraih */
2765   { CODE_FOR_subsi3,                    NULL }, /* sub */
2766   { CODE_FOR_insn_subb,                 NULL }, /* subb */
2767   { CODE_FOR_insn_subbs_u,              NULL }, /* subbs_u */
2768   { CODE_FOR_insn_subh,                 NULL }, /* subh */
2769   { CODE_FOR_insn_subhs,                NULL }, /* subhs */
2770   { CODE_FOR_sssubsi3,                  NULL }, /* subs */
2771   { CODE_FOR_insn_sw,                   NULL }, /* sw */
2772   { CODE_FOR_insn_tblidxb0,             NULL }, /* tblidxb0 */
2773   { CODE_FOR_insn_tblidxb1,             NULL }, /* tblidxb1 */
2774   { CODE_FOR_insn_tblidxb2,             NULL }, /* tblidxb2 */
2775   { CODE_FOR_insn_tblidxb3,             NULL }, /* tblidxb3 */
2776   { CODE_FOR_insn_tns,                  NULL }, /* tns */
2777   { CODE_FOR_insn_wh64,                 NULL }, /* wh64 */
2778   { CODE_FOR_xorsi3,                    NULL }, /* xor */
2779   { CODE_FOR_tilepro_network_barrier,   NULL }, /* network_barrier */
2780   { CODE_FOR_tilepro_idn0_receive,      NULL }, /* idn0_receive */
2781   { CODE_FOR_tilepro_idn1_receive,      NULL }, /* idn1_receive */
2782   { CODE_FOR_tilepro_idn_send,          NULL }, /* idn_send */
2783   { CODE_FOR_tilepro_sn_receive,        NULL }, /* sn_receive */
2784   { CODE_FOR_tilepro_sn_send,           NULL }, /* sn_send */
2785   { CODE_FOR_tilepro_udn0_receive,      NULL }, /* udn0_receive */
2786   { CODE_FOR_tilepro_udn1_receive,      NULL }, /* udn1_receive */
2787   { CODE_FOR_tilepro_udn2_receive,      NULL }, /* udn2_receive */
2788   { CODE_FOR_tilepro_udn3_receive,      NULL }, /* udn3_receive */
2789   { CODE_FOR_tilepro_udn_send,          NULL }, /* udn_send */
2790 };
2791 
2792 
2793 struct tilepro_builtin_def
2794 {
2795   const char *name;
2796   enum tilepro_builtin code;
2797   bool is_const;
2798   /* The first character is the return type.  Subsequent characters
2799      are the argument types. See char_to_type.  */
2800   const char *type;
2801 };
2802 
2803 
2804 static const struct tilepro_builtin_def tilepro_builtins[] = {
2805   { "__insn_add",             TILEPRO_INSN_ADD,         true,  "lll"   },
2806   { "__insn_addb",            TILEPRO_INSN_ADDB,        true,  "lll"   },
2807   { "__insn_addbs_u",         TILEPRO_INSN_ADDBS_U,     false, "lll"   },
2808   { "__insn_addh",            TILEPRO_INSN_ADDH,        true,  "lll"   },
2809   { "__insn_addhs",           TILEPRO_INSN_ADDHS,       false, "lll"   },
2810   { "__insn_addi",            TILEPRO_INSN_ADD,         true,  "lll"   },
2811   { "__insn_addib",           TILEPRO_INSN_ADDIB,       true,  "lll"   },
2812   { "__insn_addih",           TILEPRO_INSN_ADDIH,       true,  "lll"   },
2813   { "__insn_addli",           TILEPRO_INSN_ADD,         true,  "lll"   },
2814   { "__insn_addlis",          TILEPRO_INSN_ADDLIS,      false, "lll"   },
2815   { "__insn_adds",            TILEPRO_INSN_ADDS,        false, "lll"   },
2816   { "__insn_adiffb_u",        TILEPRO_INSN_ADIFFB_U,    true,  "lll"   },
2817   { "__insn_adiffh",          TILEPRO_INSN_ADIFFH,      true,  "lll"   },
2818   { "__insn_and",             TILEPRO_INSN_AND,         true,  "lll"   },
2819   { "__insn_andi",            TILEPRO_INSN_AND,         true,  "lll"   },
2820   { "__insn_auli",            TILEPRO_INSN_AULI,        true,  "lll"   },
2821   { "__insn_avgb_u",          TILEPRO_INSN_AVGB_U,      true,  "lll"   },
2822   { "__insn_avgh",            TILEPRO_INSN_AVGH,        true,  "lll"   },
2823   { "__insn_bitx",            TILEPRO_INSN_BITX,        true,  "ll"    },
2824   { "__insn_bytex",           TILEPRO_INSN_BYTEX,       true,  "ll"    },
2825   { "__insn_clz",             TILEPRO_INSN_CLZ,         true,  "ll"    },
2826   { "__insn_crc32_32",        TILEPRO_INSN_CRC32_32,    true,  "lll"   },
2827   { "__insn_crc32_8",         TILEPRO_INSN_CRC32_8,     true,  "lll"   },
2828   { "__insn_ctz",             TILEPRO_INSN_CTZ,         true,  "ll"    },
2829   { "__insn_drain",           TILEPRO_INSN_DRAIN,       false, "v"     },
2830   { "__insn_dtlbpr",          TILEPRO_INSN_DTLBPR,      false, "vl"    },
2831   { "__insn_dword_align",     TILEPRO_INSN_DWORD_ALIGN, true,  "lllk"  },
2832   { "__insn_finv",            TILEPRO_INSN_FINV,        false, "vk"    },
2833   { "__insn_flush",           TILEPRO_INSN_FLUSH,       false, "vk"    },
2834   { "__insn_fnop",            TILEPRO_INSN_FNOP,        false, "v"     },
2835   { "__insn_icoh",            TILEPRO_INSN_ICOH,        false, "vk"    },
2836   { "__insn_ill",             TILEPRO_INSN_ILL,         false, "v"     },
2837   { "__insn_info",            TILEPRO_INSN_INFO,        false, "vl"    },
2838   { "__insn_infol",           TILEPRO_INSN_INFOL,       false, "vl"    },
2839   { "__insn_inthb",           TILEPRO_INSN_INTHB,       true,  "lll"   },
2840   { "__insn_inthh",           TILEPRO_INSN_INTHH,       true,  "lll"   },
2841   { "__insn_intlb",           TILEPRO_INSN_INTLB,       true,  "lll"   },
2842   { "__insn_intlh",           TILEPRO_INSN_INTLH,       true,  "lll"   },
2843   { "__insn_inv",             TILEPRO_INSN_INV,         false, "vp"    },
2844   { "__insn_lb",              TILEPRO_INSN_LB,          false, "lk"    },
2845   { "__insn_lb_u",            TILEPRO_INSN_LB_U,        false, "lk"    },
2846   { "__insn_lh",              TILEPRO_INSN_LH,          false, "lk"    },
2847   { "__insn_lh_u",            TILEPRO_INSN_LH_U,        false, "lk"    },
2848   { "__insn_lnk",             TILEPRO_INSN_LNK,         true,  "l"     },
2849   { "__insn_lw",              TILEPRO_INSN_LW,          false, "lk"    },
2850   { "__insn_lw_na",           TILEPRO_INSN_LW_NA,       false, "lk"    },
2851   { "__insn_lb_L2",           TILEPRO_INSN_LB_L2,       false, "lk"    },
2852   { "__insn_lb_u_L2",         TILEPRO_INSN_LB_U_L2,     false, "lk"    },
2853   { "__insn_lh_L2",           TILEPRO_INSN_LH_L2,       false, "lk"    },
2854   { "__insn_lh_u_L2",         TILEPRO_INSN_LH_U_L2,     false, "lk"    },
2855   { "__insn_lw_L2",           TILEPRO_INSN_LW_L2,       false, "lk"    },
2856   { "__insn_lw_na_L2",        TILEPRO_INSN_LW_NA_L2,    false, "lk"    },
2857   { "__insn_lb_miss",         TILEPRO_INSN_LB_MISS,     false, "lk"    },
2858   { "__insn_lb_u_miss",       TILEPRO_INSN_LB_U_MISS,   false, "lk"    },
2859   { "__insn_lh_miss",         TILEPRO_INSN_LH_MISS,     false, "lk"    },
2860   { "__insn_lh_u_miss",       TILEPRO_INSN_LH_U_MISS,   false, "lk"    },
2861   { "__insn_lw_miss",         TILEPRO_INSN_LW_MISS,     false, "lk"    },
2862   { "__insn_lw_na_miss",      TILEPRO_INSN_LW_NA_MISS,  false, "lk"    },
2863   { "__insn_maxb_u",          TILEPRO_INSN_MAXB_U,      true,  "lll"   },
2864   { "__insn_maxh",            TILEPRO_INSN_MAXH,        true,  "lll"   },
2865   { "__insn_maxib_u",         TILEPRO_INSN_MAXIB_U,     true,  "lll"   },
2866   { "__insn_maxih",           TILEPRO_INSN_MAXIH,       true,  "lll"   },
2867   { "__insn_mf",              TILEPRO_INSN_MF,          false, "v"     },
2868   { "__insn_mfspr",           TILEPRO_INSN_MFSPR,       false, "ll"    },
2869   { "__insn_minb_u",          TILEPRO_INSN_MINB_U,      true,  "lll"   },
2870   { "__insn_minh",            TILEPRO_INSN_MINH,        true,  "lll"   },
2871   { "__insn_minib_u",         TILEPRO_INSN_MINIB_U,     true,  "lll"   },
2872   { "__insn_minih",           TILEPRO_INSN_MINIH,       true,  "lll"   },
2873   { "__insn_mm",              TILEPRO_INSN_MM,          true,  "lllll" },
2874   { "__insn_mnz",             TILEPRO_INSN_MNZ,         true,  "lll"   },
2875   { "__insn_mnzb",            TILEPRO_INSN_MNZB,        true,  "lll"   },
2876   { "__insn_mnzh",            TILEPRO_INSN_MNZH,        true,  "lll"   },
2877   { "__insn_move",            TILEPRO_INSN_MOVE,        true,  "ll"    },
2878   { "__insn_movei",           TILEPRO_INSN_MOVE,        true,  "ll"    },
2879   { "__insn_moveli",          TILEPRO_INSN_MOVE,        true,  "ll"    },
2880   { "__insn_movelis",         TILEPRO_INSN_MOVELIS,     false, "ll"    },
2881   { "__insn_mtspr",           TILEPRO_INSN_MTSPR,       false, "vll"   },
2882   { "__insn_mulhh_ss",        TILEPRO_INSN_MULHH_SS,    true,  "lll"   },
2883   { "__insn_mulhh_su",        TILEPRO_INSN_MULHH_SU,    true,  "lll"   },
2884   { "__insn_mulhh_uu",        TILEPRO_INSN_MULHH_UU,    true,  "lll"   },
2885   { "__insn_mulhha_ss",       TILEPRO_INSN_MULHHA_SS,   true,  "llll"  },
2886   { "__insn_mulhha_su",       TILEPRO_INSN_MULHHA_SU,   true,  "llll"  },
2887   { "__insn_mulhha_uu",       TILEPRO_INSN_MULHHA_UU,   true,  "llll"  },
2888   { "__insn_mulhhsa_uu",      TILEPRO_INSN_MULHHSA_UU,  true,  "llll"  },
2889   { "__insn_mulhl_ss",        TILEPRO_INSN_MULHL_SS,    true,  "lll"   },
2890   { "__insn_mulhl_su",        TILEPRO_INSN_MULHL_SU,    true,  "lll"   },
2891   { "__insn_mulhl_us",        TILEPRO_INSN_MULHL_US,    true,  "lll"   },
2892   { "__insn_mulhl_uu",        TILEPRO_INSN_MULHL_UU,    true,  "lll"   },
2893   { "__insn_mulhla_ss",       TILEPRO_INSN_MULHLA_SS,   true,  "llll"  },
2894   { "__insn_mulhla_su",       TILEPRO_INSN_MULHLA_SU,   true,  "llll"  },
2895   { "__insn_mulhla_us",       TILEPRO_INSN_MULHLA_US,   true,  "llll"  },
2896   { "__insn_mulhla_uu",       TILEPRO_INSN_MULHLA_UU,   true,  "llll"  },
2897   { "__insn_mulhlsa_uu",      TILEPRO_INSN_MULHLSA_UU,  true,  "llll"  },
2898   { "__insn_mulll_ss",        TILEPRO_INSN_MULLL_SS,    true,  "lll"   },
2899   { "__insn_mulll_su",        TILEPRO_INSN_MULLL_SU,    true,  "lll"   },
2900   { "__insn_mulll_uu",        TILEPRO_INSN_MULLL_UU,    true,  "lll"   },
2901   { "__insn_mullla_ss",       TILEPRO_INSN_MULLLA_SS,   true,  "llll"  },
2902   { "__insn_mullla_su",       TILEPRO_INSN_MULLLA_SU,   true,  "llll"  },
2903   { "__insn_mullla_uu",       TILEPRO_INSN_MULLLA_UU,   true,  "llll"  },
2904   { "__insn_mulllsa_uu",      TILEPRO_INSN_MULLLSA_UU,  true,  "llll"  },
2905   { "__insn_mvnz",            TILEPRO_INSN_MVNZ,        true,  "llll"  },
2906   { "__insn_mvz",             TILEPRO_INSN_MVZ,         true,  "llll"  },
2907   { "__insn_mz",              TILEPRO_INSN_MZ,          true,  "lll"   },
2908   { "__insn_mzb",             TILEPRO_INSN_MZB,         true,  "lll"   },
2909   { "__insn_mzh",             TILEPRO_INSN_MZH,         true,  "lll"   },
2910   { "__insn_nap",             TILEPRO_INSN_NAP,         false, "v"     },
2911   { "__insn_nop",             TILEPRO_INSN_NOP,         true,  "v"     },
2912   { "__insn_nor",             TILEPRO_INSN_NOR,         true,  "lll"   },
2913   { "__insn_or",              TILEPRO_INSN_OR,          true,  "lll"   },
2914   { "__insn_ori",             TILEPRO_INSN_OR,          true,  "lll"   },
2915   { "__insn_packbs_u",        TILEPRO_INSN_PACKBS_U,    false, "lll"   },
2916   { "__insn_packhb",          TILEPRO_INSN_PACKHB,      true,  "lll"   },
2917   { "__insn_packhs",          TILEPRO_INSN_PACKHS,      false, "lll"   },
2918   { "__insn_packlb",          TILEPRO_INSN_PACKLB,      true,  "lll"   },
2919   { "__insn_pcnt",            TILEPRO_INSN_PCNT,        true,  "ll"    },
2920   { "__insn_prefetch",        TILEPRO_INSN_PREFETCH,    false, "vk"    },
2921   { "__insn_prefetch_L1",     TILEPRO_INSN_PREFETCH_L1, false, "vk"    },
2922   { "__insn_rl",              TILEPRO_INSN_RL,          true,  "lll"   },
2923   { "__insn_rli",             TILEPRO_INSN_RL,          true,  "lll"   },
2924   { "__insn_s1a",             TILEPRO_INSN_S1A,         true,  "lll"   },
2925   { "__insn_s2a",             TILEPRO_INSN_S2A,         true,  "lll"   },
2926   { "__insn_s3a",             TILEPRO_INSN_S3A,         true,  "lll"   },
2927   { "__insn_sadab_u",         TILEPRO_INSN_SADAB_U,     true,  "llll"  },
2928   { "__insn_sadah",           TILEPRO_INSN_SADAH,       true,  "llll"  },
2929   { "__insn_sadah_u",         TILEPRO_INSN_SADAH_U,     true,  "llll"  },
2930   { "__insn_sadb_u",          TILEPRO_INSN_SADB_U,      true,  "lll"   },
2931   { "__insn_sadh",            TILEPRO_INSN_SADH,        true,  "lll"   },
2932   { "__insn_sadh_u",          TILEPRO_INSN_SADH_U,      true,  "lll"   },
2933   { "__insn_sb",              TILEPRO_INSN_SB,          false, "vpl"   },
2934   { "__insn_seq",             TILEPRO_INSN_SEQ,         true,  "lll"   },
2935   { "__insn_seqb",            TILEPRO_INSN_SEQB,        true,  "lll"   },
2936   { "__insn_seqh",            TILEPRO_INSN_SEQH,        true,  "lll"   },
2937   { "__insn_seqi",            TILEPRO_INSN_SEQ,         true,  "lll"   },
2938   { "__insn_seqib",           TILEPRO_INSN_SEQIB,       true,  "lll"   },
2939   { "__insn_seqih",           TILEPRO_INSN_SEQIH,       true,  "lll"   },
2940   { "__insn_sh",              TILEPRO_INSN_SH,          false, "vpl"   },
2941   { "__insn_shl",             TILEPRO_INSN_SHL,         true,  "lll"   },
2942   { "__insn_shlb",            TILEPRO_INSN_SHLB,        true,  "lll"   },
2943   { "__insn_shlh",            TILEPRO_INSN_SHLH,        true,  "lll"   },
2944   { "__insn_shli",            TILEPRO_INSN_SHL,         true,  "lll"   },
2945   { "__insn_shlib",           TILEPRO_INSN_SHLIB,       true,  "lll"   },
2946   { "__insn_shlih",           TILEPRO_INSN_SHLIH,       true,  "lll"   },
2947   { "__insn_shr",             TILEPRO_INSN_SHR,         true,  "lll"   },
2948   { "__insn_shrb",            TILEPRO_INSN_SHRB,        true,  "lll"   },
2949   { "__insn_shrh",            TILEPRO_INSN_SHRH,        true,  "lll"   },
2950   { "__insn_shri",            TILEPRO_INSN_SHR,         true,  "lll"   },
2951   { "__insn_shrib",           TILEPRO_INSN_SHRIB,       true,  "lll"   },
2952   { "__insn_shrih",           TILEPRO_INSN_SHRIH,       true,  "lll"   },
2953   { "__insn_slt",             TILEPRO_INSN_SLT,         true,  "lll"   },
2954   { "__insn_slt_u",           TILEPRO_INSN_SLT_U,       true,  "lll"   },
2955   { "__insn_sltb",            TILEPRO_INSN_SLTB,        true,  "lll"   },
2956   { "__insn_sltb_u",          TILEPRO_INSN_SLTB_U,      true,  "lll"   },
2957   { "__insn_slte",            TILEPRO_INSN_SLTE,        true,  "lll"   },
2958   { "__insn_slte_u",          TILEPRO_INSN_SLTE_U,      true,  "lll"   },
2959   { "__insn_slteb",           TILEPRO_INSN_SLTEB,       true,  "lll"   },
2960   { "__insn_slteb_u",         TILEPRO_INSN_SLTEB_U,     true,  "lll"   },
2961   { "__insn_slteh",           TILEPRO_INSN_SLTEH,       true,  "lll"   },
2962   { "__insn_slteh_u",         TILEPRO_INSN_SLTEH_U,     true,  "lll"   },
2963   { "__insn_slth",            TILEPRO_INSN_SLTH,        true,  "lll"   },
2964   { "__insn_slth_u",          TILEPRO_INSN_SLTH_U,      true,  "lll"   },
2965   { "__insn_slti",            TILEPRO_INSN_SLT,         true,  "lll"   },
2966   { "__insn_slti_u",          TILEPRO_INSN_SLT_U,       true,  "lll"   },
2967   { "__insn_sltib",           TILEPRO_INSN_SLTIB,       true,  "lll"   },
2968   { "__insn_sltib_u",         TILEPRO_INSN_SLTIB_U,     true,  "lll"   },
2969   { "__insn_sltih",           TILEPRO_INSN_SLTIH,       true,  "lll"   },
2970   { "__insn_sltih_u",         TILEPRO_INSN_SLTIH_U,     true,  "lll"   },
2971   { "__insn_sne",             TILEPRO_INSN_SNE,         true,  "lll"   },
2972   { "__insn_sneb",            TILEPRO_INSN_SNEB,        true,  "lll"   },
2973   { "__insn_sneh",            TILEPRO_INSN_SNEH,        true,  "lll"   },
2974   { "__insn_sra",             TILEPRO_INSN_SRA,         true,  "lll"   },
2975   { "__insn_srab",            TILEPRO_INSN_SRAB,        true,  "lll"   },
2976   { "__insn_srah",            TILEPRO_INSN_SRAH,        true,  "lll"   },
2977   { "__insn_srai",            TILEPRO_INSN_SRA,         true,  "lll"   },
2978   { "__insn_sraib",           TILEPRO_INSN_SRAIB,       true,  "lll"   },
2979   { "__insn_sraih",           TILEPRO_INSN_SRAIH,       true,  "lll"   },
2980   { "__insn_sub",             TILEPRO_INSN_SUB,         true,  "lll"   },
2981   { "__insn_subb",            TILEPRO_INSN_SUBB,        true,  "lll"   },
2982   { "__insn_subbs_u",         TILEPRO_INSN_SUBBS_U,     false, "lll"   },
2983   { "__insn_subh",            TILEPRO_INSN_SUBH,        true,  "lll"   },
2984   { "__insn_subhs",           TILEPRO_INSN_SUBHS,       false, "lll"   },
2985   { "__insn_subs",            TILEPRO_INSN_SUBS,        false, "lll"   },
2986   { "__insn_sw",              TILEPRO_INSN_SW,          false, "vpl"   },
2987   { "__insn_tblidxb0",        TILEPRO_INSN_TBLIDXB0,    true,  "lll"   },
2988   { "__insn_tblidxb1",        TILEPRO_INSN_TBLIDXB1,    true,  "lll"   },
2989   { "__insn_tblidxb2",        TILEPRO_INSN_TBLIDXB2,    true,  "lll"   },
2990   { "__insn_tblidxb3",        TILEPRO_INSN_TBLIDXB3,    true,  "lll"   },
2991   { "__insn_tns",             TILEPRO_INSN_TNS,         false, "lp"    },
2992   { "__insn_wh64",            TILEPRO_INSN_WH64,        false, "vp"    },
2993   { "__insn_xor",             TILEPRO_INSN_XOR,         true,  "lll"   },
2994   { "__insn_xori",            TILEPRO_INSN_XOR,         true,  "lll"   },
2995   { "__tile_network_barrier", TILEPRO_NETWORK_BARRIER,  false, "v"     },
2996   { "__tile_idn0_receive",    TILEPRO_IDN0_RECEIVE,     false, "l"     },
2997   { "__tile_idn1_receive",    TILEPRO_IDN1_RECEIVE,     false, "l"     },
2998   { "__tile_idn_send",        TILEPRO_IDN_SEND,         false, "vl"    },
2999   { "__tile_sn_receive",      TILEPRO_SN_RECEIVE,       false, "l"     },
3000   { "__tile_sn_send",         TILEPRO_SN_SEND,          false, "vl"    },
3001   { "__tile_udn0_receive",    TILEPRO_UDN0_RECEIVE,     false, "l"     },
3002   { "__tile_udn1_receive",    TILEPRO_UDN1_RECEIVE,     false, "l"     },
3003   { "__tile_udn2_receive",    TILEPRO_UDN2_RECEIVE,     false, "l"     },
3004   { "__tile_udn3_receive",    TILEPRO_UDN3_RECEIVE,     false, "l"     },
3005   { "__tile_udn_send",        TILEPRO_UDN_SEND,         false, "vl"    },
3006 };
3007 
3008 
3009 /* Convert a character in a builtin type string to a tree type.  */
3010 static tree
char_to_type(char c)3011 char_to_type (char c)
3012 {
3013   static tree volatile_ptr_type_node = NULL;
3014   static tree volatile_const_ptr_type_node = NULL;
3015 
3016   if (volatile_ptr_type_node == NULL)
3017     {
3018       volatile_ptr_type_node =
3019 	build_pointer_type (build_qualified_type (void_type_node,
3020 						  TYPE_QUAL_VOLATILE));
3021       volatile_const_ptr_type_node =
3022 	build_pointer_type (build_qualified_type (void_type_node,
3023 						  TYPE_QUAL_CONST
3024 						  | TYPE_QUAL_VOLATILE));
3025     }
3026 
3027   switch (c)
3028     {
3029     case 'v':
3030       return void_type_node;
3031     case 'l':
3032       return long_unsigned_type_node;
3033     case 'p':
3034       return volatile_ptr_type_node;
3035     case 'k':
3036       return volatile_const_ptr_type_node;
3037     default:
3038       gcc_unreachable ();
3039     }
3040 }
3041 
3042 
3043 /* Implement TARGET_INIT_BUILTINS.  */
3044 static void
tilepro_init_builtins(void)3045 tilepro_init_builtins (void)
3046 {
3047   size_t i;
3048 
3049   for (i = 0; i < ARRAY_SIZE (tilepro_builtins); i++)
3050     {
3051       const struct tilepro_builtin_def *p = &tilepro_builtins[i];
3052       tree ftype, ret_type, arg_type_list = void_list_node;
3053       tree decl;
3054       int j;
3055 
3056       for (j = strlen (p->type) - 1; j > 0; j--)
3057 	{
3058 	  arg_type_list =
3059 	    tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list);
3060 	}
3061 
3062       ret_type = char_to_type (p->type[0]);
3063 
3064       ftype = build_function_type (ret_type, arg_type_list);
3065 
3066       decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
3067 				   NULL, NULL);
3068 
3069       if (p->is_const)
3070 	TREE_READONLY (decl) = 1;
3071       TREE_NOTHROW (decl) = 1;
3072 
3073       if (tilepro_builtin_info[p->code].fndecl == NULL)
3074 	tilepro_builtin_info[p->code].fndecl = decl;
3075     }
3076 }
3077 
3078 
3079 /* Implement TARGET_EXPAND_BUILTIN.  */
3080 static rtx
tilepro_expand_builtin(tree exp,rtx target,rtx subtarget ATTRIBUTE_UNUSED,machine_mode mode ATTRIBUTE_UNUSED,int ignore ATTRIBUTE_UNUSED)3081 tilepro_expand_builtin (tree exp,
3082 			rtx target,
3083 			rtx subtarget ATTRIBUTE_UNUSED,
3084 			machine_mode mode ATTRIBUTE_UNUSED,
3085 			int ignore ATTRIBUTE_UNUSED)
3086 {
3087 #define MAX_BUILTIN_ARGS 4
3088 
3089   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
3090   unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl);
3091   tree arg;
3092   call_expr_arg_iterator iter;
3093   enum insn_code icode;
3094   rtx op[MAX_BUILTIN_ARGS + 1], pat;
3095   int opnum;
3096   bool nonvoid;
3097   insn_gen_fn fn;
3098 
3099   if (fcode >= TILEPRO_BUILTIN_max)
3100     internal_error ("bad builtin fcode");
3101   icode = tilepro_builtin_info[fcode].icode;
3102   if (icode == 0)
3103     internal_error ("bad builtin icode");
3104 
3105   nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
3106 
3107   opnum = nonvoid;
3108   FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
3109   {
3110     const struct insn_operand_data *insn_op;
3111 
3112     if (arg == error_mark_node)
3113       return NULL_RTX;
3114     if (opnum > MAX_BUILTIN_ARGS)
3115       return NULL_RTX;
3116 
3117     insn_op = &insn_data[icode].operand[opnum];
3118 
3119     op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL);
3120 
3121     if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3122       op[opnum] = copy_to_mode_reg (insn_op->mode, op[opnum]);
3123 
3124     if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3125       {
3126 	/* We still failed to meet the predicate even after moving
3127 	   into a register. Assume we needed an immediate.  */
3128 	error_at (EXPR_LOCATION (exp),
3129 		  "operand must be an immediate of the right size");
3130 	return const0_rtx;
3131       }
3132 
3133     opnum++;
3134   }
3135 
3136   if (nonvoid)
3137     {
3138       machine_mode tmode = insn_data[icode].operand[0].mode;
3139       if (!target
3140 	  || GET_MODE (target) != tmode
3141 	  || !(*insn_data[icode].operand[0].predicate) (target, tmode))
3142 	target = gen_reg_rtx (tmode);
3143       op[0] = target;
3144     }
3145 
3146   fn = GEN_FCN (icode);
3147   switch (opnum)
3148     {
3149     case 0:
3150       pat = fn (NULL_RTX);
3151       break;
3152     case 1:
3153       pat = fn (op[0]);
3154       break;
3155     case 2:
3156       pat = fn (op[0], op[1]);
3157       break;
3158     case 3:
3159       pat = fn (op[0], op[1], op[2]);
3160       break;
3161     case 4:
3162       pat = fn (op[0], op[1], op[2], op[3]);
3163       break;
3164     case 5:
3165       pat = fn (op[0], op[1], op[2], op[3], op[4]);
3166       break;
3167     default:
3168       gcc_unreachable ();
3169     }
3170   if (!pat)
3171     return NULL_RTX;
3172 
3173   /* If we are generating a prefetch, tell the scheduler not to move
3174      it around.  */
3175   if (GET_CODE (pat) == PREFETCH)
3176     PREFETCH_SCHEDULE_BARRIER_P (pat) = true;
3177 
3178   emit_insn (pat);
3179 
3180   if (nonvoid)
3181     return target;
3182   else
3183     return const0_rtx;
3184 }
3185 
3186 
3187 /* Implement TARGET_BUILTIN_DECL.  */
3188 static tree
tilepro_builtin_decl(unsigned code,bool initialize_p ATTRIBUTE_UNUSED)3189 tilepro_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
3190 {
3191   if (code >= TILEPRO_BUILTIN_max)
3192     return error_mark_node;
3193 
3194   return tilepro_builtin_info[code].fndecl;
3195 }
3196 
3197 
3198 
3199 /* Stack frames  */
3200 
3201 /* Return whether REGNO needs to be saved in the stack frame.  */
3202 static bool
need_to_save_reg(unsigned int regno)3203 need_to_save_reg (unsigned int regno)
3204 {
3205   if (!call_used_or_fixed_reg_p (regno)
3206       && df_regs_ever_live_p (regno))
3207     return true;
3208 
3209   if (flag_pic
3210       && (regno == PIC_OFFSET_TABLE_REGNUM
3211 	  || regno == TILEPRO_PIC_TEXT_LABEL_REGNUM)
3212       && (crtl->uses_pic_offset_table || crtl->saves_all_registers))
3213     return true;
3214 
3215   if (crtl->calls_eh_return)
3216     {
3217       unsigned i;
3218       for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++)
3219 	{
3220 	  if (regno == EH_RETURN_DATA_REGNO (i))
3221 	    return true;
3222 	}
3223     }
3224 
3225   return false;
3226 }
3227 
3228 
3229 /* Return the size of the register savev area.  This function is only
3230    correct starting with local register allocation */
3231 static int
tilepro_saved_regs_size(void)3232 tilepro_saved_regs_size (void)
3233 {
3234   int reg_save_size = 0;
3235   int regno;
3236   int offset_to_frame;
3237   int align_mask;
3238 
3239   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3240     if (need_to_save_reg (regno))
3241       reg_save_size += UNITS_PER_WORD;
3242 
3243   /* Pad out the register save area if necessary to make
3244      frame_pointer_rtx be as aligned as the stack pointer.  */
3245   offset_to_frame = crtl->args.pretend_args_size + reg_save_size;
3246   align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1;
3247   reg_save_size += (-offset_to_frame) & align_mask;
3248 
3249   return reg_save_size;
3250 }
3251 
3252 
3253 /* Round up frame size SIZE.  */
3254 static int
round_frame_size(int size)3255 round_frame_size (int size)
3256 {
3257   return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1)
3258 	  & -STACK_BOUNDARY / BITS_PER_UNIT);
3259 }
3260 
3261 
3262 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3263    emit the corresponding REG_CFA_OFFSET note described by CFA and
3264    CFA_OFFSET.  Return the emitted insn.  */
3265 static rtx
frame_emit_store(int regno,int regno_note,rtx addr,rtx cfa,int cfa_offset)3266 frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa,
3267 		  int cfa_offset)
3268 {
3269   rtx reg = gen_rtx_REG (Pmode, regno);
3270   rtx mem = gen_frame_mem (Pmode, addr);
3271   rtx mov = gen_movsi (mem, reg);
3272 
3273   /* Describe what just happened in a way that dwarf understands.  We
3274      use temporary registers to hold the address to make scheduling
3275      easier, and use the REG_CFA_OFFSET to describe the address as an
3276      offset from the CFA.  */
3277   rtx reg_note = gen_rtx_REG (Pmode, regno_note);
3278   rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, gen_int_si (cfa_offset));
3279   rtx cfa_relative_mem = gen_frame_mem (Pmode, cfa_relative_addr);
3280   rtx real = gen_rtx_SET (cfa_relative_mem, reg_note);
3281   add_reg_note (mov, REG_CFA_OFFSET, real);
3282 
3283   return emit_insn (mov);
3284 }
3285 
3286 
3287 /* Emit a load in the stack frame to load REGNO from address ADDR.
3288    Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3289    non-null.  Return the emitted insn.  */
3290 static rtx_insn *
frame_emit_load(int regno,rtx addr,rtx * cfa_restores)3291 frame_emit_load (int regno, rtx addr, rtx *cfa_restores)
3292 {
3293   rtx reg = gen_rtx_REG (Pmode, regno);
3294   rtx mem = gen_frame_mem (Pmode, addr);
3295   if (cfa_restores)
3296     *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores);
3297   return emit_insn (gen_movsi (reg, mem));
3298 }
3299 
3300 
3301 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3302    including sequences.  */
3303 static rtx_insn *
set_frame_related_p(void)3304 set_frame_related_p (void)
3305 {
3306   rtx_insn *seq = get_insns ();
3307   rtx_insn *insn;
3308 
3309   end_sequence ();
3310 
3311   if (!seq)
3312     return NULL;
3313 
3314   if (INSN_P (seq))
3315     {
3316       insn = seq;
3317       while (insn != NULL_RTX)
3318 	{
3319 	  RTX_FRAME_RELATED_P (insn) = 1;
3320 	  insn = NEXT_INSN (insn);
3321 	}
3322       seq = emit_insn (seq);
3323     }
3324   else
3325     {
3326       seq = emit_insn (seq);
3327       RTX_FRAME_RELATED_P (seq) = 1;
3328     }
3329   return seq;
3330 }
3331 
3332 
3333 #define FRP(exp)  (start_sequence (), exp, set_frame_related_p ())
3334 
3335 /* This emits code for 'sp += offset'.
3336 
3337    The ABI only allows us to modify 'sp' in a single 'addi' or
3338    'addli', so the backtracer understands it. Larger amounts cannot
3339    use those instructions, so are added by placing the offset into a
3340    large register and using 'add'.
3341 
3342    This happens after reload, so we need to expand it ourselves.  */
3343 static rtx_insn *
emit_sp_adjust(int offset,int * next_scratch_regno,bool frame_related,rtx reg_notes)3344 emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related,
3345 		rtx reg_notes)
3346 {
3347   rtx to_add;
3348   rtx imm_rtx = gen_int_si (offset);
3349 
3350   rtx_insn *insn;
3351   if (satisfies_constraint_J (imm_rtx))
3352     {
3353       /* We can add this using a single addi or addli.  */
3354       to_add = imm_rtx;
3355     }
3356   else
3357     {
3358       rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3359       tilepro_expand_set_const32 (tmp, imm_rtx);
3360       to_add = tmp;
3361     }
3362 
3363   /* Actually adjust the stack pointer.  */
3364   insn = emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
3365 				   to_add));
3366   REG_NOTES (insn) = reg_notes;
3367 
3368   /* Describe what just happened in a way that dwarf understands.  */
3369   if (frame_related)
3370     {
3371       rtx real = gen_rtx_SET (stack_pointer_rtx,
3372 			      gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3373 					    imm_rtx));
3374       RTX_FRAME_RELATED_P (insn) = 1;
3375       add_reg_note (insn, REG_CFA_ADJUST_CFA, real);
3376     }
3377 
3378   return insn;
3379 }
3380 
3381 
3382 /* Return whether the current function is leaf.  This takes into
3383    account whether the function calls tls_get_addr.  */
3384 static bool
tilepro_current_function_is_leaf(void)3385 tilepro_current_function_is_leaf (void)
3386 {
3387   return crtl->is_leaf && !cfun->machine->calls_tls_get_addr;
3388 }
3389 
3390 
3391 /* Return the frame size.  */
3392 static int
compute_total_frame_size(void)3393 compute_total_frame_size (void)
3394 {
3395   int total_size = (get_frame_size () + tilepro_saved_regs_size ()
3396 		    + crtl->outgoing_args_size
3397 		    + crtl->args.pretend_args_size);
3398 
3399   if (!tilepro_current_function_is_leaf () || cfun->calls_alloca)
3400     {
3401       /* Make room for save area in callee.  */
3402       total_size += STACK_POINTER_OFFSET;
3403     }
3404 
3405   return round_frame_size (total_size);
3406 }
3407 
3408 
3409 /* Return nonzero if this function is known to have a null epilogue.
3410    This allows the optimizer to omit jumps to jumps if no stack was
3411    created.  */
3412 bool
tilepro_can_use_return_insn_p(void)3413 tilepro_can_use_return_insn_p (void)
3414 {
3415   return (reload_completed
3416 	  && cfun->static_chain_decl == 0
3417 	  && compute_total_frame_size () == 0
3418 	  && tilepro_current_function_is_leaf ()
3419 	  && !crtl->profile && !df_regs_ever_live_p (TILEPRO_LINK_REGNUM));
3420 }
3421 
3422 
3423 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'.  If there
3424    is a frame pointer, it computes the value relative to
3425    that. Otherwise it uses the stack pointer.  */
3426 static rtx
compute_frame_addr(int offset_from_fp,int * next_scratch_regno)3427 compute_frame_addr (int offset_from_fp, int *next_scratch_regno)
3428 {
3429   rtx base_reg_rtx, tmp_reg_rtx, offset_rtx;
3430   int offset_from_base;
3431 
3432   if (frame_pointer_needed)
3433     {
3434       base_reg_rtx = hard_frame_pointer_rtx;
3435       offset_from_base = offset_from_fp;
3436     }
3437   else
3438     {
3439       int offset_from_sp = compute_total_frame_size () + offset_from_fp;
3440       base_reg_rtx = stack_pointer_rtx;
3441       offset_from_base = offset_from_sp;
3442     }
3443 
3444   if (offset_from_base == 0)
3445     return base_reg_rtx;
3446 
3447   /* Compute the new value of the stack pointer.  */
3448   tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3449   offset_rtx = gen_int_si (offset_from_base);
3450 
3451   if (!tilepro_expand_addsi (tmp_reg_rtx, base_reg_rtx, offset_rtx))
3452     {
3453       emit_insn (gen_rtx_SET (tmp_reg_rtx,
3454 			      gen_rtx_PLUS (Pmode, base_reg_rtx,
3455 					    offset_rtx)));
3456     }
3457 
3458   return tmp_reg_rtx;
3459 }
3460 
3461 
3462 /* The stack frame looks like this:
3463          +-------------+
3464          |    ...      |
3465          |  incoming   |
3466          | stack args  |
3467    AP -> +-------------+
3468          | caller's HFP|
3469          +-------------+
3470          | lr save     |
3471   HFP -> +-------------+
3472          |  var args   |
3473          |  reg save   | crtl->args.pretend_args_size bytes
3474          +-------------+
3475          |    ...      |
3476          | saved regs  | tilepro_saved_regs_size() bytes
3477    FP -> +-------------+
3478          |    ...      |
3479          |   vars      | get_frame_size() bytes
3480          +-------------+
3481          |    ...      |
3482          |  outgoing   |
3483          |  stack args | crtl->outgoing_args_size bytes
3484          +-------------+
3485          | HFP         | 4 bytes (only here if nonleaf / alloca)
3486          +-------------+
3487          | callee lr   | 4 bytes (only here if nonleaf / alloca)
3488          | save        |
3489    SP -> +-------------+
3490 
3491   HFP == incoming SP.
3492 
3493   For functions with a frame larger than 32767 bytes, or which use
3494   alloca (), r52 is used as a frame pointer.  Otherwise there is no
3495   frame pointer.
3496 
3497   FP is saved at SP+4 before calling a subroutine so the
3498   callee can chain.  */
3499 void
tilepro_expand_prologue(void)3500 tilepro_expand_prologue (void)
3501 {
3502 #define ROUND_ROBIN_SIZE 4
3503   /* We round-robin through four scratch registers to hold temporary
3504      addresses for saving registers, to make instruction scheduling
3505      easier.  */
3506   rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3507     NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3508   };
3509   rtx insn, cfa;
3510   unsigned int which_scratch;
3511   int offset, start_offset, regno;
3512 
3513   /* A register that holds a copy of the incoming fp.  */
3514   int fp_copy_regno = -1;
3515 
3516   /* A register that holds a copy of the incoming sp.  */
3517   int sp_copy_regno = -1;
3518 
3519   /* Next scratch register number to hand out (postdecrementing).  */
3520   int next_scratch_regno = 29;
3521 
3522   int total_size = compute_total_frame_size ();
3523 
3524   if (flag_stack_usage_info)
3525     current_function_static_stack_size = total_size;
3526 
3527   /* Save lr first in its special location because code after this
3528      might use the link register as a scratch register.  */
3529   if (df_regs_ever_live_p (TILEPRO_LINK_REGNUM) || crtl->calls_eh_return)
3530     {
3531       FRP (frame_emit_store (TILEPRO_LINK_REGNUM, TILEPRO_LINK_REGNUM,
3532 			     stack_pointer_rtx, stack_pointer_rtx, 0));
3533       emit_insn (gen_blockage ());
3534     }
3535 
3536   if (total_size == 0)
3537     {
3538       /* Load the PIC register if needed.  */
3539       if (flag_pic && crtl->uses_pic_offset_table)
3540 	load_pic_register (false);
3541 
3542       return;
3543     }
3544 
3545   cfa = stack_pointer_rtx;
3546 
3547   if (frame_pointer_needed)
3548     {
3549       fp_copy_regno = next_scratch_regno--;
3550 
3551       /* Copy the old frame pointer aside so we can save it later.  */
3552       insn = FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno),
3553 				  hard_frame_pointer_rtx));
3554       add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
3555 
3556       /* Set up the frame pointer.  */
3557       insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
3558       add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx);
3559       cfa = hard_frame_pointer_rtx;
3560       REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
3561 
3562       /* fp holds a copy of the incoming sp, in case we need to store
3563          it.  */
3564       sp_copy_regno = HARD_FRAME_POINTER_REGNUM;
3565     }
3566   else if (!tilepro_current_function_is_leaf ())
3567     {
3568       /* Copy the old stack pointer aside so we can save it later.  */
3569       sp_copy_regno = next_scratch_regno--;
3570       emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno),
3571 		      stack_pointer_rtx);
3572     }
3573 
3574   if (tilepro_current_function_is_leaf ())
3575     {
3576       /* No need to store chain pointer to caller's frame.  */
3577       emit_sp_adjust (-total_size, &next_scratch_regno,
3578 		      !frame_pointer_needed, NULL_RTX);
3579     }
3580   else
3581     {
3582       /* Save the frame pointer (incoming sp value) to support
3583          backtracing.  First we need to create an rtx with the store
3584          address.  */
3585       rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--);
3586       rtx size_rtx = gen_int_si (-(total_size - UNITS_PER_WORD));
3587 
3588       if (add_operand (size_rtx, Pmode))
3589 	{
3590 	  /* Expose more parallelism by computing this value from the
3591 	     original stack pointer, not the one after we have pushed
3592 	     the frame.  */
3593 	  rtx p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, size_rtx);
3594 	  emit_insn (gen_rtx_SET (chain_addr, p));
3595 	  emit_sp_adjust (-total_size, &next_scratch_regno,
3596 			  !frame_pointer_needed, NULL_RTX);
3597 	}
3598       else
3599 	{
3600 	  /* The stack frame is large, so just store the incoming sp
3601 	     value at *(new_sp + UNITS_PER_WORD).  */
3602 	  rtx p;
3603 	  emit_sp_adjust (-total_size, &next_scratch_regno,
3604 			  !frame_pointer_needed, NULL_RTX);
3605 	  p = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3606 			    GEN_INT (UNITS_PER_WORD));
3607 	  emit_insn (gen_rtx_SET (chain_addr, p));
3608 	}
3609 
3610       /* Save our frame pointer for backtrace chaining.  */
3611       emit_insn (gen_movsi (gen_frame_mem (SImode, chain_addr),
3612 			    gen_rtx_REG (SImode, sp_copy_regno)));
3613     }
3614 
3615   /* Compute where to start storing registers we need to save.  */
3616   start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
3617   offset = start_offset;
3618 
3619   /* Store all registers that need saving.  */
3620   which_scratch = 0;
3621   for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
3622     if (need_to_save_reg (regno))
3623       {
3624 	rtx r = reg_save_addr[which_scratch];
3625 	int from_regno;
3626 	int cfa_offset = frame_pointer_needed ? offset : total_size + offset;
3627 
3628 	if (r == NULL_RTX)
3629 	  {
3630 	    rtx p = compute_frame_addr (offset, &next_scratch_regno);
3631 	    r = gen_rtx_REG (word_mode, next_scratch_regno--);
3632 	    reg_save_addr[which_scratch] = r;
3633 
3634 	    emit_insn (gen_rtx_SET (r, p));
3635 	  }
3636 	else
3637 	  {
3638 	    /* Advance to the next stack slot to store this register.  */
3639 	    int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
3640 	    rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
3641 	    emit_insn (gen_rtx_SET (r, p));
3642 	  }
3643 
3644 	/* Save this register to the stack (but use the old fp value
3645 	   we copied aside if appropriate).  */
3646 	from_regno = (fp_copy_regno >= 0
3647 		      && regno ==
3648 		      HARD_FRAME_POINTER_REGNUM) ? fp_copy_regno : regno;
3649 	FRP (frame_emit_store (from_regno, regno, r, cfa, cfa_offset));
3650 
3651 	offset -= UNITS_PER_WORD;
3652 	which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
3653       }
3654 
3655   /* If profiling, force that to happen after the frame is set up.  */
3656   if (crtl->profile)
3657     emit_insn (gen_blockage ());
3658 
3659   /* Load the PIC register if needed.  */
3660   if (flag_pic && crtl->uses_pic_offset_table)
3661     load_pic_register (false);
3662 }
3663 
3664 
3665 /* Implement the epilogue and sibcall_epilogue patterns.  SIBCALL_P is
3666    true for a sibcall_epilogue pattern, and false for an epilogue
3667    pattern.  */
3668 void
tilepro_expand_epilogue(bool sibcall_p)3669 tilepro_expand_epilogue (bool sibcall_p)
3670 {
3671   /* We round-robin through four scratch registers to hold temporary
3672      addresses for saving registers, to make instruction scheduling
3673      easier.  */
3674   rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3675     NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3676   };
3677   rtx_insn *last_insn, *insn;
3678   unsigned int which_scratch;
3679   int offset, start_offset, regno;
3680   rtx cfa_restores = NULL_RTX;
3681 
3682   /* A register that holds a copy of the incoming fp.  */
3683   int fp_copy_regno = -1;
3684 
3685   /* Next scratch register number to hand out (postdecrementing).  */
3686   int next_scratch_regno = 29;
3687 
3688   int total_size = compute_total_frame_size ();
3689 
3690   last_insn = get_last_insn ();
3691 
3692   /* Load lr first since we are going to need it first.  */
3693   insn = NULL;
3694   if (df_regs_ever_live_p (TILEPRO_LINK_REGNUM))
3695     {
3696       insn = frame_emit_load (TILEPRO_LINK_REGNUM,
3697 			      compute_frame_addr (0, &next_scratch_regno),
3698 			      &cfa_restores);
3699     }
3700 
3701   if (total_size == 0)
3702     {
3703       if (insn)
3704 	{
3705 	  RTX_FRAME_RELATED_P (insn) = 1;
3706 	  REG_NOTES (insn) = cfa_restores;
3707 	}
3708       goto done;
3709     }
3710 
3711   /* Compute where to start restoring registers.  */
3712   start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
3713   offset = start_offset;
3714 
3715   if (frame_pointer_needed)
3716     fp_copy_regno = next_scratch_regno--;
3717 
3718   /* Restore all callee-saved registers.  */
3719   which_scratch = 0;
3720   for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
3721     if (need_to_save_reg (regno))
3722       {
3723 	rtx r = reg_save_addr[which_scratch];
3724 	if (r == NULL_RTX)
3725 	  {
3726 	    r = compute_frame_addr (offset, &next_scratch_regno);
3727 	    reg_save_addr[which_scratch] = r;
3728 	  }
3729 	else
3730 	  {
3731 	    /* Advance to the next stack slot to store this
3732 	       register.  */
3733 	    int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
3734 	    rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
3735 	    emit_insn (gen_rtx_SET (r, p));
3736 	  }
3737 
3738 	if (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM)
3739 	  frame_emit_load (fp_copy_regno, r, NULL);
3740 	else
3741 	  frame_emit_load (regno, r, &cfa_restores);
3742 
3743 	offset -= UNITS_PER_WORD;
3744 	which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
3745       }
3746 
3747   if (!tilepro_current_function_is_leaf ())
3748     cfa_restores =
3749       alloc_reg_note (REG_CFA_RESTORE, stack_pointer_rtx, cfa_restores);
3750 
3751   emit_insn (gen_blockage ());
3752 
3753   if (frame_pointer_needed)
3754     {
3755       /* Restore the old stack pointer by copying from the frame
3756          pointer.  */
3757       insn = emit_insn (gen_sp_restore (stack_pointer_rtx,
3758 					hard_frame_pointer_rtx));
3759       RTX_FRAME_RELATED_P (insn) = 1;
3760       REG_NOTES (insn) = cfa_restores;
3761       add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx);
3762     }
3763   else
3764     {
3765       insn = emit_sp_adjust (total_size, &next_scratch_regno, true,
3766 			     cfa_restores);
3767     }
3768 
3769   if (crtl->calls_eh_return)
3770     emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
3771 			      EH_RETURN_STACKADJ_RTX));
3772 
3773   /* Restore the old frame pointer.  */
3774   if (frame_pointer_needed)
3775     {
3776       insn = emit_move_insn (hard_frame_pointer_rtx,
3777 			     gen_rtx_REG (Pmode, fp_copy_regno));
3778       add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);
3779     }
3780 
3781   /* Mark the pic registers as live outside of the function.  */
3782   if (flag_pic)
3783     {
3784       emit_use (cfun->machine->text_label_rtx);
3785       emit_use (cfun->machine->got_rtx);
3786     }
3787 
3788 done:
3789   if (!sibcall_p)
3790     {
3791       /* Emit the actual 'return' instruction.  */
3792       emit_jump_insn (gen__return ());
3793     }
3794   else
3795     {
3796       emit_use (gen_rtx_REG (Pmode, TILEPRO_LINK_REGNUM));
3797     }
3798 
3799   /* Mark all insns we just emitted as frame-related.  */
3800   for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn))
3801     RTX_FRAME_RELATED_P (last_insn) = 1;
3802 }
3803 
3804 #undef ROUND_ROBIN_SIZE
3805 
3806 
3807 /* Implement INITIAL_ELIMINATION_OFFSET.  */
3808 int
tilepro_initial_elimination_offset(int from,int to)3809 tilepro_initial_elimination_offset (int from, int to)
3810 {
3811   int total_size = compute_total_frame_size ();
3812 
3813   if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
3814     {
3815       return (total_size - crtl->args.pretend_args_size
3816 	      - tilepro_saved_regs_size ());
3817     }
3818   else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
3819     {
3820       return -(crtl->args.pretend_args_size + tilepro_saved_regs_size ());
3821     }
3822   else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
3823     {
3824       return STACK_POINTER_OFFSET + total_size;
3825     }
3826   else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
3827     {
3828       return STACK_POINTER_OFFSET;
3829     }
3830   else
3831     gcc_unreachable ();
3832 }
3833 
3834 
3835 /* Return an RTX indicating where the return address to the
3836    calling function can be found.  */
3837 rtx
tilepro_return_addr(int count,rtx frame ATTRIBUTE_UNUSED)3838 tilepro_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3839 {
3840   if (count != 0)
3841     return const0_rtx;
3842 
3843   return get_hard_reg_initial_val (Pmode, TILEPRO_LINK_REGNUM);
3844 }
3845 
3846 
3847 /* Implement EH_RETURN_HANDLER_RTX.  */
3848 rtx
tilepro_eh_return_handler_rtx(void)3849 tilepro_eh_return_handler_rtx (void)
3850 {
3851   /* The MEM needs to be volatile to prevent it from being
3852      deleted.  */
3853   rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
3854   MEM_VOLATILE_P (tmp) = true;
3855   return tmp;
3856 }
3857 
3858 
3859 
3860 /* Registers  */
3861 
3862 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE.  */
3863 static void
tilepro_conditional_register_usage(void)3864 tilepro_conditional_register_usage (void)
3865 {
3866   global_regs[TILEPRO_NETORDER_REGNUM] = 1;
3867   /* TILEPRO_PIC_TEXT_LABEL_REGNUM is conditionally used.  */
3868   if (TILEPRO_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM)
3869     fixed_regs[TILEPRO_PIC_TEXT_LABEL_REGNUM] = 1;
3870   if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
3871     fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
3872 }
3873 
3874 
3875 /* Implement TARGET_FRAME_POINTER_REQUIRED.  */
3876 static bool
tilepro_frame_pointer_required(void)3877 tilepro_frame_pointer_required (void)
3878 {
3879   return crtl->calls_eh_return || cfun->calls_alloca;
3880 }
3881 
3882 
3883 
3884 /* Scheduling and reorg  */
3885 
3886 /* Return the length of INSN.  LENGTH is the initial length computed
3887    by attributes in the machine-description file.  This is where we
3888    account for bundles.  */
3889 int
tilepro_adjust_insn_length(rtx_insn * insn,int length)3890 tilepro_adjust_insn_length (rtx_insn *insn, int length)
3891 {
3892   machine_mode mode = GET_MODE (insn);
3893 
3894   /* A non-termininating instruction in a bundle has length 0.  */
3895   if (mode == SImode)
3896     return 0;
3897 
3898   /* By default, there is not length adjustment.  */
3899   return length;
3900 }
3901 
3902 
3903 /* Implement TARGET_SCHED_ISSUE_RATE.  */
3904 static int
tilepro_issue_rate(void)3905 tilepro_issue_rate (void)
3906 {
3907   return 3;
3908 }
3909 
3910 
3911 /* Return the rtx for the jump target.  */
3912 static rtx
get_jump_target(rtx branch)3913 get_jump_target (rtx branch)
3914 {
3915   if (CALL_P (branch))
3916     {
3917       rtx call;
3918       call = PATTERN (branch);
3919 
3920       if (GET_CODE (call) == PARALLEL)
3921 	call = XVECEXP (call, 0, 0);
3922 
3923       if (GET_CODE (call) == SET)
3924 	call = SET_SRC (call);
3925 
3926       if (GET_CODE (call) == CALL)
3927 	return XEXP (XEXP (call, 0), 0);
3928     }
3929   return 0;
3930 }
3931 
3932 /* Implement TARGET_SCHED_ADJUST_COST.  */
3933 static int
tilepro_sched_adjust_cost(rtx_insn * insn,int dep_type,rtx_insn * dep_insn,int cost,unsigned int)3934 tilepro_sched_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn,
3935 			   int cost, unsigned int)
3936 {
3937   /* If we have a true dependence, INSN is a call, and DEP_INSN
3938      defines a register that is needed by the call (argument or stack
3939      pointer), set its latency to 0 so that it can be bundled with
3940      the call.  Explicitly check for and exclude the case when
3941      DEP_INSN defines the target of the jump.  */
3942   if (CALL_P (insn) && dep_type == REG_DEP_TRUE)
3943     {
3944       rtx target = get_jump_target (insn);
3945       if (!REG_P (target) || !set_of (target, dep_insn))
3946 	return 0;
3947     }
3948 
3949   return cost;
3950 }
3951 
3952 
3953 /* Skip over irrelevant NOTEs and such and look for the next insn we
3954    would consider bundling.  */
3955 static rtx_insn *
next_insn_to_bundle(rtx_insn * r,rtx_insn * end)3956 next_insn_to_bundle (rtx_insn *r, rtx_insn *end)
3957 {
3958   for (; r != end; r = NEXT_INSN (r))
3959     {
3960       if (NONDEBUG_INSN_P (r)
3961 	  && GET_CODE (PATTERN (r)) != USE
3962 	  && GET_CODE (PATTERN (r)) != CLOBBER)
3963 	return r;
3964     }
3965 
3966   return NULL;
3967 }
3968 
3969 
3970 /* Go through all insns, and use the information generated during
3971    scheduling to generate SEQUENCEs to represent bundles of
3972    instructions issued simultaneously.  */
3973 static void
tilepro_gen_bundles(void)3974 tilepro_gen_bundles (void)
3975 {
3976   basic_block bb;
3977   FOR_EACH_BB_FN (bb, cfun)
3978   {
3979     rtx_insn *insn, *next;
3980     rtx_insn *end = NEXT_INSN (BB_END (bb));
3981 
3982     for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn; insn = next)
3983       {
3984 	next = next_insn_to_bundle (NEXT_INSN (insn), end);
3985 
3986 	/* Never wrap {} around inline asm.  */
3987 	if (GET_CODE (PATTERN (insn)) != ASM_INPUT)
3988 	  {
3989 	    if (next == NULL_RTX || GET_MODE (next) == TImode
3990 		/* NOTE: The scheduler incorrectly believes a call
3991 		   insn can execute in the same cycle as the insn
3992 		   after the call.  This is of course impossible.
3993 		   Really we need to fix the scheduler somehow, so
3994 		   the code after the call gets scheduled
3995 		   optimally.  */
3996 		|| CALL_P (insn))
3997 	      {
3998 		/* Mark current insn as the end of a bundle.  */
3999 		PUT_MODE (insn, QImode);
4000 	      }
4001 	    else
4002 	      {
4003 		/* Mark it as part of a bundle.  */
4004 		PUT_MODE (insn, SImode);
4005 	      }
4006 	  }
4007       }
4008   }
4009 }
4010 
4011 
4012 /* Helper function for tilepro_fixup_pcrel_references.  */
4013 static void
replace_pc_relative_symbol_ref(rtx_insn * insn,rtx opnds[4],bool first_insn_p)4014 replace_pc_relative_symbol_ref (rtx_insn *insn, rtx opnds[4], bool first_insn_p)
4015 {
4016   rtx_insn *new_insns;
4017 
4018   start_sequence ();
4019 
4020   if (flag_pic == 1)
4021     {
4022       if (!first_insn_p)
4023 	{
4024 	  emit_insn (gen_add_got16 (opnds[0], tilepro_got_rtx (),
4025 				    opnds[2]));
4026 	  emit_insn (gen_insn_lw (opnds[0], opnds[0]));
4027 	}
4028     }
4029   else
4030     {
4031       if (first_insn_p)
4032 	{
4033 	  emit_insn (gen_addhi_got32 (opnds[0], tilepro_got_rtx (),
4034 				      opnds[2]));
4035 	}
4036       else
4037 	{
4038 	  emit_insn (gen_addlo_got32 (opnds[0], opnds[1], opnds[2]));
4039 	  emit_insn (gen_insn_lw (opnds[0], opnds[0]));
4040 	}
4041     }
4042 
4043   new_insns = get_insns ();
4044   end_sequence ();
4045 
4046   if (new_insns)
4047     emit_insn_before (new_insns, insn);
4048 
4049   delete_insn (insn);
4050 }
4051 
4052 
4053 /* Returns whether INSN is a pc-relative addli insn.   */
4054 static bool
match_addli_pcrel(rtx_insn * insn)4055 match_addli_pcrel (rtx_insn *insn)
4056 {
4057   rtx pattern = PATTERN (insn);
4058   rtx unspec;
4059 
4060   if (GET_CODE (pattern) != SET)
4061     return false;
4062 
4063   if (GET_CODE (SET_SRC (pattern)) != LO_SUM)
4064     return false;
4065 
4066   if (GET_CODE (XEXP (SET_SRC (pattern), 1)) != CONST)
4067     return false;
4068 
4069   unspec = XEXP (XEXP (SET_SRC (pattern), 1), 0);
4070 
4071   return (GET_CODE (unspec) == UNSPEC
4072 	  && XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4073 }
4074 
4075 
4076 /* Helper function for tilepro_fixup_pcrel_references.  */
4077 static void
replace_addli_pcrel(rtx_insn * insn)4078 replace_addli_pcrel (rtx_insn *insn)
4079 {
4080   rtx pattern = PATTERN (insn);
4081   rtx set_src;
4082   rtx unspec;
4083   rtx opnds[4];
4084   bool first_insn_p;
4085 
4086   gcc_assert (GET_CODE (pattern) == SET);
4087   opnds[0] = SET_DEST (pattern);
4088 
4089   set_src = SET_SRC (pattern);
4090   gcc_assert (GET_CODE (set_src) == LO_SUM);
4091   gcc_assert (GET_CODE (XEXP (set_src, 1)) == CONST);
4092   opnds[1] = XEXP (set_src, 0);
4093 
4094   unspec = XEXP (XEXP (set_src, 1), 0);
4095   gcc_assert (GET_CODE (unspec) == UNSPEC);
4096   gcc_assert (XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4097   opnds[2] = XVECEXP (unspec, 0, 0);
4098   opnds[3] = XVECEXP (unspec, 0, 1);
4099 
4100   /* We only need to replace SYMBOL_REFs, not LABEL_REFs.  */
4101   if (GET_CODE (opnds[2]) != SYMBOL_REF)
4102     return;
4103 
4104   first_insn_p = (opnds[1] == tilepro_text_label_rtx ());
4105 
4106   replace_pc_relative_symbol_ref (insn, opnds, first_insn_p);
4107 }
4108 
4109 
4110 /* Returns whether INSN is a pc-relative auli insn.   */
4111 static bool
match_auli_pcrel(rtx_insn * insn)4112 match_auli_pcrel (rtx_insn *insn)
4113 {
4114   rtx pattern = PATTERN (insn);
4115   rtx high;
4116   rtx unspec;
4117 
4118   if (GET_CODE (pattern) != SET)
4119     return false;
4120 
4121   if (GET_CODE (SET_SRC (pattern)) != PLUS)
4122     return false;
4123 
4124   high = XEXP (SET_SRC (pattern), 1);
4125 
4126   if (GET_CODE (high) != HIGH
4127       || GET_CODE (XEXP (high, 0)) != CONST)
4128     return false;
4129 
4130   unspec = XEXP (XEXP (high, 0), 0);
4131 
4132   return (GET_CODE (unspec) == UNSPEC
4133 	  && XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4134 }
4135 
4136 
4137 /* Helper function for tilepro_fixup_pcrel_references.  */
4138 static void
replace_auli_pcrel(rtx_insn * insn)4139 replace_auli_pcrel (rtx_insn *insn)
4140 {
4141   rtx pattern = PATTERN (insn);
4142   rtx set_src;
4143   rtx high;
4144   rtx unspec;
4145   rtx opnds[4];
4146   bool first_insn_p;
4147 
4148   gcc_assert (GET_CODE (pattern) == SET);
4149   opnds[0] = SET_DEST (pattern);
4150 
4151   set_src = SET_SRC (pattern);
4152   gcc_assert (GET_CODE (set_src) == PLUS);
4153   opnds[1] = XEXP (set_src, 0);
4154 
4155   high = XEXP (set_src, 1);
4156   gcc_assert (GET_CODE (high) == HIGH);
4157   gcc_assert (GET_CODE (XEXP (high, 0)) == CONST);
4158 
4159   unspec = XEXP (XEXP (high, 0), 0);
4160   gcc_assert (GET_CODE (unspec) == UNSPEC);
4161   gcc_assert (XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4162   opnds[2] = XVECEXP (unspec, 0, 0);
4163   opnds[3] = XVECEXP (unspec, 0, 1);
4164 
4165   /* We only need to replace SYMBOL_REFs, not LABEL_REFs.  */
4166   if (GET_CODE (opnds[2]) != SYMBOL_REF)
4167     return;
4168 
4169   first_insn_p = (opnds[1] == tilepro_text_label_rtx ());
4170 
4171   replace_pc_relative_symbol_ref (insn, opnds, first_insn_p);
4172 }
4173 
4174 
4175 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4176    going through the GOT when the symbol is local to the compilation
4177    unit.  But such a symbol requires that the common text_label that
4178    we generate at the beginning of the function be in the same section
4179    as the reference to the SYMBOL_REF.  This may not be true if we
4180    generate hot/cold sections.  This function looks for such cases and
4181    replaces such references with the longer sequence going through the
4182    GOT.
4183 
4184    We expect one of the following two instruction sequences:
4185    addli tmp1, txt_label_reg, lo16(sym - txt_label)
4186    auli  tmp2,          tmp1, ha16(sym - txt_label)
4187 
4188    auli  tmp1, txt_label_reg, ha16(sym - txt_label)
4189    addli tmp2,          tmp1, lo16(sym - txt_label)
4190 
4191    If we're compiling -fpic, we replace the first instruction with
4192    nothing, and the second instruction with:
4193 
4194    addli tmp2, got_rtx, got(sym)
4195    lw    tmp2,    tmp2
4196 
4197    If we're compiling -fPIC, we replace the first instruction with:
4198 
4199    auli  tmp1, got_rtx, got_ha16(sym)
4200 
4201    and the second instruction with:
4202 
4203    addli tmp2,    tmp1, got_lo16(sym)
4204    lw    tmp2,    tmp2
4205 
4206    Note that we're careful to disturb the instruction sequence as
4207    little as possible, since it's very late in the compilation
4208    process.
4209 */
4210 static void
tilepro_fixup_pcrel_references(void)4211 tilepro_fixup_pcrel_references (void)
4212 {
4213   rtx_insn *insn, *next_insn;
4214   bool same_section_as_entry = true;
4215 
4216   for (insn = get_insns (); insn; insn = next_insn)
4217     {
4218       next_insn = NEXT_INSN (insn);
4219 
4220       if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
4221 	{
4222 	  same_section_as_entry = !same_section_as_entry;
4223 	  continue;
4224 	}
4225 
4226       if (same_section_as_entry)
4227       	continue;
4228 
4229       if (!(INSN_P (insn)
4230 	    && GET_CODE (PATTERN (insn)) != USE
4231 	    && GET_CODE (PATTERN (insn)) != CLOBBER))
4232 	continue;
4233 
4234       if (match_addli_pcrel (insn))
4235 	replace_addli_pcrel (insn);
4236       else if (match_auli_pcrel (insn))
4237 	replace_auli_pcrel (insn);
4238     }
4239 }
4240 
4241 
4242 /* Ensure that no var tracking notes are emitted in the middle of a
4243    three-instruction bundle.  */
4244 static void
reorder_var_tracking_notes(void)4245 reorder_var_tracking_notes (void)
4246 {
4247   basic_block bb;
4248   FOR_EACH_BB_FN (bb, cfun)
4249   {
4250     rtx_insn *insn, *next;
4251     rtx_insn *queue = NULL;
4252     bool in_bundle = false;
4253 
4254     for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4255       {
4256 	next = NEXT_INSN (insn);
4257 
4258 	if (INSN_P (insn))
4259 	  {
4260 	    /* Emit queued up notes at the last instruction of a bundle.  */
4261 	    if (GET_MODE (insn) == QImode)
4262 	      {
4263 		while (queue)
4264 		  {
4265 		    rtx_insn *next_queue = PREV_INSN (queue);
4266 		    SET_PREV_INSN (NEXT_INSN (insn)) = queue;
4267 		    SET_NEXT_INSN (queue) = NEXT_INSN (insn);
4268 		    SET_NEXT_INSN (insn) = queue;
4269 		    SET_PREV_INSN (queue) = insn;
4270 		    queue = next_queue;
4271 		  }
4272 		in_bundle = false;
4273 	      }
4274 	    else if (GET_MODE (insn) == SImode)
4275 	      in_bundle = true;
4276 	  }
4277 	else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4278 	  {
4279 	    if (in_bundle)
4280 	      {
4281 		rtx_insn *prev = PREV_INSN (insn);
4282 		SET_PREV_INSN (next) = prev;
4283 		SET_NEXT_INSN (prev) = next;
4284 
4285 		SET_PREV_INSN (insn) = queue;
4286 		queue = insn;
4287 	      }
4288 	  }
4289       }
4290   }
4291 }
4292 
4293 
4294 /* Perform machine dependent operations on the rtl chain INSNS.  */
4295 static void
tilepro_reorg(void)4296 tilepro_reorg (void)
4297 {
4298   /* We are freeing block_for_insn in the toplev to keep compatibility
4299      with old MDEP_REORGS that are not CFG based.  Recompute it
4300      now.  */
4301   compute_bb_for_insn ();
4302 
4303   if (flag_reorder_blocks_and_partition)
4304     {
4305       tilepro_fixup_pcrel_references ();
4306     }
4307 
4308   if (flag_schedule_insns_after_reload)
4309     {
4310       split_all_insns ();
4311 
4312       timevar_push (TV_SCHED2);
4313       schedule_insns ();
4314       timevar_pop (TV_SCHED2);
4315 
4316       /* Examine the schedule to group into bundles.  */
4317       tilepro_gen_bundles ();
4318     }
4319 
4320   df_analyze ();
4321 
4322   if (flag_var_tracking)
4323     {
4324       timevar_push (TV_VAR_TRACKING);
4325       variable_tracking_main ();
4326       reorder_var_tracking_notes ();
4327       timevar_pop (TV_VAR_TRACKING);
4328     }
4329 
4330   df_finish_pass (false);
4331 }
4332 
4333 
4334 
4335 /* Assembly  */
4336 
4337 /* Select a format to encode pointers in exception handling data.
4338    CODE is 0 for data, 1 for code labels, 2 for function pointers.
4339    GLOBAL is true if the symbol may be affected by dynamic
4340    relocations.  */
4341 int
tilepro_asm_preferred_eh_data_format(int code ATTRIBUTE_UNUSED,int global)4342 tilepro_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
4343 {
4344   return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4;
4345 }
4346 
4347 
4348 /* Implement TARGET_ASM_OUTPUT_MI_THUNK.  */
4349 static void
tilepro_asm_output_mi_thunk(FILE * file,tree thunk_fndecl ATTRIBUTE_UNUSED,HOST_WIDE_INT delta,HOST_WIDE_INT vcall_offset,tree function)4350 tilepro_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
4351 			     HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
4352 			     tree function)
4353 {
4354   const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl));
4355   rtx this_rtx, funexp;
4356   rtx_insn *insn;
4357 
4358   /* Pretend to be a post-reload pass while generating rtl.  */
4359   reload_completed = 1;
4360 
4361   /* Mark the end of the (empty) prologue.  */
4362   emit_note (NOTE_INSN_PROLOGUE_END);
4363 
4364   /* Find the "this" pointer.  If the function returns a structure,
4365      the structure return pointer is in $1.  */
4366   if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
4367     this_rtx = gen_rtx_REG (Pmode, 1);
4368   else
4369     this_rtx = gen_rtx_REG (Pmode, 0);
4370 
4371   /* Add DELTA to THIS_RTX.  */
4372   emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
4373 
4374   /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX.  */
4375   if (vcall_offset)
4376     {
4377       rtx tmp;
4378 
4379       tmp = gen_rtx_REG (Pmode, 29);
4380       emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx));
4381 
4382       emit_insn (gen_addsi3 (tmp, tmp, GEN_INT (vcall_offset)));
4383 
4384       emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
4385 
4386       emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp));
4387     }
4388 
4389   /* Generate a tail call to the target function.  */
4390   if (!TREE_USED (function))
4391     {
4392       assemble_external (function);
4393       TREE_USED (function) = 1;
4394     }
4395   funexp = XEXP (DECL_RTL (function), 0);
4396   funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
4397   insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
4398   SIBLING_CALL_P (insn) = 1;
4399 
4400   /* Run just enough of rest_of_compilation to get the insns emitted.
4401      There's not really enough bulk here to make other passes such as
4402      instruction scheduling worth while.
4403 
4404      We don't currently bundle, but the instruciton sequence is all
4405      serial except for the tail call, so we're only wasting one cycle.
4406    */
4407   insn = get_insns ();
4408   shorten_branches (insn);
4409   assemble_start_function (thunk_fndecl, fnname);
4410   final_start_function (insn, file, 1);
4411   final (insn, file, 1);
4412   final_end_function ();
4413   assemble_end_function (thunk_fndecl, fnname);
4414 
4415   /* Stop pretending to be a post-reload pass.  */
4416   reload_completed = 0;
4417 }
4418 
4419 
4420 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE.  */
4421 static void
tilepro_asm_trampoline_template(FILE * file)4422 tilepro_asm_trampoline_template (FILE *file)
4423 {
4424   fprintf (file, "\tlnk   r10\n");
4425   fprintf (file, "\taddi  r10, r10, 32\n");
4426   fprintf (file, "\tlwadd r11, r10, %d\n", GET_MODE_SIZE (ptr_mode));
4427   fprintf (file, "\tlw    r10, r10\n");
4428   fprintf (file, "\tjr    r11\n");
4429   fprintf (file, "\t.word 0 # <function address>\n");
4430   fprintf (file, "\t.word 0 # <static chain value>\n");
4431 }
4432 
4433 
4434 /* Implement TARGET_TRAMPOLINE_INIT.  */
4435 static void
tilepro_trampoline_init(rtx m_tramp,tree fndecl,rtx static_chain)4436 tilepro_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
4437 {
4438   rtx fnaddr, chaddr;
4439   rtx mem;
4440   rtx begin_addr, end_addr;
4441   int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4442 
4443   fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
4444   chaddr = copy_to_reg (static_chain);
4445 
4446   emit_block_move (m_tramp, assemble_trampoline_template (),
4447 		   GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
4448 
4449   mem = adjust_address (m_tramp, ptr_mode,
4450 			TRAMPOLINE_SIZE - 2 * ptr_mode_size);
4451   emit_move_insn (mem, fnaddr);
4452   mem = adjust_address (m_tramp, ptr_mode,
4453 			TRAMPOLINE_SIZE - ptr_mode_size);
4454   emit_move_insn (mem, chaddr);
4455 
4456   /* Get pointers to the beginning and end of the code block.  */
4457   begin_addr = force_reg (Pmode, XEXP (m_tramp, 0));
4458   end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0),
4459 					      TRAMPOLINE_SIZE));
4460 
4461   maybe_emit_call_builtin___clear_cache (begin_addr, end_addr);
4462 }
4463 
4464 
4465 /* Implement TARGET_PRINT_OPERAND.  */
4466 static void
tilepro_print_operand(FILE * file,rtx x,int code)4467 tilepro_print_operand (FILE *file, rtx x, int code)
4468 {
4469   switch (code)
4470     {
4471     case 'c':
4472       /* Print the compare operator opcode for conditional moves. */
4473       switch (GET_CODE (x))
4474 	{
4475 	case EQ:
4476 	  fputs ("z", file);
4477 	  break;
4478 	case NE:
4479 	  fputs ("nz", file);
4480 	  break;
4481 	default:
4482 	  output_operand_lossage ("invalid %%c operand");
4483 	}
4484       return;
4485 
4486     case 'C':
4487       /* Print the compare operator opcode for conditional moves. */
4488       switch (GET_CODE (x))
4489 	{
4490 	case EQ:
4491 	  fputs ("nz", file);
4492 	  break;
4493 	case NE:
4494 	  fputs ("z", file);
4495 	  break;
4496 	default:
4497 	  output_operand_lossage ("invalid %%C operand");
4498 	}
4499       return;
4500 
4501     case 'h':
4502       {
4503 	/* Print the high 16 bits of a 32-bit constant.  */
4504 	HOST_WIDE_INT i;
4505 	if (CONST_INT_P (x))
4506 	  i = INTVAL (x);
4507 	else if (GET_CODE (x) == CONST_DOUBLE)
4508 	  i = CONST_DOUBLE_LOW (x);
4509 	else
4510 	  {
4511 	    output_operand_lossage ("invalid %%h operand");
4512 	    return;
4513 	  }
4514 	i = trunc_int_for_mode (i >> 16, HImode);
4515 	fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4516 	return;
4517       }
4518 
4519     case 'H':
4520       {
4521 	rtx addr = NULL;
4522 	const char *opstr = NULL;
4523 	bool pcrel = false;
4524 	if (GET_CODE (x) == CONST
4525 	    && GET_CODE (XEXP (x, 0)) == UNSPEC)
4526 	  {
4527 	    addr = XVECEXP (XEXP (x, 0), 0, 0);
4528 	    switch (XINT (XEXP (x, 0), 1))
4529 	    {
4530 	    case UNSPEC_GOT32_SYM:
4531 	      opstr = "got_ha16";
4532 	      break;
4533 	    case UNSPEC_PCREL_SYM:
4534 	      opstr = "ha16";
4535 	      pcrel = true;
4536 	      break;
4537 	    case UNSPEC_TLS_GD:
4538 	      opstr = "tls_gd_ha16";
4539 	      break;
4540 	    case UNSPEC_TLS_IE:
4541 	      opstr = "tls_ie_ha16";
4542 	      break;
4543 	    case UNSPEC_TLS_LE:
4544 	      opstr = "tls_le_ha16";
4545 	      break;
4546 	    default:
4547 	      output_operand_lossage ("invalid %%H operand");
4548 	    }
4549 	  }
4550 	else
4551 	  {
4552 	    addr = x;
4553 	    opstr = "ha16";
4554 	  }
4555 
4556 	fputs (opstr, file);
4557 	fputc ('(', file);
4558 	output_addr_const (file, addr);
4559 
4560 	if (pcrel)
4561 	  {
4562 	    rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
4563 	    fputs (" - " , file);
4564 	    output_addr_const (file, addr2);
4565 	  }
4566 
4567 	fputc (')', file);
4568 	return;
4569       }
4570 
4571     case 'I':
4572       /* Print an auto-inc memory operand.  */
4573       if (!MEM_P (x))
4574 	{
4575 	  output_operand_lossage ("invalid %%I operand");
4576 	  return;
4577 	}
4578 
4579       output_memory_autoinc_first = true;
4580       output_address (GET_MODE (x), XEXP (x, 0));
4581       return;
4582 
4583     case 'i':
4584       /* Print an auto-inc memory operand.  */
4585       if (!MEM_P (x))
4586 	{
4587 	  output_operand_lossage ("invalid %%i operand");
4588 	  return;
4589 	}
4590 
4591       output_memory_autoinc_first = false;
4592       output_address (GET_MODE (x), XEXP (x, 0));
4593       return;
4594 
4595     case 'j':
4596       {
4597 	/* Print the low 8 bits of a constant.  */
4598 	HOST_WIDE_INT i;
4599 	if (CONST_INT_P (x))
4600 	  i = INTVAL (x);
4601 	else if (GET_CODE (x) == CONST_DOUBLE)
4602 	  i = CONST_DOUBLE_LOW (x);
4603 	else if (GET_CODE (x) == CONST_VECTOR
4604 		 && CONST_INT_P (CONST_VECTOR_ELT (x, 0)))
4605 	  i = INTVAL (CONST_VECTOR_ELT (x, 0));
4606 	else
4607 	  {
4608 	    output_operand_lossage ("invalid %%j operand");
4609 	    return;
4610 	  }
4611 	i = trunc_int_for_mode (i, QImode);
4612 	fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4613 	return;
4614       }
4615 
4616     case 'L':
4617       {
4618 	rtx addr = NULL;
4619 	const char *opstr = NULL;
4620 	bool pcrel = false;
4621 	if (GET_CODE (x) == CONST
4622 	    && GET_CODE (XEXP (x, 0)) == UNSPEC)
4623 	  {
4624 	    addr = XVECEXP (XEXP (x, 0), 0, 0);
4625 	    switch (XINT (XEXP (x, 0), 1))
4626 	    {
4627 	    case UNSPEC_GOT16_SYM:
4628 	      opstr = "got";
4629 	      break;
4630 	    case UNSPEC_GOT32_SYM:
4631 	      opstr = "got_lo16";
4632 	      break;
4633 	    case UNSPEC_PCREL_SYM:
4634 	      opstr = "lo16";
4635 	      pcrel = true;
4636 	      break;
4637 	    case UNSPEC_TLS_GD:
4638 	      opstr = "tls_gd_lo16";
4639 	      break;
4640 	    case UNSPEC_TLS_IE:
4641 	      opstr = "tls_ie_lo16";
4642 	      break;
4643 	    case UNSPEC_TLS_LE:
4644 	      opstr = "tls_le_lo16";
4645 	      break;
4646 	    default:
4647 	      output_operand_lossage ("invalid %%L operand");
4648 	    }
4649 	  }
4650 	else
4651 	  {
4652 	    addr = x;
4653 	    opstr = "lo16";
4654 	  }
4655 
4656 	fputs (opstr, file);
4657 	fputc ('(', file);
4658 	output_addr_const (file, addr);
4659 
4660 	if (pcrel)
4661 	  {
4662 	    rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
4663 	    fputs (" - " , file);
4664 	    output_addr_const (file, addr2);
4665 	  }
4666 
4667 	fputc (')', file);
4668 	return;
4669       }
4670 
4671     case 'p':
4672       if (GET_CODE (x) == SYMBOL_REF)
4673 	{
4674 	  if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
4675 	    fprintf (file, "plt(");
4676 	  output_addr_const (file, x);
4677 	  if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
4678 	    fprintf (file, ")");
4679 	}
4680       else
4681 	output_addr_const (file, x);
4682       return;
4683 
4684     case 'P':
4685       {
4686 	/* Print a 32-bit constant plus one.  */
4687 	HOST_WIDE_INT i;
4688 	if (!CONST_INT_P (x))
4689 	  {
4690 	    output_operand_lossage ("invalid %%P operand");
4691 	    return;
4692 	  }
4693 	i = trunc_int_for_mode (INTVAL (x) + 1, SImode);
4694 	fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4695 	return;
4696       }
4697 
4698     case 'M':
4699       {
4700 	/* Print an mm-style bit range.  */
4701 	int first_bit, last_bit;
4702 
4703 	if (!CONST_INT_P (x)
4704 	    || !tilepro_bitfield_operand_p (INTVAL (x), &first_bit,
4705 					    &last_bit))
4706 	  {
4707 	    output_operand_lossage ("invalid %%M operand");
4708 	    return;
4709 	  }
4710 
4711 	fprintf (file, "%d, %d", first_bit, last_bit);
4712 	return;
4713       }
4714 
4715     case 'N':
4716       {
4717 	const char *reg = NULL;
4718 
4719 	/* Print a network register.  */
4720 	if (!CONST_INT_P (x))
4721 	  {
4722 	    output_operand_lossage ("invalid %%N operand");
4723 	    return;
4724 	  }
4725 
4726 	switch (INTVAL (x))
4727 	  {
4728 	  case TILEPRO_NETREG_IDN0: reg = "idn0"; break;
4729 	  case TILEPRO_NETREG_IDN1: reg = "idn1"; break;
4730 	  case TILEPRO_NETREG_SN:   reg = "sn";   break;
4731 	  case TILEPRO_NETREG_UDN0: reg = "udn0"; break;
4732 	  case TILEPRO_NETREG_UDN1: reg = "udn1"; break;
4733 	  case TILEPRO_NETREG_UDN2: reg = "udn2"; break;
4734 	  case TILEPRO_NETREG_UDN3: reg = "udn3"; break;
4735 	  default: gcc_unreachable ();
4736 	  }
4737 
4738 	fprintf (file, reg);
4739 	return;
4740       }
4741 
4742     case 't':
4743       {
4744 	/* Log base 2 of a power of two.  */
4745 	HOST_WIDE_INT i;
4746 	HOST_WIDE_INT n;
4747 
4748 	if (!CONST_INT_P (x))
4749 	  {
4750 	    output_operand_lossage ("invalid %%t operand");
4751 	    return;
4752 	  }
4753 	n = trunc_int_for_mode (INTVAL (x), SImode);
4754 	i = exact_log2 (n);
4755 	if (i < 0)
4756 	  {
4757 	    output_operand_lossage ("invalid %%t operand");
4758 	    return;
4759 	  }
4760 
4761 	fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4762 	return;
4763       }
4764       break;
4765 
4766     case 'r':
4767       /* In this case we need a register.  Use 'zero' if the
4768          operand is const0_rtx.  */
4769       if (x == const0_rtx
4770 	  || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
4771 	{
4772 	  fputs ("zero", file);
4773 	  return;
4774 	}
4775       else if (!REG_P (x))
4776 	{
4777 	  output_operand_lossage ("invalid %%r operand");
4778 	  return;
4779 	}
4780       /* FALLTHRU */
4781 
4782     case 0:
4783       if (REG_P (x))
4784 	{
4785 	  fprintf (file, "%s", reg_names[REGNO (x)]);
4786 	  return;
4787 	}
4788       else if (MEM_P (x))
4789 	{
4790 	  output_address (VOIDmode, XEXP (x, 0));
4791 	  return;
4792 	}
4793       else
4794 	{
4795 	  output_addr_const (file, x);
4796 	  return;
4797 	}
4798       break;
4799     }
4800 
4801   debug_rtx (x);
4802   output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
4803 			  code, code);
4804 }
4805 
4806 
4807 /* Implement TARGET_PRINT_OPERAND_ADDRESS.  */
4808 static void
tilepro_print_operand_address(FILE * file,machine_mode mode,rtx addr)4809 tilepro_print_operand_address (FILE *file, machine_mode mode, rtx addr)
4810 {
4811   if (GET_CODE (addr) == POST_DEC
4812       || GET_CODE (addr) == POST_INC)
4813     {
4814       int offset = GET_MODE_SIZE (mode);
4815 
4816       gcc_assert (mode != VOIDmode);
4817 
4818       if (output_memory_autoinc_first)
4819 	fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
4820       else
4821 	fprintf (file, "%d",
4822 		 GET_CODE (addr) == POST_DEC ? -offset : offset);
4823     }
4824   else if (GET_CODE (addr) == POST_MODIFY)
4825     {
4826       gcc_assert (mode != VOIDmode);
4827 
4828       gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
4829 
4830       if (output_memory_autoinc_first)
4831 	fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
4832       else
4833 	fprintf (file, HOST_WIDE_INT_PRINT_DEC,
4834 		 INTVAL (XEXP (XEXP (addr, 1), 1)));
4835     }
4836   else
4837     tilepro_print_operand (file, addr, 'r');
4838 }
4839 
4840 
4841 /* Machine mode of current insn, for determining curly brace
4842    placement.  */
4843 static machine_mode insn_mode;
4844 
4845 
4846 /* Implement FINAL_PRESCAN_INSN.  This is used to emit bundles.  */
4847 void
tilepro_final_prescan_insn(rtx_insn * insn)4848 tilepro_final_prescan_insn (rtx_insn *insn)
4849 {
4850   /* Record this for tilepro_asm_output_opcode to examine.  */
4851   insn_mode = GET_MODE (insn);
4852 }
4853 
4854 
4855 /* While emitting asm, are we currently inside '{' for a bundle? */
4856 static bool tilepro_in_bundle = false;
4857 
4858 /* Implement ASM_OUTPUT_OPCODE.  Prepend/append curly braces as
4859    appropriate given the bundling information recorded by
4860    tilepro_gen_bundles.  */
4861 const char *
tilepro_asm_output_opcode(FILE * stream,const char * code)4862 tilepro_asm_output_opcode (FILE *stream, const char *code)
4863 {
4864   bool pseudo = !strcmp (code, "pseudo");
4865 
4866   if (!tilepro_in_bundle && insn_mode == SImode)
4867     {
4868       /* Start a new bundle.  */
4869       fprintf (stream, "{\n\t");
4870       tilepro_in_bundle = true;
4871     }
4872 
4873   if (tilepro_in_bundle && insn_mode == QImode)
4874     {
4875       /* Close an existing bundle.  */
4876       static char buf[100];
4877 
4878       gcc_assert (strlen (code) + 3 + 1 < sizeof (buf));
4879 
4880       strcpy (buf, pseudo ? "" : code);
4881       strcat (buf, "\n\t}");
4882       tilepro_in_bundle = false;
4883 
4884       return buf;
4885     }
4886   else
4887     {
4888       return pseudo ? "" : code;
4889     }
4890 }
4891 
4892 
4893 /* Output assembler code to FILE to increment profiler label # LABELNO
4894    for profiling a function entry.  */
4895 void
tilepro_function_profiler(FILE * file,int labelno ATTRIBUTE_UNUSED)4896 tilepro_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
4897 {
4898   if (tilepro_in_bundle)
4899     {
4900       fprintf (file, "\t}\n");
4901     }
4902 
4903   if (flag_pic)
4904     {
4905       fprintf (file,
4906 	       "\t{\n"
4907 	       "\tmove\tr10, lr\n"
4908 	       "\tjal\tplt(%s)\n"
4909 	       "\t}\n", MCOUNT_NAME);
4910     }
4911   else
4912     {
4913       fprintf (file,
4914 	       "\t{\n"
4915 	       "\tmove\tr10, lr\n"
4916 	       "\tjal\t%s\n"
4917 	       "\t}\n", MCOUNT_NAME);
4918     }
4919 
4920   tilepro_in_bundle = false;
4921 }
4922 
4923 
4924 /* Implement TARGET_ASM_FILE_END.  */
4925 static void
tilepro_file_end(void)4926 tilepro_file_end (void)
4927 {
4928   if (NEED_INDICATE_EXEC_STACK)
4929     file_end_indicate_exec_stack ();
4930 }
4931 
4932 
4933 #undef  TARGET_HAVE_TLS
4934 #define TARGET_HAVE_TLS HAVE_AS_TLS
4935 
4936 #undef  TARGET_OPTION_OVERRIDE
4937 #define TARGET_OPTION_OVERRIDE tilepro_option_override
4938 
4939 #ifdef TARGET_THREAD_SSP_OFFSET
4940 #undef TARGET_STACK_PROTECT_GUARD
4941 #define TARGET_STACK_PROTECT_GUARD hook_tree_void_null
4942 #endif
4943 
4944 #undef  TARGET_SCALAR_MODE_SUPPORTED_P
4945 #define TARGET_SCALAR_MODE_SUPPORTED_P tilepro_scalar_mode_supported_p
4946 
4947 #undef  TARGET_VECTOR_MODE_SUPPORTED_P
4948 #define TARGET_VECTOR_MODE_SUPPORTED_P tile_vector_mode_supported_p
4949 
4950 #undef  TARGET_CANNOT_FORCE_CONST_MEM
4951 #define TARGET_CANNOT_FORCE_CONST_MEM tilepro_cannot_force_const_mem
4952 
4953 #undef  TARGET_FUNCTION_OK_FOR_SIBCALL
4954 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilepro_function_ok_for_sibcall
4955 
4956 #undef  TARGET_PASS_BY_REFERENCE
4957 #define TARGET_PASS_BY_REFERENCE tilepro_pass_by_reference
4958 
4959 #undef  TARGET_RETURN_IN_MEMORY
4960 #define TARGET_RETURN_IN_MEMORY tilepro_return_in_memory
4961 
4962 #undef  TARGET_FUNCTION_ARG_BOUNDARY
4963 #define TARGET_FUNCTION_ARG_BOUNDARY tilepro_function_arg_boundary
4964 
4965 #undef  TARGET_FUNCTION_ARG
4966 #define TARGET_FUNCTION_ARG tilepro_function_arg
4967 
4968 #undef  TARGET_FUNCTION_ARG_ADVANCE
4969 #define TARGET_FUNCTION_ARG_ADVANCE tilepro_function_arg_advance
4970 
4971 #undef  TARGET_FUNCTION_VALUE
4972 #define TARGET_FUNCTION_VALUE tilepro_function_value
4973 
4974 #undef  TARGET_LIBCALL_VALUE
4975 #define TARGET_LIBCALL_VALUE tilepro_libcall_value
4976 
4977 #undef  TARGET_FUNCTION_VALUE_REGNO_P
4978 #define TARGET_FUNCTION_VALUE_REGNO_P tilepro_function_value_regno_p
4979 
4980 #undef  TARGET_PROMOTE_FUNCTION_MODE
4981 #define TARGET_PROMOTE_FUNCTION_MODE \
4982   default_promote_function_mode_always_promote
4983 
4984 #undef  TARGET_PROMOTE_PROTOTYPES
4985 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
4986 
4987 #undef  TARGET_BUILD_BUILTIN_VA_LIST
4988 #define TARGET_BUILD_BUILTIN_VA_LIST tilepro_build_builtin_va_list
4989 
4990 #undef  TARGET_EXPAND_BUILTIN_VA_START
4991 #define TARGET_EXPAND_BUILTIN_VA_START tilepro_va_start
4992 
4993 #undef  TARGET_SETUP_INCOMING_VARARGS
4994 #define TARGET_SETUP_INCOMING_VARARGS tilepro_setup_incoming_varargs
4995 
4996 #undef  TARGET_GIMPLIFY_VA_ARG_EXPR
4997 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilepro_gimplify_va_arg_expr
4998 
4999 #undef  TARGET_RTX_COSTS
5000 #define TARGET_RTX_COSTS tilepro_rtx_costs
5001 
5002 /* Limit to what we can reach in one addli.  */
5003 #undef  TARGET_MIN_ANCHOR_OFFSET
5004 #define TARGET_MIN_ANCHOR_OFFSET -32768
5005 #undef  TARGET_MAX_ANCHOR_OFFSET
5006 #define TARGET_MAX_ANCHOR_OFFSET 32767
5007 
5008 #undef  TARGET_LEGITIMATE_CONSTANT_P
5009 #define TARGET_LEGITIMATE_CONSTANT_P tilepro_legitimate_constant_p
5010 
5011 #undef TARGET_LRA_P
5012 #define TARGET_LRA_P hook_bool_void_false
5013 
5014 #undef  TARGET_LEGITIMATE_ADDRESS_P
5015 #define TARGET_LEGITIMATE_ADDRESS_P tilepro_legitimate_address_p
5016 
5017 #undef  TARGET_LEGITIMIZE_ADDRESS
5018 #define TARGET_LEGITIMIZE_ADDRESS tilepro_legitimize_address
5019 
5020 #undef  TARGET_DELEGITIMIZE_ADDRESS
5021 #define TARGET_DELEGITIMIZE_ADDRESS tilepro_delegitimize_address
5022 
5023 #undef  TARGET_INIT_BUILTINS
5024 #define TARGET_INIT_BUILTINS  tilepro_init_builtins
5025 
5026 #undef  TARGET_BUILTIN_DECL
5027 #define TARGET_BUILTIN_DECL tilepro_builtin_decl
5028 
5029 #undef  TARGET_EXPAND_BUILTIN
5030 #define TARGET_EXPAND_BUILTIN tilepro_expand_builtin
5031 
5032 #undef  TARGET_CONDITIONAL_REGISTER_USAGE
5033 #define TARGET_CONDITIONAL_REGISTER_USAGE tilepro_conditional_register_usage
5034 
5035 #undef  TARGET_FRAME_POINTER_REQUIRED
5036 #define TARGET_FRAME_POINTER_REQUIRED tilepro_frame_pointer_required
5037 
5038 #undef  TARGET_DELAY_SCHED2
5039 #define TARGET_DELAY_SCHED2 true
5040 
5041 #undef  TARGET_DELAY_VARTRACK
5042 #define TARGET_DELAY_VARTRACK true
5043 
5044 #undef  TARGET_SCHED_ISSUE_RATE
5045 #define TARGET_SCHED_ISSUE_RATE tilepro_issue_rate
5046 
5047 #undef  TARGET_SCHED_ADJUST_COST
5048 #define TARGET_SCHED_ADJUST_COST tilepro_sched_adjust_cost
5049 
5050 #undef  TARGET_MACHINE_DEPENDENT_REORG
5051 #define TARGET_MACHINE_DEPENDENT_REORG tilepro_reorg
5052 
5053 #undef  TARGET_ASM_CAN_OUTPUT_MI_THUNK
5054 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5055   hook_bool_const_tree_hwi_hwi_const_tree_true
5056 
5057 #undef  TARGET_ASM_OUTPUT_MI_THUNK
5058 #define TARGET_ASM_OUTPUT_MI_THUNK tilepro_asm_output_mi_thunk
5059 
5060 #undef  TARGET_ASM_TRAMPOLINE_TEMPLATE
5061 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilepro_asm_trampoline_template
5062 
5063 #undef  TARGET_TRAMPOLINE_INIT
5064 #define TARGET_TRAMPOLINE_INIT tilepro_trampoline_init
5065 
5066 #undef  TARGET_PRINT_OPERAND
5067 #define TARGET_PRINT_OPERAND tilepro_print_operand
5068 
5069 #undef  TARGET_PRINT_OPERAND_ADDRESS
5070 #define TARGET_PRINT_OPERAND_ADDRESS tilepro_print_operand_address
5071 
5072 #undef  TARGET_ASM_FILE_END
5073 #define TARGET_ASM_FILE_END tilepro_file_end
5074 
5075 #undef  TARGET_CAN_USE_DOLOOP_P
5076 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
5077 
5078 #undef  TARGET_CONSTANT_ALIGNMENT
5079 #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
5080 
5081 struct gcc_target targetm = TARGET_INITIALIZER;
5082 
5083 #include "gt-tilepro.h"
5084