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