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