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 /* 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
1339 constant into DEST_REG.
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);
2056 /* Expand the muldi pattern. */
2058 tilegx_expand_muldi (rtx op0, rtx op1, rtx op2)
2060 if (CONST_INT_P (op2))
2062 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), DImode);
2063 return tilegx_expand_const_muldi (op0, op1, n);
2069 /* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the
2070 operands, and SIGN is true if it's a signed multiply, and false if
2071 it's an unsigned multiply. */
2073 tilegx_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign)
2075 rtx tmp0 = gen_reg_rtx (DImode);
2076 rtx tmp1 = gen_reg_rtx (DImode);
2077 rtx tmp2 = gen_reg_rtx (DImode);
2078 rtx tmp3 = gen_reg_rtx (DImode);
2079 rtx tmp4 = gen_reg_rtx (DImode);
2080 rtx tmp5 = gen_reg_rtx (DImode);
2081 rtx tmp6 = gen_reg_rtx (DImode);
2082 rtx tmp7 = gen_reg_rtx (DImode);
2083 rtx tmp8 = gen_reg_rtx (DImode);
2084 rtx tmp9 = gen_reg_rtx (DImode);
2085 rtx tmp10 = gen_reg_rtx (DImode);
2086 rtx tmp11 = gen_reg_rtx (DImode);
2087 rtx tmp12 = gen_reg_rtx (DImode);
2088 rtx tmp13 = gen_reg_rtx (DImode);
2089 rtx result_lo = gen_reg_rtx (DImode);
2093 emit_insn (gen_insn_mul_hs_lu (tmp0, op1, op2));
2094 emit_insn (gen_insn_mul_hs_lu (tmp1, op2, op1));
2095 emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2));
2096 emit_insn (gen_insn_mul_hs_hs (tmp3, op1, op2));
2100 emit_insn (gen_insn_mul_hu_lu (tmp0, op1, op2));
2101 emit_insn (gen_insn_mul_hu_lu (tmp1, op2, op1));
2102 emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2));
2103 emit_insn (gen_insn_mul_hu_hu (tmp3, op1, op2));
2106 emit_move_insn (tmp4, (gen_rtx_ASHIFT (DImode, tmp0, GEN_INT (32))));
2108 emit_move_insn (tmp5, (gen_rtx_ASHIFT (DImode, tmp1, GEN_INT (32))));
2110 emit_move_insn (tmp6, (gen_rtx_PLUS (DImode, tmp4, tmp5)));
2111 emit_move_insn (result_lo, (gen_rtx_PLUS (DImode, tmp2, tmp6)));
2113 emit_move_insn (tmp7, gen_rtx_LTU (DImode, tmp6, tmp4));
2114 emit_move_insn (tmp8, gen_rtx_LTU (DImode, result_lo, tmp2));
2118 emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (DImode, tmp0, GEN_INT (32))));
2119 emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (DImode, tmp1, GEN_INT (32))));
2123 emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (DImode, tmp0, GEN_INT (32))));
2124 emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (DImode, tmp1, GEN_INT (32))));
2127 emit_move_insn (tmp11, (gen_rtx_PLUS (DImode, tmp3, tmp7)));
2128 emit_move_insn (tmp12, (gen_rtx_PLUS (DImode, tmp8, tmp9)));
2129 emit_move_insn (tmp13, (gen_rtx_PLUS (DImode, tmp11, tmp12)));
2130 emit_move_insn (result, (gen_rtx_PLUS (DImode, tmp13, tmp10)));
2134 /* Implement smuldi3_highpart. */
2136 tilegx_expand_smuldi3_highpart (rtx op0, rtx op1, rtx op2)
2138 tilegx_expand_high_multiply (op0, op1, op2, true);
2142 /* Implement umuldi3_highpart. */
2144 tilegx_expand_umuldi3_highpart (rtx op0, rtx op1, rtx op2)
2146 tilegx_expand_high_multiply (op0, op1, op2, false);
2151 /* Compare and branches */
2153 /* Produce the rtx yielding a bool for a floating point
2156 tilegx_emit_fp_setcc (rtx res, enum rtx_code code, enum machine_mode mode,
2159 /* TODO: Certain compares again constants can be done using entirely
2160 integer operations. But you have to get the special cases right
2161 e.g. NaN, +0 == -0, etc. */
2165 rtx a = force_reg (DImode, gen_lowpart (DImode, op0));
2166 rtx b = force_reg (DImode, gen_lowpart (DImode, op1));
2168 flags = gen_reg_rtx (DImode);
2172 emit_insn (gen_insn_fsingle_add1 (flags, a, b));
2176 gcc_assert (mode == DFmode);
2177 emit_insn (gen_insn_fdouble_add_flags (flags, a, b));
2182 case EQ: flag_index = 30; break;
2183 case NE: flag_index = 31; break;
2184 case LE: flag_index = 27; break;
2185 case LT: flag_index = 26; break;
2186 case GE: flag_index = 29; break;
2187 case GT: flag_index = 28; break;
2188 default: gcc_unreachable ();
2191 gcc_assert (GET_MODE (res) == DImode);
2192 emit_move_insn (res, gen_rtx_ZERO_EXTRACT (DImode, flags, GEN_INT (1),
2193 GEN_INT (flag_index)));
2198 /* Certain simplifications can be done to make invalid setcc
2199 operations valid. Return the final comparison, or NULL if we can't
2202 tilegx_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1,
2203 enum machine_mode cmp_mode)
2208 if (cmp_mode == SFmode || cmp_mode == DFmode)
2209 return tilegx_emit_fp_setcc (res, code, cmp_mode, op0, op1);
2211 /* The general case: fold the comparison code to the types of
2212 compares that we have, choosing the branch as necessary. */
2222 /* We have these compares. */
2229 /* We do not have these compares, so we reverse the
2235 /* We should not have called this with any other code. */
2241 code = swap_condition (code);
2242 tmp = op0, op0 = op1, op1 = tmp;
2245 if (!reg_or_0_operand (op0, cmp_mode))
2246 op0 = force_reg (cmp_mode, op0);
2248 if (!CONST_INT_P (op1) && !register_operand (op1, cmp_mode))
2249 op1 = force_reg (cmp_mode, op1);
2251 /* Return the setcc comparison. */
2252 emit_insn (gen_rtx_SET (VOIDmode, res,
2253 gen_rtx_fmt_ee (code, DImode, op0, op1)));
2259 /* Implement cstore patterns. */
2261 tilegx_emit_setcc (rtx operands[], enum machine_mode cmp_mode)
2264 tilegx_emit_setcc_internal (operands[0], GET_CODE (operands[1]),
2265 operands[2], operands[3], cmp_mode);
2269 /* Return whether CODE is a signed comparison. */
2271 signed_compare_p (enum rtx_code code)
2273 return (code == EQ || code == NE || code == LT || code == LE
2274 || code == GT || code == GE);
2278 /* Generate the comparison for a DImode conditional branch. */
2280 tilegx_emit_cc_test (enum rtx_code code, rtx op0, rtx op1,
2281 enum machine_mode cmp_mode, bool eq_ne_only)
2283 enum rtx_code branch_code;
2286 if (cmp_mode == SFmode || cmp_mode == DFmode)
2288 /* Compute a boolean saying whether the comparison is true. */
2289 temp = gen_reg_rtx (DImode);
2290 tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2292 /* Test that flag. */
2293 return gen_rtx_fmt_ee (NE, VOIDmode, temp, const0_rtx);
2296 /* Check for a compare against zero using a comparison we can do
2298 if (op1 == const0_rtx
2299 && (code == EQ || code == NE
2300 || (!eq_ne_only && signed_compare_p (code))))
2302 op0 = force_reg (cmp_mode, op0);
2303 return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx);
2306 /* The general case: fold the comparison code to the types of
2307 compares that we have, choosing the branch as necessary. */
2315 /* We have these compares. */
2324 /* These must be reversed (except NE, but let's
2326 code = reverse_condition (code);
2334 if (CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU))
2336 HOST_WIDE_INT n = INTVAL (op1);
2341 /* Subtract off the value we want to compare against and see
2342 if we get zero. This is cheaper than creating a constant
2343 in a register. Except that subtracting -128 is more
2344 expensive than seqi to -128, so we leave that alone. */
2345 /* ??? Don't do this when comparing against symbols,
2346 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2347 0), which will be declared false out of hand (at least
2350 && add_operand (GEN_INT (-n), DImode)
2351 && !(symbolic_operand (op0, VOIDmode)
2352 || (REG_P (op0) && REG_POINTER (op0))))
2354 /* TODO: Use a SIMD add immediate to hit zero for tiled
2355 constants in a single instruction. */
2356 if (GET_MODE (op0) != DImode)
2358 /* Convert to DImode so we can use addli. Note that
2359 this will not actually generate any code because
2360 sign extension from SI -> DI is a no-op. I don't
2361 know if it's safe just to make a paradoxical
2362 subreg here though. */
2363 rtx temp2 = gen_reg_rtx (DImode);
2364 emit_insn (gen_extendsidi2 (temp2, op0));
2369 op0 = force_reg (DImode, op0);
2371 temp = gen_reg_rtx (DImode);
2372 emit_move_insn (temp, gen_rtx_PLUS (DImode, op0, GEN_INT (-n)));
2373 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2374 VOIDmode, temp, const0_rtx);
2384 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2385 We use arithmetic shift right because it's a 3-wide op,
2386 while logical shift right is not. */
2388 int first = exact_log2 (code == LTU ? n : n + 1);
2391 op0 = force_reg (cmp_mode, op0);
2392 temp = gen_reg_rtx (cmp_mode);
2393 emit_move_insn (temp,
2394 gen_rtx_ASHIFTRT (cmp_mode, op0,
2396 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2397 VOIDmode, temp, const0_rtx);
2407 /* Compute a flag saying whether we should branch. */
2408 temp = gen_reg_rtx (DImode);
2409 tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2411 /* Return the branch comparison. */
2412 return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx);
2416 /* Generate the comparison for a conditional branch. */
2418 tilegx_emit_conditional_branch (rtx operands[], enum machine_mode cmp_mode)
2421 tilegx_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2],
2423 rtx branch_rtx = gen_rtx_SET (VOIDmode, pc_rtx,
2424 gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx,
2429 emit_jump_insn (branch_rtx);
2433 /* Implement the mov<mode>cc pattern. */
2435 tilegx_emit_conditional_move (rtx cmp)
2438 tilegx_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1),
2439 GET_MODE (XEXP (cmp, 0)), true);
2443 /* Return true if INSN is annotated with a REG_BR_PROB note that
2444 indicates it's a branch that's predicted taken. */
2446 cbranch_predicted_p (rtx insn)
2448 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2452 int pred_val = INTVAL (XEXP (x, 0));
2454 return pred_val >= REG_BR_PROB_BASE / 2;
2461 /* Output assembly code for a specific branch instruction, appending
2462 the branch prediction flag to the opcode if appropriate. */
2464 tilegx_output_simple_cbranch_with_opcode (rtx insn, const char *opcode,
2465 int regop, bool reverse_predicted)
2467 static char buf[64];
2468 sprintf (buf, "%s%s\t%%r%d, %%l0", opcode,
2469 (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "",
2475 /* Output assembly code for a specific branch instruction, appending
2476 the branch prediction flag to the opcode if appropriate. */
2478 tilegx_output_cbranch_with_opcode (rtx insn, rtx *operands,
2480 const char *rev_opcode, int regop)
2482 const char *branch_if_false;
2483 rtx taken, not_taken;
2484 bool is_simple_branch;
2486 gcc_assert (LABEL_P (operands[0]));
2488 is_simple_branch = true;
2489 if (INSN_ADDRESSES_SET_P ())
2491 int from_addr = INSN_ADDRESSES (INSN_UID (insn));
2492 int to_addr = INSN_ADDRESSES (INSN_UID (operands[0]));
2493 int delta = to_addr - from_addr;
2494 is_simple_branch = IN_RANGE (delta, -524288, 524280);
2497 if (is_simple_branch)
2499 /* Just a simple conditional branch. */
2501 tilegx_output_simple_cbranch_with_opcode (insn, opcode, regop, false);
2504 /* Generate a reversed branch around a direct jump. This fallback
2505 does not use branch-likely instructions. */
2506 not_taken = gen_label_rtx ();
2507 taken = operands[0];
2509 /* Generate the reversed branch to NOT_TAKEN. */
2510 operands[0] = not_taken;
2512 tilegx_output_simple_cbranch_with_opcode (insn, rev_opcode, regop, true);
2513 output_asm_insn (branch_if_false, operands);
2515 output_asm_insn ("j\t%l0", &taken);
2517 /* Output NOT_TAKEN. */
2518 targetm.asm_out.internal_label (asm_out_file, "L",
2519 CODE_LABEL_NUMBER (not_taken));
2524 /* Output assembly code for a conditional branch instruction. */
2526 tilegx_output_cbranch (rtx insn, rtx *operands, bool reversed)
2528 enum rtx_code code = GET_CODE (operands[1]);
2530 const char *rev_opcode;
2533 code = reverse_condition (code);
2539 rev_opcode = "beqz";
2543 rev_opcode = "bnez";
2547 rev_opcode = "bltz";
2551 rev_opcode = "blez";
2555 rev_opcode = "bgtz";
2559 rev_opcode = "bgez";
2565 return tilegx_output_cbranch_with_opcode (insn, operands, opcode,
2570 /* Implement the tablejump pattern. */
2572 tilegx_expand_tablejump (rtx op0, rtx op1)
2576 rtx temp = gen_reg_rtx (Pmode);
2577 rtx temp2 = gen_reg_rtx (Pmode);
2579 compute_pcrel_address (temp, gen_rtx_LABEL_REF (Pmode, op1));
2580 emit_move_insn (temp2,
2581 gen_rtx_PLUS (Pmode,
2582 convert_to_mode (Pmode, op0, false),
2587 emit_jump_insn (gen_tablejump_aux (op0, op1));
2591 /* Emit barrier before an atomic, as needed for the memory MODEL. */
2593 tilegx_pre_atomic_barrier (enum memmodel model)
2597 case MEMMODEL_RELAXED:
2598 case MEMMODEL_CONSUME:
2599 case MEMMODEL_ACQUIRE:
2601 case MEMMODEL_RELEASE:
2602 case MEMMODEL_ACQ_REL:
2603 case MEMMODEL_SEQ_CST:
2604 emit_insn (gen_memory_barrier ());
2612 /* Emit barrier after an atomic, as needed for the memory MODEL. */
2614 tilegx_post_atomic_barrier (enum memmodel model)
2618 case MEMMODEL_RELAXED:
2619 case MEMMODEL_CONSUME:
2620 case MEMMODEL_RELEASE:
2622 case MEMMODEL_ACQUIRE:
2623 case MEMMODEL_ACQ_REL:
2624 case MEMMODEL_SEQ_CST:
2625 emit_insn (gen_memory_barrier ());
2634 /* Expand a builtin vector binary op, by calling gen function GEN with
2635 operands in the proper modes. DEST is converted to DEST_MODE, and
2636 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2638 tilegx_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx),
2639 enum machine_mode dest_mode,
2641 enum machine_mode src_mode,
2642 rtx src0, rtx src1, bool do_src1)
2644 dest = gen_lowpart (dest_mode, dest);
2646 if (src0 == const0_rtx)
2647 src0 = CONST0_RTX (src_mode);
2649 src0 = gen_lowpart (src_mode, src0);
2653 if (src1 == const0_rtx)
2654 src1 = CONST0_RTX (src_mode);
2656 src1 = gen_lowpart (src_mode, src1);
2659 emit_insn ((*gen) (dest, src0, src1));
2667 struct tile_builtin_info
2669 enum insn_code icode;
2673 static struct tile_builtin_info tilegx_builtin_info[TILEGX_BUILTIN_max] = {
2674 { CODE_FOR_adddi3, NULL }, /* add */
2675 { CODE_FOR_addsi3, NULL }, /* addx */
2676 { CODE_FOR_ssaddsi3, NULL }, /* addxsc */
2677 { CODE_FOR_anddi3, NULL }, /* and */
2678 { CODE_FOR_insn_bfexts, NULL }, /* bfexts */
2679 { CODE_FOR_insn_bfextu, NULL }, /* bfextu */
2680 { CODE_FOR_insn_bfins, NULL }, /* bfins */
2681 { CODE_FOR_clzdi2, NULL }, /* clz */
2682 { CODE_FOR_insn_cmoveqz, NULL }, /* cmoveqz */
2683 { CODE_FOR_insn_cmovnez, NULL }, /* cmovnez */
2684 { CODE_FOR_insn_cmpeq_didi, NULL }, /* cmpeq */
2685 { CODE_FOR_insn_cmpexch, NULL }, /* cmpexch */
2686 { CODE_FOR_insn_cmpexch4, NULL }, /* cmpexch4 */
2687 { CODE_FOR_insn_cmples_didi, NULL }, /* cmples */
2688 { CODE_FOR_insn_cmpleu_didi, NULL }, /* cmpleu */
2689 { CODE_FOR_insn_cmplts_didi, NULL }, /* cmplts */
2690 { CODE_FOR_insn_cmpltu_didi, NULL }, /* cmpltu */
2691 { CODE_FOR_insn_cmpne_didi, NULL }, /* cmpne */
2692 { CODE_FOR_insn_cmul, NULL }, /* cmul */
2693 { CODE_FOR_insn_cmula, NULL }, /* cmula */
2694 { CODE_FOR_insn_cmulaf, NULL }, /* cmulaf */
2695 { CODE_FOR_insn_cmulf, NULL }, /* cmulf */
2696 { CODE_FOR_insn_cmulfr, NULL }, /* cmulfr */
2697 { CODE_FOR_insn_cmulh, NULL }, /* cmulh */
2698 { CODE_FOR_insn_cmulhr, NULL }, /* cmulhr */
2699 { CODE_FOR_insn_crc32_32, NULL }, /* crc32_32 */
2700 { CODE_FOR_insn_crc32_8, NULL }, /* crc32_8 */
2701 { CODE_FOR_ctzdi2, NULL }, /* ctz */
2702 { CODE_FOR_insn_dblalign, NULL }, /* dblalign */
2703 { CODE_FOR_insn_dblalign2, NULL }, /* dblalign2 */
2704 { CODE_FOR_insn_dblalign4, NULL }, /* dblalign4 */
2705 { CODE_FOR_insn_dblalign6, NULL }, /* dblalign6 */
2706 { CODE_FOR_insn_drain, NULL }, /* drain */
2707 { CODE_FOR_insn_dtlbpr, NULL }, /* dtlbpr */
2708 { CODE_FOR_insn_exch, NULL }, /* exch */
2709 { CODE_FOR_insn_exch4, NULL }, /* exch4 */
2710 { CODE_FOR_insn_fdouble_add_flags, NULL }, /* fdouble_add_flags */
2711 { CODE_FOR_insn_fdouble_addsub, NULL }, /* fdouble_addsub */
2712 { CODE_FOR_insn_fdouble_mul_flags, NULL }, /* fdouble_mul_flags */
2713 { CODE_FOR_insn_fdouble_pack1, NULL }, /* fdouble_pack1 */
2714 { CODE_FOR_insn_fdouble_pack2, NULL }, /* fdouble_pack2 */
2715 { CODE_FOR_insn_fdouble_sub_flags, NULL }, /* fdouble_sub_flags */
2716 { CODE_FOR_insn_fdouble_unpack_max, NULL }, /* fdouble_unpack_max */
2717 { CODE_FOR_insn_fdouble_unpack_min, NULL }, /* fdouble_unpack_min */
2718 { CODE_FOR_insn_fetchadd, NULL }, /* fetchadd */
2719 { CODE_FOR_insn_fetchadd4, NULL }, /* fetchadd4 */
2720 { CODE_FOR_insn_fetchaddgez, NULL }, /* fetchaddgez */
2721 { CODE_FOR_insn_fetchaddgez4, NULL }, /* fetchaddgez4 */
2722 { CODE_FOR_insn_fetchand, NULL }, /* fetchand */
2723 { CODE_FOR_insn_fetchand4, NULL }, /* fetchand4 */
2724 { CODE_FOR_insn_fetchor, NULL }, /* fetchor */
2725 { CODE_FOR_insn_fetchor4, NULL }, /* fetchor4 */
2726 { CODE_FOR_insn_finv, NULL }, /* finv */
2727 { CODE_FOR_insn_flush, NULL }, /* flush */
2728 { CODE_FOR_insn_flushwb, NULL }, /* flushwb */
2729 { CODE_FOR_insn_fnop, NULL }, /* fnop */
2730 { CODE_FOR_insn_fsingle_add1, NULL }, /* fsingle_add1 */
2731 { CODE_FOR_insn_fsingle_addsub2, NULL }, /* fsingle_addsub2 */
2732 { CODE_FOR_insn_fsingle_mul1, NULL }, /* fsingle_mul1 */
2733 { CODE_FOR_insn_fsingle_mul2, NULL }, /* fsingle_mul2 */
2734 { CODE_FOR_insn_fsingle_pack1, NULL }, /* fsingle_pack1 */
2735 { CODE_FOR_insn_fsingle_pack2, NULL }, /* fsingle_pack2 */
2736 { CODE_FOR_insn_fsingle_sub1, NULL }, /* fsingle_sub1 */
2737 { CODE_FOR_insn_icoh, NULL }, /* icoh */
2738 { CODE_FOR_insn_ill, NULL }, /* ill */
2739 { CODE_FOR_insn_info, NULL }, /* info */
2740 { CODE_FOR_insn_infol, NULL }, /* infol */
2741 { CODE_FOR_insn_inv, NULL }, /* inv */
2742 { CODE_FOR_insn_ld, NULL }, /* ld */
2743 { CODE_FOR_insn_ld1s, NULL }, /* ld1s */
2744 { CODE_FOR_insn_ld1u, NULL }, /* ld1u */
2745 { CODE_FOR_insn_ld2s, NULL }, /* ld2s */
2746 { CODE_FOR_insn_ld2u, NULL }, /* ld2u */
2747 { CODE_FOR_insn_ld4s, NULL }, /* ld4s */
2748 { CODE_FOR_insn_ld4u, NULL }, /* ld4u */
2749 { CODE_FOR_insn_ldna, NULL }, /* ldna */
2750 { CODE_FOR_insn_ldnt, NULL }, /* ldnt */
2751 { CODE_FOR_insn_ldnt1s, NULL }, /* ldnt1s */
2752 { CODE_FOR_insn_ldnt1u, NULL }, /* ldnt1u */
2753 { CODE_FOR_insn_ldnt2s, NULL }, /* ldnt2s */
2754 { CODE_FOR_insn_ldnt2u, NULL }, /* ldnt2u */
2755 { CODE_FOR_insn_ldnt4s, NULL }, /* ldnt4s */
2756 { CODE_FOR_insn_ldnt4u, NULL }, /* ldnt4u */
2757 { CODE_FOR_insn_ld_L2, NULL }, /* ld_L2 */
2758 { CODE_FOR_insn_ld1s_L2, NULL }, /* ld1s_L2 */
2759 { CODE_FOR_insn_ld1u_L2, NULL }, /* ld1u_L2 */
2760 { CODE_FOR_insn_ld2s_L2, NULL }, /* ld2s_L2 */
2761 { CODE_FOR_insn_ld2u_L2, NULL }, /* ld2u_L2 */
2762 { CODE_FOR_insn_ld4s_L2, NULL }, /* ld4s_L2 */
2763 { CODE_FOR_insn_ld4u_L2, NULL }, /* ld4u_L2 */
2764 { CODE_FOR_insn_ldna_L2, NULL }, /* ldna_L2 */
2765 { CODE_FOR_insn_ldnt_L2, NULL }, /* ldnt_L2 */
2766 { CODE_FOR_insn_ldnt1s_L2, NULL }, /* ldnt1s_L2 */
2767 { CODE_FOR_insn_ldnt1u_L2, NULL }, /* ldnt1u_L2 */
2768 { CODE_FOR_insn_ldnt2s_L2, NULL }, /* ldnt2s_L2 */
2769 { CODE_FOR_insn_ldnt2u_L2, NULL }, /* ldnt2u_L2 */
2770 { CODE_FOR_insn_ldnt4s_L2, NULL }, /* ldnt4s_L2 */
2771 { CODE_FOR_insn_ldnt4u_L2, NULL }, /* ldnt4u_L2 */
2772 { CODE_FOR_insn_ld_miss, NULL }, /* ld_miss */
2773 { CODE_FOR_insn_ld1s_miss, NULL }, /* ld1s_miss */
2774 { CODE_FOR_insn_ld1u_miss, NULL }, /* ld1u_miss */
2775 { CODE_FOR_insn_ld2s_miss, NULL }, /* ld2s_miss */
2776 { CODE_FOR_insn_ld2u_miss, NULL }, /* ld2u_miss */
2777 { CODE_FOR_insn_ld4s_miss, NULL }, /* ld4s_miss */
2778 { CODE_FOR_insn_ld4u_miss, NULL }, /* ld4u_miss */
2779 { CODE_FOR_insn_ldna_miss, NULL }, /* ldna_miss */
2780 { CODE_FOR_insn_ldnt_miss, NULL }, /* ldnt_miss */
2781 { CODE_FOR_insn_ldnt1s_miss, NULL }, /* ldnt1s_miss */
2782 { CODE_FOR_insn_ldnt1u_miss, NULL }, /* ldnt1u_miss */
2783 { CODE_FOR_insn_ldnt2s_miss, NULL }, /* ldnt2s_miss */
2784 { CODE_FOR_insn_ldnt2u_miss, NULL }, /* ldnt2u_miss */
2785 { CODE_FOR_insn_ldnt4s_miss, NULL }, /* ldnt4s_miss */
2786 { CODE_FOR_insn_ldnt4u_miss, NULL }, /* ldnt4u_miss */
2787 { CODE_FOR_insn_lnk, NULL }, /* lnk */
2788 { CODE_FOR_memory_barrier, NULL }, /* mf */
2789 { CODE_FOR_insn_mfspr, NULL }, /* mfspr */
2790 { CODE_FOR_insn_mm, NULL }, /* mm */
2791 { CODE_FOR_insn_mnz, NULL }, /* mnz */
2792 { CODE_FOR_movdi, NULL }, /* move */
2793 { CODE_FOR_insn_mtspr, NULL }, /* mtspr */
2794 { CODE_FOR_insn_mul_hs_hs, NULL }, /* mul_hs_hs */
2795 { CODE_FOR_insn_mul_hs_hu, NULL }, /* mul_hs_hu */
2796 { CODE_FOR_insn_mul_hs_ls, NULL }, /* mul_hs_ls */
2797 { CODE_FOR_insn_mul_hs_lu, NULL }, /* mul_hs_lu */
2798 { CODE_FOR_insn_mul_hu_hu, NULL }, /* mul_hu_hu */
2799 { CODE_FOR_insn_mul_hu_ls, NULL }, /* mul_hu_ls */
2800 { CODE_FOR_insn_mul_hu_lu, NULL }, /* mul_hu_lu */
2801 { CODE_FOR_insn_mul_ls_ls, NULL }, /* mul_ls_ls */
2802 { CODE_FOR_insn_mul_ls_lu, NULL }, /* mul_ls_lu */
2803 { CODE_FOR_insn_mul_lu_lu, NULL }, /* mul_lu_lu */
2804 { CODE_FOR_insn_mula_hs_hs, NULL }, /* mula_hs_hs */
2805 { CODE_FOR_insn_mula_hs_hu, NULL }, /* mula_hs_hu */
2806 { CODE_FOR_insn_mula_hs_ls, NULL }, /* mula_hs_ls */
2807 { CODE_FOR_insn_mula_hs_lu, NULL }, /* mula_hs_lu */
2808 { CODE_FOR_insn_mula_hu_hu, NULL }, /* mula_hu_hu */
2809 { CODE_FOR_insn_mula_hu_ls, NULL }, /* mula_hu_ls */
2810 { CODE_FOR_insn_mula_hu_lu, NULL }, /* mula_hu_lu */
2811 { CODE_FOR_insn_mula_ls_ls, NULL }, /* mula_ls_ls */
2812 { CODE_FOR_insn_mula_ls_lu, NULL }, /* mula_ls_lu */
2813 { CODE_FOR_insn_mula_lu_lu, NULL }, /* mula_lu_lu */
2814 { CODE_FOR_insn_mulax, NULL }, /* mulax */
2815 { CODE_FOR_mulsi3, NULL }, /* mulx */
2816 { CODE_FOR_insn_mz, NULL }, /* mz */
2817 { CODE_FOR_insn_nap, NULL }, /* nap */
2818 { CODE_FOR_nop, NULL }, /* nop */
2819 { CODE_FOR_insn_nor_di, NULL }, /* nor */
2820 { CODE_FOR_iordi3, NULL }, /* or */
2821 { CODE_FOR_popcountdi2, NULL }, /* pcnt */
2822 { CODE_FOR_insn_prefetch_l1, NULL }, /* prefetch_l1 */
2823 { CODE_FOR_insn_prefetch_l1_fault, NULL }, /* prefetch_l1_fault */
2824 { CODE_FOR_insn_prefetch_l2, NULL }, /* prefetch_l2 */
2825 { CODE_FOR_insn_prefetch_l2_fault, NULL }, /* prefetch_l2_fault */
2826 { CODE_FOR_insn_prefetch_l3, NULL }, /* prefetch_l3 */
2827 { CODE_FOR_insn_prefetch_l3_fault, NULL }, /* prefetch_l3_fault */
2828 { CODE_FOR_insn_revbits, NULL }, /* revbits */
2829 { CODE_FOR_bswapdi2, NULL }, /* revbytes */
2830 { CODE_FOR_rotldi3, NULL }, /* rotl */
2831 { CODE_FOR_ashldi3, NULL }, /* shl */
2832 { CODE_FOR_insn_shl16insli, NULL }, /* shl16insli */
2833 { CODE_FOR_insn_shl1add, NULL }, /* shl1add */
2834 { CODE_FOR_insn_shl1addx, NULL }, /* shl1addx */
2835 { CODE_FOR_insn_shl2add, NULL }, /* shl2add */
2836 { CODE_FOR_insn_shl2addx, NULL }, /* shl2addx */
2837 { CODE_FOR_insn_shl3add, NULL }, /* shl3add */
2838 { CODE_FOR_insn_shl3addx, NULL }, /* shl3addx */
2839 { CODE_FOR_ashlsi3, NULL }, /* shlx */
2840 { CODE_FOR_ashrdi3, NULL }, /* shrs */
2841 { CODE_FOR_lshrdi3, NULL }, /* shru */
2842 { CODE_FOR_lshrsi3, NULL }, /* shrux */
2843 { CODE_FOR_insn_shufflebytes, NULL }, /* shufflebytes */
2844 { CODE_FOR_insn_st, NULL }, /* st */
2845 { CODE_FOR_insn_st1, NULL }, /* st1 */
2846 { CODE_FOR_insn_st2, NULL }, /* st2 */
2847 { CODE_FOR_insn_st4, NULL }, /* st4 */
2848 { CODE_FOR_insn_stnt, NULL }, /* stnt */
2849 { CODE_FOR_insn_stnt1, NULL }, /* stnt1 */
2850 { CODE_FOR_insn_stnt2, NULL }, /* stnt2 */
2851 { CODE_FOR_insn_stnt4, NULL }, /* stnt4 */
2852 { CODE_FOR_subdi3, NULL }, /* sub */
2853 { CODE_FOR_subsi3, NULL }, /* subx */
2854 { CODE_FOR_sssubsi3, NULL }, /* subxsc */
2855 { CODE_FOR_insn_tblidxb0, NULL }, /* tblidxb0 */
2856 { CODE_FOR_insn_tblidxb1, NULL }, /* tblidxb1 */
2857 { CODE_FOR_insn_tblidxb2, NULL }, /* tblidxb2 */
2858 { CODE_FOR_insn_tblidxb3, NULL }, /* tblidxb3 */
2859 { CODE_FOR_insn_v1add, NULL }, /* v1add */
2860 { CODE_FOR_insn_v1addi, NULL }, /* v1addi */
2861 { CODE_FOR_insn_v1adduc, NULL }, /* v1adduc */
2862 { CODE_FOR_insn_v1adiffu, NULL }, /* v1adiffu */
2863 { CODE_FOR_insn_v1avgu, NULL }, /* v1avgu */
2864 { CODE_FOR_insn_v1cmpeq, NULL }, /* v1cmpeq */
2865 { CODE_FOR_insn_v1cmpeqi, NULL }, /* v1cmpeqi */
2866 { CODE_FOR_insn_v1cmples, NULL }, /* v1cmples */
2867 { CODE_FOR_insn_v1cmpleu, NULL }, /* v1cmpleu */
2868 { CODE_FOR_insn_v1cmplts, NULL }, /* v1cmplts */
2869 { CODE_FOR_insn_v1cmpltsi, NULL }, /* v1cmpltsi */
2870 { CODE_FOR_insn_v1cmpltu, NULL }, /* v1cmpltu */
2871 { CODE_FOR_insn_v1cmpltui, NULL }, /* v1cmpltui */
2872 { CODE_FOR_insn_v1cmpne, NULL }, /* v1cmpne */
2873 { CODE_FOR_insn_v1ddotpu, NULL }, /* v1ddotpu */
2874 { CODE_FOR_insn_v1ddotpua, NULL }, /* v1ddotpua */
2875 { CODE_FOR_insn_v1ddotpus, NULL }, /* v1ddotpus */
2876 { CODE_FOR_insn_v1ddotpusa, NULL }, /* v1ddotpusa */
2877 { CODE_FOR_insn_v1dotp, NULL }, /* v1dotp */
2878 { CODE_FOR_insn_v1dotpa, NULL }, /* v1dotpa */
2879 { CODE_FOR_insn_v1dotpu, NULL }, /* v1dotpu */
2880 { CODE_FOR_insn_v1dotpua, NULL }, /* v1dotpua */
2881 { CODE_FOR_insn_v1dotpus, NULL }, /* v1dotpus */
2882 { CODE_FOR_insn_v1dotpusa, NULL }, /* v1dotpusa */
2883 { CODE_FOR_insn_v1int_h, NULL }, /* v1int_h */
2884 { CODE_FOR_insn_v1int_l, NULL }, /* v1int_l */
2885 { CODE_FOR_insn_v1maxu, NULL }, /* v1maxu */
2886 { CODE_FOR_insn_v1maxui, NULL }, /* v1maxui */
2887 { CODE_FOR_insn_v1minu, NULL }, /* v1minu */
2888 { CODE_FOR_insn_v1minui, NULL }, /* v1minui */
2889 { CODE_FOR_insn_v1mnz, NULL }, /* v1mnz */
2890 { CODE_FOR_insn_v1multu, NULL }, /* v1multu */
2891 { CODE_FOR_insn_v1mulu, NULL }, /* v1mulu */
2892 { CODE_FOR_insn_v1mulus, NULL }, /* v1mulus */
2893 { CODE_FOR_insn_v1mz, NULL }, /* v1mz */
2894 { CODE_FOR_insn_v1sadau, NULL }, /* v1sadau */
2895 { CODE_FOR_insn_v1sadu, NULL }, /* v1sadu */
2896 { CODE_FOR_insn_v1shl, NULL }, /* v1shl */
2897 { CODE_FOR_insn_v1shl, NULL }, /* v1shli */
2898 { CODE_FOR_insn_v1shrs, NULL }, /* v1shrs */
2899 { CODE_FOR_insn_v1shrs, NULL }, /* v1shrsi */
2900 { CODE_FOR_insn_v1shru, NULL }, /* v1shru */
2901 { CODE_FOR_insn_v1shru, NULL }, /* v1shrui */
2902 { CODE_FOR_insn_v1sub, NULL }, /* v1sub */
2903 { CODE_FOR_insn_v1subuc, NULL }, /* v1subuc */
2904 { CODE_FOR_insn_v2add, NULL }, /* v2add */
2905 { CODE_FOR_insn_v2addi, NULL }, /* v2addi */
2906 { CODE_FOR_insn_v2addsc, NULL }, /* v2addsc */
2907 { CODE_FOR_insn_v2adiffs, NULL }, /* v2adiffs */
2908 { CODE_FOR_insn_v2avgs, NULL }, /* v2avgs */
2909 { CODE_FOR_insn_v2cmpeq, NULL }, /* v2cmpeq */
2910 { CODE_FOR_insn_v2cmpeqi, NULL }, /* v2cmpeqi */
2911 { CODE_FOR_insn_v2cmples, NULL }, /* v2cmples */
2912 { CODE_FOR_insn_v2cmpleu, NULL }, /* v2cmpleu */
2913 { CODE_FOR_insn_v2cmplts, NULL }, /* v2cmplts */
2914 { CODE_FOR_insn_v2cmpltsi, NULL }, /* v2cmpltsi */
2915 { CODE_FOR_insn_v2cmpltu, NULL }, /* v2cmpltu */
2916 { CODE_FOR_insn_v2cmpltui, NULL }, /* v2cmpltui */
2917 { CODE_FOR_insn_v2cmpne, NULL }, /* v2cmpne */
2918 { CODE_FOR_insn_v2dotp, NULL }, /* v2dotp */
2919 { CODE_FOR_insn_v2dotpa, NULL }, /* v2dotpa */
2920 { CODE_FOR_insn_v2int_h, NULL }, /* v2int_h */
2921 { CODE_FOR_insn_v2int_l, NULL }, /* v2int_l */
2922 { CODE_FOR_insn_v2maxs, NULL }, /* v2maxs */
2923 { CODE_FOR_insn_v2maxsi, NULL }, /* v2maxsi */
2924 { CODE_FOR_insn_v2mins, NULL }, /* v2mins */
2925 { CODE_FOR_insn_v2minsi, NULL }, /* v2minsi */
2926 { CODE_FOR_insn_v2mnz, NULL }, /* v2mnz */
2927 { CODE_FOR_insn_v2mulfsc, NULL }, /* v2mulfsc */
2928 { CODE_FOR_insn_v2muls, NULL }, /* v2muls */
2929 { CODE_FOR_insn_v2mults, NULL }, /* v2mults */
2930 { CODE_FOR_insn_v2mz, NULL }, /* v2mz */
2931 { CODE_FOR_insn_v2packh, NULL }, /* v2packh */
2932 { CODE_FOR_insn_v2packl, NULL }, /* v2packl */
2933 { CODE_FOR_insn_v2packuc, NULL }, /* v2packuc */
2934 { CODE_FOR_insn_v2sadas, NULL }, /* v2sadas */
2935 { CODE_FOR_insn_v2sadau, NULL }, /* v2sadau */
2936 { CODE_FOR_insn_v2sads, NULL }, /* v2sads */
2937 { CODE_FOR_insn_v2sadu, NULL }, /* v2sadu */
2938 { CODE_FOR_insn_v2shl, NULL }, /* v2shl */
2939 { CODE_FOR_insn_v2shl, NULL }, /* v2shli */
2940 { CODE_FOR_insn_v2shlsc, NULL }, /* v2shlsc */
2941 { CODE_FOR_insn_v2shrs, NULL }, /* v2shrs */
2942 { CODE_FOR_insn_v2shrs, NULL }, /* v2shrsi */
2943 { CODE_FOR_insn_v2shru, NULL }, /* v2shru */
2944 { CODE_FOR_insn_v2shru, NULL }, /* v2shrui */
2945 { CODE_FOR_insn_v2sub, NULL }, /* v2sub */
2946 { CODE_FOR_insn_v2subsc, NULL }, /* v2subsc */
2947 { CODE_FOR_insn_v4add, NULL }, /* v4add */
2948 { CODE_FOR_insn_v4addsc, NULL }, /* v4addsc */
2949 { CODE_FOR_insn_v4int_h, NULL }, /* v4int_h */
2950 { CODE_FOR_insn_v4int_l, NULL }, /* v4int_l */
2951 { CODE_FOR_insn_v4packsc, NULL }, /* v4packsc */
2952 { CODE_FOR_insn_v4shl, NULL }, /* v4shl */
2953 { CODE_FOR_insn_v4shlsc, NULL }, /* v4shlsc */
2954 { CODE_FOR_insn_v4shrs, NULL }, /* v4shrs */
2955 { CODE_FOR_insn_v4shru, NULL }, /* v4shru */
2956 { CODE_FOR_insn_v4sub, NULL }, /* v4sub */
2957 { CODE_FOR_insn_v4subsc, NULL }, /* v4subsc */
2958 { CODE_FOR_insn_wh64, NULL }, /* wh64 */
2959 { CODE_FOR_xordi3, NULL }, /* xor */
2960 { CODE_FOR_tilegx_network_barrier, NULL }, /* network_barrier */
2961 { CODE_FOR_tilegx_idn0_receive, NULL }, /* idn0_receive */
2962 { CODE_FOR_tilegx_idn1_receive, NULL }, /* idn1_receive */
2963 { CODE_FOR_tilegx_idn_send, NULL }, /* idn_send */
2964 { CODE_FOR_tilegx_udn0_receive, NULL }, /* udn0_receive */
2965 { CODE_FOR_tilegx_udn1_receive, NULL }, /* udn1_receive */
2966 { CODE_FOR_tilegx_udn2_receive, NULL }, /* udn2_receive */
2967 { CODE_FOR_tilegx_udn3_receive, NULL }, /* udn3_receive */
2968 { CODE_FOR_tilegx_udn_send, NULL }, /* udn_send */
2972 struct tilegx_builtin_def
2975 enum tilegx_builtin code;
2977 /* The first character is the return type. Subsequent characters
2978 are the argument types. See char_to_type. */
2983 static const struct tilegx_builtin_def tilegx_builtins[] = {
2984 { "__insn_add", TILEGX_INSN_ADD, true, "lll" },
2985 { "__insn_addi", TILEGX_INSN_ADD, true, "lll" },
2986 { "__insn_addli", TILEGX_INSN_ADD, true, "lll" },
2987 { "__insn_addx", TILEGX_INSN_ADDX, true, "iii" },
2988 { "__insn_addxi", TILEGX_INSN_ADDX, true, "iii" },
2989 { "__insn_addxli", TILEGX_INSN_ADDX, true, "iii" },
2990 { "__insn_addxsc", TILEGX_INSN_ADDXSC, true, "iii" },
2991 { "__insn_and", TILEGX_INSN_AND, true, "lll" },
2992 { "__insn_andi", TILEGX_INSN_AND, true, "lll" },
2993 { "__insn_bfexts", TILEGX_INSN_BFEXTS, true, "llll" },
2994 { "__insn_bfextu", TILEGX_INSN_BFEXTU, true, "llll" },
2995 { "__insn_bfins", TILEGX_INSN_BFINS, true, "lllll"},
2996 { "__insn_clz", TILEGX_INSN_CLZ, true, "ll" },
2997 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ, true, "llll" },
2998 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ, true, "llll" },
2999 { "__insn_cmpeq", TILEGX_INSN_CMPEQ, true, "lll" },
3000 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ, true, "lll" },
3001 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH, false, "lpl" },
3002 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4, false, "ipi" },
3003 { "__insn_cmples", TILEGX_INSN_CMPLES, true, "lll" },
3004 { "__insn_cmpleu", TILEGX_INSN_CMPLEU, true, "lll" },
3005 { "__insn_cmplts", TILEGX_INSN_CMPLTS, true, "lll" },
3006 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS, true, "lll" },
3007 { "__insn_cmpltu", TILEGX_INSN_CMPLTU, true, "lll" },
3008 { "__insn_cmpltui", TILEGX_INSN_CMPLTU, true, "lll" },
3009 { "__insn_cmpne", TILEGX_INSN_CMPNE, true, "lll" },
3010 { "__insn_cmul", TILEGX_INSN_CMUL, true, "lll" },
3011 { "__insn_cmula", TILEGX_INSN_CMULA, true, "llll" },
3012 { "__insn_cmulaf", TILEGX_INSN_CMULAF, true, "llll" },
3013 { "__insn_cmulf", TILEGX_INSN_CMULF, true, "lll" },
3014 { "__insn_cmulfr", TILEGX_INSN_CMULFR, true, "lll" },
3015 { "__insn_cmulh", TILEGX_INSN_CMULH, true, "lll" },
3016 { "__insn_cmulhr", TILEGX_INSN_CMULHR, true, "lll" },
3017 { "__insn_crc32_32", TILEGX_INSN_CRC32_32, true, "lll" },
3018 { "__insn_crc32_8", TILEGX_INSN_CRC32_8, true, "lll" },
3019 { "__insn_ctz", TILEGX_INSN_CTZ, true, "ll" },
3020 { "__insn_dblalign", TILEGX_INSN_DBLALIGN, true, "lllk" },
3021 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2, true, "lll" },
3022 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4, true, "lll" },
3023 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6, true, "lll" },
3024 { "__insn_drain", TILEGX_INSN_DRAIN, false, "v" },
3025 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR, false, "vl" },
3026 { "__insn_exch", TILEGX_INSN_EXCH, false, "lpl" },
3027 { "__insn_exch4", TILEGX_INSN_EXCH4, false, "ipi" },
3028 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS, true, "lll" },
3029 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB, true, "llll" },
3030 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS, true, "lll" },
3031 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1, true, "lll" },
3032 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2, true, "llll" },
3033 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS, true, "lll" },
3034 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX, true, "lll" },
3035 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN, true, "lll" },
3036 { "__insn_fetchadd", TILEGX_INSN_FETCHADD, false, "lpl" },
3037 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4, false, "ipi" },
3038 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ, false, "lpl" },
3039 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4, false, "ipi" },
3040 { "__insn_fetchand", TILEGX_INSN_FETCHAND, false, "lpl" },
3041 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4, false, "ipi" },
3042 { "__insn_fetchor", TILEGX_INSN_FETCHOR, false, "lpl" },
3043 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4, false, "ipi" },
3044 { "__insn_finv", TILEGX_INSN_FINV, false, "vk" },
3045 { "__insn_flush", TILEGX_INSN_FLUSH, false, "vk" },
3046 { "__insn_flushwb", TILEGX_INSN_FLUSHWB, false, "v" },
3047 { "__insn_fnop", TILEGX_INSN_FNOP, false, "v" },
3048 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1, true, "lll" },
3049 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2, true, "llll" },
3050 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1, true, "lll" },
3051 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2, true, "lll" },
3052 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1, true, "ll" },
3053 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2, true, "lll" },
3054 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1, true, "lll" },
3055 { "__insn_icoh", TILEGX_INSN_ICOH, false, "vk" },
3056 { "__insn_ill", TILEGX_INSN_ILL, false, "v" },
3057 { "__insn_info", TILEGX_INSN_INFO, false, "vl" },
3058 { "__insn_infol", TILEGX_INSN_INFOL, false, "vl" },
3059 { "__insn_inv", TILEGX_INSN_INV, false, "vp" },
3060 { "__insn_ld", TILEGX_INSN_LD, false, "lk" },
3061 { "__insn_ld1s", TILEGX_INSN_LD1S, false, "lk" },
3062 { "__insn_ld1u", TILEGX_INSN_LD1U, false, "lk" },
3063 { "__insn_ld2s", TILEGX_INSN_LD2S, false, "lk" },
3064 { "__insn_ld2u", TILEGX_INSN_LD2U, false, "lk" },
3065 { "__insn_ld4s", TILEGX_INSN_LD4S, false, "lk" },
3066 { "__insn_ld4u", TILEGX_INSN_LD4U, false, "lk" },
3067 { "__insn_ldna", TILEGX_INSN_LDNA, false, "lk" },
3068 { "__insn_ldnt", TILEGX_INSN_LDNT, false, "lk" },
3069 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S, false, "lk" },
3070 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U, false, "lk" },
3071 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S, false, "lk" },
3072 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U, false, "lk" },
3073 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S, false, "lk" },
3074 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U, false, "lk" },
3075 { "__insn_ld_L2", TILEGX_INSN_LD_L2, false, "lk" },
3076 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2, false, "lk" },
3077 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2, false, "lk" },
3078 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2, false, "lk" },
3079 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2, false, "lk" },
3080 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2, false, "lk" },
3081 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2, false, "lk" },
3082 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2, false, "lk" },
3083 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2, false, "lk" },
3084 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2, false, "lk" },
3085 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2, false, "lk" },
3086 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2, false, "lk" },
3087 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2, false, "lk" },
3088 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2, false, "lk" },
3089 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2, false, "lk" },
3090 { "__insn_ld_miss", TILEGX_INSN_LD_MISS, false, "lk" },
3091 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS, false, "lk" },
3092 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS, false, "lk" },
3093 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS, false, "lk" },
3094 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS, false, "lk" },
3095 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS, false, "lk" },
3096 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS, false, "lk" },
3097 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS, false, "lk" },
3098 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS, false, "lk" },
3099 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS, false, "lk" },
3100 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS, false, "lk" },
3101 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS, false, "lk" },
3102 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS, false, "lk" },
3103 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS, false, "lk" },
3104 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS, false, "lk" },
3105 { "__insn_lnk", TILEGX_INSN_LNK, true, "l" },
3106 { "__insn_mf", TILEGX_INSN_MF, false, "v" },
3107 { "__insn_mfspr", TILEGX_INSN_MFSPR, false, "ll" },
3108 { "__insn_mm", TILEGX_INSN_MM, true, "lllll"},
3109 { "__insn_mnz", TILEGX_INSN_MNZ, true, "lll" },
3110 { "__insn_move", TILEGX_INSN_MOVE, true, "ll" },
3111 { "__insn_movei", TILEGX_INSN_MOVE, true, "ll" },
3112 { "__insn_moveli", TILEGX_INSN_MOVE, true, "ll" },
3113 { "__insn_mtspr", TILEGX_INSN_MTSPR, false, "vll" },
3114 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS, true, "lll" },
3115 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU, true, "lll" },
3116 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS, true, "lll" },
3117 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU, true, "lll" },
3118 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU, true, "lll" },
3119 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS, true, "lll" },
3120 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU, true, "lll" },
3121 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS, true, "lll" },
3122 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU, true, "lll" },
3123 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU, true, "lll" },
3124 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS, true, "llll" },
3125 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU, true, "llll" },
3126 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS, true, "llll" },
3127 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU, true, "llll" },
3128 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU, true, "llll" },
3129 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS, true, "llll" },
3130 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU, true, "llll" },
3131 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS, true, "llll" },
3132 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU, true, "llll" },
3133 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU, true, "llll" },
3134 { "__insn_mulax", TILEGX_INSN_MULAX, true, "iiii" },
3135 { "__insn_mulx", TILEGX_INSN_MULX, true, "iii" },
3136 { "__insn_mz", TILEGX_INSN_MZ, true, "lll" },
3137 { "__insn_nap", TILEGX_INSN_NAP, false, "v" },
3138 { "__insn_nop", TILEGX_INSN_NOP, true, "v" },
3139 { "__insn_nor", TILEGX_INSN_NOR, true, "lll" },
3140 { "__insn_or", TILEGX_INSN_OR, true, "lll" },
3141 { "__insn_ori", TILEGX_INSN_OR, true, "lll" },
3142 { "__insn_pcnt", TILEGX_INSN_PCNT, true, "ll" },
3143 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1, false, "vk" },
3144 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1, false, "vk" },
3145 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT, false, "vk" },
3146 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2, false, "vk" },
3147 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT, false, "vk" },
3148 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3, false, "vk" },
3149 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT, false, "vk" },
3150 { "__insn_revbits", TILEGX_INSN_REVBITS, true, "ll" },
3151 { "__insn_revbytes", TILEGX_INSN_REVBYTES, true, "ll" },
3152 { "__insn_rotl", TILEGX_INSN_ROTL, true, "lli" },
3153 { "__insn_rotli", TILEGX_INSN_ROTL, true, "lli" },
3154 { "__insn_shl", TILEGX_INSN_SHL, true, "lli" },
3155 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI, true, "lll" },
3156 { "__insn_shl1add", TILEGX_INSN_SHL1ADD, true, "lll" },
3157 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX, true, "iii" },
3158 { "__insn_shl2add", TILEGX_INSN_SHL2ADD, true, "lll" },
3159 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX, true, "iii" },
3160 { "__insn_shl3add", TILEGX_INSN_SHL3ADD, true, "lll" },
3161 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX, true, "iii" },
3162 { "__insn_shli", TILEGX_INSN_SHL, true, "lli" },
3163 { "__insn_shlx", TILEGX_INSN_SHLX, true, "iii" },
3164 { "__insn_shlxi", TILEGX_INSN_SHLX, true, "iii" },
3165 { "__insn_shrs", TILEGX_INSN_SHRS, true, "lli" },
3166 { "__insn_shrsi", TILEGX_INSN_SHRS, true, "lli" },
3167 { "__insn_shru", TILEGX_INSN_SHRU, true, "lli" },
3168 { "__insn_shrui", TILEGX_INSN_SHRU, true, "lli" },
3169 { "__insn_shrux", TILEGX_INSN_SHRUX, true, "iii" },
3170 { "__insn_shruxi", TILEGX_INSN_SHRUX, true, "iii" },
3171 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES, true, "llll" },
3172 { "__insn_st", TILEGX_INSN_ST, false, "vpl" },
3173 { "__insn_st1", TILEGX_INSN_ST1, false, "vpl" },
3174 { "__insn_st2", TILEGX_INSN_ST2, false, "vpl" },
3175 { "__insn_st4", TILEGX_INSN_ST4, false, "vpl" },
3176 { "__insn_stnt", TILEGX_INSN_STNT, false, "vpl" },
3177 { "__insn_stnt1", TILEGX_INSN_STNT1, false, "vpl" },
3178 { "__insn_stnt2", TILEGX_INSN_STNT2, false, "vpl" },
3179 { "__insn_stnt4", TILEGX_INSN_STNT4, false, "vpl" },
3180 { "__insn_sub", TILEGX_INSN_SUB, true, "lll" },
3181 { "__insn_subx", TILEGX_INSN_SUBX, true, "iii" },
3182 { "__insn_subxsc", TILEGX_INSN_SUBXSC, true, "iii" },
3183 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0, true, "lll" },
3184 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1, true, "lll" },
3185 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2, true, "lll" },
3186 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3, true, "lll" },
3187 { "__insn_v1add", TILEGX_INSN_V1ADD, true, "lll" },
3188 { "__insn_v1addi", TILEGX_INSN_V1ADDI, true, "lll" },
3189 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC, true, "lll" },
3190 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU, true, "lll" },
3191 { "__insn_v1avgu", TILEGX_INSN_V1AVGU, true, "lll" },
3192 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ, true, "lll" },
3193 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI, true, "lll" },
3194 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES, true, "lll" },
3195 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU, true, "lll" },
3196 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS, true, "lll" },
3197 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI, true, "lll" },
3198 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU, true, "lll" },
3199 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI, true, "lll" },
3200 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE, true, "lll" },
3201 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU, true, "lll" },
3202 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA, true, "llll" },
3203 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS, true, "lll" },
3204 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA, true, "llll" },
3205 { "__insn_v1dotp", TILEGX_INSN_V1DOTP, true, "lll" },
3206 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA, true, "llll" },
3207 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU, true, "lll" },
3208 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA, true, "llll" },
3209 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS, true, "lll" },
3210 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA, true, "llll" },
3211 { "__insn_v1int_h", TILEGX_INSN_V1INT_H, true, "lll" },
3212 { "__insn_v1int_l", TILEGX_INSN_V1INT_L, true, "lll" },
3213 { "__insn_v1maxu", TILEGX_INSN_V1MAXU, true, "lll" },
3214 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI, true, "lll" },
3215 { "__insn_v1minu", TILEGX_INSN_V1MINU, true, "lll" },
3216 { "__insn_v1minui", TILEGX_INSN_V1MINUI, true, "lll" },
3217 { "__insn_v1mnz", TILEGX_INSN_V1MNZ, true, "lll" },
3218 { "__insn_v1multu", TILEGX_INSN_V1MULTU, true, "lll" },
3219 { "__insn_v1mulu", TILEGX_INSN_V1MULU, true, "lll" },
3220 { "__insn_v1mulus", TILEGX_INSN_V1MULUS, true, "lll" },
3221 { "__insn_v1mz", TILEGX_INSN_V1MZ, true, "lll" },
3222 { "__insn_v1sadau", TILEGX_INSN_V1SADAU, true, "llll" },
3223 { "__insn_v1sadu", TILEGX_INSN_V1SADU, true, "lll" },
3224 { "__insn_v1shl", TILEGX_INSN_V1SHL, true, "lll" },
3225 { "__insn_v1shli", TILEGX_INSN_V1SHLI, true, "lll" },
3226 { "__insn_v1shrs", TILEGX_INSN_V1SHRS, true, "lll" },
3227 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI, true, "lll" },
3228 { "__insn_v1shru", TILEGX_INSN_V1SHRU, true, "lll" },
3229 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI, true, "lll" },
3230 { "__insn_v1sub", TILEGX_INSN_V1SUB, true, "lll" },
3231 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC, true, "lll" },
3232 { "__insn_v2add", TILEGX_INSN_V2ADD, true, "lll" },
3233 { "__insn_v2addi", TILEGX_INSN_V2ADDI, true, "lll" },
3234 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC, true, "lll" },
3235 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS, true, "lll" },
3236 { "__insn_v2avgs", TILEGX_INSN_V2AVGS, true, "lll" },
3237 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ, true, "lll" },
3238 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI, true, "lll" },
3239 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES, true, "lll" },
3240 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU, true, "lll" },
3241 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS, true, "lll" },
3242 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI, true, "lll" },
3243 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU, true, "lll" },
3244 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI, true, "lll" },
3245 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE, true, "lll" },
3246 { "__insn_v2dotp", TILEGX_INSN_V2DOTP, true, "lll" },
3247 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA, true, "llll" },
3248 { "__insn_v2int_h", TILEGX_INSN_V2INT_H, true, "lll" },
3249 { "__insn_v2int_l", TILEGX_INSN_V2INT_L, true, "lll" },
3250 { "__insn_v2maxs", TILEGX_INSN_V2MAXS, true, "lll" },
3251 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI, true, "lll" },
3252 { "__insn_v2mins", TILEGX_INSN_V2MINS, true, "lll" },
3253 { "__insn_v2minsi", TILEGX_INSN_V2MINSI, true, "lll" },
3254 { "__insn_v2mnz", TILEGX_INSN_V2MNZ, true, "lll" },
3255 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC, true, "lll" },
3256 { "__insn_v2muls", TILEGX_INSN_V2MULS, true, "lll" },
3257 { "__insn_v2mults", TILEGX_INSN_V2MULTS, true, "lll" },
3258 { "__insn_v2mz", TILEGX_INSN_V2MZ, true, "lll" },
3259 { "__insn_v2packh", TILEGX_INSN_V2PACKH, true, "lll" },
3260 { "__insn_v2packl", TILEGX_INSN_V2PACKL, true, "lll" },
3261 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC, true, "lll" },
3262 { "__insn_v2sadas", TILEGX_INSN_V2SADAS, true, "llll" },
3263 { "__insn_v2sadau", TILEGX_INSN_V2SADAU, true, "llll" },
3264 { "__insn_v2sads", TILEGX_INSN_V2SADS, true, "lll" },
3265 { "__insn_v2sadu", TILEGX_INSN_V2SADU, true, "lll" },
3266 { "__insn_v2shl", TILEGX_INSN_V2SHL, true, "lll" },
3267 { "__insn_v2shli", TILEGX_INSN_V2SHLI, true, "lll" },
3268 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC, true, "lll" },
3269 { "__insn_v2shrs", TILEGX_INSN_V2SHRS, true, "lll" },
3270 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI, true, "lll" },
3271 { "__insn_v2shru", TILEGX_INSN_V2SHRU, true, "lll" },
3272 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI, true, "lll" },
3273 { "__insn_v2sub", TILEGX_INSN_V2SUB, true, "lll" },
3274 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC, true, "lll" },
3275 { "__insn_v4add", TILEGX_INSN_V4ADD, true, "lll" },
3276 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC, true, "lll" },
3277 { "__insn_v4int_h", TILEGX_INSN_V4INT_H, true, "lll" },
3278 { "__insn_v4int_l", TILEGX_INSN_V4INT_L, true, "lll" },
3279 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC, true, "lll" },
3280 { "__insn_v4shl", TILEGX_INSN_V4SHL, true, "lll" },
3281 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC, true, "lll" },
3282 { "__insn_v4shrs", TILEGX_INSN_V4SHRS, true, "lll" },
3283 { "__insn_v4shru", TILEGX_INSN_V4SHRU, true, "lll" },
3284 { "__insn_v4sub", TILEGX_INSN_V4SUB, true, "lll" },
3285 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC, true, "lll" },
3286 { "__insn_wh64", TILEGX_INSN_WH64, false, "vp" },
3287 { "__insn_xor", TILEGX_INSN_XOR, true, "lll" },
3288 { "__insn_xori", TILEGX_INSN_XOR, true, "lll" },
3289 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER, false, "v" },
3290 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE, false, "l" },
3291 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE, false, "l" },
3292 { "__tile_idn_send", TILEGX_IDN_SEND, false, "vl" },
3293 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE, false, "l" },
3294 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE, false, "l" },
3295 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE, false, "l" },
3296 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE, false, "l" },
3297 { "__tile_udn_send", TILEGX_UDN_SEND, false, "vl" },
3301 /* Convert a character in a builtin type string to a tree type. */
3303 char_to_type (char c)
3305 static tree volatile_ptr_type_node = NULL;
3306 static tree volatile_const_ptr_type_node = NULL;
3308 if (volatile_ptr_type_node == NULL)
3310 volatile_ptr_type_node =
3311 build_pointer_type (build_qualified_type (void_type_node,
3312 TYPE_QUAL_VOLATILE));
3313 volatile_const_ptr_type_node =
3314 build_pointer_type (build_qualified_type (void_type_node,
3316 | TYPE_QUAL_VOLATILE));
3322 return void_type_node;
3324 return unsigned_type_node;
3326 return long_long_unsigned_type_node;
3328 return volatile_ptr_type_node;
3330 return volatile_const_ptr_type_node;
3337 /* Implement TARGET_INIT_BUILTINS. */
3339 tilegx_init_builtins (void)
3343 for (i = 0; i < ARRAY_SIZE (tilegx_builtins); i++)
3345 const struct tilegx_builtin_def *p = &tilegx_builtins[i];
3346 tree ftype, ret_type, arg_type_list = void_list_node;
3350 for (j = strlen (p->type) - 1; j > 0; j--)
3353 tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list);
3356 ret_type = char_to_type (p->type[0]);
3358 ftype = build_function_type (ret_type, arg_type_list);
3360 decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
3364 TREE_READONLY (decl) = 1;
3365 TREE_NOTHROW (decl) = 1;
3367 if (tilegx_builtin_info[p->code].fndecl == NULL)
3368 tilegx_builtin_info[p->code].fndecl = decl;
3373 /* Implement TARGET_EXPAND_BUILTIN. */
3375 tilegx_expand_builtin (tree exp,
3377 rtx subtarget ATTRIBUTE_UNUSED,
3378 enum machine_mode mode ATTRIBUTE_UNUSED,
3379 int ignore ATTRIBUTE_UNUSED)
3381 #define MAX_BUILTIN_ARGS 4
3383 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
3384 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
3386 call_expr_arg_iterator iter;
3387 enum insn_code icode;
3388 rtx op[MAX_BUILTIN_ARGS + 1], pat;
3393 if (fcode >= TILEGX_BUILTIN_max)
3394 internal_error ("bad builtin fcode");
3395 icode = tilegx_builtin_info[fcode].icode;
3397 internal_error ("bad builtin icode");
3399 nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
3402 FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
3404 const struct insn_operand_data *insn_op;
3406 if (arg == error_mark_node)
3408 if (opnum > MAX_BUILTIN_ARGS)
3411 insn_op = &insn_data[icode].operand[opnum];
3413 op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL);
3415 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3417 enum machine_mode opmode = insn_op->mode;
3419 /* pointer_operand and pmode_register_operand operands do
3420 not specify a mode, so use the operand's mode instead
3421 (which should always be right by the time we get here,
3422 except for constants, which are VOIDmode). */
3423 if (opmode == VOIDmode)
3425 enum machine_mode m = GET_MODE (op[opnum]);
3426 gcc_assert (m == Pmode || m == VOIDmode);
3430 op[opnum] = copy_to_mode_reg (opmode, op[opnum]);
3433 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3435 /* We still failed to meet the predicate even after moving
3436 into a register. Assume we needed an immediate. */
3437 error_at (EXPR_LOCATION (exp),
3438 "operand must be an immediate of the right size");
3447 enum machine_mode tmode = insn_data[icode].operand[0].mode;
3449 || GET_MODE (target) != tmode
3450 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
3452 if (tmode == VOIDmode)
3454 /* get the mode from the return type. */
3455 tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl)));
3457 target = gen_reg_rtx (tmode);
3462 fn = GEN_FCN (icode);
3466 pat = fn (NULL_RTX);
3472 pat = fn (op[0], op[1]);
3475 pat = fn (op[0], op[1], op[2]);
3478 pat = fn (op[0], op[1], op[2], op[3]);
3481 pat = fn (op[0], op[1], op[2], op[3], op[4]);
3497 /* Implement TARGET_BUILTIN_DECL. */
3499 tilegx_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
3501 if (code >= TILEGX_BUILTIN_max)
3502 return error_mark_node;
3504 return tilegx_builtin_info[code].fndecl;
3511 /* Return whether REGNO needs to be saved in the stack frame. */
3513 need_to_save_reg (unsigned int regno)
3515 if (!fixed_regs[regno] && !call_used_regs[regno]
3516 && df_regs_ever_live_p (regno))
3520 && (regno == PIC_OFFSET_TABLE_REGNUM
3521 || regno == TILEGX_PIC_TEXT_LABEL_REGNUM)
3522 && (crtl->uses_pic_offset_table || crtl->saves_all_registers))
3525 if (crtl->calls_eh_return)
3528 for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++)
3530 if (regno == EH_RETURN_DATA_REGNO (i))
3539 /* Return the size of the register savev area. This function is only
3540 correct starting with local register allocation */
3542 tilegx_saved_regs_size (void)
3544 int reg_save_size = 0;
3546 int offset_to_frame;
3549 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3550 if (need_to_save_reg (regno))
3551 reg_save_size += UNITS_PER_WORD;
3553 /* Pad out the register save area if necessary to make
3554 frame_pointer_rtx be as aligned as the stack pointer. */
3555 offset_to_frame = crtl->args.pretend_args_size + reg_save_size;
3556 align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1;
3557 reg_save_size += (-offset_to_frame) & align_mask;
3559 return reg_save_size;
3563 /* Round up frame size SIZE. */
3565 round_frame_size (int size)
3567 return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1)
3568 & -STACK_BOUNDARY / BITS_PER_UNIT);
3572 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3573 emit the corresponding REG_CFA_OFFSET note described by CFA and
3574 CFA_OFFSET. Return the emitted insn. */
3576 frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa,
3579 rtx reg = gen_rtx_REG (DImode, regno);
3580 rtx mem = gen_frame_mem (DImode, addr);
3581 rtx mov = gen_movdi (mem, reg);
3583 /* Describe what just happened in a way that dwarf understands. We
3584 use temporary registers to hold the address to make scheduling
3585 easier, and use the REG_CFA_OFFSET to describe the address as an
3586 offset from the CFA. */
3587 rtx reg_note = gen_rtx_REG (DImode, regno_note);
3588 rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, GEN_INT (cfa_offset));
3589 rtx cfa_relative_mem = gen_frame_mem (DImode, cfa_relative_addr);
3590 rtx real = gen_rtx_SET (VOIDmode, cfa_relative_mem, reg_note);
3591 add_reg_note (mov, REG_CFA_OFFSET, real);
3593 return emit_insn (mov);
3597 /* Emit a load in the stack frame to load REGNO from address ADDR.
3598 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3599 non-null. Return the emitted insn. */
3601 frame_emit_load (int regno, rtx addr, rtx *cfa_restores)
3603 rtx reg = gen_rtx_REG (DImode, regno);
3604 rtx mem = gen_frame_mem (DImode, addr);
3606 *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores);
3607 return emit_insn (gen_movdi (reg, mem));
3611 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3612 including sequences. */
3614 set_frame_related_p (void)
3616 rtx seq = get_insns ();
3627 while (insn != NULL_RTX)
3629 RTX_FRAME_RELATED_P (insn) = 1;
3630 insn = NEXT_INSN (insn);
3632 seq = emit_insn (seq);
3636 seq = emit_insn (seq);
3637 RTX_FRAME_RELATED_P (seq) = 1;
3643 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3645 /* This emits code for 'sp += offset'.
3647 The ABI only allows us to modify 'sp' in a single 'addi' or
3648 'addli', so the backtracer understands it. Larger amounts cannot
3649 use those instructions, so are added by placing the offset into a
3650 large register and using 'add'.
3652 This happens after reload, so we need to expand it ourselves. */
3654 emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related,
3658 rtx imm_rtx = GEN_INT (offset);
3661 if (satisfies_constraint_J (imm_rtx))
3663 /* We can add this using a single immediate add. */
3668 rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3669 tilegx_expand_set_const64 (tmp, imm_rtx);
3673 /* Actually adjust the stack pointer. */
3675 insn = gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx, to_add);
3677 insn = gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx, to_add);
3679 insn = emit_insn (insn);
3680 REG_NOTES (insn) = reg_notes;
3682 /* Describe what just happened in a way that dwarf understands. */
3685 rtx real = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
3686 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3688 RTX_FRAME_RELATED_P (insn) = 1;
3689 add_reg_note (insn, REG_CFA_ADJUST_CFA, real);
3696 /* Return whether the current function is leaf. This takes into
3697 account whether the function calls tls_get_addr. */
3699 tilegx_current_function_is_leaf (void)
3701 return current_function_is_leaf && !cfun->machine->calls_tls_get_addr;
3705 /* Return the frame size. */
3707 compute_total_frame_size (void)
3709 int total_size = (get_frame_size () + tilegx_saved_regs_size ()
3710 + crtl->outgoing_args_size
3711 + crtl->args.pretend_args_size);
3713 if (!tilegx_current_function_is_leaf () || cfun->calls_alloca)
3715 /* Make room for save area in callee. */
3716 total_size += STACK_POINTER_OFFSET;
3719 return round_frame_size (total_size);
3723 /* Return nonzero if this function is known to have a null epilogue.
3724 This allows the optimizer to omit jumps to jumps if no stack was
3727 tilegx_can_use_return_insn_p (void)
3729 return (reload_completed
3730 && cfun->static_chain_decl == 0
3731 && compute_total_frame_size () == 0
3732 && tilegx_current_function_is_leaf ()
3733 && !crtl->profile && !df_regs_ever_live_p (TILEGX_LINK_REGNUM));
3737 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3738 is a frame pointer, it computes the value relative to
3739 that. Otherwise it uses the stack pointer. */
3741 compute_frame_addr (int offset_from_fp, int *next_scratch_regno)
3743 rtx base_reg_rtx, tmp_reg_rtx, offset_rtx;
3744 int offset_from_base;
3746 if (frame_pointer_needed)
3748 base_reg_rtx = hard_frame_pointer_rtx;
3749 offset_from_base = offset_from_fp;
3753 int offset_from_sp = compute_total_frame_size () + offset_from_fp;
3754 offset_from_base = offset_from_sp;
3755 base_reg_rtx = stack_pointer_rtx;
3758 if (offset_from_base == 0)
3759 return base_reg_rtx;
3761 /* Compute the new value of the stack pointer. */
3762 tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3763 offset_rtx = GEN_INT (offset_from_base);
3765 if (!add_operand (offset_rtx, Pmode))
3767 expand_set_cint64 (tmp_reg_rtx, offset_rtx);
3768 offset_rtx = tmp_reg_rtx;
3771 emit_insn (gen_rtx_SET (VOIDmode, tmp_reg_rtx,
3772 gen_rtx_PLUS (Pmode, base_reg_rtx, offset_rtx)));
3778 /* The stack frame looks like this:
3783 AP -> +-------------+
3787 HFP -> +-------------+
3789 | reg save | crtl->args.pretend_args_size bytes
3792 | saved regs | tilegx_saved_regs_size() bytes
3793 FP -> +-------------+
3795 | vars | get_frame_size() bytes
3799 | stack args | crtl->outgoing_args_size bytes
3801 | HFP | ptr_size bytes (only here if nonleaf / alloca)
3803 | callee lr | ptr_size bytes (only here if nonleaf / alloca)
3805 SP -> +-------------+
3809 For functions with a frame larger than 32767 bytes, or which use
3810 alloca (), r52 is used as a frame pointer. Otherwise there is no
3813 FP is saved at SP+ptr_size before calling a subroutine so the callee
3816 tilegx_expand_prologue (void)
3818 #define ROUND_ROBIN_SIZE 4
3819 /* We round-robin through four scratch registers to hold temporary
3820 addresses for saving registers, to make instruction scheduling
3822 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3823 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3826 unsigned int which_scratch;
3827 int offset, start_offset, regno;
3829 /* A register that holds a copy of the incoming fp. */
3830 int fp_copy_regno = -1;
3832 /* A register that holds a copy of the incoming sp. */
3833 int sp_copy_regno = -1;
3835 /* Next scratch register number to hand out (postdecrementing). */
3836 int next_scratch_regno = 29;
3838 int total_size = compute_total_frame_size ();
3840 if (flag_stack_usage_info)
3841 current_function_static_stack_size = total_size;
3843 /* Save lr first in its special location because code after this
3844 might use the link register as a scratch register. */
3845 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM) || crtl->calls_eh_return)
3846 FRP (frame_emit_store (TILEGX_LINK_REGNUM, TILEGX_LINK_REGNUM,
3847 stack_pointer_rtx, stack_pointer_rtx, 0));
3849 if (total_size == 0)
3851 /* Load the PIC register if needed. */
3852 if (flag_pic && crtl->uses_pic_offset_table)
3853 load_pic_register (false);
3858 cfa = stack_pointer_rtx;
3860 if (frame_pointer_needed)
3862 fp_copy_regno = next_scratch_regno--;
3864 /* Copy the old frame pointer aside so we can save it later. */
3866 FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno),
3867 gen_lowpart (word_mode, hard_frame_pointer_rtx)));
3868 add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
3870 /* Set up the frame pointer. */
3871 insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
3872 add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx);
3873 cfa = hard_frame_pointer_rtx;
3874 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
3876 /* fp holds a copy of the incoming sp, in case we need to store
3878 sp_copy_regno = HARD_FRAME_POINTER_REGNUM;
3880 else if (!tilegx_current_function_is_leaf ())
3882 /* Copy the old stack pointer aside so we can save it later. */
3883 sp_copy_regno = next_scratch_regno--;
3884 insn = FRP (emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno),
3885 stack_pointer_rtx));
3886 add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
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 FRP (frame_emit_store (sp_copy_regno, STACK_POINTER_REGNUM,
3929 chain_addr, cfa, cfa_offset));
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 (crtl->calls_eh_return)
4072 rtx r = compute_frame_addr (-total_size + UNITS_PER_WORD,
4073 &next_scratch_regno);
4074 insn = emit_move_insn (gen_lowpart (DImode, stack_pointer_rtx),
4075 gen_frame_mem (DImode, r));
4076 RTX_FRAME_RELATED_P (insn) = 1;
4077 REG_NOTES (insn) = cfa_restores;
4079 else if (frame_pointer_needed)
4081 /* Restore the old stack pointer by copying from the frame
4085 insn = emit_insn (gen_sp_restore_32bit (stack_pointer_rtx,
4086 hard_frame_pointer_rtx));
4090 insn = emit_insn (gen_sp_restore (stack_pointer_rtx,
4091 hard_frame_pointer_rtx));
4093 RTX_FRAME_RELATED_P (insn) = 1;
4094 REG_NOTES (insn) = cfa_restores;
4095 add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx);
4099 insn = emit_sp_adjust (total_size, &next_scratch_regno, true,
4103 /* Restore the old frame pointer. */
4104 if (frame_pointer_needed)
4106 insn = emit_move_insn (gen_lowpart (DImode, hard_frame_pointer_rtx),
4107 gen_rtx_REG (DImode, fp_copy_regno));
4108 add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);
4111 /* Mark the pic registers as live outside of the function. */
4114 emit_use (cfun->machine->text_label_rtx);
4115 emit_use (cfun->machine->got_rtx);
4121 emit_jump_insn (gen__return ());
4125 emit_use (gen_rtx_REG (Pmode, TILEGX_LINK_REGNUM));
4128 /* Mark all insns we just emitted as frame-related. */
4129 for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn))
4130 RTX_FRAME_RELATED_P (last_insn) = 1;
4133 #undef ROUND_ROBIN_SIZE
4136 /* Implement INITIAL_ELIMINATION_OFFSET. */
4138 tilegx_initial_elimination_offset (int from, int to)
4140 int total_size = compute_total_frame_size ();
4142 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
4144 return (total_size - crtl->args.pretend_args_size
4145 - tilegx_saved_regs_size ());
4147 else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
4149 return -(crtl->args.pretend_args_size + tilegx_saved_regs_size ());
4151 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
4153 return STACK_POINTER_OFFSET + total_size;
4155 else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
4157 return STACK_POINTER_OFFSET;
4164 /* Return an RTX indicating where the return address to the calling
4165 function can be found. */
4167 tilegx_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
4172 return get_hard_reg_initial_val (Pmode, TILEGX_LINK_REGNUM);
4176 /* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to
4177 prevent it from being deleted. */
4179 tilegx_eh_return_handler_rtx (void)
4181 rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
4182 MEM_VOLATILE_P (tmp) = true;
4190 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
4192 tilegx_conditional_register_usage (void)
4194 global_regs[TILEGX_NETORDER_REGNUM] = 1;
4195 /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
4196 member of fixed_regs, and therefore must be member of
4197 call_used_regs, but it is not a member of call_really_used_regs[]
4198 because it is not clobbered by a call. */
4199 if (TILEGX_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM)
4201 fixed_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1;
4202 call_used_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1;
4204 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
4206 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
4207 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
4212 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
4214 tilegx_frame_pointer_required (void)
4216 return crtl->calls_eh_return || cfun->calls_alloca;
4221 /* Scheduling and reorg */
4223 /* Return the length of INSN. LENGTH is the initial length computed
4224 by attributes in the machine-description file. This is where we
4225 account for bundles. */
4227 tilegx_adjust_insn_length (rtx insn, int length)
4229 enum machine_mode mode = GET_MODE (insn);
4231 /* A non-termininating instruction in a bundle has length 0. */
4235 /* By default, there is not length adjustment. */
4240 /* Implement TARGET_SCHED_ISSUE_RATE. */
4242 tilegx_issue_rate (void)
4248 /* Return the rtx for the jump target. */
4250 get_jump_target (rtx branch)
4252 if (CALL_P (branch))
4255 call = PATTERN (branch);
4257 if (GET_CODE (call) == PARALLEL)
4258 call = XVECEXP (call, 0, 0);
4260 if (GET_CODE (call) == SET)
4261 call = SET_SRC (call);
4263 if (GET_CODE (call) == CALL)
4264 return XEXP (XEXP (call, 0), 0);
4269 /* Implement TARGET_SCHED_ADJUST_COST. */
4271 tilegx_sched_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
4273 /* If we have a true dependence, INSN is a call, and DEP_INSN
4274 defines a register that is needed by the call (argument or stack
4275 pointer) , set its latency to 0 so that it can be bundled with
4276 the call. Explicitly check for and exclude the case when
4277 DEP_INSN defines the target of the jump. */
4278 if (CALL_P (insn) && REG_NOTE_KIND (link) == REG_DEP_TRUE)
4280 rtx target = get_jump_target (insn);
4281 if (!REG_P (target) || !set_of (target, dep_insn))
4289 /* Skip over irrelevant NOTEs and such and look for the next insn we
4290 would consider bundling. */
4292 next_insn_to_bundle (rtx r, rtx end)
4294 for (; r != end; r = NEXT_INSN (r))
4296 if (NONDEBUG_INSN_P (r)
4297 && GET_CODE (PATTERN (r)) != USE
4298 && GET_CODE (PATTERN (r)) != CLOBBER)
4306 /* Go through all insns, and use the information generated during
4307 scheduling to generate SEQUENCEs to represent bundles of
4308 instructions issued simultaneously. */
4310 tilegx_gen_bundles (void)
4316 rtx end = NEXT_INSN (BB_END (bb));
4318 for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn; insn = next)
4320 next = next_insn_to_bundle (NEXT_INSN (insn), end);
4322 /* Never wrap {} around inline asm. */
4323 if (GET_CODE (PATTERN (insn)) != ASM_INPUT)
4325 if (next == NULL_RTX || GET_MODE (next) == TImode
4326 /* NOTE: The scheduler incorrectly believes a call
4327 insn can execute in the same cycle as the insn
4328 after the call. This is of course impossible.
4329 Really we need to fix the scheduler somehow, so
4330 the code after the call gets scheduled
4334 /* Mark current insn as the end of a bundle. */
4335 PUT_MODE (insn, QImode);
4339 /* Mark it as part of a bundle. */
4340 PUT_MODE (insn, SImode);
4348 /* Replace OLD_INSN with NEW_INSN. */
4350 replace_insns (rtx old_insn, rtx new_insns)
4353 emit_insn_before (new_insns, old_insn);
4355 delete_insn (old_insn);
4359 /* Returns true if INSN is the first instruction of a pc-relative
4360 address compuatation. */
4362 match_pcrel_step1 (rtx insn)
4364 rtx pattern = PATTERN (insn);
4367 if (GET_CODE (pattern) != SET)
4370 src = SET_SRC (pattern);
4372 return (GET_CODE (src) == CONST
4373 && GET_CODE (XEXP (src, 0)) == UNSPEC
4374 && XINT (XEXP (src, 0), 1) == UNSPEC_HW1_LAST_PCREL);
4378 /* Do the first replacement step in tilegx_fixup_pcrel_references. */
4380 replace_mov_pcrel_step1 (rtx insn)
4382 rtx pattern = PATTERN (insn);
4387 gcc_assert (GET_CODE (pattern) == SET);
4388 opnds[0] = SET_DEST (pattern);
4390 gcc_assert (GET_CODE (SET_SRC (pattern)) == CONST);
4392 unspec = XEXP (SET_SRC (pattern), 0);
4393 gcc_assert (GET_CODE (unspec) == UNSPEC);
4394 gcc_assert (XINT (unspec, 1) == UNSPEC_HW1_LAST_PCREL);
4395 opnds[1] = XVECEXP (unspec, 0, 0);
4397 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4398 if (GET_CODE (opnds[1]) != SYMBOL_REF)
4406 emit_insn (gen_mov_got32_step1_32bit (opnds[0], opnds[1]));
4408 emit_insn (gen_mov_got32_step1 (opnds[0], opnds[1]));
4411 new_insns = get_insns ();
4414 replace_insns (insn, new_insns);
4418 /* Returns true if INSN is the second instruction of a pc-relative
4419 address compuatation. */
4421 match_pcrel_step2 (rtx insn)
4428 if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli_32bit)
4433 if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli)
4437 unspec = SET_SRC (PATTERN (insn));
4438 addr = XVECEXP (unspec, 0, 1);
4440 return (GET_CODE (addr) == CONST
4441 && GET_CODE (XEXP (addr, 0)) == UNSPEC
4442 && XINT (XEXP (addr, 0), 1) == UNSPEC_HW0_PCREL);
4446 /* Do the second replacement step in tilegx_fixup_pcrel_references. */
4448 replace_mov_pcrel_step2 (rtx insn)
4450 rtx pattern = PATTERN (insn);
4455 rtx got_rtx = tilegx_got_rtx ();
4457 gcc_assert (GET_CODE (pattern) == SET);
4458 opnds[0] = SET_DEST (pattern);
4460 unspec = SET_SRC (pattern);
4461 gcc_assert (GET_CODE (unspec) == UNSPEC);
4462 gcc_assert (XINT (unspec, 1) == UNSPEC_INSN_ADDR_SHL16INSLI);
4464 opnds[1] = XVECEXP (unspec, 0, 0);
4466 addr = XVECEXP (unspec, 0, 1);
4467 gcc_assert (GET_CODE (addr) == CONST);
4469 unspec = XEXP (addr, 0);
4470 gcc_assert (GET_CODE (unspec) == UNSPEC);
4471 gcc_assert (XINT (unspec, 1) == UNSPEC_HW0_PCREL);
4472 opnds[2] = XVECEXP (unspec, 0, 0);
4474 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4475 if (GET_CODE (opnds[2]) != SYMBOL_REF)
4483 emit_insn (gen_add_got16_32bit (opnds[0], got_rtx, opnds[2]));
4485 emit_insn (gen_add_got16 (opnds[0], got_rtx, opnds[2]));
4490 emit_insn (gen_mov_got32_step2_32bit
4491 (opnds[0], opnds[1], opnds[2]));
4493 emit_insn (gen_mov_got32_step2 (opnds[0], opnds[1], opnds[2]));
4496 new_insns = get_insns ();
4499 replace_insns (insn, new_insns);
4503 /* Do the third replacement step in tilegx_fixup_pcrel_references. */
4505 replace_mov_pcrel_step3 (rtx insn)
4507 rtx pattern = PATTERN (insn);
4511 rtx got_rtx = tilegx_got_rtx ();
4512 rtx text_label_rtx = tilegx_text_label_rtx ();
4514 gcc_assert (GET_CODE (pattern) == SET);
4515 opnds[0] = SET_DEST (pattern);
4517 unspec = SET_SRC (pattern);
4518 gcc_assert (GET_CODE (unspec) == UNSPEC);
4519 gcc_assert (XINT (unspec, 1) == UNSPEC_MOV_PCREL_STEP3);
4523 if (XVECEXP (unspec, 0, 0) == text_label_rtx)
4524 opnds[2] = XVECEXP (unspec, 0, 1);
4527 gcc_assert (XVECEXP (unspec, 0, 1) == text_label_rtx);
4528 opnds[2] = XVECEXP (unspec, 0, 0);
4531 opnds[3] = XVECEXP (unspec, 0, 2);
4533 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4534 if (GET_CODE (opnds[3]) != SYMBOL_REF)
4541 emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[2]));
4545 emit_move_insn (opnds[0], gen_rtx_PLUS (Pmode, opnds[1], opnds[2]));
4546 emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[0]));
4549 new_insns = get_insns ();
4552 replace_insns (insn, new_insns);
4556 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4557 going through the GOT when the symbol is local to the compilation
4558 unit. But such a symbol requires that the common text_label that
4559 we generate at the beginning of the function be in the same section
4560 as the reference to the SYMBOL_REF. This may not be true if we
4561 generate hot/cold sections. This function looks for such cases and
4562 replaces such references with the longer sequence going through the
4565 We expect following instruction sequence:
4566 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4567 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4568 add<x> tmp3, txt_label_reg, tmp2 [3]
4570 If we're compiling -fpic, we replace with the following sequence
4571 (the numbers in brackets match the instructions they're replacing
4574 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4575 ld<4> tmp3, tmp2 [3]
4577 If we're compiling -fPIC, we replace the first instruction with:
4579 moveli tmp1, hw1_last_got(x) [1]
4580 shl16insli tmp2, tmp1, hw0_got(x) [2]
4581 add<x> tmp3, got_reg, tmp2 [3]
4582 ld<4> tmp3, tmp3 [3]
4584 Note that we're careful to disturb the instruction sequence as
4585 little as possible, since it's very late in the compilation
4588 tilegx_fixup_pcrel_references (void)
4590 rtx insn, next_insn;
4591 bool same_section_as_entry = true;
4593 for (insn = get_insns (); insn; insn = next_insn)
4595 next_insn = NEXT_INSN (insn);
4597 if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
4599 same_section_as_entry = !same_section_as_entry;
4603 if (same_section_as_entry)
4607 && GET_CODE (PATTERN (insn)) != USE
4608 && GET_CODE (PATTERN (insn)) != CLOBBER))
4613 if (match_pcrel_step1 (insn))
4614 replace_mov_pcrel_step1 (insn);
4615 else if (match_pcrel_step2 (insn))
4616 replace_mov_pcrel_step2 (insn);
4617 else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3_32bit)
4618 replace_mov_pcrel_step3 (insn);
4622 if (match_pcrel_step1 (insn))
4623 replace_mov_pcrel_step1 (insn);
4624 else if (match_pcrel_step2 (insn))
4625 replace_mov_pcrel_step2 (insn);
4626 else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3)
4627 replace_mov_pcrel_step3 (insn);
4633 /* Ensure that no var tracking notes are emitted in the middle of a
4634 three-instruction bundle. */
4636 reorder_var_tracking_notes (void)
4642 rtx queue = NULL_RTX;
4643 bool in_bundle = false;
4645 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4647 next = NEXT_INSN (insn);
4651 /* Emit queued up notes at the last instruction of a
4653 if (GET_MODE (insn) == QImode)
4657 rtx next_queue = PREV_INSN (queue);
4658 PREV_INSN (NEXT_INSN (insn)) = queue;
4659 NEXT_INSN (queue) = NEXT_INSN (insn);
4660 NEXT_INSN (insn) = queue;
4661 PREV_INSN (queue) = insn;
4666 else if (GET_MODE (insn) == SImode)
4669 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4673 rtx prev = PREV_INSN (insn);
4674 PREV_INSN (next) = prev;
4675 NEXT_INSN (prev) = next;
4677 PREV_INSN (insn) = queue;
4686 /* Perform machine dependent operations on the rtl chain INSNS. */
4690 /* We are freeing block_for_insn in the toplev to keep compatibility
4691 with old MDEP_REORGS that are not CFG based. Recompute it
4693 compute_bb_for_insn ();
4695 if (flag_reorder_blocks_and_partition)
4697 tilegx_fixup_pcrel_references ();
4700 if (flag_schedule_insns_after_reload)
4704 timevar_push (TV_SCHED2);
4706 timevar_pop (TV_SCHED2);
4708 /* Examine the schedule to group into bundles. */
4709 tilegx_gen_bundles ();
4714 if (flag_var_tracking)
4716 timevar_push (TV_VAR_TRACKING);
4717 variable_tracking_main ();
4718 reorder_var_tracking_notes ();
4719 timevar_pop (TV_VAR_TRACKING);
4722 df_finish_pass (false);
4729 /* Select a format to encode pointers in exception handling data.
4730 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4731 GLOBAL is true if the symbol may be affected by dynamic
4734 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
4738 int type = TARGET_32BIT ? DW_EH_PE_sdata4 : DW_EH_PE_sdata8;
4739 return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type;
4742 return DW_EH_PE_absptr;
4746 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4748 tilegx_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
4749 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
4752 rtx this_rtx, insn, funexp, addend;
4754 /* Pretend to be a post-reload pass while generating rtl. */
4755 reload_completed = 1;
4757 /* Mark the end of the (empty) prologue. */
4758 emit_note (NOTE_INSN_PROLOGUE_END);
4760 /* Find the "this" pointer. If the function returns a structure,
4761 the structure return pointer is in $1. */
4762 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
4763 this_rtx = gen_rtx_REG (Pmode, 1);
4765 this_rtx = gen_rtx_REG (Pmode, 0);
4767 /* Add DELTA to THIS_RTX. */
4768 if (!(delta >= -32868 && delta <= 32767))
4770 addend = gen_rtx_REG (Pmode, 29);
4771 emit_move_insn (addend, GEN_INT (delta));
4774 addend = GEN_INT (delta);
4777 emit_insn (gen_addsi3 (this_rtx, this_rtx, addend));
4779 emit_insn (gen_adddi3 (this_rtx, this_rtx, addend));
4781 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4786 tmp = gen_rtx_REG (Pmode, 29);
4787 emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx));
4789 if (!(vcall_offset >= -32868 && vcall_offset <= 32767))
4791 addend = gen_rtx_REG (Pmode, 28);
4792 emit_move_insn (addend, GEN_INT (vcall_offset));
4795 addend = GEN_INT (vcall_offset);
4798 emit_insn (gen_addsi3 (tmp, tmp, addend));
4800 emit_insn (gen_adddi3 (tmp, tmp, addend));
4802 emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
4805 emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp));
4807 emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp));
4810 /* Generate a tail call to the target function. */
4811 if (!TREE_USED (function))
4813 assemble_external (function);
4814 TREE_USED (function) = 1;
4816 funexp = XEXP (DECL_RTL (function), 0);
4817 funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
4818 insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
4819 SIBLING_CALL_P (insn) = 1;
4821 /* Run just enough of rest_of_compilation to get the insns emitted.
4822 There's not really enough bulk here to make other passes such as
4823 instruction scheduling worth while. Note that use_thunk calls
4824 assemble_start_function and assemble_end_function.
4826 We don't currently bundle, but the instruciton sequence is all
4827 serial except for the tail call, so we're only wasting one cycle.
4829 insn = get_insns ();
4830 insn_locators_alloc ();
4831 shorten_branches (insn);
4832 final_start_function (insn, file, 1);
4833 final (insn, file, 1);
4834 final_end_function ();
4836 /* Stop pretending to be a post-reload pass. */
4837 reload_completed = 0;
4841 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
4843 tilegx_asm_trampoline_template (FILE *file)
4845 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4848 fprintf (file, "\tlnk r10\n");
4849 fprintf (file, "\taddxi r10, r10, 32\n");
4850 fprintf (file, "\tld4s_add r11, r10, %d\n", ptr_mode_size);
4851 fprintf (file, "\tld4s r10, r10\n");
4852 fprintf (file, "\tjr r11\n");
4853 fprintf (file, "\t.word 0 # <function address>\n");
4854 fprintf (file, "\t.word 0 # <static chain value>\n");
4858 fprintf (file, "\tlnk r10\n");
4859 fprintf (file, "\taddi r10, r10, 32\n");
4860 fprintf (file, "\tld_add r11, r10, %d\n", ptr_mode_size);
4861 fprintf (file, "\tld r10, r10\n");
4862 fprintf (file, "\tjr r11\n");
4863 fprintf (file, "\t.quad 0 # <function address>\n");
4864 fprintf (file, "\t.quad 0 # <static chain value>\n");
4869 /* Implement TARGET_TRAMPOLINE_INIT. */
4871 tilegx_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
4875 rtx begin_addr, end_addr;
4876 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4878 fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
4879 chaddr = copy_to_reg (static_chain);
4881 emit_block_move (m_tramp, assemble_trampoline_template (),
4882 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
4884 mem = adjust_address (m_tramp, ptr_mode,
4885 TRAMPOLINE_SIZE - 2 * ptr_mode_size);
4886 emit_move_insn (mem, fnaddr);
4887 mem = adjust_address (m_tramp, ptr_mode,
4888 TRAMPOLINE_SIZE - ptr_mode_size);
4889 emit_move_insn (mem, chaddr);
4891 /* Get pointers to the beginning and end of the code block. */
4892 begin_addr = force_reg (Pmode, XEXP (m_tramp, 0));
4893 end_addr = force_reg (Pmode, plus_constant (XEXP (m_tramp, 0),
4896 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
4897 LCT_NORMAL, VOIDmode, 2, begin_addr, Pmode,
4902 /* Implement TARGET_PRINT_OPERAND. */
4904 tilegx_print_operand (FILE *file, rtx x, int code)
4909 /* Print the compare operator opcode for conditional moves. */
4910 switch (GET_CODE (x))
4919 output_operand_lossage ("invalid %%c operand");
4924 /* Print the compare operator opcode for conditional moves. */
4925 switch (GET_CODE (x))
4934 output_operand_lossage ("invalid %%C operand");
4940 /* Print the compare operator opcode for conditional moves. */
4941 switch (GET_CODE (x))
4950 output_operand_lossage ("invalid %%d operand");
4957 /* Print the compare operator opcode for conditional moves. */
4958 switch (GET_CODE (x))
4967 output_operand_lossage ("invalid %%D operand");
4974 if (GET_CODE (x) == CONST
4975 && GET_CODE (XEXP (x, 0)) == UNSPEC)
4977 rtx addr = XVECEXP (XEXP (x, 0), 0, 0);
4978 int unspec = XINT (XEXP (x, 0), 1);
4979 const char *opstr = NULL;
4983 case UNSPEC_HW0_PCREL:
4995 case UNSPEC_HW0_LAST:
4998 case UNSPEC_HW1_LAST:
4999 case UNSPEC_HW1_LAST_PCREL:
5002 case UNSPEC_HW2_LAST:
5005 case UNSPEC_HW0_GOT:
5008 case UNSPEC_HW0_LAST_GOT:
5009 opstr = "hw0_last_got";
5011 case UNSPEC_HW1_LAST_GOT:
5012 opstr = "hw1_last_got";
5014 case UNSPEC_HW0_TLS_GD:
5015 opstr = "hw0_tls_gd";
5017 case UNSPEC_HW1_LAST_TLS_GD:
5018 opstr = "hw1_last_tls_gd";
5020 case UNSPEC_HW0_TLS_IE:
5021 opstr = "hw0_tls_ie";
5023 case UNSPEC_HW1_LAST_TLS_IE:
5024 opstr = "hw1_last_tls_ie";
5026 case UNSPEC_HW0_TLS_LE:
5027 opstr = "hw0_tls_le";
5029 case UNSPEC_HW1_LAST_TLS_LE:
5030 opstr = "hw1_last_tls_le";
5033 output_operand_lossage ("invalid %%H specifier");
5036 fputs (opstr, file);
5038 output_addr_const (file, addr);
5040 if (unspec == UNSPEC_HW0_PCREL
5041 || unspec == UNSPEC_HW1_LAST_PCREL)
5043 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
5044 fputs (" - " , file);
5045 output_addr_const (file, addr2);
5051 else if (symbolic_operand (x, VOIDmode))
5053 output_addr_const (file, x);
5061 /* Print the low 16 bits of a constant. */
5063 if (CONST_INT_P (x))
5065 else if (GET_CODE (x) == CONST_DOUBLE)
5066 i = CONST_DOUBLE_LOW (x);
5069 output_operand_lossage ("invalid %%h operand");
5072 i = trunc_int_for_mode (i, HImode);
5073 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
5078 /* Print an auto-inc memory operand. */
5081 output_operand_lossage ("invalid %%I operand");
5085 output_memory_reference_mode = GET_MODE (x);
5086 output_memory_autoinc_first = true;
5087 output_address (XEXP (x, 0));
5088 output_memory_reference_mode = VOIDmode;
5092 /* Print an auto-inc memory operand. */
5095 output_operand_lossage ("invalid %%i operand");
5099 output_memory_reference_mode = GET_MODE (x);
5100 output_memory_autoinc_first = false;
5101 output_address (XEXP (x, 0));
5102 output_memory_reference_mode = VOIDmode;
5107 /* Print the low 8 bits of a constant. */
5109 if (CONST_INT_P (x))
5111 else if (GET_CODE (x) == CONST_DOUBLE)
5112 i = CONST_DOUBLE_LOW (x);
5113 else if (GET_CODE (x) == CONST_VECTOR
5114 && CONST_INT_P (CONST_VECTOR_ELT (x, 0)))
5115 i = INTVAL (CONST_VECTOR_ELT (x, 0));
5118 output_operand_lossage ("invalid %%j operand");
5121 i = trunc_int_for_mode (i, QImode);
5122 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
5128 /* Print a constant plus one. */
5129 if (!CONST_INT_P (x))
5131 output_operand_lossage ("invalid %%P operand");
5134 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + 1);
5141 /* Print a bfextu-style bit range. */
5142 int first_bit, last_bit;
5143 HOST_WIDE_INT flip = (code == 'm') ? ~0 : 0;
5145 if (!CONST_INT_P (x)
5146 || !tilegx_bitfield_operand_p (INTVAL (x) ^ flip,
5147 &first_bit, &last_bit))
5149 output_operand_lossage ("invalid %%%c operand", code);
5153 fprintf (file, "%d, %d", first_bit, last_bit);
5159 const char *reg = NULL;
5161 /* Print a network register. */
5162 if (!CONST_INT_P (x))
5164 output_operand_lossage ("invalid %%N operand");
5170 case TILEGX_NETREG_IDN0: reg = "idn0"; break;
5171 case TILEGX_NETREG_IDN1: reg = "idn1"; break;
5172 case TILEGX_NETREG_UDN0: reg = "udn0"; break;
5173 case TILEGX_NETREG_UDN1: reg = "udn1"; break;
5174 case TILEGX_NETREG_UDN2: reg = "udn2"; break;
5175 case TILEGX_NETREG_UDN3: reg = "udn3"; break;
5180 fprintf (file, reg);
5185 if (GET_CODE (x) == SYMBOL_REF)
5187 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
5188 fprintf (file, "plt(");
5189 output_addr_const (file, x);
5190 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
5191 fprintf (file, ")");
5194 output_addr_const (file, x);
5198 /* In this case we need a register. Use 'zero' if the operand
5201 || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
5203 fputs ("zero", file);
5206 else if (!REG_P (x))
5208 output_operand_lossage ("invalid operand for 'r' specifier");
5216 fprintf (file, "%s", reg_names[REGNO (x)]);
5221 output_memory_reference_mode = VOIDmode;
5222 output_address (XEXP (x, 0));
5227 output_addr_const (file, x);
5233 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5238 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5240 tilegx_print_operand_address (FILE *file, rtx addr)
5242 if (GET_CODE (addr) == POST_DEC
5243 || GET_CODE (addr) == POST_INC)
5245 int offset = GET_MODE_SIZE (output_memory_reference_mode);
5247 gcc_assert (output_memory_reference_mode != VOIDmode);
5249 if (output_memory_autoinc_first)
5250 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
5252 fprintf (file, "%d",
5253 GET_CODE (addr) == POST_DEC ? -offset : offset);
5255 else if (GET_CODE (addr) == POST_MODIFY)
5257 gcc_assert (output_memory_reference_mode != VOIDmode);
5259 gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
5261 if (output_memory_autoinc_first)
5262 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
5264 fprintf (file, HOST_WIDE_INT_PRINT_DEC,
5265 INTVAL (XEXP (XEXP (addr, 1), 1)));
5268 tilegx_print_operand (file, addr, 'r');
5272 /* Machine mode of current insn, for determining curly brace
5274 static enum machine_mode insn_mode;
5277 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5279 tilegx_final_prescan_insn (rtx insn)
5281 /* Record this for tilegx_asm_output_opcode to examine. */
5282 insn_mode = GET_MODE (insn);
5286 /* While emitting asm, are we currently inside '{' for a bundle? */
5287 static bool tilegx_in_bundle = false;
5289 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5290 appropriate given the bundling information recorded by
5291 tilegx_gen_bundles. */
5293 tilegx_asm_output_opcode (FILE *stream, const char *code)
5295 bool pseudo = !strcmp (code, "pseudo");
5297 if (!tilegx_in_bundle && insn_mode == SImode)
5299 /* Start a new bundle. */
5300 fprintf (stream, "{\n\t");
5301 tilegx_in_bundle = true;
5304 if (tilegx_in_bundle && insn_mode == QImode)
5306 /* Close an existing bundle. */
5307 static char buf[100];
5309 gcc_assert (strlen (code) + 3 + 1 < sizeof (buf));
5311 strcpy (buf, pseudo ? "" : code);
5312 strcat (buf, "\n\t}");
5313 tilegx_in_bundle = false;
5319 return pseudo ? "" : code;
5324 /* Output assembler code to FILE to increment profiler label # LABELNO
5325 for profiling a function entry. */
5327 tilegx_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
5329 if (tilegx_in_bundle)
5331 fprintf (file, "\t}\n");
5340 "\t}\n", MCOUNT_NAME);
5348 "\t}\t\n", MCOUNT_NAME);
5351 tilegx_in_bundle = false;
5355 /* Implement TARGET_ASM_FILE_END. */
5357 tilegx_file_end (void)
5359 if (NEED_INDICATE_EXEC_STACK)
5360 file_end_indicate_exec_stack ();
5365 #undef TARGET_HAVE_TLS
5366 #define TARGET_HAVE_TLS HAVE_AS_TLS
5368 #undef TARGET_OPTION_OVERRIDE
5369 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5371 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5372 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5374 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5375 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5377 #undef TARGET_CANNOT_FORCE_CONST_MEM
5378 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5380 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5381 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5383 #undef TARGET_PASS_BY_REFERENCE
5384 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5386 #undef TARGET_RETURN_IN_MEMORY
5387 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5389 #undef TARGET_MODE_REP_EXTENDED
5390 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5392 #undef TARGET_FUNCTION_ARG_BOUNDARY
5393 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5395 #undef TARGET_FUNCTION_ARG
5396 #define TARGET_FUNCTION_ARG tilegx_function_arg
5398 #undef TARGET_FUNCTION_ARG_ADVANCE
5399 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5401 #undef TARGET_FUNCTION_VALUE
5402 #define TARGET_FUNCTION_VALUE tilegx_function_value
5404 #undef TARGET_LIBCALL_VALUE
5405 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5407 #undef TARGET_FUNCTION_VALUE_REGNO_P
5408 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5410 #undef TARGET_PROMOTE_FUNCTION_MODE
5411 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5413 #undef TARGET_PROMOTE_PROTOTYPES
5414 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5416 #undef TARGET_BUILD_BUILTIN_VA_LIST
5417 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5419 #undef TARGET_EXPAND_BUILTIN_VA_START
5420 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5422 #undef TARGET_SETUP_INCOMING_VARARGS
5423 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5425 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5426 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5428 #undef TARGET_RTX_COSTS
5429 #define TARGET_RTX_COSTS tilegx_rtx_costs
5431 #undef TARGET_SHIFT_TRUNCATION_MASK
5432 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5434 #undef TARGET_INIT_LIBFUNCS
5435 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5437 /* Limit to what we can reach in one addli. */
5438 #undef TARGET_MIN_ANCHOR_OFFSET
5439 #define TARGET_MIN_ANCHOR_OFFSET -32768
5440 #undef TARGET_MAX_ANCHOR_OFFSET
5441 #define TARGET_MAX_ANCHOR_OFFSET 32767
5443 #undef TARGET_LEGITIMATE_CONSTANT_P
5444 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5446 #undef TARGET_LEGITIMATE_ADDRESS_P
5447 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5449 #undef TARGET_LEGITIMIZE_ADDRESS
5450 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5452 #undef TARGET_DELEGITIMIZE_ADDRESS
5453 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5455 #undef TARGET_INIT_BUILTINS
5456 #define TARGET_INIT_BUILTINS tilegx_init_builtins
5458 #undef TARGET_BUILTIN_DECL
5459 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5461 #undef TARGET_EXPAND_BUILTIN
5462 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5464 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5465 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5467 #undef TARGET_FRAME_POINTER_REQUIRED
5468 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5470 #undef TARGET_DELAY_SCHED2
5471 #define TARGET_DELAY_SCHED2 true
5473 #undef TARGET_DELAY_VARTRACK
5474 #define TARGET_DELAY_VARTRACK true
5476 #undef TARGET_SCHED_ISSUE_RATE
5477 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5479 #undef TARGET_SCHED_ADJUST_COST
5480 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5482 #undef TARGET_MACHINE_DEPENDENT_REORG
5483 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5485 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5486 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5487 hook_bool_const_tree_hwi_hwi_const_tree_true
5489 #undef TARGET_ASM_OUTPUT_MI_THUNK
5490 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5492 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5493 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5495 #undef TARGET_TRAMPOLINE_INIT
5496 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5498 #undef TARGET_PRINT_OPERAND
5499 #define TARGET_PRINT_OPERAND tilegx_print_operand
5501 #undef TARGET_PRINT_OPERAND_ADDRESS
5502 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5504 #undef TARGET_ASM_FILE_END
5505 #define TARGET_ASM_FILE_END tilegx_file_end
5507 #undef TARGET_ASM_ALIGNED_DI_OP
5508 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5511 struct gcc_target targetm = TARGET_INITIALIZER;
5513 #include "gt-tilegx.h"