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