1 /* Subroutines used for code generation on the Tilera TILE-Gx.
2 Copyright (C) 2011, 2012
3 Free Software Foundation, Inc.
4 Contributed by Walter Lee (walt@tilera.com)
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
28 #include "insn-config.h"
30 #include "insn-attr.h"
33 #include "langhooks.h"
35 #include "sched-int.h"
37 #include "tm-constrs.h"
39 #include "target-def.h"
40 #include "integrate.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;
66 /* Implement TARGET_OPTION_OVERRIDE. */
68 tilegx_option_override (void)
70 /* When modulo scheduling is enabled, we still rely on regular
71 scheduler for bundling. */
72 if (flag_modulo_sched)
73 flag_resched_modulo_sched = 1;
78 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
80 tilegx_scalar_mode_supported_p (enum machine_mode mode)
101 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
103 tilegx_vector_mode_supported_p (enum machine_mode mode)
105 return mode == V8QImode || mode == V4HImode || mode == V2SImode;
109 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
111 tilegx_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED,
112 rtx x ATTRIBUTE_UNUSED)
118 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
120 tilegx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
126 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
127 passed by reference. */
129 tilegx_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
130 enum machine_mode mode ATTRIBUTE_UNUSED,
131 const_tree type, bool named ATTRIBUTE_UNUSED)
133 return (type && TYPE_SIZE (type)
134 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST);
138 /* Implement TARGET_RETURN_IN_MEMORY. */
140 tilegx_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
142 return !IN_RANGE (int_size_in_bytes (type),
143 0, TILEGX_NUM_RETURN_REGS * UNITS_PER_WORD);
147 /* Implement TARGET_MODE_REP_EXTENDED. */
149 tilegx_mode_rep_extended (enum machine_mode mode, enum machine_mode mode_rep)
151 /* SImode register values are sign-extended to DImode. */
152 if (mode == SImode && mode_rep == DImode)
159 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
161 tilegx_function_arg_boundary (enum machine_mode mode, const_tree type)
163 unsigned int alignment;
165 alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode);
166 if (alignment < PARM_BOUNDARY)
167 alignment = PARM_BOUNDARY;
168 if (alignment > STACK_BOUNDARY)
169 alignment = STACK_BOUNDARY;
174 /* Implement TARGET_FUNCTION_ARG. */
176 tilegx_function_arg (cumulative_args_t cum_v,
177 enum machine_mode mode,
178 const_tree type, bool named ATTRIBUTE_UNUSED)
180 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
181 int byte_size = ((mode == BLKmode)
182 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
184 if (cum >= TILEGX_NUM_ARG_REGS)
187 /* The ABI does not allow parameters to be passed partially in reg
188 and partially in stack. */
189 if ((cum + (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
190 > TILEGX_NUM_ARG_REGS)
193 return gen_rtx_REG (mode, cum);
197 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
199 tilegx_function_arg_advance (cumulative_args_t cum_v,
200 enum machine_mode mode,
201 const_tree type, bool named ATTRIBUTE_UNUSED)
203 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
205 int byte_size = ((mode == BLKmode)
206 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
207 int word_size = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
209 /* If the current argument does not fit in the pretend_args space,
211 if (*cum < TILEGX_NUM_ARG_REGS
212 && *cum + word_size > TILEGX_NUM_ARG_REGS)
213 *cum = TILEGX_NUM_ARG_REGS;
219 /* Implement TARGET_FUNCTION_VALUE. */
221 tilegx_function_value (const_tree valtype, const_tree fn_decl_or_type,
222 bool outgoing ATTRIBUTE_UNUSED)
224 enum machine_mode mode;
227 mode = TYPE_MODE (valtype);
228 unsigned_p = TYPE_UNSIGNED (valtype);
230 mode = promote_function_mode (valtype, mode, &unsigned_p,
233 return gen_rtx_REG (mode, 0);
237 /* Implement TARGET_LIBCALL_VALUE. */
239 tilegx_libcall_value (enum machine_mode mode,
240 const_rtx fun ATTRIBUTE_UNUSED)
242 return gen_rtx_REG (mode, 0);
246 /* Implement FUNCTION_VALUE_REGNO_P. */
248 tilegx_function_value_regno_p (const unsigned int regno)
250 return regno < TILEGX_NUM_RETURN_REGS;
254 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
256 tilegx_build_builtin_va_list (void)
258 tree f_args, f_skip, record, type_decl;
261 record = lang_hooks.types.make_type (RECORD_TYPE);
263 type_decl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
264 get_identifier ("__va_list_tag"), record);
266 f_args = build_decl (BUILTINS_LOCATION, FIELD_DECL,
267 get_identifier ("__args"), ptr_type_node);
268 f_skip = build_decl (BUILTINS_LOCATION, FIELD_DECL,
269 get_identifier ("__skip"), ptr_type_node);
271 DECL_FIELD_CONTEXT (f_args) = record;
273 DECL_FIELD_CONTEXT (f_skip) = record;
275 TREE_CHAIN (record) = type_decl;
276 TYPE_NAME (record) = type_decl;
277 TYPE_FIELDS (record) = f_args;
278 TREE_CHAIN (f_args) = f_skip;
280 /* We know this is being padded and we want it too. It is an
281 internal type so hide the warnings from the user. */
285 layout_type (record);
289 /* The correct type is an array type of one element. */
294 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
296 tilegx_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
301 f_args = TYPE_FIELDS (TREE_TYPE (valist));
302 f_skip = TREE_CHAIN (f_args);
305 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
307 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
309 /* Find the __args area. */
310 t = make_tree (TREE_TYPE (args), virtual_incoming_args_rtx);
311 t = fold_build_pointer_plus_hwi (t,
313 (crtl->args.info - TILEGX_NUM_ARG_REGS));
315 if (crtl->args.pretend_args_size > 0)
316 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
318 t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t);
319 TREE_SIDE_EFFECTS (t) = 1;
320 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
322 /* Find the __skip area. */
323 t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx);
324 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
325 t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t);
326 TREE_SIDE_EFFECTS (t) = 1;
327 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
331 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
333 tilegx_setup_incoming_varargs (cumulative_args_t cum,
334 enum machine_mode mode,
335 tree type, int *pretend_args, int no_rtl)
337 CUMULATIVE_ARGS local_cum = *get_cumulative_args (cum);
340 /* The caller has advanced CUM up to, but not beyond, the last named
341 argument. Advance a local copy of CUM past the last "real" named
342 argument, to find out how many registers are left over. */
343 targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum),
345 first_reg = local_cum;
347 if (local_cum < TILEGX_NUM_ARG_REGS)
349 *pretend_args = UNITS_PER_WORD * (TILEGX_NUM_ARG_REGS - first_reg);
353 alias_set_type set = get_varargs_alias_set ();
355 gen_rtx_MEM (BLKmode, plus_constant (virtual_incoming_args_rtx,
356 -STACK_POINTER_OFFSET -
358 (TILEGX_NUM_ARG_REGS -
360 MEM_NOTRAP_P (tmp) = 1;
361 set_mem_alias_set (tmp, set);
362 move_block_from_reg (first_reg, tmp,
363 TILEGX_NUM_ARG_REGS - first_reg);
371 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
372 the va_list structure VALIST as required to retrieve an argument of
373 type TYPE, and returning that argument.
375 ret = va_arg(VALIST, TYPE);
377 generates code equivalent to:
379 paddedsize = (sizeof(TYPE) + 3) & -4;
380 if ( (VALIST.__args + paddedsize > VALIST.__skip)
381 & (VALIST.__args <= VALIST.__skip))
382 addr = VALIST.__skip + STACK_POINTER_OFFSET;
384 addr = VALIST.__args;
385 VALIST.__args = addr + paddedsize;
389 tilegx_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
390 gimple_seq *post_p ATTRIBUTE_UNUSED)
394 HOST_WIDE_INT size, rsize;
396 bool pass_by_reference_p;
398 f_args = TYPE_FIELDS (va_list_type_node);
399 f_skip = TREE_CHAIN (f_args);
402 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
404 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
406 addr = create_tmp_var (ptr_type_node, "va_arg");
408 /* If an object is dynamically sized, a pointer to it is passed
409 instead of the object itself. */
410 pass_by_reference_p = pass_by_reference (NULL, TYPE_MODE (type), type,
413 if (pass_by_reference_p)
414 type = build_pointer_type (type);
416 size = int_size_in_bytes (type);
417 rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD;
419 /* Assert alignment assumption. */
420 gcc_assert (STACK_BOUNDARY == PARM_BOUNDARY);
422 /* Build conditional expression to calculate addr. The expression
423 will be gimplified later. */
424 tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize);
425 tmp = build2 (TRUTH_AND_EXPR, boolean_type_node,
426 build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)),
427 build2 (LE_EXPR, boolean_type_node, unshare_expr (args),
428 unshare_expr (skip)));
430 tmp = build3 (COND_EXPR, ptr_type_node, tmp,
431 build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip),
432 size_int (STACK_POINTER_OFFSET)),
433 unshare_expr (args));
435 gimplify_assign (addr, tmp, pre_p);
437 /* Update VALIST.__args. */
438 tmp = fold_build_pointer_plus_hwi (addr, rsize);
439 gimplify_assign (unshare_expr (args), tmp, pre_p);
441 addr = fold_convert (build_pointer_type (type), addr);
443 if (pass_by_reference_p)
444 addr = build_va_arg_indirect_ref (addr);
446 return build_va_arg_indirect_ref (addr);
451 /* Implement TARGET_RTX_COSTS. */
453 tilegx_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
459 /* If this is an 8-bit constant, return zero since it can be
460 used nearly anywhere with no cost. If it is a valid operand
461 for an ADD or AND, likewise return 0 if we know it will be
462 used in that context. Otherwise, return 2 since it might be
463 used there later. All other constants take at least two
465 if (satisfies_constraint_I (x))
470 else if (outer_code == PLUS && add_operand (x, VOIDmode))
472 /* Slightly penalize large constants even though we can add
473 them in one instruction, because it forces the use of
474 2-wide bundling mode. */
478 else if (move_operand (x, SImode))
480 /* We can materialize in one move. */
481 *total = COSTS_N_INSNS (1);
486 /* We can materialize in two moves. */
487 *total = COSTS_N_INSNS (2);
496 *total = COSTS_N_INSNS (2);
500 *total = COSTS_N_INSNS (4);
508 /* If outer-code was a sign or zero extension, a cost of
509 COSTS_N_INSNS (1) was already added in, so account for
511 if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND)
512 *total = COSTS_N_INSNS (1);
514 *total = COSTS_N_INSNS (2);
518 /* Convey that shl[123]add are efficient. */
519 if (GET_CODE (XEXP (x, 0)) == MULT
520 && cint_248_operand (XEXP (XEXP (x, 0), 1), VOIDmode))
522 *total = (rtx_cost (XEXP (XEXP (x, 0), 0),
523 (enum rtx_code) outer_code, opno, speed)
524 + rtx_cost (XEXP (x, 1),
525 (enum rtx_code) outer_code, opno, speed)
526 + COSTS_N_INSNS (1));
532 *total = COSTS_N_INSNS (2);
539 /* These are handled by software and are very expensive. */
540 *total = COSTS_N_INSNS (100);
544 case UNSPEC_VOLATILE:
546 int num = XINT (x, 1);
548 if (num <= TILEGX_LAST_LATENCY_1_INSN)
549 *total = COSTS_N_INSNS (1);
550 else if (num <= TILEGX_LAST_LATENCY_2_INSN)
551 *total = COSTS_N_INSNS (2);
552 else if (num > TILEGX_LAST_LATENCY_INSN)
554 if (num == UNSPEC_NON_TEMPORAL)
556 /* These are basically loads. */
557 if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND)
558 *total = COSTS_N_INSNS (1);
560 *total = COSTS_N_INSNS (2);
564 if (outer_code == PLUS)
567 *total = COSTS_N_INSNS (1);
574 case UNSPEC_BLOCKAGE:
575 case UNSPEC_NETWORK_BARRIER:
580 case UNSPEC_LNK_AND_LABEL:
582 case UNSPEC_MOV_PCREL_STEP3:
583 case UNSPEC_NETWORK_RECEIVE:
584 case UNSPEC_NETWORK_SEND:
585 case UNSPEC_SPR_MOVE:
586 case UNSPEC_TLS_GD_ADD:
587 *total = COSTS_N_INSNS (1);
590 case UNSPEC_TLS_IE_LOAD:
592 *total = COSTS_N_INSNS (2);
596 *total = COSTS_N_INSNS (3);
600 *total = COSTS_N_INSNS (4);
604 case UNSPEC_INSN_CMPEXCH:
605 case UNSPEC_LATENCY_L2:
606 *total = COSTS_N_INSNS (11);
609 case UNSPEC_TLS_GD_CALL:
610 *total = COSTS_N_INSNS (30);
613 case UNSPEC_LATENCY_MISS:
614 *total = COSTS_N_INSNS (80);
618 *total = COSTS_N_INSNS (1);
633 /* Create a temporary variable to hold a partial result, to enable
636 create_temp_reg_if_possible (enum machine_mode mode, rtx default_reg)
638 return can_create_pseudo_p () ? gen_reg_rtx (mode) : default_reg;
642 /* Functions to save and restore machine-specific function data. */
643 static struct machine_function *
644 tilegx_init_machine_status (void)
646 return ggc_alloc_cleared_machine_function ();
650 /* Do anything needed before RTL is emitted for each function. */
652 tilegx_init_expanders (void)
654 /* Arrange to initialize and mark the machine per-function
656 init_machine_status = tilegx_init_machine_status;
658 if (cfun && cfun->machine && flag_pic)
660 static int label_num = 0;
662 char text_label_name[32];
664 struct machine_function *machine = cfun->machine;
666 ASM_GENERATE_INTERNAL_LABEL (text_label_name, "L_PICLNK", label_num++);
668 machine->text_label_symbol =
669 gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (text_label_name));
671 machine->text_label_rtx =
672 gen_rtx_REG (Pmode, TILEGX_PIC_TEXT_LABEL_REGNUM);
674 machine->got_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
676 machine->calls_tls_get_addr = false;
681 /* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode
682 matching insns and therefore guarantee that the shift count is
683 modulo 64. SImode shifts sometimes use the 64 bit version so do
684 not hold such guarantee. */
685 static unsigned HOST_WIDE_INT
686 tilegx_shift_truncation_mask (enum machine_mode mode)
688 return mode == DImode ? 63 : 0;
692 /* Implement TARGET_INIT_LIBFUNCS. */
694 tilegx_init_libfuncs (void)
696 /* We need to explicitly generate these libfunc's to support
697 conversion of divide by constant to multiply (the divide stubs in
698 tilegx.md exist also for this reason). Normally we'd expect gcc
699 to lazily generate them when they are needed, but for some reason
700 it's set up to only generate them if the mode is the word
702 set_optab_libfunc (sdiv_optab, SImode, "__divsi3");
703 set_optab_libfunc (udiv_optab, SImode, "__udivsi3");
704 set_optab_libfunc (smod_optab, SImode, "__modsi3");
705 set_optab_libfunc (umod_optab, SImode, "__umodsi3");
709 /* Return true if X contains a thread-local symbol. */
711 tilegx_tls_referenced_p (rtx x)
713 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
714 x = XEXP (XEXP (x, 0), 0);
716 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
719 /* That's all we handle in tilegx_legitimize_tls_address for
725 /* Return true if X requires a scratch register. It is given that
726 flag_pic is on and that X satisfies CONSTANT_P. */
728 tilegx_pic_address_needs_scratch (rtx x)
730 if (GET_CODE (x) == CONST
731 && GET_CODE (XEXP (x, 0)) == PLUS
732 && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
733 || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
734 && (CONST_INT_P (XEXP (XEXP (x, 0), 1))))
741 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
742 which we are willing to load the value into a register via a move
743 pattern. TLS cannot be treated as a constant because it can
744 include a function call. */
746 tilegx_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
748 switch (GET_CODE (x))
752 return !tilegx_tls_referenced_p (x);
760 /* Return true if the constant value X is a legitimate general operand
761 when generating PIC code. It is given that flag_pic is on and that
762 X satisfies CONSTANT_P. */
764 tilegx_legitimate_pic_operand_p (rtx x)
766 if (tilegx_pic_address_needs_scratch (x))
769 if (tilegx_tls_referenced_p (x))
776 /* Return true if the rtx X can be used as an address operand. */
778 tilegx_legitimate_address_p (enum machine_mode ARG_UNUSED (mode), rtx x,
781 if (GET_CODE (x) == SUBREG)
784 switch (GET_CODE (x))
788 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
795 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
798 if (GET_CODE (XEXP (x, 1)) != PLUS)
801 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
804 if (!satisfies_constraint_I (XEXP (XEXP (x, 1), 1)))
817 /* Check if x is a valid reg. */
822 return REGNO_OK_FOR_BASE_P (REGNO (x));
828 /* Return the rtx containing SYMBOL_REF to the text label. */
830 tilegx_text_label_symbol (void)
832 return cfun->machine->text_label_symbol;
836 /* Return the register storing the value of the text label. */
838 tilegx_text_label_rtx (void)
840 return cfun->machine->text_label_rtx;
844 /* Return the register storing the value of the global offset
847 tilegx_got_rtx (void)
849 return cfun->machine->got_rtx;
853 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
855 tilegx_got_symbol (void)
857 if (g_got_symbol == NULL)
858 g_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
864 /* Return a reference to the got to be used by tls references. */
866 tilegx_tls_got (void)
871 crtl->uses_pic_offset_table = 1;
872 return tilegx_got_rtx ();
875 temp = gen_reg_rtx (Pmode);
876 emit_move_insn (temp, tilegx_got_symbol ());
882 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
883 this (thread-local) address. */
885 tilegx_legitimize_tls_address (rtx addr)
889 gcc_assert (can_create_pseudo_p ());
891 if (GET_CODE (addr) == SYMBOL_REF)
892 switch (SYMBOL_REF_TLS_MODEL (addr))
894 case TLS_MODEL_GLOBAL_DYNAMIC:
895 case TLS_MODEL_LOCAL_DYNAMIC:
897 rtx r0, temp, temp2, temp3, got, last;
899 ret = gen_reg_rtx (Pmode);
900 r0 = gen_rtx_REG (Pmode, 0);
901 temp = gen_reg_rtx (Pmode);
902 temp2 = gen_reg_rtx (Pmode);
903 temp3 = gen_reg_rtx (Pmode);
905 got = tilegx_tls_got ();
908 emit_insn (gen_mov_tls_gd_step1_32bit (temp, addr));
909 emit_insn (gen_mov_tls_gd_step2_32bit (temp2, temp, addr));
910 emit_insn (gen_tls_add_32bit (temp2, got, temp2, addr));
914 emit_insn (gen_mov_tls_gd_step1 (temp, addr));
915 emit_insn (gen_mov_tls_gd_step2 (temp2, temp, addr));
916 emit_insn (gen_tls_add (temp2, got, temp2, addr));
919 emit_move_insn (r0, temp2);
923 emit_insn (gen_tls_gd_call_32bit (addr));
927 emit_insn (gen_tls_gd_call (addr));
930 emit_move_insn (temp3, r0);
933 last = emit_insn (gen_tls_gd_add_32bit (ret, temp3, addr));
935 last = emit_insn (gen_tls_gd_add (ret, temp3, addr));
937 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
940 case TLS_MODEL_INITIAL_EXEC:
942 rtx temp, temp2, temp3, got, last;
944 ret = gen_reg_rtx (Pmode);
945 temp = gen_reg_rtx (Pmode);
946 temp2 = gen_reg_rtx (Pmode);
947 temp3 = gen_reg_rtx (Pmode);
949 got = tilegx_tls_got ();
952 emit_insn (gen_mov_tls_ie_step1_32bit (temp, addr));
953 emit_insn (gen_mov_tls_ie_step2_32bit (temp2, temp, addr));
954 emit_insn (gen_tls_add_32bit (temp2, got, temp2, addr));
955 emit_insn (gen_tls_ie_load_32bit (temp3, temp2, addr));
959 emit_insn (gen_mov_tls_ie_step1 (temp, addr));
960 emit_insn (gen_mov_tls_ie_step2 (temp2, temp, addr));
961 emit_insn (gen_tls_add (temp2, got, temp2, addr));
962 emit_insn (gen_tls_ie_load (temp3, temp2, addr));
969 THREAD_POINTER_REGNUM),
971 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
974 case TLS_MODEL_LOCAL_EXEC:
976 rtx temp, temp2, last;
978 ret = gen_reg_rtx (Pmode);
979 temp = gen_reg_rtx (Pmode);
980 temp2 = gen_reg_rtx (Pmode);
984 emit_insn (gen_mov_tls_le_step1_32bit (temp, addr));
985 emit_insn (gen_mov_tls_le_step2_32bit (temp2, temp, addr));
989 emit_insn (gen_mov_tls_le_step1 (temp, addr));
990 emit_insn (gen_mov_tls_le_step2 (temp2, temp, addr));
997 THREAD_POINTER_REGNUM),
999 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
1005 else if (GET_CODE (addr) == CONST)
1009 gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
1011 base = tilegx_legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
1012 offset = XEXP (XEXP (addr, 0), 1);
1014 base = force_operand (base, NULL_RTX);
1015 ret = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
1024 /* Returns a register that points to ADDR, a symbolic address, by
1025 computing its address relative to tilegx_text_label_symbol. */
1027 compute_pcrel_address (rtx result, rtx addr)
1029 rtx text_label_symbol = tilegx_text_label_symbol ();
1030 rtx text_label_rtx = tilegx_text_label_rtx ();
1033 temp = create_temp_reg_if_possible (Pmode, result);
1034 temp2 = create_temp_reg_if_possible (Pmode, result);
1038 emit_insn (gen_mov_pcrel_step1_32bit (temp, addr, text_label_symbol));
1039 emit_insn (gen_mov_pcrel_step2_32bit (temp2, temp, addr,
1040 text_label_symbol));
1041 emit_insn (gen_mov_pcrel_step3_32bit (result, temp2,
1043 addr, text_label_symbol));
1047 emit_insn (gen_mov_pcrel_step1 (temp, addr, text_label_symbol));
1048 emit_insn (gen_mov_pcrel_step2 (temp2, temp, addr, text_label_symbol));
1049 emit_insn (gen_mov_pcrel_step3 (result, temp2,
1051 addr, text_label_symbol));
1056 /* Legitimize PIC addresses. If the address is already
1057 position-independent, we return ORIG. Newly generated
1058 position-independent addresses go into a reg. This is REG if
1059 nonzero, otherwise we allocate register(s) as necessary. */
1061 tilegx_legitimize_pic_address (rtx orig,
1062 enum machine_mode mode ATTRIBUTE_UNUSED,
1065 if (GET_CODE (orig) == SYMBOL_REF)
1067 rtx address, pic_ref;
1071 gcc_assert (can_create_pseudo_p ());
1072 reg = gen_reg_rtx (Pmode);
1075 if (SYMBOL_REF_LOCAL_P (orig))
1077 /* If not during reload, allocate another temp reg here for
1078 loading in the address, so that these instructions can be
1079 optimized properly. */
1080 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
1081 compute_pcrel_address (temp_reg, orig);
1083 /* Note: this is conservative. We use the text_label but we
1084 don't use the pic_offset_table. However, in some cases
1085 we may need the pic_offset_table (see
1086 tilegx_fixup_pcrel_references). */
1087 crtl->uses_pic_offset_table = 1;
1091 emit_move_insn (reg, address);
1096 /* If not during reload, allocate another temp reg here for
1097 loading in the address, so that these instructions can be
1098 optimized properly. */
1099 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
1101 gcc_assert (flag_pic);
1106 emit_insn (gen_add_got16_32bit (temp_reg,
1112 emit_insn (gen_add_got16 (temp_reg,
1113 tilegx_got_rtx (), orig));
1118 rtx temp_reg2 = create_temp_reg_if_possible (Pmode, reg);
1119 rtx temp_reg3 = create_temp_reg_if_possible (Pmode, reg);
1122 emit_insn (gen_mov_got32_step1_32bit (temp_reg3, orig));
1123 emit_insn (gen_mov_got32_step2_32bit
1124 (temp_reg2, temp_reg3, orig));
1128 emit_insn (gen_mov_got32_step1 (temp_reg3, orig));
1129 emit_insn (gen_mov_got32_step2 (temp_reg2, temp_reg3,
1132 emit_move_insn (temp_reg,
1133 gen_rtx_PLUS (Pmode,
1134 tilegx_got_rtx (), temp_reg2));
1139 pic_ref = gen_const_mem (Pmode, address);
1140 crtl->uses_pic_offset_table = 1;
1141 emit_move_insn (reg, pic_ref);
1142 /* The following put a REG_EQUAL note on this insn, so that
1143 it can be optimized by loop. But it causes the label to
1144 be optimized away. */
1145 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1149 else if (GET_CODE (orig) == CONST)
1153 if (GET_CODE (XEXP (orig, 0)) == PLUS
1154 && XEXP (XEXP (orig, 0), 0) == tilegx_got_rtx ())
1159 gcc_assert (can_create_pseudo_p ());
1160 reg = gen_reg_rtx (Pmode);
1163 gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
1164 base = tilegx_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
1166 offset = tilegx_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
1167 base == reg ? 0 : reg);
1169 if (CONST_INT_P (offset))
1171 if (can_create_pseudo_p ())
1172 offset = force_reg (Pmode, offset);
1174 /* If we reach here, then something is seriously wrong. */
1178 if (can_create_pseudo_p ())
1179 return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
1183 else if (GET_CODE (orig) == LABEL_REF)
1190 gcc_assert (can_create_pseudo_p ());
1191 reg = gen_reg_rtx (Pmode);
1194 /* If not during reload, allocate another temp reg here for
1195 loading in the address, so that these instructions can be
1196 optimized properly. */
1197 temp_reg = create_temp_reg_if_possible (Pmode, reg);
1198 compute_pcrel_address (temp_reg, orig);
1200 /* Note: this is conservative. We use the text_label but we
1201 don't use the pic_offset_table. */
1202 crtl->uses_pic_offset_table = 1;
1206 emit_move_insn (reg, address);
1215 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1217 tilegx_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1218 enum machine_mode mode)
1220 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
1221 && symbolic_operand (x, Pmode) && tilegx_tls_referenced_p (x))
1223 return tilegx_legitimize_tls_address (x);
1227 return tilegx_legitimize_pic_address (x, mode, 0);
1234 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1236 tilegx_delegitimize_address (rtx x)
1238 x = delegitimize_mem_from_attrs (x);
1240 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC)
1242 switch (XINT (XEXP (x, 0), 1))
1248 case UNSPEC_HW0_LAST:
1249 case UNSPEC_HW1_LAST:
1250 case UNSPEC_HW2_LAST:
1251 case UNSPEC_HW0_PCREL:
1252 case UNSPEC_HW1_LAST_PCREL:
1253 case UNSPEC_HW0_GOT:
1254 case UNSPEC_HW0_LAST_GOT:
1255 case UNSPEC_HW1_LAST_GOT:
1256 case UNSPEC_HW0_TLS_GD:
1257 case UNSPEC_HW1_LAST_TLS_GD:
1258 case UNSPEC_HW0_TLS_IE:
1259 case UNSPEC_HW1_LAST_TLS_IE:
1260 case UNSPEC_HW0_TLS_LE:
1261 case UNSPEC_HW1_LAST_TLS_LE:
1262 x = XVECEXP (XEXP (x, 0), 0, 0);
1271 /* Emit code to load the PIC register. */
1273 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED)
1275 int orig_flag_pic = flag_pic;
1277 rtx got_symbol = tilegx_got_symbol ();
1278 rtx text_label_symbol = tilegx_text_label_symbol ();
1279 rtx text_label_rtx = tilegx_text_label_rtx ();
1284 emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx,
1285 text_label_symbol));
1289 emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol));
1292 compute_pcrel_address (tilegx_got_rtx (), got_symbol);
1294 flag_pic = orig_flag_pic;
1296 /* Need to emit this whether or not we obey regdecls, since
1297 setjmp/longjmp can cause life info to screw up. ??? In the case
1298 where we don't obey regdecls, this is not sufficient since we may
1299 not fall out the bottom. */
1300 emit_use (tilegx_got_rtx ());
1304 /* Return the simd variant of the constant NUM of mode MODE, by
1305 replicating it to fill an interger of mode DImode. NUM is first
1306 truncated to fit in MODE. */
1308 tilegx_simd_int (rtx num, enum machine_mode mode)
1310 HOST_WIDE_INT n = 0;
1312 gcc_assert (CONST_INT_P (num));
1319 n = 0x0101010101010101LL * (n & 0x000000FF);
1322 n = 0x0001000100010001LL * (n & 0x0000FFFF);
1325 n = 0x0000000100000001LL * (n & 0xFFFFFFFF);
1337 /* Returns true iff VAL can be moved into a register in one
1338 instruction. And if it can, it emits the code to move the constant
1341 If THREE_WIDE_ONLY is true, this insists on an instruction that
1342 works in a bundle containing three instructions. */
1344 expand_set_cint64_one_inst (rtx dest_reg,
1345 HOST_WIDE_INT val, bool three_wide_only)
1347 if (val == trunc_int_for_mode (val, QImode))
1350 emit_move_insn (dest_reg, GEN_INT (val));
1353 else if (!three_wide_only)
1355 rtx imm_op = GEN_INT (val);
1357 if (satisfies_constraint_J (imm_op)
1358 || satisfies_constraint_K (imm_op)
1359 || satisfies_constraint_N (imm_op)
1360 || satisfies_constraint_P (imm_op))
1362 emit_move_insn (dest_reg, imm_op);
1371 /* Implement DImode rotatert. */
1372 static HOST_WIDE_INT
1373 rotate_right (HOST_WIDE_INT n, int count)
1375 unsigned HOST_WIDE_INT x = n & 0xFFFFFFFFFFFFFFFFULL;
1378 return ((x >> count) | (x << (64 - count))) & 0xFFFFFFFFFFFFFFFFULL;
1382 /* Return true iff n contains exactly one contiguous sequence of 1
1383 bits, possibly wrapping around from high bits to low bits. */
1385 tilegx_bitfield_operand_p (HOST_WIDE_INT n, int *first_bit, int *last_bit)
1392 for (i = 0; i < 64; i++)
1394 unsigned HOST_WIDE_INT x = rotate_right (n, i);
1398 /* See if x is a power of two minus one, i.e. only consecutive 1
1399 bits starting from bit 0. */
1400 if ((x & (x + 1)) == 0)
1402 if (first_bit != NULL)
1404 if (last_bit != NULL)
1405 *last_bit = (i + exact_log2 (x ^ (x >> 1))) & 63;
1415 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1417 expand_set_cint64 (rtx dest_reg, rtx src_val)
1420 int leading_zeroes, trailing_zeroes;
1421 int three_wide_only;
1422 int shift, ins_shift, zero_cluster_shift;
1425 gcc_assert (CONST_INT_P (src_val));
1426 val = trunc_int_for_mode (INTVAL (src_val), GET_MODE (dest_reg));
1428 /* See if we can generate the constant in one instruction. */
1429 if (expand_set_cint64_one_inst (dest_reg, val, false))
1432 /* Force the destination to DImode so we can use DImode instructions
1433 to create it. This both allows instructions like rotl, and
1434 certain efficient 3-wide instructions. */
1435 subreg = simplify_gen_subreg (DImode, dest_reg, GET_MODE (dest_reg), 0);
1436 gcc_assert (subreg != NULL);
1439 temp = create_temp_reg_if_possible (DImode, dest_reg);
1441 leading_zeroes = 63 - floor_log2 (val & 0xFFFFFFFFFFFFFFFFULL);
1442 trailing_zeroes = exact_log2 (val & -val);
1444 /* First try all three-wide instructions that generate a constant
1445 (i.e. movei) followed by various shifts and rotates. If none of
1446 those work, try various two-wide ways of generating a constant
1447 followed by various shifts and rotates. */
1448 for (three_wide_only = 1; three_wide_only >= 0; three_wide_only--)
1452 if (expand_set_cint64_one_inst (temp, val >> trailing_zeroes,
1455 /* 0xFFFFFFFFFFFFA500 becomes:
1456 movei temp, 0xFFFFFFFFFFFFFFA5
1457 shli dest, temp, 8 */
1458 emit_move_insn (dest_reg,
1459 gen_rtx_ASHIFT (DImode, temp,
1460 GEN_INT (trailing_zeroes)));
1464 if (expand_set_cint64_one_inst (temp, val << leading_zeroes,
1467 /* 0x7FFFFFFFFFFFFFFF becomes:
1469 shrui dest, temp, 1 */
1470 emit_move_insn (dest_reg,
1471 gen_rtx_LSHIFTRT (DImode, temp,
1472 GEN_INT (leading_zeroes)));
1476 /* Try rotating a one-instruction immediate. */
1477 for (count = 1; count < 64; count++)
1479 HOST_WIDE_INT r = rotate_right (val, count);
1480 if (expand_set_cint64_one_inst (temp, r, three_wide_only))
1482 /* 0xFFFFFFFFFFA5FFFF becomes:
1483 movei temp, 0xFFFFFFFFFFFFFFA5
1484 rotli dest, temp, 16 */
1485 emit_move_insn (dest_reg,
1486 gen_rtx_ROTATE (DImode, temp, GEN_INT (count)));
1492 /* There are two cases here to produce a large constant.
1493 In the most general case, we do this:
1496 shl16insli x, x, hw2(NUM)
1497 shl16insli x, x, hw1(NUM)
1498 shl16insli x, x, hw0(NUM)
1500 However, we can sometimes do better. shl16insli is a poor way to
1501 insert 16 zero bits, because simply shifting left by 16 has more
1502 bundling freedom. So if we see any contiguous aligned sequence
1503 of 16 or more zero bits (below the highest set bit), it is always
1504 more efficient to materialize the bits above the zero bits, then
1505 left shift to put in the zeroes, then insert whatever bits
1506 remain. For example, we might end up with:
1508 movei x, NUM >> (37 + 16)
1510 shl16insli x, x, hw0(NUM) */
1512 zero_cluster_shift = -1;
1514 for (shift = 0; shift < 48 - leading_zeroes; shift += 16)
1516 HOST_WIDE_INT x = val >> shift;
1518 /* Find the least significant group of 16 aligned zero bits. */
1519 if ((x & 0xFFFF) == 0x0000)
1521 /* Grab any following zero bits as well. */
1522 zero_cluster_shift = exact_log2 (x & -x);
1523 shift += zero_cluster_shift;
1528 if (zero_cluster_shift >= 0)
1530 unsigned HOST_WIDE_INT leftover;
1532 /* Recursively create the constant above the lowest 16 zero
1534 expand_set_cint64 (temp, GEN_INT (val >> shift));
1536 /* See if we can easily insert the remaining bits, or if we need
1537 to fall through to the more general case. */
1538 leftover = val - ((val >> shift) << shift);
1541 /* A simple left shift is enough. */
1542 emit_move_insn (dest_reg,
1543 gen_rtx_ASHIFT (DImode, temp, GEN_INT (shift)));
1546 else if (leftover <= 32767)
1548 /* Left shift into position then add in the leftover. */
1549 rtx temp2 = create_temp_reg_if_possible (DImode, temp);
1550 emit_move_insn (temp2,
1551 gen_rtx_ASHIFT (DImode, temp, GEN_INT (shift)));
1552 emit_move_insn (dest_reg,
1553 gen_rtx_PLUS (DImode, temp2, GEN_INT (leftover)));
1558 /* Shift in the batch of >= 16 zeroes we detected earlier.
1559 After this, shift will be aligned mod 16 so the final
1560 loop can use shl16insli. */
1561 rtx temp2 = create_temp_reg_if_possible (DImode, temp);
1562 rtx shift_count_rtx = GEN_INT (zero_cluster_shift);
1564 emit_move_insn (temp2,
1565 gen_rtx_ASHIFT (DImode, temp, shift_count_rtx));
1567 shift -= zero_cluster_shift;
1573 /* Set as many high 16-bit blocks as we can with a single
1574 instruction. We'll insert the remaining 16-bit blocks
1576 for (shift = 16;; shift += 16)
1578 gcc_assert (shift < 64);
1579 if (expand_set_cint64_one_inst (temp, val >> shift, false))
1584 /* At this point, temp == val >> shift, shift % 16 == 0, and we
1585 still need to insert any bits of 'val' below 'shift'. Those bits
1586 are guaranteed to not have 16 contiguous zeroes. */
1588 gcc_assert ((shift & 15) == 0);
1590 for (ins_shift = shift - 16; ins_shift >= 0; ins_shift -= 16)
1593 HOST_WIDE_INT bits = (val >> ins_shift) & 0xFFFF;
1594 gcc_assert (bits != 0);
1596 /* On the last iteration we need to store into dest_reg. */
1600 result = create_temp_reg_if_possible (DImode, dest_reg);
1602 emit_insn (gen_insn_shl16insli (result, temp, GEN_INT (bits)));
1609 /* Load OP1, a 64-bit constant, into OP0, a register. We know it
1610 can't be done in one insn when we get here, the move expander
1613 tilegx_expand_set_const64 (rtx op0, rtx op1)
1615 if (CONST_INT_P (op1))
1617 /* TODO: I don't know if we want to split large constants
1618 now, or wait until later (with a define_split).
1620 Does splitting early help CSE? Does it harm other
1621 optimizations that might fold loads? */
1622 expand_set_cint64 (op0, op1);
1626 rtx temp = create_temp_reg_if_possible (Pmode, op0);
1630 /* Generate the 2-insn sequence to materialize a symbolic
1632 emit_insn (gen_mov_address_32bit_step1 (temp, op1));
1633 emit_insn (gen_mov_address_32bit_step2 (op0, temp, op1));
1637 /* Generate the 3-insn sequence to materialize a symbolic
1638 address. Note that this assumes that virtual addresses
1639 fit in 48 signed bits, which is currently true. */
1640 rtx temp2 = create_temp_reg_if_possible (Pmode, op0);
1641 emit_insn (gen_mov_address_step1 (temp, op1));
1642 emit_insn (gen_mov_address_step2 (temp2, temp, op1));
1643 emit_insn (gen_mov_address_step3 (op0, temp2, op1));
1649 /* Expand a move instruction. Return true if all work is done. */
1651 tilegx_expand_mov (enum machine_mode mode, rtx *operands)
1653 /* Handle sets of MEM first. */
1654 if (MEM_P (operands[0]))
1656 if (can_create_pseudo_p ())
1657 operands[0] = validize_mem (operands[0]);
1659 if (reg_or_0_operand (operands[1], mode))
1662 if (!reload_in_progress)
1663 operands[1] = force_reg (mode, operands[1]);
1666 /* Fixup TLS cases. */
1667 if (CONSTANT_P (operands[1]) && tilegx_tls_referenced_p (operands[1]))
1669 operands[1] = tilegx_legitimize_tls_address (operands[1]);
1673 /* Fixup PIC cases. */
1674 if (flag_pic && CONSTANT_P (operands[1]))
1676 if (tilegx_pic_address_needs_scratch (operands[1]))
1677 operands[1] = tilegx_legitimize_pic_address (operands[1], mode, 0);
1679 if (symbolic_operand (operands[1], mode))
1681 operands[1] = tilegx_legitimize_pic_address (operands[1],
1683 (reload_in_progress ?
1690 /* Accept non-constants and valid constants unmodified. */
1691 if (!CONSTANT_P (operands[1]) || move_operand (operands[1], mode))
1694 /* Split large integers. */
1695 tilegx_expand_set_const64 (operands[0], operands[1]);
1700 /* Expand unaligned loads. */
1702 tilegx_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize,
1703 HOST_WIDE_INT bit_offset, bool sign)
1705 enum machine_mode mode;
1706 rtx addr_lo, addr_hi;
1707 rtx mem_lo, mem_hi, hi;
1708 rtx mema, wide_result;
1709 int last_byte_offset;
1710 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1712 mode = GET_MODE (dest_reg);
1714 hi = gen_reg_rtx (mode);
1716 if (bitsize == 2 * BITS_PER_UNIT && (bit_offset % BITS_PER_UNIT) == 0)
1718 /* When just loading a two byte value, we can load the two bytes
1719 individually and combine them efficiently. */
1721 mem_lo = adjust_address (mem, QImode, byte_offset);
1722 mem_hi = adjust_address (mem, QImode, byte_offset + 1);
1726 /* Do a signed load of the second byte and use bfins to set
1727 the high bits of the result. */
1728 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, dest_reg),
1730 emit_insn (gen_extendqidi2 (gen_lowpart (DImode, hi), mem_hi));
1731 emit_insn (gen_insv (gen_lowpart (DImode, dest_reg),
1732 GEN_INT (64 - 8), GEN_INT (8),
1733 gen_lowpart (DImode, hi)));
1737 /* Do two unsigned loads and use v1int_l to interleave
1739 rtx lo = gen_reg_rtx (mode);
1740 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, lo),
1742 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, hi),
1744 emit_insn (gen_insn_v1int_l (gen_lowpart (DImode, dest_reg),
1745 gen_lowpart (DImode, hi),
1746 gen_lowpart (DImode, lo)));
1752 mema = XEXP (mem, 0);
1754 /* AND addresses cannot be in any alias set, since they may
1755 implicitly alias surrounding code. Ideally we'd have some alias
1756 set that covered all types except those with alignment 8 or
1758 addr_lo = force_reg (Pmode, plus_constant (mema, byte_offset));
1759 mem_lo = change_address (mem, mode,
1760 gen_rtx_AND (GET_MODE (mema), addr_lo,
1762 set_mem_alias_set (mem_lo, 0);
1764 /* Load the high word at an address that will not fault if the low
1765 address is aligned and at the very end of a page. */
1766 last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT;
1767 addr_hi = force_reg (Pmode, plus_constant (mema, last_byte_offset));
1768 mem_hi = change_address (mem, mode,
1769 gen_rtx_AND (GET_MODE (mema), addr_hi,
1771 set_mem_alias_set (mem_hi, 0);
1775 addr_lo = make_safe_from (addr_lo, dest_reg);
1776 wide_result = dest_reg;
1780 wide_result = gen_reg_rtx (mode);
1783 /* Load hi first in case dest_reg is used in mema. */
1784 emit_move_insn (hi, mem_hi);
1785 emit_move_insn (wide_result, mem_lo);
1787 emit_insn (gen_insn_dblalign (gen_lowpart (DImode, wide_result),
1788 gen_lowpart (DImode, wide_result),
1789 gen_lowpart (DImode, hi), addr_lo));
1794 extract_bit_field (gen_lowpart (DImode, wide_result),
1795 bitsize, bit_offset % BITS_PER_UNIT,
1796 !sign, false, gen_lowpart (DImode, dest_reg),
1799 if (extracted != dest_reg)
1800 emit_move_insn (dest_reg, gen_lowpart (DImode, extracted));
1805 /* Expand unaligned stores. */
1807 tilegx_expand_unaligned_store (rtx mem, rtx src, HOST_WIDE_INT bitsize,
1808 HOST_WIDE_INT bit_offset)
1810 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1811 HOST_WIDE_INT bytesize = bitsize / BITS_PER_UNIT;
1812 HOST_WIDE_INT shift_amt;
1817 for (i = 0, shift_amt = 0; i < bytesize; i++, shift_amt += BITS_PER_UNIT)
1819 mem_addr = adjust_address (mem, QImode, byte_offset + i);
1823 store_val = expand_simple_binop (DImode, LSHIFTRT,
1824 gen_lowpart (DImode, src),
1825 GEN_INT (shift_amt), NULL, 1,
1827 store_val = gen_lowpart (QImode, store_val);
1831 store_val = gen_lowpart (QImode, src);
1834 emit_move_insn (mem_addr, store_val);
1839 /* Implement the movmisalign patterns. One of the operands is a
1840 memory that is not naturally aligned. Emit instructions to load
1843 tilegx_expand_movmisalign (enum machine_mode mode, rtx *operands)
1845 if (MEM_P (operands[1]))
1849 if (register_operand (operands[0], mode))
1852 tmp = gen_reg_rtx (mode);
1854 tilegx_expand_unaligned_load (tmp, operands[1], GET_MODE_BITSIZE (mode),
1857 if (tmp != operands[0])
1858 emit_move_insn (operands[0], tmp);
1860 else if (MEM_P (operands[0]))
1862 if (!reg_or_0_operand (operands[1], mode))
1863 operands[1] = force_reg (mode, operands[1]);
1865 tilegx_expand_unaligned_store (operands[0], operands[1],
1866 GET_MODE_BITSIZE (mode), 0);
1874 /* Implement the allocate_stack pattern (alloca). */
1876 tilegx_allocate_stack (rtx op0, rtx op1)
1878 /* Technically the correct way to initialize chain_loc is with
1879 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
1880 * sets the alias_set to that of a frame reference. Some of our
1881 * tests rely on some unsafe assumption about when the chaining
1882 * update is done, we need to be conservative about reordering the
1883 * chaining instructions.
1885 rtx fp_addr = gen_reg_rtx (Pmode);
1886 rtx fp_value = gen_reg_rtx (Pmode);
1889 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1890 GEN_INT (UNITS_PER_WORD)));
1892 fp_loc = gen_frame_mem (Pmode, fp_addr);
1894 emit_move_insn (fp_value, fp_loc);
1896 op1 = force_reg (Pmode, op1);
1898 emit_move_insn (stack_pointer_rtx,
1899 gen_rtx_MINUS (Pmode, stack_pointer_rtx, op1));
1901 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1902 GEN_INT (UNITS_PER_WORD)));
1904 fp_loc = gen_frame_mem (Pmode, fp_addr);
1906 emit_move_insn (fp_loc, fp_value);
1908 emit_move_insn (op0, virtual_stack_dynamic_rtx);
1916 /* Returns the insn_code in ENTRY. */
1917 static enum insn_code
1918 tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry
1921 return tilegx_multiply_insn_seq_decode_opcode[entry->compressed_opcode];
1925 /* Returns the length of the 'op' array. */
1927 tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq *seq)
1929 /* The array either uses all of its allocated slots or is terminated
1930 by a bogus opcode. Either way, the array size is the index of the
1931 last valid opcode plus one. */
1933 for (i = tilegx_multiply_insn_seq_MAX_OPERATIONS - 1; i >= 0; i--)
1934 if (tilegx_multiply_get_opcode (&seq->op[i]) != CODE_FOR_nothing)
1937 /* An empty array is not allowed. */
1942 /* We precompute a number of expression trees for multiplying by
1943 constants. This generates code for such an expression tree by
1944 walking through the nodes in the tree (which are conveniently
1945 pre-linearized) and emitting an instruction for each one. */
1947 tilegx_expand_constant_multiply_given_sequence (rtx result, rtx src,
1949 tilegx_multiply_insn_seq *seq)
1954 /* Keep track of the subexpressions computed so far, so later
1955 instructions can refer to them. We seed the array with zero and
1956 the value being multiplied. */
1957 int num_subexprs = 2;
1958 rtx subexprs[tilegx_multiply_insn_seq_MAX_OPERATIONS + 2];
1959 subexprs[0] = const0_rtx;
1962 /* Determine how many instructions we are going to generate. */
1963 num_ops = tilegx_multiply_get_num_ops (seq);
1964 gcc_assert (num_ops > 0
1965 && num_ops <= tilegx_multiply_insn_seq_MAX_OPERATIONS);
1967 for (i = 0; i < num_ops; i++)
1969 const struct tilegx_multiply_insn_seq_entry *entry = &seq->op[i];
1971 /* Figure out where to store the output of this instruction. */
1972 const bool is_last_op = (i + 1 == num_ops);
1973 rtx out = is_last_op ? result : gen_reg_rtx (DImode);
1975 enum insn_code opcode = tilegx_multiply_get_opcode (entry);
1976 if (opcode == CODE_FOR_ashldi3)
1978 /* Handle shift by immediate. This is a special case because
1979 the meaning of the second operand is a constant shift
1980 count rather than an operand index. */
1982 /* Make sure the shift count is in range. Zero should not
1984 const int shift_count = entry->rhs;
1985 gcc_assert (shift_count > 0 && shift_count < 64);
1987 /* Emit the actual instruction. */
1988 emit_insn (GEN_FCN (opcode)
1989 (out, subexprs[entry->lhs],
1990 gen_rtx_CONST_INT (DImode, shift_count)));
1994 /* Handle a normal two-operand instruction, such as add or
1997 /* Make sure we are referring to a previously computed
1999 gcc_assert (entry->rhs < num_subexprs);
2001 /* Emit the actual instruction. */
2002 emit_insn (GEN_FCN (opcode)
2003 (out, subexprs[entry->lhs], subexprs[entry->rhs]));
2006 /* Record this subexpression for use by later expressions. */
2007 subexprs[num_subexprs++] = out;
2012 /* bsearch helper function. */
2014 tilegx_compare_multipliers (const void *key, const void *t)
2017 (*(const long long *) key
2018 - ((const struct tilegx_multiply_insn_seq *) t)->multiplier);
2019 return (delta < 0) ? -1 : (delta > 0);
2023 /* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none
2025 static const struct tilegx_multiply_insn_seq *
2026 tilegx_find_multiply_insn_seq_for_constant (long long multiplier)
2028 return ((const struct tilegx_multiply_insn_seq *)
2029 bsearch (&multiplier, tilegx_multiply_insn_seq_table,
2030 tilegx_multiply_insn_seq_table_size,
2031 sizeof tilegx_multiply_insn_seq_table[0],
2032 tilegx_compare_multipliers));
2036 /* Try to a expand constant multiply in DImode by looking it up in a
2037 precompiled table. OP0 is the result operand, OP1 is the source
2038 operand, and MULTIPLIER is the value of the constant. Return true
2041 tilegx_expand_const_muldi (rtx op0, rtx op1, long long multiplier)
2043 /* See if we have precomputed an efficient way to multiply by this
2045 const struct tilegx_multiply_insn_seq *seq =
2046 tilegx_find_multiply_insn_seq_for_constant (multiplier);
2049 tilegx_expand_constant_multiply_given_sequence (op0, op1, seq);
2057 /* Expand the muldi pattern. */
2059 tilegx_expand_muldi (rtx op0, rtx op1, rtx op2)
2061 if (CONST_INT_P (op2))
2063 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), DImode);
2064 return tilegx_expand_const_muldi (op0, op1, n);
2070 /* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the
2071 operands, and SIGN is true if it's a signed multiply, and false if
2072 it's an unsigned multiply. */
2074 tilegx_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign)
2076 rtx tmp0 = gen_reg_rtx (DImode);
2077 rtx tmp1 = gen_reg_rtx (DImode);
2078 rtx tmp2 = gen_reg_rtx (DImode);
2079 rtx tmp3 = gen_reg_rtx (DImode);
2080 rtx tmp4 = gen_reg_rtx (DImode);
2081 rtx tmp5 = gen_reg_rtx (DImode);
2082 rtx tmp6 = gen_reg_rtx (DImode);
2083 rtx tmp7 = gen_reg_rtx (DImode);
2084 rtx tmp8 = gen_reg_rtx (DImode);
2085 rtx tmp9 = gen_reg_rtx (DImode);
2086 rtx tmp10 = gen_reg_rtx (DImode);
2087 rtx tmp11 = gen_reg_rtx (DImode);
2088 rtx tmp12 = gen_reg_rtx (DImode);
2089 rtx tmp13 = gen_reg_rtx (DImode);
2090 rtx result_lo = gen_reg_rtx (DImode);
2094 emit_insn (gen_insn_mul_hs_lu (tmp0, op1, op2));
2095 emit_insn (gen_insn_mul_hs_lu (tmp1, op2, op1));
2096 emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2));
2097 emit_insn (gen_insn_mul_hs_hs (tmp3, op1, op2));
2101 emit_insn (gen_insn_mul_hu_lu (tmp0, op1, op2));
2102 emit_insn (gen_insn_mul_hu_lu (tmp1, op2, op1));
2103 emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2));
2104 emit_insn (gen_insn_mul_hu_hu (tmp3, op1, op2));
2107 emit_move_insn (tmp4, (gen_rtx_ASHIFT (DImode, tmp0, GEN_INT (32))));
2109 emit_move_insn (tmp5, (gen_rtx_ASHIFT (DImode, tmp1, GEN_INT (32))));
2111 emit_move_insn (tmp6, (gen_rtx_PLUS (DImode, tmp4, tmp5)));
2112 emit_move_insn (result_lo, (gen_rtx_PLUS (DImode, tmp2, tmp6)));
2114 emit_move_insn (tmp7, gen_rtx_LTU (DImode, tmp6, tmp4));
2115 emit_move_insn (tmp8, gen_rtx_LTU (DImode, result_lo, tmp2));
2119 emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (DImode, tmp0, GEN_INT (32))));
2120 emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (DImode, tmp1, GEN_INT (32))));
2124 emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (DImode, tmp0, GEN_INT (32))));
2125 emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (DImode, tmp1, GEN_INT (32))));
2128 emit_move_insn (tmp11, (gen_rtx_PLUS (DImode, tmp3, tmp7)));
2129 emit_move_insn (tmp12, (gen_rtx_PLUS (DImode, tmp8, tmp9)));
2130 emit_move_insn (tmp13, (gen_rtx_PLUS (DImode, tmp11, tmp12)));
2131 emit_move_insn (result, (gen_rtx_PLUS (DImode, tmp13, tmp10)));
2135 /* Implement smuldi3_highpart. */
2137 tilegx_expand_smuldi3_highpart (rtx op0, rtx op1, rtx op2)
2139 tilegx_expand_high_multiply (op0, op1, op2, true);
2143 /* Implement umuldi3_highpart. */
2145 tilegx_expand_umuldi3_highpart (rtx op0, rtx op1, rtx op2)
2147 tilegx_expand_high_multiply (op0, op1, op2, false);
2152 /* Compare and branches */
2154 /* Produce the rtx yielding a bool for a floating point
2157 tilegx_emit_fp_setcc (rtx res, enum rtx_code code, enum machine_mode mode,
2160 /* TODO: Certain compares again constants can be done using entirely
2161 integer operations. But you have to get the special cases right
2162 e.g. NaN, +0 == -0, etc. */
2166 rtx a = force_reg (DImode, gen_lowpart (DImode, op0));
2167 rtx b = force_reg (DImode, gen_lowpart (DImode, op1));
2169 flags = gen_reg_rtx (DImode);
2173 emit_insn (gen_insn_fsingle_add1 (flags, a, b));
2177 gcc_assert (mode == DFmode);
2178 emit_insn (gen_insn_fdouble_add_flags (flags, a, b));
2183 case EQ: flag_index = 30; break;
2184 case NE: flag_index = 31; break;
2185 case LE: flag_index = 27; break;
2186 case LT: flag_index = 26; break;
2187 case GE: flag_index = 29; break;
2188 case GT: flag_index = 28; break;
2189 default: gcc_unreachable ();
2192 gcc_assert (GET_MODE (res) == DImode);
2193 emit_move_insn (res, gen_rtx_ZERO_EXTRACT (DImode, flags, GEN_INT (1),
2194 GEN_INT (flag_index)));
2199 /* Certain simplifications can be done to make invalid setcc
2200 operations valid. Return the final comparison, or NULL if we can't
2203 tilegx_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1,
2204 enum machine_mode cmp_mode)
2209 if (cmp_mode == SFmode || cmp_mode == DFmode)
2210 return tilegx_emit_fp_setcc (res, code, cmp_mode, op0, op1);
2212 /* The general case: fold the comparison code to the types of
2213 compares that we have, choosing the branch as necessary. */
2223 /* We have these compares. */
2230 /* We do not have these compares, so we reverse the
2236 /* We should not have called this with any other code. */
2242 code = swap_condition (code);
2243 tmp = op0, op0 = op1, op1 = tmp;
2246 if (!reg_or_0_operand (op0, cmp_mode))
2247 op0 = force_reg (cmp_mode, op0);
2249 if (!CONST_INT_P (op1) && !register_operand (op1, cmp_mode))
2250 op1 = force_reg (cmp_mode, op1);
2252 /* Return the setcc comparison. */
2253 emit_insn (gen_rtx_SET (VOIDmode, res,
2254 gen_rtx_fmt_ee (code, DImode, op0, op1)));
2260 /* Implement cstore patterns. */
2262 tilegx_emit_setcc (rtx operands[], enum machine_mode cmp_mode)
2265 tilegx_emit_setcc_internal (operands[0], GET_CODE (operands[1]),
2266 operands[2], operands[3], cmp_mode);
2270 /* Return whether CODE is a signed comparison. */
2272 signed_compare_p (enum rtx_code code)
2274 return (code == EQ || code == NE || code == LT || code == LE
2275 || code == GT || code == GE);
2279 /* Generate the comparison for a DImode conditional branch. */
2281 tilegx_emit_cc_test (enum rtx_code code, rtx op0, rtx op1,
2282 enum machine_mode cmp_mode, bool eq_ne_only)
2284 enum rtx_code branch_code;
2287 if (cmp_mode == SFmode || cmp_mode == DFmode)
2289 /* Compute a boolean saying whether the comparison is true. */
2290 temp = gen_reg_rtx (DImode);
2291 tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2293 /* Test that flag. */
2294 return gen_rtx_fmt_ee (NE, VOIDmode, temp, const0_rtx);
2297 /* Check for a compare against zero using a comparison we can do
2299 if (op1 == const0_rtx
2300 && (code == EQ || code == NE
2301 || (!eq_ne_only && signed_compare_p (code))))
2303 op0 = force_reg (cmp_mode, op0);
2304 return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx);
2307 /* The general case: fold the comparison code to the types of
2308 compares that we have, choosing the branch as necessary. */
2316 /* We have these compares. */
2325 /* These must be reversed (except NE, but let's
2327 code = reverse_condition (code);
2335 if (CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU))
2337 HOST_WIDE_INT n = INTVAL (op1);
2342 /* Subtract off the value we want to compare against and see
2343 if we get zero. This is cheaper than creating a constant
2344 in a register. Except that subtracting -128 is more
2345 expensive than seqi to -128, so we leave that alone. */
2346 /* ??? Don't do this when comparing against symbols,
2347 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2348 0), which will be declared false out of hand (at least
2351 && add_operand (GEN_INT (-n), DImode)
2352 && !(symbolic_operand (op0, VOIDmode)
2353 || (REG_P (op0) && REG_POINTER (op0))))
2355 /* TODO: Use a SIMD add immediate to hit zero for tiled
2356 constants in a single instruction. */
2357 if (GET_MODE (op0) != DImode)
2359 /* Convert to DImode so we can use addli. Note that
2360 this will not actually generate any code because
2361 sign extension from SI -> DI is a no-op. I don't
2362 know if it's safe just to make a paradoxical
2363 subreg here though. */
2364 rtx temp2 = gen_reg_rtx (DImode);
2365 emit_insn (gen_extendsidi2 (temp2, op0));
2370 op0 = force_reg (DImode, op0);
2372 temp = gen_reg_rtx (DImode);
2373 emit_move_insn (temp, gen_rtx_PLUS (DImode, op0, GEN_INT (-n)));
2374 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2375 VOIDmode, temp, const0_rtx);
2385 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2386 We use arithmetic shift right because it's a 3-wide op,
2387 while logical shift right is not. */
2389 int first = exact_log2 (code == LTU ? n : n + 1);
2392 op0 = force_reg (cmp_mode, op0);
2393 temp = gen_reg_rtx (cmp_mode);
2394 emit_move_insn (temp,
2395 gen_rtx_ASHIFTRT (cmp_mode, op0,
2397 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2398 VOIDmode, temp, const0_rtx);
2408 /* Compute a flag saying whether we should branch. */
2409 temp = gen_reg_rtx (DImode);
2410 tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2412 /* Return the branch comparison. */
2413 return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx);
2417 /* Generate the comparison for a conditional branch. */
2419 tilegx_emit_conditional_branch (rtx operands[], enum machine_mode cmp_mode)
2422 tilegx_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2],
2424 rtx branch_rtx = gen_rtx_SET (VOIDmode, pc_rtx,
2425 gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx,
2430 emit_jump_insn (branch_rtx);
2434 /* Implement the mov<mode>cc pattern. */
2436 tilegx_emit_conditional_move (rtx cmp)
2439 tilegx_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1),
2440 GET_MODE (XEXP (cmp, 0)), true);
2444 /* Return true if INSN is annotated with a REG_BR_PROB note that
2445 indicates it's a branch that's predicted taken. */
2447 cbranch_predicted_p (rtx insn)
2449 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2453 int pred_val = INTVAL (XEXP (x, 0));
2455 return pred_val >= REG_BR_PROB_BASE / 2;
2462 /* Output assembly code for a specific branch instruction, appending
2463 the branch prediction flag to the opcode if appropriate. */
2465 tilegx_output_simple_cbranch_with_opcode (rtx insn, const char *opcode,
2466 int regop, bool reverse_predicted)
2468 static char buf[64];
2469 sprintf (buf, "%s%s\t%%r%d, %%l0", opcode,
2470 (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "",
2476 /* Output assembly code for a specific branch instruction, appending
2477 the branch prediction flag to the opcode if appropriate. */
2479 tilegx_output_cbranch_with_opcode (rtx insn, rtx *operands,
2481 const char *rev_opcode, int regop)
2483 const char *branch_if_false;
2484 rtx taken, not_taken;
2485 bool is_simple_branch;
2487 gcc_assert (LABEL_P (operands[0]));
2489 is_simple_branch = true;
2490 if (INSN_ADDRESSES_SET_P ())
2492 int from_addr = INSN_ADDRESSES (INSN_UID (insn));
2493 int to_addr = INSN_ADDRESSES (INSN_UID (operands[0]));
2494 int delta = to_addr - from_addr;
2495 is_simple_branch = IN_RANGE (delta, -524288, 524280);
2498 if (is_simple_branch)
2500 /* Just a simple conditional branch. */
2502 tilegx_output_simple_cbranch_with_opcode (insn, opcode, regop, false);
2505 /* Generate a reversed branch around a direct jump. This fallback
2506 does not use branch-likely instructions. */
2507 not_taken = gen_label_rtx ();
2508 taken = operands[0];
2510 /* Generate the reversed branch to NOT_TAKEN. */
2511 operands[0] = not_taken;
2513 tilegx_output_simple_cbranch_with_opcode (insn, rev_opcode, regop, true);
2514 output_asm_insn (branch_if_false, operands);
2516 output_asm_insn ("j\t%l0", &taken);
2518 /* Output NOT_TAKEN. */
2519 targetm.asm_out.internal_label (asm_out_file, "L",
2520 CODE_LABEL_NUMBER (not_taken));
2525 /* Output assembly code for a conditional branch instruction. */
2527 tilegx_output_cbranch (rtx insn, rtx *operands, bool reversed)
2529 enum rtx_code code = GET_CODE (operands[1]);
2531 const char *rev_opcode;
2534 code = reverse_condition (code);
2540 rev_opcode = "beqz";
2544 rev_opcode = "bnez";
2548 rev_opcode = "bltz";
2552 rev_opcode = "blez";
2556 rev_opcode = "bgtz";
2560 rev_opcode = "bgez";
2566 return tilegx_output_cbranch_with_opcode (insn, operands, opcode,
2571 /* Implement the tablejump pattern. */
2573 tilegx_expand_tablejump (rtx op0, rtx op1)
2577 rtx temp = gen_reg_rtx (Pmode);
2578 rtx temp2 = gen_reg_rtx (Pmode);
2580 compute_pcrel_address (temp, gen_rtx_LABEL_REF (Pmode, op1));
2581 emit_move_insn (temp2,
2582 gen_rtx_PLUS (Pmode,
2583 convert_to_mode (Pmode, op0, false),
2588 emit_jump_insn (gen_tablejump_aux (op0, op1));
2592 /* Emit barrier before an atomic, as needed for the memory MODEL. */
2594 tilegx_pre_atomic_barrier (enum memmodel model)
2598 case MEMMODEL_RELAXED:
2599 case MEMMODEL_CONSUME:
2600 case MEMMODEL_ACQUIRE:
2602 case MEMMODEL_RELEASE:
2603 case MEMMODEL_ACQ_REL:
2604 case MEMMODEL_SEQ_CST:
2605 emit_insn (gen_memory_barrier ());
2613 /* Emit barrier after an atomic, as needed for the memory MODEL. */
2615 tilegx_post_atomic_barrier (enum memmodel model)
2619 case MEMMODEL_RELAXED:
2620 case MEMMODEL_CONSUME:
2621 case MEMMODEL_RELEASE:
2623 case MEMMODEL_ACQUIRE:
2624 case MEMMODEL_ACQ_REL:
2625 case MEMMODEL_SEQ_CST:
2626 emit_insn (gen_memory_barrier ());
2635 /* Expand a builtin vector binary op, by calling gen function GEN with
2636 operands in the proper modes. DEST is converted to DEST_MODE, and
2637 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2639 tilegx_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx),
2640 enum machine_mode dest_mode,
2642 enum machine_mode src_mode,
2643 rtx src0, rtx src1, bool do_src1)
2645 dest = gen_lowpart (dest_mode, dest);
2647 if (src0 == const0_rtx)
2648 src0 = CONST0_RTX (src_mode);
2650 src0 = gen_lowpart (src_mode, src0);
2654 if (src1 == const0_rtx)
2655 src1 = CONST0_RTX (src_mode);
2657 src1 = gen_lowpart (src_mode, src1);
2660 emit_insn ((*gen) (dest, src0, src1));
2668 struct tile_builtin_info
2670 enum insn_code icode;
2674 static struct tile_builtin_info tilegx_builtin_info[TILEGX_BUILTIN_max] = {
2675 { CODE_FOR_adddi3, NULL }, /* add */
2676 { CODE_FOR_addsi3, NULL }, /* addx */
2677 { CODE_FOR_ssaddsi3, NULL }, /* addxsc */
2678 { CODE_FOR_anddi3, NULL }, /* and */
2679 { CODE_FOR_insn_bfexts, NULL }, /* bfexts */
2680 { CODE_FOR_insn_bfextu, NULL }, /* bfextu */
2681 { CODE_FOR_insn_bfins, NULL }, /* bfins */
2682 { CODE_FOR_clzdi2, NULL }, /* clz */
2683 { CODE_FOR_insn_cmoveqz, NULL }, /* cmoveqz */
2684 { CODE_FOR_insn_cmovnez, NULL }, /* cmovnez */
2685 { CODE_FOR_insn_cmpeq_didi, NULL }, /* cmpeq */
2686 { CODE_FOR_insn_cmpexch, NULL }, /* cmpexch */
2687 { CODE_FOR_insn_cmpexch4, NULL }, /* cmpexch4 */
2688 { CODE_FOR_insn_cmples_didi, NULL }, /* cmples */
2689 { CODE_FOR_insn_cmpleu_didi, NULL }, /* cmpleu */
2690 { CODE_FOR_insn_cmplts_didi, NULL }, /* cmplts */
2691 { CODE_FOR_insn_cmpltu_didi, NULL }, /* cmpltu */
2692 { CODE_FOR_insn_cmpne_didi, NULL }, /* cmpne */
2693 { CODE_FOR_insn_cmul, NULL }, /* cmul */
2694 { CODE_FOR_insn_cmula, NULL }, /* cmula */
2695 { CODE_FOR_insn_cmulaf, NULL }, /* cmulaf */
2696 { CODE_FOR_insn_cmulf, NULL }, /* cmulf */
2697 { CODE_FOR_insn_cmulfr, NULL }, /* cmulfr */
2698 { CODE_FOR_insn_cmulh, NULL }, /* cmulh */
2699 { CODE_FOR_insn_cmulhr, NULL }, /* cmulhr */
2700 { CODE_FOR_insn_crc32_32, NULL }, /* crc32_32 */
2701 { CODE_FOR_insn_crc32_8, NULL }, /* crc32_8 */
2702 { CODE_FOR_ctzdi2, NULL }, /* ctz */
2703 { CODE_FOR_insn_dblalign, NULL }, /* dblalign */
2704 { CODE_FOR_insn_dblalign2, NULL }, /* dblalign2 */
2705 { CODE_FOR_insn_dblalign4, NULL }, /* dblalign4 */
2706 { CODE_FOR_insn_dblalign6, NULL }, /* dblalign6 */
2707 { CODE_FOR_insn_drain, NULL }, /* drain */
2708 { CODE_FOR_insn_dtlbpr, NULL }, /* dtlbpr */
2709 { CODE_FOR_insn_exch, NULL }, /* exch */
2710 { CODE_FOR_insn_exch4, NULL }, /* exch4 */
2711 { CODE_FOR_insn_fdouble_add_flags, NULL }, /* fdouble_add_flags */
2712 { CODE_FOR_insn_fdouble_addsub, NULL }, /* fdouble_addsub */
2713 { CODE_FOR_insn_fdouble_mul_flags, NULL }, /* fdouble_mul_flags */
2714 { CODE_FOR_insn_fdouble_pack1, NULL }, /* fdouble_pack1 */
2715 { CODE_FOR_insn_fdouble_pack2, NULL }, /* fdouble_pack2 */
2716 { CODE_FOR_insn_fdouble_sub_flags, NULL }, /* fdouble_sub_flags */
2717 { CODE_FOR_insn_fdouble_unpack_max, NULL }, /* fdouble_unpack_max */
2718 { CODE_FOR_insn_fdouble_unpack_min, NULL }, /* fdouble_unpack_min */
2719 { CODE_FOR_insn_fetchadd, NULL }, /* fetchadd */
2720 { CODE_FOR_insn_fetchadd4, NULL }, /* fetchadd4 */
2721 { CODE_FOR_insn_fetchaddgez, NULL }, /* fetchaddgez */
2722 { CODE_FOR_insn_fetchaddgez4, NULL }, /* fetchaddgez4 */
2723 { CODE_FOR_insn_fetchand, NULL }, /* fetchand */
2724 { CODE_FOR_insn_fetchand4, NULL }, /* fetchand4 */
2725 { CODE_FOR_insn_fetchor, NULL }, /* fetchor */
2726 { CODE_FOR_insn_fetchor4, NULL }, /* fetchor4 */
2727 { CODE_FOR_insn_finv, NULL }, /* finv */
2728 { CODE_FOR_insn_flush, NULL }, /* flush */
2729 { CODE_FOR_insn_flushwb, NULL }, /* flushwb */
2730 { CODE_FOR_insn_fnop, NULL }, /* fnop */
2731 { CODE_FOR_insn_fsingle_add1, NULL }, /* fsingle_add1 */
2732 { CODE_FOR_insn_fsingle_addsub2, NULL }, /* fsingle_addsub2 */
2733 { CODE_FOR_insn_fsingle_mul1, NULL }, /* fsingle_mul1 */
2734 { CODE_FOR_insn_fsingle_mul2, NULL }, /* fsingle_mul2 */
2735 { CODE_FOR_insn_fsingle_pack1, NULL }, /* fsingle_pack1 */
2736 { CODE_FOR_insn_fsingle_pack2, NULL }, /* fsingle_pack2 */
2737 { CODE_FOR_insn_fsingle_sub1, NULL }, /* fsingle_sub1 */
2738 { CODE_FOR_insn_icoh, NULL }, /* icoh */
2739 { CODE_FOR_insn_ill, NULL }, /* ill */
2740 { CODE_FOR_insn_info, NULL }, /* info */
2741 { CODE_FOR_insn_infol, NULL }, /* infol */
2742 { CODE_FOR_insn_inv, NULL }, /* inv */
2743 { CODE_FOR_insn_ld, NULL }, /* ld */
2744 { CODE_FOR_insn_ld1s, NULL }, /* ld1s */
2745 { CODE_FOR_insn_ld1u, NULL }, /* ld1u */
2746 { CODE_FOR_insn_ld2s, NULL }, /* ld2s */
2747 { CODE_FOR_insn_ld2u, NULL }, /* ld2u */
2748 { CODE_FOR_insn_ld4s, NULL }, /* ld4s */
2749 { CODE_FOR_insn_ld4u, NULL }, /* ld4u */
2750 { CODE_FOR_insn_ldna, NULL }, /* ldna */
2751 { CODE_FOR_insn_ldnt, NULL }, /* ldnt */
2752 { CODE_FOR_insn_ldnt1s, NULL }, /* ldnt1s */
2753 { CODE_FOR_insn_ldnt1u, NULL }, /* ldnt1u */
2754 { CODE_FOR_insn_ldnt2s, NULL }, /* ldnt2s */
2755 { CODE_FOR_insn_ldnt2u, NULL }, /* ldnt2u */
2756 { CODE_FOR_insn_ldnt4s, NULL }, /* ldnt4s */
2757 { CODE_FOR_insn_ldnt4u, NULL }, /* ldnt4u */
2758 { CODE_FOR_insn_ld_L2, NULL }, /* ld_L2 */
2759 { CODE_FOR_insn_ld1s_L2, NULL }, /* ld1s_L2 */
2760 { CODE_FOR_insn_ld1u_L2, NULL }, /* ld1u_L2 */
2761 { CODE_FOR_insn_ld2s_L2, NULL }, /* ld2s_L2 */
2762 { CODE_FOR_insn_ld2u_L2, NULL }, /* ld2u_L2 */
2763 { CODE_FOR_insn_ld4s_L2, NULL }, /* ld4s_L2 */
2764 { CODE_FOR_insn_ld4u_L2, NULL }, /* ld4u_L2 */
2765 { CODE_FOR_insn_ldna_L2, NULL }, /* ldna_L2 */
2766 { CODE_FOR_insn_ldnt_L2, NULL }, /* ldnt_L2 */
2767 { CODE_FOR_insn_ldnt1s_L2, NULL }, /* ldnt1s_L2 */
2768 { CODE_FOR_insn_ldnt1u_L2, NULL }, /* ldnt1u_L2 */
2769 { CODE_FOR_insn_ldnt2s_L2, NULL }, /* ldnt2s_L2 */
2770 { CODE_FOR_insn_ldnt2u_L2, NULL }, /* ldnt2u_L2 */
2771 { CODE_FOR_insn_ldnt4s_L2, NULL }, /* ldnt4s_L2 */
2772 { CODE_FOR_insn_ldnt4u_L2, NULL }, /* ldnt4u_L2 */
2773 { CODE_FOR_insn_ld_miss, NULL }, /* ld_miss */
2774 { CODE_FOR_insn_ld1s_miss, NULL }, /* ld1s_miss */
2775 { CODE_FOR_insn_ld1u_miss, NULL }, /* ld1u_miss */
2776 { CODE_FOR_insn_ld2s_miss, NULL }, /* ld2s_miss */
2777 { CODE_FOR_insn_ld2u_miss, NULL }, /* ld2u_miss */
2778 { CODE_FOR_insn_ld4s_miss, NULL }, /* ld4s_miss */
2779 { CODE_FOR_insn_ld4u_miss, NULL }, /* ld4u_miss */
2780 { CODE_FOR_insn_ldna_miss, NULL }, /* ldna_miss */
2781 { CODE_FOR_insn_ldnt_miss, NULL }, /* ldnt_miss */
2782 { CODE_FOR_insn_ldnt1s_miss, NULL }, /* ldnt1s_miss */
2783 { CODE_FOR_insn_ldnt1u_miss, NULL }, /* ldnt1u_miss */
2784 { CODE_FOR_insn_ldnt2s_miss, NULL }, /* ldnt2s_miss */
2785 { CODE_FOR_insn_ldnt2u_miss, NULL }, /* ldnt2u_miss */
2786 { CODE_FOR_insn_ldnt4s_miss, NULL }, /* ldnt4s_miss */
2787 { CODE_FOR_insn_ldnt4u_miss, NULL }, /* ldnt4u_miss */
2788 { CODE_FOR_insn_lnk, NULL }, /* lnk */
2789 { CODE_FOR_memory_barrier, NULL }, /* mf */
2790 { CODE_FOR_insn_mfspr, NULL }, /* mfspr */
2791 { CODE_FOR_insn_mm, NULL }, /* mm */
2792 { CODE_FOR_insn_mnz, NULL }, /* mnz */
2793 { CODE_FOR_movdi, NULL }, /* move */
2794 { CODE_FOR_insn_mtspr, NULL }, /* mtspr */
2795 { CODE_FOR_insn_mul_hs_hs, NULL }, /* mul_hs_hs */
2796 { CODE_FOR_insn_mul_hs_hu, NULL }, /* mul_hs_hu */
2797 { CODE_FOR_insn_mul_hs_ls, NULL }, /* mul_hs_ls */
2798 { CODE_FOR_insn_mul_hs_lu, NULL }, /* mul_hs_lu */
2799 { CODE_FOR_insn_mul_hu_hu, NULL }, /* mul_hu_hu */
2800 { CODE_FOR_insn_mul_hu_ls, NULL }, /* mul_hu_ls */
2801 { CODE_FOR_insn_mul_hu_lu, NULL }, /* mul_hu_lu */
2802 { CODE_FOR_insn_mul_ls_ls, NULL }, /* mul_ls_ls */
2803 { CODE_FOR_insn_mul_ls_lu, NULL }, /* mul_ls_lu */
2804 { CODE_FOR_insn_mul_lu_lu, NULL }, /* mul_lu_lu */
2805 { CODE_FOR_insn_mula_hs_hs, NULL }, /* mula_hs_hs */
2806 { CODE_FOR_insn_mula_hs_hu, NULL }, /* mula_hs_hu */
2807 { CODE_FOR_insn_mula_hs_ls, NULL }, /* mula_hs_ls */
2808 { CODE_FOR_insn_mula_hs_lu, NULL }, /* mula_hs_lu */
2809 { CODE_FOR_insn_mula_hu_hu, NULL }, /* mula_hu_hu */
2810 { CODE_FOR_insn_mula_hu_ls, NULL }, /* mula_hu_ls */
2811 { CODE_FOR_insn_mula_hu_lu, NULL }, /* mula_hu_lu */
2812 { CODE_FOR_insn_mula_ls_ls, NULL }, /* mula_ls_ls */
2813 { CODE_FOR_insn_mula_ls_lu, NULL }, /* mula_ls_lu */
2814 { CODE_FOR_insn_mula_lu_lu, NULL }, /* mula_lu_lu */
2815 { CODE_FOR_insn_mulax, NULL }, /* mulax */
2816 { CODE_FOR_mulsi3, NULL }, /* mulx */
2817 { CODE_FOR_insn_mz, NULL }, /* mz */
2818 { CODE_FOR_insn_nap, NULL }, /* nap */
2819 { CODE_FOR_nop, NULL }, /* nop */
2820 { CODE_FOR_insn_nor_di, NULL }, /* nor */
2821 { CODE_FOR_iordi3, NULL }, /* or */
2822 { CODE_FOR_popcountdi2, NULL }, /* pcnt */
2823 { CODE_FOR_insn_prefetch_l1, NULL }, /* prefetch_l1 */
2824 { CODE_FOR_insn_prefetch_l1_fault, NULL }, /* prefetch_l1_fault */
2825 { CODE_FOR_insn_prefetch_l2, NULL }, /* prefetch_l2 */
2826 { CODE_FOR_insn_prefetch_l2_fault, NULL }, /* prefetch_l2_fault */
2827 { CODE_FOR_insn_prefetch_l3, NULL }, /* prefetch_l3 */
2828 { CODE_FOR_insn_prefetch_l3_fault, NULL }, /* prefetch_l3_fault */
2829 { CODE_FOR_insn_revbits, NULL }, /* revbits */
2830 { CODE_FOR_bswapdi2, NULL }, /* revbytes */
2831 { CODE_FOR_rotldi3, NULL }, /* rotl */
2832 { CODE_FOR_ashldi3, NULL }, /* shl */
2833 { CODE_FOR_insn_shl16insli, NULL }, /* shl16insli */
2834 { CODE_FOR_insn_shl1add, NULL }, /* shl1add */
2835 { CODE_FOR_insn_shl1addx, NULL }, /* shl1addx */
2836 { CODE_FOR_insn_shl2add, NULL }, /* shl2add */
2837 { CODE_FOR_insn_shl2addx, NULL }, /* shl2addx */
2838 { CODE_FOR_insn_shl3add, NULL }, /* shl3add */
2839 { CODE_FOR_insn_shl3addx, NULL }, /* shl3addx */
2840 { CODE_FOR_ashlsi3, NULL }, /* shlx */
2841 { CODE_FOR_ashrdi3, NULL }, /* shrs */
2842 { CODE_FOR_lshrdi3, NULL }, /* shru */
2843 { CODE_FOR_lshrsi3, NULL }, /* shrux */
2844 { CODE_FOR_insn_shufflebytes, NULL }, /* shufflebytes */
2845 { CODE_FOR_insn_st, NULL }, /* st */
2846 { CODE_FOR_insn_st1, NULL }, /* st1 */
2847 { CODE_FOR_insn_st2, NULL }, /* st2 */
2848 { CODE_FOR_insn_st4, NULL }, /* st4 */
2849 { CODE_FOR_insn_stnt, NULL }, /* stnt */
2850 { CODE_FOR_insn_stnt1, NULL }, /* stnt1 */
2851 { CODE_FOR_insn_stnt2, NULL }, /* stnt2 */
2852 { CODE_FOR_insn_stnt4, NULL }, /* stnt4 */
2853 { CODE_FOR_subdi3, NULL }, /* sub */
2854 { CODE_FOR_subsi3, NULL }, /* subx */
2855 { CODE_FOR_sssubsi3, NULL }, /* subxsc */
2856 { CODE_FOR_insn_tblidxb0, NULL }, /* tblidxb0 */
2857 { CODE_FOR_insn_tblidxb1, NULL }, /* tblidxb1 */
2858 { CODE_FOR_insn_tblidxb2, NULL }, /* tblidxb2 */
2859 { CODE_FOR_insn_tblidxb3, NULL }, /* tblidxb3 */
2860 { CODE_FOR_insn_v1add, NULL }, /* v1add */
2861 { CODE_FOR_insn_v1addi, NULL }, /* v1addi */
2862 { CODE_FOR_insn_v1adduc, NULL }, /* v1adduc */
2863 { CODE_FOR_insn_v1adiffu, NULL }, /* v1adiffu */
2864 { CODE_FOR_insn_v1avgu, NULL }, /* v1avgu */
2865 { CODE_FOR_insn_v1cmpeq, NULL }, /* v1cmpeq */
2866 { CODE_FOR_insn_v1cmpeqi, NULL }, /* v1cmpeqi */
2867 { CODE_FOR_insn_v1cmples, NULL }, /* v1cmples */
2868 { CODE_FOR_insn_v1cmpleu, NULL }, /* v1cmpleu */
2869 { CODE_FOR_insn_v1cmplts, NULL }, /* v1cmplts */
2870 { CODE_FOR_insn_v1cmpltsi, NULL }, /* v1cmpltsi */
2871 { CODE_FOR_insn_v1cmpltu, NULL }, /* v1cmpltu */
2872 { CODE_FOR_insn_v1cmpltui, NULL }, /* v1cmpltui */
2873 { CODE_FOR_insn_v1cmpne, NULL }, /* v1cmpne */
2874 { CODE_FOR_insn_v1ddotpu, NULL }, /* v1ddotpu */
2875 { CODE_FOR_insn_v1ddotpua, NULL }, /* v1ddotpua */
2876 { CODE_FOR_insn_v1ddotpus, NULL }, /* v1ddotpus */
2877 { CODE_FOR_insn_v1ddotpusa, NULL }, /* v1ddotpusa */
2878 { CODE_FOR_insn_v1dotp, NULL }, /* v1dotp */
2879 { CODE_FOR_insn_v1dotpa, NULL }, /* v1dotpa */
2880 { CODE_FOR_insn_v1dotpu, NULL }, /* v1dotpu */
2881 { CODE_FOR_insn_v1dotpua, NULL }, /* v1dotpua */
2882 { CODE_FOR_insn_v1dotpus, NULL }, /* v1dotpus */
2883 { CODE_FOR_insn_v1dotpusa, NULL }, /* v1dotpusa */
2884 { CODE_FOR_insn_v1int_h, NULL }, /* v1int_h */
2885 { CODE_FOR_insn_v1int_l, NULL }, /* v1int_l */
2886 { CODE_FOR_insn_v1maxu, NULL }, /* v1maxu */
2887 { CODE_FOR_insn_v1maxui, NULL }, /* v1maxui */
2888 { CODE_FOR_insn_v1minu, NULL }, /* v1minu */
2889 { CODE_FOR_insn_v1minui, NULL }, /* v1minui */
2890 { CODE_FOR_insn_v1mnz, NULL }, /* v1mnz */
2891 { CODE_FOR_insn_v1multu, NULL }, /* v1multu */
2892 { CODE_FOR_insn_v1mulu, NULL }, /* v1mulu */
2893 { CODE_FOR_insn_v1mulus, NULL }, /* v1mulus */
2894 { CODE_FOR_insn_v1mz, NULL }, /* v1mz */
2895 { CODE_FOR_insn_v1sadau, NULL }, /* v1sadau */
2896 { CODE_FOR_insn_v1sadu, NULL }, /* v1sadu */
2897 { CODE_FOR_insn_v1shl, NULL }, /* v1shl */
2898 { CODE_FOR_insn_v1shl, NULL }, /* v1shli */
2899 { CODE_FOR_insn_v1shrs, NULL }, /* v1shrs */
2900 { CODE_FOR_insn_v1shrs, NULL }, /* v1shrsi */
2901 { CODE_FOR_insn_v1shru, NULL }, /* v1shru */
2902 { CODE_FOR_insn_v1shru, NULL }, /* v1shrui */
2903 { CODE_FOR_insn_v1sub, NULL }, /* v1sub */
2904 { CODE_FOR_insn_v1subuc, NULL }, /* v1subuc */
2905 { CODE_FOR_insn_v2add, NULL }, /* v2add */
2906 { CODE_FOR_insn_v2addi, NULL }, /* v2addi */
2907 { CODE_FOR_insn_v2addsc, NULL }, /* v2addsc */
2908 { CODE_FOR_insn_v2adiffs, NULL }, /* v2adiffs */
2909 { CODE_FOR_insn_v2avgs, NULL }, /* v2avgs */
2910 { CODE_FOR_insn_v2cmpeq, NULL }, /* v2cmpeq */
2911 { CODE_FOR_insn_v2cmpeqi, NULL }, /* v2cmpeqi */
2912 { CODE_FOR_insn_v2cmples, NULL }, /* v2cmples */
2913 { CODE_FOR_insn_v2cmpleu, NULL }, /* v2cmpleu */
2914 { CODE_FOR_insn_v2cmplts, NULL }, /* v2cmplts */
2915 { CODE_FOR_insn_v2cmpltsi, NULL }, /* v2cmpltsi */
2916 { CODE_FOR_insn_v2cmpltu, NULL }, /* v2cmpltu */
2917 { CODE_FOR_insn_v2cmpltui, NULL }, /* v2cmpltui */
2918 { CODE_FOR_insn_v2cmpne, NULL }, /* v2cmpne */
2919 { CODE_FOR_insn_v2dotp, NULL }, /* v2dotp */
2920 { CODE_FOR_insn_v2dotpa, NULL }, /* v2dotpa */
2921 { CODE_FOR_insn_v2int_h, NULL }, /* v2int_h */
2922 { CODE_FOR_insn_v2int_l, NULL }, /* v2int_l */
2923 { CODE_FOR_insn_v2maxs, NULL }, /* v2maxs */
2924 { CODE_FOR_insn_v2maxsi, NULL }, /* v2maxsi */
2925 { CODE_FOR_insn_v2mins, NULL }, /* v2mins */
2926 { CODE_FOR_insn_v2minsi, NULL }, /* v2minsi */
2927 { CODE_FOR_insn_v2mnz, NULL }, /* v2mnz */
2928 { CODE_FOR_insn_v2mulfsc, NULL }, /* v2mulfsc */
2929 { CODE_FOR_insn_v2muls, NULL }, /* v2muls */
2930 { CODE_FOR_insn_v2mults, NULL }, /* v2mults */
2931 { CODE_FOR_insn_v2mz, NULL }, /* v2mz */
2932 { CODE_FOR_insn_v2packh, NULL }, /* v2packh */
2933 { CODE_FOR_insn_v2packl, NULL }, /* v2packl */
2934 { CODE_FOR_insn_v2packuc, NULL }, /* v2packuc */
2935 { CODE_FOR_insn_v2sadas, NULL }, /* v2sadas */
2936 { CODE_FOR_insn_v2sadau, NULL }, /* v2sadau */
2937 { CODE_FOR_insn_v2sads, NULL }, /* v2sads */
2938 { CODE_FOR_insn_v2sadu, NULL }, /* v2sadu */
2939 { CODE_FOR_insn_v2shl, NULL }, /* v2shl */
2940 { CODE_FOR_insn_v2shl, NULL }, /* v2shli */
2941 { CODE_FOR_insn_v2shlsc, NULL }, /* v2shlsc */
2942 { CODE_FOR_insn_v2shrs, NULL }, /* v2shrs */
2943 { CODE_FOR_insn_v2shrs, NULL }, /* v2shrsi */
2944 { CODE_FOR_insn_v2shru, NULL }, /* v2shru */
2945 { CODE_FOR_insn_v2shru, NULL }, /* v2shrui */
2946 { CODE_FOR_insn_v2sub, NULL }, /* v2sub */
2947 { CODE_FOR_insn_v2subsc, NULL }, /* v2subsc */
2948 { CODE_FOR_insn_v4add, NULL }, /* v4add */
2949 { CODE_FOR_insn_v4addsc, NULL }, /* v4addsc */
2950 { CODE_FOR_insn_v4int_h, NULL }, /* v4int_h */
2951 { CODE_FOR_insn_v4int_l, NULL }, /* v4int_l */
2952 { CODE_FOR_insn_v4packsc, NULL }, /* v4packsc */
2953 { CODE_FOR_insn_v4shl, NULL }, /* v4shl */
2954 { CODE_FOR_insn_v4shlsc, NULL }, /* v4shlsc */
2955 { CODE_FOR_insn_v4shrs, NULL }, /* v4shrs */
2956 { CODE_FOR_insn_v4shru, NULL }, /* v4shru */
2957 { CODE_FOR_insn_v4sub, NULL }, /* v4sub */
2958 { CODE_FOR_insn_v4subsc, NULL }, /* v4subsc */
2959 { CODE_FOR_insn_wh64, NULL }, /* wh64 */
2960 { CODE_FOR_xordi3, NULL }, /* xor */
2961 { CODE_FOR_tilegx_network_barrier, NULL }, /* network_barrier */
2962 { CODE_FOR_tilegx_idn0_receive, NULL }, /* idn0_receive */
2963 { CODE_FOR_tilegx_idn1_receive, NULL }, /* idn1_receive */
2964 { CODE_FOR_tilegx_idn_send, NULL }, /* idn_send */
2965 { CODE_FOR_tilegx_udn0_receive, NULL }, /* udn0_receive */
2966 { CODE_FOR_tilegx_udn1_receive, NULL }, /* udn1_receive */
2967 { CODE_FOR_tilegx_udn2_receive, NULL }, /* udn2_receive */
2968 { CODE_FOR_tilegx_udn3_receive, NULL }, /* udn3_receive */
2969 { CODE_FOR_tilegx_udn_send, NULL }, /* udn_send */
2973 struct tilegx_builtin_def
2976 enum tilegx_builtin code;
2978 /* The first character is the return type. Subsequent characters
2979 are the argument types. See char_to_type. */
2984 static const struct tilegx_builtin_def tilegx_builtins[] = {
2985 { "__insn_add", TILEGX_INSN_ADD, true, "lll" },
2986 { "__insn_addi", TILEGX_INSN_ADD, true, "lll" },
2987 { "__insn_addli", TILEGX_INSN_ADD, true, "lll" },
2988 { "__insn_addx", TILEGX_INSN_ADDX, true, "iii" },
2989 { "__insn_addxi", TILEGX_INSN_ADDX, true, "iii" },
2990 { "__insn_addxli", TILEGX_INSN_ADDX, true, "iii" },
2991 { "__insn_addxsc", TILEGX_INSN_ADDXSC, true, "iii" },
2992 { "__insn_and", TILEGX_INSN_AND, true, "lll" },
2993 { "__insn_andi", TILEGX_INSN_AND, true, "lll" },
2994 { "__insn_bfexts", TILEGX_INSN_BFEXTS, true, "llll" },
2995 { "__insn_bfextu", TILEGX_INSN_BFEXTU, true, "llll" },
2996 { "__insn_bfins", TILEGX_INSN_BFINS, true, "lllll"},
2997 { "__insn_clz", TILEGX_INSN_CLZ, true, "ll" },
2998 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ, true, "llll" },
2999 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ, true, "llll" },
3000 { "__insn_cmpeq", TILEGX_INSN_CMPEQ, true, "lll" },
3001 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ, true, "lll" },
3002 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH, false, "lpl" },
3003 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4, false, "ipi" },
3004 { "__insn_cmples", TILEGX_INSN_CMPLES, true, "lll" },
3005 { "__insn_cmpleu", TILEGX_INSN_CMPLEU, true, "lll" },
3006 { "__insn_cmplts", TILEGX_INSN_CMPLTS, true, "lll" },
3007 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS, true, "lll" },
3008 { "__insn_cmpltu", TILEGX_INSN_CMPLTU, true, "lll" },
3009 { "__insn_cmpltui", TILEGX_INSN_CMPLTU, true, "lll" },
3010 { "__insn_cmpne", TILEGX_INSN_CMPNE, true, "lll" },
3011 { "__insn_cmul", TILEGX_INSN_CMUL, true, "lll" },
3012 { "__insn_cmula", TILEGX_INSN_CMULA, true, "llll" },
3013 { "__insn_cmulaf", TILEGX_INSN_CMULAF, true, "llll" },
3014 { "__insn_cmulf", TILEGX_INSN_CMULF, true, "lll" },
3015 { "__insn_cmulfr", TILEGX_INSN_CMULFR, true, "lll" },
3016 { "__insn_cmulh", TILEGX_INSN_CMULH, true, "lll" },
3017 { "__insn_cmulhr", TILEGX_INSN_CMULHR, true, "lll" },
3018 { "__insn_crc32_32", TILEGX_INSN_CRC32_32, true, "lll" },
3019 { "__insn_crc32_8", TILEGX_INSN_CRC32_8, true, "lll" },
3020 { "__insn_ctz", TILEGX_INSN_CTZ, true, "ll" },
3021 { "__insn_dblalign", TILEGX_INSN_DBLALIGN, true, "lllk" },
3022 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2, true, "lll" },
3023 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4, true, "lll" },
3024 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6, true, "lll" },
3025 { "__insn_drain", TILEGX_INSN_DRAIN, false, "v" },
3026 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR, false, "vl" },
3027 { "__insn_exch", TILEGX_INSN_EXCH, false, "lpl" },
3028 { "__insn_exch4", TILEGX_INSN_EXCH4, false, "ipi" },
3029 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS, true, "lll" },
3030 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB, true, "llll" },
3031 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS, true, "lll" },
3032 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1, true, "lll" },
3033 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2, true, "llll" },
3034 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS, true, "lll" },
3035 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX, true, "lll" },
3036 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN, true, "lll" },
3037 { "__insn_fetchadd", TILEGX_INSN_FETCHADD, false, "lpl" },
3038 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4, false, "ipi" },
3039 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ, false, "lpl" },
3040 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4, false, "ipi" },
3041 { "__insn_fetchand", TILEGX_INSN_FETCHAND, false, "lpl" },
3042 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4, false, "ipi" },
3043 { "__insn_fetchor", TILEGX_INSN_FETCHOR, false, "lpl" },
3044 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4, false, "ipi" },
3045 { "__insn_finv", TILEGX_INSN_FINV, false, "vk" },
3046 { "__insn_flush", TILEGX_INSN_FLUSH, false, "vk" },
3047 { "__insn_flushwb", TILEGX_INSN_FLUSHWB, false, "v" },
3048 { "__insn_fnop", TILEGX_INSN_FNOP, false, "v" },
3049 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1, true, "lll" },
3050 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2, true, "llll" },
3051 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1, true, "lll" },
3052 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2, true, "lll" },
3053 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1, true, "ll" },
3054 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2, true, "lll" },
3055 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1, true, "lll" },
3056 { "__insn_icoh", TILEGX_INSN_ICOH, false, "vk" },
3057 { "__insn_ill", TILEGX_INSN_ILL, false, "v" },
3058 { "__insn_info", TILEGX_INSN_INFO, false, "vl" },
3059 { "__insn_infol", TILEGX_INSN_INFOL, false, "vl" },
3060 { "__insn_inv", TILEGX_INSN_INV, false, "vp" },
3061 { "__insn_ld", TILEGX_INSN_LD, false, "lk" },
3062 { "__insn_ld1s", TILEGX_INSN_LD1S, false, "lk" },
3063 { "__insn_ld1u", TILEGX_INSN_LD1U, false, "lk" },
3064 { "__insn_ld2s", TILEGX_INSN_LD2S, false, "lk" },
3065 { "__insn_ld2u", TILEGX_INSN_LD2U, false, "lk" },
3066 { "__insn_ld4s", TILEGX_INSN_LD4S, false, "lk" },
3067 { "__insn_ld4u", TILEGX_INSN_LD4U, false, "lk" },
3068 { "__insn_ldna", TILEGX_INSN_LDNA, false, "lk" },
3069 { "__insn_ldnt", TILEGX_INSN_LDNT, false, "lk" },
3070 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S, false, "lk" },
3071 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U, false, "lk" },
3072 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S, false, "lk" },
3073 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U, false, "lk" },
3074 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S, false, "lk" },
3075 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U, false, "lk" },
3076 { "__insn_ld_L2", TILEGX_INSN_LD_L2, false, "lk" },
3077 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2, false, "lk" },
3078 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2, false, "lk" },
3079 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2, false, "lk" },
3080 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2, false, "lk" },
3081 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2, false, "lk" },
3082 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2, false, "lk" },
3083 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2, false, "lk" },
3084 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2, false, "lk" },
3085 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2, false, "lk" },
3086 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2, false, "lk" },
3087 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2, false, "lk" },
3088 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2, false, "lk" },
3089 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2, false, "lk" },
3090 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2, false, "lk" },
3091 { "__insn_ld_miss", TILEGX_INSN_LD_MISS, false, "lk" },
3092 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS, false, "lk" },
3093 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS, false, "lk" },
3094 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS, false, "lk" },
3095 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS, false, "lk" },
3096 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS, false, "lk" },
3097 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS, false, "lk" },
3098 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS, false, "lk" },
3099 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS, false, "lk" },
3100 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS, false, "lk" },
3101 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS, false, "lk" },
3102 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS, false, "lk" },
3103 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS, false, "lk" },
3104 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS, false, "lk" },
3105 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS, false, "lk" },
3106 { "__insn_lnk", TILEGX_INSN_LNK, true, "l" },
3107 { "__insn_mf", TILEGX_INSN_MF, false, "v" },
3108 { "__insn_mfspr", TILEGX_INSN_MFSPR, false, "ll" },
3109 { "__insn_mm", TILEGX_INSN_MM, true, "lllll"},
3110 { "__insn_mnz", TILEGX_INSN_MNZ, true, "lll" },
3111 { "__insn_move", TILEGX_INSN_MOVE, true, "ll" },
3112 { "__insn_movei", TILEGX_INSN_MOVE, true, "ll" },
3113 { "__insn_moveli", TILEGX_INSN_MOVE, true, "ll" },
3114 { "__insn_mtspr", TILEGX_INSN_MTSPR, false, "vll" },
3115 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS, true, "lll" },
3116 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU, true, "lll" },
3117 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS, true, "lll" },
3118 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU, true, "lll" },
3119 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU, true, "lll" },
3120 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS, true, "lll" },
3121 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU, true, "lll" },
3122 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS, true, "lll" },
3123 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU, true, "lll" },
3124 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU, true, "lll" },
3125 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS, true, "llll" },
3126 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU, true, "llll" },
3127 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS, true, "llll" },
3128 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU, true, "llll" },
3129 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU, true, "llll" },
3130 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS, true, "llll" },
3131 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU, true, "llll" },
3132 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS, true, "llll" },
3133 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU, true, "llll" },
3134 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU, true, "llll" },
3135 { "__insn_mulax", TILEGX_INSN_MULAX, true, "iiii" },
3136 { "__insn_mulx", TILEGX_INSN_MULX, true, "iii" },
3137 { "__insn_mz", TILEGX_INSN_MZ, true, "lll" },
3138 { "__insn_nap", TILEGX_INSN_NAP, false, "v" },
3139 { "__insn_nop", TILEGX_INSN_NOP, true, "v" },
3140 { "__insn_nor", TILEGX_INSN_NOR, true, "lll" },
3141 { "__insn_or", TILEGX_INSN_OR, true, "lll" },
3142 { "__insn_ori", TILEGX_INSN_OR, true, "lll" },
3143 { "__insn_pcnt", TILEGX_INSN_PCNT, true, "ll" },
3144 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1, false, "vk" },
3145 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1, false, "vk" },
3146 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT, false, "vk" },
3147 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2, false, "vk" },
3148 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT, false, "vk" },
3149 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3, false, "vk" },
3150 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT, false, "vk" },
3151 { "__insn_revbits", TILEGX_INSN_REVBITS, true, "ll" },
3152 { "__insn_revbytes", TILEGX_INSN_REVBYTES, true, "ll" },
3153 { "__insn_rotl", TILEGX_INSN_ROTL, true, "lli" },
3154 { "__insn_rotli", TILEGX_INSN_ROTL, true, "lli" },
3155 { "__insn_shl", TILEGX_INSN_SHL, true, "lli" },
3156 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI, true, "lll" },
3157 { "__insn_shl1add", TILEGX_INSN_SHL1ADD, true, "lll" },
3158 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX, true, "iii" },
3159 { "__insn_shl2add", TILEGX_INSN_SHL2ADD, true, "lll" },
3160 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX, true, "iii" },
3161 { "__insn_shl3add", TILEGX_INSN_SHL3ADD, true, "lll" },
3162 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX, true, "iii" },
3163 { "__insn_shli", TILEGX_INSN_SHL, true, "lli" },
3164 { "__insn_shlx", TILEGX_INSN_SHLX, true, "iii" },
3165 { "__insn_shlxi", TILEGX_INSN_SHLX, true, "iii" },
3166 { "__insn_shrs", TILEGX_INSN_SHRS, true, "lli" },
3167 { "__insn_shrsi", TILEGX_INSN_SHRS, true, "lli" },
3168 { "__insn_shru", TILEGX_INSN_SHRU, true, "lli" },
3169 { "__insn_shrui", TILEGX_INSN_SHRU, true, "lli" },
3170 { "__insn_shrux", TILEGX_INSN_SHRUX, true, "iii" },
3171 { "__insn_shruxi", TILEGX_INSN_SHRUX, true, "iii" },
3172 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES, true, "llll" },
3173 { "__insn_st", TILEGX_INSN_ST, false, "vpl" },
3174 { "__insn_st1", TILEGX_INSN_ST1, false, "vpl" },
3175 { "__insn_st2", TILEGX_INSN_ST2, false, "vpl" },
3176 { "__insn_st4", TILEGX_INSN_ST4, false, "vpl" },
3177 { "__insn_stnt", TILEGX_INSN_STNT, false, "vpl" },
3178 { "__insn_stnt1", TILEGX_INSN_STNT1, false, "vpl" },
3179 { "__insn_stnt2", TILEGX_INSN_STNT2, false, "vpl" },
3180 { "__insn_stnt4", TILEGX_INSN_STNT4, false, "vpl" },
3181 { "__insn_sub", TILEGX_INSN_SUB, true, "lll" },
3182 { "__insn_subx", TILEGX_INSN_SUBX, true, "iii" },
3183 { "__insn_subxsc", TILEGX_INSN_SUBXSC, true, "iii" },
3184 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0, true, "lll" },
3185 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1, true, "lll" },
3186 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2, true, "lll" },
3187 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3, true, "lll" },
3188 { "__insn_v1add", TILEGX_INSN_V1ADD, true, "lll" },
3189 { "__insn_v1addi", TILEGX_INSN_V1ADDI, true, "lll" },
3190 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC, true, "lll" },
3191 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU, true, "lll" },
3192 { "__insn_v1avgu", TILEGX_INSN_V1AVGU, true, "lll" },
3193 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ, true, "lll" },
3194 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI, true, "lll" },
3195 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES, true, "lll" },
3196 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU, true, "lll" },
3197 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS, true, "lll" },
3198 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI, true, "lll" },
3199 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU, true, "lll" },
3200 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI, true, "lll" },
3201 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE, true, "lll" },
3202 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU, true, "lll" },
3203 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA, true, "llll" },
3204 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS, true, "lll" },
3205 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA, true, "llll" },
3206 { "__insn_v1dotp", TILEGX_INSN_V1DOTP, true, "lll" },
3207 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA, true, "llll" },
3208 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU, true, "lll" },
3209 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA, true, "llll" },
3210 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS, true, "lll" },
3211 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA, true, "llll" },
3212 { "__insn_v1int_h", TILEGX_INSN_V1INT_H, true, "lll" },
3213 { "__insn_v1int_l", TILEGX_INSN_V1INT_L, true, "lll" },
3214 { "__insn_v1maxu", TILEGX_INSN_V1MAXU, true, "lll" },
3215 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI, true, "lll" },
3216 { "__insn_v1minu", TILEGX_INSN_V1MINU, true, "lll" },
3217 { "__insn_v1minui", TILEGX_INSN_V1MINUI, true, "lll" },
3218 { "__insn_v1mnz", TILEGX_INSN_V1MNZ, true, "lll" },
3219 { "__insn_v1multu", TILEGX_INSN_V1MULTU, true, "lll" },
3220 { "__insn_v1mulu", TILEGX_INSN_V1MULU, true, "lll" },
3221 { "__insn_v1mulus", TILEGX_INSN_V1MULUS, true, "lll" },
3222 { "__insn_v1mz", TILEGX_INSN_V1MZ, true, "lll" },
3223 { "__insn_v1sadau", TILEGX_INSN_V1SADAU, true, "llll" },
3224 { "__insn_v1sadu", TILEGX_INSN_V1SADU, true, "lll" },
3225 { "__insn_v1shl", TILEGX_INSN_V1SHL, true, "lll" },
3226 { "__insn_v1shli", TILEGX_INSN_V1SHLI, true, "lll" },
3227 { "__insn_v1shrs", TILEGX_INSN_V1SHRS, true, "lll" },
3228 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI, true, "lll" },
3229 { "__insn_v1shru", TILEGX_INSN_V1SHRU, true, "lll" },
3230 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI, true, "lll" },
3231 { "__insn_v1sub", TILEGX_INSN_V1SUB, true, "lll" },
3232 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC, true, "lll" },
3233 { "__insn_v2add", TILEGX_INSN_V2ADD, true, "lll" },
3234 { "__insn_v2addi", TILEGX_INSN_V2ADDI, true, "lll" },
3235 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC, true, "lll" },
3236 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS, true, "lll" },
3237 { "__insn_v2avgs", TILEGX_INSN_V2AVGS, true, "lll" },
3238 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ, true, "lll" },
3239 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI, true, "lll" },
3240 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES, true, "lll" },
3241 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU, true, "lll" },
3242 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS, true, "lll" },
3243 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI, true, "lll" },
3244 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU, true, "lll" },
3245 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI, true, "lll" },
3246 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE, true, "lll" },
3247 { "__insn_v2dotp", TILEGX_INSN_V2DOTP, true, "lll" },
3248 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA, true, "llll" },
3249 { "__insn_v2int_h", TILEGX_INSN_V2INT_H, true, "lll" },
3250 { "__insn_v2int_l", TILEGX_INSN_V2INT_L, true, "lll" },
3251 { "__insn_v2maxs", TILEGX_INSN_V2MAXS, true, "lll" },
3252 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI, true, "lll" },
3253 { "__insn_v2mins", TILEGX_INSN_V2MINS, true, "lll" },
3254 { "__insn_v2minsi", TILEGX_INSN_V2MINSI, true, "lll" },
3255 { "__insn_v2mnz", TILEGX_INSN_V2MNZ, true, "lll" },
3256 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC, true, "lll" },
3257 { "__insn_v2muls", TILEGX_INSN_V2MULS, true, "lll" },
3258 { "__insn_v2mults", TILEGX_INSN_V2MULTS, true, "lll" },
3259 { "__insn_v2mz", TILEGX_INSN_V2MZ, true, "lll" },
3260 { "__insn_v2packh", TILEGX_INSN_V2PACKH, true, "lll" },
3261 { "__insn_v2packl", TILEGX_INSN_V2PACKL, true, "lll" },
3262 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC, true, "lll" },
3263 { "__insn_v2sadas", TILEGX_INSN_V2SADAS, true, "llll" },
3264 { "__insn_v2sadau", TILEGX_INSN_V2SADAU, true, "llll" },
3265 { "__insn_v2sads", TILEGX_INSN_V2SADS, true, "lll" },
3266 { "__insn_v2sadu", TILEGX_INSN_V2SADU, true, "lll" },
3267 { "__insn_v2shl", TILEGX_INSN_V2SHL, true, "lll" },
3268 { "__insn_v2shli", TILEGX_INSN_V2SHLI, true, "lll" },
3269 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC, true, "lll" },
3270 { "__insn_v2shrs", TILEGX_INSN_V2SHRS, true, "lll" },
3271 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI, true, "lll" },
3272 { "__insn_v2shru", TILEGX_INSN_V2SHRU, true, "lll" },
3273 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI, true, "lll" },
3274 { "__insn_v2sub", TILEGX_INSN_V2SUB, true, "lll" },
3275 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC, true, "lll" },
3276 { "__insn_v4add", TILEGX_INSN_V4ADD, true, "lll" },
3277 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC, true, "lll" },
3278 { "__insn_v4int_h", TILEGX_INSN_V4INT_H, true, "lll" },
3279 { "__insn_v4int_l", TILEGX_INSN_V4INT_L, true, "lll" },
3280 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC, true, "lll" },
3281 { "__insn_v4shl", TILEGX_INSN_V4SHL, true, "lll" },
3282 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC, true, "lll" },
3283 { "__insn_v4shrs", TILEGX_INSN_V4SHRS, true, "lll" },
3284 { "__insn_v4shru", TILEGX_INSN_V4SHRU, true, "lll" },
3285 { "__insn_v4sub", TILEGX_INSN_V4SUB, true, "lll" },
3286 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC, true, "lll" },
3287 { "__insn_wh64", TILEGX_INSN_WH64, false, "vp" },
3288 { "__insn_xor", TILEGX_INSN_XOR, true, "lll" },
3289 { "__insn_xori", TILEGX_INSN_XOR, true, "lll" },
3290 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER, false, "v" },
3291 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE, false, "l" },
3292 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE, false, "l" },
3293 { "__tile_idn_send", TILEGX_IDN_SEND, false, "vl" },
3294 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE, false, "l" },
3295 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE, false, "l" },
3296 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE, false, "l" },
3297 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE, false, "l" },
3298 { "__tile_udn_send", TILEGX_UDN_SEND, false, "vl" },
3302 /* Convert a character in a builtin type string to a tree type. */
3304 char_to_type (char c)
3306 static tree volatile_ptr_type_node = NULL;
3307 static tree volatile_const_ptr_type_node = NULL;
3309 if (volatile_ptr_type_node == NULL)
3311 volatile_ptr_type_node =
3312 build_pointer_type (build_qualified_type (void_type_node,
3313 TYPE_QUAL_VOLATILE));
3314 volatile_const_ptr_type_node =
3315 build_pointer_type (build_qualified_type (void_type_node,
3317 | TYPE_QUAL_VOLATILE));
3323 return void_type_node;
3325 return unsigned_type_node;
3327 return long_long_unsigned_type_node;
3329 return volatile_ptr_type_node;
3331 return volatile_const_ptr_type_node;
3338 /* Implement TARGET_INIT_BUILTINS. */
3340 tilegx_init_builtins (void)
3344 for (i = 0; i < ARRAY_SIZE (tilegx_builtins); i++)
3346 const struct tilegx_builtin_def *p = &tilegx_builtins[i];
3347 tree ftype, ret_type, arg_type_list = void_list_node;
3351 for (j = strlen (p->type) - 1; j > 0; j--)
3354 tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list);
3357 ret_type = char_to_type (p->type[0]);
3359 ftype = build_function_type (ret_type, arg_type_list);
3361 decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
3365 TREE_READONLY (decl) = 1;
3366 TREE_NOTHROW (decl) = 1;
3368 if (tilegx_builtin_info[p->code].fndecl == NULL)
3369 tilegx_builtin_info[p->code].fndecl = decl;
3374 /* Implement TARGET_EXPAND_BUILTIN. */
3376 tilegx_expand_builtin (tree exp,
3378 rtx subtarget ATTRIBUTE_UNUSED,
3379 enum machine_mode mode ATTRIBUTE_UNUSED,
3380 int ignore ATTRIBUTE_UNUSED)
3382 #define MAX_BUILTIN_ARGS 4
3384 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
3385 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
3387 call_expr_arg_iterator iter;
3388 enum insn_code icode;
3389 rtx op[MAX_BUILTIN_ARGS + 1], pat;
3394 if (fcode >= TILEGX_BUILTIN_max)
3395 internal_error ("bad builtin fcode");
3396 icode = tilegx_builtin_info[fcode].icode;
3398 internal_error ("bad builtin icode");
3400 nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
3403 FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
3405 const struct insn_operand_data *insn_op;
3407 if (arg == error_mark_node)
3409 if (opnum > MAX_BUILTIN_ARGS)
3412 insn_op = &insn_data[icode].operand[opnum];
3414 op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL);
3416 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3418 enum machine_mode opmode = insn_op->mode;
3420 /* pointer_operand and pmode_register_operand operands do
3421 not specify a mode, so use the operand's mode instead
3422 (which should always be right by the time we get here,
3423 except for constants, which are VOIDmode). */
3424 if (opmode == VOIDmode)
3426 enum machine_mode m = GET_MODE (op[opnum]);
3427 gcc_assert (m == Pmode || m == VOIDmode);
3431 op[opnum] = copy_to_mode_reg (opmode, op[opnum]);
3434 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3436 /* We still failed to meet the predicate even after moving
3437 into a register. Assume we needed an immediate. */
3438 error_at (EXPR_LOCATION (exp),
3439 "operand must be an immediate of the right size");
3448 enum machine_mode tmode = insn_data[icode].operand[0].mode;
3450 || GET_MODE (target) != tmode
3451 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
3453 if (tmode == VOIDmode)
3455 /* get the mode from the return type. */
3456 tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl)));
3458 target = gen_reg_rtx (tmode);
3463 fn = GEN_FCN (icode);
3467 pat = fn (NULL_RTX);
3473 pat = fn (op[0], op[1]);
3476 pat = fn (op[0], op[1], op[2]);
3479 pat = fn (op[0], op[1], op[2], op[3]);
3482 pat = fn (op[0], op[1], op[2], op[3], op[4]);
3498 /* Implement TARGET_BUILTIN_DECL. */
3500 tilegx_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
3502 if (code >= TILEGX_BUILTIN_max)
3503 return error_mark_node;
3505 return tilegx_builtin_info[code].fndecl;
3512 /* Return whether REGNO needs to be saved in the stack frame. */
3514 need_to_save_reg (unsigned int regno)
3516 if (!fixed_regs[regno] && !call_used_regs[regno]
3517 && df_regs_ever_live_p (regno))
3521 && (regno == PIC_OFFSET_TABLE_REGNUM
3522 || regno == TILEGX_PIC_TEXT_LABEL_REGNUM)
3523 && (crtl->uses_pic_offset_table || crtl->saves_all_registers))
3526 if (crtl->calls_eh_return)
3529 for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++)
3531 if (regno == EH_RETURN_DATA_REGNO (i))
3540 /* Return the size of the register savev area. This function is only
3541 correct starting with local register allocation */
3543 tilegx_saved_regs_size (void)
3545 int reg_save_size = 0;
3547 int offset_to_frame;
3550 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3551 if (need_to_save_reg (regno))
3552 reg_save_size += UNITS_PER_WORD;
3554 /* Pad out the register save area if necessary to make
3555 frame_pointer_rtx be as aligned as the stack pointer. */
3556 offset_to_frame = crtl->args.pretend_args_size + reg_save_size;
3557 align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1;
3558 reg_save_size += (-offset_to_frame) & align_mask;
3560 return reg_save_size;
3564 /* Round up frame size SIZE. */
3566 round_frame_size (int size)
3568 return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1)
3569 & -STACK_BOUNDARY / BITS_PER_UNIT);
3573 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3574 emit the corresponding REG_CFA_OFFSET note described by CFA and
3575 CFA_OFFSET. Return the emitted insn. */
3577 frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa,
3580 rtx reg = gen_rtx_REG (DImode, regno);
3581 rtx mem = gen_frame_mem (DImode, addr);
3582 rtx mov = gen_movdi (mem, reg);
3584 /* Describe what just happened in a way that dwarf understands. We
3585 use temporary registers to hold the address to make scheduling
3586 easier, and use the REG_CFA_OFFSET to describe the address as an
3587 offset from the CFA. */
3588 rtx reg_note = gen_rtx_REG (DImode, regno_note);
3589 rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, GEN_INT (cfa_offset));
3590 rtx cfa_relative_mem = gen_frame_mem (DImode, cfa_relative_addr);
3591 rtx real = gen_rtx_SET (VOIDmode, cfa_relative_mem, reg_note);
3592 add_reg_note (mov, REG_CFA_OFFSET, real);
3594 return emit_insn (mov);
3598 /* Emit a load in the stack frame to load REGNO from address ADDR.
3599 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3600 non-null. Return the emitted insn. */
3602 frame_emit_load (int regno, rtx addr, rtx *cfa_restores)
3604 rtx reg = gen_rtx_REG (DImode, regno);
3605 rtx mem = gen_frame_mem (DImode, addr);
3607 *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores);
3608 return emit_insn (gen_movdi (reg, mem));
3612 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3613 including sequences. */
3615 set_frame_related_p (void)
3617 rtx seq = get_insns ();
3628 while (insn != NULL_RTX)
3630 RTX_FRAME_RELATED_P (insn) = 1;
3631 insn = NEXT_INSN (insn);
3633 seq = emit_insn (seq);
3637 seq = emit_insn (seq);
3638 RTX_FRAME_RELATED_P (seq) = 1;
3644 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3646 /* This emits code for 'sp += offset'.
3648 The ABI only allows us to modify 'sp' in a single 'addi' or
3649 'addli', so the backtracer understands it. Larger amounts cannot
3650 use those instructions, so are added by placing the offset into a
3651 large register and using 'add'.
3653 This happens after reload, so we need to expand it ourselves. */
3655 emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related,
3659 rtx imm_rtx = GEN_INT (offset);
3662 if (satisfies_constraint_J (imm_rtx))
3664 /* We can add this using a single immediate add. */
3669 rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3670 tilegx_expand_set_const64 (tmp, imm_rtx);
3674 /* Actually adjust the stack pointer. */
3676 insn = gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx, to_add);
3678 insn = gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx, to_add);
3680 insn = emit_insn (insn);
3681 REG_NOTES (insn) = reg_notes;
3683 /* Describe what just happened in a way that dwarf understands. */
3686 rtx real = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
3687 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3689 RTX_FRAME_RELATED_P (insn) = 1;
3690 add_reg_note (insn, REG_CFA_ADJUST_CFA, real);
3697 /* Return whether the current function is leaf. This takes into
3698 account whether the function calls tls_get_addr. */
3700 tilegx_current_function_is_leaf (void)
3702 return current_function_is_leaf && !cfun->machine->calls_tls_get_addr;
3706 /* Return the frame size. */
3708 compute_total_frame_size (void)
3710 int total_size = (get_frame_size () + tilegx_saved_regs_size ()
3711 + crtl->outgoing_args_size
3712 + crtl->args.pretend_args_size);
3714 if (!tilegx_current_function_is_leaf () || cfun->calls_alloca)
3716 /* Make room for save area in callee. */
3717 total_size += STACK_POINTER_OFFSET;
3720 return round_frame_size (total_size);
3724 /* Return nonzero if this function is known to have a null epilogue.
3725 This allows the optimizer to omit jumps to jumps if no stack was
3728 tilegx_can_use_return_insn_p (void)
3730 return (reload_completed
3731 && cfun->static_chain_decl == 0
3732 && compute_total_frame_size () == 0
3733 && tilegx_current_function_is_leaf ()
3734 && !crtl->profile && !df_regs_ever_live_p (TILEGX_LINK_REGNUM));
3738 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3739 is a frame pointer, it computes the value relative to
3740 that. Otherwise it uses the stack pointer. */
3742 compute_frame_addr (int offset_from_fp, int *next_scratch_regno)
3744 rtx base_reg_rtx, tmp_reg_rtx, offset_rtx;
3745 int offset_from_base;
3747 if (frame_pointer_needed)
3749 base_reg_rtx = hard_frame_pointer_rtx;
3750 offset_from_base = offset_from_fp;
3754 int offset_from_sp = compute_total_frame_size () + offset_from_fp;
3755 offset_from_base = offset_from_sp;
3756 base_reg_rtx = stack_pointer_rtx;
3759 if (offset_from_base == 0)
3760 return base_reg_rtx;
3762 /* Compute the new value of the stack pointer. */
3763 tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3764 offset_rtx = GEN_INT (offset_from_base);
3766 if (!add_operand (offset_rtx, Pmode))
3768 expand_set_cint64 (tmp_reg_rtx, offset_rtx);
3769 offset_rtx = tmp_reg_rtx;
3772 emit_insn (gen_rtx_SET (VOIDmode, tmp_reg_rtx,
3773 gen_rtx_PLUS (Pmode, base_reg_rtx, offset_rtx)));
3779 /* The stack frame looks like this:
3784 AP -> +-------------+
3788 HFP -> +-------------+
3790 | reg save | crtl->args.pretend_args_size bytes
3793 | saved regs | tilegx_saved_regs_size() bytes
3794 FP -> +-------------+
3796 | vars | get_frame_size() bytes
3800 | stack args | crtl->outgoing_args_size bytes
3802 | HFP | ptr_size bytes (only here if nonleaf / alloca)
3804 | callee lr | ptr_size bytes (only here if nonleaf / alloca)
3806 SP -> +-------------+
3810 For functions with a frame larger than 32767 bytes, or which use
3811 alloca (), r52 is used as a frame pointer. Otherwise there is no
3814 FP is saved at SP+ptr_size before calling a subroutine so the callee
3817 tilegx_expand_prologue (void)
3819 #define ROUND_ROBIN_SIZE 4
3820 /* We round-robin through four scratch registers to hold temporary
3821 addresses for saving registers, to make instruction scheduling
3823 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3824 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3827 unsigned int which_scratch;
3828 int offset, start_offset, regno;
3830 /* A register that holds a copy of the incoming fp. */
3831 int fp_copy_regno = -1;
3833 /* A register that holds a copy of the incoming sp. */
3834 int sp_copy_regno = -1;
3836 /* Next scratch register number to hand out (postdecrementing). */
3837 int next_scratch_regno = 29;
3839 int total_size = compute_total_frame_size ();
3841 if (flag_stack_usage_info)
3842 current_function_static_stack_size = total_size;
3844 /* Save lr first in its special location because code after this
3845 might use the link register as a scratch register. */
3846 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM) || crtl->calls_eh_return)
3847 FRP (frame_emit_store (TILEGX_LINK_REGNUM, TILEGX_LINK_REGNUM,
3848 stack_pointer_rtx, stack_pointer_rtx, 0));
3850 if (total_size == 0)
3852 /* Load the PIC register if needed. */
3853 if (flag_pic && crtl->uses_pic_offset_table)
3854 load_pic_register (false);
3859 cfa = stack_pointer_rtx;
3861 if (frame_pointer_needed)
3863 fp_copy_regno = next_scratch_regno--;
3865 /* Copy the old frame pointer aside so we can save it later. */
3867 FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno),
3868 gen_lowpart (word_mode, hard_frame_pointer_rtx)));
3869 add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
3871 /* Set up the frame pointer. */
3872 insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
3873 add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx);
3874 cfa = hard_frame_pointer_rtx;
3875 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
3877 /* fp holds a copy of the incoming sp, in case we need to store
3879 sp_copy_regno = HARD_FRAME_POINTER_REGNUM;
3881 else if (!tilegx_current_function_is_leaf ())
3883 /* Copy the old stack pointer aside so we can save it later. */
3884 sp_copy_regno = next_scratch_regno--;
3885 emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno),
3889 if (tilegx_current_function_is_leaf ())
3891 /* No need to store chain pointer to caller's frame. */
3892 emit_sp_adjust (-total_size, &next_scratch_regno,
3893 !frame_pointer_needed, NULL_RTX);
3897 /* Save the frame pointer (incoming sp value) to support
3898 backtracing. First we need to create an rtx with the store
3900 rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--);
3901 rtx size_rtx = GEN_INT (-(total_size - UNITS_PER_WORD));
3903 frame_pointer_needed ? UNITS_PER_WORD - total_size : UNITS_PER_WORD;
3905 if (add_operand (size_rtx, Pmode))
3907 /* Expose more parallelism by computing this value from the
3908 original stack pointer, not the one after we have pushed
3910 rtx p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, size_rtx);
3911 emit_insn (gen_rtx_SET (VOIDmode, chain_addr, p));
3912 emit_sp_adjust (-total_size, &next_scratch_regno,
3913 !frame_pointer_needed, NULL_RTX);
3917 /* The stack frame is large, so just store the incoming sp
3918 value at *(new_sp + UNITS_PER_WORD). */
3920 emit_sp_adjust (-total_size, &next_scratch_regno,
3921 !frame_pointer_needed, NULL_RTX);
3922 p = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3923 GEN_INT (UNITS_PER_WORD));
3924 emit_insn (gen_rtx_SET (VOIDmode, chain_addr, p));
3927 /* Save our frame pointer for backtrace chaining. */
3928 emit_insn (gen_movdi (gen_frame_mem (DImode, chain_addr),
3929 gen_rtx_REG (DImode, sp_copy_regno)));
3932 /* Compute where to start storing registers we need to save. */
3933 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
3934 offset = start_offset;
3936 /* Store all registers that need saving. */
3938 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
3939 if (need_to_save_reg (regno))
3941 rtx r = reg_save_addr[which_scratch];
3943 int cfa_offset = frame_pointer_needed ? offset : total_size + offset;
3947 rtx p = compute_frame_addr (offset, &next_scratch_regno);
3948 r = gen_rtx_REG (Pmode, next_scratch_regno--);
3949 reg_save_addr[which_scratch] = r;
3951 emit_insn (gen_rtx_SET (VOIDmode, r, p));
3955 /* Advance to the next stack slot to store this
3957 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
3958 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
3959 emit_insn (gen_rtx_SET (VOIDmode, r, p));
3962 /* Save this register to the stack (but use the old fp value
3963 we copied aside if appropriate). */
3965 (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM)
3966 ? fp_copy_regno : regno;
3967 FRP (frame_emit_store (from_regno, regno, r, cfa, cfa_offset));
3969 offset -= UNITS_PER_WORD;
3970 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
3973 /* If profiling, force that to happen after the frame is set up. */
3975 emit_insn (gen_blockage ());
3977 /* Load the PIC register if needed. */
3978 if (flag_pic && crtl->uses_pic_offset_table)
3979 load_pic_register (false);
3983 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
3984 true for a sibcall_epilogue pattern, and false for an epilogue
3987 tilegx_expand_epilogue (bool sibcall_p)
3989 /* We round-robin through four scratch registers to hold temporary
3990 addresses for saving registers, to make instruction scheduling
3992 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3993 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3995 rtx last_insn, insn;
3996 unsigned int which_scratch;
3997 int offset, start_offset, regno;
3998 rtx cfa_restores = NULL_RTX;
4000 /* A register that holds a copy of the incoming fp. */
4001 int fp_copy_regno = -1;
4003 /* Next scratch register number to hand out (postdecrementing). */
4004 int next_scratch_regno = 29;
4006 int total_size = compute_total_frame_size ();
4008 last_insn = get_last_insn ();
4010 /* Load lr first since we are going to need it first. */
4012 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM))
4014 insn = frame_emit_load (TILEGX_LINK_REGNUM,
4015 compute_frame_addr (0, &next_scratch_regno),
4019 if (total_size == 0)
4023 RTX_FRAME_RELATED_P (insn) = 1;
4024 REG_NOTES (insn) = cfa_restores;
4029 /* Compute where to start restoring registers. */
4030 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
4031 offset = start_offset;
4033 if (frame_pointer_needed)
4034 fp_copy_regno = next_scratch_regno--;
4036 /* Restore all callee-saved registers. */
4038 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
4039 if (need_to_save_reg (regno))
4041 rtx r = reg_save_addr[which_scratch];
4044 r = compute_frame_addr (offset, &next_scratch_regno);
4045 reg_save_addr[which_scratch] = r;
4049 /* Advance to the next stack slot to store this register. */
4050 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
4051 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
4052 emit_insn (gen_rtx_SET (VOIDmode, r, p));
4055 if (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM)
4056 frame_emit_load (fp_copy_regno, r, NULL);
4058 frame_emit_load (regno, r, &cfa_restores);
4060 offset -= UNITS_PER_WORD;
4061 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
4064 if (!tilegx_current_function_is_leaf ())
4066 alloc_reg_note (REG_CFA_RESTORE, stack_pointer_rtx, cfa_restores);
4068 emit_insn (gen_blockage ());
4070 if (frame_pointer_needed)
4072 /* Restore the old stack pointer by copying from the frame
4076 insn = emit_insn (gen_sp_restore_32bit (stack_pointer_rtx,
4077 hard_frame_pointer_rtx));
4081 insn = emit_insn (gen_sp_restore (stack_pointer_rtx,
4082 hard_frame_pointer_rtx));
4084 RTX_FRAME_RELATED_P (insn) = 1;
4085 REG_NOTES (insn) = cfa_restores;
4086 add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx);
4090 insn = emit_sp_adjust (total_size, &next_scratch_regno, true,
4094 if (crtl->calls_eh_return)
4097 emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx,
4098 EH_RETURN_STACKADJ_RTX));
4100 emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
4101 EH_RETURN_STACKADJ_RTX));
4104 /* Restore the old frame pointer. */
4105 if (frame_pointer_needed)
4107 insn = emit_move_insn (gen_lowpart (DImode, hard_frame_pointer_rtx),
4108 gen_rtx_REG (DImode, fp_copy_regno));
4109 add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);
4112 /* Mark the pic registers as live outside of the function. */
4115 emit_use (cfun->machine->text_label_rtx);
4116 emit_use (cfun->machine->got_rtx);
4122 emit_jump_insn (gen__return ());
4126 emit_use (gen_rtx_REG (Pmode, TILEGX_LINK_REGNUM));
4129 /* Mark all insns we just emitted as frame-related. */
4130 for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn))
4131 RTX_FRAME_RELATED_P (last_insn) = 1;
4134 #undef ROUND_ROBIN_SIZE
4137 /* Implement INITIAL_ELIMINATION_OFFSET. */
4139 tilegx_initial_elimination_offset (int from, int to)
4141 int total_size = compute_total_frame_size ();
4143 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
4145 return (total_size - crtl->args.pretend_args_size
4146 - tilegx_saved_regs_size ());
4148 else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
4150 return -(crtl->args.pretend_args_size + tilegx_saved_regs_size ());
4152 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
4154 return STACK_POINTER_OFFSET + total_size;
4156 else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
4158 return STACK_POINTER_OFFSET;
4165 /* Return an RTX indicating where the return address to the calling
4166 function can be found. */
4168 tilegx_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
4173 return get_hard_reg_initial_val (Pmode, TILEGX_LINK_REGNUM);
4177 /* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to
4178 prevent it from being deleted. */
4180 tilegx_eh_return_handler_rtx (void)
4182 rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
4183 MEM_VOLATILE_P (tmp) = true;
4191 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
4193 tilegx_conditional_register_usage (void)
4195 global_regs[TILEGX_NETORDER_REGNUM] = 1;
4196 /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
4197 member of fixed_regs, and therefore must be member of
4198 call_used_regs, but it is not a member of call_really_used_regs[]
4199 because it is not clobbered by a call. */
4200 if (TILEGX_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM)
4202 fixed_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1;
4203 call_used_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1;
4205 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
4207 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
4208 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
4213 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
4215 tilegx_frame_pointer_required (void)
4217 return crtl->calls_eh_return || cfun->calls_alloca;
4222 /* Scheduling and reorg */
4224 /* Return the length of INSN. LENGTH is the initial length computed
4225 by attributes in the machine-description file. This is where we
4226 account for bundles. */
4228 tilegx_adjust_insn_length (rtx insn, int length)
4230 enum machine_mode mode = GET_MODE (insn);
4232 /* A non-termininating instruction in a bundle has length 0. */
4236 /* By default, there is not length adjustment. */
4241 /* Implement TARGET_SCHED_ISSUE_RATE. */
4243 tilegx_issue_rate (void)
4249 /* Return the rtx for the jump target. */
4251 get_jump_target (rtx branch)
4253 if (CALL_P (branch))
4256 call = PATTERN (branch);
4258 if (GET_CODE (call) == PARALLEL)
4259 call = XVECEXP (call, 0, 0);
4261 if (GET_CODE (call) == SET)
4262 call = SET_SRC (call);
4264 if (GET_CODE (call) == CALL)
4265 return XEXP (XEXP (call, 0), 0);
4271 /* Implement TARGET_SCHED_ADJUST_COST. */
4273 tilegx_sched_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
4275 /* If we have a true dependence, INSN is a call, and DEP_INSN
4276 defines a register that is needed by the call (argument or stack
4277 pointer) , set its latency to 0 so that it can be bundled with
4278 the call. Explicitly check for and exclude the case when
4279 DEP_INSN defines the target of the jump. */
4280 if (CALL_P (insn) && REG_NOTE_KIND (link) == REG_DEP_TRUE)
4282 rtx target = get_jump_target (insn);
4283 if (!REG_P (target) || !set_of (target, dep_insn))
4291 /* Skip over irrelevant NOTEs and such and look for the next insn we
4292 would consider bundling. */
4294 next_insn_to_bundle (rtx r, rtx end)
4296 for (; r != end; r = NEXT_INSN (r))
4298 if (NONDEBUG_INSN_P (r)
4299 && GET_CODE (PATTERN (r)) != USE
4300 && GET_CODE (PATTERN (r)) != CLOBBER)
4308 /* Go through all insns, and use the information generated during
4309 scheduling to generate SEQUENCEs to represent bundles of
4310 instructions issued simultaneously. */
4312 tilegx_gen_bundles (void)
4318 rtx end = NEXT_INSN (BB_END (bb));
4320 for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn; insn = next)
4322 next = next_insn_to_bundle (NEXT_INSN (insn), end);
4324 /* Never wrap {} around inline asm. */
4325 if (GET_CODE (PATTERN (insn)) != ASM_INPUT)
4327 if (next == NULL_RTX || GET_MODE (next) == TImode
4328 /* NOTE: The scheduler incorrectly believes a call
4329 insn can execute in the same cycle as the insn
4330 after the call. This is of course impossible.
4331 Really we need to fix the scheduler somehow, so
4332 the code after the call gets scheduled
4336 /* Mark current insn as the end of a bundle. */
4337 PUT_MODE (insn, QImode);
4341 /* Mark it as part of a bundle. */
4342 PUT_MODE (insn, SImode);
4350 /* Replace OLD_INSN with NEW_INSN. */
4352 replace_insns (rtx old_insn, rtx new_insns)
4355 emit_insn_before (new_insns, old_insn);
4357 delete_insn (old_insn);
4361 /* Returns true if INSN is the first instruction of a pc-relative
4362 address compuatation. */
4364 match_pcrel_step1 (rtx insn)
4366 rtx pattern = PATTERN (insn);
4369 if (GET_CODE (pattern) != SET)
4372 src = SET_SRC (pattern);
4374 return (GET_CODE (src) == CONST
4375 && GET_CODE (XEXP (src, 0)) == UNSPEC
4376 && XINT (XEXP (src, 0), 1) == UNSPEC_HW1_LAST_PCREL);
4380 /* Do the first replacement step in tilegx_fixup_pcrel_references. */
4382 replace_mov_pcrel_step1 (rtx insn)
4384 rtx pattern = PATTERN (insn);
4389 gcc_assert (GET_CODE (pattern) == SET);
4390 opnds[0] = SET_DEST (pattern);
4392 gcc_assert (GET_CODE (SET_SRC (pattern)) == CONST);
4394 unspec = XEXP (SET_SRC (pattern), 0);
4395 gcc_assert (GET_CODE (unspec) == UNSPEC);
4396 gcc_assert (XINT (unspec, 1) == UNSPEC_HW1_LAST_PCREL);
4397 opnds[1] = XVECEXP (unspec, 0, 0);
4399 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4400 if (GET_CODE (opnds[1]) != SYMBOL_REF)
4408 emit_insn (gen_mov_got32_step1_32bit (opnds[0], opnds[1]));
4410 emit_insn (gen_mov_got32_step1 (opnds[0], opnds[1]));
4413 new_insns = get_insns ();
4416 replace_insns (insn, new_insns);
4420 /* Returns true if INSN is the second instruction of a pc-relative
4421 address compuatation. */
4423 match_pcrel_step2 (rtx insn)
4430 if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli_32bit)
4435 if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli)
4439 unspec = SET_SRC (PATTERN (insn));
4440 addr = XVECEXP (unspec, 0, 1);
4442 return (GET_CODE (addr) == CONST
4443 && GET_CODE (XEXP (addr, 0)) == UNSPEC
4444 && XINT (XEXP (addr, 0), 1) == UNSPEC_HW0_PCREL);
4448 /* Do the second replacement step in tilegx_fixup_pcrel_references. */
4450 replace_mov_pcrel_step2 (rtx insn)
4452 rtx pattern = PATTERN (insn);
4457 rtx got_rtx = tilegx_got_rtx ();
4459 gcc_assert (GET_CODE (pattern) == SET);
4460 opnds[0] = SET_DEST (pattern);
4462 unspec = SET_SRC (pattern);
4463 gcc_assert (GET_CODE (unspec) == UNSPEC);
4464 gcc_assert (XINT (unspec, 1) == UNSPEC_INSN_ADDR_SHL16INSLI);
4466 opnds[1] = XVECEXP (unspec, 0, 0);
4468 addr = XVECEXP (unspec, 0, 1);
4469 gcc_assert (GET_CODE (addr) == CONST);
4471 unspec = XEXP (addr, 0);
4472 gcc_assert (GET_CODE (unspec) == UNSPEC);
4473 gcc_assert (XINT (unspec, 1) == UNSPEC_HW0_PCREL);
4474 opnds[2] = XVECEXP (unspec, 0, 0);
4476 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4477 if (GET_CODE (opnds[2]) != SYMBOL_REF)
4485 emit_insn (gen_add_got16_32bit (opnds[0], got_rtx, opnds[2]));
4487 emit_insn (gen_add_got16 (opnds[0], got_rtx, opnds[2]));
4492 emit_insn (gen_mov_got32_step2_32bit
4493 (opnds[0], opnds[1], opnds[2]));
4495 emit_insn (gen_mov_got32_step2 (opnds[0], opnds[1], opnds[2]));
4498 new_insns = get_insns ();
4501 replace_insns (insn, new_insns);
4505 /* Do the third replacement step in tilegx_fixup_pcrel_references. */
4507 replace_mov_pcrel_step3 (rtx insn)
4509 rtx pattern = PATTERN (insn);
4513 rtx got_rtx = tilegx_got_rtx ();
4514 rtx text_label_rtx = tilegx_text_label_rtx ();
4516 gcc_assert (GET_CODE (pattern) == SET);
4517 opnds[0] = SET_DEST (pattern);
4519 unspec = SET_SRC (pattern);
4520 gcc_assert (GET_CODE (unspec) == UNSPEC);
4521 gcc_assert (XINT (unspec, 1) == UNSPEC_MOV_PCREL_STEP3);
4525 if (XVECEXP (unspec, 0, 0) == text_label_rtx)
4526 opnds[2] = XVECEXP (unspec, 0, 1);
4529 gcc_assert (XVECEXP (unspec, 0, 1) == text_label_rtx);
4530 opnds[2] = XVECEXP (unspec, 0, 0);
4533 opnds[3] = XVECEXP (unspec, 0, 2);
4535 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4536 if (GET_CODE (opnds[3]) != SYMBOL_REF)
4543 emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[2]));
4547 emit_move_insn (opnds[0], gen_rtx_PLUS (Pmode, opnds[1], opnds[2]));
4548 emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[0]));
4551 new_insns = get_insns ();
4554 replace_insns (insn, new_insns);
4558 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4559 going through the GOT when the symbol is local to the compilation
4560 unit. But such a symbol requires that the common text_label that
4561 we generate at the beginning of the function be in the same section
4562 as the reference to the SYMBOL_REF. This may not be true if we
4563 generate hot/cold sections. This function looks for such cases and
4564 replaces such references with the longer sequence going through the
4567 We expect following instruction sequence:
4568 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4569 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4570 add<x> tmp3, txt_label_reg, tmp2 [3]
4572 If we're compiling -fpic, we replace with the following sequence
4573 (the numbers in brackets match the instructions they're replacing
4576 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4577 ld<4> tmp3, tmp2 [3]
4579 If we're compiling -fPIC, we replace the first instruction with:
4581 moveli tmp1, hw1_last_got(x) [1]
4582 shl16insli tmp2, tmp1, hw0_got(x) [2]
4583 add<x> tmp3, got_reg, tmp2 [3]
4584 ld<4> tmp3, tmp3 [3]
4586 Note that we're careful to disturb the instruction sequence as
4587 little as possible, since it's very late in the compilation
4590 tilegx_fixup_pcrel_references (void)
4592 rtx insn, next_insn;
4593 bool same_section_as_entry = true;
4595 for (insn = get_insns (); insn; insn = next_insn)
4597 next_insn = NEXT_INSN (insn);
4599 if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
4601 same_section_as_entry = !same_section_as_entry;
4605 if (same_section_as_entry)
4609 && GET_CODE (PATTERN (insn)) != USE
4610 && GET_CODE (PATTERN (insn)) != CLOBBER))
4615 if (match_pcrel_step1 (insn))
4616 replace_mov_pcrel_step1 (insn);
4617 else if (match_pcrel_step2 (insn))
4618 replace_mov_pcrel_step2 (insn);
4619 else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3_32bit)
4620 replace_mov_pcrel_step3 (insn);
4624 if (match_pcrel_step1 (insn))
4625 replace_mov_pcrel_step1 (insn);
4626 else if (match_pcrel_step2 (insn))
4627 replace_mov_pcrel_step2 (insn);
4628 else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3)
4629 replace_mov_pcrel_step3 (insn);
4635 /* Ensure that no var tracking notes are emitted in the middle of a
4636 three-instruction bundle. */
4638 reorder_var_tracking_notes (void)
4644 rtx queue = NULL_RTX;
4645 bool in_bundle = false;
4647 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4649 next = NEXT_INSN (insn);
4653 /* Emit queued up notes at the last instruction of a
4655 if (GET_MODE (insn) == QImode)
4659 rtx next_queue = PREV_INSN (queue);
4660 PREV_INSN (NEXT_INSN (insn)) = queue;
4661 NEXT_INSN (queue) = NEXT_INSN (insn);
4662 NEXT_INSN (insn) = queue;
4663 PREV_INSN (queue) = insn;
4668 else if (GET_MODE (insn) == SImode)
4671 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4675 rtx prev = PREV_INSN (insn);
4676 PREV_INSN (next) = prev;
4677 NEXT_INSN (prev) = next;
4679 PREV_INSN (insn) = queue;
4688 /* Perform machine dependent operations on the rtl chain INSNS. */
4692 /* We are freeing block_for_insn in the toplev to keep compatibility
4693 with old MDEP_REORGS that are not CFG based. Recompute it
4695 compute_bb_for_insn ();
4697 if (flag_reorder_blocks_and_partition)
4699 tilegx_fixup_pcrel_references ();
4702 if (flag_schedule_insns_after_reload)
4706 timevar_push (TV_SCHED2);
4708 timevar_pop (TV_SCHED2);
4710 /* Examine the schedule to group into bundles. */
4711 tilegx_gen_bundles ();
4716 if (flag_var_tracking)
4718 timevar_push (TV_VAR_TRACKING);
4719 variable_tracking_main ();
4720 reorder_var_tracking_notes ();
4721 timevar_pop (TV_VAR_TRACKING);
4724 df_finish_pass (false);
4731 /* Select a format to encode pointers in exception handling data.
4732 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4733 GLOBAL is true if the symbol may be affected by dynamic
4736 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
4740 int type = TARGET_32BIT ? DW_EH_PE_sdata4 : DW_EH_PE_sdata8;
4741 return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type;
4744 return DW_EH_PE_absptr;
4748 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4750 tilegx_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
4751 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
4754 rtx this_rtx, insn, funexp, addend;
4756 /* Pretend to be a post-reload pass while generating rtl. */
4757 reload_completed = 1;
4759 /* Mark the end of the (empty) prologue. */
4760 emit_note (NOTE_INSN_PROLOGUE_END);
4762 /* Find the "this" pointer. If the function returns a structure,
4763 the structure return pointer is in $1. */
4764 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
4765 this_rtx = gen_rtx_REG (Pmode, 1);
4767 this_rtx = gen_rtx_REG (Pmode, 0);
4769 /* Add DELTA to THIS_RTX. */
4770 if (!(delta >= -32868 && delta <= 32767))
4772 addend = gen_rtx_REG (Pmode, 29);
4773 emit_move_insn (addend, GEN_INT (delta));
4776 addend = GEN_INT (delta);
4779 emit_insn (gen_addsi3 (this_rtx, this_rtx, addend));
4781 emit_insn (gen_adddi3 (this_rtx, this_rtx, addend));
4783 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4788 tmp = gen_rtx_REG (Pmode, 29);
4789 emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx));
4791 if (!(vcall_offset >= -32868 && vcall_offset <= 32767))
4793 addend = gen_rtx_REG (Pmode, 28);
4794 emit_move_insn (addend, GEN_INT (vcall_offset));
4797 addend = GEN_INT (vcall_offset);
4800 emit_insn (gen_addsi3 (tmp, tmp, addend));
4802 emit_insn (gen_adddi3 (tmp, tmp, addend));
4804 emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
4807 emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp));
4809 emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp));
4812 /* Generate a tail call to the target function. */
4813 if (!TREE_USED (function))
4815 assemble_external (function);
4816 TREE_USED (function) = 1;
4818 funexp = XEXP (DECL_RTL (function), 0);
4819 funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
4820 insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
4821 SIBLING_CALL_P (insn) = 1;
4823 /* Run just enough of rest_of_compilation to get the insns emitted.
4824 There's not really enough bulk here to make other passes such as
4825 instruction scheduling worth while. Note that use_thunk calls
4826 assemble_start_function and assemble_end_function.
4828 We don't currently bundle, but the instruciton sequence is all
4829 serial except for the tail call, so we're only wasting one cycle.
4831 insn = get_insns ();
4832 insn_locators_alloc ();
4833 shorten_branches (insn);
4834 final_start_function (insn, file, 1);
4835 final (insn, file, 1);
4836 final_end_function ();
4838 /* Stop pretending to be a post-reload pass. */
4839 reload_completed = 0;
4843 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
4845 tilegx_asm_trampoline_template (FILE *file)
4847 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4850 fprintf (file, "\tlnk r10\n");
4851 fprintf (file, "\taddxi r10, r10, 32\n");
4852 fprintf (file, "\tld4s_add r11, r10, %d\n", ptr_mode_size);
4853 fprintf (file, "\tld4s r10, r10\n");
4854 fprintf (file, "\tjr r11\n");
4855 fprintf (file, "\t.word 0 # <function address>\n");
4856 fprintf (file, "\t.word 0 # <static chain value>\n");
4860 fprintf (file, "\tlnk r10\n");
4861 fprintf (file, "\taddi r10, r10, 32\n");
4862 fprintf (file, "\tld_add r11, r10, %d\n", ptr_mode_size);
4863 fprintf (file, "\tld r10, r10\n");
4864 fprintf (file, "\tjr r11\n");
4865 fprintf (file, "\t.quad 0 # <function address>\n");
4866 fprintf (file, "\t.quad 0 # <static chain value>\n");
4871 /* Implement TARGET_TRAMPOLINE_INIT. */
4873 tilegx_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
4877 rtx begin_addr, end_addr;
4878 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4880 fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
4881 chaddr = copy_to_reg (static_chain);
4883 emit_block_move (m_tramp, assemble_trampoline_template (),
4884 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
4886 mem = adjust_address (m_tramp, ptr_mode,
4887 TRAMPOLINE_SIZE - 2 * ptr_mode_size);
4888 emit_move_insn (mem, fnaddr);
4889 mem = adjust_address (m_tramp, ptr_mode,
4890 TRAMPOLINE_SIZE - ptr_mode_size);
4891 emit_move_insn (mem, chaddr);
4893 /* Get pointers to the beginning and end of the code block. */
4894 begin_addr = force_reg (Pmode, XEXP (m_tramp, 0));
4895 end_addr = force_reg (Pmode, plus_constant (XEXP (m_tramp, 0),
4898 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
4899 LCT_NORMAL, VOIDmode, 2, begin_addr, Pmode,
4904 /* Implement TARGET_PRINT_OPERAND. */
4906 tilegx_print_operand (FILE *file, rtx x, int code)
4911 /* Print the compare operator opcode for conditional moves. */
4912 switch (GET_CODE (x))
4921 output_operand_lossage ("invalid %%c operand");
4926 /* Print the compare operator opcode for conditional moves. */
4927 switch (GET_CODE (x))
4936 output_operand_lossage ("invalid %%C operand");
4942 /* Print the compare operator opcode for conditional moves. */
4943 switch (GET_CODE (x))
4952 output_operand_lossage ("invalid %%d operand");
4959 /* Print the compare operator opcode for conditional moves. */
4960 switch (GET_CODE (x))
4969 output_operand_lossage ("invalid %%D operand");
4976 if (GET_CODE (x) == CONST
4977 && GET_CODE (XEXP (x, 0)) == UNSPEC)
4979 rtx addr = XVECEXP (XEXP (x, 0), 0, 0);
4980 int unspec = XINT (XEXP (x, 0), 1);
4981 const char *opstr = NULL;
4985 case UNSPEC_HW0_PCREL:
4997 case UNSPEC_HW0_LAST:
5000 case UNSPEC_HW1_LAST:
5001 case UNSPEC_HW1_LAST_PCREL:
5004 case UNSPEC_HW2_LAST:
5007 case UNSPEC_HW0_GOT:
5010 case UNSPEC_HW0_LAST_GOT:
5011 opstr = "hw0_last_got";
5013 case UNSPEC_HW1_LAST_GOT:
5014 opstr = "hw1_last_got";
5016 case UNSPEC_HW0_TLS_GD:
5017 opstr = "hw0_tls_gd";
5019 case UNSPEC_HW1_LAST_TLS_GD:
5020 opstr = "hw1_last_tls_gd";
5022 case UNSPEC_HW0_TLS_IE:
5023 opstr = "hw0_tls_ie";
5025 case UNSPEC_HW1_LAST_TLS_IE:
5026 opstr = "hw1_last_tls_ie";
5028 case UNSPEC_HW0_TLS_LE:
5029 opstr = "hw0_tls_le";
5031 case UNSPEC_HW1_LAST_TLS_LE:
5032 opstr = "hw1_last_tls_le";
5035 output_operand_lossage ("invalid %%H specifier");
5038 fputs (opstr, file);
5040 output_addr_const (file, addr);
5042 if (unspec == UNSPEC_HW0_PCREL
5043 || unspec == UNSPEC_HW1_LAST_PCREL)
5045 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
5046 fputs (" - " , file);
5047 output_addr_const (file, addr2);
5053 else if (symbolic_operand (x, VOIDmode))
5055 output_addr_const (file, x);
5063 /* Print the low 16 bits of a constant. */
5065 if (CONST_INT_P (x))
5067 else if (GET_CODE (x) == CONST_DOUBLE)
5068 i = CONST_DOUBLE_LOW (x);
5071 output_operand_lossage ("invalid %%h operand");
5074 i = trunc_int_for_mode (i, HImode);
5075 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
5080 /* Print an auto-inc memory operand. */
5083 output_operand_lossage ("invalid %%I operand");
5087 output_memory_reference_mode = GET_MODE (x);
5088 output_memory_autoinc_first = true;
5089 output_address (XEXP (x, 0));
5090 output_memory_reference_mode = VOIDmode;
5094 /* Print an auto-inc memory operand. */
5097 output_operand_lossage ("invalid %%i operand");
5101 output_memory_reference_mode = GET_MODE (x);
5102 output_memory_autoinc_first = false;
5103 output_address (XEXP (x, 0));
5104 output_memory_reference_mode = VOIDmode;
5109 /* Print the low 8 bits of a constant. */
5111 if (CONST_INT_P (x))
5113 else if (GET_CODE (x) == CONST_DOUBLE)
5114 i = CONST_DOUBLE_LOW (x);
5115 else if (GET_CODE (x) == CONST_VECTOR
5116 && CONST_INT_P (CONST_VECTOR_ELT (x, 0)))
5117 i = INTVAL (CONST_VECTOR_ELT (x, 0));
5120 output_operand_lossage ("invalid %%j operand");
5123 i = trunc_int_for_mode (i, QImode);
5124 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
5130 /* Print a constant plus one. */
5131 if (!CONST_INT_P (x))
5133 output_operand_lossage ("invalid %%P operand");
5136 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + 1);
5143 /* Print a bfextu-style bit range. */
5144 int first_bit, last_bit;
5145 HOST_WIDE_INT flip = (code == 'm') ? ~0 : 0;
5147 if (!CONST_INT_P (x)
5148 || !tilegx_bitfield_operand_p (INTVAL (x) ^ flip,
5149 &first_bit, &last_bit))
5151 output_operand_lossage ("invalid %%%c operand", code);
5155 fprintf (file, "%d, %d", first_bit, last_bit);
5161 const char *reg = NULL;
5163 /* Print a network register. */
5164 if (!CONST_INT_P (x))
5166 output_operand_lossage ("invalid %%N operand");
5172 case TILEGX_NETREG_IDN0: reg = "idn0"; break;
5173 case TILEGX_NETREG_IDN1: reg = "idn1"; break;
5174 case TILEGX_NETREG_UDN0: reg = "udn0"; break;
5175 case TILEGX_NETREG_UDN1: reg = "udn1"; break;
5176 case TILEGX_NETREG_UDN2: reg = "udn2"; break;
5177 case TILEGX_NETREG_UDN3: reg = "udn3"; break;
5182 fprintf (file, reg);
5187 if (GET_CODE (x) == SYMBOL_REF)
5189 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
5190 fprintf (file, "plt(");
5191 output_addr_const (file, x);
5192 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
5193 fprintf (file, ")");
5196 output_addr_const (file, x);
5200 /* In this case we need a register. Use 'zero' if the operand
5203 || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
5205 fputs ("zero", file);
5208 else if (!REG_P (x))
5210 output_operand_lossage ("invalid operand for 'r' specifier");
5218 fprintf (file, "%s", reg_names[REGNO (x)]);
5223 output_memory_reference_mode = VOIDmode;
5224 output_address (XEXP (x, 0));
5229 output_addr_const (file, x);
5235 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5240 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5242 tilegx_print_operand_address (FILE *file, rtx addr)
5244 if (GET_CODE (addr) == POST_DEC
5245 || GET_CODE (addr) == POST_INC)
5247 int offset = GET_MODE_SIZE (output_memory_reference_mode);
5249 gcc_assert (output_memory_reference_mode != VOIDmode);
5251 if (output_memory_autoinc_first)
5252 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
5254 fprintf (file, "%d",
5255 GET_CODE (addr) == POST_DEC ? -offset : offset);
5257 else if (GET_CODE (addr) == POST_MODIFY)
5259 gcc_assert (output_memory_reference_mode != VOIDmode);
5261 gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
5263 if (output_memory_autoinc_first)
5264 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
5266 fprintf (file, HOST_WIDE_INT_PRINT_DEC,
5267 INTVAL (XEXP (XEXP (addr, 1), 1)));
5270 tilegx_print_operand (file, addr, 'r');
5274 /* Machine mode of current insn, for determining curly brace
5276 static enum machine_mode insn_mode;
5279 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5281 tilegx_final_prescan_insn (rtx insn)
5283 /* Record this for tilegx_asm_output_opcode to examine. */
5284 insn_mode = GET_MODE (insn);
5288 /* While emitting asm, are we currently inside '{' for a bundle? */
5289 static bool tilegx_in_bundle = false;
5291 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5292 appropriate given the bundling information recorded by
5293 tilegx_gen_bundles. */
5295 tilegx_asm_output_opcode (FILE *stream, const char *code)
5297 bool pseudo = !strcmp (code, "pseudo");
5299 if (!tilegx_in_bundle && insn_mode == SImode)
5301 /* Start a new bundle. */
5302 fprintf (stream, "{\n\t");
5303 tilegx_in_bundle = true;
5306 if (tilegx_in_bundle && insn_mode == QImode)
5308 /* Close an existing bundle. */
5309 static char buf[100];
5311 gcc_assert (strlen (code) + 3 + 1 < sizeof (buf));
5313 strcpy (buf, pseudo ? "" : code);
5314 strcat (buf, "\n\t}");
5315 tilegx_in_bundle = false;
5321 return pseudo ? "" : code;
5326 /* Output assembler code to FILE to increment profiler label # LABELNO
5327 for profiling a function entry. */
5329 tilegx_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
5331 if (tilegx_in_bundle)
5333 fprintf (file, "\t}\n");
5342 "\t}\n", MCOUNT_NAME);
5350 "\t}\n", MCOUNT_NAME);
5353 tilegx_in_bundle = false;
5357 /* Implement TARGET_ASM_FILE_END. */
5359 tilegx_file_end (void)
5361 if (NEED_INDICATE_EXEC_STACK)
5362 file_end_indicate_exec_stack ();
5367 #undef TARGET_HAVE_TLS
5368 #define TARGET_HAVE_TLS HAVE_AS_TLS
5370 #undef TARGET_OPTION_OVERRIDE
5371 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5373 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5374 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5376 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5377 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5379 #undef TARGET_CANNOT_FORCE_CONST_MEM
5380 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5382 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5383 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5385 #undef TARGET_PASS_BY_REFERENCE
5386 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5388 #undef TARGET_RETURN_IN_MEMORY
5389 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5391 #undef TARGET_MODE_REP_EXTENDED
5392 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5394 #undef TARGET_FUNCTION_ARG_BOUNDARY
5395 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5397 #undef TARGET_FUNCTION_ARG
5398 #define TARGET_FUNCTION_ARG tilegx_function_arg
5400 #undef TARGET_FUNCTION_ARG_ADVANCE
5401 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5403 #undef TARGET_FUNCTION_VALUE
5404 #define TARGET_FUNCTION_VALUE tilegx_function_value
5406 #undef TARGET_LIBCALL_VALUE
5407 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5409 #undef TARGET_FUNCTION_VALUE_REGNO_P
5410 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5412 #undef TARGET_PROMOTE_FUNCTION_MODE
5413 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5415 #undef TARGET_PROMOTE_PROTOTYPES
5416 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5418 #undef TARGET_BUILD_BUILTIN_VA_LIST
5419 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5421 #undef TARGET_EXPAND_BUILTIN_VA_START
5422 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5424 #undef TARGET_SETUP_INCOMING_VARARGS
5425 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5427 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5428 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5430 #undef TARGET_RTX_COSTS
5431 #define TARGET_RTX_COSTS tilegx_rtx_costs
5433 #undef TARGET_SHIFT_TRUNCATION_MASK
5434 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5436 #undef TARGET_INIT_LIBFUNCS
5437 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5439 /* Limit to what we can reach in one addli. */
5440 #undef TARGET_MIN_ANCHOR_OFFSET
5441 #define TARGET_MIN_ANCHOR_OFFSET -32768
5442 #undef TARGET_MAX_ANCHOR_OFFSET
5443 #define TARGET_MAX_ANCHOR_OFFSET 32767
5445 #undef TARGET_LEGITIMATE_CONSTANT_P
5446 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5448 #undef TARGET_LEGITIMATE_ADDRESS_P
5449 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5451 #undef TARGET_LEGITIMIZE_ADDRESS
5452 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5454 #undef TARGET_DELEGITIMIZE_ADDRESS
5455 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5457 #undef TARGET_INIT_BUILTINS
5458 #define TARGET_INIT_BUILTINS tilegx_init_builtins
5460 #undef TARGET_BUILTIN_DECL
5461 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5463 #undef TARGET_EXPAND_BUILTIN
5464 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5466 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5467 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5469 #undef TARGET_FRAME_POINTER_REQUIRED
5470 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5472 #undef TARGET_DELAY_SCHED2
5473 #define TARGET_DELAY_SCHED2 true
5475 #undef TARGET_DELAY_VARTRACK
5476 #define TARGET_DELAY_VARTRACK true
5478 #undef TARGET_SCHED_ISSUE_RATE
5479 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5481 #undef TARGET_SCHED_ADJUST_COST
5482 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5484 #undef TARGET_MACHINE_DEPENDENT_REORG
5485 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5487 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5488 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5489 hook_bool_const_tree_hwi_hwi_const_tree_true
5491 #undef TARGET_ASM_OUTPUT_MI_THUNK
5492 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5494 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5495 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5497 #undef TARGET_TRAMPOLINE_INIT
5498 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5500 #undef TARGET_PRINT_OPERAND
5501 #define TARGET_PRINT_OPERAND tilegx_print_operand
5503 #undef TARGET_PRINT_OPERAND_ADDRESS
5504 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5506 #undef TARGET_ASM_FILE_END
5507 #define TARGET_ASM_FILE_END tilegx_file_end
5509 #undef TARGET_ASM_ALIGNED_DI_OP
5510 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5513 struct gcc_target targetm = TARGET_INITIALIZER;
5515 #include "gt-tilegx.h"