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)
4426 if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli_32bit)
4431 if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli)
4435 src = SET_SRC (PATTERN (insn));
4437 return (GET_CODE (src) == CONST
4438 && GET_CODE (XEXP (src, 0)) == UNSPEC
4439 && XINT (XEXP (src, 0), 1) == UNSPEC_HW0_PCREL);
4443 /* Do the second replacement step in tilegx_fixup_pcrel_references. */
4445 replace_mov_pcrel_step2 (rtx insn)
4447 rtx pattern = PATTERN (insn);
4451 rtx got_rtx = tilegx_got_rtx ();
4453 gcc_assert (GET_CODE (pattern) == SET);
4454 opnds[0] = SET_DEST (pattern);
4456 unspec = XEXP (SET_SRC (pattern), 0);
4457 gcc_assert (GET_CODE (unspec) == UNSPEC);
4458 gcc_assert (XINT (unspec, 1) == UNSPEC_HW0_PCREL);
4459 opnds[1] = XEXP (XEXP (SET_SRC (pattern), 0), 0);
4460 opnds[2] = XVECEXP (unspec, 0, 0);
4462 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4463 if (GET_CODE (opnds[2]) != SYMBOL_REF)
4471 emit_insn (gen_add_got16_32bit (opnds[0], got_rtx, opnds[2]));
4473 emit_insn (gen_add_got16 (opnds[0], got_rtx, opnds[2]));
4478 emit_insn (gen_mov_got32_step2_32bit
4479 (opnds[0], opnds[1], opnds[2]));
4481 emit_insn (gen_mov_got32_step2 (opnds[0], opnds[1], opnds[2]));
4484 new_insns = get_insns ();
4487 replace_insns (insn, new_insns);
4491 /* Do the third replacement step in tilegx_fixup_pcrel_references. */
4493 replace_mov_pcrel_step3 (rtx insn)
4495 rtx pattern = PATTERN (insn);
4499 rtx got_rtx = tilegx_got_rtx ();
4500 rtx text_label_rtx = tilegx_text_label_rtx ();
4502 gcc_assert (GET_CODE (pattern) == SET);
4503 opnds[0] = SET_DEST (pattern);
4505 unspec = SET_SRC (pattern);
4506 gcc_assert (GET_CODE (unspec) == UNSPEC);
4507 gcc_assert (XINT (unspec, 1) == UNSPEC_MOV_PCREL_STEP3);
4511 if (XVECEXP (unspec, 0, 0) == text_label_rtx)
4512 opnds[2] = XVECEXP (unspec, 0, 1);
4515 gcc_assert (XVECEXP (unspec, 0, 1) == text_label_rtx);
4516 opnds[2] = XVECEXP (unspec, 0, 0);
4519 opnds[3] = XVECEXP (unspec, 0, 2);
4521 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4522 if (GET_CODE (opnds[3]) != SYMBOL_REF)
4529 emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[2]));
4533 emit_move_insn (opnds[0], gen_rtx_PLUS (Pmode, opnds[1], opnds[2]));
4534 emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[0]));
4537 new_insns = get_insns ();
4540 replace_insns (insn, new_insns);
4544 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4545 going through the GOT when the symbol is local to the compilation
4546 unit. But such a symbol requires that the common text_label that
4547 we generate at the beginning of the function be in the same section
4548 as the reference to the SYMBOL_REF. This may not be true if we
4549 generate hot/cold sections. This function looks for such cases and
4550 replaces such references with the longer sequence going through the
4553 We expect following instruction sequence:
4554 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4555 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4556 add<x> tmp3, txt_label_reg, tmp2 [3]
4558 If we're compiling -fpic, we replace with the following sequence
4559 (the numbers in brackets match the instructions they're replacing
4562 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4563 ld<4> tmp3, tmp2 [3]
4565 If we're compiling -fPIC, we replace the first instruction with:
4567 moveli tmp1, hw1_last_got(x) [1]
4568 shl16insli tmp2, tmp1, hw0_got(x) [2]
4569 add<x> tmp3, got_reg, tmp2 [3]
4570 ld<4> tmp3, tmp3 [3]
4572 Note that we're careful to disturb the instruction sequence as
4573 little as possible, since it's very late in the compilation
4576 tilegx_fixup_pcrel_references (void)
4578 rtx insn, next_insn;
4579 bool same_section_as_entry = true;
4581 for (insn = get_insns (); insn; insn = next_insn)
4583 next_insn = NEXT_INSN (insn);
4585 if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
4587 same_section_as_entry = !same_section_as_entry;
4591 if (same_section_as_entry)
4595 && GET_CODE (PATTERN (insn)) != USE
4596 && GET_CODE (PATTERN (insn)) != CLOBBER))
4601 if (match_pcrel_step1 (insn))
4602 replace_mov_pcrel_step1 (insn);
4603 else if (match_pcrel_step2 (insn))
4604 replace_mov_pcrel_step2 (insn);
4605 else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3_32bit)
4606 replace_mov_pcrel_step3 (insn);
4610 if (match_pcrel_step1 (insn))
4611 replace_mov_pcrel_step1 (insn);
4612 else if (match_pcrel_step2 (insn))
4613 replace_mov_pcrel_step2 (insn);
4614 else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3)
4615 replace_mov_pcrel_step3 (insn);
4621 /* Ensure that no var tracking notes are emitted in the middle of a
4622 three-instruction bundle. */
4624 reorder_var_tracking_notes (void)
4630 rtx queue = NULL_RTX;
4631 bool in_bundle = false;
4633 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4635 next = NEXT_INSN (insn);
4639 /* Emit queued up notes at the last instruction of a
4641 if (GET_MODE (insn) == QImode)
4645 rtx next_queue = PREV_INSN (queue);
4646 PREV_INSN (NEXT_INSN (insn)) = queue;
4647 NEXT_INSN (queue) = NEXT_INSN (insn);
4648 NEXT_INSN (insn) = queue;
4649 PREV_INSN (queue) = insn;
4654 else if (GET_MODE (insn) == SImode)
4657 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4661 rtx prev = PREV_INSN (insn);
4662 PREV_INSN (next) = prev;
4663 NEXT_INSN (prev) = next;
4665 PREV_INSN (insn) = queue;
4674 /* Perform machine dependent operations on the rtl chain INSNS. */
4678 /* We are freeing block_for_insn in the toplev to keep compatibility
4679 with old MDEP_REORGS that are not CFG based. Recompute it
4681 compute_bb_for_insn ();
4683 if (flag_reorder_blocks_and_partition)
4685 tilegx_fixup_pcrel_references ();
4688 if (flag_schedule_insns_after_reload)
4692 timevar_push (TV_SCHED2);
4694 timevar_pop (TV_SCHED2);
4696 /* Examine the schedule to group into bundles. */
4697 tilegx_gen_bundles ();
4702 if (flag_var_tracking)
4704 timevar_push (TV_VAR_TRACKING);
4705 variable_tracking_main ();
4706 reorder_var_tracking_notes ();
4707 timevar_pop (TV_VAR_TRACKING);
4710 df_finish_pass (false);
4717 /* Select a format to encode pointers in exception handling data.
4718 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4719 GLOBAL is true if the symbol may be affected by dynamic
4722 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
4726 int type = TARGET_32BIT ? DW_EH_PE_sdata4 : DW_EH_PE_sdata8;
4727 return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type;
4730 return DW_EH_PE_absptr;
4734 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4736 tilegx_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
4737 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
4740 rtx this_rtx, insn, funexp, addend;
4742 /* Pretend to be a post-reload pass while generating rtl. */
4743 reload_completed = 1;
4745 /* Mark the end of the (empty) prologue. */
4746 emit_note (NOTE_INSN_PROLOGUE_END);
4748 /* Find the "this" pointer. If the function returns a structure,
4749 the structure return pointer is in $1. */
4750 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
4751 this_rtx = gen_rtx_REG (Pmode, 1);
4753 this_rtx = gen_rtx_REG (Pmode, 0);
4755 /* Add DELTA to THIS_RTX. */
4756 if (!(delta >= -32868 && delta <= 32767))
4758 addend = gen_rtx_REG (Pmode, 29);
4759 emit_move_insn (addend, GEN_INT (delta));
4762 addend = GEN_INT (delta);
4765 emit_insn (gen_addsi3 (this_rtx, this_rtx, addend));
4767 emit_insn (gen_adddi3 (this_rtx, this_rtx, addend));
4769 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4774 tmp = gen_rtx_REG (Pmode, 29);
4775 emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx));
4777 if (!(vcall_offset >= -32868 && vcall_offset <= 32767))
4779 addend = gen_rtx_REG (Pmode, 28);
4780 emit_move_insn (addend, GEN_INT (vcall_offset));
4783 addend = GEN_INT (vcall_offset);
4786 emit_insn (gen_addsi3 (tmp, tmp, addend));
4788 emit_insn (gen_adddi3 (tmp, tmp, addend));
4790 emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
4793 emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp));
4795 emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp));
4798 /* Generate a tail call to the target function. */
4799 if (!TREE_USED (function))
4801 assemble_external (function);
4802 TREE_USED (function) = 1;
4804 funexp = XEXP (DECL_RTL (function), 0);
4805 funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
4806 insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
4807 SIBLING_CALL_P (insn) = 1;
4809 /* Run just enough of rest_of_compilation to get the insns emitted.
4810 There's not really enough bulk here to make other passes such as
4811 instruction scheduling worth while. Note that use_thunk calls
4812 assemble_start_function and assemble_end_function.
4814 We don't currently bundle, but the instruciton sequence is all
4815 serial except for the tail call, so we're only wasting one cycle.
4817 insn = get_insns ();
4818 insn_locators_alloc ();
4819 shorten_branches (insn);
4820 final_start_function (insn, file, 1);
4821 final (insn, file, 1);
4822 final_end_function ();
4824 /* Stop pretending to be a post-reload pass. */
4825 reload_completed = 0;
4829 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
4831 tilegx_asm_trampoline_template (FILE *file)
4833 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4836 fprintf (file, "\tlnk r10\n");
4837 fprintf (file, "\taddxi r10, r10, 32\n");
4838 fprintf (file, "\tld4s_add r11, r10, %d\n", ptr_mode_size);
4839 fprintf (file, "\tld4s r10, r10\n");
4840 fprintf (file, "\tjr r11\n");
4841 fprintf (file, "\t.word 0 # <function address>\n");
4842 fprintf (file, "\t.word 0 # <static chain value>\n");
4846 fprintf (file, "\tlnk r10\n");
4847 fprintf (file, "\taddi r10, r10, 32\n");
4848 fprintf (file, "\tld_add r11, r10, %d\n", ptr_mode_size);
4849 fprintf (file, "\tld r10, r10\n");
4850 fprintf (file, "\tjr r11\n");
4851 fprintf (file, "\t.quad 0 # <function address>\n");
4852 fprintf (file, "\t.quad 0 # <static chain value>\n");
4857 /* Implement TARGET_TRAMPOLINE_INIT. */
4859 tilegx_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
4863 rtx begin_addr, end_addr;
4864 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4866 fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
4867 chaddr = copy_to_reg (static_chain);
4869 emit_block_move (m_tramp, assemble_trampoline_template (),
4870 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
4872 mem = adjust_address (m_tramp, ptr_mode,
4873 TRAMPOLINE_SIZE - 2 * ptr_mode_size);
4874 emit_move_insn (mem, fnaddr);
4875 mem = adjust_address (m_tramp, ptr_mode,
4876 TRAMPOLINE_SIZE - ptr_mode_size);
4877 emit_move_insn (mem, chaddr);
4879 /* Get pointers to the beginning and end of the code block. */
4880 begin_addr = force_reg (Pmode, XEXP (m_tramp, 0));
4881 end_addr = force_reg (Pmode, plus_constant (XEXP (m_tramp, 0),
4884 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
4885 LCT_NORMAL, VOIDmode, 2, begin_addr, Pmode,
4890 /* Implement TARGET_PRINT_OPERAND. */
4892 tilegx_print_operand (FILE *file, rtx x, int code)
4897 /* Print the compare operator opcode for conditional moves. */
4898 switch (GET_CODE (x))
4907 output_operand_lossage ("invalid %%c operand");
4912 /* Print the compare operator opcode for conditional moves. */
4913 switch (GET_CODE (x))
4922 output_operand_lossage ("invalid %%C operand");
4928 /* Print the compare operator opcode for conditional moves. */
4929 switch (GET_CODE (x))
4938 output_operand_lossage ("invalid %%d operand");
4945 /* Print the compare operator opcode for conditional moves. */
4946 switch (GET_CODE (x))
4955 output_operand_lossage ("invalid %%D operand");
4962 if (GET_CODE (x) == CONST
4963 && GET_CODE (XEXP (x, 0)) == UNSPEC)
4965 rtx addr = XVECEXP (XEXP (x, 0), 0, 0);
4966 int unspec = XINT (XEXP (x, 0), 1);
4967 const char *opstr = NULL;
4971 case UNSPEC_HW0_PCREL:
4983 case UNSPEC_HW0_LAST:
4986 case UNSPEC_HW1_LAST:
4987 case UNSPEC_HW1_LAST_PCREL:
4990 case UNSPEC_HW2_LAST:
4993 case UNSPEC_HW0_GOT:
4996 case UNSPEC_HW0_LAST_GOT:
4997 opstr = "hw0_last_got";
4999 case UNSPEC_HW1_LAST_GOT:
5000 opstr = "hw1_last_got";
5002 case UNSPEC_HW0_TLS_GD:
5003 opstr = "hw0_tls_gd";
5005 case UNSPEC_HW1_LAST_TLS_GD:
5006 opstr = "hw1_last_tls_gd";
5008 case UNSPEC_HW0_TLS_IE:
5009 opstr = "hw0_tls_ie";
5011 case UNSPEC_HW1_LAST_TLS_IE:
5012 opstr = "hw1_last_tls_ie";
5014 case UNSPEC_HW0_TLS_LE:
5015 opstr = "hw0_tls_le";
5017 case UNSPEC_HW1_LAST_TLS_LE:
5018 opstr = "hw1_last_tls_le";
5021 output_operand_lossage ("invalid %%H specifier");
5024 fputs (opstr, file);
5026 output_addr_const (file, addr);
5028 if (unspec == UNSPEC_HW0_PCREL
5029 || unspec == UNSPEC_HW1_LAST_PCREL)
5031 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
5032 fputs (" - " , file);
5033 output_addr_const (file, addr2);
5039 else if (symbolic_operand (x, VOIDmode))
5041 output_addr_const (file, x);
5049 /* Print the low 16 bits of a constant. */
5051 if (CONST_INT_P (x))
5053 else if (GET_CODE (x) == CONST_DOUBLE)
5054 i = CONST_DOUBLE_LOW (x);
5057 output_operand_lossage ("invalid %%h operand");
5060 i = trunc_int_for_mode (i, HImode);
5061 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
5066 /* Print an auto-inc memory operand. */
5069 output_operand_lossage ("invalid %%I operand");
5073 output_memory_reference_mode = GET_MODE (x);
5074 output_memory_autoinc_first = true;
5075 output_address (XEXP (x, 0));
5076 output_memory_reference_mode = VOIDmode;
5080 /* Print an auto-inc memory operand. */
5083 output_operand_lossage ("invalid %%i operand");
5087 output_memory_reference_mode = GET_MODE (x);
5088 output_memory_autoinc_first = false;
5089 output_address (XEXP (x, 0));
5090 output_memory_reference_mode = VOIDmode;
5095 /* Print the low 8 bits of a constant. */
5097 if (CONST_INT_P (x))
5099 else if (GET_CODE (x) == CONST_DOUBLE)
5100 i = CONST_DOUBLE_LOW (x);
5101 else if (GET_CODE (x) == CONST_VECTOR
5102 && CONST_INT_P (CONST_VECTOR_ELT (x, 0)))
5103 i = INTVAL (CONST_VECTOR_ELT (x, 0));
5106 output_operand_lossage ("invalid %%j operand");
5109 i = trunc_int_for_mode (i, QImode);
5110 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
5116 /* Print a constant plus one. */
5117 if (!CONST_INT_P (x))
5119 output_operand_lossage ("invalid %%P operand");
5122 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + 1);
5129 /* Print a bfextu-style bit range. */
5130 int first_bit, last_bit;
5131 HOST_WIDE_INT flip = (code == 'm') ? ~0 : 0;
5133 if (!CONST_INT_P (x)
5134 || !tilegx_bitfield_operand_p (INTVAL (x) ^ flip,
5135 &first_bit, &last_bit))
5137 output_operand_lossage ("invalid %%%c operand", code);
5141 fprintf (file, "%d, %d", first_bit, last_bit);
5147 const char *reg = NULL;
5149 /* Print a network register. */
5150 if (!CONST_INT_P (x))
5152 output_operand_lossage ("invalid %%N operand");
5158 case TILEGX_NETREG_IDN0: reg = "idn0"; break;
5159 case TILEGX_NETREG_IDN1: reg = "idn1"; break;
5160 case TILEGX_NETREG_UDN0: reg = "udn0"; break;
5161 case TILEGX_NETREG_UDN1: reg = "udn1"; break;
5162 case TILEGX_NETREG_UDN2: reg = "udn2"; break;
5163 case TILEGX_NETREG_UDN3: reg = "udn3"; break;
5168 fprintf (file, reg);
5173 if (GET_CODE (x) == SYMBOL_REF)
5175 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
5176 fprintf (file, "plt(");
5177 output_addr_const (file, x);
5178 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
5179 fprintf (file, ")");
5182 output_addr_const (file, x);
5186 /* In this case we need a register. Use 'zero' if the operand
5189 || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
5191 fputs ("zero", file);
5194 else if (!REG_P (x))
5196 output_operand_lossage ("invalid operand for 'r' specifier");
5204 fprintf (file, "%s", reg_names[REGNO (x)]);
5209 output_memory_reference_mode = VOIDmode;
5210 output_address (XEXP (x, 0));
5215 output_addr_const (file, x);
5221 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5226 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5228 tilegx_print_operand_address (FILE *file, rtx addr)
5230 if (GET_CODE (addr) == POST_DEC
5231 || GET_CODE (addr) == POST_INC)
5233 int offset = GET_MODE_SIZE (output_memory_reference_mode);
5235 gcc_assert (output_memory_reference_mode != VOIDmode);
5237 if (output_memory_autoinc_first)
5238 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
5240 fprintf (file, "%d",
5241 GET_CODE (addr) == POST_DEC ? -offset : offset);
5243 else if (GET_CODE (addr) == POST_MODIFY)
5245 gcc_assert (output_memory_reference_mode != VOIDmode);
5247 gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
5249 if (output_memory_autoinc_first)
5250 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
5252 fprintf (file, HOST_WIDE_INT_PRINT_DEC,
5253 INTVAL (XEXP (XEXP (addr, 1), 1)));
5256 tilegx_print_operand (file, addr, 'r');
5260 /* Machine mode of current insn, for determining curly brace
5262 static enum machine_mode insn_mode;
5265 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5267 tilegx_final_prescan_insn (rtx insn)
5269 /* Record this for tilegx_asm_output_opcode to examine. */
5270 insn_mode = GET_MODE (insn);
5274 /* While emitting asm, are we currently inside '{' for a bundle? */
5275 static bool tilegx_in_bundle = false;
5277 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5278 appropriate given the bundling information recorded by
5279 tilegx_gen_bundles. */
5281 tilegx_asm_output_opcode (FILE *stream, const char *code)
5283 bool pseudo = !strcmp (code, "pseudo");
5285 if (!tilegx_in_bundle && insn_mode == SImode)
5287 /* Start a new bundle. */
5288 fprintf (stream, "{\n\t");
5289 tilegx_in_bundle = true;
5292 if (tilegx_in_bundle && insn_mode == QImode)
5294 /* Close an existing bundle. */
5295 static char buf[100];
5297 gcc_assert (strlen (code) + 3 + 1 < sizeof (buf));
5299 strcpy (buf, pseudo ? "" : code);
5300 strcat (buf, "\n\t}");
5301 tilegx_in_bundle = false;
5307 return pseudo ? "" : code;
5312 /* Output assembler code to FILE to increment profiler label # LABELNO
5313 for profiling a function entry. */
5315 tilegx_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
5317 if (tilegx_in_bundle)
5319 fprintf (file, "\t}\n");
5328 "\t}\n", MCOUNT_NAME);
5336 "\t}\t\n", MCOUNT_NAME);
5339 tilegx_in_bundle = false;
5343 /* Implement TARGET_ASM_FILE_END. */
5345 tilegx_file_end (void)
5347 if (NEED_INDICATE_EXEC_STACK)
5348 file_end_indicate_exec_stack ();
5353 #undef TARGET_HAVE_TLS
5354 #define TARGET_HAVE_TLS HAVE_AS_TLS
5356 #undef TARGET_OPTION_OVERRIDE
5357 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5359 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5360 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5362 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5363 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5365 #undef TARGET_CANNOT_FORCE_CONST_MEM
5366 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5368 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5369 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5371 #undef TARGET_PASS_BY_REFERENCE
5372 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5374 #undef TARGET_RETURN_IN_MEMORY
5375 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5377 #undef TARGET_MODE_REP_EXTENDED
5378 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5380 #undef TARGET_FUNCTION_ARG_BOUNDARY
5381 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5383 #undef TARGET_FUNCTION_ARG
5384 #define TARGET_FUNCTION_ARG tilegx_function_arg
5386 #undef TARGET_FUNCTION_ARG_ADVANCE
5387 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5389 #undef TARGET_FUNCTION_VALUE
5390 #define TARGET_FUNCTION_VALUE tilegx_function_value
5392 #undef TARGET_LIBCALL_VALUE
5393 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5395 #undef TARGET_FUNCTION_VALUE_REGNO_P
5396 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5398 #undef TARGET_PROMOTE_FUNCTION_MODE
5399 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5401 #undef TARGET_PROMOTE_PROTOTYPES
5402 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5404 #undef TARGET_BUILD_BUILTIN_VA_LIST
5405 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5407 #undef TARGET_EXPAND_BUILTIN_VA_START
5408 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5410 #undef TARGET_SETUP_INCOMING_VARARGS
5411 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5413 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5414 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5416 #undef TARGET_RTX_COSTS
5417 #define TARGET_RTX_COSTS tilegx_rtx_costs
5419 #undef TARGET_SHIFT_TRUNCATION_MASK
5420 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5422 #undef TARGET_INIT_LIBFUNCS
5423 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5425 /* Limit to what we can reach in one addli. */
5426 #undef TARGET_MIN_ANCHOR_OFFSET
5427 #define TARGET_MIN_ANCHOR_OFFSET -32768
5428 #undef TARGET_MAX_ANCHOR_OFFSET
5429 #define TARGET_MAX_ANCHOR_OFFSET 32767
5431 #undef TARGET_LEGITIMATE_CONSTANT_P
5432 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5434 #undef TARGET_LEGITIMATE_ADDRESS_P
5435 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5437 #undef TARGET_LEGITIMIZE_ADDRESS
5438 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5440 #undef TARGET_DELEGITIMIZE_ADDRESS
5441 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5443 #undef TARGET_INIT_BUILTINS
5444 #define TARGET_INIT_BUILTINS tilegx_init_builtins
5446 #undef TARGET_BUILTIN_DECL
5447 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5449 #undef TARGET_EXPAND_BUILTIN
5450 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5452 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5453 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5455 #undef TARGET_FRAME_POINTER_REQUIRED
5456 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5458 #undef TARGET_DELAY_SCHED2
5459 #define TARGET_DELAY_SCHED2 true
5461 #undef TARGET_DELAY_VARTRACK
5462 #define TARGET_DELAY_VARTRACK true
5464 #undef TARGET_SCHED_ISSUE_RATE
5465 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5467 #undef TARGET_SCHED_ADJUST_COST
5468 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5470 #undef TARGET_MACHINE_DEPENDENT_REORG
5471 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5473 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5474 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5475 hook_bool_const_tree_hwi_hwi_const_tree_true
5477 #undef TARGET_ASM_OUTPUT_MI_THUNK
5478 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5480 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5481 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5483 #undef TARGET_TRAMPOLINE_INIT
5484 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5486 #undef TARGET_PRINT_OPERAND
5487 #define TARGET_PRINT_OPERAND tilegx_print_operand
5489 #undef TARGET_PRINT_OPERAND_ADDRESS
5490 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5492 #undef TARGET_ASM_FILE_END
5493 #define TARGET_ASM_FILE_END tilegx_file_end
5495 #undef TARGET_ASM_ALIGNED_DI_OP
5496 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5499 struct gcc_target targetm = TARGET_INITIALIZER;
5501 #include "gt-tilegx.h"