xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/tilegx/tilegx.c (revision 212397c69a103ae7e5eafa8731ddfae671d2dee7)
1 /* Subroutines used for code generation on the Tilera TILE-Gx.
2    Copyright (C) 2011-2013 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 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "insn-config.h"
28 #include "output.h"
29 #include "insn-attr.h"
30 #include "recog.h"
31 #include "expr.h"
32 #include "langhooks.h"
33 #include "optabs.h"
34 #include "sched-int.h"
35 #include "tm_p.h"
36 #include "tm-constrs.h"
37 #include "target.h"
38 #include "target-def.h"
39 #include "function.h"
40 #include "dwarf2.h"
41 #include "timevar.h"
42 #include "gimple.h"
43 #include "cfgloop.h"
44 #include "tilegx-builtins.h"
45 #include "tilegx-multiply.h"
46 #include "diagnostic.h"
47 
48 /* SYMBOL_REF for GOT */
49 static GTY(()) rtx g_got_symbol = NULL;
50 
51 /* In case of a POST_INC or POST_DEC memory reference, we must report
52    the mode of the memory reference from TARGET_PRINT_OPERAND to
53    TARGET_PRINT_OPERAND_ADDRESS.  */
54 static enum machine_mode output_memory_reference_mode;
55 
56 /* Report whether we're printing out the first address fragment of a
57    POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
58    TARGET_PRINT_OPERAND_ADDRESS.  */
59 static bool output_memory_autoinc_first;
60 
61 
62 
63 /* Option handling  */
64 
65 /* Implement TARGET_OPTION_OVERRIDE.  */
66 static void
67 tilegx_option_override (void)
68 {
69   if (global_options_set.x_tilegx_cmodel)
70     {
71       switch (tilegx_cmodel)
72 	{
73 	case CM_SMALL:
74 	case CM_SMALL_PIC:
75 	  if (flag_pic)
76 	    tilegx_cmodel = CM_SMALL_PIC;
77 	  break;
78 
79 	case CM_LARGE:
80 	case CM_LARGE_PIC:
81 	  if (flag_pic)
82 	    tilegx_cmodel = CM_LARGE_PIC;
83 	  break;
84 
85 	default:
86 	  gcc_unreachable ();
87 	}
88     }
89   else
90     tilegx_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
91 
92   /* When modulo scheduling is enabled, we still rely on regular
93      scheduler for bundling.  */
94   if (flag_modulo_sched)
95     flag_resched_modulo_sched = 1;
96 }
97 
98 
99 
100 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P.  */
101 static bool
102 tilegx_scalar_mode_supported_p (enum machine_mode mode)
103 {
104   switch (mode)
105     {
106     case QImode:
107     case HImode:
108     case SImode:
109     case DImode:
110     case TImode:
111       return true;
112 
113     case SFmode:
114     case DFmode:
115       return true;
116 
117     default:
118       return false;
119     }
120 }
121 
122 
123 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P.  */
124 static bool
125 tilegx_vector_mode_supported_p (enum machine_mode mode)
126 {
127   return mode == V8QImode || mode == V4HImode || mode == V2SImode;
128 }
129 
130 
131 /* Implement TARGET_CANNOT_FORCE_CONST_MEM.  */
132 static bool
133 tilegx_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED,
134 			       rtx x ATTRIBUTE_UNUSED)
135 {
136   return true;
137 }
138 
139 
140 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
141 static bool
142 tilegx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
143 {
144   return (tilegx_cmodel != CM_LARGE && tilegx_cmodel != CM_LARGE_PIC
145 	  && (decl != NULL));
146 }
147 
148 
149 /* Implement TARGET_PASS_BY_REFERENCE.  Variable sized types are
150    passed by reference.  */
151 static bool
152 tilegx_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
153 			  enum machine_mode mode ATTRIBUTE_UNUSED,
154 			  const_tree type, bool named ATTRIBUTE_UNUSED)
155 {
156   return (type && TYPE_SIZE (type)
157 	  && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST);
158 }
159 
160 
161 /* Implement TARGET_RETURN_IN_MEMORY.  */
162 static bool
163 tilegx_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
164 {
165   return !IN_RANGE (int_size_in_bytes (type),
166 		    0, TILEGX_NUM_RETURN_REGS * UNITS_PER_WORD);
167 }
168 
169 
170 /* Implement TARGET_MODE_REP_EXTENDED.  */
171 static int
172 tilegx_mode_rep_extended (enum machine_mode mode, enum machine_mode mode_rep)
173 {
174   /* SImode register values are sign-extended to DImode.  */
175   if (mode == SImode && mode_rep == DImode)
176     return SIGN_EXTEND;
177 
178   return UNKNOWN;
179 }
180 
181 
182 /* Implement TARGET_FUNCTION_ARG_BOUNDARY.  */
183 static unsigned int
184 tilegx_function_arg_boundary (enum machine_mode mode, const_tree type)
185 {
186   unsigned int alignment;
187 
188   alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode);
189   if (alignment < PARM_BOUNDARY)
190     alignment = PARM_BOUNDARY;
191   if (alignment > STACK_BOUNDARY)
192     alignment = STACK_BOUNDARY;
193   return alignment;
194 }
195 
196 
197 /* Implement TARGET_FUNCTION_ARG.  */
198 static rtx
199 tilegx_function_arg (cumulative_args_t cum_v,
200 		     enum machine_mode mode,
201 		     const_tree type, bool named ATTRIBUTE_UNUSED)
202 {
203   CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
204   int byte_size = ((mode == BLKmode)
205 		   ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
206 
207   if (cum >= TILEGX_NUM_ARG_REGS)
208     return NULL_RTX;
209 
210   /* The ABI does not allow parameters to be passed partially in reg
211      and partially in stack.  */
212   if ((cum + (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
213       > TILEGX_NUM_ARG_REGS)
214     return NULL_RTX;
215 
216   return gen_rtx_REG (mode, cum);
217 }
218 
219 
220 /* Implement TARGET_FUNCTION_ARG_ADVANCE.  */
221 static void
222 tilegx_function_arg_advance (cumulative_args_t cum_v,
223 			     enum machine_mode mode,
224 			     const_tree type, bool named ATTRIBUTE_UNUSED)
225 {
226   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
227 
228   int byte_size = ((mode == BLKmode)
229 		   ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
230   int word_size = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
231 
232   /* If the current argument does not fit in the pretend_args space,
233      skip over it.  */
234   if (*cum < TILEGX_NUM_ARG_REGS
235       && *cum + word_size > TILEGX_NUM_ARG_REGS)
236     *cum = TILEGX_NUM_ARG_REGS;
237 
238   *cum += word_size;
239 }
240 
241 
242 /* Implement TARGET_FUNCTION_VALUE.  */
243 static rtx
244 tilegx_function_value (const_tree valtype, const_tree fn_decl_or_type,
245 		       bool outgoing ATTRIBUTE_UNUSED)
246 {
247   enum machine_mode mode;
248   int unsigned_p;
249 
250   mode = TYPE_MODE (valtype);
251   unsigned_p = TYPE_UNSIGNED (valtype);
252 
253   mode = promote_function_mode (valtype, mode, &unsigned_p,
254 				fn_decl_or_type, 1);
255 
256   return gen_rtx_REG (mode, 0);
257 }
258 
259 
260 /* Implement TARGET_LIBCALL_VALUE.  */
261 static rtx
262 tilegx_libcall_value (enum machine_mode mode,
263 		       const_rtx fun ATTRIBUTE_UNUSED)
264 {
265   return gen_rtx_REG (mode, 0);
266 }
267 
268 
269 /* Implement FUNCTION_VALUE_REGNO_P.  */
270 static bool
271 tilegx_function_value_regno_p (const unsigned int regno)
272 {
273   return regno < TILEGX_NUM_RETURN_REGS;
274 }
275 
276 
277 /* Implement TARGET_BUILD_BUILTIN_VA_LIST.  */
278 static tree
279 tilegx_build_builtin_va_list (void)
280 {
281   tree f_args, f_skip, record, type_decl;
282   bool owp;
283 
284   record = lang_hooks.types.make_type (RECORD_TYPE);
285 
286   type_decl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
287 			  get_identifier ("__va_list_tag"), record);
288 
289   f_args = build_decl (BUILTINS_LOCATION, FIELD_DECL,
290 		       get_identifier ("__args"), ptr_type_node);
291   f_skip = build_decl (BUILTINS_LOCATION, FIELD_DECL,
292 		       get_identifier ("__skip"), ptr_type_node);
293 
294   DECL_FIELD_CONTEXT (f_args) = record;
295 
296   DECL_FIELD_CONTEXT (f_skip) = record;
297 
298   TREE_CHAIN (record) = type_decl;
299   TYPE_NAME (record) = type_decl;
300   TYPE_FIELDS (record) = f_args;
301   TREE_CHAIN (f_args) = f_skip;
302 
303   /* We know this is being padded and we want it too.  It is an
304      internal type so hide the warnings from the user.  */
305   owp = warn_padded;
306   warn_padded = false;
307 
308   layout_type (record);
309 
310   warn_padded = owp;
311 
312   /* The correct type is an array type of one element.  */
313   return record;
314 }
315 
316 
317 /* Implement TARGET_EXPAND_BUILTIN_VA_START.  */
318 static void
319 tilegx_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
320 {
321   tree f_args, f_skip;
322   tree args, skip, t;
323 
324   f_args = TYPE_FIELDS (TREE_TYPE (valist));
325   f_skip = TREE_CHAIN (f_args);
326 
327   args =
328     build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
329   skip =
330     build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
331 
332   /* Find the __args area.  */
333   t = make_tree (TREE_TYPE (args), virtual_incoming_args_rtx);
334   t = fold_build_pointer_plus_hwi (t,
335 				   UNITS_PER_WORD *
336 				   (crtl->args.info - TILEGX_NUM_ARG_REGS));
337 
338   if (crtl->args.pretend_args_size > 0)
339     t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
340 
341   t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t);
342   TREE_SIDE_EFFECTS (t) = 1;
343   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
344 
345   /* Find the __skip area.  */
346   t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx);
347   t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
348   t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t);
349   TREE_SIDE_EFFECTS (t) = 1;
350   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
351 }
352 
353 
354 /* Implement TARGET_SETUP_INCOMING_VARARGS.  */
355 static void
356 tilegx_setup_incoming_varargs (cumulative_args_t cum,
357 			       enum machine_mode mode,
358 			       tree type, int *pretend_args, int no_rtl)
359 {
360   CUMULATIVE_ARGS local_cum = *get_cumulative_args (cum);
361   int first_reg;
362 
363   /* The caller has advanced CUM up to, but not beyond, the last named
364      argument.  Advance a local copy of CUM past the last "real" named
365      argument, to find out how many registers are left over.  */
366   targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum),
367 				      mode, type, true);
368   first_reg = local_cum;
369 
370   if (local_cum < TILEGX_NUM_ARG_REGS)
371     {
372       *pretend_args = UNITS_PER_WORD * (TILEGX_NUM_ARG_REGS - first_reg);
373 
374       if (!no_rtl)
375 	{
376 	  alias_set_type set = get_varargs_alias_set ();
377 	  rtx tmp =
378 	    gen_rtx_MEM (BLKmode, plus_constant (Pmode,
379 						 virtual_incoming_args_rtx,
380 						 -STACK_POINTER_OFFSET -
381 						 UNITS_PER_WORD *
382 						 (TILEGX_NUM_ARG_REGS -
383 						  first_reg)));
384 	  MEM_NOTRAP_P (tmp) = 1;
385 	  set_mem_alias_set (tmp, set);
386 	  move_block_from_reg (first_reg, tmp,
387 			       TILEGX_NUM_ARG_REGS - first_reg);
388 	}
389     }
390   else
391     *pretend_args = 0;
392 }
393 
394 
395 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR.  Gimplify va_arg by updating
396    the va_list structure VALIST as required to retrieve an argument of
397    type TYPE, and returning that argument.
398 
399    ret = va_arg(VALIST, TYPE);
400 
401    generates code equivalent to:
402 
403     paddedsize = (sizeof(TYPE) + 3) & -4;
404     if (  (VALIST.__args + paddedsize > VALIST.__skip)
405 	& (VALIST.__args <= VALIST.__skip))
406       addr = VALIST.__skip + STACK_POINTER_OFFSET;
407     else
408       addr = VALIST.__args;
409     VALIST.__args = addr + paddedsize;
410     ret = *(TYPE *)addr;
411  */
412 static tree
413 tilegx_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
414 			     gimple_seq *post_p ATTRIBUTE_UNUSED)
415 {
416   tree f_args, f_skip;
417   tree args, skip;
418   HOST_WIDE_INT size, rsize;
419   tree addr, tmp;
420   bool pass_by_reference_p;
421 
422   f_args = TYPE_FIELDS (va_list_type_node);
423   f_skip = TREE_CHAIN (f_args);
424 
425   args =
426     build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
427   skip =
428     build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
429 
430   addr = create_tmp_var (ptr_type_node, "va_arg");
431 
432   /* If an object is dynamically sized, a pointer to it is passed
433      instead of the object itself.  */
434   pass_by_reference_p = pass_by_reference (NULL, TYPE_MODE (type), type,
435 					   false);
436 
437   if (pass_by_reference_p)
438     type = build_pointer_type (type);
439 
440   size = int_size_in_bytes (type);
441   rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD;
442 
443   /* Assert alignment assumption.  */
444   gcc_assert (STACK_BOUNDARY == PARM_BOUNDARY);
445 
446   /* Build conditional expression to calculate addr. The expression
447      will be gimplified later.  */
448   tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize);
449   tmp = build2 (TRUTH_AND_EXPR, boolean_type_node,
450 		build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)),
451 		build2 (LE_EXPR, boolean_type_node, unshare_expr (args),
452 			unshare_expr (skip)));
453 
454   tmp = build3 (COND_EXPR, ptr_type_node, tmp,
455 		build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip),
456 			size_int (STACK_POINTER_OFFSET)),
457 		unshare_expr (args));
458 
459   gimplify_assign (addr, tmp, pre_p);
460 
461   /* Update VALIST.__args.  */
462   tmp = fold_build_pointer_plus_hwi (addr, rsize);
463   gimplify_assign (unshare_expr (args), tmp, pre_p);
464 
465   addr = fold_convert (build_pointer_type (type), addr);
466 
467   if (pass_by_reference_p)
468     addr = build_va_arg_indirect_ref (addr);
469 
470   return build_va_arg_indirect_ref (addr);
471 }
472 
473 
474 
475 /* Implement TARGET_RTX_COSTS.  */
476 static bool
477 tilegx_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
478 		  bool speed)
479 {
480   switch (code)
481     {
482     case CONST_INT:
483       /* If this is an 8-bit constant, return zero since it can be
484 	 used nearly anywhere with no cost.  If it is a valid operand
485 	 for an ADD or AND, likewise return 0 if we know it will be
486 	 used in that context.  Otherwise, return 2 since it might be
487 	 used there later.  All other constants take at least two
488 	 insns.  */
489       if (satisfies_constraint_I (x))
490 	{
491 	  *total = 0;
492 	  return true;
493 	}
494       else if (outer_code == PLUS && add_operand (x, VOIDmode))
495 	{
496 	  /* Slightly penalize large constants even though we can add
497 	     them in one instruction, because it forces the use of
498 	     2-wide bundling mode.  */
499 	  *total = 1;
500 	  return true;
501 	}
502       else if (move_operand (x, SImode))
503 	{
504 	  /* We can materialize in one move.  */
505 	  *total = COSTS_N_INSNS (1);
506 	  return true;
507 	}
508       else
509 	{
510 	  /* We can materialize in two moves.  */
511 	  *total = COSTS_N_INSNS (2);
512 	  return true;
513 	}
514 
515       return false;
516 
517     case CONST:
518     case LABEL_REF:
519     case SYMBOL_REF:
520       *total = COSTS_N_INSNS (2);
521       return true;
522 
523     case CONST_DOUBLE:
524       *total = COSTS_N_INSNS (4);
525       return true;
526 
527     case HIGH:
528       *total = 0;
529       return true;
530 
531     case MEM:
532       /* If outer-code was a sign or zero extension, a cost of
533 	 COSTS_N_INSNS (1) was already added in, so account for
534 	 that.  */
535       if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND)
536 	*total = COSTS_N_INSNS (1);
537       else
538 	*total = COSTS_N_INSNS (2);
539       return true;
540 
541     case PLUS:
542       /* Convey that shl[123]add are efficient.  */
543       if (GET_CODE (XEXP (x, 0)) == MULT
544 	  && cint_248_operand (XEXP (XEXP (x, 0), 1), VOIDmode))
545 	{
546 	  *total = (rtx_cost (XEXP (XEXP (x, 0), 0),
547 			      (enum rtx_code) outer_code, opno, speed)
548 		    + rtx_cost (XEXP (x, 1),
549 				(enum rtx_code) outer_code, opno, speed)
550 		    + COSTS_N_INSNS (1));
551 	  return true;
552 	}
553       return false;
554 
555     case MULT:
556       *total = COSTS_N_INSNS (2);
557       return false;
558 
559     case DIV:
560     case UDIV:
561     case MOD:
562     case UMOD:
563       /* These are handled by software and are very expensive.  */
564       *total = COSTS_N_INSNS (100);
565       return false;
566 
567     case UNSPEC:
568     case UNSPEC_VOLATILE:
569       {
570 	int num = XINT (x, 1);
571 
572 	if (num <= TILEGX_LAST_LATENCY_1_INSN)
573 	  *total = COSTS_N_INSNS (1);
574 	else if (num <= TILEGX_LAST_LATENCY_2_INSN)
575 	  *total = COSTS_N_INSNS (2);
576 	else if (num > TILEGX_LAST_LATENCY_INSN)
577 	  {
578 	    if (num == UNSPEC_NON_TEMPORAL)
579 	      {
580 		/* These are basically loads.  */
581 		if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND)
582 		  *total = COSTS_N_INSNS (1);
583 		else
584 		  *total = COSTS_N_INSNS (2);
585 	      }
586 	    else
587 	      {
588 		if (outer_code == PLUS)
589 		  *total = 0;
590 		else
591 		  *total = COSTS_N_INSNS (1);
592 	      }
593 	  }
594 	else
595 	  {
596 	    switch (num)
597 	      {
598 	      case UNSPEC_BLOCKAGE:
599 	      case UNSPEC_NETWORK_BARRIER:
600 	      case UNSPEC_ATOMIC:
601 		*total = 0;
602 		break;
603 
604 	      case UNSPEC_LNK_AND_LABEL:
605 	      case UNSPEC_MF:
606 	      case UNSPEC_MOV_PCREL_STEP3:
607 	      case UNSPEC_NETWORK_RECEIVE:
608 	      case UNSPEC_NETWORK_SEND:
609 	      case UNSPEC_SPR_MOVE:
610 	      case UNSPEC_TLS_GD_ADD:
611 		*total = COSTS_N_INSNS (1);
612 		break;
613 
614 	      case UNSPEC_TLS_IE_LOAD:
615 	      case UNSPEC_XCHG:
616 		*total = COSTS_N_INSNS (2);
617 		break;
618 
619 	      case UNSPEC_SP_SET:
620 		*total = COSTS_N_INSNS (3);
621 		break;
622 
623 	      case UNSPEC_SP_TEST:
624 		*total = COSTS_N_INSNS (4);
625 		break;
626 
627 	      case UNSPEC_CMPXCHG:
628 	      case UNSPEC_INSN_CMPEXCH:
629 	      case UNSPEC_LATENCY_L2:
630 		*total = COSTS_N_INSNS (11);
631 		break;
632 
633 	      case UNSPEC_TLS_GD_CALL:
634 		*total = COSTS_N_INSNS (30);
635 		break;
636 
637 	      case UNSPEC_LATENCY_MISS:
638 		*total = COSTS_N_INSNS (80);
639 		break;
640 
641 	      default:
642 		*total = COSTS_N_INSNS (1);
643 	      }
644 	  }
645 	return true;
646       }
647 
648     default:
649       return false;
650     }
651 }
652 
653 
654 
655 /* Rtl lowering.  */
656 
657 /* Create a temporary variable to hold a partial result, to enable
658    CSE.  */
659 static rtx
660 create_temp_reg_if_possible (enum machine_mode mode, rtx default_reg)
661 {
662   return can_create_pseudo_p () ? gen_reg_rtx (mode) : default_reg;
663 }
664 
665 
666 /* Functions to save and restore machine-specific function data.  */
667 static struct machine_function *
668 tilegx_init_machine_status (void)
669 {
670   return ggc_alloc_cleared_machine_function ();
671 }
672 
673 
674 /* Do anything needed before RTL is emitted for each function.  */
675 void
676 tilegx_init_expanders (void)
677 {
678   /* Arrange to initialize and mark the machine per-function
679      status.  */
680   init_machine_status = tilegx_init_machine_status;
681 
682   if (cfun && cfun->machine && flag_pic)
683     {
684       static int label_num = 0;
685 
686       char text_label_name[32];
687 
688       struct machine_function *machine = cfun->machine;
689 
690       ASM_GENERATE_INTERNAL_LABEL (text_label_name, "L_PICLNK", label_num++);
691 
692       machine->text_label_symbol =
693 	gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (text_label_name));
694 
695       machine->text_label_rtx =
696 	gen_rtx_REG (Pmode, TILEGX_PIC_TEXT_LABEL_REGNUM);
697 
698       machine->got_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
699 
700       machine->calls_tls_get_addr = false;
701     }
702 }
703 
704 
705 /* Implement TARGET_EXPAND_TO_RTL_HOOK.  */
706 static void
707 tilegx_expand_to_rtl_hook (void)
708 {
709   /* Exclude earlier sets of crtl->uses_pic_offset_table, because we
710      only care about uses actually emitted.  */
711   crtl->uses_pic_offset_table = 0;
712 }
713 
714 
715 /* Implement TARGET_SHIFT_TRUNCATION_MASK.  DImode shifts use the mode
716    matching insns and therefore guarantee that the shift count is
717    modulo 64.  SImode shifts sometimes use the 64 bit version so do
718    not hold such guarantee.  */
719 static unsigned HOST_WIDE_INT
720 tilegx_shift_truncation_mask (enum machine_mode mode)
721 {
722   return mode == DImode ? 63 : 0;
723 }
724 
725 
726 /* Implement TARGET_INIT_LIBFUNCS.  */
727 static void
728 tilegx_init_libfuncs (void)
729 {
730   /* We need to explicitly generate these libfunc's to support
731      conversion of divide by constant to multiply (the divide stubs in
732      tilegx.md exist also for this reason).  Normally we'd expect gcc
733      to lazily generate them when they are needed, but for some reason
734      it's set up to only generate them if the mode is the word
735      mode.  */
736   set_optab_libfunc (sdiv_optab, SImode, "__divsi3");
737   set_optab_libfunc (udiv_optab, SImode, "__udivsi3");
738   set_optab_libfunc (smod_optab, SImode, "__modsi3");
739   set_optab_libfunc (umod_optab, SImode, "__umodsi3");
740 }
741 
742 
743 /* Return true if X contains a thread-local symbol.  */
744 static bool
745 tilegx_tls_referenced_p (rtx x)
746 {
747   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
748     x = XEXP (XEXP (x, 0), 0);
749 
750   if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
751     return true;
752 
753   /* That's all we handle in tilegx_legitimize_tls_address for
754      now.  */
755   return false;
756 }
757 
758 
759 /* Return true if X requires a scratch register.  It is given that
760    flag_pic is on and that X satisfies CONSTANT_P.  */
761 static int
762 tilegx_pic_address_needs_scratch (rtx x)
763 {
764   if (GET_CODE (x) == CONST
765       && GET_CODE (XEXP (x, 0)) == PLUS
766       && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
767 	  || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
768       && (CONST_INT_P (XEXP (XEXP (x, 0), 1))))
769     return true;
770 
771   return false;
772 }
773 
774 
775 /* Implement TARGET_LEGITIMATE_CONSTANT_P.  This is all constants for
776    which we are willing to load the value into a register via a move
777    pattern.  TLS cannot be treated as a constant because it can
778    include a function call.  */
779 static bool
780 tilegx_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
781 {
782   switch (GET_CODE (x))
783     {
784     case CONST:
785     case SYMBOL_REF:
786       return !tilegx_tls_referenced_p (x);
787 
788     default:
789       return true;
790     }
791 }
792 
793 
794 /* Return true if the constant value X is a legitimate general operand
795    when generating PIC code.  It is given that flag_pic is on and that
796    X satisfies CONSTANT_P.  */
797 bool
798 tilegx_legitimate_pic_operand_p (rtx x)
799 {
800   if (tilegx_pic_address_needs_scratch (x))
801     return false;
802 
803   if (tilegx_tls_referenced_p (x))
804     return false;
805 
806   return true;
807 }
808 
809 
810 /* Return true if the rtx X can be used as an address operand.  */
811 static bool
812 tilegx_legitimate_address_p (enum machine_mode ARG_UNUSED (mode), rtx x,
813 			     bool strict)
814 {
815   if (GET_CODE (x) == SUBREG)
816     x = SUBREG_REG (x);
817 
818   switch (GET_CODE (x))
819     {
820     case POST_INC:
821     case POST_DEC:
822       if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
823 	return false;
824 
825       x = XEXP (x, 0);
826       break;
827 
828     case POST_MODIFY:
829       if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
830 	return false;
831 
832       if (GET_CODE (XEXP (x, 1)) != PLUS)
833 	return false;
834 
835       if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
836 	return false;
837 
838       if (!satisfies_constraint_I (XEXP (XEXP (x, 1), 1)))
839 	return false;
840 
841       x = XEXP (x, 0);
842       break;
843 
844     case REG:
845       break;
846 
847     default:
848       return false;
849     }
850 
851   /* Check if x is a valid reg.  */
852   if (!REG_P (x))
853     return false;
854 
855   if (strict)
856     return REGNO_OK_FOR_BASE_P (REGNO (x));
857   else
858     return true;
859 }
860 
861 
862 /* Return the rtx containing SYMBOL_REF to the text label.  */
863 static rtx
864 tilegx_text_label_symbol (void)
865 {
866   return cfun->machine->text_label_symbol;
867 }
868 
869 
870 /* Return the register storing the value of the text label.  */
871 static rtx
872 tilegx_text_label_rtx (void)
873 {
874   return cfun->machine->text_label_rtx;
875 }
876 
877 
878 /* Return the register storing the value of the global offset
879    table.  */
880 static rtx
881 tilegx_got_rtx (void)
882 {
883   return cfun->machine->got_rtx;
884 }
885 
886 
887 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_.  */
888 static rtx
889 tilegx_got_symbol (void)
890 {
891   if (g_got_symbol == NULL)
892     g_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
893 
894   return g_got_symbol;
895 }
896 
897 
898 /* Return a reference to the got to be used by tls references.  */
899 static rtx
900 tilegx_tls_got (void)
901 {
902   rtx temp;
903   if (flag_pic)
904     {
905       crtl->uses_pic_offset_table = 1;
906       return tilegx_got_rtx ();
907     }
908 
909   temp = gen_reg_rtx (Pmode);
910   emit_move_insn (temp, tilegx_got_symbol ());
911 
912   return temp;
913 }
914 
915 
916 /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
917    this (thread-local) address.  */
918 static rtx
919 tilegx_legitimize_tls_address (rtx addr)
920 {
921   rtx ret;
922 
923   gcc_assert (can_create_pseudo_p ());
924 
925   if (GET_CODE (addr) == SYMBOL_REF)
926     switch (SYMBOL_REF_TLS_MODEL (addr))
927       {
928       case TLS_MODEL_GLOBAL_DYNAMIC:
929       case TLS_MODEL_LOCAL_DYNAMIC:
930 	{
931 	  rtx r0, temp, temp2, temp3, got, last;
932 
933 	  ret = gen_reg_rtx (Pmode);
934 	  r0 = gen_rtx_REG (Pmode, 0);
935 	  temp = gen_reg_rtx (Pmode);
936 	  temp2 = gen_reg_rtx (Pmode);
937 	  temp3 = gen_reg_rtx (Pmode);
938 
939 	  got = tilegx_tls_got ();
940 	  if (TARGET_32BIT)
941 	    {
942 	      emit_insn (gen_mov_tls_gd_step1_32bit (temp, addr));
943 	      emit_insn (gen_mov_tls_gd_step2_32bit (temp2, temp, addr));
944 	      emit_insn (gen_tls_add_32bit (temp2, got, temp2, addr));
945 	    }
946 	  else
947 	    {
948 	      emit_insn (gen_mov_tls_gd_step1 (temp, addr));
949 	      emit_insn (gen_mov_tls_gd_step2 (temp2, temp, addr));
950 	      emit_insn (gen_tls_add (temp2, got, temp2, addr));
951 	    }
952 
953 	  emit_move_insn (r0, temp2);
954 
955 	  if (TARGET_32BIT)
956 	    {
957 	      emit_insn (gen_tls_gd_call_32bit (addr));
958 	    }
959 	  else
960 	    {
961 	      emit_insn (gen_tls_gd_call (addr));
962 	    }
963 
964 	  emit_move_insn (temp3, r0);
965 
966 	  if (TARGET_32BIT)
967 	    last = emit_insn (gen_tls_gd_add_32bit (ret, temp3, addr));
968 	  else
969 	    last = emit_insn (gen_tls_gd_add (ret, temp3, addr));
970 
971 	  set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
972 	  break;
973 	}
974       case TLS_MODEL_INITIAL_EXEC:
975 	{
976 	  rtx temp, temp2, temp3, got, last;
977 
978 	  ret = gen_reg_rtx (Pmode);
979 	  temp = gen_reg_rtx (Pmode);
980 	  temp2 = gen_reg_rtx (Pmode);
981 	  temp3 = gen_reg_rtx (Pmode);
982 
983 	  got = tilegx_tls_got ();
984 	  if (TARGET_32BIT)
985 	    {
986 	      emit_insn (gen_mov_tls_ie_step1_32bit (temp, addr));
987 	      emit_insn (gen_mov_tls_ie_step2_32bit (temp2, temp, addr));
988 	      emit_insn (gen_tls_add_32bit (temp2, got, temp2, addr));
989 	      emit_insn (gen_tls_ie_load_32bit (temp3, temp2, addr));
990 	    }
991 	  else
992 	    {
993 	      emit_insn (gen_mov_tls_ie_step1 (temp, addr));
994 	      emit_insn (gen_mov_tls_ie_step2 (temp2, temp, addr));
995 	      emit_insn (gen_tls_add (temp2, got, temp2, addr));
996 	      emit_insn (gen_tls_ie_load (temp3, temp2, addr));
997 	    }
998 
999 	  last =
1000 	    emit_move_insn(ret,
1001 			   gen_rtx_PLUS (Pmode,
1002 					 gen_rtx_REG (Pmode,
1003 						      THREAD_POINTER_REGNUM),
1004 					 temp3));
1005 	  set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
1006 	  break;
1007 	}
1008       case TLS_MODEL_LOCAL_EXEC:
1009 	{
1010 	  rtx temp, temp2, last;
1011 
1012 	  ret = gen_reg_rtx (Pmode);
1013 	  temp = gen_reg_rtx (Pmode);
1014 	  temp2 = gen_reg_rtx (Pmode);
1015 
1016 	  if (TARGET_32BIT)
1017 	    {
1018 	      emit_insn (gen_mov_tls_le_step1_32bit (temp, addr));
1019 	      emit_insn (gen_mov_tls_le_step2_32bit (temp2, temp, addr));
1020 	    }
1021 	  else
1022 	    {
1023 	      emit_insn (gen_mov_tls_le_step1 (temp, addr));
1024 	      emit_insn (gen_mov_tls_le_step2 (temp2, temp, addr));
1025 	    }
1026 
1027 	  last =
1028 	    emit_move_insn (ret,
1029 			    gen_rtx_PLUS (Pmode,
1030 					  gen_rtx_REG (Pmode,
1031 						       THREAD_POINTER_REGNUM),
1032 					  temp2));
1033 	  set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
1034 	  break;
1035 	}
1036       default:
1037 	gcc_unreachable ();
1038       }
1039   else if (GET_CODE (addr) == CONST)
1040     {
1041       rtx base, offset;
1042 
1043       gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
1044 
1045       base = tilegx_legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
1046       offset = XEXP (XEXP (addr, 0), 1);
1047 
1048       base = force_operand (base, NULL_RTX);
1049       ret = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
1050     }
1051   else
1052     gcc_unreachable ();
1053 
1054   return ret;
1055 }
1056 
1057 
1058 /* Returns a register that points to ADDR, a symbolic address, by
1059    computing its address relative to tilegx_text_label_symbol.  */
1060 void
1061 tilegx_compute_pcrel_address (rtx result, rtx addr)
1062 {
1063   rtx text_label_symbol = tilegx_text_label_symbol ();
1064   rtx text_label_rtx = tilegx_text_label_rtx ();
1065   rtx temp, temp2, temp3;
1066 
1067   temp = create_temp_reg_if_possible (Pmode, result);
1068   temp2 = create_temp_reg_if_possible (Pmode, result);
1069 
1070   if (TARGET_32BIT)
1071     {
1072       emit_insn (gen_mov_pcrel_step1_32bit (temp, addr, text_label_symbol));
1073       emit_insn (gen_mov_pcrel_step2_32bit (temp2, temp, addr,
1074 					    text_label_symbol));
1075       emit_insn (gen_mov_pcrel_step3_32bit (result, temp2,
1076 					    text_label_rtx,
1077 					    addr, text_label_symbol));
1078     }
1079   else if (tilegx_cmodel == CM_LARGE_PIC)
1080     {
1081       temp3 = create_temp_reg_if_possible (Pmode, result);
1082       emit_insn (gen_mov_large_pcrel_step1 (temp, addr, text_label_symbol));
1083       emit_insn (gen_mov_large_pcrel_step2 (temp2, temp, addr,
1084 					    text_label_symbol));
1085       emit_insn (gen_mov_large_pcrel_step3 (temp3, temp2, addr,
1086 					    text_label_symbol));
1087       emit_insn (gen_mov_large_pcrel_step4 (result, temp3,
1088 					    text_label_rtx,
1089 					    addr, text_label_symbol));
1090     }
1091   else
1092     {
1093       emit_insn (gen_mov_pcrel_step1 (temp, addr, text_label_symbol));
1094       emit_insn (gen_mov_pcrel_step2 (temp2, temp, addr, text_label_symbol));
1095       emit_insn (gen_mov_pcrel_step3 (result, temp2,
1096 				      text_label_rtx,
1097 				      addr, text_label_symbol));
1098     }
1099 }
1100 
1101 
1102 /* Returns a register that points to the plt entry of ADDR, a symbolic
1103    address, by computing its address relative to
1104    tilegx_text_label_symbol.  */
1105 void
1106 tilegx_compute_pcrel_plt_address (rtx result, rtx addr)
1107 {
1108   rtx text_label_symbol = tilegx_text_label_symbol ();
1109   rtx text_label_rtx = tilegx_text_label_rtx ();
1110   rtx temp, temp2, temp3;
1111 
1112   temp = create_temp_reg_if_possible (Pmode, result);
1113   temp2 = create_temp_reg_if_possible (Pmode, result);
1114 
1115   if (TARGET_32BIT)
1116     {
1117       emit_insn (gen_mov_plt_pcrel_step1_32bit (temp, addr,
1118 						text_label_symbol));
1119       emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2, temp, addr,
1120 						text_label_symbol));
1121       emit_move_insn (result, gen_rtx_PLUS (Pmode, temp2, text_label_rtx));
1122     }
1123   else
1124     {
1125       temp3 = create_temp_reg_if_possible (Pmode, result);
1126 
1127       emit_insn (gen_mov_plt_pcrel_step1 (temp, addr, text_label_symbol));
1128       emit_insn (gen_mov_plt_pcrel_step2 (temp2, temp, addr,
1129 					  text_label_symbol));
1130       emit_insn (gen_mov_plt_pcrel_step3 (temp3, temp2, addr,
1131 					  text_label_symbol));
1132       emit_move_insn (result, gen_rtx_PLUS (Pmode, temp3, text_label_rtx));
1133     }
1134 }
1135 
1136 
1137 /* Legitimize PIC addresses.  If the address is already
1138    position-independent, we return ORIG.  Newly generated
1139    position-independent addresses go into a reg.  This is REG if
1140    nonzero, otherwise we allocate register(s) as necessary.  */
1141 static rtx
1142 tilegx_legitimize_pic_address (rtx orig,
1143 			       enum machine_mode mode ATTRIBUTE_UNUSED,
1144 			       rtx reg)
1145 {
1146   if (GET_CODE (orig) == SYMBOL_REF)
1147     {
1148       rtx address, pic_ref;
1149 
1150       if (reg == 0)
1151 	{
1152 	  gcc_assert (can_create_pseudo_p ());
1153 	  reg = gen_reg_rtx (Pmode);
1154 	}
1155 
1156       if (SYMBOL_REF_LOCAL_P (orig))
1157 	{
1158 	  /* If not during reload, allocate another temp reg here for
1159 	     loading in the address, so that these instructions can be
1160 	     optimized properly.  */
1161 	  rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
1162 	  tilegx_compute_pcrel_address (temp_reg, orig);
1163 
1164 	  /* Note: this is conservative.  We use the text_label but we
1165 	     don't use the pic_offset_table.  However, in some cases
1166 	     we may need the pic_offset_table (see
1167 	     tilegx_fixup_pcrel_references).  */
1168 	  crtl->uses_pic_offset_table = 1;
1169 
1170 	  address = temp_reg;
1171 
1172 	  emit_move_insn (reg, address);
1173 	  return reg;
1174 	}
1175       else
1176 	{
1177 	  /* If not during reload, allocate another temp reg here for
1178 	     loading in the address, so that these instructions can be
1179 	     optimized properly.  */
1180 	  rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
1181 
1182 	  gcc_assert (flag_pic);
1183 	  if (flag_pic == 1)
1184 	    {
1185 	      if (TARGET_32BIT)
1186 		{
1187 		  emit_insn (gen_add_got16_32bit (temp_reg,
1188 						  tilegx_got_rtx (),
1189 						  orig));
1190 		}
1191 	      else
1192 		{
1193 		  emit_insn (gen_add_got16 (temp_reg,
1194 					    tilegx_got_rtx (), orig));
1195 		}
1196 	    }
1197 	  else
1198 	    {
1199 	      rtx temp_reg2 = create_temp_reg_if_possible (Pmode, reg);
1200 	      rtx temp_reg3 = create_temp_reg_if_possible (Pmode, reg);
1201 	      if (TARGET_32BIT)
1202 		{
1203 		  emit_insn (gen_mov_got32_step1_32bit (temp_reg3, orig));
1204 		  emit_insn (gen_mov_got32_step2_32bit
1205 			     (temp_reg2, temp_reg3, orig));
1206 		}
1207 	      else
1208 		{
1209 		  emit_insn (gen_mov_got32_step1 (temp_reg3, orig));
1210 		  emit_insn (gen_mov_got32_step2 (temp_reg2, temp_reg3,
1211 						  orig));
1212 		}
1213 	      emit_move_insn (temp_reg,
1214 			      gen_rtx_PLUS (Pmode,
1215 					    tilegx_got_rtx (), temp_reg2));
1216 	    }
1217 
1218 	  address = temp_reg;
1219 
1220 	  pic_ref = gen_const_mem (Pmode, address);
1221 	  crtl->uses_pic_offset_table = 1;
1222 	  emit_move_insn (reg, pic_ref);
1223 	  /* The following put a REG_EQUAL note on this insn, so that
1224 	     it can be optimized by loop.  But it causes the label to
1225 	     be optimized away.  */
1226 	  /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1227 	  return reg;
1228 	}
1229     }
1230   else if (GET_CODE (orig) == CONST)
1231     {
1232       rtx base, offset;
1233 
1234       if (GET_CODE (XEXP (orig, 0)) == PLUS
1235 	  && XEXP (XEXP (orig, 0), 0) == tilegx_got_rtx ())
1236 	return orig;
1237 
1238       if (reg == 0)
1239 	{
1240 	  gcc_assert (can_create_pseudo_p ());
1241 	  reg = gen_reg_rtx (Pmode);
1242 	}
1243 
1244       gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
1245       base = tilegx_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
1246 					    Pmode, reg);
1247       offset = tilegx_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
1248 					      base == reg ? 0 : reg);
1249 
1250       if (CONST_INT_P (offset))
1251 	{
1252 	  if (can_create_pseudo_p ())
1253 	    offset = force_reg (Pmode, offset);
1254 	  else
1255 	    /* If we reach here, then something is seriously wrong.  */
1256 	    gcc_unreachable ();
1257 	}
1258 
1259       if (can_create_pseudo_p ())
1260 	return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
1261       else
1262 	gcc_unreachable ();
1263     }
1264   else if (GET_CODE (orig) == LABEL_REF)
1265     {
1266       rtx address;
1267       rtx temp_reg;
1268 
1269       if (reg == 0)
1270 	{
1271 	  gcc_assert (can_create_pseudo_p ());
1272 	  reg = gen_reg_rtx (Pmode);
1273 	}
1274 
1275       /* If not during reload, allocate another temp reg here for
1276 	 loading in the address, so that these instructions can be
1277 	 optimized properly.  */
1278       temp_reg = create_temp_reg_if_possible (Pmode, reg);
1279       tilegx_compute_pcrel_address (temp_reg, orig);
1280 
1281       /* Note: this is conservative.  We use the text_label but we
1282 	 don't use the pic_offset_table.  */
1283       crtl->uses_pic_offset_table = 1;
1284 
1285       address = temp_reg;
1286 
1287       emit_move_insn (reg, address);
1288 
1289       return reg;
1290     }
1291 
1292   return orig;
1293 }
1294 
1295 
1296 /* Implement TARGET_LEGITIMIZE_ADDRESS.  */
1297 static rtx
1298 tilegx_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1299 			   enum machine_mode mode)
1300 {
1301   if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
1302       && symbolic_operand (x, Pmode) && tilegx_tls_referenced_p (x))
1303     {
1304       return tilegx_legitimize_tls_address (x);
1305     }
1306   else if (flag_pic)
1307     {
1308       return tilegx_legitimize_pic_address (x, mode, 0);
1309     }
1310   else
1311     return x;
1312 }
1313 
1314 
1315 /* Implement TARGET_DELEGITIMIZE_ADDRESS.  */
1316 static rtx
1317 tilegx_delegitimize_address (rtx x)
1318 {
1319   x = delegitimize_mem_from_attrs (x);
1320 
1321   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC)
1322     {
1323       switch (XINT (XEXP (x, 0), 1))
1324 	{
1325 	  case UNSPEC_HW0:
1326 	  case UNSPEC_HW1:
1327 	  case UNSPEC_HW2:
1328 	  case UNSPEC_HW3:
1329 	  case UNSPEC_HW0_LAST:
1330 	  case UNSPEC_HW1_LAST:
1331 	  case UNSPEC_HW2_LAST:
1332 	  case UNSPEC_HW0_PCREL:
1333 	  case UNSPEC_HW1_PCREL:
1334 	  case UNSPEC_HW1_LAST_PCREL:
1335 	  case UNSPEC_HW2_LAST_PCREL:
1336 	  case UNSPEC_HW0_PLT_PCREL:
1337 	  case UNSPEC_HW1_PLT_PCREL:
1338 	  case UNSPEC_HW1_LAST_PLT_PCREL:
1339 	  case UNSPEC_HW2_LAST_PLT_PCREL:
1340 	  case UNSPEC_HW0_GOT:
1341 	  case UNSPEC_HW0_LAST_GOT:
1342   	  case UNSPEC_HW1_LAST_GOT:
1343   	  case UNSPEC_HW0_TLS_GD:
1344   	  case UNSPEC_HW1_LAST_TLS_GD:
1345   	  case UNSPEC_HW0_TLS_IE:
1346   	  case UNSPEC_HW1_LAST_TLS_IE:
1347   	  case UNSPEC_HW0_TLS_LE:
1348   	  case UNSPEC_HW1_LAST_TLS_LE:
1349 	    x = XVECEXP (XEXP (x, 0), 0, 0);
1350 	  break;
1351 	}
1352     }
1353 
1354   return x;
1355 }
1356 
1357 
1358 /* Emit code to load the PIC register.  */
1359 static void
1360 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED)
1361 {
1362   int orig_flag_pic = flag_pic;
1363 
1364   rtx got_symbol = tilegx_got_symbol ();
1365   rtx text_label_symbol = tilegx_text_label_symbol ();
1366   rtx text_label_rtx = tilegx_text_label_rtx ();
1367   flag_pic = 0;
1368 
1369   if (TARGET_32BIT)
1370     {
1371       emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx,
1372 					       text_label_symbol));
1373     }
1374   else
1375     {
1376       emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol));
1377     }
1378 
1379   tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol);
1380 
1381   flag_pic = orig_flag_pic;
1382 
1383   /* Need to emit this whether or not we obey regdecls, since
1384      setjmp/longjmp can cause life info to screw up.  ??? In the case
1385      where we don't obey regdecls, this is not sufficient since we may
1386      not fall out the bottom.  */
1387   emit_use (tilegx_got_rtx ());
1388 }
1389 
1390 
1391 /* Return the simd variant of the constant NUM of mode MODE, by
1392    replicating it to fill an interger of mode DImode.  NUM is first
1393    truncated to fit in MODE.  */
1394 rtx
1395 tilegx_simd_int (rtx num, enum machine_mode mode)
1396 {
1397   HOST_WIDE_INT n = 0;
1398 
1399   gcc_assert (CONST_INT_P (num));
1400 
1401   n = INTVAL (num);
1402 
1403   switch (mode)
1404     {
1405     case QImode:
1406       n = 0x0101010101010101LL * (n & 0x000000FF);
1407       break;
1408     case HImode:
1409       n = 0x0001000100010001LL * (n & 0x0000FFFF);
1410       break;
1411     case SImode:
1412       n = 0x0000000100000001LL * (n & 0xFFFFFFFF);
1413       break;
1414     case DImode:
1415       break;
1416     default:
1417       gcc_unreachable ();
1418     }
1419 
1420   return GEN_INT (n);
1421 }
1422 
1423 
1424 /* Returns true iff VAL can be moved into a register in one
1425    instruction.  And if it can, it emits the code to move the constant
1426    into DEST_REG.
1427 
1428    If THREE_WIDE_ONLY is true, this insists on an instruction that
1429    works in a bundle containing three instructions.  */
1430 static bool
1431 expand_set_cint64_one_inst (rtx dest_reg,
1432 			    HOST_WIDE_INT val, bool three_wide_only)
1433 {
1434   if (val == trunc_int_for_mode (val, QImode))
1435     {
1436       /* Success! */
1437       emit_move_insn (dest_reg, GEN_INT (val));
1438       return true;
1439     }
1440   else if (!three_wide_only)
1441     {
1442       /* Test for the following constraints: J, K, N, P.  We avoid
1443 	 generating an rtx and using existing predicates because we
1444 	 can be testing and rejecting a lot of constants, and GEN_INT
1445 	 is O(N).  */
1446       if ((val >= -32768 && val <= 65535)
1447 	  || ((val == (val & 0xFF) * 0x0101010101010101LL))
1448 	  || (val == ((trunc_int_for_mode (val, QImode) & 0xFFFF)
1449 		      * 0x0001000100010001LL)))
1450 	{
1451 	  emit_move_insn (dest_reg, GEN_INT (val));
1452 	  return true;
1453 	}
1454     }
1455 
1456   return false;
1457 }
1458 
1459 
1460 /* Implement DImode rotatert.  */
1461 static HOST_WIDE_INT
1462 rotate_right (HOST_WIDE_INT n, int count)
1463 {
1464   unsigned HOST_WIDE_INT x = n & 0xFFFFFFFFFFFFFFFFULL;
1465   if (count == 0)
1466     return x;
1467   return ((x >> count) | (x << (64 - count))) & 0xFFFFFFFFFFFFFFFFULL;
1468 }
1469 
1470 
1471 /* Return true iff n contains exactly one contiguous sequence of 1
1472    bits, possibly wrapping around from high bits to low bits.  */
1473 bool
1474 tilegx_bitfield_operand_p (HOST_WIDE_INT n, int *first_bit, int *last_bit)
1475 {
1476   int i;
1477 
1478   if (n == 0)
1479     return false;
1480 
1481   for (i = 0; i < 64; i++)
1482     {
1483       unsigned HOST_WIDE_INT x = rotate_right (n, i);
1484       if (!(x & 1))
1485 	continue;
1486 
1487       /* See if x is a power of two minus one, i.e. only consecutive 1
1488 	 bits starting from bit 0.  */
1489       if ((x & (x + 1)) == 0)
1490 	{
1491 	  if (first_bit != NULL)
1492 	    *first_bit = i;
1493 	  if (last_bit != NULL)
1494 	    *last_bit = (i + exact_log2 (x ^ (x >> 1))) & 63;
1495 
1496 	  return true;
1497 	}
1498     }
1499 
1500   return false;
1501 }
1502 
1503 
1504 /* Create code to move the CONST_INT value in src_val to dest_reg.  */
1505 static void
1506 expand_set_cint64 (rtx dest_reg, rtx src_val)
1507 {
1508   HOST_WIDE_INT val;
1509   int leading_zeroes, trailing_zeroes;
1510   int three_wide_only;
1511   int shift, ins_shift, zero_cluster_shift;
1512   rtx temp, subreg;
1513 
1514   gcc_assert (CONST_INT_P (src_val));
1515   val = trunc_int_for_mode (INTVAL (src_val), GET_MODE (dest_reg));
1516 
1517   /* See if we can generate the constant in one instruction.  */
1518   if (expand_set_cint64_one_inst (dest_reg, val, false))
1519     return;
1520 
1521   /* Force the destination to DImode so we can use DImode instructions
1522      to create it.  This both allows instructions like rotl, and
1523      certain efficient 3-wide instructions.  */
1524   subreg = simplify_gen_subreg (DImode, dest_reg, GET_MODE (dest_reg), 0);
1525   gcc_assert (subreg != NULL);
1526   dest_reg = subreg;
1527 
1528   temp = create_temp_reg_if_possible (DImode, dest_reg);
1529 
1530   leading_zeroes = 63 - floor_log2 (val & 0xFFFFFFFFFFFFFFFFULL);
1531   trailing_zeroes = exact_log2 (val & -val);
1532 
1533   /* First try all three-wide instructions that generate a constant
1534      (i.e. movei) followed by various shifts and rotates. If none of
1535      those work, try various two-wide ways of generating a constant
1536      followed by various shifts and rotates.  */
1537   for (three_wide_only = 1; three_wide_only >= 0; three_wide_only--)
1538     {
1539       int count;
1540 
1541       if (expand_set_cint64_one_inst (temp, val >> trailing_zeroes,
1542 				      three_wide_only))
1543 	{
1544 	  /* 0xFFFFFFFFFFFFA500 becomes:
1545 	     movei temp, 0xFFFFFFFFFFFFFFA5
1546 	     shli dest, temp, 8  */
1547 	  emit_move_insn (dest_reg,
1548 			  gen_rtx_ASHIFT (DImode, temp,
1549 					  GEN_INT (trailing_zeroes)));
1550 	  return;
1551 	}
1552 
1553       if (expand_set_cint64_one_inst (temp, val << leading_zeroes,
1554 				      three_wide_only))
1555 	{
1556 	  /* 0x7FFFFFFFFFFFFFFF becomes:
1557 	     movei temp, -2
1558 	     shrui dest, temp, 1  */
1559 	  emit_move_insn (dest_reg,
1560 			  gen_rtx_LSHIFTRT (DImode, temp,
1561 					    GEN_INT (leading_zeroes)));
1562 	  return;
1563 	}
1564 
1565       /* Try rotating a one-instruction immediate.  */
1566       for (count = 1; count < 64; count++)
1567 	{
1568 	  HOST_WIDE_INT r = rotate_right (val, count);
1569 	  if (expand_set_cint64_one_inst (temp, r, three_wide_only))
1570 	    {
1571 	      /* 0xFFFFFFFFFFA5FFFF becomes:
1572 		 movei temp, 0xFFFFFFFFFFFFFFA5
1573 		 rotli dest, temp, 16  */
1574 	      emit_move_insn (dest_reg,
1575 			      gen_rtx_ROTATE (DImode, temp, GEN_INT (count)));
1576 	      return;
1577 	    }
1578 	}
1579     }
1580 
1581   /* There are two cases here to produce a large constant.
1582      In the most general case, we do this:
1583 
1584      moveli x, hw3(NUM)
1585      shl16insli x, x, hw2(NUM)
1586      shl16insli x, x, hw1(NUM)
1587      shl16insli x, x, hw0(NUM)
1588 
1589      However, we can sometimes do better.  shl16insli is a poor way to
1590      insert 16 zero bits, because simply shifting left by 16 has more
1591      bundling freedom.  So if we see any contiguous aligned sequence
1592      of 16 or more zero bits (below the highest set bit), it is always
1593      more efficient to materialize the bits above the zero bits, then
1594      left shift to put in the zeroes, then insert whatever bits
1595      remain.  For example, we might end up with:
1596 
1597      movei x, NUM >> (37 + 16)
1598      shli x, x, 37
1599      shl16insli x, x, hw0(NUM)      */
1600 
1601   zero_cluster_shift = -1;
1602 
1603   for (shift = 0; shift < 48 - leading_zeroes; shift += 16)
1604     {
1605       HOST_WIDE_INT x = val >> shift;
1606 
1607       /* Find the least significant group of 16 aligned zero bits.  */
1608       if ((x & 0xFFFF) == 0x0000)
1609 	{
1610 	  /* Grab any following zero bits as well.  */
1611 	  zero_cluster_shift = exact_log2 (x & -x);
1612 	  shift += zero_cluster_shift;
1613 	  break;
1614 	}
1615     }
1616 
1617   if (zero_cluster_shift >= 0)
1618     {
1619       unsigned HOST_WIDE_INT leftover;
1620 
1621       /* Recursively create the constant above the lowest 16 zero
1622 	 bits.  */
1623       expand_set_cint64 (temp, GEN_INT (val >> shift));
1624 
1625       /* See if we can easily insert the remaining bits, or if we need
1626 	 to fall through to the more general case.  */
1627       leftover = val - ((val >> shift) << shift);
1628       if (leftover == 0)
1629 	{
1630 	  /* A simple left shift is enough.  */
1631 	  emit_move_insn (dest_reg,
1632 			  gen_rtx_ASHIFT (DImode, temp, GEN_INT (shift)));
1633 	  return;
1634 	}
1635       else if (leftover <= 32767)
1636 	{
1637 	  /* Left shift into position then add in the leftover.  */
1638 	  rtx temp2 = create_temp_reg_if_possible (DImode, temp);
1639 	  emit_move_insn (temp2,
1640 			  gen_rtx_ASHIFT (DImode, temp, GEN_INT (shift)));
1641 	  emit_move_insn (dest_reg,
1642 			  gen_rtx_PLUS (DImode, temp2, GEN_INT (leftover)));
1643 	  return;
1644 	}
1645       else
1646 	{
1647 	  /* Shift in the batch of >= 16 zeroes we detected earlier.
1648 	     After this, shift will be aligned mod 16 so the final
1649 	     loop can use shl16insli.  */
1650 	  rtx temp2 = create_temp_reg_if_possible (DImode, temp);
1651 	  rtx shift_count_rtx = GEN_INT (zero_cluster_shift);
1652 
1653 	  emit_move_insn (temp2,
1654 			  gen_rtx_ASHIFT (DImode, temp, shift_count_rtx));
1655 
1656 	  shift -= zero_cluster_shift;
1657 	  temp = temp2;
1658 	}
1659     }
1660   else
1661     {
1662       /* Set as many high 16-bit blocks as we can with a single
1663 	 instruction.  We'll insert the remaining 16-bit blocks
1664 	 below.  */
1665       for (shift = 16;; shift += 16)
1666 	{
1667 	  gcc_assert (shift < 64);
1668 	  if (expand_set_cint64_one_inst (temp, val >> shift, false))
1669 	    break;
1670 	}
1671     }
1672 
1673   /* At this point, temp == val >> shift, shift % 16 == 0, and we
1674      still need to insert any bits of 'val' below 'shift'. Those bits
1675      are guaranteed to not have 16 contiguous zeroes.  */
1676 
1677   gcc_assert ((shift & 15) == 0);
1678 
1679   for (ins_shift = shift - 16; ins_shift >= 0; ins_shift -= 16)
1680     {
1681       rtx result;
1682       HOST_WIDE_INT bits = (val >> ins_shift) & 0xFFFF;
1683       gcc_assert (bits != 0);
1684 
1685       /* On the last iteration we need to store into dest_reg.  */
1686       if (ins_shift == 0)
1687 	result = dest_reg;
1688       else
1689 	result = create_temp_reg_if_possible (DImode, dest_reg);
1690 
1691       emit_insn (gen_insn_shl16insli (result, temp, GEN_INT (bits)));
1692 
1693       temp = result;
1694     }
1695 }
1696 
1697 
1698 /* Load OP1, a 64-bit constant, into OP0, a register.  We know it
1699    can't be done in one insn when we get here, the move expander
1700    guarantees this.  */
1701 void
1702 tilegx_expand_set_const64 (rtx op0, rtx op1)
1703 {
1704   if (CONST_INT_P (op1))
1705     {
1706       /* TODO: I don't know if we want to split large constants
1707 	 now, or wait until later (with a define_split).
1708 
1709 	 Does splitting early help CSE?  Does it harm other
1710 	 optimizations that might fold loads?  */
1711       expand_set_cint64 (op0, op1);
1712     }
1713   else
1714     {
1715       rtx temp = create_temp_reg_if_possible (Pmode, op0);
1716 
1717       if (TARGET_32BIT)
1718 	{
1719 	  /* Generate the 2-insn sequence to materialize a symbolic
1720 	     address.  */
1721 	  emit_insn (gen_mov_address_32bit_step1 (temp, op1));
1722 	  emit_insn (gen_mov_address_32bit_step2 (op0, temp, op1));
1723 	}
1724       else
1725 	{
1726 	  /* Generate the 3-insn sequence to materialize a symbolic
1727 	     address.  Note that this assumes that virtual addresses
1728 	     fit in 48 signed bits, which is currently true.  */
1729 	  rtx temp2 = create_temp_reg_if_possible (Pmode, op0);
1730 	  emit_insn (gen_mov_address_step1 (temp, op1));
1731 	  emit_insn (gen_mov_address_step2 (temp2, temp, op1));
1732 	  emit_insn (gen_mov_address_step3 (op0, temp2, op1));
1733 	}
1734     }
1735 }
1736 
1737 
1738 /* Expand a move instruction.  Return true if all work is done.  */
1739 bool
1740 tilegx_expand_mov (enum machine_mode mode, rtx *operands)
1741 {
1742   /* Handle sets of MEM first.  */
1743   if (MEM_P (operands[0]))
1744     {
1745       if (can_create_pseudo_p ())
1746 	operands[0] = validize_mem (operands[0]);
1747 
1748       if (reg_or_0_operand (operands[1], mode))
1749 	return false;
1750 
1751       if (!reload_in_progress)
1752 	operands[1] = force_reg (mode, operands[1]);
1753     }
1754 
1755   /* Fixup TLS cases.  */
1756   if (CONSTANT_P (operands[1]) && tilegx_tls_referenced_p (operands[1]))
1757     {
1758       operands[1] = tilegx_legitimize_tls_address (operands[1]);
1759       return false;
1760     }
1761 
1762   /* Fixup PIC cases.  */
1763   if (flag_pic && CONSTANT_P (operands[1]))
1764     {
1765       if (tilegx_pic_address_needs_scratch (operands[1]))
1766 	operands[1] = tilegx_legitimize_pic_address (operands[1], mode, 0);
1767 
1768       if (symbolic_operand (operands[1], mode))
1769 	{
1770 	  operands[1] = tilegx_legitimize_pic_address (operands[1],
1771 						       mode,
1772 						       (reload_in_progress ?
1773 							operands[0] :
1774 							NULL_RTX));
1775 	  return false;
1776 	}
1777     }
1778 
1779   /* Accept non-constants and valid constants unmodified.  */
1780   if (!CONSTANT_P (operands[1]) || move_operand (operands[1], mode))
1781     return false;
1782 
1783   /* Split large integers.  */
1784   tilegx_expand_set_const64 (operands[0], operands[1]);
1785   return true;
1786 }
1787 
1788 
1789 /* Expand unaligned loads.  */
1790 void
1791 tilegx_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize,
1792 			      HOST_WIDE_INT bit_offset, bool sign)
1793 {
1794   enum machine_mode mode;
1795   rtx addr_lo, addr_hi;
1796   rtx mem_lo, mem_hi, hi;
1797   rtx mema, wide_result;
1798   int last_byte_offset;
1799   HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1800 
1801   mode = GET_MODE (dest_reg);
1802 
1803   hi = gen_reg_rtx (mode);
1804 
1805   if (bitsize == 2 * BITS_PER_UNIT && (bit_offset % BITS_PER_UNIT) == 0)
1806     {
1807       /* When just loading a two byte value, we can load the two bytes
1808 	 individually and combine them efficiently.  */
1809 
1810       mem_lo = adjust_address (mem, QImode, byte_offset);
1811       mem_hi = adjust_address (mem, QImode, byte_offset + 1);
1812 
1813       if (sign)
1814 	{
1815 	  /* Do a signed load of the second byte and use bfins to set
1816 	     the high bits of the result.  */
1817 	  emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, dest_reg),
1818 					   mem_lo));
1819 	  emit_insn (gen_extendqidi2 (gen_lowpart (DImode, hi), mem_hi));
1820 	  emit_insn (gen_insv (gen_lowpart (DImode, dest_reg),
1821 			       GEN_INT (64 - 8), GEN_INT (8),
1822 			       gen_lowpart (DImode, hi)));
1823 	}
1824       else
1825 	{
1826 	  /* Do two unsigned loads and use v1int_l to interleave
1827 	     them.  */
1828 	  rtx lo = gen_reg_rtx (mode);
1829 	  emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, lo),
1830 					   mem_lo));
1831 	  emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, hi),
1832 					   mem_hi));
1833 	  emit_insn (gen_insn_v1int_l (gen_lowpart (DImode, dest_reg),
1834 				       gen_lowpart (DImode, hi),
1835 				       gen_lowpart (DImode, lo)));
1836 	}
1837 
1838       return;
1839     }
1840 
1841   mema = XEXP (mem, 0);
1842 
1843   /* AND addresses cannot be in any alias set, since they may
1844      implicitly alias surrounding code.  Ideally we'd have some alias
1845      set that covered all types except those with alignment 8 or
1846      higher.  */
1847   addr_lo = force_reg (Pmode, plus_constant (Pmode, mema, byte_offset));
1848   mem_lo = change_address (mem, mode,
1849 			   gen_rtx_AND (GET_MODE (mema), addr_lo,
1850 					GEN_INT (-8)));
1851   set_mem_alias_set (mem_lo, 0);
1852 
1853   /* Load the high word at an address that will not fault if the low
1854      address is aligned and at the very end of a page.  */
1855   last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT;
1856   addr_hi = force_reg (Pmode, plus_constant (Pmode, mema, last_byte_offset));
1857   mem_hi = change_address (mem, mode,
1858 			   gen_rtx_AND (GET_MODE (mema), addr_hi,
1859 					GEN_INT (-8)));
1860   set_mem_alias_set (mem_hi, 0);
1861 
1862   if (bitsize == 64)
1863     {
1864       addr_lo = make_safe_from (addr_lo, dest_reg);
1865       wide_result = dest_reg;
1866     }
1867   else
1868     {
1869       wide_result = gen_reg_rtx (mode);
1870     }
1871 
1872   /* Load hi first in case dest_reg is used in mema.  */
1873   emit_move_insn (hi, mem_hi);
1874   emit_move_insn (wide_result, mem_lo);
1875 
1876   emit_insn (gen_insn_dblalign (gen_lowpart (DImode, wide_result),
1877 				gen_lowpart (DImode, wide_result),
1878 				gen_lowpart (DImode, hi), addr_lo));
1879 
1880   if (bitsize != 64)
1881     {
1882       rtx extracted =
1883 	extract_bit_field (gen_lowpart (DImode, wide_result),
1884 			   bitsize, bit_offset % BITS_PER_UNIT,
1885 			   !sign, false, gen_lowpart (DImode, dest_reg),
1886 			   DImode, DImode);
1887 
1888       if (extracted != dest_reg)
1889 	emit_move_insn (dest_reg, gen_lowpart (DImode, extracted));
1890     }
1891 }
1892 
1893 
1894 /* Expand unaligned stores.  */
1895 static void
1896 tilegx_expand_unaligned_store (rtx mem, rtx src, HOST_WIDE_INT bitsize,
1897 			       HOST_WIDE_INT bit_offset)
1898 {
1899   HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1900   HOST_WIDE_INT bytesize = bitsize / BITS_PER_UNIT;
1901   HOST_WIDE_INT shift_amt;
1902   HOST_WIDE_INT i;
1903   rtx mem_addr;
1904   rtx store_val;
1905 
1906   for (i = 0, shift_amt = 0; i < bytesize; i++, shift_amt += BITS_PER_UNIT)
1907     {
1908       mem_addr = adjust_address (mem, QImode, byte_offset + i);
1909 
1910       if (shift_amt)
1911 	{
1912 	  store_val = expand_simple_binop (DImode, LSHIFTRT,
1913 					   gen_lowpart (DImode, src),
1914 					   GEN_INT (shift_amt), NULL, 1,
1915 					   OPTAB_LIB_WIDEN);
1916 	  store_val = gen_lowpart (QImode, store_val);
1917 	}
1918       else
1919 	{
1920 	  store_val = gen_lowpart (QImode, src);
1921 	}
1922 
1923       emit_move_insn (mem_addr, store_val);
1924     }
1925 }
1926 
1927 
1928 /* Implement the movmisalign patterns.  One of the operands is a
1929    memory that is not naturally aligned.  Emit instructions to load
1930    it.  */
1931 void
1932 tilegx_expand_movmisalign (enum machine_mode mode, rtx *operands)
1933 {
1934   if (MEM_P (operands[1]))
1935     {
1936       rtx tmp;
1937 
1938       if (register_operand (operands[0], mode))
1939 	tmp = operands[0];
1940       else
1941 	tmp = gen_reg_rtx (mode);
1942 
1943       tilegx_expand_unaligned_load (tmp, operands[1], GET_MODE_BITSIZE (mode),
1944 				    0, true);
1945 
1946       if (tmp != operands[0])
1947 	emit_move_insn (operands[0], tmp);
1948     }
1949   else if (MEM_P (operands[0]))
1950     {
1951       if (!reg_or_0_operand (operands[1], mode))
1952 	operands[1] = force_reg (mode, operands[1]);
1953 
1954       tilegx_expand_unaligned_store (operands[0], operands[1],
1955 				     GET_MODE_BITSIZE (mode), 0);
1956     }
1957   else
1958     gcc_unreachable ();
1959 
1960 }
1961 
1962 
1963 /* Implement the allocate_stack pattern (alloca).  */
1964 void
1965 tilegx_allocate_stack (rtx op0, rtx op1)
1966 {
1967   /* Technically the correct way to initialize chain_loc is with
1968    * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
1969    * sets the alias_set to that of a frame reference.  Some of our
1970    * tests rely on some unsafe assumption about when the chaining
1971    * update is done, we need to be conservative about reordering the
1972    * chaining instructions.
1973    */
1974   rtx fp_addr = gen_reg_rtx (Pmode);
1975   rtx fp_value = gen_reg_rtx (Pmode);
1976   rtx fp_loc;
1977 
1978   emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1979 					 GEN_INT (UNITS_PER_WORD)));
1980 
1981   fp_loc = gen_frame_mem (Pmode, fp_addr);
1982 
1983   emit_move_insn (fp_value, fp_loc);
1984 
1985   op1 = force_reg (Pmode, op1);
1986 
1987   emit_move_insn (stack_pointer_rtx,
1988 		  gen_rtx_MINUS (Pmode, stack_pointer_rtx, op1));
1989 
1990   emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1991 					 GEN_INT (UNITS_PER_WORD)));
1992 
1993   fp_loc = gen_frame_mem (Pmode, fp_addr);
1994 
1995   emit_move_insn (fp_loc, fp_value);
1996 
1997   emit_move_insn (op0, virtual_stack_dynamic_rtx);
1998 }
1999 
2000 
2001 
2002 /* Multiplies */
2003 
2004 
2005 /* Returns the insn_code in ENTRY.  */
2006 static enum insn_code
2007 tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry
2008 			    *entry)
2009 {
2010   return tilegx_multiply_insn_seq_decode_opcode[entry->compressed_opcode];
2011 }
2012 
2013 
2014 /* Returns the length of the 'op' array.  */
2015 static int
2016 tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq *seq)
2017 {
2018   /* The array either uses all of its allocated slots or is terminated
2019      by a bogus opcode. Either way, the array size is the index of the
2020      last valid opcode plus one.  */
2021   int i;
2022   for (i = tilegx_multiply_insn_seq_MAX_OPERATIONS - 1; i >= 0; i--)
2023     if (tilegx_multiply_get_opcode (&seq->op[i]) != CODE_FOR_nothing)
2024       return i + 1;
2025 
2026   /* An empty array is not allowed.  */
2027   gcc_unreachable ();
2028 }
2029 
2030 
2031 /* We precompute a number of expression trees for multiplying by
2032    constants.  This generates code for such an expression tree by
2033    walking through the nodes in the tree (which are conveniently
2034    pre-linearized) and emitting an instruction for each one.  */
2035 static void
2036 tilegx_expand_constant_multiply_given_sequence (rtx result, rtx src,
2037 						const struct
2038 						tilegx_multiply_insn_seq *seq)
2039 {
2040   int i;
2041   int num_ops;
2042 
2043   /* Keep track of the subexpressions computed so far, so later
2044      instructions can refer to them.  We seed the array with zero and
2045      the value being multiplied.  */
2046   int num_subexprs = 2;
2047   rtx subexprs[tilegx_multiply_insn_seq_MAX_OPERATIONS + 2];
2048   subexprs[0] = const0_rtx;
2049   subexprs[1] = src;
2050 
2051   /* Determine how many instructions we are going to generate.  */
2052   num_ops = tilegx_multiply_get_num_ops (seq);
2053   gcc_assert (num_ops > 0
2054 	      && num_ops <= tilegx_multiply_insn_seq_MAX_OPERATIONS);
2055 
2056   for (i = 0; i < num_ops; i++)
2057     {
2058       const struct tilegx_multiply_insn_seq_entry *entry = &seq->op[i];
2059 
2060       /* Figure out where to store the output of this instruction.  */
2061       const bool is_last_op = (i + 1 == num_ops);
2062       rtx out = is_last_op ? result : gen_reg_rtx (DImode);
2063 
2064       enum insn_code opcode = tilegx_multiply_get_opcode (entry);
2065       if (opcode == CODE_FOR_ashldi3)
2066 	{
2067 	  /* Handle shift by immediate. This is a special case because
2068 	     the meaning of the second operand is a constant shift
2069 	     count rather than an operand index.  */
2070 
2071 	  /* Make sure the shift count is in range. Zero should not
2072 	     happen.  */
2073 	  const int shift_count = entry->rhs;
2074 	  gcc_assert (shift_count > 0 && shift_count < 64);
2075 
2076 	  /* Emit the actual instruction.  */
2077 	  emit_insn (GEN_FCN (opcode)
2078 		     (out, subexprs[entry->lhs],
2079 		      gen_rtx_CONST_INT (DImode, shift_count)));
2080 	}
2081       else
2082 	{
2083 	  /* Handle a normal two-operand instruction, such as add or
2084 	     shl1add.  */
2085 
2086 	  /* Make sure we are referring to a previously computed
2087 	     subexpression.  */
2088 	  gcc_assert (entry->rhs < num_subexprs);
2089 
2090 	  /* Emit the actual instruction.  */
2091 	  emit_insn (GEN_FCN (opcode)
2092 		     (out, subexprs[entry->lhs], subexprs[entry->rhs]));
2093 	}
2094 
2095       /* Record this subexpression for use by later expressions.  */
2096       subexprs[num_subexprs++] = out;
2097     }
2098 }
2099 
2100 
2101 /* bsearch helper function.  */
2102 static int
2103 tilegx_compare_multipliers (const void *key, const void *t)
2104 {
2105   long long delta =
2106     (*(const long long *) key
2107      - ((const struct tilegx_multiply_insn_seq *) t)->multiplier);
2108   return (delta < 0) ? -1 : (delta > 0);
2109 }
2110 
2111 
2112 /* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none
2113    exists.  */
2114 static const struct tilegx_multiply_insn_seq *
2115 tilegx_find_multiply_insn_seq_for_constant (long long multiplier)
2116 {
2117   return ((const struct tilegx_multiply_insn_seq *)
2118 	  bsearch (&multiplier, tilegx_multiply_insn_seq_table,
2119 		   tilegx_multiply_insn_seq_table_size,
2120 		   sizeof tilegx_multiply_insn_seq_table[0],
2121 		   tilegx_compare_multipliers));
2122 }
2123 
2124 
2125 /* Try to a expand constant multiply in DImode by looking it up in a
2126    precompiled table.  OP0 is the result operand, OP1 is the source
2127    operand, and MULTIPLIER is the value of the constant.  Return true
2128    if it succeeds.  */
2129 static bool
2130 tilegx_expand_const_muldi (rtx op0, rtx op1, long long multiplier)
2131 {
2132   /* See if we have precomputed an efficient way to multiply by this
2133      constant.  */
2134   const struct tilegx_multiply_insn_seq *seq =
2135     tilegx_find_multiply_insn_seq_for_constant (multiplier);
2136   if (seq != NULL)
2137     {
2138       tilegx_expand_constant_multiply_given_sequence (op0, op1, seq);
2139       return true;
2140     }
2141   else
2142     return false;
2143 }
2144 
2145 
2146 /* Expand the muldi pattern.  */
2147 bool
2148 tilegx_expand_muldi (rtx op0, rtx op1, rtx op2)
2149 {
2150   if (CONST_INT_P (op2))
2151     {
2152       HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), DImode);
2153       return tilegx_expand_const_muldi (op0, op1, n);
2154     }
2155   return false;
2156 }
2157 
2158 
2159 /* Expand a high multiply pattern in DImode.  RESULT, OP1, OP2 are the
2160    operands, and SIGN is true if it's a signed multiply, and false if
2161    it's an unsigned multiply.  */
2162 static void
2163 tilegx_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign)
2164 {
2165   rtx tmp0 = gen_reg_rtx (DImode);
2166   rtx tmp1 = gen_reg_rtx (DImode);
2167   rtx tmp2 = gen_reg_rtx (DImode);
2168   rtx tmp3 = gen_reg_rtx (DImode);
2169   rtx tmp4 = gen_reg_rtx (DImode);
2170   rtx tmp5 = gen_reg_rtx (DImode);
2171   rtx tmp6 = gen_reg_rtx (DImode);
2172   rtx tmp7 = gen_reg_rtx (DImode);
2173   rtx tmp8 = gen_reg_rtx (DImode);
2174   rtx tmp9 = gen_reg_rtx (DImode);
2175   rtx tmp10 = gen_reg_rtx (DImode);
2176   rtx tmp11 = gen_reg_rtx (DImode);
2177   rtx tmp12 = gen_reg_rtx (DImode);
2178   rtx tmp13 = gen_reg_rtx (DImode);
2179   rtx result_lo = gen_reg_rtx (DImode);
2180 
2181   if (sign)
2182     {
2183       emit_insn (gen_insn_mul_hs_lu (tmp0, op1, op2));
2184       emit_insn (gen_insn_mul_hs_lu (tmp1, op2, op1));
2185       emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2));
2186       emit_insn (gen_insn_mul_hs_hs (tmp3, op1, op2));
2187     }
2188   else
2189     {
2190       emit_insn (gen_insn_mul_hu_lu (tmp0, op1, op2));
2191       emit_insn (gen_insn_mul_hu_lu (tmp1, op2, op1));
2192       emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2));
2193       emit_insn (gen_insn_mul_hu_hu (tmp3, op1, op2));
2194     }
2195 
2196   emit_move_insn (tmp4, (gen_rtx_ASHIFT (DImode, tmp0, GEN_INT (32))));
2197 
2198   emit_move_insn (tmp5, (gen_rtx_ASHIFT (DImode, tmp1, GEN_INT (32))));
2199 
2200   emit_move_insn (tmp6, (gen_rtx_PLUS (DImode, tmp4, tmp5)));
2201   emit_move_insn (result_lo, (gen_rtx_PLUS (DImode, tmp2, tmp6)));
2202 
2203   emit_move_insn (tmp7, gen_rtx_LTU (DImode, tmp6, tmp4));
2204   emit_move_insn (tmp8, gen_rtx_LTU (DImode, result_lo, tmp2));
2205 
2206   if (sign)
2207     {
2208       emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (DImode, tmp0, GEN_INT (32))));
2209       emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (DImode, tmp1, GEN_INT (32))));
2210     }
2211   else
2212     {
2213       emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (DImode, tmp0, GEN_INT (32))));
2214       emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (DImode, tmp1, GEN_INT (32))));
2215     }
2216 
2217   emit_move_insn (tmp11, (gen_rtx_PLUS (DImode, tmp3, tmp7)));
2218   emit_move_insn (tmp12, (gen_rtx_PLUS (DImode, tmp8, tmp9)));
2219   emit_move_insn (tmp13, (gen_rtx_PLUS (DImode, tmp11, tmp12)));
2220   emit_move_insn (result, (gen_rtx_PLUS (DImode, tmp13, tmp10)));
2221 }
2222 
2223 
2224 /* Implement smuldi3_highpart.  */
2225 void
2226 tilegx_expand_smuldi3_highpart (rtx op0, rtx op1, rtx op2)
2227 {
2228   tilegx_expand_high_multiply (op0, op1, op2, true);
2229 }
2230 
2231 
2232 /* Implement umuldi3_highpart.  */
2233 void
2234 tilegx_expand_umuldi3_highpart (rtx op0, rtx op1, rtx op2)
2235 {
2236   tilegx_expand_high_multiply (op0, op1, op2, false);
2237 }
2238 
2239 
2240 
2241 /* Compare and branches  */
2242 
2243 /* Produce the rtx yielding a bool for a floating point
2244    comparison.  */
2245 static bool
2246 tilegx_emit_fp_setcc (rtx res, enum rtx_code code, enum machine_mode mode,
2247 		      rtx op0, rtx op1)
2248 {
2249   /* TODO: Certain compares again constants can be done using entirely
2250      integer operations. But you have to get the special cases right
2251      e.g. NaN, +0 == -0, etc.  */
2252 
2253   rtx flags;
2254   int flag_index;
2255   rtx a = force_reg (DImode, gen_lowpart (DImode, op0));
2256   rtx b = force_reg (DImode, gen_lowpart (DImode, op1));
2257 
2258   flags = gen_reg_rtx (DImode);
2259 
2260   if (mode == SFmode)
2261     {
2262       emit_insn (gen_insn_fsingle_add1 (flags, a, b));
2263     }
2264   else
2265     {
2266       gcc_assert (mode == DFmode);
2267       emit_insn (gen_insn_fdouble_add_flags (flags, a, b));
2268     }
2269 
2270   switch (code)
2271     {
2272     case EQ: flag_index = 30; break;
2273     case NE: flag_index = 31; break;
2274     case LE: flag_index = 27; break;
2275     case LT: flag_index = 26; break;
2276     case GE: flag_index = 29; break;
2277     case GT: flag_index = 28; break;
2278     default: gcc_unreachable ();
2279     }
2280 
2281   gcc_assert (GET_MODE (res) == DImode);
2282   emit_move_insn (res, gen_rtx_ZERO_EXTRACT (DImode, flags, GEN_INT (1),
2283 					     GEN_INT (flag_index)));
2284   return true;
2285 }
2286 
2287 
2288 /* Certain simplifications can be done to make invalid setcc
2289    operations valid.  Return the final comparison, or NULL if we can't
2290    work.  */
2291 static bool
2292 tilegx_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1,
2293 			    enum machine_mode cmp_mode)
2294 {
2295   rtx tmp;
2296   bool swap = false;
2297 
2298   if (cmp_mode == SFmode || cmp_mode == DFmode)
2299     return tilegx_emit_fp_setcc (res, code, cmp_mode, op0, op1);
2300 
2301   /* The general case: fold the comparison code to the types of
2302      compares that we have, choosing the branch as necessary.  */
2303 
2304   switch (code)
2305     {
2306     case EQ:
2307     case NE:
2308     case LE:
2309     case LT:
2310     case LEU:
2311     case LTU:
2312       /* We have these compares.  */
2313       break;
2314 
2315     case GE:
2316     case GT:
2317     case GEU:
2318     case GTU:
2319       /* We do not have these compares, so we reverse the
2320 	 operands.  */
2321       swap = true;
2322       break;
2323 
2324     default:
2325       /* We should not have called this with any other code.  */
2326       gcc_unreachable ();
2327     }
2328 
2329   if (swap)
2330     {
2331       code = swap_condition (code);
2332       tmp = op0, op0 = op1, op1 = tmp;
2333     }
2334 
2335   if (!reg_or_0_operand (op0, cmp_mode))
2336     op0 = force_reg (cmp_mode, op0);
2337 
2338   if (!CONST_INT_P (op1) && !register_operand (op1, cmp_mode))
2339     op1 = force_reg (cmp_mode, op1);
2340 
2341   /* Return the setcc comparison.  */
2342   emit_insn (gen_rtx_SET (VOIDmode, res,
2343 			  gen_rtx_fmt_ee (code, DImode, op0, op1)));
2344 
2345   return true;
2346 }
2347 
2348 
2349 /* Implement cstore patterns.  */
2350 bool
2351 tilegx_emit_setcc (rtx operands[], enum machine_mode cmp_mode)
2352 {
2353   return
2354     tilegx_emit_setcc_internal (operands[0], GET_CODE (operands[1]),
2355 				operands[2], operands[3], cmp_mode);
2356 }
2357 
2358 
2359 /* Return whether CODE is a signed comparison.  */
2360 static bool
2361 signed_compare_p (enum rtx_code code)
2362 {
2363   return (code == EQ || code == NE || code == LT || code == LE
2364 	  || code == GT || code == GE);
2365 }
2366 
2367 
2368 /* Generate the comparison for a DImode conditional branch.  */
2369 static rtx
2370 tilegx_emit_cc_test (enum rtx_code code, rtx op0, rtx op1,
2371 		     enum machine_mode cmp_mode, bool eq_ne_only)
2372 {
2373   enum rtx_code branch_code;
2374   rtx temp;
2375 
2376   if (cmp_mode == SFmode || cmp_mode == DFmode)
2377     {
2378       /* Compute a boolean saying whether the comparison is true.  */
2379       temp = gen_reg_rtx (DImode);
2380       tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2381 
2382       /* Test that flag.  */
2383       return gen_rtx_fmt_ee (NE, VOIDmode, temp, const0_rtx);
2384     }
2385 
2386   /* Check for a compare against zero using a comparison we can do
2387      directly.  */
2388   if (op1 == const0_rtx
2389       && (code == EQ || code == NE
2390 	  || (!eq_ne_only && signed_compare_p (code))))
2391     {
2392       op0 = force_reg (cmp_mode, op0);
2393       return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx);
2394     }
2395 
2396   /* The general case: fold the comparison code to the types of
2397      compares that we have, choosing the branch as necessary.  */
2398   switch (code)
2399     {
2400     case EQ:
2401     case LE:
2402     case LT:
2403     case LEU:
2404     case LTU:
2405       /* We have these compares.  */
2406       branch_code = NE;
2407       break;
2408 
2409     case NE:
2410     case GE:
2411     case GT:
2412     case GEU:
2413     case GTU:
2414       /* These must be reversed (except NE, but let's
2415 	 canonicalize).  */
2416       code = reverse_condition (code);
2417       branch_code = EQ;
2418       break;
2419 
2420     default:
2421       gcc_unreachable ();
2422     }
2423 
2424   if (CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU))
2425     {
2426       HOST_WIDE_INT n = INTVAL (op1);
2427 
2428       switch (code)
2429 	{
2430 	case EQ:
2431 	  /* Subtract off the value we want to compare against and see
2432 	     if we get zero.  This is cheaper than creating a constant
2433 	     in a register. Except that subtracting -128 is more
2434 	     expensive than seqi to -128, so we leave that alone.  */
2435 	  /* ??? Don't do this when comparing against symbols,
2436 	     otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2437 	     0), which will be declared false out of hand (at least
2438 	     for non-weak).  */
2439 	  if (n != -128
2440 	      && add_operand (GEN_INT (-n), DImode)
2441 	      && !(symbolic_operand (op0, VOIDmode)
2442 		   || (REG_P (op0) && REG_POINTER (op0))))
2443 	    {
2444 	      /* TODO: Use a SIMD add immediate to hit zero for tiled
2445 		 constants in a single instruction.  */
2446 	      if (GET_MODE (op0) != DImode)
2447 		{
2448 		  /* Convert to DImode so we can use addli.  Note that
2449 		     this will not actually generate any code because
2450 		     sign extension from SI -> DI is a no-op.  I don't
2451 		     know if it's safe just to make a paradoxical
2452 		     subreg here though.  */
2453 		  rtx temp2 = gen_reg_rtx (DImode);
2454 		  emit_insn (gen_extendsidi2 (temp2, op0));
2455 		  op0 = temp2;
2456 		}
2457 	      else
2458 		{
2459 		  op0 = force_reg (DImode, op0);
2460 		}
2461 	      temp = gen_reg_rtx (DImode);
2462 	      emit_move_insn (temp, gen_rtx_PLUS (DImode, op0, GEN_INT (-n)));
2463 	      return gen_rtx_fmt_ee (reverse_condition (branch_code),
2464 				     VOIDmode, temp, const0_rtx);
2465 	    }
2466 	  break;
2467 
2468 	case LEU:
2469 	  if (n == -1)
2470 	    break;
2471 	  /* FALLTHRU */
2472 
2473 	case LTU:
2474 	  /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2475 	     We use arithmetic shift right because it's a 3-wide op,
2476 	     while logical shift right is not.  */
2477 	  {
2478 	    int first = exact_log2 (code == LTU ? n : n + 1);
2479 	    if (first != -1)
2480 	      {
2481 		op0 = force_reg (cmp_mode, op0);
2482 		temp = gen_reg_rtx (cmp_mode);
2483 		emit_move_insn (temp,
2484 				gen_rtx_ASHIFTRT (cmp_mode, op0,
2485 						  GEN_INT (first)));
2486 		return gen_rtx_fmt_ee (reverse_condition (branch_code),
2487 				       VOIDmode, temp, const0_rtx);
2488 	      }
2489 	  }
2490 	  break;
2491 
2492 	default:
2493 	  break;
2494 	}
2495     }
2496 
2497   /* Compute a flag saying whether we should branch.  */
2498   temp = gen_reg_rtx (DImode);
2499   tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2500 
2501   /* Return the branch comparison.  */
2502   return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx);
2503 }
2504 
2505 
2506 /* Generate the comparison for a conditional branch.  */
2507 void
2508 tilegx_emit_conditional_branch (rtx operands[], enum machine_mode cmp_mode)
2509 {
2510   rtx cmp_rtx =
2511     tilegx_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2],
2512 			 cmp_mode, false);
2513   rtx branch_rtx = gen_rtx_SET (VOIDmode, pc_rtx,
2514 				gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx,
2515 						      gen_rtx_LABEL_REF
2516 						      (VOIDmode,
2517 						       operands[3]),
2518 						      pc_rtx));
2519   emit_jump_insn (branch_rtx);
2520 }
2521 
2522 
2523 /* Implement the mov<mode>cc pattern.  */
2524 rtx
2525 tilegx_emit_conditional_move (rtx cmp)
2526 {
2527   return
2528     tilegx_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1),
2529 			 GET_MODE (XEXP (cmp, 0)), true);
2530 }
2531 
2532 
2533 /* Return true if INSN is annotated with a REG_BR_PROB note that
2534    indicates it's a branch that's predicted taken.  */
2535 static bool
2536 cbranch_predicted_p (rtx insn)
2537 {
2538   rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2539 
2540   if (x)
2541     {
2542       int pred_val = INTVAL (XEXP (x, 0));
2543 
2544       return pred_val >= REG_BR_PROB_BASE / 2;
2545     }
2546 
2547   return false;
2548 }
2549 
2550 
2551 /* Output assembly code for a specific branch instruction, appending
2552    the branch prediction flag to the opcode if appropriate.  */
2553 static const char *
2554 tilegx_output_simple_cbranch_with_opcode (rtx insn, const char *opcode,
2555 					  int regop, bool reverse_predicted)
2556 {
2557   static char buf[64];
2558   sprintf (buf, "%s%s\t%%r%d, %%l0", opcode,
2559 	   (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "",
2560 	   regop);
2561   return buf;
2562 }
2563 
2564 
2565 /* Output assembly code for a specific branch instruction, appending
2566    the branch prediction flag to the opcode if appropriate.  */
2567 const char *
2568 tilegx_output_cbranch_with_opcode (rtx insn, rtx *operands,
2569 				   const char *opcode,
2570 				   const char *rev_opcode, int regop)
2571 {
2572   const char *branch_if_false;
2573   rtx taken, not_taken;
2574   bool is_simple_branch;
2575 
2576   gcc_assert (LABEL_P (operands[0]));
2577 
2578   is_simple_branch = true;
2579   if (INSN_ADDRESSES_SET_P ())
2580     {
2581       int from_addr = INSN_ADDRESSES (INSN_UID (insn));
2582       int to_addr = INSN_ADDRESSES (INSN_UID (operands[0]));
2583       int delta = to_addr - from_addr;
2584       is_simple_branch = IN_RANGE (delta, -524288, 524280);
2585     }
2586 
2587   if (is_simple_branch)
2588     {
2589       /* Just a simple conditional branch.  */
2590       return
2591 	tilegx_output_simple_cbranch_with_opcode (insn, opcode, regop, false);
2592     }
2593 
2594   /* Generate a reversed branch around a direct jump.  This fallback
2595      does not use branch-likely instructions.  */
2596   not_taken = gen_label_rtx ();
2597   taken = operands[0];
2598 
2599   /* Generate the reversed branch to NOT_TAKEN.  */
2600   operands[0] = not_taken;
2601   branch_if_false =
2602     tilegx_output_simple_cbranch_with_opcode (insn, rev_opcode, regop, true);
2603   output_asm_insn (branch_if_false, operands);
2604 
2605   output_asm_insn ("j\t%l0", &taken);
2606 
2607   /* Output NOT_TAKEN.  */
2608   targetm.asm_out.internal_label (asm_out_file, "L",
2609 				  CODE_LABEL_NUMBER (not_taken));
2610   return "";
2611 }
2612 
2613 
2614 /* Output assembly code for a conditional branch instruction.  */
2615 const char *
2616 tilegx_output_cbranch (rtx insn, rtx *operands, bool reversed)
2617 {
2618   enum rtx_code code = GET_CODE (operands[1]);
2619   const char *opcode;
2620   const char *rev_opcode;
2621 
2622   if (reversed)
2623     code = reverse_condition (code);
2624 
2625   switch (code)
2626     {
2627     case NE:
2628       opcode = "bnez";
2629       rev_opcode = "beqz";
2630       break;
2631     case EQ:
2632       opcode = "beqz";
2633       rev_opcode = "bnez";
2634       break;
2635     case GE:
2636       opcode = "bgez";
2637       rev_opcode = "bltz";
2638       break;
2639     case GT:
2640       opcode = "bgtz";
2641       rev_opcode = "blez";
2642       break;
2643     case LE:
2644       opcode = "blez";
2645       rev_opcode = "bgtz";
2646       break;
2647     case LT:
2648       opcode = "bltz";
2649       rev_opcode = "bgez";
2650       break;
2651     default:
2652       gcc_unreachable ();
2653     }
2654 
2655   return tilegx_output_cbranch_with_opcode (insn, operands, opcode,
2656 					    rev_opcode, 2);
2657 }
2658 
2659 
2660 /* Implement the tablejump pattern.  */
2661 void
2662 tilegx_expand_tablejump (rtx op0, rtx op1)
2663 {
2664   if (flag_pic)
2665     {
2666       rtx temp = gen_reg_rtx (Pmode);
2667       rtx temp2 = gen_reg_rtx (Pmode);
2668 
2669       tilegx_compute_pcrel_address (temp, gen_rtx_LABEL_REF (Pmode, op1));
2670       emit_move_insn (temp2,
2671 		      gen_rtx_PLUS (Pmode,
2672 				    convert_to_mode (Pmode, op0, false),
2673 				    temp));
2674       op0 = temp2;
2675     }
2676 
2677   emit_jump_insn (gen_tablejump_aux (op0, op1));
2678 }
2679 
2680 
2681 /* Emit barrier before an atomic, as needed for the memory MODEL.  */
2682 void
2683 tilegx_pre_atomic_barrier (enum memmodel model)
2684 {
2685   if (need_atomic_barrier_p (model, true))
2686     emit_insn (gen_memory_barrier ());
2687 }
2688 
2689 
2690 /* Emit barrier after an atomic, as needed for the memory MODEL.  */
2691 void
2692 tilegx_post_atomic_barrier (enum memmodel model)
2693 {
2694   if (need_atomic_barrier_p (model, false))
2695     emit_insn (gen_memory_barrier ());
2696 }
2697 
2698 
2699 
2700 /* Expand a builtin vector binary op, by calling gen function GEN with
2701    operands in the proper modes.  DEST is converted to DEST_MODE, and
2702    src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE.  */
2703 void
2704 tilegx_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx),
2705 				    enum machine_mode dest_mode,
2706 				    rtx dest,
2707 				    enum machine_mode src_mode,
2708 				    rtx src0, rtx src1, bool do_src1)
2709 {
2710   dest = gen_lowpart (dest_mode, dest);
2711 
2712   if (src0 == const0_rtx)
2713     src0 = CONST0_RTX (src_mode);
2714   else
2715     src0 = gen_lowpart (src_mode, src0);
2716 
2717   if (do_src1)
2718     {
2719       if (src1 == const0_rtx)
2720 	src1 = CONST0_RTX (src_mode);
2721       else
2722 	src1 = gen_lowpart (src_mode, src1);
2723     }
2724 
2725   emit_insn ((*gen) (dest, src0, src1));
2726 }
2727 
2728 
2729 
2730 /* Intrinsics  */
2731 
2732 
2733 struct tile_builtin_info
2734 {
2735   enum insn_code icode;
2736   tree fndecl;
2737 };
2738 
2739 static struct tile_builtin_info tilegx_builtin_info[TILEGX_BUILTIN_max] = {
2740   { CODE_FOR_adddi3,                    NULL }, /* add */
2741   { CODE_FOR_addsi3,                    NULL }, /* addx */
2742   { CODE_FOR_ssaddsi3,                  NULL }, /* addxsc */
2743   { CODE_FOR_anddi3,                    NULL }, /* and */
2744   { CODE_FOR_insn_bfexts,               NULL }, /* bfexts */
2745   { CODE_FOR_insn_bfextu,               NULL }, /* bfextu */
2746   { CODE_FOR_insn_bfins,                NULL }, /* bfins */
2747   { CODE_FOR_clzdi2,                    NULL }, /* clz */
2748   { CODE_FOR_insn_cmoveqz,              NULL }, /* cmoveqz */
2749   { CODE_FOR_insn_cmovnez,              NULL }, /* cmovnez */
2750   { CODE_FOR_insn_cmpeq_didi,           NULL }, /* cmpeq */
2751   { CODE_FOR_insn_cmpexch,              NULL }, /* cmpexch */
2752   { CODE_FOR_insn_cmpexch4,             NULL }, /* cmpexch4 */
2753   { CODE_FOR_insn_cmples_didi,          NULL }, /* cmples */
2754   { CODE_FOR_insn_cmpleu_didi,          NULL }, /* cmpleu */
2755   { CODE_FOR_insn_cmplts_didi,          NULL }, /* cmplts */
2756   { CODE_FOR_insn_cmpltu_didi,          NULL }, /* cmpltu */
2757   { CODE_FOR_insn_cmpne_didi,           NULL }, /* cmpne */
2758   { CODE_FOR_insn_cmul,                 NULL }, /* cmul */
2759   { CODE_FOR_insn_cmula,                NULL }, /* cmula */
2760   { CODE_FOR_insn_cmulaf,               NULL }, /* cmulaf */
2761   { CODE_FOR_insn_cmulf,                NULL }, /* cmulf */
2762   { CODE_FOR_insn_cmulfr,               NULL }, /* cmulfr */
2763   { CODE_FOR_insn_cmulh,                NULL }, /* cmulh */
2764   { CODE_FOR_insn_cmulhr,               NULL }, /* cmulhr */
2765   { CODE_FOR_insn_crc32_32,             NULL }, /* crc32_32 */
2766   { CODE_FOR_insn_crc32_8,              NULL }, /* crc32_8 */
2767   { CODE_FOR_ctzdi2,                    NULL }, /* ctz */
2768   { CODE_FOR_insn_dblalign,             NULL }, /* dblalign */
2769   { CODE_FOR_insn_dblalign2,            NULL }, /* dblalign2 */
2770   { CODE_FOR_insn_dblalign4,            NULL }, /* dblalign4 */
2771   { CODE_FOR_insn_dblalign6,            NULL }, /* dblalign6 */
2772   { CODE_FOR_insn_drain,                NULL }, /* drain */
2773   { CODE_FOR_insn_dtlbpr,               NULL }, /* dtlbpr */
2774   { CODE_FOR_insn_exch,                 NULL }, /* exch */
2775   { CODE_FOR_insn_exch4,                NULL }, /* exch4 */
2776   { CODE_FOR_insn_fdouble_add_flags,    NULL }, /* fdouble_add_flags */
2777   { CODE_FOR_insn_fdouble_addsub,       NULL }, /* fdouble_addsub */
2778   { CODE_FOR_insn_fdouble_mul_flags,    NULL }, /* fdouble_mul_flags */
2779   { CODE_FOR_insn_fdouble_pack1,        NULL }, /* fdouble_pack1 */
2780   { CODE_FOR_insn_fdouble_pack2,        NULL }, /* fdouble_pack2 */
2781   { CODE_FOR_insn_fdouble_sub_flags,    NULL }, /* fdouble_sub_flags */
2782   { CODE_FOR_insn_fdouble_unpack_max,   NULL }, /* fdouble_unpack_max */
2783   { CODE_FOR_insn_fdouble_unpack_min,   NULL }, /* fdouble_unpack_min */
2784   { CODE_FOR_insn_fetchadd,             NULL }, /* fetchadd */
2785   { CODE_FOR_insn_fetchadd4,            NULL }, /* fetchadd4 */
2786   { CODE_FOR_insn_fetchaddgez,          NULL }, /* fetchaddgez */
2787   { CODE_FOR_insn_fetchaddgez4,         NULL }, /* fetchaddgez4 */
2788   { CODE_FOR_insn_fetchand,             NULL }, /* fetchand */
2789   { CODE_FOR_insn_fetchand4,            NULL }, /* fetchand4 */
2790   { CODE_FOR_insn_fetchor,              NULL }, /* fetchor */
2791   { CODE_FOR_insn_fetchor4,             NULL }, /* fetchor4 */
2792   { CODE_FOR_insn_finv,                 NULL }, /* finv */
2793   { CODE_FOR_insn_flush,                NULL }, /* flush */
2794   { CODE_FOR_insn_flushwb,              NULL }, /* flushwb */
2795   { CODE_FOR_insn_fnop,                 NULL }, /* fnop */
2796   { CODE_FOR_insn_fsingle_add1,         NULL }, /* fsingle_add1 */
2797   { CODE_FOR_insn_fsingle_addsub2,      NULL }, /* fsingle_addsub2 */
2798   { CODE_FOR_insn_fsingle_mul1,         NULL }, /* fsingle_mul1 */
2799   { CODE_FOR_insn_fsingle_mul2,         NULL }, /* fsingle_mul2 */
2800   { CODE_FOR_insn_fsingle_pack1,        NULL }, /* fsingle_pack1 */
2801   { CODE_FOR_insn_fsingle_pack2,        NULL }, /* fsingle_pack2 */
2802   { CODE_FOR_insn_fsingle_sub1,         NULL }, /* fsingle_sub1 */
2803   { CODE_FOR_insn_icoh,                 NULL }, /* icoh */
2804   { CODE_FOR_insn_ill,                  NULL }, /* ill */
2805   { CODE_FOR_insn_info,                 NULL }, /* info */
2806   { CODE_FOR_insn_infol,                NULL }, /* infol */
2807   { CODE_FOR_insn_inv,                  NULL }, /* inv */
2808   { CODE_FOR_insn_ld,                   NULL }, /* ld */
2809   { CODE_FOR_insn_ld1s,                 NULL }, /* ld1s */
2810   { CODE_FOR_insn_ld1u,                 NULL }, /* ld1u */
2811   { CODE_FOR_insn_ld2s,                 NULL }, /* ld2s */
2812   { CODE_FOR_insn_ld2u,                 NULL }, /* ld2u */
2813   { CODE_FOR_insn_ld4s,                 NULL }, /* ld4s */
2814   { CODE_FOR_insn_ld4u,                 NULL }, /* ld4u */
2815   { CODE_FOR_insn_ldna,                 NULL }, /* ldna */
2816   { CODE_FOR_insn_ldnt,                 NULL }, /* ldnt */
2817   { CODE_FOR_insn_ldnt1s,               NULL }, /* ldnt1s */
2818   { CODE_FOR_insn_ldnt1u,               NULL }, /* ldnt1u */
2819   { CODE_FOR_insn_ldnt2s,               NULL }, /* ldnt2s */
2820   { CODE_FOR_insn_ldnt2u,               NULL }, /* ldnt2u */
2821   { CODE_FOR_insn_ldnt4s,               NULL }, /* ldnt4s */
2822   { CODE_FOR_insn_ldnt4u,               NULL }, /* ldnt4u */
2823   { CODE_FOR_insn_ld_L2,                NULL }, /* ld_L2 */
2824   { CODE_FOR_insn_ld1s_L2,              NULL }, /* ld1s_L2 */
2825   { CODE_FOR_insn_ld1u_L2,              NULL }, /* ld1u_L2 */
2826   { CODE_FOR_insn_ld2s_L2,              NULL }, /* ld2s_L2 */
2827   { CODE_FOR_insn_ld2u_L2,              NULL }, /* ld2u_L2 */
2828   { CODE_FOR_insn_ld4s_L2,              NULL }, /* ld4s_L2 */
2829   { CODE_FOR_insn_ld4u_L2,              NULL }, /* ld4u_L2 */
2830   { CODE_FOR_insn_ldna_L2,              NULL }, /* ldna_L2 */
2831   { CODE_FOR_insn_ldnt_L2,              NULL }, /* ldnt_L2 */
2832   { CODE_FOR_insn_ldnt1s_L2,            NULL }, /* ldnt1s_L2 */
2833   { CODE_FOR_insn_ldnt1u_L2,            NULL }, /* ldnt1u_L2 */
2834   { CODE_FOR_insn_ldnt2s_L2,            NULL }, /* ldnt2s_L2 */
2835   { CODE_FOR_insn_ldnt2u_L2,            NULL }, /* ldnt2u_L2 */
2836   { CODE_FOR_insn_ldnt4s_L2,            NULL }, /* ldnt4s_L2 */
2837   { CODE_FOR_insn_ldnt4u_L2,            NULL }, /* ldnt4u_L2 */
2838   { CODE_FOR_insn_ld_miss,              NULL }, /* ld_miss */
2839   { CODE_FOR_insn_ld1s_miss,            NULL }, /* ld1s_miss */
2840   { CODE_FOR_insn_ld1u_miss,            NULL }, /* ld1u_miss */
2841   { CODE_FOR_insn_ld2s_miss,            NULL }, /* ld2s_miss */
2842   { CODE_FOR_insn_ld2u_miss,            NULL }, /* ld2u_miss */
2843   { CODE_FOR_insn_ld4s_miss,            NULL }, /* ld4s_miss */
2844   { CODE_FOR_insn_ld4u_miss,            NULL }, /* ld4u_miss */
2845   { CODE_FOR_insn_ldna_miss,            NULL }, /* ldna_miss */
2846   { CODE_FOR_insn_ldnt_miss,            NULL }, /* ldnt_miss */
2847   { CODE_FOR_insn_ldnt1s_miss,          NULL }, /* ldnt1s_miss */
2848   { CODE_FOR_insn_ldnt1u_miss,          NULL }, /* ldnt1u_miss */
2849   { CODE_FOR_insn_ldnt2s_miss,          NULL }, /* ldnt2s_miss */
2850   { CODE_FOR_insn_ldnt2u_miss,          NULL }, /* ldnt2u_miss */
2851   { CODE_FOR_insn_ldnt4s_miss,          NULL }, /* ldnt4s_miss */
2852   { CODE_FOR_insn_ldnt4u_miss,          NULL }, /* ldnt4u_miss */
2853   { CODE_FOR_insn_lnk,                  NULL }, /* lnk */
2854   { CODE_FOR_memory_barrier,            NULL }, /* mf */
2855   { CODE_FOR_insn_mfspr,                NULL }, /* mfspr */
2856   { CODE_FOR_insn_mm,                   NULL }, /* mm */
2857   { CODE_FOR_insn_mnz,                  NULL }, /* mnz */
2858   { CODE_FOR_movdi,                     NULL }, /* move */
2859   { CODE_FOR_insn_mtspr,                NULL }, /* mtspr */
2860   { CODE_FOR_insn_mul_hs_hs,            NULL }, /* mul_hs_hs */
2861   { CODE_FOR_insn_mul_hs_hu,            NULL }, /* mul_hs_hu */
2862   { CODE_FOR_insn_mul_hs_ls,            NULL }, /* mul_hs_ls */
2863   { CODE_FOR_insn_mul_hs_lu,            NULL }, /* mul_hs_lu */
2864   { CODE_FOR_insn_mul_hu_hu,            NULL }, /* mul_hu_hu */
2865   { CODE_FOR_insn_mul_hu_ls,            NULL }, /* mul_hu_ls */
2866   { CODE_FOR_insn_mul_hu_lu,            NULL }, /* mul_hu_lu */
2867   { CODE_FOR_insn_mul_ls_ls,            NULL }, /* mul_ls_ls */
2868   { CODE_FOR_insn_mul_ls_lu,            NULL }, /* mul_ls_lu */
2869   { CODE_FOR_insn_mul_lu_lu,            NULL }, /* mul_lu_lu */
2870   { CODE_FOR_insn_mula_hs_hs,           NULL }, /* mula_hs_hs */
2871   { CODE_FOR_insn_mula_hs_hu,           NULL }, /* mula_hs_hu */
2872   { CODE_FOR_insn_mula_hs_ls,           NULL }, /* mula_hs_ls */
2873   { CODE_FOR_insn_mula_hs_lu,           NULL }, /* mula_hs_lu */
2874   { CODE_FOR_insn_mula_hu_hu,           NULL }, /* mula_hu_hu */
2875   { CODE_FOR_insn_mula_hu_ls,           NULL }, /* mula_hu_ls */
2876   { CODE_FOR_insn_mula_hu_lu,           NULL }, /* mula_hu_lu */
2877   { CODE_FOR_insn_mula_ls_ls,           NULL }, /* mula_ls_ls */
2878   { CODE_FOR_insn_mula_ls_lu,           NULL }, /* mula_ls_lu */
2879   { CODE_FOR_insn_mula_lu_lu,           NULL }, /* mula_lu_lu */
2880   { CODE_FOR_insn_mulax,                NULL }, /* mulax */
2881   { CODE_FOR_mulsi3,                    NULL }, /* mulx */
2882   { CODE_FOR_insn_mz,                   NULL }, /* mz */
2883   { CODE_FOR_insn_nap,                  NULL }, /* nap */
2884   { CODE_FOR_nop,                       NULL }, /* nop */
2885   { CODE_FOR_insn_nor_di,               NULL }, /* nor */
2886   { CODE_FOR_iordi3,                    NULL }, /* or */
2887   { CODE_FOR_popcountdi2,               NULL }, /* pcnt */
2888   { CODE_FOR_insn_prefetch_l1,          NULL }, /* prefetch_l1 */
2889   { CODE_FOR_insn_prefetch_l1_fault,    NULL }, /* prefetch_l1_fault */
2890   { CODE_FOR_insn_prefetch_l2,          NULL }, /* prefetch_l2 */
2891   { CODE_FOR_insn_prefetch_l2_fault,    NULL }, /* prefetch_l2_fault */
2892   { CODE_FOR_insn_prefetch_l3,          NULL }, /* prefetch_l3 */
2893   { CODE_FOR_insn_prefetch_l3_fault,    NULL }, /* prefetch_l3_fault */
2894   { CODE_FOR_insn_revbits,              NULL }, /* revbits */
2895   { CODE_FOR_bswapdi2,                  NULL }, /* revbytes */
2896   { CODE_FOR_rotldi3,                   NULL }, /* rotl */
2897   { CODE_FOR_ashldi3,                   NULL }, /* shl */
2898   { CODE_FOR_insn_shl16insli,           NULL }, /* shl16insli */
2899   { CODE_FOR_insn_shl1add,              NULL }, /* shl1add */
2900   { CODE_FOR_insn_shl1addx,             NULL }, /* shl1addx */
2901   { CODE_FOR_insn_shl2add,              NULL }, /* shl2add */
2902   { CODE_FOR_insn_shl2addx,             NULL }, /* shl2addx */
2903   { CODE_FOR_insn_shl3add,              NULL }, /* shl3add */
2904   { CODE_FOR_insn_shl3addx,             NULL }, /* shl3addx */
2905   { CODE_FOR_ashlsi3,                   NULL }, /* shlx */
2906   { CODE_FOR_ashrdi3,                   NULL }, /* shrs */
2907   { CODE_FOR_lshrdi3,                   NULL }, /* shru */
2908   { CODE_FOR_lshrsi3,                   NULL }, /* shrux */
2909   { CODE_FOR_insn_shufflebytes,         NULL }, /* shufflebytes */
2910   { CODE_FOR_insn_shufflebytes1,        NULL }, /* shufflebytes1 */
2911   { CODE_FOR_insn_st,                   NULL }, /* st */
2912   { CODE_FOR_insn_st1,                  NULL }, /* st1 */
2913   { CODE_FOR_insn_st2,                  NULL }, /* st2 */
2914   { CODE_FOR_insn_st4,                  NULL }, /* st4 */
2915   { CODE_FOR_insn_stnt,                 NULL }, /* stnt */
2916   { CODE_FOR_insn_stnt1,                NULL }, /* stnt1 */
2917   { CODE_FOR_insn_stnt2,                NULL }, /* stnt2 */
2918   { CODE_FOR_insn_stnt4,                NULL }, /* stnt4 */
2919   { CODE_FOR_subdi3,                    NULL }, /* sub */
2920   { CODE_FOR_subsi3,                    NULL }, /* subx */
2921   { CODE_FOR_sssubsi3,                  NULL }, /* subxsc */
2922   { CODE_FOR_insn_tblidxb0,             NULL }, /* tblidxb0 */
2923   { CODE_FOR_insn_tblidxb1,             NULL }, /* tblidxb1 */
2924   { CODE_FOR_insn_tblidxb2,             NULL }, /* tblidxb2 */
2925   { CODE_FOR_insn_tblidxb3,             NULL }, /* tblidxb3 */
2926   { CODE_FOR_insn_v1add,                NULL }, /* v1add */
2927   { CODE_FOR_insn_v1addi,               NULL }, /* v1addi */
2928   { CODE_FOR_insn_v1adduc,              NULL }, /* v1adduc */
2929   { CODE_FOR_insn_v1adiffu,             NULL }, /* v1adiffu */
2930   { CODE_FOR_insn_v1avgu,               NULL }, /* v1avgu */
2931   { CODE_FOR_insn_v1cmpeq,              NULL }, /* v1cmpeq */
2932   { CODE_FOR_insn_v1cmpeqi,             NULL }, /* v1cmpeqi */
2933   { CODE_FOR_insn_v1cmples,             NULL }, /* v1cmples */
2934   { CODE_FOR_insn_v1cmpleu,             NULL }, /* v1cmpleu */
2935   { CODE_FOR_insn_v1cmplts,             NULL }, /* v1cmplts */
2936   { CODE_FOR_insn_v1cmpltsi,            NULL }, /* v1cmpltsi */
2937   { CODE_FOR_insn_v1cmpltu,             NULL }, /* v1cmpltu */
2938   { CODE_FOR_insn_v1cmpltui,            NULL }, /* v1cmpltui */
2939   { CODE_FOR_insn_v1cmpne,              NULL }, /* v1cmpne */
2940   { CODE_FOR_insn_v1ddotpu,             NULL }, /* v1ddotpu */
2941   { CODE_FOR_insn_v1ddotpua,            NULL }, /* v1ddotpua */
2942   { CODE_FOR_insn_v1ddotpus,            NULL }, /* v1ddotpus */
2943   { CODE_FOR_insn_v1ddotpusa,           NULL }, /* v1ddotpusa */
2944   { CODE_FOR_insn_v1dotp,               NULL }, /* v1dotp */
2945   { CODE_FOR_insn_v1dotpa,              NULL }, /* v1dotpa */
2946   { CODE_FOR_insn_v1dotpu,              NULL }, /* v1dotpu */
2947   { CODE_FOR_insn_v1dotpua,             NULL }, /* v1dotpua */
2948   { CODE_FOR_insn_v1dotpus,             NULL }, /* v1dotpus */
2949   { CODE_FOR_insn_v1dotpusa,            NULL }, /* v1dotpusa */
2950   { CODE_FOR_insn_v1int_h,              NULL }, /* v1int_h */
2951   { CODE_FOR_insn_v1int_l,              NULL }, /* v1int_l */
2952   { CODE_FOR_insn_v1maxu,               NULL }, /* v1maxu */
2953   { CODE_FOR_insn_v1maxui,              NULL }, /* v1maxui */
2954   { CODE_FOR_insn_v1minu,               NULL }, /* v1minu */
2955   { CODE_FOR_insn_v1minui,              NULL }, /* v1minui */
2956   { CODE_FOR_insn_v1mnz,                NULL }, /* v1mnz */
2957   { CODE_FOR_insn_v1multu,              NULL }, /* v1multu */
2958   { CODE_FOR_insn_v1mulu,               NULL }, /* v1mulu */
2959   { CODE_FOR_insn_v1mulus,              NULL }, /* v1mulus */
2960   { CODE_FOR_insn_v1mz,                 NULL }, /* v1mz */
2961   { CODE_FOR_insn_v1sadau,              NULL }, /* v1sadau */
2962   { CODE_FOR_insn_v1sadu,               NULL }, /* v1sadu */
2963   { CODE_FOR_insn_v1shl,                NULL }, /* v1shl */
2964   { CODE_FOR_insn_v1shl,                NULL }, /* v1shli */
2965   { CODE_FOR_insn_v1shrs,               NULL }, /* v1shrs */
2966   { CODE_FOR_insn_v1shrs,               NULL }, /* v1shrsi */
2967   { CODE_FOR_insn_v1shru,               NULL }, /* v1shru */
2968   { CODE_FOR_insn_v1shru,               NULL }, /* v1shrui */
2969   { CODE_FOR_insn_v1sub,                NULL }, /* v1sub */
2970   { CODE_FOR_insn_v1subuc,              NULL }, /* v1subuc */
2971   { CODE_FOR_insn_v2add,                NULL }, /* v2add */
2972   { CODE_FOR_insn_v2addi,               NULL }, /* v2addi */
2973   { CODE_FOR_insn_v2addsc,              NULL }, /* v2addsc */
2974   { CODE_FOR_insn_v2adiffs,             NULL }, /* v2adiffs */
2975   { CODE_FOR_insn_v2avgs,               NULL }, /* v2avgs */
2976   { CODE_FOR_insn_v2cmpeq,              NULL }, /* v2cmpeq */
2977   { CODE_FOR_insn_v2cmpeqi,             NULL }, /* v2cmpeqi */
2978   { CODE_FOR_insn_v2cmples,             NULL }, /* v2cmples */
2979   { CODE_FOR_insn_v2cmpleu,             NULL }, /* v2cmpleu */
2980   { CODE_FOR_insn_v2cmplts,             NULL }, /* v2cmplts */
2981   { CODE_FOR_insn_v2cmpltsi,            NULL }, /* v2cmpltsi */
2982   { CODE_FOR_insn_v2cmpltu,             NULL }, /* v2cmpltu */
2983   { CODE_FOR_insn_v2cmpltui,            NULL }, /* v2cmpltui */
2984   { CODE_FOR_insn_v2cmpne,              NULL }, /* v2cmpne */
2985   { CODE_FOR_insn_v2dotp,               NULL }, /* v2dotp */
2986   { CODE_FOR_insn_v2dotpa,              NULL }, /* v2dotpa */
2987   { CODE_FOR_insn_v2int_h,              NULL }, /* v2int_h */
2988   { CODE_FOR_insn_v2int_l,              NULL }, /* v2int_l */
2989   { CODE_FOR_insn_v2maxs,               NULL }, /* v2maxs */
2990   { CODE_FOR_insn_v2maxsi,              NULL }, /* v2maxsi */
2991   { CODE_FOR_insn_v2mins,               NULL }, /* v2mins */
2992   { CODE_FOR_insn_v2minsi,              NULL }, /* v2minsi */
2993   { CODE_FOR_insn_v2mnz,                NULL }, /* v2mnz */
2994   { CODE_FOR_insn_v2mulfsc,             NULL }, /* v2mulfsc */
2995   { CODE_FOR_insn_v2muls,               NULL }, /* v2muls */
2996   { CODE_FOR_insn_v2mults,              NULL }, /* v2mults */
2997   { CODE_FOR_insn_v2mz,                 NULL }, /* v2mz */
2998   { CODE_FOR_insn_v2packh,              NULL }, /* v2packh */
2999   { CODE_FOR_insn_v2packl,              NULL }, /* v2packl */
3000   { CODE_FOR_insn_v2packuc,             NULL }, /* v2packuc */
3001   { CODE_FOR_insn_v2sadas,              NULL }, /* v2sadas */
3002   { CODE_FOR_insn_v2sadau,              NULL }, /* v2sadau */
3003   { CODE_FOR_insn_v2sads,               NULL }, /* v2sads */
3004   { CODE_FOR_insn_v2sadu,               NULL }, /* v2sadu */
3005   { CODE_FOR_insn_v2shl,                NULL }, /* v2shl */
3006   { CODE_FOR_insn_v2shl,                NULL }, /* v2shli */
3007   { CODE_FOR_insn_v2shlsc,              NULL }, /* v2shlsc */
3008   { CODE_FOR_insn_v2shrs,               NULL }, /* v2shrs */
3009   { CODE_FOR_insn_v2shrs,               NULL }, /* v2shrsi */
3010   { CODE_FOR_insn_v2shru,               NULL }, /* v2shru */
3011   { CODE_FOR_insn_v2shru,               NULL }, /* v2shrui */
3012   { CODE_FOR_insn_v2sub,                NULL }, /* v2sub */
3013   { CODE_FOR_insn_v2subsc,              NULL }, /* v2subsc */
3014   { CODE_FOR_insn_v4add,                NULL }, /* v4add */
3015   { CODE_FOR_insn_v4addsc,              NULL }, /* v4addsc */
3016   { CODE_FOR_insn_v4int_h,              NULL }, /* v4int_h */
3017   { CODE_FOR_insn_v4int_l,              NULL }, /* v4int_l */
3018   { CODE_FOR_insn_v4packsc,             NULL }, /* v4packsc */
3019   { CODE_FOR_insn_v4shl,                NULL }, /* v4shl */
3020   { CODE_FOR_insn_v4shlsc,              NULL }, /* v4shlsc */
3021   { CODE_FOR_insn_v4shrs,               NULL }, /* v4shrs */
3022   { CODE_FOR_insn_v4shru,               NULL }, /* v4shru */
3023   { CODE_FOR_insn_v4sub,                NULL }, /* v4sub */
3024   { CODE_FOR_insn_v4subsc,              NULL }, /* v4subsc */
3025   { CODE_FOR_insn_wh64,                 NULL }, /* wh64 */
3026   { CODE_FOR_xordi3,                    NULL }, /* xor */
3027   { CODE_FOR_tilegx_network_barrier,    NULL }, /* network_barrier */
3028   { CODE_FOR_tilegx_idn0_receive,       NULL }, /* idn0_receive */
3029   { CODE_FOR_tilegx_idn1_receive,       NULL }, /* idn1_receive */
3030   { CODE_FOR_tilegx_idn_send,           NULL }, /* idn_send */
3031   { CODE_FOR_tilegx_udn0_receive,       NULL }, /* udn0_receive */
3032   { CODE_FOR_tilegx_udn1_receive,       NULL }, /* udn1_receive */
3033   { CODE_FOR_tilegx_udn2_receive,       NULL }, /* udn2_receive */
3034   { CODE_FOR_tilegx_udn3_receive,       NULL }, /* udn3_receive */
3035   { CODE_FOR_tilegx_udn_send,           NULL }, /* udn_send */
3036 };
3037 
3038 
3039 struct tilegx_builtin_def
3040 {
3041   const char *name;
3042   enum tilegx_builtin code;
3043   bool is_const;
3044   /* The first character is the return type.  Subsequent characters
3045      are the argument types. See char_to_type.  */
3046   const char *type;
3047 };
3048 
3049 
3050 static const struct tilegx_builtin_def tilegx_builtins[] = {
3051   { "__insn_add",                TILEGX_INSN_ADD,                true,  "lll"  },
3052   { "__insn_addi",               TILEGX_INSN_ADD,                true,  "lll"  },
3053   { "__insn_addli",              TILEGX_INSN_ADD,                true,  "lll"  },
3054   { "__insn_addx",               TILEGX_INSN_ADDX,               true,  "iii"  },
3055   { "__insn_addxi",              TILEGX_INSN_ADDX,               true,  "iii"  },
3056   { "__insn_addxli",             TILEGX_INSN_ADDX,               true,  "iii"  },
3057   { "__insn_addxsc",             TILEGX_INSN_ADDXSC,             true,  "iii"  },
3058   { "__insn_and",                TILEGX_INSN_AND,                true,  "lll"  },
3059   { "__insn_andi",               TILEGX_INSN_AND,                true,  "lll"  },
3060   { "__insn_bfexts",             TILEGX_INSN_BFEXTS,             true,  "llll" },
3061   { "__insn_bfextu",             TILEGX_INSN_BFEXTU,             true,  "llll" },
3062   { "__insn_bfins",              TILEGX_INSN_BFINS,              true,  "lllll"},
3063   { "__insn_clz",                TILEGX_INSN_CLZ,                true,  "ll"   },
3064   { "__insn_cmoveqz",            TILEGX_INSN_CMOVEQZ,            true,  "llll" },
3065   { "__insn_cmovnez",            TILEGX_INSN_CMOVNEZ,            true,  "llll" },
3066   { "__insn_cmpeq",              TILEGX_INSN_CMPEQ,              true,  "lll"  },
3067   { "__insn_cmpeqi",             TILEGX_INSN_CMPEQ,              true,  "lll"  },
3068   { "__insn_cmpexch",            TILEGX_INSN_CMPEXCH,            false, "lpl"  },
3069   { "__insn_cmpexch4",           TILEGX_INSN_CMPEXCH4,           false, "ipi"  },
3070   { "__insn_cmples",             TILEGX_INSN_CMPLES,             true,  "lll"  },
3071   { "__insn_cmpleu",             TILEGX_INSN_CMPLEU,             true,  "lll"  },
3072   { "__insn_cmplts",             TILEGX_INSN_CMPLTS,             true,  "lll"  },
3073   { "__insn_cmpltsi",            TILEGX_INSN_CMPLTS,             true,  "lll"  },
3074   { "__insn_cmpltu",             TILEGX_INSN_CMPLTU,             true,  "lll"  },
3075   { "__insn_cmpltui",            TILEGX_INSN_CMPLTU,             true,  "lll"  },
3076   { "__insn_cmpne",              TILEGX_INSN_CMPNE,              true,  "lll"  },
3077   { "__insn_cmul",               TILEGX_INSN_CMUL,               true,  "lll"  },
3078   { "__insn_cmula",              TILEGX_INSN_CMULA,              true,  "llll" },
3079   { "__insn_cmulaf",             TILEGX_INSN_CMULAF,             true,  "llll" },
3080   { "__insn_cmulf",              TILEGX_INSN_CMULF,              true,  "lll"  },
3081   { "__insn_cmulfr",             TILEGX_INSN_CMULFR,             true,  "lll"  },
3082   { "__insn_cmulh",              TILEGX_INSN_CMULH,              true,  "lll"  },
3083   { "__insn_cmulhr",             TILEGX_INSN_CMULHR,             true,  "lll"  },
3084   { "__insn_crc32_32",           TILEGX_INSN_CRC32_32,           true,  "lll"  },
3085   { "__insn_crc32_8",            TILEGX_INSN_CRC32_8,            true,  "lll"  },
3086   { "__insn_ctz",                TILEGX_INSN_CTZ,                true,  "ll"   },
3087   { "__insn_dblalign",           TILEGX_INSN_DBLALIGN,           true,  "lllk" },
3088   { "__insn_dblalign2",          TILEGX_INSN_DBLALIGN2,          true,  "lll"  },
3089   { "__insn_dblalign4",          TILEGX_INSN_DBLALIGN4,          true,  "lll"  },
3090   { "__insn_dblalign6",          TILEGX_INSN_DBLALIGN6,          true,  "lll"  },
3091   { "__insn_drain",              TILEGX_INSN_DRAIN,              false, "v"    },
3092   { "__insn_dtlbpr",             TILEGX_INSN_DTLBPR,             false, "vl"   },
3093   { "__insn_exch",               TILEGX_INSN_EXCH,               false, "lpl"  },
3094   { "__insn_exch4",              TILEGX_INSN_EXCH4,              false, "ipi"  },
3095   { "__insn_fdouble_add_flags",  TILEGX_INSN_FDOUBLE_ADD_FLAGS,  true,  "lll"  },
3096   { "__insn_fdouble_addsub",     TILEGX_INSN_FDOUBLE_ADDSUB,     true,  "llll" },
3097   { "__insn_fdouble_mul_flags",  TILEGX_INSN_FDOUBLE_MUL_FLAGS,  true,  "lll"  },
3098   { "__insn_fdouble_pack1",      TILEGX_INSN_FDOUBLE_PACK1,      true,  "lll"  },
3099   { "__insn_fdouble_pack2",      TILEGX_INSN_FDOUBLE_PACK2,      true,  "llll" },
3100   { "__insn_fdouble_sub_flags",  TILEGX_INSN_FDOUBLE_SUB_FLAGS,  true,  "lll"  },
3101   { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX, true,  "lll"  },
3102   { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN, true,  "lll"  },
3103   { "__insn_fetchadd",           TILEGX_INSN_FETCHADD,           false, "lpl"  },
3104   { "__insn_fetchadd4",          TILEGX_INSN_FETCHADD4,          false, "ipi"  },
3105   { "__insn_fetchaddgez",        TILEGX_INSN_FETCHADDGEZ,        false, "lpl"  },
3106   { "__insn_fetchaddgez4",       TILEGX_INSN_FETCHADDGEZ4,       false, "ipi"  },
3107   { "__insn_fetchand",           TILEGX_INSN_FETCHAND,           false, "lpl"  },
3108   { "__insn_fetchand4",          TILEGX_INSN_FETCHAND4,          false, "ipi"  },
3109   { "__insn_fetchor",            TILEGX_INSN_FETCHOR,            false, "lpl"  },
3110   { "__insn_fetchor4",           TILEGX_INSN_FETCHOR4,           false, "ipi"  },
3111   { "__insn_finv",               TILEGX_INSN_FINV,               false, "vk"   },
3112   { "__insn_flush",              TILEGX_INSN_FLUSH,              false, "vk"   },
3113   { "__insn_flushwb",            TILEGX_INSN_FLUSHWB,            false, "v"    },
3114   { "__insn_fnop",               TILEGX_INSN_FNOP,               false, "v"    },
3115   { "__insn_fsingle_add1",       TILEGX_INSN_FSINGLE_ADD1,       true,  "lll"  },
3116   { "__insn_fsingle_addsub2",    TILEGX_INSN_FSINGLE_ADDSUB2,    true,  "llll" },
3117   { "__insn_fsingle_mul1",       TILEGX_INSN_FSINGLE_MUL1,       true,  "lll"  },
3118   { "__insn_fsingle_mul2",       TILEGX_INSN_FSINGLE_MUL2,       true,  "lll"  },
3119   { "__insn_fsingle_pack1",      TILEGX_INSN_FSINGLE_PACK1,      true,  "ll"   },
3120   { "__insn_fsingle_pack2",      TILEGX_INSN_FSINGLE_PACK2,      true,  "lll"  },
3121   { "__insn_fsingle_sub1",       TILEGX_INSN_FSINGLE_SUB1,       true,  "lll"  },
3122   { "__insn_icoh",               TILEGX_INSN_ICOH,               false, "vk"   },
3123   { "__insn_ill",                TILEGX_INSN_ILL,                false, "v"    },
3124   { "__insn_info",               TILEGX_INSN_INFO,               false, "vl"   },
3125   { "__insn_infol",              TILEGX_INSN_INFOL,              false, "vl"   },
3126   { "__insn_inv",                TILEGX_INSN_INV,                false, "vp"   },
3127   { "__insn_ld",                 TILEGX_INSN_LD,                 false, "lk"   },
3128   { "__insn_ld1s",               TILEGX_INSN_LD1S,               false, "lk"   },
3129   { "__insn_ld1u",               TILEGX_INSN_LD1U,               false, "lk"   },
3130   { "__insn_ld2s",               TILEGX_INSN_LD2S,               false, "lk"   },
3131   { "__insn_ld2u",               TILEGX_INSN_LD2U,               false, "lk"   },
3132   { "__insn_ld4s",               TILEGX_INSN_LD4S,               false, "lk"   },
3133   { "__insn_ld4u",               TILEGX_INSN_LD4U,               false, "lk"   },
3134   { "__insn_ldna",               TILEGX_INSN_LDNA,               false, "lk"   },
3135   { "__insn_ldnt",               TILEGX_INSN_LDNT,               false, "lk"   },
3136   { "__insn_ldnt1s",             TILEGX_INSN_LDNT1S,             false, "lk"   },
3137   { "__insn_ldnt1u",             TILEGX_INSN_LDNT1U,             false, "lk"   },
3138   { "__insn_ldnt2s",             TILEGX_INSN_LDNT2S,             false, "lk"   },
3139   { "__insn_ldnt2u",             TILEGX_INSN_LDNT2U,             false, "lk"   },
3140   { "__insn_ldnt4s",             TILEGX_INSN_LDNT4S,             false, "lk"   },
3141   { "__insn_ldnt4u",             TILEGX_INSN_LDNT4U,             false, "lk"   },
3142   { "__insn_ld_L2",              TILEGX_INSN_LD_L2,              false, "lk"   },
3143   { "__insn_ld1s_L2",            TILEGX_INSN_LD1S_L2,            false, "lk"   },
3144   { "__insn_ld1u_L2",            TILEGX_INSN_LD1U_L2,            false, "lk"   },
3145   { "__insn_ld2s_L2",            TILEGX_INSN_LD2S_L2,            false, "lk"   },
3146   { "__insn_ld2u_L2",            TILEGX_INSN_LD2U_L2,            false, "lk"   },
3147   { "__insn_ld4s_L2",            TILEGX_INSN_LD4S_L2,            false, "lk"   },
3148   { "__insn_ld4u_L2",            TILEGX_INSN_LD4U_L2,            false, "lk"   },
3149   { "__insn_ldna_L2",            TILEGX_INSN_LDNA_L2,            false, "lk"   },
3150   { "__insn_ldnt_L2",            TILEGX_INSN_LDNT_L2,            false, "lk"   },
3151   { "__insn_ldnt1s_L2",          TILEGX_INSN_LDNT1S_L2,          false, "lk"   },
3152   { "__insn_ldnt1u_L2",          TILEGX_INSN_LDNT1U_L2,          false, "lk"   },
3153   { "__insn_ldnt2s_L2",          TILEGX_INSN_LDNT2S_L2,          false, "lk"   },
3154   { "__insn_ldnt2u_L2",          TILEGX_INSN_LDNT2U_L2,          false, "lk"   },
3155   { "__insn_ldnt4s_L2",          TILEGX_INSN_LDNT4S_L2,          false, "lk"   },
3156   { "__insn_ldnt4u_L2",          TILEGX_INSN_LDNT4U_L2,          false, "lk"   },
3157   { "__insn_ld_miss",            TILEGX_INSN_LD_MISS,            false, "lk"   },
3158   { "__insn_ld1s_miss",          TILEGX_INSN_LD1S_MISS,          false, "lk"   },
3159   { "__insn_ld1u_miss",          TILEGX_INSN_LD1U_MISS,          false, "lk"   },
3160   { "__insn_ld2s_miss",          TILEGX_INSN_LD2S_MISS,          false, "lk"   },
3161   { "__insn_ld2u_miss",          TILEGX_INSN_LD2U_MISS,          false, "lk"   },
3162   { "__insn_ld4s_miss",          TILEGX_INSN_LD4S_MISS,          false, "lk"   },
3163   { "__insn_ld4u_miss",          TILEGX_INSN_LD4U_MISS,          false, "lk"   },
3164   { "__insn_ldna_miss",          TILEGX_INSN_LDNA_MISS,          false, "lk"   },
3165   { "__insn_ldnt_miss",          TILEGX_INSN_LDNT_MISS,          false, "lk"   },
3166   { "__insn_ldnt1s_miss",        TILEGX_INSN_LDNT1S_MISS,        false, "lk"   },
3167   { "__insn_ldnt1u_miss",        TILEGX_INSN_LDNT1U_MISS,        false, "lk"   },
3168   { "__insn_ldnt2s_miss",        TILEGX_INSN_LDNT2S_MISS,        false, "lk"   },
3169   { "__insn_ldnt2u_miss",        TILEGX_INSN_LDNT2U_MISS,        false, "lk"   },
3170   { "__insn_ldnt4s_miss",        TILEGX_INSN_LDNT4S_MISS,        false, "lk"   },
3171   { "__insn_ldnt4u_miss",        TILEGX_INSN_LDNT4U_MISS,        false, "lk"   },
3172   { "__insn_lnk",                TILEGX_INSN_LNK,                true,  "l"    },
3173   { "__insn_mf",                 TILEGX_INSN_MF,                 false, "v"    },
3174   { "__insn_mfspr",              TILEGX_INSN_MFSPR,              false, "ll"   },
3175   { "__insn_mm",                 TILEGX_INSN_MM,                 true,  "lllll"},
3176   { "__insn_mnz",                TILEGX_INSN_MNZ,                true,  "lll"  },
3177   { "__insn_move",               TILEGX_INSN_MOVE,               true,  "ll"   },
3178   { "__insn_movei",              TILEGX_INSN_MOVE,               true,  "ll"   },
3179   { "__insn_moveli",             TILEGX_INSN_MOVE,               true,  "ll"   },
3180   { "__insn_mtspr",              TILEGX_INSN_MTSPR,              false, "vll"  },
3181   { "__insn_mul_hs_hs",          TILEGX_INSN_MUL_HS_HS,          true,  "lll"  },
3182   { "__insn_mul_hs_hu",          TILEGX_INSN_MUL_HS_HU,          true,  "lll"  },
3183   { "__insn_mul_hs_ls",          TILEGX_INSN_MUL_HS_LS,          true,  "lll"  },
3184   { "__insn_mul_hs_lu",          TILEGX_INSN_MUL_HS_LU,          true,  "lll"  },
3185   { "__insn_mul_hu_hu",          TILEGX_INSN_MUL_HU_HU,          true,  "lll"  },
3186   { "__insn_mul_hu_ls",          TILEGX_INSN_MUL_HU_LS,          true,  "lll"  },
3187   { "__insn_mul_hu_lu",          TILEGX_INSN_MUL_HU_LU,          true,  "lll"  },
3188   { "__insn_mul_ls_ls",          TILEGX_INSN_MUL_LS_LS,          true,  "lll"  },
3189   { "__insn_mul_ls_lu",          TILEGX_INSN_MUL_LS_LU,          true,  "lll"  },
3190   { "__insn_mul_lu_lu",          TILEGX_INSN_MUL_LU_LU,          true,  "lll"  },
3191   { "__insn_mula_hs_hs",         TILEGX_INSN_MULA_HS_HS,         true,  "llll" },
3192   { "__insn_mula_hs_hu",         TILEGX_INSN_MULA_HS_HU,         true,  "llll" },
3193   { "__insn_mula_hs_ls",         TILEGX_INSN_MULA_HS_LS,         true,  "llll" },
3194   { "__insn_mula_hs_lu",         TILEGX_INSN_MULA_HS_LU,         true,  "llll" },
3195   { "__insn_mula_hu_hu",         TILEGX_INSN_MULA_HU_HU,         true,  "llll" },
3196   { "__insn_mula_hu_ls",         TILEGX_INSN_MULA_HU_LS,         true,  "llll" },
3197   { "__insn_mula_hu_lu",         TILEGX_INSN_MULA_HU_LU,         true,  "llll" },
3198   { "__insn_mula_ls_ls",         TILEGX_INSN_MULA_LS_LS,         true,  "llll" },
3199   { "__insn_mula_ls_lu",         TILEGX_INSN_MULA_LS_LU,         true,  "llll" },
3200   { "__insn_mula_lu_lu",         TILEGX_INSN_MULA_LU_LU,         true,  "llll" },
3201   { "__insn_mulax",              TILEGX_INSN_MULAX,              true,  "iiii" },
3202   { "__insn_mulx",               TILEGX_INSN_MULX,               true,  "iii"  },
3203   { "__insn_mz",                 TILEGX_INSN_MZ,                 true,  "lll"  },
3204   { "__insn_nap",                TILEGX_INSN_NAP,                false, "v"    },
3205   { "__insn_nop",                TILEGX_INSN_NOP,                true,  "v"    },
3206   { "__insn_nor",                TILEGX_INSN_NOR,                true,  "lll"  },
3207   { "__insn_or",                 TILEGX_INSN_OR,                 true,  "lll"  },
3208   { "__insn_ori",                TILEGX_INSN_OR,                 true,  "lll"  },
3209   { "__insn_pcnt",               TILEGX_INSN_PCNT,               true,  "ll"   },
3210   { "__insn_prefetch",           TILEGX_INSN_PREFETCH_L1,        false, "vk"   },
3211   { "__insn_prefetch_l1",        TILEGX_INSN_PREFETCH_L1,        false, "vk"   },
3212   { "__insn_prefetch_l1_fault",  TILEGX_INSN_PREFETCH_L1_FAULT,  false, "vk"   },
3213   { "__insn_prefetch_l2",        TILEGX_INSN_PREFETCH_L2,        false, "vk"   },
3214   { "__insn_prefetch_l2_fault",  TILEGX_INSN_PREFETCH_L2_FAULT,  false, "vk"   },
3215   { "__insn_prefetch_l3",        TILEGX_INSN_PREFETCH_L3,        false, "vk"   },
3216   { "__insn_prefetch_l3_fault",  TILEGX_INSN_PREFETCH_L3_FAULT,  false, "vk"   },
3217   { "__insn_revbits",            TILEGX_INSN_REVBITS,            true,  "ll"   },
3218   { "__insn_revbytes",           TILEGX_INSN_REVBYTES,           true,  "ll"   },
3219   { "__insn_rotl",               TILEGX_INSN_ROTL,               true,  "lli"  },
3220   { "__insn_rotli",              TILEGX_INSN_ROTL,               true,  "lli"  },
3221   { "__insn_shl",                TILEGX_INSN_SHL,                true,  "lli"  },
3222   { "__insn_shl16insli",         TILEGX_INSN_SHL16INSLI,         true,  "lll"  },
3223   { "__insn_shl1add",            TILEGX_INSN_SHL1ADD,            true,  "lll"  },
3224   { "__insn_shl1addx",           TILEGX_INSN_SHL1ADDX,           true,  "iii"  },
3225   { "__insn_shl2add",            TILEGX_INSN_SHL2ADD,            true,  "lll"  },
3226   { "__insn_shl2addx",           TILEGX_INSN_SHL2ADDX,           true,  "iii"  },
3227   { "__insn_shl3add",            TILEGX_INSN_SHL3ADD,            true,  "lll"  },
3228   { "__insn_shl3addx",           TILEGX_INSN_SHL3ADDX,           true,  "iii"  },
3229   { "__insn_shli",               TILEGX_INSN_SHL,                true,  "lli"  },
3230   { "__insn_shlx",               TILEGX_INSN_SHLX,               true,  "iii"  },
3231   { "__insn_shlxi",              TILEGX_INSN_SHLX,               true,  "iii"  },
3232   { "__insn_shrs",               TILEGX_INSN_SHRS,               true,  "lli"  },
3233   { "__insn_shrsi",              TILEGX_INSN_SHRS,               true,  "lli"  },
3234   { "__insn_shru",               TILEGX_INSN_SHRU,               true,  "lli"  },
3235   { "__insn_shrui",              TILEGX_INSN_SHRU,               true,  "lli"  },
3236   { "__insn_shrux",              TILEGX_INSN_SHRUX,              true,  "iii"  },
3237   { "__insn_shruxi",             TILEGX_INSN_SHRUX,              true,  "iii"  },
3238   { "__insn_shufflebytes",       TILEGX_INSN_SHUFFLEBYTES,       true,  "llll" },
3239   { "__insn_shufflebytes1",      TILEGX_INSN_SHUFFLEBYTES1,      true,  "lll"  },
3240   { "__insn_st",                 TILEGX_INSN_ST,                 false, "vpl"  },
3241   { "__insn_st1",                TILEGX_INSN_ST1,                false, "vpl"  },
3242   { "__insn_st2",                TILEGX_INSN_ST2,                false, "vpl"  },
3243   { "__insn_st4",                TILEGX_INSN_ST4,                false, "vpl"  },
3244   { "__insn_stnt",               TILEGX_INSN_STNT,               false, "vpl"  },
3245   { "__insn_stnt1",              TILEGX_INSN_STNT1,              false, "vpl"  },
3246   { "__insn_stnt2",              TILEGX_INSN_STNT2,              false, "vpl"  },
3247   { "__insn_stnt4",              TILEGX_INSN_STNT4,              false, "vpl"  },
3248   { "__insn_sub",                TILEGX_INSN_SUB,                true,  "lll"  },
3249   { "__insn_subx",               TILEGX_INSN_SUBX,               true,  "iii"  },
3250   { "__insn_subxsc",             TILEGX_INSN_SUBXSC,             true,  "iii"  },
3251   { "__insn_tblidxb0",           TILEGX_INSN_TBLIDXB0,           true,  "lll"  },
3252   { "__insn_tblidxb1",           TILEGX_INSN_TBLIDXB1,           true,  "lll"  },
3253   { "__insn_tblidxb2",           TILEGX_INSN_TBLIDXB2,           true,  "lll"  },
3254   { "__insn_tblidxb3",           TILEGX_INSN_TBLIDXB3,           true,  "lll"  },
3255   { "__insn_v1add",              TILEGX_INSN_V1ADD,              true,  "lll"  },
3256   { "__insn_v1addi",             TILEGX_INSN_V1ADDI,             true,  "lll"  },
3257   { "__insn_v1adduc",            TILEGX_INSN_V1ADDUC,            true,  "lll"  },
3258   { "__insn_v1adiffu",           TILEGX_INSN_V1ADIFFU,           true,  "lll"  },
3259   { "__insn_v1avgu",             TILEGX_INSN_V1AVGU,             true,  "lll"  },
3260   { "__insn_v1cmpeq",            TILEGX_INSN_V1CMPEQ,            true,  "lll"  },
3261   { "__insn_v1cmpeqi",           TILEGX_INSN_V1CMPEQI,           true,  "lll"  },
3262   { "__insn_v1cmples",           TILEGX_INSN_V1CMPLES,           true,  "lll"  },
3263   { "__insn_v1cmpleu",           TILEGX_INSN_V1CMPLEU,           true,  "lll"  },
3264   { "__insn_v1cmplts",           TILEGX_INSN_V1CMPLTS,           true,  "lll"  },
3265   { "__insn_v1cmpltsi",          TILEGX_INSN_V1CMPLTSI,          true,  "lll"  },
3266   { "__insn_v1cmpltu",           TILEGX_INSN_V1CMPLTU,           true,  "lll"  },
3267   { "__insn_v1cmpltui",          TILEGX_INSN_V1CMPLTUI,          true,  "lll"  },
3268   { "__insn_v1cmpne",            TILEGX_INSN_V1CMPNE,            true,  "lll"  },
3269   { "__insn_v1ddotpu",           TILEGX_INSN_V1DDOTPU,           true,  "lll"  },
3270   { "__insn_v1ddotpua",          TILEGX_INSN_V1DDOTPUA,          true,  "llll" },
3271   { "__insn_v1ddotpus",          TILEGX_INSN_V1DDOTPUS,          true,  "lll"  },
3272   { "__insn_v1ddotpusa",         TILEGX_INSN_V1DDOTPUSA,         true,  "llll" },
3273   { "__insn_v1dotp",             TILEGX_INSN_V1DOTP,             true,  "lll"  },
3274   { "__insn_v1dotpa",            TILEGX_INSN_V1DOTPA,            true,  "llll" },
3275   { "__insn_v1dotpu",            TILEGX_INSN_V1DOTPU,            true,  "lll"  },
3276   { "__insn_v1dotpua",           TILEGX_INSN_V1DOTPUA,           true,  "llll" },
3277   { "__insn_v1dotpus",           TILEGX_INSN_V1DOTPUS,           true,  "lll"  },
3278   { "__insn_v1dotpusa",          TILEGX_INSN_V1DOTPUSA,          true,  "llll" },
3279   { "__insn_v1int_h",            TILEGX_INSN_V1INT_H,            true,  "lll"  },
3280   { "__insn_v1int_l",            TILEGX_INSN_V1INT_L,            true,  "lll"  },
3281   { "__insn_v1maxu",             TILEGX_INSN_V1MAXU,             true,  "lll"  },
3282   { "__insn_v1maxui",            TILEGX_INSN_V1MAXUI,            true,  "lll"  },
3283   { "__insn_v1minu",             TILEGX_INSN_V1MINU,             true,  "lll"  },
3284   { "__insn_v1minui",            TILEGX_INSN_V1MINUI,            true,  "lll"  },
3285   { "__insn_v1mnz",              TILEGX_INSN_V1MNZ,              true,  "lll"  },
3286   { "__insn_v1multu",            TILEGX_INSN_V1MULTU,            true,  "lll"  },
3287   { "__insn_v1mulu",             TILEGX_INSN_V1MULU,             true,  "lll"  },
3288   { "__insn_v1mulus",            TILEGX_INSN_V1MULUS,            true,  "lll"  },
3289   { "__insn_v1mz",               TILEGX_INSN_V1MZ,               true,  "lll"  },
3290   { "__insn_v1sadau",            TILEGX_INSN_V1SADAU,            true,  "llll" },
3291   { "__insn_v1sadu",             TILEGX_INSN_V1SADU,             true,  "lll"  },
3292   { "__insn_v1shl",              TILEGX_INSN_V1SHL,              true,  "lll"  },
3293   { "__insn_v1shli",             TILEGX_INSN_V1SHLI,             true,  "lll"  },
3294   { "__insn_v1shrs",             TILEGX_INSN_V1SHRS,             true,  "lll"  },
3295   { "__insn_v1shrsi",            TILEGX_INSN_V1SHRSI,            true,  "lll"  },
3296   { "__insn_v1shru",             TILEGX_INSN_V1SHRU,             true,  "lll"  },
3297   { "__insn_v1shrui",            TILEGX_INSN_V1SHRUI,            true,  "lll"  },
3298   { "__insn_v1sub",              TILEGX_INSN_V1SUB,              true,  "lll"  },
3299   { "__insn_v1subuc",            TILEGX_INSN_V1SUBUC,            true,  "lll"  },
3300   { "__insn_v2add",              TILEGX_INSN_V2ADD,              true,  "lll"  },
3301   { "__insn_v2addi",             TILEGX_INSN_V2ADDI,             true,  "lll"  },
3302   { "__insn_v2addsc",            TILEGX_INSN_V2ADDSC,            true,  "lll"  },
3303   { "__insn_v2adiffs",           TILEGX_INSN_V2ADIFFS,           true,  "lll"  },
3304   { "__insn_v2avgs",             TILEGX_INSN_V2AVGS,             true,  "lll"  },
3305   { "__insn_v2cmpeq",            TILEGX_INSN_V2CMPEQ,            true,  "lll"  },
3306   { "__insn_v2cmpeqi",           TILEGX_INSN_V2CMPEQI,           true,  "lll"  },
3307   { "__insn_v2cmples",           TILEGX_INSN_V2CMPLES,           true,  "lll"  },
3308   { "__insn_v2cmpleu",           TILEGX_INSN_V2CMPLEU,           true,  "lll"  },
3309   { "__insn_v2cmplts",           TILEGX_INSN_V2CMPLTS,           true,  "lll"  },
3310   { "__insn_v2cmpltsi",          TILEGX_INSN_V2CMPLTSI,          true,  "lll"  },
3311   { "__insn_v2cmpltu",           TILEGX_INSN_V2CMPLTU,           true,  "lll"  },
3312   { "__insn_v2cmpltui",          TILEGX_INSN_V2CMPLTUI,          true,  "lll"  },
3313   { "__insn_v2cmpne",            TILEGX_INSN_V2CMPNE,            true,  "lll"  },
3314   { "__insn_v2dotp",             TILEGX_INSN_V2DOTP,             true,  "lll"  },
3315   { "__insn_v2dotpa",            TILEGX_INSN_V2DOTPA,            true,  "llll" },
3316   { "__insn_v2int_h",            TILEGX_INSN_V2INT_H,            true,  "lll"  },
3317   { "__insn_v2int_l",            TILEGX_INSN_V2INT_L,            true,  "lll"  },
3318   { "__insn_v2maxs",             TILEGX_INSN_V2MAXS,             true,  "lll"  },
3319   { "__insn_v2maxsi",            TILEGX_INSN_V2MAXSI,            true,  "lll"  },
3320   { "__insn_v2mins",             TILEGX_INSN_V2MINS,             true,  "lll"  },
3321   { "__insn_v2minsi",            TILEGX_INSN_V2MINSI,            true,  "lll"  },
3322   { "__insn_v2mnz",              TILEGX_INSN_V2MNZ,              true,  "lll"  },
3323   { "__insn_v2mulfsc",           TILEGX_INSN_V2MULFSC,           true,  "lll"  },
3324   { "__insn_v2muls",             TILEGX_INSN_V2MULS,             true,  "lll"  },
3325   { "__insn_v2mults",            TILEGX_INSN_V2MULTS,            true,  "lll"  },
3326   { "__insn_v2mz",               TILEGX_INSN_V2MZ,               true,  "lll"  },
3327   { "__insn_v2packh",            TILEGX_INSN_V2PACKH,            true,  "lll"  },
3328   { "__insn_v2packl",            TILEGX_INSN_V2PACKL,            true,  "lll"  },
3329   { "__insn_v2packuc",           TILEGX_INSN_V2PACKUC,           true,  "lll"  },
3330   { "__insn_v2sadas",            TILEGX_INSN_V2SADAS,            true,  "llll" },
3331   { "__insn_v2sadau",            TILEGX_INSN_V2SADAU,            true,  "llll" },
3332   { "__insn_v2sads",             TILEGX_INSN_V2SADS,             true,  "lll"  },
3333   { "__insn_v2sadu",             TILEGX_INSN_V2SADU,             true,  "lll"  },
3334   { "__insn_v2shl",              TILEGX_INSN_V2SHL,              true,  "lll"  },
3335   { "__insn_v2shli",             TILEGX_INSN_V2SHLI,             true,  "lll"  },
3336   { "__insn_v2shlsc",            TILEGX_INSN_V2SHLSC,            true,  "lll"  },
3337   { "__insn_v2shrs",             TILEGX_INSN_V2SHRS,             true,  "lll"  },
3338   { "__insn_v2shrsi",            TILEGX_INSN_V2SHRSI,            true,  "lll"  },
3339   { "__insn_v2shru",             TILEGX_INSN_V2SHRU,             true,  "lll"  },
3340   { "__insn_v2shrui",            TILEGX_INSN_V2SHRUI,            true,  "lll"  },
3341   { "__insn_v2sub",              TILEGX_INSN_V2SUB,              true,  "lll"  },
3342   { "__insn_v2subsc",            TILEGX_INSN_V2SUBSC,            true,  "lll"  },
3343   { "__insn_v4add",              TILEGX_INSN_V4ADD,              true,  "lll"  },
3344   { "__insn_v4addsc",            TILEGX_INSN_V4ADDSC,            true,  "lll"  },
3345   { "__insn_v4int_h",            TILEGX_INSN_V4INT_H,            true,  "lll"  },
3346   { "__insn_v4int_l",            TILEGX_INSN_V4INT_L,            true,  "lll"  },
3347   { "__insn_v4packsc",           TILEGX_INSN_V4PACKSC,           true,  "lll"  },
3348   { "__insn_v4shl",              TILEGX_INSN_V4SHL,              true,  "lll"  },
3349   { "__insn_v4shlsc",            TILEGX_INSN_V4SHLSC,            true,  "lll"  },
3350   { "__insn_v4shrs",             TILEGX_INSN_V4SHRS,             true,  "lll"  },
3351   { "__insn_v4shru",             TILEGX_INSN_V4SHRU,             true,  "lll"  },
3352   { "__insn_v4sub",              TILEGX_INSN_V4SUB,              true,  "lll"  },
3353   { "__insn_v4subsc",            TILEGX_INSN_V4SUBSC,            true,  "lll"  },
3354   { "__insn_wh64",               TILEGX_INSN_WH64,               false, "vp"   },
3355   { "__insn_xor",                TILEGX_INSN_XOR,                true,  "lll"  },
3356   { "__insn_xori",               TILEGX_INSN_XOR,                true,  "lll"  },
3357   { "__tile_network_barrier",    TILEGX_NETWORK_BARRIER,         false, "v"    },
3358   { "__tile_idn0_receive",       TILEGX_IDN0_RECEIVE,            false, "l"    },
3359   { "__tile_idn1_receive",       TILEGX_IDN1_RECEIVE,            false, "l"    },
3360   { "__tile_idn_send",           TILEGX_IDN_SEND,                false, "vl"   },
3361   { "__tile_udn0_receive",       TILEGX_UDN0_RECEIVE,            false, "l"    },
3362   { "__tile_udn1_receive",       TILEGX_UDN1_RECEIVE,            false, "l"    },
3363   { "__tile_udn2_receive",       TILEGX_UDN2_RECEIVE,            false, "l"    },
3364   { "__tile_udn3_receive",       TILEGX_UDN3_RECEIVE,            false, "l"    },
3365   { "__tile_udn_send",           TILEGX_UDN_SEND,                false, "vl"   },
3366 };
3367 
3368 
3369 /* Convert a character in a builtin type string to a tree type.  */
3370 static tree
3371 char_to_type (char c)
3372 {
3373   static tree volatile_ptr_type_node = NULL;
3374   static tree volatile_const_ptr_type_node = NULL;
3375 
3376   if (volatile_ptr_type_node == NULL)
3377     {
3378       volatile_ptr_type_node =
3379 	build_pointer_type (build_qualified_type (void_type_node,
3380 						  TYPE_QUAL_VOLATILE));
3381       volatile_const_ptr_type_node =
3382 	build_pointer_type (build_qualified_type (void_type_node,
3383 						  TYPE_QUAL_CONST
3384 						  | TYPE_QUAL_VOLATILE));
3385     }
3386 
3387   switch (c)
3388     {
3389     case 'v':
3390       return void_type_node;
3391     case 'i':
3392       return unsigned_type_node;
3393     case 'l':
3394       return long_long_unsigned_type_node;
3395     case 'p':
3396       return volatile_ptr_type_node;
3397     case 'k':
3398       return volatile_const_ptr_type_node;
3399     default:
3400       gcc_unreachable ();
3401     }
3402 }
3403 
3404 
3405 /* Implement TARGET_INIT_BUILTINS.  */
3406 static void
3407 tilegx_init_builtins (void)
3408 {
3409   size_t i;
3410 
3411   for (i = 0; i < ARRAY_SIZE (tilegx_builtins); i++)
3412     {
3413       const struct tilegx_builtin_def *p = &tilegx_builtins[i];
3414       tree ftype, ret_type, arg_type_list = void_list_node;
3415       tree decl;
3416       int j;
3417 
3418       for (j = strlen (p->type) - 1; j > 0; j--)
3419 	{
3420 	  arg_type_list =
3421 	    tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list);
3422 	}
3423 
3424       ret_type = char_to_type (p->type[0]);
3425 
3426       ftype = build_function_type (ret_type, arg_type_list);
3427 
3428       decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
3429 				   NULL, NULL);
3430 
3431       if (p->is_const)
3432 	TREE_READONLY (decl) = 1;
3433       TREE_NOTHROW (decl) = 1;
3434 
3435       if (tilegx_builtin_info[p->code].fndecl == NULL)
3436 	tilegx_builtin_info[p->code].fndecl = decl;
3437     }
3438 }
3439 
3440 
3441 /* Implement TARGET_EXPAND_BUILTIN.  */
3442 static rtx
3443 tilegx_expand_builtin (tree exp,
3444 		       rtx target,
3445 		       rtx subtarget ATTRIBUTE_UNUSED,
3446 		       enum machine_mode mode ATTRIBUTE_UNUSED,
3447 		       int ignore ATTRIBUTE_UNUSED)
3448 {
3449 #define MAX_BUILTIN_ARGS 4
3450 
3451   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
3452   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
3453   tree arg;
3454   call_expr_arg_iterator iter;
3455   enum insn_code icode;
3456   rtx op[MAX_BUILTIN_ARGS + 1], pat;
3457   int opnum;
3458   bool nonvoid;
3459   insn_gen_fn fn;
3460 
3461   if (fcode >= TILEGX_BUILTIN_max)
3462     internal_error ("bad builtin fcode");
3463   icode = tilegx_builtin_info[fcode].icode;
3464   if (icode == 0)
3465     internal_error ("bad builtin icode");
3466 
3467   nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
3468 
3469   opnum = nonvoid;
3470   FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
3471     {
3472       const struct insn_operand_data *insn_op;
3473 
3474       if (arg == error_mark_node)
3475 	return NULL_RTX;
3476       if (opnum > MAX_BUILTIN_ARGS)
3477 	return NULL_RTX;
3478 
3479       insn_op = &insn_data[icode].operand[opnum];
3480 
3481       op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL);
3482 
3483       if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3484 	{
3485 	  enum machine_mode opmode = insn_op->mode;
3486 
3487 	  /* pointer_operand and pmode_register_operand operands do
3488 	     not specify a mode, so use the operand's mode instead
3489 	     (which should always be right by the time we get here,
3490 	     except for constants, which are VOIDmode).  */
3491 	  if (opmode == VOIDmode)
3492 	    {
3493 	      enum machine_mode m = GET_MODE (op[opnum]);
3494 	      gcc_assert (m == Pmode || m == VOIDmode);
3495 	      opmode = Pmode;
3496 	    }
3497 
3498 	  op[opnum] = copy_to_mode_reg (opmode, op[opnum]);
3499 	}
3500 
3501       if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3502 	{
3503 	  /* We still failed to meet the predicate even after moving
3504 	     into a register. Assume we needed an immediate.  */
3505 	  error_at (EXPR_LOCATION (exp),
3506 		    "operand must be an immediate of the right size");
3507 	  return const0_rtx;
3508 	}
3509 
3510       opnum++;
3511     }
3512 
3513   if (nonvoid)
3514     {
3515       enum machine_mode tmode = insn_data[icode].operand[0].mode;
3516       if (!target
3517 	  || GET_MODE (target) != tmode
3518 	  || !(*insn_data[icode].operand[0].predicate) (target, tmode))
3519 	{
3520 	  if (tmode == VOIDmode)
3521 	    {
3522 	      /* get the mode from the return type.  */
3523 	      tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl)));
3524 	    }
3525 	  target = gen_reg_rtx (tmode);
3526 	}
3527       op[0] = target;
3528     }
3529 
3530   fn = GEN_FCN (icode);
3531   switch (opnum)
3532     {
3533     case 0:
3534       pat = fn (NULL_RTX);
3535       break;
3536     case 1:
3537       pat = fn (op[0]);
3538       break;
3539     case 2:
3540       pat = fn (op[0], op[1]);
3541       break;
3542     case 3:
3543       pat = fn (op[0], op[1], op[2]);
3544       break;
3545     case 4:
3546       pat = fn (op[0], op[1], op[2], op[3]);
3547       break;
3548     case 5:
3549       pat = fn (op[0], op[1], op[2], op[3], op[4]);
3550       break;
3551     default:
3552       gcc_unreachable ();
3553     }
3554   if (!pat)
3555     return NULL_RTX;
3556 
3557   /* If we are generating a prefetch, tell the scheduler not to move
3558      it around.  */
3559   if (GET_CODE (pat) == PREFETCH)
3560     PREFETCH_SCHEDULE_BARRIER_P (pat) = true;
3561 
3562   emit_insn (pat);
3563 
3564   if (nonvoid)
3565     return target;
3566   else
3567     return const0_rtx;
3568 }
3569 
3570 
3571 /* Implement TARGET_BUILTIN_DECL.  */
3572 static tree
3573 tilegx_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
3574 {
3575   if (code >= TILEGX_BUILTIN_max)
3576     return error_mark_node;
3577 
3578   return tilegx_builtin_info[code].fndecl;
3579 }
3580 
3581 
3582 
3583 /* Stack frames  */
3584 
3585 /* Return whether REGNO needs to be saved in the stack frame.  */
3586 static bool
3587 need_to_save_reg (unsigned int regno)
3588 {
3589   if (!fixed_regs[regno] && !call_used_regs[regno]
3590       && df_regs_ever_live_p (regno))
3591     return true;
3592 
3593   if (flag_pic
3594       && (regno == PIC_OFFSET_TABLE_REGNUM
3595 	  || regno == TILEGX_PIC_TEXT_LABEL_REGNUM)
3596       && (crtl->uses_pic_offset_table || crtl->saves_all_registers))
3597     return true;
3598 
3599   if (crtl->calls_eh_return)
3600     {
3601       unsigned i;
3602       for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++)
3603 	{
3604 	  if (regno == EH_RETURN_DATA_REGNO (i))
3605 	    return true;
3606 	}
3607     }
3608 
3609   return false;
3610 }
3611 
3612 
3613 /* Return the size of the register savev area.  This function is only
3614    correct starting with local register allocation */
3615 static int
3616 tilegx_saved_regs_size (void)
3617 {
3618   int reg_save_size = 0;
3619   int regno;
3620   int offset_to_frame;
3621   int align_mask;
3622 
3623   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3624     if (need_to_save_reg (regno))
3625       reg_save_size += UNITS_PER_WORD;
3626 
3627   /* Pad out the register save area if necessary to make
3628      frame_pointer_rtx be as aligned as the stack pointer.  */
3629   offset_to_frame = crtl->args.pretend_args_size + reg_save_size;
3630   align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1;
3631   reg_save_size += (-offset_to_frame) & align_mask;
3632 
3633   return reg_save_size;
3634 }
3635 
3636 
3637 /* Round up frame size SIZE.  */
3638 static int
3639 round_frame_size (int size)
3640 {
3641   return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1)
3642 	  & -STACK_BOUNDARY / BITS_PER_UNIT);
3643 }
3644 
3645 
3646 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3647    emit the corresponding REG_CFA_OFFSET note described by CFA and
3648    CFA_OFFSET.  Return the emitted insn.  */
3649 static rtx
3650 frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa,
3651 		  int cfa_offset)
3652 {
3653   rtx reg = gen_rtx_REG (DImode, regno);
3654   rtx mem = gen_frame_mem (DImode, addr);
3655   rtx mov = gen_movdi (mem, reg);
3656 
3657   /* Describe what just happened in a way that dwarf understands.  We
3658      use temporary registers to hold the address to make scheduling
3659      easier, and use the REG_CFA_OFFSET to describe the address as an
3660      offset from the CFA.  */
3661   rtx reg_note = gen_rtx_REG (DImode, regno_note);
3662   rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, GEN_INT (cfa_offset));
3663   rtx cfa_relative_mem = gen_frame_mem (DImode, cfa_relative_addr);
3664   rtx real = gen_rtx_SET (VOIDmode, cfa_relative_mem, reg_note);
3665   add_reg_note (mov, REG_CFA_OFFSET, real);
3666 
3667   return emit_insn (mov);
3668 }
3669 
3670 
3671 /* Emit a load in the stack frame to load REGNO from address ADDR.
3672    Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3673    non-null.  Return the emitted insn.  */
3674 static rtx
3675 frame_emit_load (int regno, rtx addr, rtx *cfa_restores)
3676 {
3677   rtx reg = gen_rtx_REG (DImode, regno);
3678   rtx mem = gen_frame_mem (DImode, addr);
3679   if (cfa_restores)
3680     *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores);
3681   return emit_insn (gen_movdi (reg, mem));
3682 }
3683 
3684 
3685 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3686    including sequences.  */
3687 static rtx
3688 set_frame_related_p (void)
3689 {
3690   rtx seq = get_insns ();
3691   rtx insn;
3692 
3693   end_sequence ();
3694 
3695   if (!seq)
3696     return NULL_RTX;
3697 
3698   if (INSN_P (seq))
3699     {
3700       insn = seq;
3701       while (insn != NULL_RTX)
3702 	{
3703 	  RTX_FRAME_RELATED_P (insn) = 1;
3704 	  insn = NEXT_INSN (insn);
3705 	}
3706       seq = emit_insn (seq);
3707     }
3708   else
3709     {
3710       seq = emit_insn (seq);
3711       RTX_FRAME_RELATED_P (seq) = 1;
3712     }
3713   return seq;
3714 }
3715 
3716 
3717 #define FRP(exp)  (start_sequence (), exp, set_frame_related_p ())
3718 
3719 /* This emits code for 'sp += offset'.
3720 
3721    The ABI only allows us to modify 'sp' in a single 'addi' or
3722    'addli', so the backtracer understands it. Larger amounts cannot
3723    use those instructions, so are added by placing the offset into a
3724    large register and using 'add'.
3725 
3726    This happens after reload, so we need to expand it ourselves.  */
3727 static rtx
3728 emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related,
3729 		rtx reg_notes)
3730 {
3731   rtx to_add;
3732   rtx imm_rtx = GEN_INT (offset);
3733 
3734   rtx insn;
3735   if (satisfies_constraint_J (imm_rtx))
3736     {
3737       /* We can add this using a single immediate add.  */
3738       to_add = imm_rtx;
3739     }
3740   else
3741     {
3742       rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3743       tilegx_expand_set_const64 (tmp, imm_rtx);
3744       to_add = tmp;
3745     }
3746 
3747   /* Actually adjust the stack pointer.  */
3748   if (TARGET_32BIT)
3749     insn = gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx, to_add);
3750   else
3751     insn = gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx, to_add);
3752 
3753   insn = emit_insn (insn);
3754   REG_NOTES (insn) = reg_notes;
3755 
3756   /* Describe what just happened in a way that dwarf understands.  */
3757   if (frame_related)
3758     {
3759       rtx real = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
3760 			      gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3761 					    imm_rtx));
3762       RTX_FRAME_RELATED_P (insn) = 1;
3763       add_reg_note (insn, REG_CFA_ADJUST_CFA, real);
3764     }
3765 
3766   return insn;
3767 }
3768 
3769 
3770 /* Return whether the current function is leaf.  This takes into
3771    account whether the function calls tls_get_addr.  */
3772 static bool
3773 tilegx_current_function_is_leaf (void)
3774 {
3775   return crtl->is_leaf && !cfun->machine->calls_tls_get_addr;
3776 }
3777 
3778 
3779 /* Return the frame size.  */
3780 static int
3781 compute_total_frame_size (void)
3782 {
3783   int total_size = (get_frame_size () + tilegx_saved_regs_size ()
3784 		    + crtl->outgoing_args_size
3785 		    + crtl->args.pretend_args_size);
3786 
3787   if (!tilegx_current_function_is_leaf () || cfun->calls_alloca)
3788     {
3789       /* Make room for save area in callee.  */
3790       total_size += STACK_POINTER_OFFSET;
3791     }
3792 
3793   return round_frame_size (total_size);
3794 }
3795 
3796 
3797 /* Return nonzero if this function is known to have a null epilogue.
3798    This allows the optimizer to omit jumps to jumps if no stack was
3799    created.  */
3800 bool
3801 tilegx_can_use_return_insn_p (void)
3802 {
3803   return (reload_completed
3804 	  && cfun->static_chain_decl == 0
3805 	  && compute_total_frame_size () == 0
3806 	  && tilegx_current_function_is_leaf ()
3807 	  && !crtl->profile && !df_regs_ever_live_p (TILEGX_LINK_REGNUM));
3808 }
3809 
3810 
3811 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'.  If there
3812    is a frame pointer, it computes the value relative to
3813    that. Otherwise it uses the stack pointer.  */
3814 static rtx
3815 compute_frame_addr (int offset_from_fp, int *next_scratch_regno)
3816 {
3817   rtx base_reg_rtx, tmp_reg_rtx, offset_rtx;
3818   int offset_from_base;
3819 
3820   if (frame_pointer_needed)
3821     {
3822       base_reg_rtx = hard_frame_pointer_rtx;
3823       offset_from_base = offset_from_fp;
3824     }
3825   else
3826     {
3827       int offset_from_sp = compute_total_frame_size () + offset_from_fp;
3828       offset_from_base = offset_from_sp;
3829       base_reg_rtx = stack_pointer_rtx;
3830     }
3831 
3832   if (offset_from_base == 0)
3833     return base_reg_rtx;
3834 
3835   /* Compute the new value of the stack pointer.  */
3836   tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3837   offset_rtx = GEN_INT (offset_from_base);
3838 
3839   if (!add_operand (offset_rtx, Pmode))
3840     {
3841       expand_set_cint64 (tmp_reg_rtx, offset_rtx);
3842       offset_rtx = tmp_reg_rtx;
3843     }
3844 
3845   emit_insn (gen_rtx_SET (VOIDmode, tmp_reg_rtx,
3846 			  gen_rtx_PLUS (Pmode, base_reg_rtx, offset_rtx)));
3847 
3848   return tmp_reg_rtx;
3849 }
3850 
3851 
3852 /* The stack frame looks like this:
3853          +-------------+
3854          |    ...      |
3855          |  incoming   |
3856          | stack args  |
3857    AP -> +-------------+
3858          | caller's HFP|
3859          +-------------+
3860          | lr save     |
3861   HFP -> +-------------+
3862          |  var args   |
3863          |  reg save   | crtl->args.pretend_args_size bytes
3864          +-------------+
3865          |    ...      |
3866          | saved regs  | tilegx_saved_regs_size() bytes
3867    FP -> +-------------+
3868          |    ...      |
3869          |   vars      | get_frame_size() bytes
3870          +-------------+
3871          |    ...      |
3872          |  outgoing   |
3873          |  stack args | crtl->outgoing_args_size bytes
3874          +-------------+
3875          | HFP         | ptr_size bytes (only here if nonleaf / alloca)
3876          +-------------+
3877          | callee lr   | ptr_size bytes (only here if nonleaf / alloca)
3878          | save        |
3879    SP -> +-------------+
3880 
3881   HFP == incoming SP.
3882 
3883   For functions with a frame larger than 32767 bytes, or which use
3884   alloca (), r52 is used as a frame pointer.  Otherwise there is no
3885   frame pointer.
3886 
3887   FP is saved at SP+ptr_size before calling a subroutine so the callee
3888   can chain.  */
3889 void
3890 tilegx_expand_prologue (void)
3891 {
3892 #define ROUND_ROBIN_SIZE 4
3893   /* We round-robin through four scratch registers to hold temporary
3894      addresses for saving registers, to make instruction scheduling
3895      easier.  */
3896   rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3897     NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3898   };
3899   rtx insn, cfa;
3900   unsigned int which_scratch;
3901   int offset, start_offset, regno;
3902 
3903   /* A register that holds a copy of the incoming fp.  */
3904   int fp_copy_regno = -1;
3905 
3906   /* A register that holds a copy of the incoming sp.  */
3907   int sp_copy_regno = -1;
3908 
3909   /* Next scratch register number to hand out (postdecrementing).  */
3910   int next_scratch_regno = 29;
3911 
3912   int total_size = compute_total_frame_size ();
3913 
3914   if (flag_stack_usage_info)
3915     current_function_static_stack_size = total_size;
3916 
3917   /* Save lr first in its special location because code after this
3918      might use the link register as a scratch register.  */
3919   if (df_regs_ever_live_p (TILEGX_LINK_REGNUM) || crtl->calls_eh_return)
3920     FRP (frame_emit_store (TILEGX_LINK_REGNUM, TILEGX_LINK_REGNUM,
3921 			   stack_pointer_rtx, stack_pointer_rtx, 0));
3922 
3923   if (total_size == 0)
3924     {
3925       /* Load the PIC register if needed.  */
3926       if (flag_pic && crtl->uses_pic_offset_table)
3927 	load_pic_register (false);
3928 
3929       return;
3930     }
3931 
3932   cfa = stack_pointer_rtx;
3933 
3934   if (frame_pointer_needed)
3935     {
3936       fp_copy_regno = next_scratch_regno--;
3937 
3938       /* Copy the old frame pointer aside so we can save it later.  */
3939       insn =
3940 	FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno),
3941 			     gen_lowpart (word_mode, hard_frame_pointer_rtx)));
3942       add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
3943 
3944       /* Set up the frame pointer.  */
3945       insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
3946       add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx);
3947       cfa = hard_frame_pointer_rtx;
3948       REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
3949 
3950       /* fp holds a copy of the incoming sp, in case we need to store
3951 	 it.  */
3952       sp_copy_regno = HARD_FRAME_POINTER_REGNUM;
3953     }
3954   else if (!tilegx_current_function_is_leaf ())
3955     {
3956       /* Copy the old stack pointer aside so we can save it later.  */
3957       sp_copy_regno = next_scratch_regno--;
3958       emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno),
3959 		      stack_pointer_rtx);
3960     }
3961 
3962   if (tilegx_current_function_is_leaf ())
3963     {
3964       /* No need to store chain pointer to caller's frame.  */
3965       emit_sp_adjust (-total_size, &next_scratch_regno,
3966 		      !frame_pointer_needed, NULL_RTX);
3967     }
3968   else
3969     {
3970       /* Save the frame pointer (incoming sp value) to support
3971          backtracing.  First we need to create an rtx with the store
3972          address.  */
3973       rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--);
3974       rtx size_rtx = GEN_INT (-(total_size - UNITS_PER_WORD));
3975 
3976       if (add_operand (size_rtx, Pmode))
3977 	{
3978 	  /* Expose more parallelism by computing this value from the
3979 	     original stack pointer, not the one after we have pushed
3980 	     the frame.  */
3981 	  rtx p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, size_rtx);
3982 	  emit_insn (gen_rtx_SET (VOIDmode, chain_addr, p));
3983 	  emit_sp_adjust (-total_size, &next_scratch_regno,
3984 			  !frame_pointer_needed, NULL_RTX);
3985 	}
3986       else
3987 	{
3988 	  /* The stack frame is large, so just store the incoming sp
3989 	     value at *(new_sp + UNITS_PER_WORD).  */
3990 	  rtx p;
3991 	  emit_sp_adjust (-total_size, &next_scratch_regno,
3992 			  !frame_pointer_needed, NULL_RTX);
3993 	  p = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3994 			    GEN_INT (UNITS_PER_WORD));
3995 	  emit_insn (gen_rtx_SET (VOIDmode, chain_addr, p));
3996 	}
3997 
3998       /* Save our frame pointer for backtrace chaining.  */
3999       emit_insn (gen_movdi (gen_frame_mem (DImode, chain_addr),
4000 			    gen_rtx_REG (DImode, sp_copy_regno)));
4001     }
4002 
4003   /* Compute where to start storing registers we need to save.  */
4004   start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
4005   offset = start_offset;
4006 
4007   /* Store all registers that need saving.  */
4008   which_scratch = 0;
4009   for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
4010     if (need_to_save_reg (regno))
4011       {
4012 	rtx r = reg_save_addr[which_scratch];
4013 	int from_regno;
4014 	int cfa_offset = frame_pointer_needed ? offset : total_size + offset;
4015 
4016 	if (r == NULL_RTX)
4017 	  {
4018 	    int prev_scratch_regno = next_scratch_regno;
4019 	    r = compute_frame_addr (offset, &next_scratch_regno);
4020 	    if (prev_scratch_regno != next_scratch_regno)
4021 	      reg_save_addr[which_scratch] = r;
4022 	  }
4023 	else
4024 	  {
4025 	    /* Advance to the next stack slot to store this
4026 	       register.  */
4027 	    int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
4028 	    rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
4029 	    emit_insn (gen_rtx_SET (VOIDmode, r, p));
4030 	  }
4031 
4032 	/* Save this register to the stack (but use the old fp value
4033 	   we copied aside if appropriate).  */
4034 	from_regno =
4035 	  (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM)
4036 	  ? fp_copy_regno : regno;
4037 	FRP (frame_emit_store (from_regno, regno, r, cfa, cfa_offset));
4038 
4039 	offset -= UNITS_PER_WORD;
4040 	which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
4041       }
4042 
4043   /* If profiling, force that to happen after the frame is set up.  */
4044   if (crtl->profile)
4045     emit_insn (gen_blockage ());
4046 
4047   /* Load the PIC register if needed.  */
4048   if (flag_pic && crtl->uses_pic_offset_table)
4049     load_pic_register (false);
4050 }
4051 
4052 
4053 /* Implement the epilogue and sibcall_epilogue patterns.  SIBCALL_P is
4054    true for a sibcall_epilogue pattern, and false for an epilogue
4055    pattern.  */
4056 void
4057 tilegx_expand_epilogue (bool sibcall_p)
4058 {
4059   /* We round-robin through four scratch registers to hold temporary
4060      addresses for saving registers, to make instruction scheduling
4061      easier.  */
4062   rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
4063     NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
4064   };
4065   rtx last_insn, insn;
4066   unsigned int which_scratch;
4067   int offset, start_offset, regno;
4068   rtx cfa_restores = NULL_RTX;
4069 
4070   /* A register that holds a copy of the incoming fp.  */
4071   int fp_copy_regno = -1;
4072 
4073   /* Next scratch register number to hand out (postdecrementing).  */
4074   int next_scratch_regno = 29;
4075 
4076   int total_size = compute_total_frame_size ();
4077 
4078   last_insn = get_last_insn ();
4079 
4080   /* Load lr first since we are going to need it first.  */
4081   insn = NULL;
4082   if (df_regs_ever_live_p (TILEGX_LINK_REGNUM))
4083     {
4084       insn = frame_emit_load (TILEGX_LINK_REGNUM,
4085 			      compute_frame_addr (0, &next_scratch_regno),
4086 			      &cfa_restores);
4087     }
4088 
4089   if (total_size == 0)
4090     {
4091       if (insn)
4092 	{
4093 	  RTX_FRAME_RELATED_P (insn) = 1;
4094 	  REG_NOTES (insn) = cfa_restores;
4095 	}
4096       goto done;
4097     }
4098 
4099   /* Compute where to start restoring registers.  */
4100   start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
4101   offset = start_offset;
4102 
4103   if (frame_pointer_needed)
4104     fp_copy_regno = next_scratch_regno--;
4105 
4106   /* Restore all callee-saved registers.  */
4107   which_scratch = 0;
4108   for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
4109     if (need_to_save_reg (regno))
4110       {
4111 	rtx r = reg_save_addr[which_scratch];
4112 	if (r == NULL_RTX)
4113 	  {
4114 	    r = compute_frame_addr (offset, &next_scratch_regno);
4115 	    reg_save_addr[which_scratch] = r;
4116 	  }
4117 	else
4118 	  {
4119 	    /* Advance to the next stack slot to store this register.  */
4120 	    int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
4121 	    rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
4122 	    emit_insn (gen_rtx_SET (VOIDmode, r, p));
4123 	  }
4124 
4125 	if (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM)
4126 	  frame_emit_load (fp_copy_regno, r, NULL);
4127 	else
4128 	  frame_emit_load (regno, r, &cfa_restores);
4129 
4130 	offset -= UNITS_PER_WORD;
4131 	which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
4132       }
4133 
4134   if (!tilegx_current_function_is_leaf ())
4135     cfa_restores =
4136       alloc_reg_note (REG_CFA_RESTORE, stack_pointer_rtx, cfa_restores);
4137 
4138   emit_insn (gen_blockage ());
4139 
4140   if (frame_pointer_needed)
4141     {
4142       /* Restore the old stack pointer by copying from the frame
4143 	 pointer.  */
4144       if (TARGET_32BIT)
4145 	{
4146 	  insn = emit_insn (gen_sp_restore_32bit (stack_pointer_rtx,
4147 						  hard_frame_pointer_rtx));
4148 	}
4149       else
4150 	{
4151 	  insn = emit_insn (gen_sp_restore (stack_pointer_rtx,
4152 					    hard_frame_pointer_rtx));
4153 	}
4154       RTX_FRAME_RELATED_P (insn) = 1;
4155       REG_NOTES (insn) = cfa_restores;
4156       add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx);
4157     }
4158   else
4159     {
4160       insn = emit_sp_adjust (total_size, &next_scratch_regno, true,
4161 			     cfa_restores);
4162     }
4163 
4164   if (crtl->calls_eh_return)
4165     {
4166       if (TARGET_32BIT)
4167 	emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx,
4168 					EH_RETURN_STACKADJ_RTX));
4169       else
4170 	emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
4171 				  EH_RETURN_STACKADJ_RTX));
4172     }
4173 
4174   /* Restore the old frame pointer.  */
4175   if (frame_pointer_needed)
4176     {
4177       insn = emit_move_insn (gen_lowpart (DImode, hard_frame_pointer_rtx),
4178 			     gen_rtx_REG (DImode, fp_copy_regno));
4179       add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);
4180     }
4181 
4182   /* Mark the pic registers as live outside of the function.  */
4183   if (flag_pic)
4184     {
4185       emit_use (cfun->machine->text_label_rtx);
4186       emit_use (cfun->machine->got_rtx);
4187     }
4188 
4189 done:
4190   if (!sibcall_p)
4191     {
4192       emit_jump_insn (gen__return ());
4193     }
4194   else
4195     {
4196       emit_use (gen_rtx_REG (Pmode, TILEGX_LINK_REGNUM));
4197     }
4198 
4199   /* Mark all insns we just emitted as frame-related.  */
4200   for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn))
4201     RTX_FRAME_RELATED_P (last_insn) = 1;
4202 }
4203 
4204 #undef ROUND_ROBIN_SIZE
4205 
4206 
4207 /* Implement INITIAL_ELIMINATION_OFFSET.  */
4208 int
4209 tilegx_initial_elimination_offset (int from, int to)
4210 {
4211   int total_size = compute_total_frame_size ();
4212 
4213   if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
4214     {
4215       return (total_size - crtl->args.pretend_args_size
4216 	      - tilegx_saved_regs_size ());
4217     }
4218   else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
4219     {
4220       return -(crtl->args.pretend_args_size + tilegx_saved_regs_size ());
4221     }
4222   else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
4223     {
4224       return STACK_POINTER_OFFSET + total_size;
4225     }
4226   else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
4227     {
4228       return STACK_POINTER_OFFSET;
4229     }
4230   else
4231     gcc_unreachable ();
4232 }
4233 
4234 
4235 /* Return an RTX indicating where the return address to the calling
4236    function can be found.  */
4237 rtx
4238 tilegx_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
4239 {
4240   if (count != 0)
4241     return const0_rtx;
4242 
4243   return get_hard_reg_initial_val (Pmode, TILEGX_LINK_REGNUM);
4244 }
4245 
4246 
4247 /* Implement EH_RETURN_HANDLER_RTX.  The MEM needs to be volatile to
4248    prevent it from being deleted.  */
4249 rtx
4250 tilegx_eh_return_handler_rtx (void)
4251 {
4252   rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
4253   MEM_VOLATILE_P (tmp) = true;
4254   return tmp;
4255 }
4256 
4257 
4258 
4259 /* Registers  */
4260 
4261 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE.  */
4262 static void
4263 tilegx_conditional_register_usage (void)
4264 {
4265   global_regs[TILEGX_NETORDER_REGNUM] = 1;
4266   /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used.  It is a
4267      member of fixed_regs, and therefore must be member of
4268      call_used_regs, but it is not a member of call_really_used_regs[]
4269      because it is not clobbered by a call.  */
4270   if (TILEGX_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM)
4271     {
4272       fixed_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1;
4273       call_used_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1;
4274     }
4275   if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
4276     {
4277       fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
4278       call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
4279     }
4280 }
4281 
4282 
4283 /* Implement TARGET_FRAME_POINTER_REQUIRED.  */
4284 static bool
4285 tilegx_frame_pointer_required (void)
4286 {
4287   return crtl->calls_eh_return || cfun->calls_alloca;
4288 }
4289 
4290 
4291 
4292 /* Scheduling and reorg  */
4293 
4294 /* Return the length of INSN.  LENGTH is the initial length computed
4295    by attributes in the machine-description file.  This is where we
4296    account for bundles.  */
4297 int
4298 tilegx_adjust_insn_length (rtx insn, int length)
4299 {
4300   enum machine_mode mode = GET_MODE (insn);
4301 
4302   /* A non-termininating instruction in a bundle has length 0.  */
4303   if (mode == SImode)
4304     return 0;
4305 
4306   /* By default, there is not length adjustment.  */
4307   return length;
4308 }
4309 
4310 
4311 /* Implement TARGET_SCHED_ISSUE_RATE.  */
4312 static int
4313 tilegx_issue_rate (void)
4314 {
4315   return 3;
4316 }
4317 
4318 
4319 /* Return the rtx for the jump target.  */
4320 static rtx
4321 get_jump_target (rtx branch)
4322 {
4323   if (CALL_P (branch))
4324     {
4325       rtx call;
4326       call = PATTERN (branch);
4327 
4328       if (GET_CODE (call) == PARALLEL)
4329 	call = XVECEXP (call, 0, 0);
4330 
4331       if (GET_CODE (call) == SET)
4332 	call = SET_SRC (call);
4333 
4334       if (GET_CODE (call) == CALL)
4335 	return XEXP (XEXP (call, 0), 0);
4336     }
4337   return 0;
4338 }
4339 
4340 
4341 /* Implement TARGET_SCHED_ADJUST_COST.  */
4342 static int
4343 tilegx_sched_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
4344 {
4345   /* If we have a true dependence, INSN is a call, and DEP_INSN
4346      defines a register that is needed by the call (argument or stack
4347      pointer) , set its latency to 0 so that it can be bundled with
4348      the call.  Explicitly check for and exclude the case when
4349      DEP_INSN defines the target of the jump.  */
4350   if (CALL_P (insn) && REG_NOTE_KIND (link) == REG_DEP_TRUE)
4351     {
4352       rtx target = get_jump_target (insn);
4353       if (!REG_P (target) || !set_of (target, dep_insn))
4354 	return 0;
4355     }
4356 
4357   return cost;
4358 }
4359 
4360 
4361 /* Skip over irrelevant NOTEs and such and look for the next insn we
4362    would consider bundling.  */
4363 static rtx
4364 next_insn_to_bundle (rtx r, rtx end)
4365 {
4366   for (; r != end; r = NEXT_INSN (r))
4367     {
4368       if (NONDEBUG_INSN_P (r)
4369 	  && GET_CODE (PATTERN (r)) != USE
4370 	  && GET_CODE (PATTERN (r)) != CLOBBER)
4371 	return r;
4372     }
4373 
4374   return NULL_RTX;
4375 }
4376 
4377 
4378 /* Go through all insns, and use the information generated during
4379    scheduling to generate SEQUENCEs to represent bundles of
4380    instructions issued simultaneously.  */
4381 static void
4382 tilegx_gen_bundles (void)
4383 {
4384   basic_block bb;
4385   FOR_EACH_BB (bb)
4386     {
4387       rtx insn, next, prev;
4388       rtx end = NEXT_INSN (BB_END (bb));
4389 
4390       prev = NULL_RTX;
4391       for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn;
4392 	   prev = insn, insn = next)
4393 	{
4394 	  next = next_insn_to_bundle (NEXT_INSN (insn), end);
4395 
4396 	  /* Never wrap {} around inline asm.  */
4397 	  if (GET_CODE (PATTERN (insn)) != ASM_INPUT)
4398 	    {
4399 	      if (next == NULL_RTX || GET_MODE (next) == TImode
4400 		  /* NOTE: The scheduler incorrectly believes a call
4401 		     insn can execute in the same cycle as the insn
4402 		     after the call.  This is of course impossible.
4403 		     Really we need to fix the scheduler somehow, so
4404 		     the code after the call gets scheduled
4405 		     optimally.  */
4406 		  || CALL_P (insn))
4407 		{
4408 		  /* Mark current insn as the end of a bundle.  */
4409 		  PUT_MODE (insn, QImode);
4410 		}
4411 	      else
4412 		{
4413 		  /* Mark it as part of a bundle.  */
4414 		  PUT_MODE (insn, SImode);
4415 		}
4416 	    }
4417 
4418 	  /* Delete barrier insns, because they can mess up the
4419 	     emitting of bundle braces.  If it is end-of-bundle, then
4420 	     the previous insn must be marked end-of-bundle.  */
4421 	  if (get_attr_type (insn) == TYPE_NOTHING) {
4422 	    if (GET_MODE (insn) == QImode && prev != NULL
4423 		&& GET_MODE (prev) == SImode)
4424 	      {
4425 		PUT_MODE (prev, QImode);
4426 	      }
4427 	    delete_insn (insn);
4428 	  }
4429 	}
4430     }
4431 }
4432 
4433 
4434 /* Replace OLD_INSN with NEW_INSN.  */
4435 static void
4436 replace_insns (rtx old_insn, rtx new_insns)
4437 {
4438   if (new_insns)
4439     emit_insn_before (new_insns, old_insn);
4440 
4441   delete_insn (old_insn);
4442 }
4443 
4444 
4445 /* Returns true if INSN is the first instruction of a pc-relative
4446    address compuatation.  */
4447 static bool
4448 match_pcrel_step1 (rtx insn)
4449 {
4450   rtx pattern = PATTERN (insn);
4451   rtx src;
4452 
4453   if (GET_CODE (pattern) != SET)
4454     return false;
4455 
4456   src = SET_SRC (pattern);
4457 
4458   return (GET_CODE (src) == CONST
4459 	  && GET_CODE (XEXP (src, 0)) == UNSPEC
4460 	  && XINT (XEXP (src, 0), 1) == UNSPEC_HW1_LAST_PCREL);
4461 }
4462 
4463 
4464 /* Do the first replacement step in tilegx_fixup_pcrel_references.  */
4465 static void
4466 replace_mov_pcrel_step1 (rtx insn)
4467 {
4468   rtx pattern = PATTERN (insn);
4469   rtx unspec;
4470   rtx opnds[2];
4471   rtx new_insns;
4472 
4473   gcc_assert (GET_CODE (pattern) == SET);
4474   opnds[0] = SET_DEST (pattern);
4475 
4476   gcc_assert (GET_CODE (SET_SRC (pattern)) == CONST);
4477 
4478   unspec = XEXP (SET_SRC (pattern), 0);
4479   gcc_assert (GET_CODE (unspec) == UNSPEC);
4480   gcc_assert (XINT (unspec, 1) == UNSPEC_HW1_LAST_PCREL);
4481   opnds[1] = XVECEXP (unspec, 0, 0);
4482 
4483   /* We only need to replace SYMBOL_REFs, not LABEL_REFs.  */
4484   if (GET_CODE (opnds[1]) != SYMBOL_REF)
4485     return;
4486 
4487   start_sequence ();
4488 
4489   if (flag_pic != 1)
4490     {
4491       if (TARGET_32BIT)
4492 	emit_insn (gen_mov_got32_step1_32bit (opnds[0], opnds[1]));
4493       else
4494 	emit_insn (gen_mov_got32_step1 (opnds[0], opnds[1]));
4495     }
4496 
4497   new_insns = get_insns ();
4498   end_sequence ();
4499 
4500   replace_insns (insn, new_insns);
4501 }
4502 
4503 
4504 /* Returns true if INSN is the second instruction of a pc-relative
4505    address compuatation.  */
4506 static bool
4507 match_pcrel_step2 (rtx insn)
4508 {
4509   rtx unspec;
4510   rtx addr;
4511 
4512   if (TARGET_32BIT)
4513     {
4514       if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli_32bit)
4515 	return false;
4516     }
4517   else
4518     {
4519       if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli)
4520 	return false;
4521     }
4522 
4523   unspec = SET_SRC (PATTERN (insn));
4524   addr = XVECEXP (unspec, 0, 1);
4525 
4526   return (GET_CODE (addr) == CONST
4527 	  && GET_CODE (XEXP (addr, 0)) == UNSPEC
4528 	  && XINT (XEXP (addr, 0), 1) == UNSPEC_HW0_PCREL);
4529 }
4530 
4531 
4532 /* Do the second replacement step in tilegx_fixup_pcrel_references.  */
4533 static void
4534 replace_mov_pcrel_step2 (rtx insn)
4535 {
4536   rtx pattern = PATTERN (insn);
4537   rtx unspec;
4538   rtx addr;
4539   rtx opnds[3];
4540   rtx new_insns;
4541   rtx got_rtx = tilegx_got_rtx ();
4542 
4543   gcc_assert (GET_CODE (pattern) == SET);
4544   opnds[0] = SET_DEST (pattern);
4545 
4546   unspec = SET_SRC (pattern);
4547   gcc_assert (GET_CODE (unspec) == UNSPEC);
4548   gcc_assert (XINT (unspec, 1) == UNSPEC_INSN_ADDR_SHL16INSLI);
4549 
4550   opnds[1] = XVECEXP (unspec, 0, 0);
4551 
4552   addr = XVECEXP (unspec, 0, 1);
4553   gcc_assert (GET_CODE (addr) == CONST);
4554 
4555   unspec = XEXP (addr, 0);
4556   gcc_assert (GET_CODE (unspec) == UNSPEC);
4557   gcc_assert (XINT (unspec, 1) == UNSPEC_HW0_PCREL);
4558   opnds[2] = XVECEXP (unspec, 0, 0);
4559 
4560   /* We only need to replace SYMBOL_REFs, not LABEL_REFs.  */
4561   if (GET_CODE (opnds[2]) != SYMBOL_REF)
4562     return;
4563 
4564   start_sequence ();
4565 
4566   if (flag_pic == 1)
4567     {
4568       if (TARGET_32BIT)
4569 	emit_insn (gen_add_got16_32bit (opnds[0], got_rtx, opnds[2]));
4570       else
4571 	emit_insn (gen_add_got16 (opnds[0], got_rtx, opnds[2]));
4572     }
4573   else
4574     {
4575       if (TARGET_32BIT)
4576 	emit_insn (gen_mov_got32_step2_32bit
4577 		   (opnds[0], opnds[1], opnds[2]));
4578       else
4579 	emit_insn (gen_mov_got32_step2 (opnds[0], opnds[1], opnds[2]));
4580     }
4581 
4582   new_insns = get_insns ();
4583   end_sequence ();
4584 
4585   replace_insns (insn, new_insns);
4586 }
4587 
4588 
4589 /* Do the third replacement step in tilegx_fixup_pcrel_references.  */
4590 static void
4591 replace_mov_pcrel_step3 (rtx insn)
4592 {
4593   rtx pattern = PATTERN (insn);
4594   rtx unspec;
4595   rtx opnds[4];
4596   rtx new_insns;
4597   rtx got_rtx = tilegx_got_rtx ();
4598   rtx text_label_rtx = tilegx_text_label_rtx ();
4599 
4600   gcc_assert (GET_CODE (pattern) == SET);
4601   opnds[0] = SET_DEST (pattern);
4602 
4603   unspec = SET_SRC (pattern);
4604   gcc_assert (GET_CODE (unspec) == UNSPEC);
4605   gcc_assert (XINT (unspec, 1) == UNSPEC_MOV_PCREL_STEP3);
4606 
4607   opnds[1] = got_rtx;
4608 
4609   if (XVECEXP (unspec, 0, 0) == text_label_rtx)
4610     opnds[2] = XVECEXP (unspec, 0, 1);
4611   else
4612     {
4613       gcc_assert (XVECEXP (unspec, 0, 1) == text_label_rtx);
4614       opnds[2] = XVECEXP (unspec, 0, 0);
4615     }
4616 
4617   opnds[3] = XVECEXP (unspec, 0, 2);
4618 
4619   /* We only need to replace SYMBOL_REFs, not LABEL_REFs.  */
4620   if (GET_CODE (opnds[3]) != SYMBOL_REF)
4621     return;
4622 
4623   start_sequence ();
4624 
4625   if (flag_pic == 1)
4626     {
4627       emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[2]));
4628     }
4629   else
4630     {
4631       emit_move_insn (opnds[0], gen_rtx_PLUS (Pmode, opnds[1], opnds[2]));
4632       emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[0]));
4633     }
4634 
4635   new_insns = get_insns ();
4636   end_sequence ();
4637 
4638   replace_insns (insn, new_insns);
4639 }
4640 
4641 
4642 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4643    going through the GOT when the symbol is local to the compilation
4644    unit.  But such a symbol requires that the common text_label that
4645    we generate at the beginning of the function be in the same section
4646    as the reference to the SYMBOL_REF.  This may not be true if we
4647    generate hot/cold sections.  This function looks for such cases and
4648    replaces such references with the longer sequence going through the
4649    GOT.
4650 
4651    We expect following instruction sequence:
4652    moveli      tmp1, hw1_last(x-.L_PICLNK)          [1]
4653    shl16insli  tmp2, tmp1, hw0(x-.L_PICLNK)         [2]
4654    add<x>      tmp3, txt_label_reg, tmp2            [3]
4655 
4656    If we're compiling -fpic, we replace with the following sequence
4657    (the numbers in brackets match the instructions they're replacing
4658    above).
4659 
4660    add<x>li    tmp2, got_reg, hw0_last_got(x)       [2]
4661    ld<4>       tmp3, tmp2                           [3]
4662 
4663    If we're compiling -fPIC, we replace the first instruction with:
4664 
4665    moveli      tmp1, hw1_last_got(x)                [1]
4666    shl16insli  tmp2, tmp1, hw0_got(x)               [2]
4667    add<x>      tmp3, got_reg, tmp2                  [3]
4668    ld<4>       tmp3, tmp3                           [3]
4669 
4670    Note that we're careful to disturb the instruction sequence as
4671    little as possible, since it's very late in the compilation
4672    process.  */
4673 static void
4674 tilegx_fixup_pcrel_references (void)
4675 {
4676   rtx insn, next_insn;
4677   bool same_section_as_entry = true;
4678 
4679   for (insn = get_insns (); insn; insn = next_insn)
4680     {
4681       next_insn = NEXT_INSN (insn);
4682 
4683       if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
4684 	{
4685 	  same_section_as_entry = !same_section_as_entry;
4686 	  continue;
4687 	}
4688 
4689       if (same_section_as_entry)
4690 	continue;
4691 
4692       if (!(INSN_P (insn)
4693 	    && GET_CODE (PATTERN (insn)) != USE
4694 	    && GET_CODE (PATTERN (insn)) != CLOBBER))
4695 	continue;
4696 
4697       if (TARGET_32BIT)
4698 	{
4699 	  if (match_pcrel_step1 (insn))
4700 	    replace_mov_pcrel_step1 (insn);
4701 	  else if (match_pcrel_step2 (insn))
4702 	    replace_mov_pcrel_step2 (insn);
4703 	  else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3_32bit)
4704 	    replace_mov_pcrel_step3 (insn);
4705 	}
4706       else
4707 	{
4708 	  if (match_pcrel_step1 (insn))
4709 	    replace_mov_pcrel_step1 (insn);
4710 	  else if (match_pcrel_step2 (insn))
4711 	    replace_mov_pcrel_step2 (insn);
4712 	  else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3)
4713 	    replace_mov_pcrel_step3 (insn);
4714 	}
4715     }
4716 }
4717 
4718 
4719 /* Ensure that no var tracking notes are emitted in the middle of a
4720    three-instruction bundle.  */
4721 static void
4722 reorder_var_tracking_notes (void)
4723 {
4724   basic_block bb;
4725   FOR_EACH_BB (bb)
4726   {
4727     rtx insn, next;
4728     rtx queue = NULL_RTX;
4729     bool in_bundle = false;
4730 
4731     for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4732       {
4733 	next = NEXT_INSN (insn);
4734 
4735 	if (INSN_P (insn))
4736 	  {
4737 	    /* Emit queued up notes at the last instruction of a
4738 	       bundle.  */
4739 	    if (GET_MODE (insn) == QImode)
4740 	      {
4741 		while (queue)
4742 		  {
4743 		    rtx next_queue = PREV_INSN (queue);
4744 		    PREV_INSN (NEXT_INSN (insn)) = queue;
4745 		    NEXT_INSN (queue) = NEXT_INSN (insn);
4746 		    NEXT_INSN (insn) = queue;
4747 		    PREV_INSN (queue) = insn;
4748 		    queue = next_queue;
4749 		  }
4750 		in_bundle = false;
4751 	      }
4752 	    else if (GET_MODE (insn) == SImode)
4753 	      in_bundle = true;
4754 	  }
4755 	else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4756 	  {
4757 	    if (in_bundle)
4758 	      {
4759 		rtx prev = PREV_INSN (insn);
4760 		PREV_INSN (next) = prev;
4761 		NEXT_INSN (prev) = next;
4762 
4763 		PREV_INSN (insn) = queue;
4764 		queue = insn;
4765 	      }
4766 	  }
4767       }
4768   }
4769 }
4770 
4771 
4772 /* Perform machine dependent operations on the rtl chain INSNS.  */
4773 static void
4774 tilegx_reorg (void)
4775 {
4776   /* We are freeing block_for_insn in the toplev to keep compatibility
4777      with old MDEP_REORGS that are not CFG based.  Recompute it
4778      now.  */
4779   compute_bb_for_insn ();
4780 
4781   if (flag_reorder_blocks_and_partition)
4782     {
4783       tilegx_fixup_pcrel_references ();
4784     }
4785 
4786   if (flag_schedule_insns_after_reload)
4787     {
4788       split_all_insns ();
4789 
4790       timevar_push (TV_SCHED2);
4791       schedule_insns ();
4792       timevar_pop (TV_SCHED2);
4793 
4794       /* Examine the schedule to group into bundles.  */
4795       tilegx_gen_bundles ();
4796     }
4797 
4798   df_analyze ();
4799 
4800   if (flag_var_tracking)
4801     {
4802       timevar_push (TV_VAR_TRACKING);
4803       variable_tracking_main ();
4804       reorder_var_tracking_notes ();
4805       timevar_pop (TV_VAR_TRACKING);
4806     }
4807 
4808   df_finish_pass (false);
4809 }
4810 
4811 
4812 
4813 /* Assembly  */
4814 
4815 /* Select a format to encode pointers in exception handling data.
4816    CODE is 0 for data, 1 for code labels, 2 for function pointers.
4817    GLOBAL is true if the symbol may be affected by dynamic
4818    relocations.  */
4819 int
4820 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
4821 {
4822   int type = TARGET_32BIT ? DW_EH_PE_sdata4 : DW_EH_PE_sdata8;
4823   return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type;
4824 }
4825 
4826 
4827 /* Implement TARGET_ASM_OUTPUT_MI_THUNK.  */
4828 static void
4829 tilegx_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
4830 			HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
4831 			tree function)
4832 {
4833   rtx this_rtx, insn, funexp, addend;
4834 
4835   /* Pretend to be a post-reload pass while generating rtl.  */
4836   reload_completed = 1;
4837 
4838   /* Mark the end of the (empty) prologue.  */
4839   emit_note (NOTE_INSN_PROLOGUE_END);
4840 
4841   /* Find the "this" pointer.  If the function returns a structure,
4842      the structure return pointer is in $1.  */
4843   if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
4844     this_rtx = gen_rtx_REG (Pmode, 1);
4845   else
4846     this_rtx = gen_rtx_REG (Pmode, 0);
4847 
4848   /* Add DELTA to THIS_RTX.  */
4849   if (!(delta >= -32868 && delta <= 32767))
4850     {
4851       addend = gen_rtx_REG (Pmode, 29);
4852       emit_move_insn (addend, GEN_INT (delta));
4853     }
4854   else
4855     addend = GEN_INT (delta);
4856 
4857   if (TARGET_32BIT)
4858     emit_insn (gen_addsi3 (this_rtx, this_rtx, addend));
4859   else
4860     emit_insn (gen_adddi3 (this_rtx, this_rtx, addend));
4861 
4862   /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX.  */
4863   if (vcall_offset)
4864     {
4865       rtx tmp;
4866 
4867       tmp = gen_rtx_REG (Pmode, 29);
4868       emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx));
4869 
4870       if (!(vcall_offset >= -32868 && vcall_offset <= 32767))
4871 	{
4872 	  addend = gen_rtx_REG (Pmode, 28);
4873 	  emit_move_insn (addend, GEN_INT (vcall_offset));
4874 	}
4875       else
4876 	addend = GEN_INT (vcall_offset);
4877 
4878       if (TARGET_32BIT)
4879 	emit_insn (gen_addsi3 (tmp, tmp, addend));
4880       else
4881 	emit_insn (gen_adddi3 (tmp, tmp, addend));
4882 
4883       emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
4884 
4885       if (TARGET_32BIT)
4886 	emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp));
4887       else
4888 	emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp));
4889     }
4890 
4891   /* Generate a tail call to the target function.  */
4892   if (!TREE_USED (function))
4893     {
4894       assemble_external (function);
4895       TREE_USED (function) = 1;
4896     }
4897   funexp = XEXP (DECL_RTL (function), 0);
4898   funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
4899   insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
4900   SIBLING_CALL_P (insn) = 1;
4901 
4902   /* Run just enough of rest_of_compilation to get the insns emitted.
4903      There's not really enough bulk here to make other passes such as
4904      instruction scheduling worth while.  Note that use_thunk calls
4905      assemble_start_function and assemble_end_function.
4906 
4907      We don't currently bundle, but the instruciton sequence is all
4908      serial except for the tail call, so we're only wasting one cycle.
4909    */
4910   insn = get_insns ();
4911   shorten_branches (insn);
4912   final_start_function (insn, file, 1);
4913   final (insn, file, 1);
4914   final_end_function ();
4915 
4916   /* Stop pretending to be a post-reload pass.  */
4917   reload_completed = 0;
4918 }
4919 
4920 
4921 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE.  */
4922 static void
4923 tilegx_asm_trampoline_template (FILE *file)
4924 {
4925   int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4926   if (TARGET_32BIT)
4927     {
4928       fprintf (file, "\tlnk      r10\n");
4929       fprintf (file, "\taddxi    r10, r10, 32\n");
4930       fprintf (file, "\tld4s_add r11, r10, %d\n", ptr_mode_size);
4931       fprintf (file, "\tld4s     r10, r10\n");
4932       fprintf (file, "\tjr       r11\n");
4933       fprintf (file, "\t.word 0 # <function address>\n");
4934       fprintf (file, "\t.word 0 # <static chain value>\n");
4935     }
4936   else
4937     {
4938       fprintf (file, "\tlnk      r10\n");
4939       fprintf (file, "\taddi     r10, r10, 32\n");
4940       fprintf (file, "\tld_add   r11, r10, %d\n", ptr_mode_size);
4941       fprintf (file, "\tld       r10, r10\n");
4942       fprintf (file, "\tjr       r11\n");
4943       fprintf (file, "\t.quad 0 # <function address>\n");
4944       fprintf (file, "\t.quad 0 # <static chain value>\n");
4945     }
4946 }
4947 
4948 
4949 /* Implement TARGET_TRAMPOLINE_INIT.  */
4950 static void
4951 tilegx_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
4952 {
4953   rtx fnaddr, chaddr;
4954   rtx mem;
4955   rtx begin_addr, end_addr;
4956   int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4957 
4958   fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
4959   chaddr = copy_to_reg (static_chain);
4960 
4961   emit_block_move (m_tramp, assemble_trampoline_template (),
4962 		   GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
4963 
4964   mem = adjust_address (m_tramp, ptr_mode,
4965 			TRAMPOLINE_SIZE - 2 * ptr_mode_size);
4966   emit_move_insn (mem, fnaddr);
4967   mem = adjust_address (m_tramp, ptr_mode,
4968 			TRAMPOLINE_SIZE - ptr_mode_size);
4969   emit_move_insn (mem, chaddr);
4970 
4971   /* Get pointers to the beginning and end of the code block.  */
4972   begin_addr = force_reg (Pmode, XEXP (m_tramp, 0));
4973   end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0),
4974 					      TRAMPOLINE_SIZE));
4975 
4976   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
4977 		     LCT_NORMAL, VOIDmode, 2, begin_addr, Pmode,
4978 		     end_addr, Pmode);
4979 }
4980 
4981 
4982 /* Implement TARGET_PRINT_OPERAND.  */
4983 static void
4984 tilegx_print_operand (FILE *file, rtx x, int code)
4985 {
4986   switch (code)
4987     {
4988     case 'c':
4989       /* Print the compare operator opcode for conditional moves.  */
4990       switch (GET_CODE (x))
4991 	{
4992 	case EQ:
4993 	  fputs ("z", file);
4994 	  break;
4995 	case NE:
4996 	  fputs ("nz", file);
4997 	  break;
4998 	default:
4999 	  output_operand_lossage ("invalid %%c operand");
5000 	}
5001       return;
5002 
5003     case 'C':
5004       /* Print the compare operator opcode for conditional moves.  */
5005       switch (GET_CODE (x))
5006 	{
5007 	case EQ:
5008 	  fputs ("nz", file);
5009 	  break;
5010 	case NE:
5011 	  fputs ("z", file);
5012 	  break;
5013 	default:
5014 	  output_operand_lossage ("invalid %%C operand");
5015 	}
5016       return;
5017 
5018     case 'd':
5019       {
5020 	/* Print the compare operator opcode for conditional moves.  */
5021 	switch (GET_CODE (x))
5022 	  {
5023 	  case EQ:
5024 	    fputs ("eq", file);
5025 	    break;
5026 	  case NE:
5027 	    fputs ("ne", file);
5028 	    break;
5029 	  default:
5030 	    output_operand_lossage ("invalid %%d operand");
5031 	  }
5032 	return;
5033       }
5034 
5035     case 'D':
5036       {
5037 	/* Print the compare operator opcode for conditional moves.  */
5038 	switch (GET_CODE (x))
5039 	  {
5040 	  case EQ:
5041 	    fputs ("ne", file);
5042 	    break;
5043 	  case NE:
5044 	    fputs ("eq", file);
5045 	    break;
5046 	  default:
5047 	    output_operand_lossage ("invalid %%D operand");
5048 	  }
5049 	return;
5050       }
5051 
5052     case 'H':
5053       {
5054       if (GET_CODE (x) == CONST
5055 	  && GET_CODE (XEXP (x, 0)) == UNSPEC)
5056 	{
5057 	  rtx addr = XVECEXP (XEXP (x, 0), 0, 0);
5058 	  int unspec = XINT (XEXP (x, 0), 1);
5059 	  const char *opstr = NULL;
5060 	  switch (unspec)
5061 	    {
5062 	    case UNSPEC_HW0:
5063 	    case UNSPEC_HW0_PCREL:
5064 	      opstr = "hw0";
5065 	      break;
5066 	    case UNSPEC_HW1:
5067 	    case UNSPEC_HW1_PCREL:
5068 	      opstr = "hw1";
5069 	      break;
5070 	    case UNSPEC_HW2:
5071 	      opstr = "hw2";
5072 	      break;
5073 	    case UNSPEC_HW3:
5074 	      opstr = "hw3";
5075 	      break;
5076 	    case UNSPEC_HW0_LAST:
5077 	      opstr = "hw0_last";
5078 	      break;
5079 	    case UNSPEC_HW1_LAST:
5080 	    case UNSPEC_HW1_LAST_PCREL:
5081 	      opstr = "hw1_last";
5082 	      break;
5083 	    case UNSPEC_HW2_LAST:
5084 	    case UNSPEC_HW2_LAST_PCREL:
5085 	      opstr = "hw2_last";
5086 	      break;
5087 	    case UNSPEC_HW0_GOT:
5088 	      opstr = "hw0_got";
5089 	      break;
5090 	    case UNSPEC_HW0_LAST_GOT:
5091 	      opstr = "hw0_last_got";
5092 	      break;
5093 	    case UNSPEC_HW1_LAST_GOT:
5094 	      opstr = "hw1_last_got";
5095 	      break;
5096 	    case UNSPEC_HW0_TLS_GD:
5097 	      opstr = "hw0_tls_gd";
5098 	      break;
5099 	    case UNSPEC_HW1_LAST_TLS_GD:
5100 	      opstr = "hw1_last_tls_gd";
5101 	      break;
5102 	    case UNSPEC_HW0_TLS_IE:
5103 	      opstr = "hw0_tls_ie";
5104 	      break;
5105 	    case UNSPEC_HW1_LAST_TLS_IE:
5106 	      opstr = "hw1_last_tls_ie";
5107 	      break;
5108 	    case UNSPEC_HW0_TLS_LE:
5109 	      opstr = "hw0_tls_le";
5110 	      break;
5111 	    case UNSPEC_HW1_LAST_TLS_LE:
5112 	      opstr = "hw1_last_tls_le";
5113 	      break;
5114 	    case UNSPEC_HW0_PLT_PCREL:
5115 	      opstr = "hw0_plt";
5116 	      break;
5117 	    case UNSPEC_HW1_PLT_PCREL:
5118 	      opstr = "hw1_plt";
5119 	      break;
5120 	    case UNSPEC_HW1_LAST_PLT_PCREL:
5121 	      opstr = "hw1_last_plt";
5122 	      break;
5123 	    case UNSPEC_HW2_LAST_PLT_PCREL:
5124 	      opstr = "hw2_last_plt";
5125 	      break;
5126 	    default:
5127 	      output_operand_lossage ("invalid %%H specifier");
5128 	    }
5129 
5130 	  fputs (opstr, file);
5131 	  fputc ('(', file);
5132 	  output_addr_const (file, addr);
5133 
5134 	  if (unspec == UNSPEC_HW0_PCREL
5135 	      || unspec == UNSPEC_HW1_PCREL
5136 	      || unspec == UNSPEC_HW1_LAST_PCREL
5137 	      || unspec == UNSPEC_HW2_LAST_PCREL
5138 	      || unspec == UNSPEC_HW0_PLT_PCREL
5139 	      || unspec == UNSPEC_HW1_PLT_PCREL
5140 	      || unspec == UNSPEC_HW1_LAST_PLT_PCREL
5141 	      || unspec == UNSPEC_HW2_LAST_PLT_PCREL)
5142 	    {
5143 	      rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
5144 	      fputs (" - " , file);
5145 	      output_addr_const (file, addr2);
5146 	    }
5147 
5148 	  fputc (')', file);
5149 	  return;
5150 	}
5151       else if (symbolic_operand (x, VOIDmode))
5152 	{
5153 	  output_addr_const (file, x);
5154 	  return;
5155 	}
5156       }
5157       /* FALLTHRU */
5158 
5159     case 'h':
5160       {
5161 	/* Print the low 16 bits of a constant.  */
5162 	HOST_WIDE_INT i;
5163 	if (CONST_INT_P (x))
5164 	  i = INTVAL (x);
5165 	else if (GET_CODE (x) == CONST_DOUBLE)
5166 	  i = CONST_DOUBLE_LOW (x);
5167 	else
5168 	  {
5169 	    output_operand_lossage ("invalid %%h operand");
5170 	    return;
5171 	  }
5172 	i = trunc_int_for_mode (i, HImode);
5173 	fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
5174 	return;
5175       }
5176 
5177     case 'I':
5178       /* Print an auto-inc memory operand.  */
5179       if (!MEM_P (x))
5180 	{
5181 	  output_operand_lossage ("invalid %%I operand");
5182 	  return;
5183 	}
5184 
5185       output_memory_reference_mode = GET_MODE (x);
5186       output_memory_autoinc_first = true;
5187       output_address (XEXP (x, 0));
5188       output_memory_reference_mode = VOIDmode;
5189       return;
5190 
5191     case 'i':
5192       /* Print an auto-inc memory operand.  */
5193       if (!MEM_P (x))
5194 	{
5195 	  output_operand_lossage ("invalid %%i operand");
5196 	  return;
5197 	}
5198 
5199       output_memory_reference_mode = GET_MODE (x);
5200       output_memory_autoinc_first = false;
5201       output_address (XEXP (x, 0));
5202       output_memory_reference_mode = VOIDmode;
5203       return;
5204 
5205     case 'j':
5206       {
5207 	/* Print the low 8 bits of a constant.  */
5208 	HOST_WIDE_INT i;
5209 	if (CONST_INT_P (x))
5210 	  i = INTVAL (x);
5211 	else if (GET_CODE (x) == CONST_DOUBLE)
5212 	  i = CONST_DOUBLE_LOW (x);
5213 	else if (GET_CODE (x) == CONST_VECTOR
5214 		 && CONST_INT_P (CONST_VECTOR_ELT (x, 0)))
5215 	  i = INTVAL (CONST_VECTOR_ELT (x, 0));
5216 	else
5217 	  {
5218 	    output_operand_lossage ("invalid %%j operand");
5219 	    return;
5220 	  }
5221 	i = trunc_int_for_mode (i, QImode);
5222 	fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
5223 	return;
5224       }
5225 
5226     case 'P':
5227       {
5228 	/* Print a constant plus one.  */
5229 	if (!CONST_INT_P (x))
5230 	  {
5231 	    output_operand_lossage ("invalid %%P operand");
5232 	    return;
5233 	  }
5234 	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + 1);
5235 	return;
5236       }
5237 
5238     case 'm':
5239     case 'M':
5240       {
5241 	/* Print a bfextu-style bit range.  */
5242 	int first_bit, last_bit;
5243 	HOST_WIDE_INT flip = (code == 'm') ? ~0 : 0;
5244 
5245 	if (!CONST_INT_P (x)
5246 	    || !tilegx_bitfield_operand_p (INTVAL (x) ^ flip,
5247 					   &first_bit, &last_bit))
5248 	  {
5249 	    output_operand_lossage ("invalid %%%c operand", code);
5250 	    return;
5251 	  }
5252 
5253 	fprintf (file, "%d, %d", first_bit, last_bit);
5254 	return;
5255       }
5256 
5257     case 'N':
5258       {
5259 	const char *reg = NULL;
5260 
5261 	/* Print a network register.  */
5262 	if (!CONST_INT_P (x))
5263 	  {
5264 	    output_operand_lossage ("invalid %%N operand");
5265 	    return;
5266 	  }
5267 
5268 	switch (INTVAL (x))
5269 	  {
5270 	  case TILEGX_NETREG_IDN0: reg = "idn0"; break;
5271 	  case TILEGX_NETREG_IDN1: reg = "idn1"; break;
5272 	  case TILEGX_NETREG_UDN0: reg = "udn0"; break;
5273 	  case TILEGX_NETREG_UDN1: reg = "udn1"; break;
5274 	  case TILEGX_NETREG_UDN2: reg = "udn2"; break;
5275 	  case TILEGX_NETREG_UDN3: reg = "udn3"; break;
5276 	  default:
5277 	    gcc_unreachable ();
5278 	  }
5279 
5280 	fprintf (file, reg);
5281 	return;
5282       }
5283 
5284     case 'p':
5285       if (GET_CODE (x) == SYMBOL_REF)
5286 	{
5287 	  if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
5288 	    fprintf (file, "plt(");
5289 	  output_addr_const (file, x);
5290 	  if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
5291 	    fprintf (file, ")");
5292 	}
5293       else
5294 	output_addr_const (file, x);
5295       return;
5296 
5297     case 'r':
5298       /* In this case we need a register.  Use 'zero' if the operand
5299 	 is const0_rtx.  */
5300       if (x == const0_rtx
5301 	  || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
5302 	{
5303 	  fputs ("zero", file);
5304 	  return;
5305 	}
5306       else if (!REG_P (x))
5307 	{
5308 	  output_operand_lossage ("invalid operand for 'r' specifier");
5309 	  return;
5310 	}
5311       /* FALLTHRU */
5312 
5313     case 0:
5314       if (REG_P (x))
5315 	{
5316 	  fprintf (file, "%s", reg_names[REGNO (x)]);
5317 	  return;
5318 	}
5319       else if (MEM_P (x))
5320 	{
5321 	  output_memory_reference_mode = VOIDmode;
5322 	  output_address (XEXP (x, 0));
5323 	  return;
5324 	}
5325       else
5326 	{
5327 	  output_addr_const (file, x);
5328 	  return;
5329 	}
5330     }
5331 
5332   debug_rtx (x);
5333   output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5334 			  code, code);
5335 }
5336 
5337 
5338 /* Implement TARGET_PRINT_OPERAND_ADDRESS.  */
5339 static void
5340 tilegx_print_operand_address (FILE *file, rtx addr)
5341 {
5342   if (GET_CODE (addr) == POST_DEC
5343       || GET_CODE (addr) == POST_INC)
5344     {
5345       int offset = GET_MODE_SIZE (output_memory_reference_mode);
5346 
5347       gcc_assert (output_memory_reference_mode != VOIDmode);
5348 
5349       if (output_memory_autoinc_first)
5350 	fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
5351       else
5352 	fprintf (file, "%d",
5353 		 GET_CODE (addr) == POST_DEC ? -offset : offset);
5354     }
5355   else if (GET_CODE (addr) == POST_MODIFY)
5356     {
5357       gcc_assert (output_memory_reference_mode != VOIDmode);
5358 
5359       gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
5360 
5361       if (output_memory_autoinc_first)
5362 	fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
5363       else
5364 	fprintf (file, HOST_WIDE_INT_PRINT_DEC,
5365 		 INTVAL (XEXP (XEXP (addr, 1), 1)));
5366     }
5367   else
5368     tilegx_print_operand (file, addr, 'r');
5369 }
5370 
5371 
5372 /* Machine mode of current insn, for determining curly brace
5373    placement.  */
5374 static enum machine_mode insn_mode;
5375 
5376 
5377 /* Implement FINAL_PRESCAN_INSN.  This is used to emit bundles.  */
5378 void
5379 tilegx_final_prescan_insn (rtx insn)
5380 {
5381   /* Record this for tilegx_asm_output_opcode to examine.  */
5382   insn_mode = GET_MODE (insn);
5383 }
5384 
5385 
5386 /* While emitting asm, are we currently inside '{' for a bundle?  */
5387 static bool tilegx_in_bundle = false;
5388 
5389 /* Implement ASM_OUTPUT_OPCODE.  Prepend/append curly braces as
5390    appropriate given the bundling information recorded by
5391    tilegx_gen_bundles.  */
5392 const char *
5393 tilegx_asm_output_opcode (FILE *stream, const char *code)
5394 {
5395   bool pseudo = !strcmp (code, "pseudo");
5396 
5397   if (!tilegx_in_bundle && insn_mode == SImode)
5398     {
5399       /* Start a new bundle.  */
5400       fprintf (stream, "{\n\t");
5401       tilegx_in_bundle = true;
5402     }
5403 
5404   if (tilegx_in_bundle && insn_mode == QImode)
5405     {
5406       /* Close an existing bundle.  */
5407       static char buf[100];
5408 
5409       gcc_assert (strlen (code) + 3 + 1 < sizeof (buf));
5410 
5411       strcpy (buf, pseudo ? "" : code);
5412       strcat (buf, "\n\t}");
5413       tilegx_in_bundle = false;
5414 
5415       return buf;
5416     }
5417   else
5418     {
5419       return pseudo ? "" : code;
5420     }
5421 }
5422 
5423 
5424 /* Output assembler code to FILE to increment profiler label # LABELNO
5425    for profiling a function entry.  */
5426 void
5427 tilegx_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
5428 {
5429   if (tilegx_in_bundle)
5430     {
5431       fprintf (file, "\t}\n");
5432     }
5433 
5434   if (flag_pic)
5435     {
5436       fprintf (file,
5437 	       "\t{\n"
5438 	       "\tmove\tr10, lr\n"
5439 	       "\tjal\tplt(%s)\n"
5440 	       "\t}\n", MCOUNT_NAME);
5441     }
5442   else
5443     {
5444       fprintf (file,
5445 	       "\t{\n"
5446 	       "\tmove\tr10, lr\n"
5447 	       "\tjal\t%s\n"
5448 	       "\t}\n", MCOUNT_NAME);
5449     }
5450 
5451   tilegx_in_bundle = false;
5452 }
5453 
5454 
5455 /* Implement TARGET_ASM_FILE_END.  */
5456 static void
5457 tilegx_file_end (void)
5458 {
5459   if (NEED_INDICATE_EXEC_STACK)
5460     file_end_indicate_exec_stack ();
5461 }
5462 
5463 
5464 
5465 #undef  TARGET_HAVE_TLS
5466 #define TARGET_HAVE_TLS HAVE_AS_TLS
5467 
5468 #undef  TARGET_OPTION_OVERRIDE
5469 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5470 
5471 #undef  TARGET_SCALAR_MODE_SUPPORTED_P
5472 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5473 
5474 #undef  TARGET_VECTOR_MODE_SUPPORTED_P
5475 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5476 
5477 #undef  TARGET_CANNOT_FORCE_CONST_MEM
5478 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5479 
5480 #undef  TARGET_FUNCTION_OK_FOR_SIBCALL
5481 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5482 
5483 #undef  TARGET_PASS_BY_REFERENCE
5484 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5485 
5486 #undef  TARGET_RETURN_IN_MEMORY
5487 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5488 
5489 #undef  TARGET_MODE_REP_EXTENDED
5490 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5491 
5492 #undef  TARGET_FUNCTION_ARG_BOUNDARY
5493 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5494 
5495 #undef  TARGET_FUNCTION_ARG
5496 #define TARGET_FUNCTION_ARG tilegx_function_arg
5497 
5498 #undef  TARGET_FUNCTION_ARG_ADVANCE
5499 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5500 
5501 #undef  TARGET_FUNCTION_VALUE
5502 #define TARGET_FUNCTION_VALUE tilegx_function_value
5503 
5504 #undef  TARGET_LIBCALL_VALUE
5505 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5506 
5507 #undef  TARGET_FUNCTION_VALUE_REGNO_P
5508 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5509 
5510 #undef  TARGET_PROMOTE_FUNCTION_MODE
5511 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5512 
5513 #undef  TARGET_PROMOTE_PROTOTYPES
5514 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5515 
5516 #undef  TARGET_BUILD_BUILTIN_VA_LIST
5517 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5518 
5519 #undef  TARGET_EXPAND_BUILTIN_VA_START
5520 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5521 
5522 #undef  TARGET_SETUP_INCOMING_VARARGS
5523 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5524 
5525 #undef  TARGET_GIMPLIFY_VA_ARG_EXPR
5526 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5527 
5528 #undef  TARGET_RTX_COSTS
5529 #define TARGET_RTX_COSTS tilegx_rtx_costs
5530 
5531 #undef  TARGET_EXPAND_TO_RTL_HOOK
5532 #define TARGET_EXPAND_TO_RTL_HOOK tilegx_expand_to_rtl_hook
5533 
5534 #undef  TARGET_SHIFT_TRUNCATION_MASK
5535 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5536 
5537 #undef  TARGET_INIT_LIBFUNCS
5538 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5539 
5540 /* Limit to what we can reach in one addli.  */
5541 #undef  TARGET_MIN_ANCHOR_OFFSET
5542 #define TARGET_MIN_ANCHOR_OFFSET -32768
5543 #undef  TARGET_MAX_ANCHOR_OFFSET
5544 #define TARGET_MAX_ANCHOR_OFFSET 32767
5545 
5546 #undef  TARGET_LEGITIMATE_CONSTANT_P
5547 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5548 
5549 #undef  TARGET_LEGITIMATE_ADDRESS_P
5550 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5551 
5552 #undef  TARGET_LEGITIMIZE_ADDRESS
5553 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5554 
5555 #undef  TARGET_DELEGITIMIZE_ADDRESS
5556 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5557 
5558 #undef  TARGET_INIT_BUILTINS
5559 #define TARGET_INIT_BUILTINS  tilegx_init_builtins
5560 
5561 #undef  TARGET_BUILTIN_DECL
5562 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5563 
5564 #undef  TARGET_EXPAND_BUILTIN
5565 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5566 
5567 #undef  TARGET_CONDITIONAL_REGISTER_USAGE
5568 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5569 
5570 #undef  TARGET_FRAME_POINTER_REQUIRED
5571 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5572 
5573 #undef  TARGET_DELAY_SCHED2
5574 #define TARGET_DELAY_SCHED2 true
5575 
5576 #undef  TARGET_DELAY_VARTRACK
5577 #define TARGET_DELAY_VARTRACK true
5578 
5579 #undef  TARGET_SCHED_ISSUE_RATE
5580 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5581 
5582 #undef  TARGET_SCHED_ADJUST_COST
5583 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5584 
5585 #undef  TARGET_MACHINE_DEPENDENT_REORG
5586 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5587 
5588 #undef  TARGET_ASM_CAN_OUTPUT_MI_THUNK
5589 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5590   hook_bool_const_tree_hwi_hwi_const_tree_true
5591 
5592 #undef  TARGET_ASM_OUTPUT_MI_THUNK
5593 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5594 
5595 #undef  TARGET_ASM_TRAMPOLINE_TEMPLATE
5596 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5597 
5598 #undef  TARGET_TRAMPOLINE_INIT
5599 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5600 
5601 #undef  TARGET_PRINT_OPERAND
5602 #define TARGET_PRINT_OPERAND tilegx_print_operand
5603 
5604 #undef  TARGET_PRINT_OPERAND_ADDRESS
5605 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5606 
5607 #undef  TARGET_ASM_FILE_END
5608 #define TARGET_ASM_FILE_END tilegx_file_end
5609 
5610 #undef  TARGET_ASM_ALIGNED_DI_OP
5611 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5612 
5613 
5614 struct gcc_target targetm = TARGET_INITIALIZER;
5615 
5616 #include "gt-tilegx.h"
5617