1 /* Subroutines used for code generation on the Tilera TILE-Gx.
2 Copyright (C) 2011-2022 Free Software Foundation, Inc.
3 Contributed by Walter Lee (walt@tilera.com)
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #define IN_TARGET_CODE 1
25 #include "coretypes.h"
34 #include "stringpool.h"
41 #include "diagnostic.h"
43 #include "insn-attr.h"
49 #include "langhooks.h"
51 #include "tm-constrs.h"
53 #include "fold-const.h"
54 #include "stor-layout.h"
56 #include "tilegx-builtins.h"
57 #include "tilegx-multiply.h"
61 /* This file should be included last. */
62 #include "target-def.h"
64 /* SYMBOL_REF for GOT */
65 static GTY(()) rtx g_got_symbol
= NULL
;
67 /* Report whether we're printing out the first address fragment of a
68 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
69 TARGET_PRINT_OPERAND_ADDRESS. */
70 static bool output_memory_autoinc_first
;
76 /* Implement TARGET_OPTION_OVERRIDE. */
78 tilegx_option_override (void)
80 if (OPTION_SET_P (tilegx_cmodel
))
82 switch (tilegx_cmodel
)
87 tilegx_cmodel
= CM_SMALL_PIC
;
93 tilegx_cmodel
= CM_LARGE_PIC
;
101 tilegx_cmodel
= flag_pic
? CM_SMALL_PIC
: CM_SMALL
;
103 /* When modulo scheduling is enabled, we still rely on regular
104 scheduler for bundling. */
105 if (flag_modulo_sched
)
106 flag_resched_modulo_sched
= 1;
111 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
113 tilegx_scalar_mode_supported_p (scalar_mode mode
)
134 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
136 tilegx_vector_mode_supported_p (machine_mode mode
)
138 return mode
== V8QImode
|| mode
== V4HImode
|| mode
== V2SImode
;
142 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
144 tilegx_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
,
145 rtx x ATTRIBUTE_UNUSED
)
151 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
153 tilegx_function_ok_for_sibcall (tree decl
, tree exp ATTRIBUTE_UNUSED
)
155 return (tilegx_cmodel
!= CM_LARGE
&& tilegx_cmodel
!= CM_LARGE_PIC
160 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
161 passed by reference. */
163 tilegx_pass_by_reference (cumulative_args_t
, const function_arg_info
&arg
)
166 && TYPE_SIZE (arg
.type
)
167 && TREE_CODE (TYPE_SIZE (arg
.type
)) != INTEGER_CST
);
171 /* Implement TARGET_RETURN_IN_MSB. We return a value in the most
172 significant part of a register if:
173 - the target is big-endian; and
174 - the value has an aggregate type (e.g., structure or union). */
176 tilegx_return_in_msb (const_tree valtype
)
178 return (TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (valtype
));
182 /* Implement TARGET_RETURN_IN_MEMORY. */
184 tilegx_return_in_memory (const_tree type
, const_tree fndecl ATTRIBUTE_UNUSED
)
186 return !IN_RANGE (int_size_in_bytes (type
),
187 0, TILEGX_NUM_RETURN_REGS
* UNITS_PER_WORD
);
191 /* Implement TARGET_MODE_REP_EXTENDED. */
193 tilegx_mode_rep_extended (scalar_int_mode mode
, scalar_int_mode mode_rep
)
195 /* SImode register values are sign-extended to DImode. */
196 if (mode
== SImode
&& mode_rep
== DImode
)
203 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
205 tilegx_function_arg_boundary (machine_mode mode
, const_tree type
)
207 unsigned int alignment
;
209 alignment
= type
? TYPE_ALIGN (type
) : GET_MODE_ALIGNMENT (mode
);
210 if (alignment
< PARM_BOUNDARY
)
211 alignment
= PARM_BOUNDARY
;
212 if (alignment
> STACK_BOUNDARY
)
213 alignment
= STACK_BOUNDARY
;
218 /* Implement TARGET_FUNCTION_ARG. */
220 tilegx_function_arg (cumulative_args_t cum_v
, const function_arg_info
&arg
)
222 CUMULATIVE_ARGS cum
= *get_cumulative_args (cum_v
);
223 int byte_size
= arg
.promoted_size_in_bytes ();
224 bool doubleword_aligned_p
;
226 if (cum
>= TILEGX_NUM_ARG_REGS
)
229 /* See whether the argument has doubleword alignment. */
230 doubleword_aligned_p
=
231 tilegx_function_arg_boundary (arg
.mode
, arg
.type
) > BITS_PER_WORD
;
233 if (doubleword_aligned_p
)
236 /* The ABI does not allow parameters to be passed partially in reg
237 and partially in stack. */
238 if ((cum
+ (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
)
239 > TILEGX_NUM_ARG_REGS
)
242 return gen_rtx_REG (arg
.mode
, cum
);
246 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
248 tilegx_function_arg_advance (cumulative_args_t cum_v
,
249 const function_arg_info
&arg
)
251 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
253 int byte_size
= arg
.promoted_size_in_bytes ();
254 int word_size
= (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
255 bool doubleword_aligned_p
;
257 /* See whether the argument has doubleword alignment. */
258 doubleword_aligned_p
=
259 tilegx_function_arg_boundary (arg
.mode
, arg
.type
) > BITS_PER_WORD
;
261 if (doubleword_aligned_p
)
264 /* If the current argument does not fit in the pretend_args space,
266 if (*cum
< TILEGX_NUM_ARG_REGS
267 && *cum
+ word_size
> TILEGX_NUM_ARG_REGS
)
268 *cum
= TILEGX_NUM_ARG_REGS
;
274 /* Implement TARGET_FUNCTION_VALUE. */
276 tilegx_function_value (const_tree valtype
, const_tree fn_decl_or_type
,
277 bool outgoing ATTRIBUTE_UNUSED
)
282 mode
= TYPE_MODE (valtype
);
283 unsigned_p
= TYPE_UNSIGNED (valtype
);
285 mode
= promote_function_mode (valtype
, mode
, &unsigned_p
,
288 return gen_rtx_REG (mode
, 0);
292 /* Implement TARGET_LIBCALL_VALUE. */
294 tilegx_libcall_value (machine_mode mode
,
295 const_rtx fun ATTRIBUTE_UNUSED
)
297 return gen_rtx_REG (mode
, 0);
301 /* Implement FUNCTION_VALUE_REGNO_P. */
303 tilegx_function_value_regno_p (const unsigned int regno
)
305 return regno
< TILEGX_NUM_RETURN_REGS
;
309 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
311 tilegx_build_builtin_va_list (void)
313 tree f_args
, f_skip
, record
, type_decl
;
316 record
= lang_hooks
.types
.make_type (RECORD_TYPE
);
318 type_decl
= build_decl (BUILTINS_LOCATION
, TYPE_DECL
,
319 get_identifier ("__va_list_tag"), record
);
321 f_args
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
322 get_identifier ("__args"), ptr_type_node
);
323 f_skip
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
324 get_identifier ("__skip"), ptr_type_node
);
326 DECL_FIELD_CONTEXT (f_args
) = record
;
328 DECL_FIELD_CONTEXT (f_skip
) = record
;
330 TREE_CHAIN (record
) = type_decl
;
331 TYPE_NAME (record
) = type_decl
;
332 TYPE_FIELDS (record
) = f_args
;
333 TREE_CHAIN (f_args
) = f_skip
;
335 /* We know this is being padded and we want it too. It is an
336 internal type so hide the warnings from the user. */
340 layout_type (record
);
344 /* The correct type is an array type of one element. */
349 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
351 tilegx_va_start (tree valist
, rtx nextarg ATTRIBUTE_UNUSED
)
356 f_args
= TYPE_FIELDS (TREE_TYPE (valist
));
357 f_skip
= TREE_CHAIN (f_args
);
360 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
362 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
364 /* Find the __args area. */
365 t
= make_tree (TREE_TYPE (args
), virtual_incoming_args_rtx
);
366 t
= fold_build_pointer_plus_hwi (t
,
368 (crtl
->args
.info
- TILEGX_NUM_ARG_REGS
));
370 if (crtl
->args
.pretend_args_size
> 0)
371 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
373 t
= build2 (MODIFY_EXPR
, TREE_TYPE (args
), args
, t
);
374 TREE_SIDE_EFFECTS (t
) = 1;
375 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
377 /* Find the __skip area. */
378 t
= make_tree (TREE_TYPE (skip
), virtual_incoming_args_rtx
);
379 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
380 t
= build2 (MODIFY_EXPR
, TREE_TYPE (skip
), skip
, t
);
381 TREE_SIDE_EFFECTS (t
) = 1;
382 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
386 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
388 tilegx_setup_incoming_varargs (cumulative_args_t cum
,
389 const function_arg_info
&arg
,
390 int *pretend_args
, int no_rtl
)
392 CUMULATIVE_ARGS local_cum
= *get_cumulative_args (cum
);
395 /* The caller has advanced CUM up to, but not beyond, the last named
396 argument. Advance a local copy of CUM past the last "real" named
397 argument, to find out how many registers are left over. */
398 targetm
.calls
.function_arg_advance (pack_cumulative_args (&local_cum
), arg
);
399 first_reg
= local_cum
;
401 if (local_cum
< TILEGX_NUM_ARG_REGS
)
403 *pretend_args
= UNITS_PER_WORD
* (TILEGX_NUM_ARG_REGS
- first_reg
);
407 alias_set_type set
= get_varargs_alias_set ();
409 gen_rtx_MEM (BLKmode
, plus_constant (Pmode
,
410 virtual_incoming_args_rtx
,
411 -STACK_POINTER_OFFSET
-
413 (TILEGX_NUM_ARG_REGS
-
415 MEM_NOTRAP_P (tmp
) = 1;
416 set_mem_alias_set (tmp
, set
);
417 move_block_from_reg (first_reg
, tmp
,
418 TILEGX_NUM_ARG_REGS
- first_reg
);
426 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
427 the va_list structure VALIST as required to retrieve an argument of
428 type TYPE, and returning that argument.
430 ret = va_arg(VALIST, TYPE);
432 generates code equivalent to:
434 paddedsize = (sizeof(TYPE) + 7) & -8;
435 if ( (VALIST.__args + paddedsize > VALIST.__skip)
436 & (VALIST.__args <= VALIST.__skip))
437 addr = VALIST.__skip + STACK_POINTER_OFFSET;
439 addr = VALIST.__args;
440 VALIST.__args = addr + paddedsize;
441 if (BYTES_BIG_ENDIAN)
442 ret = *(TYPE *)(addr + paddedsize - sizeof(TYPE));
447 tilegx_gimplify_va_arg_expr (tree valist
, tree type
, gimple_seq
*pre_p
,
448 gimple_seq
*post_p ATTRIBUTE_UNUSED
)
452 HOST_WIDE_INT size
, rsize
;
454 bool pass_by_reference_p
;
456 f_args
= TYPE_FIELDS (va_list_type_node
);
457 f_skip
= TREE_CHAIN (f_args
);
460 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
462 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
464 addr
= create_tmp_var (ptr_type_node
, "va_arg");
466 /* If an object is dynamically sized, a pointer to it is passed
467 instead of the object itself. */
468 pass_by_reference_p
= pass_va_arg_by_reference (type
);
470 if (pass_by_reference_p
)
471 type
= build_pointer_type (type
);
473 size
= int_size_in_bytes (type
);
474 rsize
= ((size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
) * UNITS_PER_WORD
;
476 /* If the alignment of the type is greater than the default for a
477 parameter, align to the STACK_BOUNDARY. */
478 if (TYPE_ALIGN (type
) > PARM_BOUNDARY
)
480 /* Assert the only case we generate code for: when
481 stack boundary = 2 * parm boundary. */
482 gcc_assert (STACK_BOUNDARY
== PARM_BOUNDARY
* 2);
484 tmp
= build2 (BIT_AND_EXPR
, sizetype
,
485 fold_convert (sizetype
, unshare_expr (args
)),
486 size_int (PARM_BOUNDARY
/ 8));
487 tmp
= build2 (POINTER_PLUS_EXPR
, ptr_type_node
,
488 unshare_expr (args
), tmp
);
490 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
493 /* Build conditional expression to calculate addr. The expression
494 will be gimplified later. */
495 tmp
= fold_build_pointer_plus_hwi (unshare_expr (args
), rsize
);
496 tmp
= build2 (TRUTH_AND_EXPR
, boolean_type_node
,
497 build2 (GT_EXPR
, boolean_type_node
, tmp
, unshare_expr (skip
)),
498 build2 (LE_EXPR
, boolean_type_node
, unshare_expr (args
),
499 unshare_expr (skip
)));
501 tmp
= build3 (COND_EXPR
, ptr_type_node
, tmp
,
502 build2 (POINTER_PLUS_EXPR
, ptr_type_node
, unshare_expr (skip
),
503 size_int (STACK_POINTER_OFFSET
)),
504 unshare_expr (args
));
506 /* Adjust the address of va_arg if it is in big endian mode. */
507 if (BYTES_BIG_ENDIAN
&& rsize
> size
)
508 tmp
= fold_build_pointer_plus_hwi (tmp
, rsize
- size
);
509 gimplify_assign (addr
, tmp
, pre_p
);
511 /* Update VALIST.__args. */
513 if (BYTES_BIG_ENDIAN
&& rsize
> size
)
514 tmp
= fold_build_pointer_plus_hwi (addr
, size
);
516 tmp
= fold_build_pointer_plus_hwi (addr
, rsize
);
517 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
519 addr
= fold_convert (build_pointer_type (type
), addr
);
521 if (pass_by_reference_p
)
522 addr
= build_va_arg_indirect_ref (addr
);
524 return build_va_arg_indirect_ref (addr
);
529 /* Implement TARGET_RTX_COSTS. */
531 tilegx_rtx_costs (rtx x
, machine_mode mode
, int outer_code
, int opno
,
532 int *total
, bool speed
)
534 int code
= GET_CODE (x
);
539 /* If this is an 8-bit constant, return zero since it can be
540 used nearly anywhere with no cost. If it is a valid operand
541 for an ADD or AND, likewise return 0 if we know it will be
542 used in that context. Otherwise, return 2 since it might be
543 used there later. All other constants take at least two
545 if (satisfies_constraint_I (x
))
550 else if (outer_code
== PLUS
&& add_operand (x
, VOIDmode
))
552 /* Slightly penalize large constants even though we can add
553 them in one instruction, because it forces the use of
554 2-wide bundling mode. */
558 else if (move_operand (x
, SImode
))
560 /* We can materialize in one move. */
561 *total
= COSTS_N_INSNS (1);
566 /* We can materialize in two moves. */
567 *total
= COSTS_N_INSNS (2);
576 *total
= COSTS_N_INSNS (2);
580 *total
= COSTS_N_INSNS (4);
588 /* If outer-code was a sign or zero extension, a cost of
589 COSTS_N_INSNS (1) was already added in, so account for
591 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
592 *total
= COSTS_N_INSNS (1);
594 *total
= COSTS_N_INSNS (2);
598 /* Convey that shl[123]add are efficient. */
599 if (GET_CODE (XEXP (x
, 0)) == MULT
600 && cint_248_operand (XEXP (XEXP (x
, 0), 1), VOIDmode
))
602 *total
= (rtx_cost (XEXP (XEXP (x
, 0), 0), mode
,
603 (enum rtx_code
) outer_code
, opno
, speed
)
604 + rtx_cost (XEXP (x
, 1), mode
,
605 (enum rtx_code
) outer_code
, opno
, speed
)
606 + COSTS_N_INSNS (1));
612 *total
= COSTS_N_INSNS (2);
619 /* These are handled by software and are very expensive. */
620 *total
= COSTS_N_INSNS (100);
624 case UNSPEC_VOLATILE
:
626 int num
= XINT (x
, 1);
628 if (num
<= TILEGX_LAST_LATENCY_1_INSN
)
629 *total
= COSTS_N_INSNS (1);
630 else if (num
<= TILEGX_LAST_LATENCY_2_INSN
)
631 *total
= COSTS_N_INSNS (2);
632 else if (num
> TILEGX_LAST_LATENCY_INSN
)
634 if (num
== UNSPEC_NON_TEMPORAL
)
636 /* These are basically loads. */
637 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
638 *total
= COSTS_N_INSNS (1);
640 *total
= COSTS_N_INSNS (2);
644 if (outer_code
== PLUS
)
647 *total
= COSTS_N_INSNS (1);
654 case UNSPEC_BLOCKAGE
:
655 case UNSPEC_NETWORK_BARRIER
:
660 case UNSPEC_LNK_AND_LABEL
:
662 case UNSPEC_MOV_PCREL_STEP3
:
663 case UNSPEC_NETWORK_RECEIVE
:
664 case UNSPEC_NETWORK_SEND
:
665 case UNSPEC_SPR_MOVE
:
666 case UNSPEC_TLS_GD_ADD
:
667 *total
= COSTS_N_INSNS (1);
670 case UNSPEC_TLS_IE_LOAD
:
672 *total
= COSTS_N_INSNS (2);
676 *total
= COSTS_N_INSNS (3);
680 *total
= COSTS_N_INSNS (4);
684 case UNSPEC_INSN_CMPEXCH
:
685 case UNSPEC_LATENCY_L2
:
686 *total
= COSTS_N_INSNS (11);
689 case UNSPEC_TLS_GD_CALL
:
690 *total
= COSTS_N_INSNS (30);
693 case UNSPEC_LATENCY_MISS
:
694 *total
= COSTS_N_INSNS (80);
698 *total
= COSTS_N_INSNS (1);
713 /* Create a temporary variable to hold a partial result, to enable
716 create_temp_reg_if_possible (machine_mode mode
, rtx default_reg
)
718 return can_create_pseudo_p () ? gen_reg_rtx (mode
) : default_reg
;
722 /* Functions to save and restore machine-specific function data. */
723 static struct machine_function
*
724 tilegx_init_machine_status (void)
726 return ggc_cleared_alloc
<machine_function
> ();
730 /* Do anything needed before RTL is emitted for each function. */
732 tilegx_init_expanders (void)
734 /* Arrange to initialize and mark the machine per-function
736 init_machine_status
= tilegx_init_machine_status
;
738 if (cfun
&& cfun
->machine
&& flag_pic
)
740 static int label_num
= 0;
742 char text_label_name
[32];
744 struct machine_function
*machine
= cfun
->machine
;
746 ASM_GENERATE_INTERNAL_LABEL (text_label_name
, "L_PICLNK", label_num
++);
748 machine
->text_label_symbol
=
749 gen_rtx_SYMBOL_REF (Pmode
, ggc_strdup (text_label_name
));
751 machine
->text_label_rtx
=
752 gen_rtx_REG (Pmode
, TILEGX_PIC_TEXT_LABEL_REGNUM
);
754 machine
->got_rtx
= gen_rtx_REG (Pmode
, PIC_OFFSET_TABLE_REGNUM
);
756 machine
->calls_tls_get_addr
= false;
761 /* Implement TARGET_EXPAND_TO_RTL_HOOK. */
763 tilegx_expand_to_rtl_hook (void)
765 /* Exclude earlier sets of crtl->uses_pic_offset_table, because we
766 only care about uses actually emitted. */
767 crtl
->uses_pic_offset_table
= 0;
771 /* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode
772 matching insns and therefore guarantee that the shift count is
773 modulo 64. SImode shifts sometimes use the 64 bit version so do
774 not hold such guarantee. */
775 static unsigned HOST_WIDE_INT
776 tilegx_shift_truncation_mask (machine_mode mode
)
778 return mode
== DImode
? 63 : 0;
782 /* Implement TARGET_INIT_LIBFUNCS. */
784 tilegx_init_libfuncs (void)
786 /* We need to explicitly generate these libfunc's to support
787 conversion of divide by constant to multiply (the divide stubs in
788 tilegx.md exist also for this reason). Normally we'd expect gcc
789 to lazily generate them when they are needed, but for some reason
790 it's set up to only generate them if the mode is the word
792 set_optab_libfunc (sdiv_optab
, SImode
, "__divsi3");
793 set_optab_libfunc (udiv_optab
, SImode
, "__udivsi3");
794 set_optab_libfunc (smod_optab
, SImode
, "__modsi3");
795 set_optab_libfunc (umod_optab
, SImode
, "__umodsi3");
799 /* Return true if X contains a thread-local symbol. */
801 tilegx_tls_referenced_p (rtx x
)
803 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == PLUS
)
804 x
= XEXP (XEXP (x
, 0), 0);
806 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
))
809 /* That's all we handle in tilegx_legitimize_tls_address for
815 /* Return true if X requires a scratch register. It is given that
816 flag_pic is on and that X satisfies CONSTANT_P. */
818 tilegx_pic_address_needs_scratch (rtx x
)
820 if (GET_CODE (x
) == CONST
821 && GET_CODE (XEXP (x
, 0)) == PLUS
822 && (GET_CODE (XEXP (XEXP (x
, 0), 0)) == SYMBOL_REF
823 || GET_CODE (XEXP (XEXP (x
, 0), 0)) == LABEL_REF
)
824 && (CONST_INT_P (XEXP (XEXP (x
, 0), 1))))
831 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
832 which we are willing to load the value into a register via a move
833 pattern. TLS cannot be treated as a constant because it can
834 include a function call. */
836 tilegx_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
838 switch (GET_CODE (x
))
842 return !tilegx_tls_referenced_p (x
);
850 /* Return true if the constant value X is a legitimate general operand
851 when generating PIC code. It is given that flag_pic is on and that
852 X satisfies CONSTANT_P. */
854 tilegx_legitimate_pic_operand_p (rtx x
)
856 if (tilegx_pic_address_needs_scratch (x
))
859 if (tilegx_tls_referenced_p (x
))
866 /* Return true if the rtx X can be used as an address operand. */
868 tilegx_legitimate_address_p (machine_mode
ARG_UNUSED (mode
), rtx x
,
871 if (GET_CODE (x
) == SUBREG
)
874 switch (GET_CODE (x
))
878 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
885 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
888 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
891 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
894 if (!satisfies_constraint_I (XEXP (XEXP (x
, 1), 1)))
907 /* Check if x is a valid reg. */
912 return REGNO_OK_FOR_BASE_P (REGNO (x
));
918 /* Return the rtx containing SYMBOL_REF to the text label. */
920 tilegx_text_label_symbol (void)
922 return cfun
->machine
->text_label_symbol
;
926 /* Return the register storing the value of the text label. */
928 tilegx_text_label_rtx (void)
930 return cfun
->machine
->text_label_rtx
;
934 /* Return the register storing the value of the global offset
937 tilegx_got_rtx (void)
939 return cfun
->machine
->got_rtx
;
943 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
945 tilegx_got_symbol (void)
947 if (g_got_symbol
== NULL
)
948 g_got_symbol
= gen_rtx_SYMBOL_REF (Pmode
, "_GLOBAL_OFFSET_TABLE_");
954 /* Return a reference to the got to be used by tls references. */
956 tilegx_tls_got (void)
961 crtl
->uses_pic_offset_table
= 1;
962 return tilegx_got_rtx ();
965 temp
= gen_reg_rtx (Pmode
);
966 emit_move_insn (temp
, tilegx_got_symbol ());
972 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
973 this (thread-local) address. */
975 tilegx_legitimize_tls_address (rtx addr
)
979 gcc_assert (can_create_pseudo_p ());
981 if (GET_CODE (addr
) == SYMBOL_REF
)
982 switch (SYMBOL_REF_TLS_MODEL (addr
))
984 case TLS_MODEL_GLOBAL_DYNAMIC
:
985 case TLS_MODEL_LOCAL_DYNAMIC
:
987 rtx r0
, temp
, temp2
, temp3
, got
;
989 ret
= gen_reg_rtx (Pmode
);
990 r0
= gen_rtx_REG (Pmode
, 0);
991 temp
= gen_reg_rtx (Pmode
);
992 temp2
= gen_reg_rtx (Pmode
);
993 temp3
= gen_reg_rtx (Pmode
);
995 got
= tilegx_tls_got ();
998 emit_insn (gen_mov_tls_gd_step1_32bit (temp
, addr
));
999 emit_insn (gen_mov_tls_gd_step2_32bit (temp2
, temp
, addr
));
1000 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
1004 emit_insn (gen_mov_tls_gd_step1 (temp
, addr
));
1005 emit_insn (gen_mov_tls_gd_step2 (temp2
, temp
, addr
));
1006 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
1009 emit_move_insn (r0
, temp2
);
1013 emit_insn (gen_tls_gd_call_32bit (addr
));
1017 emit_insn (gen_tls_gd_call (addr
));
1020 emit_move_insn (temp3
, r0
);
1024 last
= emit_insn (gen_tls_gd_add_32bit (ret
, temp3
, addr
));
1026 last
= emit_insn (gen_tls_gd_add (ret
, temp3
, addr
));
1028 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1031 case TLS_MODEL_INITIAL_EXEC
:
1033 rtx temp
, temp2
, temp3
, got
;
1036 ret
= gen_reg_rtx (Pmode
);
1037 temp
= gen_reg_rtx (Pmode
);
1038 temp2
= gen_reg_rtx (Pmode
);
1039 temp3
= gen_reg_rtx (Pmode
);
1041 got
= tilegx_tls_got ();
1044 emit_insn (gen_mov_tls_ie_step1_32bit (temp
, addr
));
1045 emit_insn (gen_mov_tls_ie_step2_32bit (temp2
, temp
, addr
));
1046 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
1047 emit_insn (gen_tls_ie_load_32bit (temp3
, temp2
, addr
));
1051 emit_insn (gen_mov_tls_ie_step1 (temp
, addr
));
1052 emit_insn (gen_mov_tls_ie_step2 (temp2
, temp
, addr
));
1053 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
1054 emit_insn (gen_tls_ie_load (temp3
, temp2
, addr
));
1059 gen_rtx_PLUS (Pmode
,
1061 THREAD_POINTER_REGNUM
),
1063 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1066 case TLS_MODEL_LOCAL_EXEC
:
1071 ret
= gen_reg_rtx (Pmode
);
1072 temp
= gen_reg_rtx (Pmode
);
1073 temp2
= gen_reg_rtx (Pmode
);
1077 emit_insn (gen_mov_tls_le_step1_32bit (temp
, addr
));
1078 emit_insn (gen_mov_tls_le_step2_32bit (temp2
, temp
, addr
));
1082 emit_insn (gen_mov_tls_le_step1 (temp
, addr
));
1083 emit_insn (gen_mov_tls_le_step2 (temp2
, temp
, addr
));
1087 emit_move_insn (ret
,
1088 gen_rtx_PLUS (Pmode
,
1090 THREAD_POINTER_REGNUM
),
1092 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1098 else if (GET_CODE (addr
) == CONST
)
1102 gcc_assert (GET_CODE (XEXP (addr
, 0)) == PLUS
);
1104 base
= tilegx_legitimize_tls_address (XEXP (XEXP (addr
, 0), 0));
1105 offset
= XEXP (XEXP (addr
, 0), 1);
1107 base
= force_operand (base
, NULL_RTX
);
1108 ret
= force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1117 /* Returns a register that points to ADDR, a symbolic address, by
1118 computing its address relative to tilegx_text_label_symbol. */
1120 tilegx_compute_pcrel_address (rtx result
, rtx addr
)
1122 rtx text_label_symbol
= tilegx_text_label_symbol ();
1123 rtx text_label_rtx
= tilegx_text_label_rtx ();
1124 rtx temp
, temp2
, temp3
;
1126 temp
= create_temp_reg_if_possible (Pmode
, result
);
1127 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1131 emit_insn (gen_mov_pcrel_step1_32bit (temp
, addr
, text_label_symbol
));
1132 emit_insn (gen_mov_pcrel_step2_32bit (temp2
, temp
, addr
,
1133 text_label_symbol
));
1134 emit_insn (gen_mov_pcrel_step3_32bit (result
, temp2
,
1136 addr
, text_label_symbol
));
1138 else if (tilegx_cmodel
== CM_LARGE_PIC
)
1140 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1141 emit_insn (gen_mov_large_pcrel_step1 (temp
, addr
, text_label_symbol
));
1142 emit_insn (gen_mov_large_pcrel_step2 (temp2
, temp
, addr
,
1143 text_label_symbol
));
1144 emit_insn (gen_mov_large_pcrel_step3 (temp3
, temp2
, addr
,
1145 text_label_symbol
));
1146 emit_insn (gen_mov_large_pcrel_step4 (result
, temp3
,
1148 addr
, text_label_symbol
));
1152 emit_insn (gen_mov_pcrel_step1 (temp
, addr
, text_label_symbol
));
1153 emit_insn (gen_mov_pcrel_step2 (temp2
, temp
, addr
, text_label_symbol
));
1154 emit_insn (gen_mov_pcrel_step3 (result
, temp2
,
1156 addr
, text_label_symbol
));
1161 /* Returns a register that points to the plt entry of ADDR, a symbolic
1162 address, by computing its address relative to
1163 tilegx_text_label_symbol. */
1165 tilegx_compute_pcrel_plt_address (rtx result
, rtx addr
)
1167 rtx text_label_symbol
= tilegx_text_label_symbol ();
1168 rtx text_label_rtx
= tilegx_text_label_rtx ();
1169 rtx temp
, temp2
, temp3
;
1171 temp
= create_temp_reg_if_possible (Pmode
, result
);
1172 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1176 emit_insn (gen_mov_plt_pcrel_step1_32bit (temp
, addr
,
1177 text_label_symbol
));
1178 emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2
, temp
, addr
,
1179 text_label_symbol
));
1180 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp2
, text_label_rtx
));
1184 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1186 emit_insn (gen_mov_plt_pcrel_step1 (temp
, addr
, text_label_symbol
));
1187 emit_insn (gen_mov_plt_pcrel_step2 (temp2
, temp
, addr
,
1188 text_label_symbol
));
1189 emit_insn (gen_mov_plt_pcrel_step3 (temp3
, temp2
, addr
,
1190 text_label_symbol
));
1191 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp3
, text_label_rtx
));
1196 /* Legitimize PIC addresses. If the address is already
1197 position-independent, we return ORIG. Newly generated
1198 position-independent addresses go into a reg. This is REG if
1199 nonzero, otherwise we allocate register(s) as necessary. */
1201 tilegx_legitimize_pic_address (rtx orig
,
1202 machine_mode mode ATTRIBUTE_UNUSED
,
1205 if (GET_CODE (orig
) == SYMBOL_REF
)
1207 rtx address
, pic_ref
;
1211 gcc_assert (can_create_pseudo_p ());
1212 reg
= gen_reg_rtx (Pmode
);
1215 if (SYMBOL_REF_LOCAL_P (orig
))
1217 /* If not during reload, allocate another temp reg here for
1218 loading in the address, so that these instructions can be
1219 optimized properly. */
1220 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1221 tilegx_compute_pcrel_address (temp_reg
, orig
);
1223 /* Note: this is conservative. We use the text_label but we
1224 don't use the pic_offset_table. However, in some cases
1225 we may need the pic_offset_table (see
1226 tilegx_fixup_pcrel_references). */
1227 crtl
->uses_pic_offset_table
= 1;
1231 emit_move_insn (reg
, address
);
1236 /* If not during reload, allocate another temp reg here for
1237 loading in the address, so that these instructions can be
1238 optimized properly. */
1239 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1241 gcc_assert (flag_pic
);
1246 emit_insn (gen_add_got16_32bit (temp_reg
,
1252 emit_insn (gen_add_got16 (temp_reg
,
1253 tilegx_got_rtx (), orig
));
1258 rtx temp_reg2
= create_temp_reg_if_possible (Pmode
, reg
);
1259 rtx temp_reg3
= create_temp_reg_if_possible (Pmode
, reg
);
1262 emit_insn (gen_mov_got32_step1_32bit (temp_reg3
, orig
));
1263 emit_insn (gen_mov_got32_step2_32bit
1264 (temp_reg2
, temp_reg3
, orig
));
1268 emit_insn (gen_mov_got32_step1 (temp_reg3
, orig
));
1269 emit_insn (gen_mov_got32_step2 (temp_reg2
, temp_reg3
,
1272 emit_move_insn (temp_reg
,
1273 gen_rtx_PLUS (Pmode
,
1274 tilegx_got_rtx (), temp_reg2
));
1279 pic_ref
= gen_const_mem (Pmode
, address
);
1280 crtl
->uses_pic_offset_table
= 1;
1281 emit_move_insn (reg
, pic_ref
);
1282 /* The following put a REG_EQUAL note on this insn, so that
1283 it can be optimized by loop. But it causes the label to
1284 be optimized away. */
1285 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1289 else if (GET_CODE (orig
) == CONST
)
1293 if (GET_CODE (XEXP (orig
, 0)) == PLUS
1294 && XEXP (XEXP (orig
, 0), 0) == tilegx_got_rtx ())
1299 gcc_assert (can_create_pseudo_p ());
1300 reg
= gen_reg_rtx (Pmode
);
1303 gcc_assert (GET_CODE (XEXP (orig
, 0)) == PLUS
);
1304 base
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 0),
1306 offset
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 1), Pmode
,
1307 base
== reg
? 0 : reg
);
1309 if (CONST_INT_P (offset
))
1311 if (can_create_pseudo_p ())
1312 offset
= force_reg (Pmode
, offset
);
1314 /* If we reach here, then something is seriously wrong. */
1318 if (can_create_pseudo_p ())
1319 return force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1323 else if (GET_CODE (orig
) == LABEL_REF
)
1330 gcc_assert (can_create_pseudo_p ());
1331 reg
= gen_reg_rtx (Pmode
);
1334 /* If not during reload, allocate another temp reg here for
1335 loading in the address, so that these instructions can be
1336 optimized properly. */
1337 temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1338 tilegx_compute_pcrel_address (temp_reg
, orig
);
1340 /* Note: this is conservative. We use the text_label but we
1341 don't use the pic_offset_table. */
1342 crtl
->uses_pic_offset_table
= 1;
1346 emit_move_insn (reg
, address
);
1355 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1357 tilegx_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
1360 if (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
1361 && symbolic_operand (x
, Pmode
) && tilegx_tls_referenced_p (x
))
1363 return tilegx_legitimize_tls_address (x
);
1367 return tilegx_legitimize_pic_address (x
, mode
, 0);
1374 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1376 tilegx_delegitimize_address (rtx x
)
1378 x
= delegitimize_mem_from_attrs (x
);
1380 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == UNSPEC
)
1382 switch (XINT (XEXP (x
, 0), 1))
1388 case UNSPEC_HW0_LAST
:
1389 case UNSPEC_HW1_LAST
:
1390 case UNSPEC_HW2_LAST
:
1391 case UNSPEC_HW0_PCREL
:
1392 case UNSPEC_HW1_PCREL
:
1393 case UNSPEC_HW1_LAST_PCREL
:
1394 case UNSPEC_HW2_LAST_PCREL
:
1395 case UNSPEC_HW0_PLT_PCREL
:
1396 case UNSPEC_HW1_PLT_PCREL
:
1397 case UNSPEC_HW1_LAST_PLT_PCREL
:
1398 case UNSPEC_HW2_LAST_PLT_PCREL
:
1399 case UNSPEC_HW0_GOT
:
1400 case UNSPEC_HW0_LAST_GOT
:
1401 case UNSPEC_HW1_LAST_GOT
:
1402 case UNSPEC_HW0_TLS_GD
:
1403 case UNSPEC_HW1_LAST_TLS_GD
:
1404 case UNSPEC_HW0_TLS_IE
:
1405 case UNSPEC_HW1_LAST_TLS_IE
:
1406 case UNSPEC_HW0_TLS_LE
:
1407 case UNSPEC_HW1_LAST_TLS_LE
:
1408 x
= XVECEXP (XEXP (x
, 0), 0, 0);
1417 /* Emit code to load the PIC register. */
1419 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED
)
1421 int orig_flag_pic
= flag_pic
;
1423 rtx got_symbol
= tilegx_got_symbol ();
1424 rtx text_label_symbol
= tilegx_text_label_symbol ();
1425 rtx text_label_rtx
= tilegx_text_label_rtx ();
1430 emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx
,
1431 text_label_symbol
));
1435 emit_insn (gen_insn_lnk_and_label (text_label_rtx
, text_label_symbol
));
1438 tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol
);
1440 flag_pic
= orig_flag_pic
;
1442 /* Need to emit this whether or not we obey regdecls, since
1443 setjmp/longjmp can cause life info to screw up. ??? In the case
1444 where we don't obey regdecls, this is not sufficient since we may
1445 not fall out the bottom. */
1446 emit_use (tilegx_got_rtx ());
1450 /* Return the simd variant of the constant NUM of mode MODE, by
1451 replicating it to fill an interger of mode DImode. NUM is first
1452 truncated to fit in MODE. */
1454 tilegx_simd_int (rtx num
, machine_mode mode
)
1456 HOST_WIDE_INT n
= 0;
1458 gcc_assert (CONST_INT_P (num
));
1465 n
= 0x0101010101010101LL
* (n
& 0x000000FF);
1468 n
= 0x0001000100010001LL
* (n
& 0x0000FFFF);
1471 n
= 0x0000000100000001LL
* (n
& 0xFFFFFFFF);
1483 /* Returns true iff VAL can be moved into a register in one
1484 instruction. And if it can, it emits the code to move the constant
1487 If THREE_WIDE_ONLY is true, this insists on an instruction that
1488 works in a bundle containing three instructions. */
1490 expand_set_cint64_one_inst (rtx dest_reg
,
1491 HOST_WIDE_INT val
, bool three_wide_only
)
1493 if (val
== trunc_int_for_mode (val
, QImode
))
1496 emit_move_insn (dest_reg
, GEN_INT (val
));
1499 else if (!three_wide_only
)
1501 /* Test for the following constraints: J, K, N, P. We avoid
1502 generating an rtx and using existing predicates because we
1503 can be testing and rejecting a lot of constants, and GEN_INT
1505 if ((val
>= -32768 && val
<= 65535)
1506 || ((val
== (val
& 0xFF) * 0x0101010101010101LL
))
1507 || (val
== ((trunc_int_for_mode (val
, QImode
) & 0xFFFF)
1508 * 0x0001000100010001LL
)))
1510 emit_move_insn (dest_reg
, GEN_INT (val
));
1519 /* Implement DImode rotatert. */
1520 static HOST_WIDE_INT
1521 rotate_right (HOST_WIDE_INT n
, int count
)
1523 unsigned HOST_WIDE_INT x
= n
& 0xFFFFFFFFFFFFFFFFULL
;
1526 return ((x
>> count
) | (x
<< (64 - count
))) & 0xFFFFFFFFFFFFFFFFULL
;
1530 /* Return true iff n contains exactly one contiguous sequence of 1
1531 bits, possibly wrapping around from high bits to low bits. */
1533 tilegx_bitfield_operand_p (HOST_WIDE_INT n
, int *first_bit
, int *last_bit
)
1540 for (i
= 0; i
< 64; i
++)
1542 unsigned HOST_WIDE_INT x
= rotate_right (n
, i
);
1546 /* See if x is a power of two minus one, i.e. only consecutive 1
1547 bits starting from bit 0. */
1548 if ((x
& (x
+ 1)) == 0)
1550 if (first_bit
!= NULL
)
1552 if (last_bit
!= NULL
)
1553 *last_bit
= (i
+ exact_log2 (x
^ (x
>> 1))) & 63;
1563 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1565 expand_set_cint64 (rtx dest_reg
, rtx src_val
)
1568 int leading_zeroes
, trailing_zeroes
;
1569 int three_wide_only
;
1570 int shift
, ins_shift
, zero_cluster_shift
;
1573 gcc_assert (CONST_INT_P (src_val
));
1574 val
= trunc_int_for_mode (INTVAL (src_val
), GET_MODE (dest_reg
));
1576 /* See if we can generate the constant in one instruction. */
1577 if (expand_set_cint64_one_inst (dest_reg
, val
, false))
1580 /* Force the destination to DImode so we can use DImode instructions
1581 to create it. This both allows instructions like rotl, and
1582 certain efficient 3-wide instructions. */
1583 subreg
= simplify_gen_subreg (DImode
, dest_reg
, GET_MODE (dest_reg
), 0);
1584 gcc_assert (subreg
!= NULL
);
1587 temp
= create_temp_reg_if_possible (DImode
, dest_reg
);
1589 leading_zeroes
= 63 - floor_log2 (val
& 0xFFFFFFFFFFFFFFFFULL
);
1590 trailing_zeroes
= exact_log2 (val
& -val
);
1592 /* First try all three-wide instructions that generate a constant
1593 (i.e. movei) followed by various shifts and rotates. If none of
1594 those work, try various two-wide ways of generating a constant
1595 followed by various shifts and rotates. */
1596 for (three_wide_only
= 1; three_wide_only
>= 0; three_wide_only
--)
1600 if (expand_set_cint64_one_inst (temp
, val
>> trailing_zeroes
,
1603 /* 0xFFFFFFFFFFFFA500 becomes:
1604 movei temp, 0xFFFFFFFFFFFFFFA5
1605 shli dest, temp, 8 */
1606 emit_move_insn (dest_reg
,
1607 gen_rtx_ASHIFT (DImode
, temp
,
1608 GEN_INT (trailing_zeroes
)));
1612 if (expand_set_cint64_one_inst (temp
, val
<< leading_zeroes
,
1615 /* 0x7FFFFFFFFFFFFFFF becomes:
1617 shrui dest, temp, 1 */
1618 emit_move_insn (dest_reg
,
1619 gen_rtx_LSHIFTRT (DImode
, temp
,
1620 GEN_INT (leading_zeroes
)));
1624 /* Try rotating a one-instruction immediate. */
1625 for (count
= 1; count
< 64; count
++)
1627 HOST_WIDE_INT r
= rotate_right (val
, count
);
1628 if (expand_set_cint64_one_inst (temp
, r
, three_wide_only
))
1630 /* 0xFFFFFFFFFFA5FFFF becomes:
1631 movei temp, 0xFFFFFFFFFFFFFFA5
1632 rotli dest, temp, 16 */
1633 emit_move_insn (dest_reg
,
1634 gen_rtx_ROTATE (DImode
, temp
, GEN_INT (count
)));
1640 /* There are two cases here to produce a large constant.
1641 In the most general case, we do this:
1644 shl16insli x, x, hw2(NUM)
1645 shl16insli x, x, hw1(NUM)
1646 shl16insli x, x, hw0(NUM)
1648 However, we can sometimes do better. shl16insli is a poor way to
1649 insert 16 zero bits, because simply shifting left by 16 has more
1650 bundling freedom. So if we see any contiguous aligned sequence
1651 of 16 or more zero bits (below the highest set bit), it is always
1652 more efficient to materialize the bits above the zero bits, then
1653 left shift to put in the zeroes, then insert whatever bits
1654 remain. For example, we might end up with:
1656 movei x, NUM >> (37 + 16)
1658 shl16insli x, x, hw0(NUM) */
1660 zero_cluster_shift
= -1;
1662 for (shift
= 0; shift
< 48 - leading_zeroes
; shift
+= 16)
1664 HOST_WIDE_INT x
= val
>> shift
;
1666 /* Find the least significant group of 16 aligned zero bits. */
1667 if ((x
& 0xFFFF) == 0x0000)
1669 /* Grab any following zero bits as well. */
1670 zero_cluster_shift
= exact_log2 (x
& -x
);
1671 shift
+= zero_cluster_shift
;
1676 if (zero_cluster_shift
>= 0)
1678 unsigned HOST_WIDE_INT leftover
;
1680 /* Recursively create the constant above the lowest 16 zero
1682 expand_set_cint64 (temp
, GEN_INT (val
>> shift
));
1684 /* See if we can easily insert the remaining bits, or if we need
1685 to fall through to the more general case. */
1686 leftover
= val
- ((val
>> shift
) << shift
);
1689 /* A simple left shift is enough. */
1690 emit_move_insn (dest_reg
,
1691 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1694 else if (leftover
<= 32767)
1696 /* Left shift into position then add in the leftover. */
1697 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1698 emit_move_insn (temp2
,
1699 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1700 emit_move_insn (dest_reg
,
1701 gen_rtx_PLUS (DImode
, temp2
, GEN_INT (leftover
)));
1706 /* Shift in the batch of >= 16 zeroes we detected earlier.
1707 After this, shift will be aligned mod 16 so the final
1708 loop can use shl16insli. */
1709 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1710 rtx shift_count_rtx
= GEN_INT (zero_cluster_shift
);
1712 emit_move_insn (temp2
,
1713 gen_rtx_ASHIFT (DImode
, temp
, shift_count_rtx
));
1715 shift
-= zero_cluster_shift
;
1721 /* Set as many high 16-bit blocks as we can with a single
1722 instruction. We'll insert the remaining 16-bit blocks
1724 for (shift
= 16;; shift
+= 16)
1726 gcc_assert (shift
< 64);
1727 if (expand_set_cint64_one_inst (temp
, val
>> shift
, false))
1732 /* At this point, temp == val >> shift, shift % 16 == 0, and we
1733 still need to insert any bits of 'val' below 'shift'. Those bits
1734 are guaranteed to not have 16 contiguous zeroes. */
1736 gcc_assert ((shift
& 15) == 0);
1738 for (ins_shift
= shift
- 16; ins_shift
>= 0; ins_shift
-= 16)
1741 HOST_WIDE_INT bits
= (val
>> ins_shift
) & 0xFFFF;
1742 gcc_assert (bits
!= 0);
1744 /* On the last iteration we need to store into dest_reg. */
1748 result
= create_temp_reg_if_possible (DImode
, dest_reg
);
1750 emit_insn (gen_insn_shl16insli (result
, temp
, GEN_INT (bits
)));
1757 /* Load OP1, a 64-bit constant, into OP0, a register. We know it
1758 can't be done in one insn when we get here, the move expander
1761 tilegx_expand_set_const64 (rtx op0
, rtx op1
)
1763 if (CONST_INT_P (op1
))
1765 /* TODO: I don't know if we want to split large constants
1766 now, or wait until later (with a define_split).
1768 Does splitting early help CSE? Does it harm other
1769 optimizations that might fold loads? */
1770 expand_set_cint64 (op0
, op1
);
1774 rtx temp
= create_temp_reg_if_possible (Pmode
, op0
);
1778 /* Generate the 2-insn sequence to materialize a symbolic
1780 emit_insn (gen_mov_address_32bit_step1 (temp
, op1
));
1781 emit_insn (gen_mov_address_32bit_step2 (op0
, temp
, op1
));
1785 /* Generate the 3-insn sequence to materialize a symbolic
1786 address. Note that this assumes that virtual addresses
1787 fit in 48 signed bits, which is currently true. */
1788 rtx temp2
= create_temp_reg_if_possible (Pmode
, op0
);
1789 emit_insn (gen_mov_address_step1 (temp
, op1
));
1790 emit_insn (gen_mov_address_step2 (temp2
, temp
, op1
));
1791 emit_insn (gen_mov_address_step3 (op0
, temp2
, op1
));
1797 /* Expand a move instruction. Return true if all work is done. */
1799 tilegx_expand_mov (machine_mode mode
, rtx
*operands
)
1801 /* Handle sets of MEM first. */
1802 if (MEM_P (operands
[0]))
1804 if (can_create_pseudo_p ())
1805 operands
[0] = validize_mem (operands
[0]);
1807 if (reg_or_0_operand (operands
[1], mode
))
1810 if (!reload_in_progress
)
1811 operands
[1] = force_reg (mode
, operands
[1]);
1814 /* Fixup TLS cases. */
1815 if (CONSTANT_P (operands
[1]) && tilegx_tls_referenced_p (operands
[1]))
1817 operands
[1] = tilegx_legitimize_tls_address (operands
[1]);
1821 /* Fixup PIC cases. */
1822 if (flag_pic
&& CONSTANT_P (operands
[1]))
1824 if (tilegx_pic_address_needs_scratch (operands
[1]))
1825 operands
[1] = tilegx_legitimize_pic_address (operands
[1], mode
, 0);
1827 if (symbolic_operand (operands
[1], mode
))
1829 operands
[1] = tilegx_legitimize_pic_address (operands
[1],
1831 (reload_in_progress
?
1838 /* Accept non-constants and valid constants unmodified. */
1839 if (!CONSTANT_P (operands
[1]) || move_operand (operands
[1], mode
))
1842 /* Split large integers. */
1843 tilegx_expand_set_const64 (operands
[0], operands
[1]);
1848 /* Expand unaligned loads. */
1850 tilegx_expand_unaligned_load (rtx dest_reg
, rtx mem
, HOST_WIDE_INT bitsize
,
1851 HOST_WIDE_INT bit_offset
, bool sign
)
1854 rtx addr_lo
, addr_hi
;
1855 rtx mem_lo
, mem_hi
, hi
;
1856 rtx mema
, wide_result
;
1857 int last_byte_offset
;
1858 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1860 mode
= GET_MODE (dest_reg
);
1862 if (bitsize
== 2 * BITS_PER_UNIT
&& (bit_offset
% BITS_PER_UNIT
) == 0)
1864 rtx mem_left
, mem_right
;
1865 rtx left
= gen_reg_rtx (mode
);
1867 /* When just loading a two byte value, we can load the two bytes
1868 individually and combine them efficiently. */
1870 mem_lo
= adjust_address (mem
, QImode
, byte_offset
);
1871 mem_hi
= adjust_address (mem
, QImode
, byte_offset
+ 1);
1873 if (BYTES_BIG_ENDIAN
)
1886 /* Do a signed load of the second byte and use bfins to set
1887 the high bits of the result. */
1888 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, dest_reg
),
1890 emit_insn (gen_extendqidi2 (gen_lowpart (DImode
, left
), mem_left
));
1891 emit_insn (gen_insv (gen_lowpart (DImode
, dest_reg
),
1892 GEN_INT (64 - 8), GEN_INT (8),
1893 gen_lowpart (DImode
, left
)));
1897 /* Do two unsigned loads and use v1int_l to interleave
1899 rtx right
= gen_reg_rtx (mode
);
1900 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, right
),
1902 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, left
),
1904 emit_insn (gen_insn_v1int_l (gen_lowpart (DImode
, dest_reg
),
1905 gen_lowpart (DImode
, left
),
1906 gen_lowpart (DImode
, right
)));
1912 mema
= XEXP (mem
, 0);
1914 /* AND addresses cannot be in any alias set, since they may
1915 implicitly alias surrounding code. Ideally we'd have some alias
1916 set that covered all types except those with alignment 8 or
1918 addr_lo
= force_reg (Pmode
, plus_constant (Pmode
, mema
, byte_offset
));
1919 mem_lo
= change_address (mem
, mode
,
1920 gen_rtx_AND (GET_MODE (mema
), addr_lo
,
1922 set_mem_alias_set (mem_lo
, 0);
1924 /* Load the high word at an address that will not fault if the low
1925 address is aligned and at the very end of a page. */
1926 last_byte_offset
= (bit_offset
+ bitsize
- 1) / BITS_PER_UNIT
;
1927 addr_hi
= force_reg (Pmode
, plus_constant (Pmode
, mema
, last_byte_offset
));
1928 mem_hi
= change_address (mem
, mode
,
1929 gen_rtx_AND (GET_MODE (mema
), addr_hi
,
1931 set_mem_alias_set (mem_hi
, 0);
1935 addr_lo
= make_safe_from (addr_lo
, dest_reg
);
1936 wide_result
= dest_reg
;
1940 wide_result
= gen_reg_rtx (mode
);
1943 /* Load hi first in case dest_reg is used in mema. */
1944 hi
= gen_reg_rtx (mode
);
1945 emit_move_insn (hi
, mem_hi
);
1946 emit_move_insn (wide_result
, mem_lo
);
1948 emit_insn (gen_insn_dblalign (gen_lowpart (DImode
, wide_result
),
1949 gen_lowpart (DImode
, wide_result
),
1950 gen_lowpart (DImode
, hi
), addr_lo
));
1955 extract_bit_field (gen_lowpart (DImode
, wide_result
),
1956 bitsize
, bit_offset
% BITS_PER_UNIT
,
1957 !sign
, gen_lowpart (DImode
, dest_reg
),
1958 DImode
, DImode
, false, NULL
);
1960 if (extracted
!= dest_reg
)
1961 emit_move_insn (dest_reg
, gen_lowpart (DImode
, extracted
));
1966 /* Expand unaligned stores. */
1968 tilegx_expand_unaligned_store (rtx mem
, rtx src
, HOST_WIDE_INT bitsize
,
1969 HOST_WIDE_INT bit_offset
)
1971 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1972 HOST_WIDE_INT bytesize
= bitsize
/ BITS_PER_UNIT
;
1973 HOST_WIDE_INT shift_init
, shift_increment
, shift_amt
;
1978 shift_init
= BYTES_BIG_ENDIAN
? (bitsize
- BITS_PER_UNIT
) : 0;
1979 shift_increment
= BYTES_BIG_ENDIAN
? -BITS_PER_UNIT
: BITS_PER_UNIT
;
1981 for (i
= 0, shift_amt
= shift_init
;
1983 i
++, shift_amt
+= shift_increment
)
1985 mem_addr
= adjust_address (mem
, QImode
, byte_offset
+ i
);
1989 store_val
= expand_simple_binop (DImode
, LSHIFTRT
,
1990 gen_lowpart (DImode
, src
),
1991 GEN_INT (shift_amt
), NULL
, 1,
1993 store_val
= gen_lowpart (QImode
, store_val
);
1997 store_val
= gen_lowpart (QImode
, src
);
2000 emit_move_insn (mem_addr
, store_val
);
2005 /* Implement the movmisalign patterns. One of the operands is a
2006 memory that is not naturally aligned. Emit instructions to load
2009 tilegx_expand_movmisalign (machine_mode mode
, rtx
*operands
)
2011 if (MEM_P (operands
[1]))
2015 if (register_operand (operands
[0], mode
))
2018 tmp
= gen_reg_rtx (mode
);
2020 tilegx_expand_unaligned_load (tmp
, operands
[1], GET_MODE_BITSIZE (mode
),
2023 if (tmp
!= operands
[0])
2024 emit_move_insn (operands
[0], tmp
);
2026 else if (MEM_P (operands
[0]))
2028 if (!reg_or_0_operand (operands
[1], mode
))
2029 operands
[1] = force_reg (mode
, operands
[1]);
2031 tilegx_expand_unaligned_store (operands
[0], operands
[1],
2032 GET_MODE_BITSIZE (mode
), 0);
2040 /* Implement the allocate_stack pattern (alloca). */
2042 tilegx_allocate_stack (rtx op0
, rtx op1
)
2044 /* Technically the correct way to initialize chain_loc is with
2045 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
2046 * sets the alias_set to that of a frame reference. Some of our
2047 * tests rely on some unsafe assumption about when the chaining
2048 * update is done, we need to be conservative about reordering the
2049 * chaining instructions.
2051 rtx fp_addr
= gen_reg_rtx (Pmode
);
2052 rtx fp_value
= gen_reg_rtx (Pmode
);
2055 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2056 GEN_INT (UNITS_PER_WORD
)));
2058 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
2060 emit_move_insn (fp_value
, fp_loc
);
2062 op1
= force_reg (Pmode
, op1
);
2064 emit_move_insn (stack_pointer_rtx
,
2065 gen_rtx_MINUS (Pmode
, stack_pointer_rtx
, op1
));
2067 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2068 GEN_INT (UNITS_PER_WORD
)));
2070 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
2072 emit_move_insn (fp_loc
, fp_value
);
2074 emit_move_insn (op0
, virtual_stack_dynamic_rtx
);
2082 /* Returns the insn_code in ENTRY. */
2083 static enum insn_code
2084 tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry
2087 return tilegx_multiply_insn_seq_decode_opcode
[entry
->compressed_opcode
];
2091 /* Returns the length of the 'op' array. */
2093 tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq
*seq
)
2095 /* The array either uses all of its allocated slots or is terminated
2096 by a bogus opcode. Either way, the array size is the index of the
2097 last valid opcode plus one. */
2099 for (i
= tilegx_multiply_insn_seq_MAX_OPERATIONS
- 1; i
>= 0; i
--)
2100 if (tilegx_multiply_get_opcode (&seq
->op
[i
]) != CODE_FOR_nothing
)
2103 /* An empty array is not allowed. */
2108 /* We precompute a number of expression trees for multiplying by
2109 constants. This generates code for such an expression tree by
2110 walking through the nodes in the tree (which are conveniently
2111 pre-linearized) and emitting an instruction for each one. */
2113 tilegx_expand_constant_multiply_given_sequence (rtx result
, rtx src
,
2115 tilegx_multiply_insn_seq
*seq
)
2120 /* Keep track of the subexpressions computed so far, so later
2121 instructions can refer to them. We seed the array with zero and
2122 the value being multiplied. */
2123 int num_subexprs
= 2;
2124 rtx subexprs
[tilegx_multiply_insn_seq_MAX_OPERATIONS
+ 2];
2125 subexprs
[0] = const0_rtx
;
2128 /* Determine how many instructions we are going to generate. */
2129 num_ops
= tilegx_multiply_get_num_ops (seq
);
2130 gcc_assert (num_ops
> 0
2131 && num_ops
<= tilegx_multiply_insn_seq_MAX_OPERATIONS
);
2133 for (i
= 0; i
< num_ops
; i
++)
2135 const struct tilegx_multiply_insn_seq_entry
*entry
= &seq
->op
[i
];
2137 /* Figure out where to store the output of this instruction. */
2138 const bool is_last_op
= (i
+ 1 == num_ops
);
2139 rtx out
= is_last_op
? result
: gen_reg_rtx (DImode
);
2141 enum insn_code opcode
= tilegx_multiply_get_opcode (entry
);
2142 if (opcode
== CODE_FOR_ashldi3
)
2144 /* Handle shift by immediate. This is a special case because
2145 the meaning of the second operand is a constant shift
2146 count rather than an operand index. */
2148 /* Make sure the shift count is in range. Zero should not
2150 const int shift_count
= entry
->rhs
;
2151 gcc_assert (shift_count
> 0 && shift_count
< 64);
2153 /* Emit the actual instruction. */
2154 emit_insn (GEN_FCN (opcode
)
2155 (out
, subexprs
[entry
->lhs
],
2156 gen_rtx_CONST_INT (DImode
, shift_count
)));
2160 /* Handle a normal two-operand instruction, such as add or
2163 /* Make sure we are referring to a previously computed
2165 gcc_assert (entry
->rhs
< num_subexprs
);
2167 /* Emit the actual instruction. */
2168 emit_insn (GEN_FCN (opcode
)
2169 (out
, subexprs
[entry
->lhs
], subexprs
[entry
->rhs
]));
2172 /* Record this subexpression for use by later expressions. */
2173 subexprs
[num_subexprs
++] = out
;
2178 /* bsearch helper function. */
2180 tilegx_compare_multipliers (const void *key
, const void *t
)
2183 (*(const long long *) key
2184 - ((const struct tilegx_multiply_insn_seq
*) t
)->multiplier
);
2185 return (delta
< 0) ? -1 : (delta
> 0);
2189 /* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none
2191 static const struct tilegx_multiply_insn_seq
*
2192 tilegx_find_multiply_insn_seq_for_constant (long long multiplier
)
2194 return ((const struct tilegx_multiply_insn_seq
*)
2195 bsearch (&multiplier
, tilegx_multiply_insn_seq_table
,
2196 tilegx_multiply_insn_seq_table_size
,
2197 sizeof tilegx_multiply_insn_seq_table
[0],
2198 tilegx_compare_multipliers
));
2202 /* Try to a expand constant multiply in DImode by looking it up in a
2203 precompiled table. OP0 is the result operand, OP1 is the source
2204 operand, and MULTIPLIER is the value of the constant. Return true
2207 tilegx_expand_const_muldi (rtx op0
, rtx op1
, long long multiplier
)
2209 /* See if we have precomputed an efficient way to multiply by this
2211 const struct tilegx_multiply_insn_seq
*seq
=
2212 tilegx_find_multiply_insn_seq_for_constant (multiplier
);
2215 tilegx_expand_constant_multiply_given_sequence (op0
, op1
, seq
);
2223 /* Expand the muldi pattern. */
2225 tilegx_expand_muldi (rtx op0
, rtx op1
, rtx op2
)
2227 if (CONST_INT_P (op2
))
2229 HOST_WIDE_INT n
= trunc_int_for_mode (INTVAL (op2
), DImode
);
2230 return tilegx_expand_const_muldi (op0
, op1
, n
);
2236 /* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the
2237 operands, and SIGN is true if it's a signed multiply, and false if
2238 it's an unsigned multiply. */
2240 tilegx_expand_high_multiply (rtx result
, rtx op1
, rtx op2
, bool sign
)
2242 rtx tmp0
= gen_reg_rtx (DImode
);
2243 rtx tmp1
= gen_reg_rtx (DImode
);
2244 rtx tmp2
= gen_reg_rtx (DImode
);
2245 rtx tmp3
= gen_reg_rtx (DImode
);
2246 rtx tmp4
= gen_reg_rtx (DImode
);
2247 rtx tmp5
= gen_reg_rtx (DImode
);
2248 rtx tmp6
= gen_reg_rtx (DImode
);
2249 rtx tmp7
= gen_reg_rtx (DImode
);
2250 rtx tmp8
= gen_reg_rtx (DImode
);
2251 rtx tmp9
= gen_reg_rtx (DImode
);
2252 rtx tmp10
= gen_reg_rtx (DImode
);
2253 rtx tmp11
= gen_reg_rtx (DImode
);
2254 rtx tmp12
= gen_reg_rtx (DImode
);
2255 rtx tmp13
= gen_reg_rtx (DImode
);
2256 rtx result_lo
= gen_reg_rtx (DImode
);
2260 emit_insn (gen_insn_mul_hs_lu (tmp0
, op1
, op2
));
2261 emit_insn (gen_insn_mul_hs_lu (tmp1
, op2
, op1
));
2262 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2263 emit_insn (gen_insn_mul_hs_hs (tmp3
, op1
, op2
));
2267 emit_insn (gen_insn_mul_hu_lu (tmp0
, op1
, op2
));
2268 emit_insn (gen_insn_mul_hu_lu (tmp1
, op2
, op1
));
2269 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2270 emit_insn (gen_insn_mul_hu_hu (tmp3
, op1
, op2
));
2273 emit_move_insn (tmp4
, (gen_rtx_ASHIFT (DImode
, tmp0
, GEN_INT (32))));
2275 emit_move_insn (tmp5
, (gen_rtx_ASHIFT (DImode
, tmp1
, GEN_INT (32))));
2277 emit_move_insn (tmp6
, (gen_rtx_PLUS (DImode
, tmp4
, tmp5
)));
2278 emit_move_insn (result_lo
, (gen_rtx_PLUS (DImode
, tmp2
, tmp6
)));
2280 emit_move_insn (tmp7
, gen_rtx_LTU (DImode
, tmp6
, tmp4
));
2281 emit_move_insn (tmp8
, gen_rtx_LTU (DImode
, result_lo
, tmp2
));
2285 emit_move_insn (tmp9
, (gen_rtx_ASHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2286 emit_move_insn (tmp10
, (gen_rtx_ASHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2290 emit_move_insn (tmp9
, (gen_rtx_LSHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2291 emit_move_insn (tmp10
, (gen_rtx_LSHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2294 emit_move_insn (tmp11
, (gen_rtx_PLUS (DImode
, tmp3
, tmp7
)));
2295 emit_move_insn (tmp12
, (gen_rtx_PLUS (DImode
, tmp8
, tmp9
)));
2296 emit_move_insn (tmp13
, (gen_rtx_PLUS (DImode
, tmp11
, tmp12
)));
2297 emit_move_insn (result
, (gen_rtx_PLUS (DImode
, tmp13
, tmp10
)));
2301 /* Implement smuldi3_highpart. */
2303 tilegx_expand_smuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2305 tilegx_expand_high_multiply (op0
, op1
, op2
, true);
2309 /* Implement umuldi3_highpart. */
2311 tilegx_expand_umuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2313 tilegx_expand_high_multiply (op0
, op1
, op2
, false);
2318 /* Compare and branches */
2320 /* Produce the rtx yielding a bool for a floating point
2323 tilegx_emit_fp_setcc (rtx res
, enum rtx_code code
, machine_mode mode
,
2326 /* TODO: Certain compares again constants can be done using entirely
2327 integer operations. But you have to get the special cases right
2328 e.g. NaN, +0 == -0, etc. */
2332 rtx a
= force_reg (DImode
, gen_lowpart (DImode
, op0
));
2333 rtx b
= force_reg (DImode
, gen_lowpart (DImode
, op1
));
2335 flags
= gen_reg_rtx (DImode
);
2339 emit_insn (gen_insn_fsingle_add1 (flags
, a
, b
));
2343 gcc_assert (mode
== DFmode
);
2344 emit_insn (gen_insn_fdouble_add_flags (flags
, a
, b
));
2349 case EQ
: flag_index
= 30; break;
2350 case NE
: flag_index
= 31; break;
2351 case LE
: flag_index
= 27; break;
2352 case LT
: flag_index
= 26; break;
2353 case GE
: flag_index
= 29; break;
2354 case GT
: flag_index
= 28; break;
2355 default: gcc_unreachable ();
2358 gcc_assert (GET_MODE (res
) == DImode
);
2359 emit_move_insn (res
, gen_rtx_ZERO_EXTRACT (DImode
, flags
, GEN_INT (1),
2360 GEN_INT (flag_index
)));
2365 /* Certain simplifications can be done to make invalid setcc
2366 operations valid. Return the final comparison, or NULL if we can't
2369 tilegx_emit_setcc_internal (rtx res
, enum rtx_code code
, rtx op0
, rtx op1
,
2370 machine_mode cmp_mode
)
2375 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2376 return tilegx_emit_fp_setcc (res
, code
, cmp_mode
, op0
, op1
);
2378 /* The general case: fold the comparison code to the types of
2379 compares that we have, choosing the branch as necessary. */
2389 /* We have these compares. */
2396 /* We do not have these compares, so we reverse the
2402 /* We should not have called this with any other code. */
2408 code
= swap_condition (code
);
2409 tmp
= op0
, op0
= op1
, op1
= tmp
;
2412 if (!reg_or_0_operand (op0
, cmp_mode
))
2413 op0
= force_reg (cmp_mode
, op0
);
2415 if (!CONST_INT_P (op1
) && !register_operand (op1
, cmp_mode
))
2416 op1
= force_reg (cmp_mode
, op1
);
2418 /* Return the setcc comparison. */
2419 emit_insn (gen_rtx_SET (res
, gen_rtx_fmt_ee (code
, DImode
, op0
, op1
)));
2425 /* Implement cstore patterns. */
2427 tilegx_emit_setcc (rtx operands
[], machine_mode cmp_mode
)
2430 tilegx_emit_setcc_internal (operands
[0], GET_CODE (operands
[1]),
2431 operands
[2], operands
[3], cmp_mode
);
2435 /* Return whether CODE is a signed comparison. */
2437 signed_compare_p (enum rtx_code code
)
2439 return (code
== EQ
|| code
== NE
|| code
== LT
|| code
== LE
2440 || code
== GT
|| code
== GE
);
2444 /* Generate the comparison for a DImode conditional branch. */
2446 tilegx_emit_cc_test (enum rtx_code code
, rtx op0
, rtx op1
,
2447 machine_mode cmp_mode
, bool eq_ne_only
)
2449 enum rtx_code branch_code
;
2452 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2454 /* Compute a boolean saying whether the comparison is true. */
2455 temp
= gen_reg_rtx (DImode
);
2456 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2458 /* Test that flag. */
2459 return gen_rtx_fmt_ee (NE
, VOIDmode
, temp
, const0_rtx
);
2462 /* Check for a compare against zero using a comparison we can do
2464 if (op1
== const0_rtx
2465 && (code
== EQ
|| code
== NE
2466 || (!eq_ne_only
&& signed_compare_p (code
))))
2468 op0
= force_reg (cmp_mode
, op0
);
2469 return gen_rtx_fmt_ee (code
, VOIDmode
, op0
, const0_rtx
);
2472 /* The general case: fold the comparison code to the types of
2473 compares that we have, choosing the branch as necessary. */
2481 /* We have these compares. */
2490 /* These must be reversed (except NE, but let's
2492 code
= reverse_condition (code
);
2500 if (CONST_INT_P (op1
) && (!satisfies_constraint_I (op1
) || code
== LEU
))
2502 HOST_WIDE_INT n
= INTVAL (op1
);
2507 /* Subtract off the value we want to compare against and see
2508 if we get zero. This is cheaper than creating a constant
2509 in a register. Except that subtracting -128 is more
2510 expensive than seqi to -128, so we leave that alone. */
2511 /* ??? Don't do this when comparing against symbols,
2512 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2513 0), which will be declared false out of hand (at least
2516 && add_operand (GEN_INT (-n
), DImode
)
2517 && !(symbolic_operand (op0
, VOIDmode
)
2518 || (REG_P (op0
) && REG_POINTER (op0
))))
2520 /* TODO: Use a SIMD add immediate to hit zero for tiled
2521 constants in a single instruction. */
2522 if (GET_MODE (op0
) != DImode
)
2524 /* Convert to DImode so we can use addli. Note that
2525 this will not actually generate any code because
2526 sign extension from SI -> DI is a no-op. I don't
2527 know if it's safe just to make a paradoxical
2528 subreg here though. */
2529 rtx temp2
= gen_reg_rtx (DImode
);
2530 emit_insn (gen_extendsidi2 (temp2
, op0
));
2535 op0
= force_reg (DImode
, op0
);
2537 temp
= gen_reg_rtx (DImode
);
2538 emit_move_insn (temp
, gen_rtx_PLUS (DImode
, op0
, GEN_INT (-n
)));
2539 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2540 VOIDmode
, temp
, const0_rtx
);
2550 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2551 We use arithmetic shift right because it's a 3-wide op,
2552 while logical shift right is not. */
2554 int first
= exact_log2 (code
== LTU
? n
: n
+ 1);
2557 op0
= force_reg (cmp_mode
, op0
);
2558 temp
= gen_reg_rtx (cmp_mode
);
2559 emit_move_insn (temp
,
2560 gen_rtx_ASHIFTRT (cmp_mode
, op0
,
2562 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2563 VOIDmode
, temp
, const0_rtx
);
2573 /* Compute a flag saying whether we should branch. */
2574 temp
= gen_reg_rtx (DImode
);
2575 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2577 /* Return the branch comparison. */
2578 return gen_rtx_fmt_ee (branch_code
, VOIDmode
, temp
, const0_rtx
);
2582 /* Generate the comparison for a conditional branch. */
2584 tilegx_emit_conditional_branch (rtx operands
[], machine_mode cmp_mode
)
2587 tilegx_emit_cc_test (GET_CODE (operands
[0]), operands
[1], operands
[2],
2589 rtx branch_rtx
= gen_rtx_SET (pc_rtx
,
2590 gen_rtx_IF_THEN_ELSE (VOIDmode
, cmp_rtx
,
2595 emit_jump_insn (branch_rtx
);
2599 /* Implement the mov<mode>cc pattern. */
2601 tilegx_emit_conditional_move (rtx cmp
)
2604 tilegx_emit_cc_test (GET_CODE (cmp
), XEXP (cmp
, 0), XEXP (cmp
, 1),
2605 GET_MODE (XEXP (cmp
, 0)), true);
2609 /* Return true if INSN is annotated with a REG_BR_PROB note that
2610 indicates it's a branch that's predicted taken. */
2612 cbranch_predicted_p (rtx_insn
*insn
)
2614 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2618 return profile_probability::from_reg_br_prob_note (XINT (x
, 0))
2619 >= profile_probability::even ();
2626 /* Output assembly code for a specific branch instruction, appending
2627 the branch prediction flag to the opcode if appropriate. */
2629 tilegx_output_simple_cbranch_with_opcode (rtx_insn
*insn
, const char *opcode
,
2630 int regop
, bool reverse_predicted
)
2632 static char buf
[64];
2633 sprintf (buf
, "%s%s\t%%r%d, %%l0", opcode
,
2634 (cbranch_predicted_p (insn
) ^ reverse_predicted
) ? "t" : "",
2640 /* Output assembly code for a specific branch instruction, appending
2641 the branch prediction flag to the opcode if appropriate. */
2643 tilegx_output_cbranch_with_opcode (rtx_insn
*insn
, rtx
*operands
,
2645 const char *rev_opcode
, int regop
)
2647 const char *branch_if_false
;
2648 rtx taken
, not_taken
;
2649 bool is_simple_branch
;
2651 gcc_assert (LABEL_P (operands
[0]));
2653 is_simple_branch
= true;
2654 if (INSN_ADDRESSES_SET_P ())
2656 int from_addr
= INSN_ADDRESSES (INSN_UID (insn
));
2657 int to_addr
= INSN_ADDRESSES (INSN_UID (operands
[0]));
2658 int delta
= to_addr
- from_addr
;
2659 is_simple_branch
= IN_RANGE (delta
, -524288, 524280);
2662 if (is_simple_branch
)
2664 /* Just a simple conditional branch. */
2666 tilegx_output_simple_cbranch_with_opcode (insn
, opcode
, regop
, false);
2669 /* Generate a reversed branch around a direct jump. This fallback
2670 does not use branch-likely instructions. */
2671 not_taken
= gen_label_rtx ();
2672 taken
= operands
[0];
2674 /* Generate the reversed branch to NOT_TAKEN. */
2675 operands
[0] = not_taken
;
2677 tilegx_output_simple_cbranch_with_opcode (insn
, rev_opcode
, regop
, true);
2678 output_asm_insn (branch_if_false
, operands
);
2680 output_asm_insn ("j\t%l0", &taken
);
2682 /* Output NOT_TAKEN. */
2683 targetm
.asm_out
.internal_label (asm_out_file
, "L",
2684 CODE_LABEL_NUMBER (not_taken
));
2689 /* Output assembly code for a conditional branch instruction. */
2691 tilegx_output_cbranch (rtx_insn
*insn
, rtx
*operands
, bool reversed
)
2693 enum rtx_code code
= GET_CODE (operands
[1]);
2695 const char *rev_opcode
;
2698 code
= reverse_condition (code
);
2704 rev_opcode
= "beqz";
2708 rev_opcode
= "bnez";
2712 rev_opcode
= "bltz";
2716 rev_opcode
= "blez";
2720 rev_opcode
= "bgtz";
2724 rev_opcode
= "bgez";
2730 return tilegx_output_cbranch_with_opcode (insn
, operands
, opcode
,
2735 /* Implement the tablejump pattern. */
2737 tilegx_expand_tablejump (rtx op0
, rtx op1
)
2741 rtx temp
= gen_reg_rtx (Pmode
);
2742 rtx temp2
= gen_reg_rtx (Pmode
);
2744 tilegx_compute_pcrel_address (temp
, gen_rtx_LABEL_REF (Pmode
, op1
));
2745 emit_move_insn (temp2
,
2746 gen_rtx_PLUS (Pmode
,
2747 convert_to_mode (Pmode
, op0
, false),
2752 emit_jump_insn (gen_tablejump_aux (op0
, op1
));
2756 /* Emit barrier before an atomic, as needed for the memory MODEL. */
2758 tilegx_pre_atomic_barrier (enum memmodel model
)
2760 if (need_atomic_barrier_p (model
, true))
2761 emit_insn (gen_memory_barrier ());
2765 /* Emit barrier after an atomic, as needed for the memory MODEL. */
2767 tilegx_post_atomic_barrier (enum memmodel model
)
2769 if (need_atomic_barrier_p (model
, false))
2770 emit_insn (gen_memory_barrier ());
2775 /* Expand a builtin vector binary op, by calling gen function GEN with
2776 operands in the proper modes. DEST is converted to DEST_MODE, and
2777 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2779 tilegx_expand_builtin_vector_binop (rtx (*gen
) (rtx
, rtx
, rtx
),
2780 machine_mode dest_mode
,
2782 machine_mode src_mode
,
2783 rtx src0
, rtx src1
, bool do_src1
)
2785 dest
= gen_lowpart (dest_mode
, dest
);
2787 if (src0
== const0_rtx
)
2788 src0
= CONST0_RTX (src_mode
);
2790 src0
= gen_lowpart (src_mode
, src0
);
2794 if (src1
== const0_rtx
)
2795 src1
= CONST0_RTX (src_mode
);
2797 src1
= gen_lowpart (src_mode
, src1
);
2800 emit_insn ((*gen
) (dest
, src0
, src1
));
2808 struct tile_builtin_info
2810 enum insn_code icode
;
2814 static struct tile_builtin_info tilegx_builtin_info
[TILEGX_BUILTIN_max
] = {
2815 { CODE_FOR_adddi3
, NULL
}, /* add */
2816 { CODE_FOR_addsi3
, NULL
}, /* addx */
2817 { CODE_FOR_ssaddsi3
, NULL
}, /* addxsc */
2818 { CODE_FOR_anddi3
, NULL
}, /* and */
2819 { CODE_FOR_insn_bfexts
, NULL
}, /* bfexts */
2820 { CODE_FOR_insn_bfextu
, NULL
}, /* bfextu */
2821 { CODE_FOR_insn_bfins
, NULL
}, /* bfins */
2822 { CODE_FOR_clzdi2
, NULL
}, /* clz */
2823 { CODE_FOR_insn_cmoveqz
, NULL
}, /* cmoveqz */
2824 { CODE_FOR_insn_cmovnez
, NULL
}, /* cmovnez */
2825 { CODE_FOR_insn_cmpeq_didi
, NULL
}, /* cmpeq */
2826 { CODE_FOR_insn_cmpexch
, NULL
}, /* cmpexch */
2827 { CODE_FOR_insn_cmpexch4
, NULL
}, /* cmpexch4 */
2828 { CODE_FOR_insn_cmples_didi
, NULL
}, /* cmples */
2829 { CODE_FOR_insn_cmpleu_didi
, NULL
}, /* cmpleu */
2830 { CODE_FOR_insn_cmplts_didi
, NULL
}, /* cmplts */
2831 { CODE_FOR_insn_cmpltu_didi
, NULL
}, /* cmpltu */
2832 { CODE_FOR_insn_cmpne_didi
, NULL
}, /* cmpne */
2833 { CODE_FOR_insn_cmul
, NULL
}, /* cmul */
2834 { CODE_FOR_insn_cmula
, NULL
}, /* cmula */
2835 { CODE_FOR_insn_cmulaf
, NULL
}, /* cmulaf */
2836 { CODE_FOR_insn_cmulf
, NULL
}, /* cmulf */
2837 { CODE_FOR_insn_cmulfr
, NULL
}, /* cmulfr */
2838 { CODE_FOR_insn_cmulh
, NULL
}, /* cmulh */
2839 { CODE_FOR_insn_cmulhr
, NULL
}, /* cmulhr */
2840 { CODE_FOR_insn_crc32_32
, NULL
}, /* crc32_32 */
2841 { CODE_FOR_insn_crc32_8
, NULL
}, /* crc32_8 */
2842 { CODE_FOR_ctzdi2
, NULL
}, /* ctz */
2843 { CODE_FOR_insn_dblalign
, NULL
}, /* dblalign */
2844 { CODE_FOR_insn_dblalign2
, NULL
}, /* dblalign2 */
2845 { CODE_FOR_insn_dblalign4
, NULL
}, /* dblalign4 */
2846 { CODE_FOR_insn_dblalign6
, NULL
}, /* dblalign6 */
2847 { CODE_FOR_insn_drain
, NULL
}, /* drain */
2848 { CODE_FOR_insn_dtlbpr
, NULL
}, /* dtlbpr */
2849 { CODE_FOR_insn_exch
, NULL
}, /* exch */
2850 { CODE_FOR_insn_exch4
, NULL
}, /* exch4 */
2851 { CODE_FOR_insn_fdouble_add_flags
, NULL
}, /* fdouble_add_flags */
2852 { CODE_FOR_insn_fdouble_addsub
, NULL
}, /* fdouble_addsub */
2853 { CODE_FOR_insn_fdouble_mul_flags
, NULL
}, /* fdouble_mul_flags */
2854 { CODE_FOR_insn_fdouble_pack1
, NULL
}, /* fdouble_pack1 */
2855 { CODE_FOR_insn_fdouble_pack2
, NULL
}, /* fdouble_pack2 */
2856 { CODE_FOR_insn_fdouble_sub_flags
, NULL
}, /* fdouble_sub_flags */
2857 { CODE_FOR_insn_fdouble_unpack_max
, NULL
}, /* fdouble_unpack_max */
2858 { CODE_FOR_insn_fdouble_unpack_min
, NULL
}, /* fdouble_unpack_min */
2859 { CODE_FOR_insn_fetchadd
, NULL
}, /* fetchadd */
2860 { CODE_FOR_insn_fetchadd4
, NULL
}, /* fetchadd4 */
2861 { CODE_FOR_insn_fetchaddgez
, NULL
}, /* fetchaddgez */
2862 { CODE_FOR_insn_fetchaddgez4
, NULL
}, /* fetchaddgez4 */
2863 { CODE_FOR_insn_fetchand
, NULL
}, /* fetchand */
2864 { CODE_FOR_insn_fetchand4
, NULL
}, /* fetchand4 */
2865 { CODE_FOR_insn_fetchor
, NULL
}, /* fetchor */
2866 { CODE_FOR_insn_fetchor4
, NULL
}, /* fetchor4 */
2867 { CODE_FOR_insn_finv
, NULL
}, /* finv */
2868 { CODE_FOR_insn_flush
, NULL
}, /* flush */
2869 { CODE_FOR_insn_flushwb
, NULL
}, /* flushwb */
2870 { CODE_FOR_insn_fnop
, NULL
}, /* fnop */
2871 { CODE_FOR_insn_fsingle_add1
, NULL
}, /* fsingle_add1 */
2872 { CODE_FOR_insn_fsingle_addsub2
, NULL
}, /* fsingle_addsub2 */
2873 { CODE_FOR_insn_fsingle_mul1
, NULL
}, /* fsingle_mul1 */
2874 { CODE_FOR_insn_fsingle_mul2
, NULL
}, /* fsingle_mul2 */
2875 { CODE_FOR_insn_fsingle_pack1
, NULL
}, /* fsingle_pack1 */
2876 { CODE_FOR_insn_fsingle_pack2
, NULL
}, /* fsingle_pack2 */
2877 { CODE_FOR_insn_fsingle_sub1
, NULL
}, /* fsingle_sub1 */
2878 { CODE_FOR_insn_icoh
, NULL
}, /* icoh */
2879 { CODE_FOR_insn_ill
, NULL
}, /* ill */
2880 { CODE_FOR_insn_info
, NULL
}, /* info */
2881 { CODE_FOR_insn_infol
, NULL
}, /* infol */
2882 { CODE_FOR_insn_inv
, NULL
}, /* inv */
2883 { CODE_FOR_insn_ld
, NULL
}, /* ld */
2884 { CODE_FOR_insn_ld1s
, NULL
}, /* ld1s */
2885 { CODE_FOR_insn_ld1u
, NULL
}, /* ld1u */
2886 { CODE_FOR_insn_ld2s
, NULL
}, /* ld2s */
2887 { CODE_FOR_insn_ld2u
, NULL
}, /* ld2u */
2888 { CODE_FOR_insn_ld4s
, NULL
}, /* ld4s */
2889 { CODE_FOR_insn_ld4u
, NULL
}, /* ld4u */
2890 { CODE_FOR_insn_ldna
, NULL
}, /* ldna */
2891 { CODE_FOR_insn_ldnt
, NULL
}, /* ldnt */
2892 { CODE_FOR_insn_ldnt1s
, NULL
}, /* ldnt1s */
2893 { CODE_FOR_insn_ldnt1u
, NULL
}, /* ldnt1u */
2894 { CODE_FOR_insn_ldnt2s
, NULL
}, /* ldnt2s */
2895 { CODE_FOR_insn_ldnt2u
, NULL
}, /* ldnt2u */
2896 { CODE_FOR_insn_ldnt4s
, NULL
}, /* ldnt4s */
2897 { CODE_FOR_insn_ldnt4u
, NULL
}, /* ldnt4u */
2898 { CODE_FOR_insn_ld_L2
, NULL
}, /* ld_L2 */
2899 { CODE_FOR_insn_ld1s_L2
, NULL
}, /* ld1s_L2 */
2900 { CODE_FOR_insn_ld1u_L2
, NULL
}, /* ld1u_L2 */
2901 { CODE_FOR_insn_ld2s_L2
, NULL
}, /* ld2s_L2 */
2902 { CODE_FOR_insn_ld2u_L2
, NULL
}, /* ld2u_L2 */
2903 { CODE_FOR_insn_ld4s_L2
, NULL
}, /* ld4s_L2 */
2904 { CODE_FOR_insn_ld4u_L2
, NULL
}, /* ld4u_L2 */
2905 { CODE_FOR_insn_ldna_L2
, NULL
}, /* ldna_L2 */
2906 { CODE_FOR_insn_ldnt_L2
, NULL
}, /* ldnt_L2 */
2907 { CODE_FOR_insn_ldnt1s_L2
, NULL
}, /* ldnt1s_L2 */
2908 { CODE_FOR_insn_ldnt1u_L2
, NULL
}, /* ldnt1u_L2 */
2909 { CODE_FOR_insn_ldnt2s_L2
, NULL
}, /* ldnt2s_L2 */
2910 { CODE_FOR_insn_ldnt2u_L2
, NULL
}, /* ldnt2u_L2 */
2911 { CODE_FOR_insn_ldnt4s_L2
, NULL
}, /* ldnt4s_L2 */
2912 { CODE_FOR_insn_ldnt4u_L2
, NULL
}, /* ldnt4u_L2 */
2913 { CODE_FOR_insn_ld_miss
, NULL
}, /* ld_miss */
2914 { CODE_FOR_insn_ld1s_miss
, NULL
}, /* ld1s_miss */
2915 { CODE_FOR_insn_ld1u_miss
, NULL
}, /* ld1u_miss */
2916 { CODE_FOR_insn_ld2s_miss
, NULL
}, /* ld2s_miss */
2917 { CODE_FOR_insn_ld2u_miss
, NULL
}, /* ld2u_miss */
2918 { CODE_FOR_insn_ld4s_miss
, NULL
}, /* ld4s_miss */
2919 { CODE_FOR_insn_ld4u_miss
, NULL
}, /* ld4u_miss */
2920 { CODE_FOR_insn_ldna_miss
, NULL
}, /* ldna_miss */
2921 { CODE_FOR_insn_ldnt_miss
, NULL
}, /* ldnt_miss */
2922 { CODE_FOR_insn_ldnt1s_miss
, NULL
}, /* ldnt1s_miss */
2923 { CODE_FOR_insn_ldnt1u_miss
, NULL
}, /* ldnt1u_miss */
2924 { CODE_FOR_insn_ldnt2s_miss
, NULL
}, /* ldnt2s_miss */
2925 { CODE_FOR_insn_ldnt2u_miss
, NULL
}, /* ldnt2u_miss */
2926 { CODE_FOR_insn_ldnt4s_miss
, NULL
}, /* ldnt4s_miss */
2927 { CODE_FOR_insn_ldnt4u_miss
, NULL
}, /* ldnt4u_miss */
2928 { CODE_FOR_insn_lnk
, NULL
}, /* lnk */
2929 { CODE_FOR_memory_barrier
, NULL
}, /* mf */
2930 { CODE_FOR_insn_mfspr
, NULL
}, /* mfspr */
2931 { CODE_FOR_insn_mm
, NULL
}, /* mm */
2932 { CODE_FOR_insn_mnz
, NULL
}, /* mnz */
2933 { CODE_FOR_movdi
, NULL
}, /* move */
2934 { CODE_FOR_insn_mtspr
, NULL
}, /* mtspr */
2935 { CODE_FOR_insn_mul_hs_hs
, NULL
}, /* mul_hs_hs */
2936 { CODE_FOR_insn_mul_hs_hu
, NULL
}, /* mul_hs_hu */
2937 { CODE_FOR_insn_mul_hs_ls
, NULL
}, /* mul_hs_ls */
2938 { CODE_FOR_insn_mul_hs_lu
, NULL
}, /* mul_hs_lu */
2939 { CODE_FOR_insn_mul_hu_hu
, NULL
}, /* mul_hu_hu */
2940 { CODE_FOR_insn_mul_hu_ls
, NULL
}, /* mul_hu_ls */
2941 { CODE_FOR_insn_mul_hu_lu
, NULL
}, /* mul_hu_lu */
2942 { CODE_FOR_insn_mul_ls_ls
, NULL
}, /* mul_ls_ls */
2943 { CODE_FOR_insn_mul_ls_lu
, NULL
}, /* mul_ls_lu */
2944 { CODE_FOR_insn_mul_lu_lu
, NULL
}, /* mul_lu_lu */
2945 { CODE_FOR_insn_mula_hs_hs
, NULL
}, /* mula_hs_hs */
2946 { CODE_FOR_insn_mula_hs_hu
, NULL
}, /* mula_hs_hu */
2947 { CODE_FOR_insn_mula_hs_ls
, NULL
}, /* mula_hs_ls */
2948 { CODE_FOR_insn_mula_hs_lu
, NULL
}, /* mula_hs_lu */
2949 { CODE_FOR_insn_mula_hu_hu
, NULL
}, /* mula_hu_hu */
2950 { CODE_FOR_insn_mula_hu_ls
, NULL
}, /* mula_hu_ls */
2951 { CODE_FOR_insn_mula_hu_lu
, NULL
}, /* mula_hu_lu */
2952 { CODE_FOR_insn_mula_ls_ls
, NULL
}, /* mula_ls_ls */
2953 { CODE_FOR_insn_mula_ls_lu
, NULL
}, /* mula_ls_lu */
2954 { CODE_FOR_insn_mula_lu_lu
, NULL
}, /* mula_lu_lu */
2955 { CODE_FOR_insn_mulax
, NULL
}, /* mulax */
2956 { CODE_FOR_mulsi3
, NULL
}, /* mulx */
2957 { CODE_FOR_insn_mz
, NULL
}, /* mz */
2958 { CODE_FOR_insn_nap
, NULL
}, /* nap */
2959 { CODE_FOR_nop
, NULL
}, /* nop */
2960 { CODE_FOR_insn_nor_di
, NULL
}, /* nor */
2961 { CODE_FOR_iordi3
, NULL
}, /* or */
2962 { CODE_FOR_popcountdi2
, NULL
}, /* pcnt */
2963 { CODE_FOR_insn_prefetch_l1
, NULL
}, /* prefetch_l1 */
2964 { CODE_FOR_insn_prefetch_l1_fault
, NULL
}, /* prefetch_l1_fault */
2965 { CODE_FOR_insn_prefetch_l2
, NULL
}, /* prefetch_l2 */
2966 { CODE_FOR_insn_prefetch_l2_fault
, NULL
}, /* prefetch_l2_fault */
2967 { CODE_FOR_insn_prefetch_l3
, NULL
}, /* prefetch_l3 */
2968 { CODE_FOR_insn_prefetch_l3_fault
, NULL
}, /* prefetch_l3_fault */
2969 { CODE_FOR_insn_revbits
, NULL
}, /* revbits */
2970 { CODE_FOR_bswapdi2
, NULL
}, /* revbytes */
2971 { CODE_FOR_rotldi3
, NULL
}, /* rotl */
2972 { CODE_FOR_ashldi3
, NULL
}, /* shl */
2973 { CODE_FOR_insn_shl16insli
, NULL
}, /* shl16insli */
2974 { CODE_FOR_insn_shl1add
, NULL
}, /* shl1add */
2975 { CODE_FOR_insn_shl1addx
, NULL
}, /* shl1addx */
2976 { CODE_FOR_insn_shl2add
, NULL
}, /* shl2add */
2977 { CODE_FOR_insn_shl2addx
, NULL
}, /* shl2addx */
2978 { CODE_FOR_insn_shl3add
, NULL
}, /* shl3add */
2979 { CODE_FOR_insn_shl3addx
, NULL
}, /* shl3addx */
2980 { CODE_FOR_ashlsi3
, NULL
}, /* shlx */
2981 { CODE_FOR_ashrdi3
, NULL
}, /* shrs */
2982 { CODE_FOR_lshrdi3
, NULL
}, /* shru */
2983 { CODE_FOR_lshrsi3
, NULL
}, /* shrux */
2984 { CODE_FOR_insn_shufflebytes
, NULL
}, /* shufflebytes */
2985 { CODE_FOR_insn_shufflebytes1
, NULL
}, /* shufflebytes1 */
2986 { CODE_FOR_insn_st
, NULL
}, /* st */
2987 { CODE_FOR_insn_st1
, NULL
}, /* st1 */
2988 { CODE_FOR_insn_st2
, NULL
}, /* st2 */
2989 { CODE_FOR_insn_st4
, NULL
}, /* st4 */
2990 { CODE_FOR_insn_stnt
, NULL
}, /* stnt */
2991 { CODE_FOR_insn_stnt1
, NULL
}, /* stnt1 */
2992 { CODE_FOR_insn_stnt2
, NULL
}, /* stnt2 */
2993 { CODE_FOR_insn_stnt4
, NULL
}, /* stnt4 */
2994 { CODE_FOR_subdi3
, NULL
}, /* sub */
2995 { CODE_FOR_subsi3
, NULL
}, /* subx */
2996 { CODE_FOR_sssubsi3
, NULL
}, /* subxsc */
2997 { CODE_FOR_insn_tblidxb0
, NULL
}, /* tblidxb0 */
2998 { CODE_FOR_insn_tblidxb1
, NULL
}, /* tblidxb1 */
2999 { CODE_FOR_insn_tblidxb2
, NULL
}, /* tblidxb2 */
3000 { CODE_FOR_insn_tblidxb3
, NULL
}, /* tblidxb3 */
3001 { CODE_FOR_insn_v1add
, NULL
}, /* v1add */
3002 { CODE_FOR_insn_v1addi
, NULL
}, /* v1addi */
3003 { CODE_FOR_insn_v1adduc
, NULL
}, /* v1adduc */
3004 { CODE_FOR_insn_v1adiffu
, NULL
}, /* v1adiffu */
3005 { CODE_FOR_insn_v1avgu
, NULL
}, /* v1avgu */
3006 { CODE_FOR_insn_v1cmpeq
, NULL
}, /* v1cmpeq */
3007 { CODE_FOR_insn_v1cmpeqi
, NULL
}, /* v1cmpeqi */
3008 { CODE_FOR_insn_v1cmples
, NULL
}, /* v1cmples */
3009 { CODE_FOR_insn_v1cmpleu
, NULL
}, /* v1cmpleu */
3010 { CODE_FOR_insn_v1cmplts
, NULL
}, /* v1cmplts */
3011 { CODE_FOR_insn_v1cmpltsi
, NULL
}, /* v1cmpltsi */
3012 { CODE_FOR_insn_v1cmpltu
, NULL
}, /* v1cmpltu */
3013 { CODE_FOR_insn_v1cmpltui
, NULL
}, /* v1cmpltui */
3014 { CODE_FOR_insn_v1cmpne
, NULL
}, /* v1cmpne */
3015 { CODE_FOR_insn_v1ddotpu
, NULL
}, /* v1ddotpu */
3016 { CODE_FOR_insn_v1ddotpua
, NULL
}, /* v1ddotpua */
3017 { CODE_FOR_insn_v1ddotpus
, NULL
}, /* v1ddotpus */
3018 { CODE_FOR_insn_v1ddotpusa
, NULL
}, /* v1ddotpusa */
3019 { CODE_FOR_insn_v1dotp
, NULL
}, /* v1dotp */
3020 { CODE_FOR_insn_v1dotpa
, NULL
}, /* v1dotpa */
3021 { CODE_FOR_insn_v1dotpu
, NULL
}, /* v1dotpu */
3022 { CODE_FOR_insn_v1dotpua
, NULL
}, /* v1dotpua */
3023 { CODE_FOR_insn_v1dotpus
, NULL
}, /* v1dotpus */
3024 { CODE_FOR_insn_v1dotpusa
, NULL
}, /* v1dotpusa */
3025 { CODE_FOR_insn_v1int_h
, NULL
}, /* v1int_h */
3026 { CODE_FOR_insn_v1int_l
, NULL
}, /* v1int_l */
3027 { CODE_FOR_insn_v1maxu
, NULL
}, /* v1maxu */
3028 { CODE_FOR_insn_v1maxui
, NULL
}, /* v1maxui */
3029 { CODE_FOR_insn_v1minu
, NULL
}, /* v1minu */
3030 { CODE_FOR_insn_v1minui
, NULL
}, /* v1minui */
3031 { CODE_FOR_insn_v1mnz
, NULL
}, /* v1mnz */
3032 { CODE_FOR_insn_v1multu
, NULL
}, /* v1multu */
3033 { CODE_FOR_insn_v1mulu
, NULL
}, /* v1mulu */
3034 { CODE_FOR_insn_v1mulus
, NULL
}, /* v1mulus */
3035 { CODE_FOR_insn_v1mz
, NULL
}, /* v1mz */
3036 { CODE_FOR_insn_v1sadau
, NULL
}, /* v1sadau */
3037 { CODE_FOR_insn_v1sadu
, NULL
}, /* v1sadu */
3038 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shl */
3039 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shli */
3040 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrs */
3041 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrsi */
3042 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shru */
3043 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shrui */
3044 { CODE_FOR_insn_v1sub
, NULL
}, /* v1sub */
3045 { CODE_FOR_insn_v1subuc
, NULL
}, /* v1subuc */
3046 { CODE_FOR_insn_v2add
, NULL
}, /* v2add */
3047 { CODE_FOR_insn_v2addi
, NULL
}, /* v2addi */
3048 { CODE_FOR_insn_v2addsc
, NULL
}, /* v2addsc */
3049 { CODE_FOR_insn_v2adiffs
, NULL
}, /* v2adiffs */
3050 { CODE_FOR_insn_v2avgs
, NULL
}, /* v2avgs */
3051 { CODE_FOR_insn_v2cmpeq
, NULL
}, /* v2cmpeq */
3052 { CODE_FOR_insn_v2cmpeqi
, NULL
}, /* v2cmpeqi */
3053 { CODE_FOR_insn_v2cmples
, NULL
}, /* v2cmples */
3054 { CODE_FOR_insn_v2cmpleu
, NULL
}, /* v2cmpleu */
3055 { CODE_FOR_insn_v2cmplts
, NULL
}, /* v2cmplts */
3056 { CODE_FOR_insn_v2cmpltsi
, NULL
}, /* v2cmpltsi */
3057 { CODE_FOR_insn_v2cmpltu
, NULL
}, /* v2cmpltu */
3058 { CODE_FOR_insn_v2cmpltui
, NULL
}, /* v2cmpltui */
3059 { CODE_FOR_insn_v2cmpne
, NULL
}, /* v2cmpne */
3060 { CODE_FOR_insn_v2dotp
, NULL
}, /* v2dotp */
3061 { CODE_FOR_insn_v2dotpa
, NULL
}, /* v2dotpa */
3062 { CODE_FOR_insn_v2int_h
, NULL
}, /* v2int_h */
3063 { CODE_FOR_insn_v2int_l
, NULL
}, /* v2int_l */
3064 { CODE_FOR_insn_v2maxs
, NULL
}, /* v2maxs */
3065 { CODE_FOR_insn_v2maxsi
, NULL
}, /* v2maxsi */
3066 { CODE_FOR_insn_v2mins
, NULL
}, /* v2mins */
3067 { CODE_FOR_insn_v2minsi
, NULL
}, /* v2minsi */
3068 { CODE_FOR_insn_v2mnz
, NULL
}, /* v2mnz */
3069 { CODE_FOR_insn_v2mulfsc
, NULL
}, /* v2mulfsc */
3070 { CODE_FOR_insn_v2muls
, NULL
}, /* v2muls */
3071 { CODE_FOR_insn_v2mults
, NULL
}, /* v2mults */
3072 { CODE_FOR_insn_v2mz
, NULL
}, /* v2mz */
3073 { CODE_FOR_insn_v2packh
, NULL
}, /* v2packh */
3074 { CODE_FOR_insn_v2packl
, NULL
}, /* v2packl */
3075 { CODE_FOR_insn_v2packuc
, NULL
}, /* v2packuc */
3076 { CODE_FOR_insn_v2sadas
, NULL
}, /* v2sadas */
3077 { CODE_FOR_insn_v2sadau
, NULL
}, /* v2sadau */
3078 { CODE_FOR_insn_v2sads
, NULL
}, /* v2sads */
3079 { CODE_FOR_insn_v2sadu
, NULL
}, /* v2sadu */
3080 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shl */
3081 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shli */
3082 { CODE_FOR_insn_v2shlsc
, NULL
}, /* v2shlsc */
3083 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrs */
3084 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrsi */
3085 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shru */
3086 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shrui */
3087 { CODE_FOR_insn_v2sub
, NULL
}, /* v2sub */
3088 { CODE_FOR_insn_v2subsc
, NULL
}, /* v2subsc */
3089 { CODE_FOR_insn_v4add
, NULL
}, /* v4add */
3090 { CODE_FOR_insn_v4addsc
, NULL
}, /* v4addsc */
3091 { CODE_FOR_insn_v4int_h
, NULL
}, /* v4int_h */
3092 { CODE_FOR_insn_v4int_l
, NULL
}, /* v4int_l */
3093 { CODE_FOR_insn_v4packsc
, NULL
}, /* v4packsc */
3094 { CODE_FOR_insn_v4shl
, NULL
}, /* v4shl */
3095 { CODE_FOR_insn_v4shlsc
, NULL
}, /* v4shlsc */
3096 { CODE_FOR_insn_v4shrs
, NULL
}, /* v4shrs */
3097 { CODE_FOR_insn_v4shru
, NULL
}, /* v4shru */
3098 { CODE_FOR_insn_v4sub
, NULL
}, /* v4sub */
3099 { CODE_FOR_insn_v4subsc
, NULL
}, /* v4subsc */
3100 { CODE_FOR_insn_wh64
, NULL
}, /* wh64 */
3101 { CODE_FOR_xordi3
, NULL
}, /* xor */
3102 { CODE_FOR_tilegx_network_barrier
, NULL
}, /* network_barrier */
3103 { CODE_FOR_tilegx_idn0_receive
, NULL
}, /* idn0_receive */
3104 { CODE_FOR_tilegx_idn1_receive
, NULL
}, /* idn1_receive */
3105 { CODE_FOR_tilegx_idn_send
, NULL
}, /* idn_send */
3106 { CODE_FOR_tilegx_udn0_receive
, NULL
}, /* udn0_receive */
3107 { CODE_FOR_tilegx_udn1_receive
, NULL
}, /* udn1_receive */
3108 { CODE_FOR_tilegx_udn2_receive
, NULL
}, /* udn2_receive */
3109 { CODE_FOR_tilegx_udn3_receive
, NULL
}, /* udn3_receive */
3110 { CODE_FOR_tilegx_udn_send
, NULL
}, /* udn_send */
3114 struct tilegx_builtin_def
3117 enum tilegx_builtin code
;
3119 /* The first character is the return type. Subsequent characters
3120 are the argument types. See char_to_type. */
3125 static const struct tilegx_builtin_def tilegx_builtins
[] = {
3126 { "__insn_add", TILEGX_INSN_ADD
, true, "lll" },
3127 { "__insn_addi", TILEGX_INSN_ADD
, true, "lll" },
3128 { "__insn_addli", TILEGX_INSN_ADD
, true, "lll" },
3129 { "__insn_addx", TILEGX_INSN_ADDX
, true, "iii" },
3130 { "__insn_addxi", TILEGX_INSN_ADDX
, true, "iii" },
3131 { "__insn_addxli", TILEGX_INSN_ADDX
, true, "iii" },
3132 { "__insn_addxsc", TILEGX_INSN_ADDXSC
, true, "iii" },
3133 { "__insn_and", TILEGX_INSN_AND
, true, "lll" },
3134 { "__insn_andi", TILEGX_INSN_AND
, true, "lll" },
3135 { "__insn_bfexts", TILEGX_INSN_BFEXTS
, true, "llll" },
3136 { "__insn_bfextu", TILEGX_INSN_BFEXTU
, true, "llll" },
3137 { "__insn_bfins", TILEGX_INSN_BFINS
, true, "lllll"},
3138 { "__insn_clz", TILEGX_INSN_CLZ
, true, "ll" },
3139 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ
, true, "llll" },
3140 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ
, true, "llll" },
3141 { "__insn_cmpeq", TILEGX_INSN_CMPEQ
, true, "lll" },
3142 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ
, true, "lll" },
3143 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH
, false, "lpl" },
3144 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4
, false, "ipi" },
3145 { "__insn_cmples", TILEGX_INSN_CMPLES
, true, "lll" },
3146 { "__insn_cmpleu", TILEGX_INSN_CMPLEU
, true, "lll" },
3147 { "__insn_cmplts", TILEGX_INSN_CMPLTS
, true, "lll" },
3148 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS
, true, "lll" },
3149 { "__insn_cmpltu", TILEGX_INSN_CMPLTU
, true, "lll" },
3150 { "__insn_cmpltui", TILEGX_INSN_CMPLTU
, true, "lll" },
3151 { "__insn_cmpne", TILEGX_INSN_CMPNE
, true, "lll" },
3152 { "__insn_cmul", TILEGX_INSN_CMUL
, true, "lll" },
3153 { "__insn_cmula", TILEGX_INSN_CMULA
, true, "llll" },
3154 { "__insn_cmulaf", TILEGX_INSN_CMULAF
, true, "llll" },
3155 { "__insn_cmulf", TILEGX_INSN_CMULF
, true, "lll" },
3156 { "__insn_cmulfr", TILEGX_INSN_CMULFR
, true, "lll" },
3157 { "__insn_cmulh", TILEGX_INSN_CMULH
, true, "lll" },
3158 { "__insn_cmulhr", TILEGX_INSN_CMULHR
, true, "lll" },
3159 { "__insn_crc32_32", TILEGX_INSN_CRC32_32
, true, "lll" },
3160 { "__insn_crc32_8", TILEGX_INSN_CRC32_8
, true, "lll" },
3161 { "__insn_ctz", TILEGX_INSN_CTZ
, true, "ll" },
3162 { "__insn_dblalign", TILEGX_INSN_DBLALIGN
, true, "lllk" },
3163 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2
, true, "lll" },
3164 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4
, true, "lll" },
3165 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6
, true, "lll" },
3166 { "__insn_drain", TILEGX_INSN_DRAIN
, false, "v" },
3167 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR
, false, "vl" },
3168 { "__insn_exch", TILEGX_INSN_EXCH
, false, "lpl" },
3169 { "__insn_exch4", TILEGX_INSN_EXCH4
, false, "ipi" },
3170 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS
, true, "lll" },
3171 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB
, true, "llll" },
3172 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS
, true, "lll" },
3173 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1
, true, "lll" },
3174 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2
, true, "llll" },
3175 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS
, true, "lll" },
3176 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX
, true, "lll" },
3177 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN
, true, "lll" },
3178 { "__insn_fetchadd", TILEGX_INSN_FETCHADD
, false, "lpl" },
3179 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4
, false, "ipi" },
3180 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ
, false, "lpl" },
3181 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4
, false, "ipi" },
3182 { "__insn_fetchand", TILEGX_INSN_FETCHAND
, false, "lpl" },
3183 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4
, false, "ipi" },
3184 { "__insn_fetchor", TILEGX_INSN_FETCHOR
, false, "lpl" },
3185 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4
, false, "ipi" },
3186 { "__insn_finv", TILEGX_INSN_FINV
, false, "vk" },
3187 { "__insn_flush", TILEGX_INSN_FLUSH
, false, "vk" },
3188 { "__insn_flushwb", TILEGX_INSN_FLUSHWB
, false, "v" },
3189 { "__insn_fnop", TILEGX_INSN_FNOP
, false, "v" },
3190 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1
, true, "lll" },
3191 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2
, true, "llll" },
3192 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1
, true, "lll" },
3193 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2
, true, "lll" },
3194 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1
, true, "ll" },
3195 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2
, true, "lll" },
3196 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1
, true, "lll" },
3197 { "__insn_icoh", TILEGX_INSN_ICOH
, false, "vk" },
3198 { "__insn_ill", TILEGX_INSN_ILL
, false, "v" },
3199 { "__insn_info", TILEGX_INSN_INFO
, false, "vl" },
3200 { "__insn_infol", TILEGX_INSN_INFOL
, false, "vl" },
3201 { "__insn_inv", TILEGX_INSN_INV
, false, "vp" },
3202 { "__insn_ld", TILEGX_INSN_LD
, false, "lk" },
3203 { "__insn_ld1s", TILEGX_INSN_LD1S
, false, "lk" },
3204 { "__insn_ld1u", TILEGX_INSN_LD1U
, false, "lk" },
3205 { "__insn_ld2s", TILEGX_INSN_LD2S
, false, "lk" },
3206 { "__insn_ld2u", TILEGX_INSN_LD2U
, false, "lk" },
3207 { "__insn_ld4s", TILEGX_INSN_LD4S
, false, "lk" },
3208 { "__insn_ld4u", TILEGX_INSN_LD4U
, false, "lk" },
3209 { "__insn_ldna", TILEGX_INSN_LDNA
, false, "lk" },
3210 { "__insn_ldnt", TILEGX_INSN_LDNT
, false, "lk" },
3211 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S
, false, "lk" },
3212 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U
, false, "lk" },
3213 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S
, false, "lk" },
3214 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U
, false, "lk" },
3215 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S
, false, "lk" },
3216 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U
, false, "lk" },
3217 { "__insn_ld_L2", TILEGX_INSN_LD_L2
, false, "lk" },
3218 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2
, false, "lk" },
3219 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2
, false, "lk" },
3220 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2
, false, "lk" },
3221 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2
, false, "lk" },
3222 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2
, false, "lk" },
3223 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2
, false, "lk" },
3224 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2
, false, "lk" },
3225 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2
, false, "lk" },
3226 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2
, false, "lk" },
3227 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2
, false, "lk" },
3228 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2
, false, "lk" },
3229 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2
, false, "lk" },
3230 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2
, false, "lk" },
3231 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2
, false, "lk" },
3232 { "__insn_ld_miss", TILEGX_INSN_LD_MISS
, false, "lk" },
3233 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS
, false, "lk" },
3234 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS
, false, "lk" },
3235 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS
, false, "lk" },
3236 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS
, false, "lk" },
3237 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS
, false, "lk" },
3238 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS
, false, "lk" },
3239 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS
, false, "lk" },
3240 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS
, false, "lk" },
3241 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS
, false, "lk" },
3242 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS
, false, "lk" },
3243 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS
, false, "lk" },
3244 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS
, false, "lk" },
3245 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS
, false, "lk" },
3246 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS
, false, "lk" },
3247 { "__insn_lnk", TILEGX_INSN_LNK
, true, "l" },
3248 { "__insn_mf", TILEGX_INSN_MF
, false, "v" },
3249 { "__insn_mfspr", TILEGX_INSN_MFSPR
, false, "ll" },
3250 { "__insn_mm", TILEGX_INSN_MM
, true, "lllll"},
3251 { "__insn_mnz", TILEGX_INSN_MNZ
, true, "lll" },
3252 { "__insn_move", TILEGX_INSN_MOVE
, true, "ll" },
3253 { "__insn_movei", TILEGX_INSN_MOVE
, true, "ll" },
3254 { "__insn_moveli", TILEGX_INSN_MOVE
, true, "ll" },
3255 { "__insn_mtspr", TILEGX_INSN_MTSPR
, false, "vll" },
3256 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS
, true, "lll" },
3257 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU
, true, "lll" },
3258 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS
, true, "lll" },
3259 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU
, true, "lll" },
3260 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU
, true, "lll" },
3261 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS
, true, "lll" },
3262 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU
, true, "lll" },
3263 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS
, true, "lll" },
3264 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU
, true, "lll" },
3265 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU
, true, "lll" },
3266 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS
, true, "llll" },
3267 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU
, true, "llll" },
3268 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS
, true, "llll" },
3269 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU
, true, "llll" },
3270 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU
, true, "llll" },
3271 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS
, true, "llll" },
3272 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU
, true, "llll" },
3273 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS
, true, "llll" },
3274 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU
, true, "llll" },
3275 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU
, true, "llll" },
3276 { "__insn_mulax", TILEGX_INSN_MULAX
, true, "iiii" },
3277 { "__insn_mulx", TILEGX_INSN_MULX
, true, "iii" },
3278 { "__insn_mz", TILEGX_INSN_MZ
, true, "lll" },
3279 { "__insn_nap", TILEGX_INSN_NAP
, false, "v" },
3280 { "__insn_nop", TILEGX_INSN_NOP
, true, "v" },
3281 { "__insn_nor", TILEGX_INSN_NOR
, true, "lll" },
3282 { "__insn_or", TILEGX_INSN_OR
, true, "lll" },
3283 { "__insn_ori", TILEGX_INSN_OR
, true, "lll" },
3284 { "__insn_pcnt", TILEGX_INSN_PCNT
, true, "ll" },
3285 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3286 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3287 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT
, false, "vk" },
3288 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2
, false, "vk" },
3289 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT
, false, "vk" },
3290 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3
, false, "vk" },
3291 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT
, false, "vk" },
3292 { "__insn_revbits", TILEGX_INSN_REVBITS
, true, "ll" },
3293 { "__insn_revbytes", TILEGX_INSN_REVBYTES
, true, "ll" },
3294 { "__insn_rotl", TILEGX_INSN_ROTL
, true, "lli" },
3295 { "__insn_rotli", TILEGX_INSN_ROTL
, true, "lli" },
3296 { "__insn_shl", TILEGX_INSN_SHL
, true, "lli" },
3297 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI
, true, "lll" },
3298 { "__insn_shl1add", TILEGX_INSN_SHL1ADD
, true, "lll" },
3299 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX
, true, "iii" },
3300 { "__insn_shl2add", TILEGX_INSN_SHL2ADD
, true, "lll" },
3301 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX
, true, "iii" },
3302 { "__insn_shl3add", TILEGX_INSN_SHL3ADD
, true, "lll" },
3303 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX
, true, "iii" },
3304 { "__insn_shli", TILEGX_INSN_SHL
, true, "lli" },
3305 { "__insn_shlx", TILEGX_INSN_SHLX
, true, "iii" },
3306 { "__insn_shlxi", TILEGX_INSN_SHLX
, true, "iii" },
3307 { "__insn_shrs", TILEGX_INSN_SHRS
, true, "lli" },
3308 { "__insn_shrsi", TILEGX_INSN_SHRS
, true, "lli" },
3309 { "__insn_shru", TILEGX_INSN_SHRU
, true, "lli" },
3310 { "__insn_shrui", TILEGX_INSN_SHRU
, true, "lli" },
3311 { "__insn_shrux", TILEGX_INSN_SHRUX
, true, "iii" },
3312 { "__insn_shruxi", TILEGX_INSN_SHRUX
, true, "iii" },
3313 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES
, true, "llll" },
3314 { "__insn_shufflebytes1", TILEGX_INSN_SHUFFLEBYTES1
, true, "lll" },
3315 { "__insn_st", TILEGX_INSN_ST
, false, "vpl" },
3316 { "__insn_st1", TILEGX_INSN_ST1
, false, "vpl" },
3317 { "__insn_st2", TILEGX_INSN_ST2
, false, "vpl" },
3318 { "__insn_st4", TILEGX_INSN_ST4
, false, "vpl" },
3319 { "__insn_stnt", TILEGX_INSN_STNT
, false, "vpl" },
3320 { "__insn_stnt1", TILEGX_INSN_STNT1
, false, "vpl" },
3321 { "__insn_stnt2", TILEGX_INSN_STNT2
, false, "vpl" },
3322 { "__insn_stnt4", TILEGX_INSN_STNT4
, false, "vpl" },
3323 { "__insn_sub", TILEGX_INSN_SUB
, true, "lll" },
3324 { "__insn_subx", TILEGX_INSN_SUBX
, true, "iii" },
3325 { "__insn_subxsc", TILEGX_INSN_SUBXSC
, true, "iii" },
3326 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0
, true, "lll" },
3327 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1
, true, "lll" },
3328 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2
, true, "lll" },
3329 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3
, true, "lll" },
3330 { "__insn_v1add", TILEGX_INSN_V1ADD
, true, "lll" },
3331 { "__insn_v1addi", TILEGX_INSN_V1ADDI
, true, "lll" },
3332 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC
, true, "lll" },
3333 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU
, true, "lll" },
3334 { "__insn_v1avgu", TILEGX_INSN_V1AVGU
, true, "lll" },
3335 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ
, true, "lll" },
3336 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI
, true, "lll" },
3337 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES
, true, "lll" },
3338 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU
, true, "lll" },
3339 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS
, true, "lll" },
3340 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI
, true, "lll" },
3341 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU
, true, "lll" },
3342 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI
, true, "lll" },
3343 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE
, true, "lll" },
3344 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU
, true, "lll" },
3345 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA
, true, "llll" },
3346 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS
, true, "lll" },
3347 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA
, true, "llll" },
3348 { "__insn_v1dotp", TILEGX_INSN_V1DOTP
, true, "lll" },
3349 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA
, true, "llll" },
3350 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU
, true, "lll" },
3351 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA
, true, "llll" },
3352 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS
, true, "lll" },
3353 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA
, true, "llll" },
3354 { "__insn_v1int_h", TILEGX_INSN_V1INT_H
, true, "lll" },
3355 { "__insn_v1int_l", TILEGX_INSN_V1INT_L
, true, "lll" },
3356 { "__insn_v1maxu", TILEGX_INSN_V1MAXU
, true, "lll" },
3357 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI
, true, "lll" },
3358 { "__insn_v1minu", TILEGX_INSN_V1MINU
, true, "lll" },
3359 { "__insn_v1minui", TILEGX_INSN_V1MINUI
, true, "lll" },
3360 { "__insn_v1mnz", TILEGX_INSN_V1MNZ
, true, "lll" },
3361 { "__insn_v1multu", TILEGX_INSN_V1MULTU
, true, "lll" },
3362 { "__insn_v1mulu", TILEGX_INSN_V1MULU
, true, "lll" },
3363 { "__insn_v1mulus", TILEGX_INSN_V1MULUS
, true, "lll" },
3364 { "__insn_v1mz", TILEGX_INSN_V1MZ
, true, "lll" },
3365 { "__insn_v1sadau", TILEGX_INSN_V1SADAU
, true, "llll" },
3366 { "__insn_v1sadu", TILEGX_INSN_V1SADU
, true, "lll" },
3367 { "__insn_v1shl", TILEGX_INSN_V1SHL
, true, "lll" },
3368 { "__insn_v1shli", TILEGX_INSN_V1SHLI
, true, "lll" },
3369 { "__insn_v1shrs", TILEGX_INSN_V1SHRS
, true, "lll" },
3370 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI
, true, "lll" },
3371 { "__insn_v1shru", TILEGX_INSN_V1SHRU
, true, "lll" },
3372 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI
, true, "lll" },
3373 { "__insn_v1sub", TILEGX_INSN_V1SUB
, true, "lll" },
3374 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC
, true, "lll" },
3375 { "__insn_v2add", TILEGX_INSN_V2ADD
, true, "lll" },
3376 { "__insn_v2addi", TILEGX_INSN_V2ADDI
, true, "lll" },
3377 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC
, true, "lll" },
3378 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS
, true, "lll" },
3379 { "__insn_v2avgs", TILEGX_INSN_V2AVGS
, true, "lll" },
3380 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ
, true, "lll" },
3381 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI
, true, "lll" },
3382 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES
, true, "lll" },
3383 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU
, true, "lll" },
3384 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS
, true, "lll" },
3385 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI
, true, "lll" },
3386 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU
, true, "lll" },
3387 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI
, true, "lll" },
3388 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE
, true, "lll" },
3389 { "__insn_v2dotp", TILEGX_INSN_V2DOTP
, true, "lll" },
3390 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA
, true, "llll" },
3391 { "__insn_v2int_h", TILEGX_INSN_V2INT_H
, true, "lll" },
3392 { "__insn_v2int_l", TILEGX_INSN_V2INT_L
, true, "lll" },
3393 { "__insn_v2maxs", TILEGX_INSN_V2MAXS
, true, "lll" },
3394 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI
, true, "lll" },
3395 { "__insn_v2mins", TILEGX_INSN_V2MINS
, true, "lll" },
3396 { "__insn_v2minsi", TILEGX_INSN_V2MINSI
, true, "lll" },
3397 { "__insn_v2mnz", TILEGX_INSN_V2MNZ
, true, "lll" },
3398 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC
, true, "lll" },
3399 { "__insn_v2muls", TILEGX_INSN_V2MULS
, true, "lll" },
3400 { "__insn_v2mults", TILEGX_INSN_V2MULTS
, true, "lll" },
3401 { "__insn_v2mz", TILEGX_INSN_V2MZ
, true, "lll" },
3402 { "__insn_v2packh", TILEGX_INSN_V2PACKH
, true, "lll" },
3403 { "__insn_v2packl", TILEGX_INSN_V2PACKL
, true, "lll" },
3404 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC
, true, "lll" },
3405 { "__insn_v2sadas", TILEGX_INSN_V2SADAS
, true, "llll" },
3406 { "__insn_v2sadau", TILEGX_INSN_V2SADAU
, true, "llll" },
3407 { "__insn_v2sads", TILEGX_INSN_V2SADS
, true, "lll" },
3408 { "__insn_v2sadu", TILEGX_INSN_V2SADU
, true, "lll" },
3409 { "__insn_v2shl", TILEGX_INSN_V2SHL
, true, "lll" },
3410 { "__insn_v2shli", TILEGX_INSN_V2SHLI
, true, "lll" },
3411 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC
, true, "lll" },
3412 { "__insn_v2shrs", TILEGX_INSN_V2SHRS
, true, "lll" },
3413 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI
, true, "lll" },
3414 { "__insn_v2shru", TILEGX_INSN_V2SHRU
, true, "lll" },
3415 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI
, true, "lll" },
3416 { "__insn_v2sub", TILEGX_INSN_V2SUB
, true, "lll" },
3417 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC
, true, "lll" },
3418 { "__insn_v4add", TILEGX_INSN_V4ADD
, true, "lll" },
3419 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC
, true, "lll" },
3420 { "__insn_v4int_h", TILEGX_INSN_V4INT_H
, true, "lll" },
3421 { "__insn_v4int_l", TILEGX_INSN_V4INT_L
, true, "lll" },
3422 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC
, true, "lll" },
3423 { "__insn_v4shl", TILEGX_INSN_V4SHL
, true, "lll" },
3424 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC
, true, "lll" },
3425 { "__insn_v4shrs", TILEGX_INSN_V4SHRS
, true, "lll" },
3426 { "__insn_v4shru", TILEGX_INSN_V4SHRU
, true, "lll" },
3427 { "__insn_v4sub", TILEGX_INSN_V4SUB
, true, "lll" },
3428 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC
, true, "lll" },
3429 { "__insn_wh64", TILEGX_INSN_WH64
, false, "vp" },
3430 { "__insn_xor", TILEGX_INSN_XOR
, true, "lll" },
3431 { "__insn_xori", TILEGX_INSN_XOR
, true, "lll" },
3432 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER
, false, "v" },
3433 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE
, false, "l" },
3434 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE
, false, "l" },
3435 { "__tile_idn_send", TILEGX_IDN_SEND
, false, "vl" },
3436 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE
, false, "l" },
3437 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE
, false, "l" },
3438 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE
, false, "l" },
3439 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE
, false, "l" },
3440 { "__tile_udn_send", TILEGX_UDN_SEND
, false, "vl" },
3444 /* Convert a character in a builtin type string to a tree type. */
3446 char_to_type (char c
)
3448 static tree volatile_ptr_type_node
= NULL
;
3449 static tree volatile_const_ptr_type_node
= NULL
;
3451 if (volatile_ptr_type_node
== NULL
)
3453 volatile_ptr_type_node
=
3454 build_pointer_type (build_qualified_type (void_type_node
,
3455 TYPE_QUAL_VOLATILE
));
3456 volatile_const_ptr_type_node
=
3457 build_pointer_type (build_qualified_type (void_type_node
,
3459 | TYPE_QUAL_VOLATILE
));
3465 return void_type_node
;
3467 return unsigned_type_node
;
3469 return long_long_unsigned_type_node
;
3471 return volatile_ptr_type_node
;
3473 return volatile_const_ptr_type_node
;
3480 /* Implement TARGET_INIT_BUILTINS. */
3482 tilegx_init_builtins (void)
3486 for (i
= 0; i
< ARRAY_SIZE (tilegx_builtins
); i
++)
3488 const struct tilegx_builtin_def
*p
= &tilegx_builtins
[i
];
3489 tree ftype
, ret_type
, arg_type_list
= void_list_node
;
3493 for (j
= strlen (p
->type
) - 1; j
> 0; j
--)
3496 tree_cons (NULL_TREE
, char_to_type (p
->type
[j
]), arg_type_list
);
3499 ret_type
= char_to_type (p
->type
[0]);
3501 ftype
= build_function_type (ret_type
, arg_type_list
);
3503 decl
= add_builtin_function (p
->name
, ftype
, p
->code
, BUILT_IN_MD
,
3507 TREE_READONLY (decl
) = 1;
3508 TREE_NOTHROW (decl
) = 1;
3510 if (tilegx_builtin_info
[p
->code
].fndecl
== NULL
)
3511 tilegx_builtin_info
[p
->code
].fndecl
= decl
;
3516 /* Implement TARGET_EXPAND_BUILTIN. */
3518 tilegx_expand_builtin (tree exp
,
3520 rtx subtarget ATTRIBUTE_UNUSED
,
3521 machine_mode mode ATTRIBUTE_UNUSED
,
3522 int ignore ATTRIBUTE_UNUSED
)
3524 #define MAX_BUILTIN_ARGS 4
3526 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
3527 unsigned int fcode
= DECL_MD_FUNCTION_CODE (fndecl
);
3529 call_expr_arg_iterator iter
;
3530 enum insn_code icode
;
3531 rtx op
[MAX_BUILTIN_ARGS
+ 1], pat
;
3536 if (fcode
>= TILEGX_BUILTIN_max
)
3537 internal_error ("bad builtin fcode");
3538 icode
= tilegx_builtin_info
[fcode
].icode
;
3540 internal_error ("bad builtin icode");
3542 nonvoid
= TREE_TYPE (TREE_TYPE (fndecl
)) != void_type_node
;
3545 FOR_EACH_CALL_EXPR_ARG (arg
, iter
, exp
)
3547 const struct insn_operand_data
*insn_op
;
3549 if (arg
== error_mark_node
)
3551 if (opnum
> MAX_BUILTIN_ARGS
)
3554 insn_op
= &insn_data
[icode
].operand
[opnum
];
3556 op
[opnum
] = expand_expr (arg
, NULL_RTX
, insn_op
->mode
, EXPAND_NORMAL
);
3558 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3560 machine_mode opmode
= insn_op
->mode
;
3562 /* pointer_operand and pmode_register_operand operands do
3563 not specify a mode, so use the operand's mode instead
3564 (which should always be right by the time we get here,
3565 except for constants, which are VOIDmode). */
3566 if (opmode
== VOIDmode
)
3568 machine_mode m
= GET_MODE (op
[opnum
]);
3569 gcc_assert (m
== Pmode
|| m
== VOIDmode
);
3573 op
[opnum
] = copy_to_mode_reg (opmode
, op
[opnum
]);
3576 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3578 /* We still failed to meet the predicate even after moving
3579 into a register. Assume we needed an immediate. */
3580 error_at (EXPR_LOCATION (exp
),
3581 "operand must be an immediate of the right size");
3590 machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
3592 || GET_MODE (target
) != tmode
3593 || !(*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
3595 if (tmode
== VOIDmode
)
3597 /* get the mode from the return type. */
3598 tmode
= TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl
)));
3600 target
= gen_reg_rtx (tmode
);
3605 fn
= GEN_FCN (icode
);
3609 pat
= fn (NULL_RTX
);
3615 pat
= fn (op
[0], op
[1]);
3618 pat
= fn (op
[0], op
[1], op
[2]);
3621 pat
= fn (op
[0], op
[1], op
[2], op
[3]);
3624 pat
= fn (op
[0], op
[1], op
[2], op
[3], op
[4]);
3632 /* If we are generating a prefetch, tell the scheduler not to move
3634 if (GET_CODE (pat
) == PREFETCH
)
3635 PREFETCH_SCHEDULE_BARRIER_P (pat
) = true;
3646 /* Implement TARGET_BUILTIN_DECL. */
3648 tilegx_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
3650 if (code
>= TILEGX_BUILTIN_max
)
3651 return error_mark_node
;
3653 return tilegx_builtin_info
[code
].fndecl
;
3660 /* Return whether REGNO needs to be saved in the stack frame. */
3662 need_to_save_reg (unsigned int regno
)
3664 if (!call_used_or_fixed_reg_p (regno
)
3665 && df_regs_ever_live_p (regno
))
3669 && (regno
== PIC_OFFSET_TABLE_REGNUM
3670 || regno
== TILEGX_PIC_TEXT_LABEL_REGNUM
)
3671 && (crtl
->uses_pic_offset_table
|| crtl
->saves_all_registers
))
3674 if (crtl
->calls_eh_return
)
3677 for (i
= 0; EH_RETURN_DATA_REGNO (i
) != INVALID_REGNUM
; i
++)
3679 if (regno
== EH_RETURN_DATA_REGNO (i
))
3688 /* Return the size of the register savev area. This function is only
3689 correct starting with local register allocation */
3691 tilegx_saved_regs_size (void)
3693 int reg_save_size
= 0;
3695 int offset_to_frame
;
3698 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
3699 if (need_to_save_reg (regno
))
3700 reg_save_size
+= UNITS_PER_WORD
;
3702 /* Pad out the register save area if necessary to make
3703 frame_pointer_rtx be as aligned as the stack pointer. */
3704 offset_to_frame
= crtl
->args
.pretend_args_size
+ reg_save_size
;
3705 align_mask
= (STACK_BOUNDARY
/ BITS_PER_UNIT
) - 1;
3706 reg_save_size
+= (-offset_to_frame
) & align_mask
;
3708 return reg_save_size
;
3712 /* Round up frame size SIZE. */
3714 round_frame_size (int size
)
3716 return ((size
+ STACK_BOUNDARY
/ BITS_PER_UNIT
- 1)
3717 & -STACK_BOUNDARY
/ BITS_PER_UNIT
);
3721 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3722 emit the corresponding REG_CFA_OFFSET note described by CFA and
3723 CFA_OFFSET. Return the emitted insn. */
3725 frame_emit_store (int regno
, int regno_note
, rtx addr
, rtx cfa
,
3728 rtx reg
= gen_rtx_REG (DImode
, regno
);
3729 rtx mem
= gen_frame_mem (DImode
, addr
);
3730 rtx mov
= gen_movdi (mem
, reg
);
3732 /* Describe what just happened in a way that dwarf understands. We
3733 use temporary registers to hold the address to make scheduling
3734 easier, and use the REG_CFA_OFFSET to describe the address as an
3735 offset from the CFA. */
3736 rtx reg_note
= gen_rtx_REG (DImode
, regno_note
);
3737 rtx cfa_relative_addr
= gen_rtx_PLUS (Pmode
, cfa
, GEN_INT (cfa_offset
));
3738 rtx cfa_relative_mem
= gen_frame_mem (DImode
, cfa_relative_addr
);
3739 rtx real
= gen_rtx_SET (cfa_relative_mem
, reg_note
);
3740 add_reg_note (mov
, REG_CFA_OFFSET
, real
);
3742 return emit_insn (mov
);
3746 /* Emit a load in the stack frame to load REGNO from address ADDR.
3747 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3748 non-null. Return the emitted insn. */
3750 frame_emit_load (int regno
, rtx addr
, rtx
*cfa_restores
)
3752 rtx reg
= gen_rtx_REG (DImode
, regno
);
3753 rtx mem
= gen_frame_mem (DImode
, addr
);
3755 *cfa_restores
= alloc_reg_note (REG_CFA_RESTORE
, reg
, *cfa_restores
);
3756 return emit_insn (gen_movdi (reg
, mem
));
3760 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3761 including sequences. */
3763 set_frame_related_p (void)
3765 rtx_insn
*seq
= get_insns ();
3776 while (insn
!= NULL_RTX
)
3778 RTX_FRAME_RELATED_P (insn
) = 1;
3779 insn
= NEXT_INSN (insn
);
3781 seq
= emit_insn (seq
);
3785 seq
= emit_insn (seq
);
3786 RTX_FRAME_RELATED_P (seq
) = 1;
3792 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3794 /* This emits code for 'sp += offset'.
3796 The ABI only allows us to modify 'sp' in a single 'addi' or
3797 'addli', so the backtracer understands it. Larger amounts cannot
3798 use those instructions, so are added by placing the offset into a
3799 large register and using 'add'.
3801 This happens after reload, so we need to expand it ourselves. */
3803 emit_sp_adjust (int offset
, int *next_scratch_regno
, bool frame_related
,
3807 rtx imm_rtx
= GEN_INT (offset
);
3811 if (satisfies_constraint_J (imm_rtx
))
3813 /* We can add this using a single immediate add. */
3818 rtx tmp
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3819 tilegx_expand_set_const64 (tmp
, imm_rtx
);
3823 /* Actually adjust the stack pointer. */
3825 pat
= gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3827 pat
= gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3829 insn
= emit_insn (pat
);
3830 REG_NOTES (insn
) = reg_notes
;
3832 /* Describe what just happened in a way that dwarf understands. */
3835 rtx real
= gen_rtx_SET (stack_pointer_rtx
,
3836 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3838 RTX_FRAME_RELATED_P (insn
) = 1;
3839 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, real
);
3846 /* Return whether the current function is leaf. This takes into
3847 account whether the function calls tls_get_addr. */
3849 tilegx_current_function_is_leaf (void)
3851 return crtl
->is_leaf
&& !cfun
->machine
->calls_tls_get_addr
;
3855 /* Return the frame size. */
3857 compute_total_frame_size (void)
3859 int total_size
= (get_frame_size () + tilegx_saved_regs_size ()
3860 + crtl
->outgoing_args_size
3861 + crtl
->args
.pretend_args_size
);
3863 if (!tilegx_current_function_is_leaf () || cfun
->calls_alloca
)
3865 /* Make room for save area in callee. */
3866 total_size
+= STACK_POINTER_OFFSET
;
3869 return round_frame_size (total_size
);
3873 /* Return nonzero if this function is known to have a null epilogue.
3874 This allows the optimizer to omit jumps to jumps if no stack was
3877 tilegx_can_use_return_insn_p (void)
3879 return (reload_completed
3880 && !cfun
->static_chain_decl
3881 && !compute_total_frame_size ()
3882 && tilegx_current_function_is_leaf ()
3883 && !crtl
->profile
&& !df_regs_ever_live_p (TILEGX_LINK_REGNUM
));
3887 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3888 is a frame pointer, it computes the value relative to
3889 that. Otherwise it uses the stack pointer. */
3891 compute_frame_addr (int offset_from_fp
, int *next_scratch_regno
)
3893 rtx base_reg_rtx
, tmp_reg_rtx
, offset_rtx
;
3894 int offset_from_base
;
3896 if (frame_pointer_needed
)
3898 base_reg_rtx
= hard_frame_pointer_rtx
;
3899 offset_from_base
= offset_from_fp
;
3903 int offset_from_sp
= compute_total_frame_size () + offset_from_fp
;
3904 offset_from_base
= offset_from_sp
;
3905 base_reg_rtx
= stack_pointer_rtx
;
3908 if (offset_from_base
== 0)
3909 return base_reg_rtx
;
3911 /* Compute the new value of the stack pointer. */
3912 tmp_reg_rtx
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3913 offset_rtx
= GEN_INT (offset_from_base
);
3915 if (!add_operand (offset_rtx
, Pmode
))
3917 expand_set_cint64 (tmp_reg_rtx
, offset_rtx
);
3918 offset_rtx
= tmp_reg_rtx
;
3921 emit_insn (gen_rtx_SET (tmp_reg_rtx
,
3922 gen_rtx_PLUS (Pmode
, base_reg_rtx
, offset_rtx
)));
3928 /* The stack frame looks like this:
3933 AP -> +-------------+
3937 HFP -> +-------------+
3939 | reg save | crtl->args.pretend_args_size bytes
3942 | saved regs | tilegx_saved_regs_size() bytes
3943 FP -> +-------------+
3945 | vars | get_frame_size() bytes
3949 | stack args | crtl->outgoing_args_size bytes
3951 | HFP | ptr_size bytes (only here if nonleaf / alloca)
3953 | callee lr | ptr_size bytes (only here if nonleaf / alloca)
3955 SP -> +-------------+
3959 For functions with a frame larger than 32767 bytes, or which use
3960 alloca (), r52 is used as a frame pointer. Otherwise there is no
3963 FP is saved at SP+ptr_size before calling a subroutine so the callee
3966 tilegx_expand_prologue (void)
3968 #define ROUND_ROBIN_SIZE 4
3969 /* We round-robin through four scratch registers to hold temporary
3970 addresses for saving registers, to make instruction scheduling
3972 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
3973 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
3976 unsigned int which_scratch
;
3977 int offset
, start_offset
, regno
;
3979 /* A register that holds a copy of the incoming fp. */
3980 int fp_copy_regno
= -1;
3982 /* A register that holds a copy of the incoming sp. */
3983 int sp_copy_regno
= -1;
3985 /* Next scratch register number to hand out (postdecrementing). */
3986 int next_scratch_regno
= 29;
3988 int total_size
= compute_total_frame_size ();
3990 if (flag_stack_usage_info
)
3991 current_function_static_stack_size
= total_size
;
3993 /* Save lr first in its special location because code after this
3994 might use the link register as a scratch register. */
3995 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
) || crtl
->calls_eh_return
)
3997 FRP (frame_emit_store (TILEGX_LINK_REGNUM
, TILEGX_LINK_REGNUM
,
3998 stack_pointer_rtx
, stack_pointer_rtx
, 0));
3999 emit_insn (gen_blockage ());
4002 if (total_size
== 0)
4004 /* Load the PIC register if needed. */
4005 if (flag_pic
&& crtl
->uses_pic_offset_table
)
4006 load_pic_register (false);
4011 cfa
= stack_pointer_rtx
;
4013 if (frame_pointer_needed
)
4015 fp_copy_regno
= next_scratch_regno
--;
4017 /* Copy the old frame pointer aside so we can save it later. */
4019 FRP (emit_move_insn (gen_rtx_REG (word_mode
, fp_copy_regno
),
4020 gen_lowpart (word_mode
, hard_frame_pointer_rtx
)));
4021 add_reg_note (insn
, REG_CFA_REGISTER
, NULL_RTX
);
4023 /* Set up the frame pointer. */
4024 insn
= FRP (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
4025 add_reg_note (insn
, REG_CFA_DEF_CFA
, hard_frame_pointer_rtx
);
4026 cfa
= hard_frame_pointer_rtx
;
4027 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM
) = STACK_BOUNDARY
;
4029 /* fp holds a copy of the incoming sp, in case we need to store
4031 sp_copy_regno
= HARD_FRAME_POINTER_REGNUM
;
4033 else if (!tilegx_current_function_is_leaf ())
4035 /* Copy the old stack pointer aside so we can save it later. */
4036 sp_copy_regno
= next_scratch_regno
--;
4037 emit_move_insn (gen_rtx_REG (Pmode
, sp_copy_regno
),
4041 if (tilegx_current_function_is_leaf ())
4043 /* No need to store chain pointer to caller's frame. */
4044 emit_sp_adjust (-total_size
, &next_scratch_regno
,
4045 !frame_pointer_needed
, NULL_RTX
);
4049 /* Save the frame pointer (incoming sp value) to support
4050 backtracing. First we need to create an rtx with the store
4052 rtx chain_addr
= gen_rtx_REG (Pmode
, next_scratch_regno
--);
4053 rtx size_rtx
= GEN_INT (-(total_size
- UNITS_PER_WORD
));
4055 if (add_operand (size_rtx
, Pmode
))
4057 /* Expose more parallelism by computing this value from the
4058 original stack pointer, not the one after we have pushed
4060 rtx p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, size_rtx
);
4061 emit_insn (gen_rtx_SET (chain_addr
, p
));
4062 emit_sp_adjust (-total_size
, &next_scratch_regno
,
4063 !frame_pointer_needed
, NULL_RTX
);
4067 /* The stack frame is large, so just store the incoming sp
4068 value at *(new_sp + UNITS_PER_WORD). */
4070 emit_sp_adjust (-total_size
, &next_scratch_regno
,
4071 !frame_pointer_needed
, NULL_RTX
);
4072 p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
4073 GEN_INT (UNITS_PER_WORD
));
4074 emit_insn (gen_rtx_SET (chain_addr
, p
));
4077 /* Save our frame pointer for backtrace chaining. */
4078 emit_insn (gen_movdi (gen_frame_mem (DImode
, chain_addr
),
4079 gen_rtx_REG (DImode
, sp_copy_regno
)));
4082 /* Compute where to start storing registers we need to save. */
4083 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
4084 offset
= start_offset
;
4086 /* Store all registers that need saving. */
4088 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
4089 if (need_to_save_reg (regno
))
4091 rtx r
= reg_save_addr
[which_scratch
];
4093 int cfa_offset
= frame_pointer_needed
? offset
: total_size
+ offset
;
4097 int prev_scratch_regno
= next_scratch_regno
;
4098 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4099 if (prev_scratch_regno
!= next_scratch_regno
)
4100 reg_save_addr
[which_scratch
] = r
;
4104 /* Advance to the next stack slot to store this
4106 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4107 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4108 emit_insn (gen_rtx_SET (r
, p
));
4111 /* Save this register to the stack (but use the old fp value
4112 we copied aside if appropriate). */
4114 (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4115 ? fp_copy_regno
: regno
;
4116 FRP (frame_emit_store (from_regno
, regno
, r
, cfa
, cfa_offset
));
4118 offset
-= UNITS_PER_WORD
;
4119 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4122 /* If profiling, force that to happen after the frame is set up. */
4124 emit_insn (gen_blockage ());
4126 /* Load the PIC register if needed. */
4127 if (flag_pic
&& crtl
->uses_pic_offset_table
)
4128 load_pic_register (false);
4132 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
4133 true for a sibcall_epilogue pattern, and false for an epilogue
4136 tilegx_expand_epilogue (bool sibcall_p
)
4138 /* We round-robin through four scratch registers to hold temporary
4139 addresses for saving registers, to make instruction scheduling
4141 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
4142 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
4144 rtx_insn
*last_insn
, *insn
;
4145 unsigned int which_scratch
;
4146 int offset
, start_offset
, regno
;
4147 rtx cfa_restores
= NULL_RTX
;
4149 /* A register that holds a copy of the incoming fp. */
4150 int fp_copy_regno
= -1;
4152 /* Next scratch register number to hand out (postdecrementing). */
4153 int next_scratch_regno
= 29;
4155 int total_size
= compute_total_frame_size ();
4157 last_insn
= get_last_insn ();
4159 /* Load lr first since we are going to need it first. */
4161 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
))
4163 insn
= frame_emit_load (TILEGX_LINK_REGNUM
,
4164 compute_frame_addr (0, &next_scratch_regno
),
4168 if (total_size
== 0)
4172 RTX_FRAME_RELATED_P (insn
) = 1;
4173 REG_NOTES (insn
) = cfa_restores
;
4178 /* Compute where to start restoring registers. */
4179 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
4180 offset
= start_offset
;
4182 if (frame_pointer_needed
)
4183 fp_copy_regno
= next_scratch_regno
--;
4185 /* Restore all callee-saved registers. */
4187 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
4188 if (need_to_save_reg (regno
))
4190 rtx r
= reg_save_addr
[which_scratch
];
4193 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4194 reg_save_addr
[which_scratch
] = r
;
4198 /* Advance to the next stack slot to store this register. */
4199 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4200 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4201 emit_insn (gen_rtx_SET (r
, p
));
4204 if (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4205 frame_emit_load (fp_copy_regno
, r
, NULL
);
4207 frame_emit_load (regno
, r
, &cfa_restores
);
4209 offset
-= UNITS_PER_WORD
;
4210 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4213 if (!tilegx_current_function_is_leaf ())
4215 alloc_reg_note (REG_CFA_RESTORE
, stack_pointer_rtx
, cfa_restores
);
4217 emit_insn (gen_blockage ());
4219 if (frame_pointer_needed
)
4221 /* Restore the old stack pointer by copying from the frame
4225 insn
= emit_insn (gen_sp_restore_32bit (stack_pointer_rtx
,
4226 hard_frame_pointer_rtx
));
4230 insn
= emit_insn (gen_sp_restore (stack_pointer_rtx
,
4231 hard_frame_pointer_rtx
));
4233 RTX_FRAME_RELATED_P (insn
) = 1;
4234 REG_NOTES (insn
) = cfa_restores
;
4235 add_reg_note (insn
, REG_CFA_DEF_CFA
, stack_pointer_rtx
);
4239 insn
= emit_sp_adjust (total_size
, &next_scratch_regno
, true,
4243 if (crtl
->calls_eh_return
)
4246 emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
,
4247 EH_RETURN_STACKADJ_RTX
));
4249 emit_insn (gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
,
4250 EH_RETURN_STACKADJ_RTX
));
4253 /* Restore the old frame pointer. */
4254 if (frame_pointer_needed
)
4256 insn
= emit_move_insn (gen_lowpart (DImode
, hard_frame_pointer_rtx
),
4257 gen_rtx_REG (DImode
, fp_copy_regno
));
4258 add_reg_note (insn
, REG_CFA_RESTORE
, hard_frame_pointer_rtx
);
4261 /* Mark the pic registers as live outside of the function. */
4264 emit_use (cfun
->machine
->text_label_rtx
);
4265 emit_use (cfun
->machine
->got_rtx
);
4271 emit_jump_insn (gen__return ());
4275 emit_use (gen_rtx_REG (Pmode
, TILEGX_LINK_REGNUM
));
4278 /* Mark all insns we just emitted as frame-related. */
4279 for (; last_insn
!= NULL_RTX
; last_insn
= next_insn (last_insn
))
4280 RTX_FRAME_RELATED_P (last_insn
) = 1;
4283 #undef ROUND_ROBIN_SIZE
4286 /* Implement INITIAL_ELIMINATION_OFFSET. */
4288 tilegx_initial_elimination_offset (int from
, int to
)
4290 int total_size
= compute_total_frame_size ();
4292 if (from
== FRAME_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4294 return (total_size
- crtl
->args
.pretend_args_size
4295 - tilegx_saved_regs_size ());
4297 else if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4299 return -(crtl
->args
.pretend_args_size
+ tilegx_saved_regs_size ());
4301 else if (from
== ARG_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4303 return STACK_POINTER_OFFSET
+ total_size
;
4305 else if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4307 return STACK_POINTER_OFFSET
;
4314 /* Return an RTX indicating where the return address to the calling
4315 function can be found. */
4317 tilegx_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
4322 return get_hard_reg_initial_val (Pmode
, TILEGX_LINK_REGNUM
);
4326 /* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to
4327 prevent it from being deleted. */
4329 tilegx_eh_return_handler_rtx (void)
4331 rtx tmp
= gen_frame_mem (Pmode
, hard_frame_pointer_rtx
);
4332 MEM_VOLATILE_P (tmp
) = true;
4340 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
4342 tilegx_conditional_register_usage (void)
4344 global_regs
[TILEGX_NETORDER_REGNUM
] = 1;
4345 /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. */
4346 if (TILEGX_PIC_TEXT_LABEL_REGNUM
!= INVALID_REGNUM
)
4347 fixed_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4348 if (PIC_OFFSET_TABLE_REGNUM
!= INVALID_REGNUM
)
4349 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4353 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
4355 tilegx_frame_pointer_required (void)
4357 return crtl
->calls_eh_return
|| cfun
->calls_alloca
;
4362 /* Scheduling and reorg */
4364 /* Return the length of INSN. LENGTH is the initial length computed
4365 by attributes in the machine-description file. This is where we
4366 account for bundles. */
4368 tilegx_adjust_insn_length (rtx_insn
*insn
, int length
)
4370 machine_mode mode
= GET_MODE (insn
);
4372 /* A non-termininating instruction in a bundle has length 0. */
4376 /* By default, there is not length adjustment. */
4381 /* Implement TARGET_SCHED_ISSUE_RATE. */
4383 tilegx_issue_rate (void)
4389 /* Return the rtx for the jump target. */
4391 get_jump_target (rtx branch
)
4393 if (CALL_P (branch
))
4396 call
= PATTERN (branch
);
4398 if (GET_CODE (call
) == PARALLEL
)
4399 call
= XVECEXP (call
, 0, 0);
4401 if (GET_CODE (call
) == SET
)
4402 call
= SET_SRC (call
);
4404 if (GET_CODE (call
) == CALL
)
4405 return XEXP (XEXP (call
, 0), 0);
4411 /* Implement TARGET_SCHED_ADJUST_COST. */
4413 tilegx_sched_adjust_cost (rtx_insn
*insn
, int dep_type
, rtx_insn
*dep_insn
,
4414 int cost
, unsigned int)
4416 /* If we have a true dependence, INSN is a call, and DEP_INSN
4417 defines a register that is needed by the call (argument or stack
4418 pointer) , set its latency to 0 so that it can be bundled with
4419 the call. Explicitly check for and exclude the case when
4420 DEP_INSN defines the target of the jump. */
4421 if (CALL_P (insn
) && dep_type
== REG_DEP_TRUE
)
4423 rtx target
= get_jump_target (insn
);
4424 if (!REG_P (target
) || !set_of (target
, dep_insn
))
4432 /* Skip over irrelevant NOTEs and such and look for the next insn we
4433 would consider bundling. */
4435 next_insn_to_bundle (rtx_insn
*r
, rtx_insn
*end
)
4437 for (; r
!= end
; r
= NEXT_INSN (r
))
4439 if (NONDEBUG_INSN_P (r
)
4440 && GET_CODE (PATTERN (r
)) != USE
4441 && GET_CODE (PATTERN (r
)) != CLOBBER
)
4449 /* Go through all insns, and use the information generated during
4450 scheduling to generate SEQUENCEs to represent bundles of
4451 instructions issued simultaneously. */
4453 tilegx_gen_bundles (void)
4456 FOR_EACH_BB_FN (bb
, cfun
)
4458 rtx_insn
*insn
, *next
, *prev
;
4459 rtx_insn
*end
= NEXT_INSN (BB_END (bb
));
4462 for (insn
= next_insn_to_bundle (BB_HEAD (bb
), end
); insn
; insn
= next
)
4464 next
= next_insn_to_bundle (NEXT_INSN (insn
), end
);
4466 /* Never wrap {} around inline asm. */
4467 if (GET_CODE (PATTERN (insn
)) != ASM_INPUT
)
4469 if (next
== NULL_RTX
|| GET_MODE (next
) == TImode
4470 /* NOTE: The scheduler incorrectly believes a call
4471 insn can execute in the same cycle as the insn
4472 after the call. This is of course impossible.
4473 Really we need to fix the scheduler somehow, so
4474 the code after the call gets scheduled
4478 /* Mark current insn as the end of a bundle. */
4479 PUT_MODE (insn
, QImode
);
4483 /* Mark it as part of a bundle. */
4484 PUT_MODE (insn
, SImode
);
4488 /* Delete barrier insns, because they can mess up the
4489 emitting of bundle braces. If it is end-of-bundle, then
4490 the previous insn must be marked end-of-bundle. */
4491 if (get_attr_type (insn
) == TYPE_NOTHING
) {
4492 if (GET_MODE (insn
) == QImode
&& prev
!= NULL
4493 && GET_MODE (prev
) == SImode
)
4495 PUT_MODE (prev
, QImode
);
4499 // Note: prev remains the same for next iteration.
4508 /* Replace OLD_INSN with NEW_INSN. */
4510 replace_insns (rtx_insn
*old_insn
, rtx_insn
*new_insns
)
4513 emit_insn_before (new_insns
, old_insn
);
4515 delete_insn (old_insn
);
4519 /* Returns true if INSN is the first instruction of a pc-relative
4520 address compuatation. */
4522 match_pcrel_step1 (rtx insn
)
4524 rtx pattern
= PATTERN (insn
);
4527 if (GET_CODE (pattern
) != SET
)
4530 src
= SET_SRC (pattern
);
4532 return (GET_CODE (src
) == CONST
4533 && GET_CODE (XEXP (src
, 0)) == UNSPEC
4534 && XINT (XEXP (src
, 0), 1) == UNSPEC_HW1_LAST_PCREL
);
4538 /* Do the first replacement step in tilegx_fixup_pcrel_references. */
4540 replace_mov_pcrel_step1 (rtx_insn
*insn
)
4542 rtx pattern
= PATTERN (insn
);
4545 rtx_insn
*new_insns
;
4547 gcc_assert (GET_CODE (pattern
) == SET
);
4548 opnds
[0] = SET_DEST (pattern
);
4550 gcc_assert (GET_CODE (SET_SRC (pattern
)) == CONST
);
4552 unspec
= XEXP (SET_SRC (pattern
), 0);
4553 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4554 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW1_LAST_PCREL
);
4555 opnds
[1] = XVECEXP (unspec
, 0, 0);
4557 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4558 if (GET_CODE (opnds
[1]) != SYMBOL_REF
)
4566 emit_insn (gen_mov_got32_step1_32bit (opnds
[0], opnds
[1]));
4568 emit_insn (gen_mov_got32_step1 (opnds
[0], opnds
[1]));
4571 new_insns
= get_insns ();
4574 replace_insns (insn
, new_insns
);
4578 /* Returns true if INSN is the second instruction of a pc-relative
4579 address compuatation. */
4581 match_pcrel_step2 (rtx_insn
*insn
)
4588 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli_32bit
)
4593 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli
)
4597 unspec
= SET_SRC (PATTERN (insn
));
4598 addr
= XVECEXP (unspec
, 0, 1);
4600 return (GET_CODE (addr
) == CONST
4601 && GET_CODE (XEXP (addr
, 0)) == UNSPEC
4602 && XINT (XEXP (addr
, 0), 1) == UNSPEC_HW0_PCREL
);
4606 /* Do the second replacement step in tilegx_fixup_pcrel_references. */
4608 replace_mov_pcrel_step2 (rtx_insn
*insn
)
4610 rtx pattern
= PATTERN (insn
);
4614 rtx_insn
*new_insns
;
4615 rtx got_rtx
= tilegx_got_rtx ();
4617 gcc_assert (GET_CODE (pattern
) == SET
);
4618 opnds
[0] = SET_DEST (pattern
);
4620 unspec
= SET_SRC (pattern
);
4621 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4622 gcc_assert (XINT (unspec
, 1) == UNSPEC_INSN_ADDR_SHL16INSLI
);
4624 opnds
[1] = XVECEXP (unspec
, 0, 0);
4626 addr
= XVECEXP (unspec
, 0, 1);
4627 gcc_assert (GET_CODE (addr
) == CONST
);
4629 unspec
= XEXP (addr
, 0);
4630 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4631 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW0_PCREL
);
4632 opnds
[2] = XVECEXP (unspec
, 0, 0);
4634 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4635 if (GET_CODE (opnds
[2]) != SYMBOL_REF
)
4643 emit_insn (gen_add_got16_32bit (opnds
[0], got_rtx
, opnds
[2]));
4645 emit_insn (gen_add_got16 (opnds
[0], got_rtx
, opnds
[2]));
4650 emit_insn (gen_mov_got32_step2_32bit
4651 (opnds
[0], opnds
[1], opnds
[2]));
4653 emit_insn (gen_mov_got32_step2 (opnds
[0], opnds
[1], opnds
[2]));
4656 new_insns
= get_insns ();
4659 replace_insns (insn
, new_insns
);
4663 /* Do the third replacement step in tilegx_fixup_pcrel_references. */
4665 replace_mov_pcrel_step3 (rtx_insn
*insn
)
4667 rtx pattern
= PATTERN (insn
);
4670 rtx_insn
*new_insns
;
4671 rtx got_rtx
= tilegx_got_rtx ();
4672 rtx text_label_rtx
= tilegx_text_label_rtx ();
4674 gcc_assert (GET_CODE (pattern
) == SET
);
4675 opnds
[0] = SET_DEST (pattern
);
4677 unspec
= SET_SRC (pattern
);
4678 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4679 gcc_assert (XINT (unspec
, 1) == UNSPEC_MOV_PCREL_STEP3
);
4683 if (XVECEXP (unspec
, 0, 0) == text_label_rtx
)
4684 opnds
[2] = XVECEXP (unspec
, 0, 1);
4687 gcc_assert (XVECEXP (unspec
, 0, 1) == text_label_rtx
);
4688 opnds
[2] = XVECEXP (unspec
, 0, 0);
4691 opnds
[3] = XVECEXP (unspec
, 0, 2);
4693 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4694 if (GET_CODE (opnds
[3]) != SYMBOL_REF
)
4701 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[2]));
4705 emit_move_insn (opnds
[0], gen_rtx_PLUS (Pmode
, opnds
[1], opnds
[2]));
4706 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[0]));
4709 new_insns
= get_insns ();
4712 replace_insns (insn
, new_insns
);
4716 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4717 going through the GOT when the symbol is local to the compilation
4718 unit. But such a symbol requires that the common text_label that
4719 we generate at the beginning of the function be in the same section
4720 as the reference to the SYMBOL_REF. This may not be true if we
4721 generate hot/cold sections. This function looks for such cases and
4722 replaces such references with the longer sequence going through the
4725 We expect following instruction sequence:
4726 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4727 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4728 add<x> tmp3, txt_label_reg, tmp2 [3]
4730 If we're compiling -fpic, we replace with the following sequence
4731 (the numbers in brackets match the instructions they're replacing
4734 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4735 ld<4> tmp3, tmp2 [3]
4737 If we're compiling -fPIC, we replace the first instruction with:
4739 moveli tmp1, hw1_last_got(x) [1]
4740 shl16insli tmp2, tmp1, hw0_got(x) [2]
4741 add<x> tmp3, got_reg, tmp2 [3]
4742 ld<4> tmp3, tmp3 [3]
4744 Note that we're careful to disturb the instruction sequence as
4745 little as possible, since it's very late in the compilation
4748 tilegx_fixup_pcrel_references (void)
4750 rtx_insn
*insn
, *next_insn
;
4751 bool same_section_as_entry
= true;
4753 for (insn
= get_insns (); insn
; insn
= next_insn
)
4755 next_insn
= NEXT_INSN (insn
);
4757 if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_SWITCH_TEXT_SECTIONS
)
4759 same_section_as_entry
= !same_section_as_entry
;
4763 if (same_section_as_entry
)
4767 && GET_CODE (PATTERN (insn
)) != USE
4768 && GET_CODE (PATTERN (insn
)) != CLOBBER
))
4773 if (match_pcrel_step1 (insn
))
4774 replace_mov_pcrel_step1 (insn
);
4775 else if (match_pcrel_step2 (insn
))
4776 replace_mov_pcrel_step2 (insn
);
4777 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3_32bit
)
4778 replace_mov_pcrel_step3 (insn
);
4782 if (match_pcrel_step1 (insn
))
4783 replace_mov_pcrel_step1 (insn
);
4784 else if (match_pcrel_step2 (insn
))
4785 replace_mov_pcrel_step2 (insn
);
4786 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3
)
4787 replace_mov_pcrel_step3 (insn
);
4793 /* Ensure that no var tracking notes are emitted in the middle of a
4794 three-instruction bundle. */
4796 reorder_var_tracking_notes (void)
4799 FOR_EACH_BB_FN (bb
, cfun
)
4801 rtx_insn
*insn
, *next
;
4802 rtx_insn
*queue
= NULL
;
4803 bool in_bundle
= false;
4805 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4807 next
= NEXT_INSN (insn
);
4811 /* Emit queued up notes at the last instruction of a
4813 if (GET_MODE (insn
) == QImode
)
4817 rtx_insn
*next_queue
= PREV_INSN (queue
);
4818 SET_PREV_INSN (NEXT_INSN (insn
)) = queue
;
4819 SET_NEXT_INSN (queue
) = NEXT_INSN (insn
);
4820 SET_NEXT_INSN (insn
) = queue
;
4821 SET_PREV_INSN (queue
) = insn
;
4826 else if (GET_MODE (insn
) == SImode
)
4829 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4833 rtx_insn
*prev
= PREV_INSN (insn
);
4834 SET_PREV_INSN (next
) = prev
;
4835 SET_NEXT_INSN (prev
) = next
;
4837 SET_PREV_INSN (insn
) = queue
;
4846 /* Perform machine dependent operations on the rtl chain INSNS. */
4850 /* We are freeing block_for_insn in the toplev to keep compatibility
4851 with old MDEP_REORGS that are not CFG based. Recompute it
4853 compute_bb_for_insn ();
4855 if (flag_reorder_blocks_and_partition
)
4857 tilegx_fixup_pcrel_references ();
4860 if (flag_schedule_insns_after_reload
)
4864 timevar_push (TV_SCHED2
);
4866 timevar_pop (TV_SCHED2
);
4868 /* Examine the schedule to group into bundles. */
4869 tilegx_gen_bundles ();
4874 if (flag_var_tracking
)
4876 timevar_push (TV_VAR_TRACKING
);
4877 variable_tracking_main ();
4878 reorder_var_tracking_notes ();
4879 timevar_pop (TV_VAR_TRACKING
);
4882 df_finish_pass (false);
4889 /* Select a format to encode pointers in exception handling data.
4890 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4891 GLOBAL is true if the symbol may be affected by dynamic
4894 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED
, int global
)
4896 int type
= TARGET_32BIT
? DW_EH_PE_sdata4
: DW_EH_PE_sdata8
;
4897 return (global
? DW_EH_PE_indirect
: 0) | DW_EH_PE_pcrel
| type
;
4901 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4903 tilegx_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
4904 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
4907 const char *fnname
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl
));
4908 rtx this_rtx
, funexp
, addend
;
4911 /* Pretend to be a post-reload pass while generating rtl. */
4912 reload_completed
= 1;
4914 /* Mark the end of the (empty) prologue. */
4915 emit_note (NOTE_INSN_PROLOGUE_END
);
4917 /* Find the "this" pointer. If the function returns a structure,
4918 the structure return pointer is in $1. */
4919 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
4920 this_rtx
= gen_rtx_REG (Pmode
, 1);
4922 this_rtx
= gen_rtx_REG (Pmode
, 0);
4924 /* Add DELTA to THIS_RTX. */
4925 if (!(delta
>= -32868 && delta
<= 32767))
4927 addend
= gen_rtx_REG (Pmode
, 29);
4928 emit_move_insn (addend
, GEN_INT (delta
));
4931 addend
= GEN_INT (delta
);
4934 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, addend
));
4936 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, addend
));
4938 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4943 tmp
= gen_rtx_REG (Pmode
, 29);
4944 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, this_rtx
));
4946 if (!(vcall_offset
>= -32868 && vcall_offset
<= 32767))
4948 addend
= gen_rtx_REG (Pmode
, 28);
4949 emit_move_insn (addend
, GEN_INT (vcall_offset
));
4952 addend
= GEN_INT (vcall_offset
);
4955 emit_insn (gen_addsi3 (tmp
, tmp
, addend
));
4957 emit_insn (gen_adddi3 (tmp
, tmp
, addend
));
4959 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, tmp
));
4962 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, tmp
));
4964 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, tmp
));
4967 /* Generate a tail call to the target function. */
4968 if (!TREE_USED (function
))
4970 assemble_external (function
);
4971 TREE_USED (function
) = 1;
4973 funexp
= XEXP (DECL_RTL (function
), 0);
4974 funexp
= gen_rtx_MEM (FUNCTION_MODE
, funexp
);
4975 insn
= emit_call_insn (gen_sibcall (funexp
, const0_rtx
));
4976 SIBLING_CALL_P (insn
) = 1;
4978 /* Run just enough of rest_of_compilation to get the insns emitted.
4979 There's not really enough bulk here to make other passes such as
4980 instruction scheduling worth while.
4982 We don't currently bundle, but the instruciton sequence is all
4983 serial except for the tail call, so we're only wasting one cycle.
4985 insn
= get_insns ();
4986 shorten_branches (insn
);
4987 assemble_start_function (thunk_fndecl
, fnname
);
4988 final_start_function (insn
, file
, 1);
4989 final (insn
, file
, 1);
4990 final_end_function ();
4991 assemble_end_function (thunk_fndecl
, fnname
);
4993 /* Stop pretending to be a post-reload pass. */
4994 reload_completed
= 0;
4998 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
5000 tilegx_asm_trampoline_template (FILE *file
)
5002 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
5005 fprintf (file
, "\tlnk r10\n");
5006 fprintf (file
, "\taddxi r10, r10, 32\n");
5007 fprintf (file
, "\tld4s_add r11, r10, %d\n", ptr_mode_size
);
5008 fprintf (file
, "\tld4s r10, r10\n");
5009 fprintf (file
, "\tjr r11\n");
5010 fprintf (file
, "\t.word 0 # <function address>\n");
5011 fprintf (file
, "\t.word 0 # <static chain value>\n");
5015 fprintf (file
, "\tlnk r10\n");
5016 fprintf (file
, "\taddi r10, r10, 32\n");
5017 fprintf (file
, "\tld_add r11, r10, %d\n", ptr_mode_size
);
5018 fprintf (file
, "\tld r10, r10\n");
5019 fprintf (file
, "\tjr r11\n");
5020 fprintf (file
, "\t.quad 0 # <function address>\n");
5021 fprintf (file
, "\t.quad 0 # <static chain value>\n");
5026 /* Implement TARGET_TRAMPOLINE_INIT. */
5028 tilegx_trampoline_init (rtx m_tramp
, tree fndecl
, rtx static_chain
)
5032 rtx begin_addr
, end_addr
;
5033 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
5035 fnaddr
= copy_to_reg (XEXP (DECL_RTL (fndecl
), 0));
5036 chaddr
= copy_to_reg (static_chain
);
5038 emit_block_move (m_tramp
, assemble_trampoline_template (),
5039 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
5041 mem
= adjust_address (m_tramp
, ptr_mode
,
5042 TRAMPOLINE_SIZE
- 2 * ptr_mode_size
);
5043 emit_move_insn (mem
, fnaddr
);
5044 mem
= adjust_address (m_tramp
, ptr_mode
,
5045 TRAMPOLINE_SIZE
- ptr_mode_size
);
5046 emit_move_insn (mem
, chaddr
);
5048 /* Get pointers to the beginning and end of the code block. */
5049 begin_addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
5050 end_addr
= force_reg (Pmode
, plus_constant (Pmode
, XEXP (m_tramp
, 0),
5053 maybe_emit_call_builtin___clear_cache (begin_addr
, end_addr
);
5057 /* Implement TARGET_PRINT_OPERAND. */
5059 tilegx_print_operand (FILE *file
, rtx x
, int code
)
5064 /* Print the compare operator opcode for conditional moves. */
5065 switch (GET_CODE (x
))
5074 output_operand_lossage ("invalid %%c operand");
5079 /* Print the compare operator opcode for conditional moves. */
5080 switch (GET_CODE (x
))
5089 output_operand_lossage ("invalid %%C operand");
5095 /* Print the compare operator opcode for conditional moves. */
5096 switch (GET_CODE (x
))
5105 output_operand_lossage ("invalid %%d operand");
5112 /* Print the compare operator opcode for conditional moves. */
5113 switch (GET_CODE (x
))
5122 output_operand_lossage ("invalid %%D operand");
5129 if (GET_CODE (x
) == CONST
5130 && GET_CODE (XEXP (x
, 0)) == UNSPEC
)
5132 rtx addr
= XVECEXP (XEXP (x
, 0), 0, 0);
5133 int unspec
= XINT (XEXP (x
, 0), 1);
5134 const char *opstr
= NULL
;
5138 case UNSPEC_HW0_PCREL
:
5142 case UNSPEC_HW1_PCREL
:
5151 case UNSPEC_HW0_LAST
:
5154 case UNSPEC_HW1_LAST
:
5155 case UNSPEC_HW1_LAST_PCREL
:
5158 case UNSPEC_HW2_LAST
:
5159 case UNSPEC_HW2_LAST_PCREL
:
5162 case UNSPEC_HW0_GOT
:
5165 case UNSPEC_HW0_LAST_GOT
:
5166 opstr
= "hw0_last_got";
5168 case UNSPEC_HW1_LAST_GOT
:
5169 opstr
= "hw1_last_got";
5171 case UNSPEC_HW0_TLS_GD
:
5172 opstr
= "hw0_tls_gd";
5174 case UNSPEC_HW1_LAST_TLS_GD
:
5175 opstr
= "hw1_last_tls_gd";
5177 case UNSPEC_HW0_TLS_IE
:
5178 opstr
= "hw0_tls_ie";
5180 case UNSPEC_HW1_LAST_TLS_IE
:
5181 opstr
= "hw1_last_tls_ie";
5183 case UNSPEC_HW0_TLS_LE
:
5184 opstr
= "hw0_tls_le";
5186 case UNSPEC_HW1_LAST_TLS_LE
:
5187 opstr
= "hw1_last_tls_le";
5189 case UNSPEC_HW0_PLT_PCREL
:
5192 case UNSPEC_HW1_PLT_PCREL
:
5195 case UNSPEC_HW1_LAST_PLT_PCREL
:
5196 opstr
= "hw1_last_plt";
5198 case UNSPEC_HW2_LAST_PLT_PCREL
:
5199 opstr
= "hw2_last_plt";
5202 output_operand_lossage ("invalid %%H specifier");
5205 fputs (opstr
, file
);
5207 output_addr_const (file
, addr
);
5209 if (unspec
== UNSPEC_HW0_PCREL
5210 || unspec
== UNSPEC_HW1_PCREL
5211 || unspec
== UNSPEC_HW1_LAST_PCREL
5212 || unspec
== UNSPEC_HW2_LAST_PCREL
5213 || unspec
== UNSPEC_HW0_PLT_PCREL
5214 || unspec
== UNSPEC_HW1_PLT_PCREL
5215 || unspec
== UNSPEC_HW1_LAST_PLT_PCREL
5216 || unspec
== UNSPEC_HW2_LAST_PLT_PCREL
)
5218 rtx addr2
= XVECEXP (XEXP (x
, 0), 0, 1);
5219 fputs (" - " , file
);
5220 output_addr_const (file
, addr2
);
5226 else if (symbolic_operand (x
, VOIDmode
))
5228 output_addr_const (file
, x
);
5236 /* Print the low 16 bits of a constant. */
5238 if (CONST_INT_P (x
))
5240 else if (GET_CODE (x
) == CONST_DOUBLE
)
5241 i
= CONST_DOUBLE_LOW (x
);
5244 output_operand_lossage ("invalid %%h operand");
5247 i
= trunc_int_for_mode (i
, HImode
);
5248 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5253 /* Print an auto-inc memory operand. */
5256 output_operand_lossage ("invalid %%I operand");
5260 output_memory_autoinc_first
= true;
5261 output_address (GET_MODE (x
), XEXP (x
, 0));
5265 /* Print an auto-inc memory operand. */
5268 output_operand_lossage ("invalid %%i operand");
5272 output_memory_autoinc_first
= false;
5273 output_address (GET_MODE (x
), XEXP (x
, 0));
5278 /* Print the low 8 bits of a constant. */
5280 if (CONST_INT_P (x
))
5282 else if (GET_CODE (x
) == CONST_DOUBLE
)
5283 i
= CONST_DOUBLE_LOW (x
);
5284 else if (GET_CODE (x
) == CONST_VECTOR
5285 && CONST_INT_P (CONST_VECTOR_ELT (x
, 0)))
5286 i
= INTVAL (CONST_VECTOR_ELT (x
, 0));
5289 output_operand_lossage ("invalid %%j operand");
5292 i
= trunc_int_for_mode (i
, QImode
);
5293 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5299 /* Print a constant plus one. */
5300 if (!CONST_INT_P (x
))
5302 output_operand_lossage ("invalid %%P operand");
5305 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (x
) + 1);
5312 /* Print a bfextu-style bit range. */
5313 int first_bit
, last_bit
;
5314 HOST_WIDE_INT flip
= (code
== 'm') ? ~0 : 0;
5316 if (!CONST_INT_P (x
)
5317 || !tilegx_bitfield_operand_p (INTVAL (x
) ^ flip
,
5318 &first_bit
, &last_bit
))
5320 output_operand_lossage ("invalid %%%c operand", code
);
5324 fprintf (file
, "%d, %d", first_bit
, last_bit
);
5330 const char *reg
= NULL
;
5332 /* Print a network register. */
5333 if (!CONST_INT_P (x
))
5335 output_operand_lossage ("invalid %%N operand");
5341 case TILEGX_NETREG_IDN0
: reg
= "idn0"; break;
5342 case TILEGX_NETREG_IDN1
: reg
= "idn1"; break;
5343 case TILEGX_NETREG_UDN0
: reg
= "udn0"; break;
5344 case TILEGX_NETREG_UDN1
: reg
= "udn1"; break;
5345 case TILEGX_NETREG_UDN2
: reg
= "udn2"; break;
5346 case TILEGX_NETREG_UDN3
: reg
= "udn3"; break;
5351 fprintf (file
, reg
);
5356 if (GET_CODE (x
) == SYMBOL_REF
)
5358 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5359 fprintf (file
, "plt(");
5360 output_addr_const (file
, x
);
5361 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5362 fprintf (file
, ")");
5365 output_addr_const (file
, x
);
5369 /* In this case we need a register. Use 'zero' if the operand
5372 || (GET_MODE (x
) != VOIDmode
&& x
== CONST0_RTX (GET_MODE (x
))))
5374 fputs ("zero", file
);
5377 else if (!REG_P (x
))
5379 output_operand_lossage ("invalid operand for 'r' specifier");
5387 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
5392 output_address (VOIDmode
, XEXP (x
, 0));
5397 output_addr_const (file
, x
);
5403 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5408 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5410 tilegx_print_operand_address (FILE *file
, machine_mode mode
, rtx addr
)
5412 if (GET_CODE (addr
) == POST_DEC
5413 || GET_CODE (addr
) == POST_INC
)
5415 int offset
= GET_MODE_SIZE (mode
);
5417 gcc_assert (mode
!= VOIDmode
);
5419 if (output_memory_autoinc_first
)
5420 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5422 fprintf (file
, "%d",
5423 GET_CODE (addr
) == POST_DEC
? -offset
: offset
);
5425 else if (GET_CODE (addr
) == POST_MODIFY
)
5427 gcc_assert (mode
!= VOIDmode
);
5429 gcc_assert (GET_CODE (XEXP (addr
, 1)) == PLUS
);
5431 if (output_memory_autoinc_first
)
5432 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5434 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
,
5435 INTVAL (XEXP (XEXP (addr
, 1), 1)));
5438 tilegx_print_operand (file
, addr
, 'r');
5442 /* Machine mode of current insn, for determining curly brace
5444 static machine_mode insn_mode
;
5447 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5449 tilegx_final_prescan_insn (rtx_insn
*insn
)
5451 /* Record this for tilegx_asm_output_opcode to examine. */
5452 insn_mode
= GET_MODE (insn
);
5456 /* While emitting asm, are we currently inside '{' for a bundle? */
5457 static bool tilegx_in_bundle
= false;
5459 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5460 appropriate given the bundling information recorded by
5461 tilegx_gen_bundles. */
5463 tilegx_asm_output_opcode (FILE *stream
, const char *code
)
5465 bool pseudo
= !strcmp (code
, "pseudo");
5467 if (!tilegx_in_bundle
&& insn_mode
== SImode
)
5469 /* Start a new bundle. */
5470 fprintf (stream
, "{\n\t");
5471 tilegx_in_bundle
= true;
5474 if (tilegx_in_bundle
&& insn_mode
== QImode
)
5476 /* Close an existing bundle. */
5477 static char buf
[100];
5479 gcc_assert (strlen (code
) + 3 + 1 < sizeof (buf
));
5481 strcpy (buf
, pseudo
? "" : code
);
5482 strcat (buf
, "\n\t}");
5483 tilegx_in_bundle
= false;
5489 return pseudo
? "" : code
;
5494 /* Output assembler code to FILE to increment profiler label # LABELNO
5495 for profiling a function entry. */
5497 tilegx_function_profiler (FILE *file
, int labelno ATTRIBUTE_UNUSED
)
5499 if (tilegx_in_bundle
)
5501 fprintf (file
, "\t}\n");
5504 if (cfun
->static_chain_decl
)
5508 "\taddi\tsp, sp, -16\n"
5519 "\t}\n", MCOUNT_NAME
);
5527 "\t}\n", MCOUNT_NAME
);
5530 if (cfun
->static_chain_decl
)
5533 "\taddi\tsp, sp, 16\n"
5537 tilegx_in_bundle
= false;
5541 /* Implement TARGET_ASM_FILE_END. */
5543 tilegx_file_end (void)
5545 if (NEED_INDICATE_EXEC_STACK
)
5546 file_end_indicate_exec_stack ();
5549 /* Implement TARGET_TRULY_NOOP_TRUNCATION. We represent all SI values
5550 as sign-extended DI values in registers. */
5553 tilegx_truly_noop_truncation (poly_uint64 outprec
, poly_uint64 inprec
)
5555 return inprec
<= 32 || outprec
> 32;
5558 #undef TARGET_HAVE_TLS
5559 #define TARGET_HAVE_TLS HAVE_AS_TLS
5561 #undef TARGET_OPTION_OVERRIDE
5562 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5564 #ifdef TARGET_THREAD_SSP_OFFSET
5565 #undef TARGET_STACK_PROTECT_GUARD
5566 #define TARGET_STACK_PROTECT_GUARD hook_tree_void_null
5569 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5570 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5572 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5573 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5575 #undef TARGET_CANNOT_FORCE_CONST_MEM
5576 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5578 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5579 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5581 #undef TARGET_PASS_BY_REFERENCE
5582 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5584 #undef TARGET_RETURN_IN_MSB
5585 #define TARGET_RETURN_IN_MSB tilegx_return_in_msb
5587 #undef TARGET_RETURN_IN_MEMORY
5588 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5590 #undef TARGET_MODE_REP_EXTENDED
5591 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5593 #undef TARGET_FUNCTION_ARG_BOUNDARY
5594 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5596 #undef TARGET_FUNCTION_ARG
5597 #define TARGET_FUNCTION_ARG tilegx_function_arg
5599 #undef TARGET_FUNCTION_ARG_ADVANCE
5600 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5602 #undef TARGET_FUNCTION_VALUE
5603 #define TARGET_FUNCTION_VALUE tilegx_function_value
5605 #undef TARGET_LIBCALL_VALUE
5606 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5608 #undef TARGET_FUNCTION_VALUE_REGNO_P
5609 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5611 #undef TARGET_PROMOTE_FUNCTION_MODE
5612 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5614 #undef TARGET_PROMOTE_PROTOTYPES
5615 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5617 #undef TARGET_BUILD_BUILTIN_VA_LIST
5618 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5620 #undef TARGET_EXPAND_BUILTIN_VA_START
5621 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5623 #undef TARGET_SETUP_INCOMING_VARARGS
5624 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5626 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5627 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5629 #undef TARGET_RTX_COSTS
5630 #define TARGET_RTX_COSTS tilegx_rtx_costs
5632 #undef TARGET_EXPAND_TO_RTL_HOOK
5633 #define TARGET_EXPAND_TO_RTL_HOOK tilegx_expand_to_rtl_hook
5635 #undef TARGET_SHIFT_TRUNCATION_MASK
5636 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5638 #undef TARGET_INIT_LIBFUNCS
5639 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5641 /* Limit to what we can reach in one addli. */
5642 #undef TARGET_MIN_ANCHOR_OFFSET
5643 #define TARGET_MIN_ANCHOR_OFFSET -32768
5644 #undef TARGET_MAX_ANCHOR_OFFSET
5645 #define TARGET_MAX_ANCHOR_OFFSET 32767
5647 #undef TARGET_LEGITIMATE_CONSTANT_P
5648 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5651 #define TARGET_LRA_P hook_bool_void_false
5653 #undef TARGET_LEGITIMATE_ADDRESS_P
5654 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5656 #undef TARGET_LEGITIMIZE_ADDRESS
5657 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5659 #undef TARGET_DELEGITIMIZE_ADDRESS
5660 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5662 #undef TARGET_INIT_BUILTINS
5663 #define TARGET_INIT_BUILTINS tilegx_init_builtins
5665 #undef TARGET_BUILTIN_DECL
5666 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5668 #undef TARGET_EXPAND_BUILTIN
5669 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5671 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5672 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5674 #undef TARGET_FRAME_POINTER_REQUIRED
5675 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5677 #undef TARGET_DELAY_SCHED2
5678 #define TARGET_DELAY_SCHED2 true
5680 #undef TARGET_DELAY_VARTRACK
5681 #define TARGET_DELAY_VARTRACK true
5683 #undef TARGET_SCHED_ISSUE_RATE
5684 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5686 #undef TARGET_SCHED_ADJUST_COST
5687 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5689 #undef TARGET_MACHINE_DEPENDENT_REORG
5690 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5692 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5693 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5694 hook_bool_const_tree_hwi_hwi_const_tree_true
5696 #undef TARGET_ASM_OUTPUT_MI_THUNK
5697 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5699 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5700 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5702 #undef TARGET_TRAMPOLINE_INIT
5703 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5705 #undef TARGET_PRINT_OPERAND
5706 #define TARGET_PRINT_OPERAND tilegx_print_operand
5708 #undef TARGET_PRINT_OPERAND_ADDRESS
5709 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5711 #undef TARGET_ASM_FILE_END
5712 #define TARGET_ASM_FILE_END tilegx_file_end
5714 #undef TARGET_ASM_ALIGNED_DI_OP
5715 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5717 #undef TARGET_CAN_USE_DOLOOP_P
5718 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
5720 #undef TARGET_TRULY_NOOP_TRUNCATION
5721 #define TARGET_TRULY_NOOP_TRUNCATION tilegx_truly_noop_truncation
5723 #undef TARGET_CONSTANT_ALIGNMENT
5724 #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
5726 struct gcc_target targetm
= TARGET_INITIALIZER
;
5728 #include "gt-tilegx.h"