1 /* Subroutines used for code generation on the Tilera TILE-Gx.
2 Copyright (C) 2011-2016 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/>. */
23 #include "coretypes.h"
31 #include "stringpool.h"
37 #include "diagnostic.h"
39 #include "insn-attr.h"
45 #include "langhooks.h"
47 #include "tm-constrs.h"
49 #include "fold-const.h"
50 #include "stor-layout.h"
52 #include "tilegx-builtins.h"
53 #include "tilegx-multiply.h"
56 /* This file should be included last. */
57 #include "target-def.h"
59 /* SYMBOL_REF for GOT */
60 static GTY(()) rtx g_got_symbol
= NULL
;
62 /* Report whether we're printing out the first address fragment of a
63 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
64 TARGET_PRINT_OPERAND_ADDRESS. */
65 static bool output_memory_autoinc_first
;
71 /* Implement TARGET_OPTION_OVERRIDE. */
73 tilegx_option_override (void)
75 if (global_options_set
.x_tilegx_cmodel
)
77 switch (tilegx_cmodel
)
82 tilegx_cmodel
= CM_SMALL_PIC
;
88 tilegx_cmodel
= CM_LARGE_PIC
;
96 tilegx_cmodel
= flag_pic
? CM_SMALL_PIC
: CM_SMALL
;
98 /* When modulo scheduling is enabled, we still rely on regular
99 scheduler for bundling. */
100 if (flag_modulo_sched
)
101 flag_resched_modulo_sched
= 1;
106 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
108 tilegx_scalar_mode_supported_p (machine_mode mode
)
129 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
131 tilegx_vector_mode_supported_p (machine_mode mode
)
133 return mode
== V8QImode
|| mode
== V4HImode
|| mode
== V2SImode
;
137 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
139 tilegx_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
,
140 rtx x ATTRIBUTE_UNUSED
)
146 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
148 tilegx_function_ok_for_sibcall (tree decl
, tree exp ATTRIBUTE_UNUSED
)
150 return (tilegx_cmodel
!= CM_LARGE
&& tilegx_cmodel
!= CM_LARGE_PIC
155 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
156 passed by reference. */
158 tilegx_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED
,
159 machine_mode mode ATTRIBUTE_UNUSED
,
160 const_tree type
, bool named ATTRIBUTE_UNUSED
)
162 return (type
&& TYPE_SIZE (type
)
163 && TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
);
167 /* Implement TARGET_RETURN_IN_MSB. We return a value in the most
168 significant part of a register if:
169 - the target is big-endian; and
170 - the value has an aggregate type (e.g., structure or union). */
172 tilegx_return_in_msb (const_tree valtype
)
174 return (TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (valtype
));
178 /* Implement TARGET_RETURN_IN_MEMORY. */
180 tilegx_return_in_memory (const_tree type
, const_tree fndecl ATTRIBUTE_UNUSED
)
182 return !IN_RANGE (int_size_in_bytes (type
),
183 0, TILEGX_NUM_RETURN_REGS
* UNITS_PER_WORD
);
187 /* Implement TARGET_MODE_REP_EXTENDED. */
189 tilegx_mode_rep_extended (machine_mode mode
, machine_mode mode_rep
)
191 /* SImode register values are sign-extended to DImode. */
192 if (mode
== SImode
&& mode_rep
== DImode
)
199 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
201 tilegx_function_arg_boundary (machine_mode mode
, const_tree type
)
203 unsigned int alignment
;
205 alignment
= type
? TYPE_ALIGN (type
) : GET_MODE_ALIGNMENT (mode
);
206 if (alignment
< PARM_BOUNDARY
)
207 alignment
= PARM_BOUNDARY
;
208 if (alignment
> STACK_BOUNDARY
)
209 alignment
= STACK_BOUNDARY
;
214 /* Implement TARGET_FUNCTION_ARG. */
216 tilegx_function_arg (cumulative_args_t cum_v
,
218 const_tree type
, bool named ATTRIBUTE_UNUSED
)
220 CUMULATIVE_ARGS cum
= *get_cumulative_args (cum_v
);
221 int byte_size
= ((mode
== BLKmode
)
222 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
223 bool doubleword_aligned_p
;
225 if (cum
>= TILEGX_NUM_ARG_REGS
)
228 /* See whether the argument has doubleword alignment. */
229 doubleword_aligned_p
=
230 tilegx_function_arg_boundary (mode
, type
) > BITS_PER_WORD
;
232 if (doubleword_aligned_p
)
235 /* The ABI does not allow parameters to be passed partially in reg
236 and partially in stack. */
237 if ((cum
+ (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
)
238 > TILEGX_NUM_ARG_REGS
)
241 return gen_rtx_REG (mode
, cum
);
245 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
247 tilegx_function_arg_advance (cumulative_args_t cum_v
,
249 const_tree type
, bool named ATTRIBUTE_UNUSED
)
251 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
253 int byte_size
= ((mode
== BLKmode
)
254 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
255 int word_size
= (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
256 bool doubleword_aligned_p
;
258 /* See whether the argument has doubleword alignment. */
259 doubleword_aligned_p
=
260 tilegx_function_arg_boundary (mode
, type
) > BITS_PER_WORD
;
262 if (doubleword_aligned_p
)
265 /* If the current argument does not fit in the pretend_args space,
267 if (*cum
< TILEGX_NUM_ARG_REGS
268 && *cum
+ word_size
> TILEGX_NUM_ARG_REGS
)
269 *cum
= TILEGX_NUM_ARG_REGS
;
275 /* Implement TARGET_FUNCTION_VALUE. */
277 tilegx_function_value (const_tree valtype
, const_tree fn_decl_or_type
,
278 bool outgoing ATTRIBUTE_UNUSED
)
283 mode
= TYPE_MODE (valtype
);
284 unsigned_p
= TYPE_UNSIGNED (valtype
);
286 mode
= promote_function_mode (valtype
, mode
, &unsigned_p
,
289 return gen_rtx_REG (mode
, 0);
293 /* Implement TARGET_LIBCALL_VALUE. */
295 tilegx_libcall_value (machine_mode mode
,
296 const_rtx fun ATTRIBUTE_UNUSED
)
298 return gen_rtx_REG (mode
, 0);
302 /* Implement FUNCTION_VALUE_REGNO_P. */
304 tilegx_function_value_regno_p (const unsigned int regno
)
306 return regno
< TILEGX_NUM_RETURN_REGS
;
310 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
312 tilegx_build_builtin_va_list (void)
314 tree f_args
, f_skip
, record
, type_decl
;
317 record
= lang_hooks
.types
.make_type (RECORD_TYPE
);
319 type_decl
= build_decl (BUILTINS_LOCATION
, TYPE_DECL
,
320 get_identifier ("__va_list_tag"), record
);
322 f_args
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
323 get_identifier ("__args"), ptr_type_node
);
324 f_skip
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
325 get_identifier ("__skip"), ptr_type_node
);
327 DECL_FIELD_CONTEXT (f_args
) = record
;
329 DECL_FIELD_CONTEXT (f_skip
) = record
;
331 TREE_CHAIN (record
) = type_decl
;
332 TYPE_NAME (record
) = type_decl
;
333 TYPE_FIELDS (record
) = f_args
;
334 TREE_CHAIN (f_args
) = f_skip
;
336 /* We know this is being padded and we want it too. It is an
337 internal type so hide the warnings from the user. */
341 layout_type (record
);
345 /* The correct type is an array type of one element. */
350 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
352 tilegx_va_start (tree valist
, rtx nextarg ATTRIBUTE_UNUSED
)
357 f_args
= TYPE_FIELDS (TREE_TYPE (valist
));
358 f_skip
= TREE_CHAIN (f_args
);
361 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
363 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
365 /* Find the __args area. */
366 t
= make_tree (TREE_TYPE (args
), virtual_incoming_args_rtx
);
367 t
= fold_build_pointer_plus_hwi (t
,
369 (crtl
->args
.info
- TILEGX_NUM_ARG_REGS
));
371 if (crtl
->args
.pretend_args_size
> 0)
372 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
374 t
= build2 (MODIFY_EXPR
, TREE_TYPE (args
), args
, t
);
375 TREE_SIDE_EFFECTS (t
) = 1;
376 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
378 /* Find the __skip area. */
379 t
= make_tree (TREE_TYPE (skip
), virtual_incoming_args_rtx
);
380 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
381 t
= build2 (MODIFY_EXPR
, TREE_TYPE (skip
), skip
, t
);
382 TREE_SIDE_EFFECTS (t
) = 1;
383 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
387 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
389 tilegx_setup_incoming_varargs (cumulative_args_t cum
,
391 tree type
, int *pretend_args
, int no_rtl
)
393 CUMULATIVE_ARGS local_cum
= *get_cumulative_args (cum
);
396 /* The caller has advanced CUM up to, but not beyond, the last named
397 argument. Advance a local copy of CUM past the last "real" named
398 argument, to find out how many registers are left over. */
399 targetm
.calls
.function_arg_advance (pack_cumulative_args (&local_cum
),
401 first_reg
= local_cum
;
403 if (local_cum
< TILEGX_NUM_ARG_REGS
)
405 *pretend_args
= UNITS_PER_WORD
* (TILEGX_NUM_ARG_REGS
- first_reg
);
409 alias_set_type set
= get_varargs_alias_set ();
411 gen_rtx_MEM (BLKmode
, plus_constant (Pmode
,
412 virtual_incoming_args_rtx
,
413 -STACK_POINTER_OFFSET
-
415 (TILEGX_NUM_ARG_REGS
-
417 MEM_NOTRAP_P (tmp
) = 1;
418 set_mem_alias_set (tmp
, set
);
419 move_block_from_reg (first_reg
, tmp
,
420 TILEGX_NUM_ARG_REGS
- first_reg
);
428 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
429 the va_list structure VALIST as required to retrieve an argument of
430 type TYPE, and returning that argument.
432 ret = va_arg(VALIST, TYPE);
434 generates code equivalent to:
436 paddedsize = (sizeof(TYPE) + 7) & -8;
437 if ( (VALIST.__args + paddedsize > VALIST.__skip)
438 & (VALIST.__args <= VALIST.__skip))
439 addr = VALIST.__skip + STACK_POINTER_OFFSET;
441 addr = VALIST.__args;
442 VALIST.__args = addr + paddedsize;
443 if (BYTES_BIG_ENDIAN)
444 ret = *(TYPE *)(addr + paddedsize - sizeof(TYPE));
449 tilegx_gimplify_va_arg_expr (tree valist
, tree type
, gimple_seq
*pre_p
,
450 gimple_seq
*post_p ATTRIBUTE_UNUSED
)
454 HOST_WIDE_INT size
, rsize
;
456 bool pass_by_reference_p
;
458 f_args
= TYPE_FIELDS (va_list_type_node
);
459 f_skip
= TREE_CHAIN (f_args
);
462 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
464 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
466 addr
= create_tmp_var (ptr_type_node
, "va_arg");
468 /* If an object is dynamically sized, a pointer to it is passed
469 instead of the object itself. */
470 pass_by_reference_p
= pass_by_reference (NULL
, TYPE_MODE (type
), type
,
473 if (pass_by_reference_p
)
474 type
= build_pointer_type (type
);
476 size
= int_size_in_bytes (type
);
477 rsize
= ((size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
) * UNITS_PER_WORD
;
479 /* If the alignment of the type is greater than the default for a
480 parameter, align to the STACK_BOUNDARY. */
481 if (TYPE_ALIGN (type
) > PARM_BOUNDARY
)
483 /* Assert the only case we generate code for: when
484 stack boundary = 2 * parm boundary. */
485 gcc_assert (STACK_BOUNDARY
== PARM_BOUNDARY
* 2);
487 tmp
= build2 (BIT_AND_EXPR
, sizetype
,
488 fold_convert (sizetype
, unshare_expr (args
)),
489 size_int (PARM_BOUNDARY
/ 8));
490 tmp
= build2 (POINTER_PLUS_EXPR
, ptr_type_node
,
491 unshare_expr (args
), tmp
);
493 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
496 /* Build conditional expression to calculate addr. The expression
497 will be gimplified later. */
498 tmp
= fold_build_pointer_plus_hwi (unshare_expr (args
), rsize
);
499 tmp
= build2 (TRUTH_AND_EXPR
, boolean_type_node
,
500 build2 (GT_EXPR
, boolean_type_node
, tmp
, unshare_expr (skip
)),
501 build2 (LE_EXPR
, boolean_type_node
, unshare_expr (args
),
502 unshare_expr (skip
)));
504 tmp
= build3 (COND_EXPR
, ptr_type_node
, tmp
,
505 build2 (POINTER_PLUS_EXPR
, ptr_type_node
, unshare_expr (skip
),
506 size_int (STACK_POINTER_OFFSET
)),
507 unshare_expr (args
));
509 /* Adjust the address of va_arg if it is in big endian mode. */
510 if (BYTES_BIG_ENDIAN
&& rsize
> size
)
511 tmp
= fold_build_pointer_plus_hwi (tmp
, rsize
- size
);
512 gimplify_assign (addr
, tmp
, pre_p
);
514 /* Update VALIST.__args. */
516 if (BYTES_BIG_ENDIAN
&& rsize
> size
)
517 tmp
= fold_build_pointer_plus_hwi (addr
, size
);
519 tmp
= fold_build_pointer_plus_hwi (addr
, rsize
);
520 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
522 addr
= fold_convert (build_pointer_type (type
), addr
);
524 if (pass_by_reference_p
)
525 addr
= build_va_arg_indirect_ref (addr
);
527 return build_va_arg_indirect_ref (addr
);
532 /* Implement TARGET_RTX_COSTS. */
534 tilegx_rtx_costs (rtx x
, machine_mode mode
, int outer_code
, int opno
,
535 int *total
, bool speed
)
537 int code
= GET_CODE (x
);
542 /* If this is an 8-bit constant, return zero since it can be
543 used nearly anywhere with no cost. If it is a valid operand
544 for an ADD or AND, likewise return 0 if we know it will be
545 used in that context. Otherwise, return 2 since it might be
546 used there later. All other constants take at least two
548 if (satisfies_constraint_I (x
))
553 else if (outer_code
== PLUS
&& add_operand (x
, VOIDmode
))
555 /* Slightly penalize large constants even though we can add
556 them in one instruction, because it forces the use of
557 2-wide bundling mode. */
561 else if (move_operand (x
, SImode
))
563 /* We can materialize in one move. */
564 *total
= COSTS_N_INSNS (1);
569 /* We can materialize in two moves. */
570 *total
= COSTS_N_INSNS (2);
579 *total
= COSTS_N_INSNS (2);
583 *total
= COSTS_N_INSNS (4);
591 /* If outer-code was a sign or zero extension, a cost of
592 COSTS_N_INSNS (1) was already added in, so account for
594 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
595 *total
= COSTS_N_INSNS (1);
597 *total
= COSTS_N_INSNS (2);
601 /* Convey that shl[123]add are efficient. */
602 if (GET_CODE (XEXP (x
, 0)) == MULT
603 && cint_248_operand (XEXP (XEXP (x
, 0), 1), VOIDmode
))
605 *total
= (rtx_cost (XEXP (XEXP (x
, 0), 0), mode
,
606 (enum rtx_code
) outer_code
, opno
, speed
)
607 + rtx_cost (XEXP (x
, 1), mode
,
608 (enum rtx_code
) outer_code
, opno
, speed
)
609 + COSTS_N_INSNS (1));
615 *total
= COSTS_N_INSNS (2);
622 /* These are handled by software and are very expensive. */
623 *total
= COSTS_N_INSNS (100);
627 case UNSPEC_VOLATILE
:
629 int num
= XINT (x
, 1);
631 if (num
<= TILEGX_LAST_LATENCY_1_INSN
)
632 *total
= COSTS_N_INSNS (1);
633 else if (num
<= TILEGX_LAST_LATENCY_2_INSN
)
634 *total
= COSTS_N_INSNS (2);
635 else if (num
> TILEGX_LAST_LATENCY_INSN
)
637 if (num
== UNSPEC_NON_TEMPORAL
)
639 /* These are basically loads. */
640 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
641 *total
= COSTS_N_INSNS (1);
643 *total
= COSTS_N_INSNS (2);
647 if (outer_code
== PLUS
)
650 *total
= COSTS_N_INSNS (1);
657 case UNSPEC_BLOCKAGE
:
658 case UNSPEC_NETWORK_BARRIER
:
663 case UNSPEC_LNK_AND_LABEL
:
665 case UNSPEC_MOV_PCREL_STEP3
:
666 case UNSPEC_NETWORK_RECEIVE
:
667 case UNSPEC_NETWORK_SEND
:
668 case UNSPEC_SPR_MOVE
:
669 case UNSPEC_TLS_GD_ADD
:
670 *total
= COSTS_N_INSNS (1);
673 case UNSPEC_TLS_IE_LOAD
:
675 *total
= COSTS_N_INSNS (2);
679 *total
= COSTS_N_INSNS (3);
683 *total
= COSTS_N_INSNS (4);
687 case UNSPEC_INSN_CMPEXCH
:
688 case UNSPEC_LATENCY_L2
:
689 *total
= COSTS_N_INSNS (11);
692 case UNSPEC_TLS_GD_CALL
:
693 *total
= COSTS_N_INSNS (30);
696 case UNSPEC_LATENCY_MISS
:
697 *total
= COSTS_N_INSNS (80);
701 *total
= COSTS_N_INSNS (1);
716 /* Create a temporary variable to hold a partial result, to enable
719 create_temp_reg_if_possible (machine_mode mode
, rtx default_reg
)
721 return can_create_pseudo_p () ? gen_reg_rtx (mode
) : default_reg
;
725 /* Functions to save and restore machine-specific function data. */
726 static struct machine_function
*
727 tilegx_init_machine_status (void)
729 return ggc_cleared_alloc
<machine_function
> ();
733 /* Do anything needed before RTL is emitted for each function. */
735 tilegx_init_expanders (void)
737 /* Arrange to initialize and mark the machine per-function
739 init_machine_status
= tilegx_init_machine_status
;
741 if (cfun
&& cfun
->machine
&& flag_pic
)
743 static int label_num
= 0;
745 char text_label_name
[32];
747 struct machine_function
*machine
= cfun
->machine
;
749 ASM_GENERATE_INTERNAL_LABEL (text_label_name
, "L_PICLNK", label_num
++);
751 machine
->text_label_symbol
=
752 gen_rtx_SYMBOL_REF (Pmode
, ggc_strdup (text_label_name
));
754 machine
->text_label_rtx
=
755 gen_rtx_REG (Pmode
, TILEGX_PIC_TEXT_LABEL_REGNUM
);
757 machine
->got_rtx
= gen_rtx_REG (Pmode
, PIC_OFFSET_TABLE_REGNUM
);
759 machine
->calls_tls_get_addr
= false;
764 /* Implement TARGET_EXPAND_TO_RTL_HOOK. */
766 tilegx_expand_to_rtl_hook (void)
768 /* Exclude earlier sets of crtl->uses_pic_offset_table, because we
769 only care about uses actually emitted. */
770 crtl
->uses_pic_offset_table
= 0;
774 /* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode
775 matching insns and therefore guarantee that the shift count is
776 modulo 64. SImode shifts sometimes use the 64 bit version so do
777 not hold such guarantee. */
778 static unsigned HOST_WIDE_INT
779 tilegx_shift_truncation_mask (machine_mode mode
)
781 return mode
== DImode
? 63 : 0;
785 /* Implement TARGET_INIT_LIBFUNCS. */
787 tilegx_init_libfuncs (void)
789 /* We need to explicitly generate these libfunc's to support
790 conversion of divide by constant to multiply (the divide stubs in
791 tilegx.md exist also for this reason). Normally we'd expect gcc
792 to lazily generate them when they are needed, but for some reason
793 it's set up to only generate them if the mode is the word
795 set_optab_libfunc (sdiv_optab
, SImode
, "__divsi3");
796 set_optab_libfunc (udiv_optab
, SImode
, "__udivsi3");
797 set_optab_libfunc (smod_optab
, SImode
, "__modsi3");
798 set_optab_libfunc (umod_optab
, SImode
, "__umodsi3");
802 /* Return true if X contains a thread-local symbol. */
804 tilegx_tls_referenced_p (rtx x
)
806 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == PLUS
)
807 x
= XEXP (XEXP (x
, 0), 0);
809 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
))
812 /* That's all we handle in tilegx_legitimize_tls_address for
818 /* Return true if X requires a scratch register. It is given that
819 flag_pic is on and that X satisfies CONSTANT_P. */
821 tilegx_pic_address_needs_scratch (rtx x
)
823 if (GET_CODE (x
) == CONST
824 && GET_CODE (XEXP (x
, 0)) == PLUS
825 && (GET_CODE (XEXP (XEXP (x
, 0), 0)) == SYMBOL_REF
826 || GET_CODE (XEXP (XEXP (x
, 0), 0)) == LABEL_REF
)
827 && (CONST_INT_P (XEXP (XEXP (x
, 0), 1))))
834 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
835 which we are willing to load the value into a register via a move
836 pattern. TLS cannot be treated as a constant because it can
837 include a function call. */
839 tilegx_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
841 switch (GET_CODE (x
))
845 return !tilegx_tls_referenced_p (x
);
853 /* Return true if the constant value X is a legitimate general operand
854 when generating PIC code. It is given that flag_pic is on and that
855 X satisfies CONSTANT_P. */
857 tilegx_legitimate_pic_operand_p (rtx x
)
859 if (tilegx_pic_address_needs_scratch (x
))
862 if (tilegx_tls_referenced_p (x
))
869 /* Return true if the rtx X can be used as an address operand. */
871 tilegx_legitimate_address_p (machine_mode
ARG_UNUSED (mode
), rtx x
,
874 if (GET_CODE (x
) == SUBREG
)
877 switch (GET_CODE (x
))
881 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
888 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
891 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
894 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
897 if (!satisfies_constraint_I (XEXP (XEXP (x
, 1), 1)))
910 /* Check if x is a valid reg. */
915 return REGNO_OK_FOR_BASE_P (REGNO (x
));
921 /* Return the rtx containing SYMBOL_REF to the text label. */
923 tilegx_text_label_symbol (void)
925 return cfun
->machine
->text_label_symbol
;
929 /* Return the register storing the value of the text label. */
931 tilegx_text_label_rtx (void)
933 return cfun
->machine
->text_label_rtx
;
937 /* Return the register storing the value of the global offset
940 tilegx_got_rtx (void)
942 return cfun
->machine
->got_rtx
;
946 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
948 tilegx_got_symbol (void)
950 if (g_got_symbol
== NULL
)
951 g_got_symbol
= gen_rtx_SYMBOL_REF (Pmode
, "_GLOBAL_OFFSET_TABLE_");
957 /* Return a reference to the got to be used by tls references. */
959 tilegx_tls_got (void)
964 crtl
->uses_pic_offset_table
= 1;
965 return tilegx_got_rtx ();
968 temp
= gen_reg_rtx (Pmode
);
969 emit_move_insn (temp
, tilegx_got_symbol ());
975 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
976 this (thread-local) address. */
978 tilegx_legitimize_tls_address (rtx addr
)
982 gcc_assert (can_create_pseudo_p ());
984 if (GET_CODE (addr
) == SYMBOL_REF
)
985 switch (SYMBOL_REF_TLS_MODEL (addr
))
987 case TLS_MODEL_GLOBAL_DYNAMIC
:
988 case TLS_MODEL_LOCAL_DYNAMIC
:
990 rtx r0
, temp
, temp2
, temp3
, got
, last
;
992 ret
= gen_reg_rtx (Pmode
);
993 r0
= gen_rtx_REG (Pmode
, 0);
994 temp
= gen_reg_rtx (Pmode
);
995 temp2
= gen_reg_rtx (Pmode
);
996 temp3
= gen_reg_rtx (Pmode
);
998 got
= tilegx_tls_got ();
1001 emit_insn (gen_mov_tls_gd_step1_32bit (temp
, addr
));
1002 emit_insn (gen_mov_tls_gd_step2_32bit (temp2
, temp
, addr
));
1003 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
1007 emit_insn (gen_mov_tls_gd_step1 (temp
, addr
));
1008 emit_insn (gen_mov_tls_gd_step2 (temp2
, temp
, addr
));
1009 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
1012 emit_move_insn (r0
, temp2
);
1016 emit_insn (gen_tls_gd_call_32bit (addr
));
1020 emit_insn (gen_tls_gd_call (addr
));
1023 emit_move_insn (temp3
, r0
);
1026 last
= emit_insn (gen_tls_gd_add_32bit (ret
, temp3
, addr
));
1028 last
= emit_insn (gen_tls_gd_add (ret
, temp3
, addr
));
1030 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1033 case TLS_MODEL_INITIAL_EXEC
:
1035 rtx temp
, temp2
, temp3
, got
;
1038 ret
= gen_reg_rtx (Pmode
);
1039 temp
= gen_reg_rtx (Pmode
);
1040 temp2
= gen_reg_rtx (Pmode
);
1041 temp3
= gen_reg_rtx (Pmode
);
1043 got
= tilegx_tls_got ();
1046 emit_insn (gen_mov_tls_ie_step1_32bit (temp
, addr
));
1047 emit_insn (gen_mov_tls_ie_step2_32bit (temp2
, temp
, addr
));
1048 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
1049 emit_insn (gen_tls_ie_load_32bit (temp3
, temp2
, addr
));
1053 emit_insn (gen_mov_tls_ie_step1 (temp
, addr
));
1054 emit_insn (gen_mov_tls_ie_step2 (temp2
, temp
, addr
));
1055 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
1056 emit_insn (gen_tls_ie_load (temp3
, temp2
, addr
));
1061 gen_rtx_PLUS (Pmode
,
1063 THREAD_POINTER_REGNUM
),
1065 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1068 case TLS_MODEL_LOCAL_EXEC
:
1073 ret
= gen_reg_rtx (Pmode
);
1074 temp
= gen_reg_rtx (Pmode
);
1075 temp2
= gen_reg_rtx (Pmode
);
1079 emit_insn (gen_mov_tls_le_step1_32bit (temp
, addr
));
1080 emit_insn (gen_mov_tls_le_step2_32bit (temp2
, temp
, addr
));
1084 emit_insn (gen_mov_tls_le_step1 (temp
, addr
));
1085 emit_insn (gen_mov_tls_le_step2 (temp2
, temp
, addr
));
1089 emit_move_insn (ret
,
1090 gen_rtx_PLUS (Pmode
,
1092 THREAD_POINTER_REGNUM
),
1094 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1100 else if (GET_CODE (addr
) == CONST
)
1104 gcc_assert (GET_CODE (XEXP (addr
, 0)) == PLUS
);
1106 base
= tilegx_legitimize_tls_address (XEXP (XEXP (addr
, 0), 0));
1107 offset
= XEXP (XEXP (addr
, 0), 1);
1109 base
= force_operand (base
, NULL_RTX
);
1110 ret
= force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1119 /* Returns a register that points to ADDR, a symbolic address, by
1120 computing its address relative to tilegx_text_label_symbol. */
1122 tilegx_compute_pcrel_address (rtx result
, rtx addr
)
1124 rtx text_label_symbol
= tilegx_text_label_symbol ();
1125 rtx text_label_rtx
= tilegx_text_label_rtx ();
1126 rtx temp
, temp2
, temp3
;
1128 temp
= create_temp_reg_if_possible (Pmode
, result
);
1129 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1133 emit_insn (gen_mov_pcrel_step1_32bit (temp
, addr
, text_label_symbol
));
1134 emit_insn (gen_mov_pcrel_step2_32bit (temp2
, temp
, addr
,
1135 text_label_symbol
));
1136 emit_insn (gen_mov_pcrel_step3_32bit (result
, temp2
,
1138 addr
, text_label_symbol
));
1140 else if (tilegx_cmodel
== CM_LARGE_PIC
)
1142 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1143 emit_insn (gen_mov_large_pcrel_step1 (temp
, addr
, text_label_symbol
));
1144 emit_insn (gen_mov_large_pcrel_step2 (temp2
, temp
, addr
,
1145 text_label_symbol
));
1146 emit_insn (gen_mov_large_pcrel_step3 (temp3
, temp2
, addr
,
1147 text_label_symbol
));
1148 emit_insn (gen_mov_large_pcrel_step4 (result
, temp3
,
1150 addr
, text_label_symbol
));
1154 emit_insn (gen_mov_pcrel_step1 (temp
, addr
, text_label_symbol
));
1155 emit_insn (gen_mov_pcrel_step2 (temp2
, temp
, addr
, text_label_symbol
));
1156 emit_insn (gen_mov_pcrel_step3 (result
, temp2
,
1158 addr
, text_label_symbol
));
1163 /* Returns a register that points to the plt entry of ADDR, a symbolic
1164 address, by computing its address relative to
1165 tilegx_text_label_symbol. */
1167 tilegx_compute_pcrel_plt_address (rtx result
, rtx addr
)
1169 rtx text_label_symbol
= tilegx_text_label_symbol ();
1170 rtx text_label_rtx
= tilegx_text_label_rtx ();
1171 rtx temp
, temp2
, temp3
;
1173 temp
= create_temp_reg_if_possible (Pmode
, result
);
1174 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1178 emit_insn (gen_mov_plt_pcrel_step1_32bit (temp
, addr
,
1179 text_label_symbol
));
1180 emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2
, temp
, addr
,
1181 text_label_symbol
));
1182 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp2
, text_label_rtx
));
1186 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1188 emit_insn (gen_mov_plt_pcrel_step1 (temp
, addr
, text_label_symbol
));
1189 emit_insn (gen_mov_plt_pcrel_step2 (temp2
, temp
, addr
,
1190 text_label_symbol
));
1191 emit_insn (gen_mov_plt_pcrel_step3 (temp3
, temp2
, addr
,
1192 text_label_symbol
));
1193 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp3
, text_label_rtx
));
1198 /* Legitimize PIC addresses. If the address is already
1199 position-independent, we return ORIG. Newly generated
1200 position-independent addresses go into a reg. This is REG if
1201 nonzero, otherwise we allocate register(s) as necessary. */
1203 tilegx_legitimize_pic_address (rtx orig
,
1204 machine_mode mode ATTRIBUTE_UNUSED
,
1207 if (GET_CODE (orig
) == SYMBOL_REF
)
1209 rtx address
, pic_ref
;
1213 gcc_assert (can_create_pseudo_p ());
1214 reg
= gen_reg_rtx (Pmode
);
1217 if (SYMBOL_REF_LOCAL_P (orig
))
1219 /* If not during reload, allocate another temp reg here for
1220 loading in the address, so that these instructions can be
1221 optimized properly. */
1222 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1223 tilegx_compute_pcrel_address (temp_reg
, orig
);
1225 /* Note: this is conservative. We use the text_label but we
1226 don't use the pic_offset_table. However, in some cases
1227 we may need the pic_offset_table (see
1228 tilegx_fixup_pcrel_references). */
1229 crtl
->uses_pic_offset_table
= 1;
1233 emit_move_insn (reg
, address
);
1238 /* If not during reload, allocate another temp reg here for
1239 loading in the address, so that these instructions can be
1240 optimized properly. */
1241 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1243 gcc_assert (flag_pic
);
1248 emit_insn (gen_add_got16_32bit (temp_reg
,
1254 emit_insn (gen_add_got16 (temp_reg
,
1255 tilegx_got_rtx (), orig
));
1260 rtx temp_reg2
= create_temp_reg_if_possible (Pmode
, reg
);
1261 rtx temp_reg3
= create_temp_reg_if_possible (Pmode
, reg
);
1264 emit_insn (gen_mov_got32_step1_32bit (temp_reg3
, orig
));
1265 emit_insn (gen_mov_got32_step2_32bit
1266 (temp_reg2
, temp_reg3
, orig
));
1270 emit_insn (gen_mov_got32_step1 (temp_reg3
, orig
));
1271 emit_insn (gen_mov_got32_step2 (temp_reg2
, temp_reg3
,
1274 emit_move_insn (temp_reg
,
1275 gen_rtx_PLUS (Pmode
,
1276 tilegx_got_rtx (), temp_reg2
));
1281 pic_ref
= gen_const_mem (Pmode
, address
);
1282 crtl
->uses_pic_offset_table
= 1;
1283 emit_move_insn (reg
, pic_ref
);
1284 /* The following put a REG_EQUAL note on this insn, so that
1285 it can be optimized by loop. But it causes the label to
1286 be optimized away. */
1287 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1291 else if (GET_CODE (orig
) == CONST
)
1295 if (GET_CODE (XEXP (orig
, 0)) == PLUS
1296 && XEXP (XEXP (orig
, 0), 0) == tilegx_got_rtx ())
1301 gcc_assert (can_create_pseudo_p ());
1302 reg
= gen_reg_rtx (Pmode
);
1305 gcc_assert (GET_CODE (XEXP (orig
, 0)) == PLUS
);
1306 base
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 0),
1308 offset
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 1), Pmode
,
1309 base
== reg
? 0 : reg
);
1311 if (CONST_INT_P (offset
))
1313 if (can_create_pseudo_p ())
1314 offset
= force_reg (Pmode
, offset
);
1316 /* If we reach here, then something is seriously wrong. */
1320 if (can_create_pseudo_p ())
1321 return force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1325 else if (GET_CODE (orig
) == LABEL_REF
)
1332 gcc_assert (can_create_pseudo_p ());
1333 reg
= gen_reg_rtx (Pmode
);
1336 /* If not during reload, allocate another temp reg here for
1337 loading in the address, so that these instructions can be
1338 optimized properly. */
1339 temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1340 tilegx_compute_pcrel_address (temp_reg
, orig
);
1342 /* Note: this is conservative. We use the text_label but we
1343 don't use the pic_offset_table. */
1344 crtl
->uses_pic_offset_table
= 1;
1348 emit_move_insn (reg
, address
);
1357 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1359 tilegx_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
1362 if (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
1363 && symbolic_operand (x
, Pmode
) && tilegx_tls_referenced_p (x
))
1365 return tilegx_legitimize_tls_address (x
);
1369 return tilegx_legitimize_pic_address (x
, mode
, 0);
1376 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1378 tilegx_delegitimize_address (rtx x
)
1380 x
= delegitimize_mem_from_attrs (x
);
1382 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == UNSPEC
)
1384 switch (XINT (XEXP (x
, 0), 1))
1390 case UNSPEC_HW0_LAST
:
1391 case UNSPEC_HW1_LAST
:
1392 case UNSPEC_HW2_LAST
:
1393 case UNSPEC_HW0_PCREL
:
1394 case UNSPEC_HW1_PCREL
:
1395 case UNSPEC_HW1_LAST_PCREL
:
1396 case UNSPEC_HW2_LAST_PCREL
:
1397 case UNSPEC_HW0_PLT_PCREL
:
1398 case UNSPEC_HW1_PLT_PCREL
:
1399 case UNSPEC_HW1_LAST_PLT_PCREL
:
1400 case UNSPEC_HW2_LAST_PLT_PCREL
:
1401 case UNSPEC_HW0_GOT
:
1402 case UNSPEC_HW0_LAST_GOT
:
1403 case UNSPEC_HW1_LAST_GOT
:
1404 case UNSPEC_HW0_TLS_GD
:
1405 case UNSPEC_HW1_LAST_TLS_GD
:
1406 case UNSPEC_HW0_TLS_IE
:
1407 case UNSPEC_HW1_LAST_TLS_IE
:
1408 case UNSPEC_HW0_TLS_LE
:
1409 case UNSPEC_HW1_LAST_TLS_LE
:
1410 x
= XVECEXP (XEXP (x
, 0), 0, 0);
1419 /* Emit code to load the PIC register. */
1421 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED
)
1423 int orig_flag_pic
= flag_pic
;
1425 rtx got_symbol
= tilegx_got_symbol ();
1426 rtx text_label_symbol
= tilegx_text_label_symbol ();
1427 rtx text_label_rtx
= tilegx_text_label_rtx ();
1432 emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx
,
1433 text_label_symbol
));
1437 emit_insn (gen_insn_lnk_and_label (text_label_rtx
, text_label_symbol
));
1440 tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol
);
1442 flag_pic
= orig_flag_pic
;
1444 /* Need to emit this whether or not we obey regdecls, since
1445 setjmp/longjmp can cause life info to screw up. ??? In the case
1446 where we don't obey regdecls, this is not sufficient since we may
1447 not fall out the bottom. */
1448 emit_use (tilegx_got_rtx ());
1452 /* Return the simd variant of the constant NUM of mode MODE, by
1453 replicating it to fill an interger of mode DImode. NUM is first
1454 truncated to fit in MODE. */
1456 tilegx_simd_int (rtx num
, machine_mode mode
)
1458 HOST_WIDE_INT n
= 0;
1460 gcc_assert (CONST_INT_P (num
));
1467 n
= 0x0101010101010101LL
* (n
& 0x000000FF);
1470 n
= 0x0001000100010001LL
* (n
& 0x0000FFFF);
1473 n
= 0x0000000100000001LL
* (n
& 0xFFFFFFFF);
1485 /* Returns true iff VAL can be moved into a register in one
1486 instruction. And if it can, it emits the code to move the constant
1489 If THREE_WIDE_ONLY is true, this insists on an instruction that
1490 works in a bundle containing three instructions. */
1492 expand_set_cint64_one_inst (rtx dest_reg
,
1493 HOST_WIDE_INT val
, bool three_wide_only
)
1495 if (val
== trunc_int_for_mode (val
, QImode
))
1498 emit_move_insn (dest_reg
, GEN_INT (val
));
1501 else if (!three_wide_only
)
1503 /* Test for the following constraints: J, K, N, P. We avoid
1504 generating an rtx and using existing predicates because we
1505 can be testing and rejecting a lot of constants, and GEN_INT
1507 if ((val
>= -32768 && val
<= 65535)
1508 || ((val
== (val
& 0xFF) * 0x0101010101010101LL
))
1509 || (val
== ((trunc_int_for_mode (val
, QImode
) & 0xFFFF)
1510 * 0x0001000100010001LL
)))
1512 emit_move_insn (dest_reg
, GEN_INT (val
));
1521 /* Implement DImode rotatert. */
1522 static HOST_WIDE_INT
1523 rotate_right (HOST_WIDE_INT n
, int count
)
1525 unsigned HOST_WIDE_INT x
= n
& 0xFFFFFFFFFFFFFFFFULL
;
1528 return ((x
>> count
) | (x
<< (64 - count
))) & 0xFFFFFFFFFFFFFFFFULL
;
1532 /* Return true iff n contains exactly one contiguous sequence of 1
1533 bits, possibly wrapping around from high bits to low bits. */
1535 tilegx_bitfield_operand_p (HOST_WIDE_INT n
, int *first_bit
, int *last_bit
)
1542 for (i
= 0; i
< 64; i
++)
1544 unsigned HOST_WIDE_INT x
= rotate_right (n
, i
);
1548 /* See if x is a power of two minus one, i.e. only consecutive 1
1549 bits starting from bit 0. */
1550 if ((x
& (x
+ 1)) == 0)
1552 if (first_bit
!= NULL
)
1554 if (last_bit
!= NULL
)
1555 *last_bit
= (i
+ exact_log2 (x
^ (x
>> 1))) & 63;
1565 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1567 expand_set_cint64 (rtx dest_reg
, rtx src_val
)
1570 int leading_zeroes
, trailing_zeroes
;
1571 int three_wide_only
;
1572 int shift
, ins_shift
, zero_cluster_shift
;
1575 gcc_assert (CONST_INT_P (src_val
));
1576 val
= trunc_int_for_mode (INTVAL (src_val
), GET_MODE (dest_reg
));
1578 /* See if we can generate the constant in one instruction. */
1579 if (expand_set_cint64_one_inst (dest_reg
, val
, false))
1582 /* Force the destination to DImode so we can use DImode instructions
1583 to create it. This both allows instructions like rotl, and
1584 certain efficient 3-wide instructions. */
1585 subreg
= simplify_gen_subreg (DImode
, dest_reg
, GET_MODE (dest_reg
), 0);
1586 gcc_assert (subreg
!= NULL
);
1589 temp
= create_temp_reg_if_possible (DImode
, dest_reg
);
1591 leading_zeroes
= 63 - floor_log2 (val
& 0xFFFFFFFFFFFFFFFFULL
);
1592 trailing_zeroes
= exact_log2 (val
& -val
);
1594 /* First try all three-wide instructions that generate a constant
1595 (i.e. movei) followed by various shifts and rotates. If none of
1596 those work, try various two-wide ways of generating a constant
1597 followed by various shifts and rotates. */
1598 for (three_wide_only
= 1; three_wide_only
>= 0; three_wide_only
--)
1602 if (expand_set_cint64_one_inst (temp
, val
>> trailing_zeroes
,
1605 /* 0xFFFFFFFFFFFFA500 becomes:
1606 movei temp, 0xFFFFFFFFFFFFFFA5
1607 shli dest, temp, 8 */
1608 emit_move_insn (dest_reg
,
1609 gen_rtx_ASHIFT (DImode
, temp
,
1610 GEN_INT (trailing_zeroes
)));
1614 if (expand_set_cint64_one_inst (temp
, val
<< leading_zeroes
,
1617 /* 0x7FFFFFFFFFFFFFFF becomes:
1619 shrui dest, temp, 1 */
1620 emit_move_insn (dest_reg
,
1621 gen_rtx_LSHIFTRT (DImode
, temp
,
1622 GEN_INT (leading_zeroes
)));
1626 /* Try rotating a one-instruction immediate. */
1627 for (count
= 1; count
< 64; count
++)
1629 HOST_WIDE_INT r
= rotate_right (val
, count
);
1630 if (expand_set_cint64_one_inst (temp
, r
, three_wide_only
))
1632 /* 0xFFFFFFFFFFA5FFFF becomes:
1633 movei temp, 0xFFFFFFFFFFFFFFA5
1634 rotli dest, temp, 16 */
1635 emit_move_insn (dest_reg
,
1636 gen_rtx_ROTATE (DImode
, temp
, GEN_INT (count
)));
1642 /* There are two cases here to produce a large constant.
1643 In the most general case, we do this:
1646 shl16insli x, x, hw2(NUM)
1647 shl16insli x, x, hw1(NUM)
1648 shl16insli x, x, hw0(NUM)
1650 However, we can sometimes do better. shl16insli is a poor way to
1651 insert 16 zero bits, because simply shifting left by 16 has more
1652 bundling freedom. So if we see any contiguous aligned sequence
1653 of 16 or more zero bits (below the highest set bit), it is always
1654 more efficient to materialize the bits above the zero bits, then
1655 left shift to put in the zeroes, then insert whatever bits
1656 remain. For example, we might end up with:
1658 movei x, NUM >> (37 + 16)
1660 shl16insli x, x, hw0(NUM) */
1662 zero_cluster_shift
= -1;
1664 for (shift
= 0; shift
< 48 - leading_zeroes
; shift
+= 16)
1666 HOST_WIDE_INT x
= val
>> shift
;
1668 /* Find the least significant group of 16 aligned zero bits. */
1669 if ((x
& 0xFFFF) == 0x0000)
1671 /* Grab any following zero bits as well. */
1672 zero_cluster_shift
= exact_log2 (x
& -x
);
1673 shift
+= zero_cluster_shift
;
1678 if (zero_cluster_shift
>= 0)
1680 unsigned HOST_WIDE_INT leftover
;
1682 /* Recursively create the constant above the lowest 16 zero
1684 expand_set_cint64 (temp
, GEN_INT (val
>> shift
));
1686 /* See if we can easily insert the remaining bits, or if we need
1687 to fall through to the more general case. */
1688 leftover
= val
- ((val
>> shift
) << shift
);
1691 /* A simple left shift is enough. */
1692 emit_move_insn (dest_reg
,
1693 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1696 else if (leftover
<= 32767)
1698 /* Left shift into position then add in the leftover. */
1699 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1700 emit_move_insn (temp2
,
1701 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1702 emit_move_insn (dest_reg
,
1703 gen_rtx_PLUS (DImode
, temp2
, GEN_INT (leftover
)));
1708 /* Shift in the batch of >= 16 zeroes we detected earlier.
1709 After this, shift will be aligned mod 16 so the final
1710 loop can use shl16insli. */
1711 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1712 rtx shift_count_rtx
= GEN_INT (zero_cluster_shift
);
1714 emit_move_insn (temp2
,
1715 gen_rtx_ASHIFT (DImode
, temp
, shift_count_rtx
));
1717 shift
-= zero_cluster_shift
;
1723 /* Set as many high 16-bit blocks as we can with a single
1724 instruction. We'll insert the remaining 16-bit blocks
1726 for (shift
= 16;; shift
+= 16)
1728 gcc_assert (shift
< 64);
1729 if (expand_set_cint64_one_inst (temp
, val
>> shift
, false))
1734 /* At this point, temp == val >> shift, shift % 16 == 0, and we
1735 still need to insert any bits of 'val' below 'shift'. Those bits
1736 are guaranteed to not have 16 contiguous zeroes. */
1738 gcc_assert ((shift
& 15) == 0);
1740 for (ins_shift
= shift
- 16; ins_shift
>= 0; ins_shift
-= 16)
1743 HOST_WIDE_INT bits
= (val
>> ins_shift
) & 0xFFFF;
1744 gcc_assert (bits
!= 0);
1746 /* On the last iteration we need to store into dest_reg. */
1750 result
= create_temp_reg_if_possible (DImode
, dest_reg
);
1752 emit_insn (gen_insn_shl16insli (result
, temp
, GEN_INT (bits
)));
1759 /* Load OP1, a 64-bit constant, into OP0, a register. We know it
1760 can't be done in one insn when we get here, the move expander
1763 tilegx_expand_set_const64 (rtx op0
, rtx op1
)
1765 if (CONST_INT_P (op1
))
1767 /* TODO: I don't know if we want to split large constants
1768 now, or wait until later (with a define_split).
1770 Does splitting early help CSE? Does it harm other
1771 optimizations that might fold loads? */
1772 expand_set_cint64 (op0
, op1
);
1776 rtx temp
= create_temp_reg_if_possible (Pmode
, op0
);
1780 /* Generate the 2-insn sequence to materialize a symbolic
1782 emit_insn (gen_mov_address_32bit_step1 (temp
, op1
));
1783 emit_insn (gen_mov_address_32bit_step2 (op0
, temp
, op1
));
1787 /* Generate the 3-insn sequence to materialize a symbolic
1788 address. Note that this assumes that virtual addresses
1789 fit in 48 signed bits, which is currently true. */
1790 rtx temp2
= create_temp_reg_if_possible (Pmode
, op0
);
1791 emit_insn (gen_mov_address_step1 (temp
, op1
));
1792 emit_insn (gen_mov_address_step2 (temp2
, temp
, op1
));
1793 emit_insn (gen_mov_address_step3 (op0
, temp2
, op1
));
1799 /* Expand a move instruction. Return true if all work is done. */
1801 tilegx_expand_mov (machine_mode mode
, rtx
*operands
)
1803 /* Handle sets of MEM first. */
1804 if (MEM_P (operands
[0]))
1806 if (can_create_pseudo_p ())
1807 operands
[0] = validize_mem (operands
[0]);
1809 if (reg_or_0_operand (operands
[1], mode
))
1812 if (!reload_in_progress
)
1813 operands
[1] = force_reg (mode
, operands
[1]);
1816 /* Fixup TLS cases. */
1817 if (CONSTANT_P (operands
[1]) && tilegx_tls_referenced_p (operands
[1]))
1819 operands
[1] = tilegx_legitimize_tls_address (operands
[1]);
1823 /* Fixup PIC cases. */
1824 if (flag_pic
&& CONSTANT_P (operands
[1]))
1826 if (tilegx_pic_address_needs_scratch (operands
[1]))
1827 operands
[1] = tilegx_legitimize_pic_address (operands
[1], mode
, 0);
1829 if (symbolic_operand (operands
[1], mode
))
1831 operands
[1] = tilegx_legitimize_pic_address (operands
[1],
1833 (reload_in_progress
?
1840 /* Accept non-constants and valid constants unmodified. */
1841 if (!CONSTANT_P (operands
[1]) || move_operand (operands
[1], mode
))
1844 /* Split large integers. */
1845 tilegx_expand_set_const64 (operands
[0], operands
[1]);
1850 /* Expand unaligned loads. */
1852 tilegx_expand_unaligned_load (rtx dest_reg
, rtx mem
, HOST_WIDE_INT bitsize
,
1853 HOST_WIDE_INT bit_offset
, bool sign
)
1856 rtx addr_lo
, addr_hi
;
1857 rtx mem_lo
, mem_hi
, hi
;
1858 rtx mema
, wide_result
;
1859 int last_byte_offset
;
1860 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1862 mode
= GET_MODE (dest_reg
);
1864 if (bitsize
== 2 * BITS_PER_UNIT
&& (bit_offset
% BITS_PER_UNIT
) == 0)
1866 rtx mem_left
, mem_right
;
1867 rtx left
= gen_reg_rtx (mode
);
1869 /* When just loading a two byte value, we can load the two bytes
1870 individually and combine them efficiently. */
1872 mem_lo
= adjust_address (mem
, QImode
, byte_offset
);
1873 mem_hi
= adjust_address (mem
, QImode
, byte_offset
+ 1);
1875 if (BYTES_BIG_ENDIAN
)
1888 /* Do a signed load of the second byte and use bfins to set
1889 the high bits of the result. */
1890 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, dest_reg
),
1892 emit_insn (gen_extendqidi2 (gen_lowpart (DImode
, left
), mem_left
));
1893 emit_insn (gen_insv (gen_lowpart (DImode
, dest_reg
),
1894 GEN_INT (64 - 8), GEN_INT (8),
1895 gen_lowpart (DImode
, left
)));
1899 /* Do two unsigned loads and use v1int_l to interleave
1901 rtx right
= gen_reg_rtx (mode
);
1902 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, right
),
1904 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, left
),
1906 emit_insn (gen_insn_v1int_l (gen_lowpart (DImode
, dest_reg
),
1907 gen_lowpart (DImode
, left
),
1908 gen_lowpart (DImode
, right
)));
1914 mema
= XEXP (mem
, 0);
1916 /* AND addresses cannot be in any alias set, since they may
1917 implicitly alias surrounding code. Ideally we'd have some alias
1918 set that covered all types except those with alignment 8 or
1920 addr_lo
= force_reg (Pmode
, plus_constant (Pmode
, mema
, byte_offset
));
1921 mem_lo
= change_address (mem
, mode
,
1922 gen_rtx_AND (GET_MODE (mema
), addr_lo
,
1924 set_mem_alias_set (mem_lo
, 0);
1926 /* Load the high word at an address that will not fault if the low
1927 address is aligned and at the very end of a page. */
1928 last_byte_offset
= (bit_offset
+ bitsize
- 1) / BITS_PER_UNIT
;
1929 addr_hi
= force_reg (Pmode
, plus_constant (Pmode
, mema
, last_byte_offset
));
1930 mem_hi
= change_address (mem
, mode
,
1931 gen_rtx_AND (GET_MODE (mema
), addr_hi
,
1933 set_mem_alias_set (mem_hi
, 0);
1937 addr_lo
= make_safe_from (addr_lo
, dest_reg
);
1938 wide_result
= dest_reg
;
1942 wide_result
= gen_reg_rtx (mode
);
1945 /* Load hi first in case dest_reg is used in mema. */
1946 hi
= gen_reg_rtx (mode
);
1947 emit_move_insn (hi
, mem_hi
);
1948 emit_move_insn (wide_result
, mem_lo
);
1950 emit_insn (gen_insn_dblalign (gen_lowpart (DImode
, wide_result
),
1951 gen_lowpart (DImode
, wide_result
),
1952 gen_lowpart (DImode
, hi
), addr_lo
));
1957 extract_bit_field (gen_lowpart (DImode
, wide_result
),
1958 bitsize
, bit_offset
% BITS_PER_UNIT
,
1959 !sign
, gen_lowpart (DImode
, dest_reg
),
1960 DImode
, DImode
, false);
1962 if (extracted
!= dest_reg
)
1963 emit_move_insn (dest_reg
, gen_lowpart (DImode
, extracted
));
1968 /* Expand unaligned stores. */
1970 tilegx_expand_unaligned_store (rtx mem
, rtx src
, HOST_WIDE_INT bitsize
,
1971 HOST_WIDE_INT bit_offset
)
1973 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1974 HOST_WIDE_INT bytesize
= bitsize
/ BITS_PER_UNIT
;
1975 HOST_WIDE_INT shift_init
, shift_increment
, shift_amt
;
1980 shift_init
= BYTES_BIG_ENDIAN
? (bitsize
- BITS_PER_UNIT
) : 0;
1981 shift_increment
= BYTES_BIG_ENDIAN
? -BITS_PER_UNIT
: BITS_PER_UNIT
;
1983 for (i
= 0, shift_amt
= shift_init
;
1985 i
++, shift_amt
+= shift_increment
)
1987 mem_addr
= adjust_address (mem
, QImode
, byte_offset
+ i
);
1991 store_val
= expand_simple_binop (DImode
, LSHIFTRT
,
1992 gen_lowpart (DImode
, src
),
1993 GEN_INT (shift_amt
), NULL
, 1,
1995 store_val
= gen_lowpart (QImode
, store_val
);
1999 store_val
= gen_lowpart (QImode
, src
);
2002 emit_move_insn (mem_addr
, store_val
);
2007 /* Implement the movmisalign patterns. One of the operands is a
2008 memory that is not naturally aligned. Emit instructions to load
2011 tilegx_expand_movmisalign (machine_mode mode
, rtx
*operands
)
2013 if (MEM_P (operands
[1]))
2017 if (register_operand (operands
[0], mode
))
2020 tmp
= gen_reg_rtx (mode
);
2022 tilegx_expand_unaligned_load (tmp
, operands
[1], GET_MODE_BITSIZE (mode
),
2025 if (tmp
!= operands
[0])
2026 emit_move_insn (operands
[0], tmp
);
2028 else if (MEM_P (operands
[0]))
2030 if (!reg_or_0_operand (operands
[1], mode
))
2031 operands
[1] = force_reg (mode
, operands
[1]);
2033 tilegx_expand_unaligned_store (operands
[0], operands
[1],
2034 GET_MODE_BITSIZE (mode
), 0);
2042 /* Implement the allocate_stack pattern (alloca). */
2044 tilegx_allocate_stack (rtx op0
, rtx op1
)
2046 /* Technically the correct way to initialize chain_loc is with
2047 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
2048 * sets the alias_set to that of a frame reference. Some of our
2049 * tests rely on some unsafe assumption about when the chaining
2050 * update is done, we need to be conservative about reordering the
2051 * chaining instructions.
2053 rtx fp_addr
= gen_reg_rtx (Pmode
);
2054 rtx fp_value
= gen_reg_rtx (Pmode
);
2057 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2058 GEN_INT (UNITS_PER_WORD
)));
2060 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
2062 emit_move_insn (fp_value
, fp_loc
);
2064 op1
= force_reg (Pmode
, op1
);
2066 emit_move_insn (stack_pointer_rtx
,
2067 gen_rtx_MINUS (Pmode
, stack_pointer_rtx
, op1
));
2069 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2070 GEN_INT (UNITS_PER_WORD
)));
2072 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
2074 emit_move_insn (fp_loc
, fp_value
);
2076 emit_move_insn (op0
, virtual_stack_dynamic_rtx
);
2084 /* Returns the insn_code in ENTRY. */
2085 static enum insn_code
2086 tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry
2089 return tilegx_multiply_insn_seq_decode_opcode
[entry
->compressed_opcode
];
2093 /* Returns the length of the 'op' array. */
2095 tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq
*seq
)
2097 /* The array either uses all of its allocated slots or is terminated
2098 by a bogus opcode. Either way, the array size is the index of the
2099 last valid opcode plus one. */
2101 for (i
= tilegx_multiply_insn_seq_MAX_OPERATIONS
- 1; i
>= 0; i
--)
2102 if (tilegx_multiply_get_opcode (&seq
->op
[i
]) != CODE_FOR_nothing
)
2105 /* An empty array is not allowed. */
2110 /* We precompute a number of expression trees for multiplying by
2111 constants. This generates code for such an expression tree by
2112 walking through the nodes in the tree (which are conveniently
2113 pre-linearized) and emitting an instruction for each one. */
2115 tilegx_expand_constant_multiply_given_sequence (rtx result
, rtx src
,
2117 tilegx_multiply_insn_seq
*seq
)
2122 /* Keep track of the subexpressions computed so far, so later
2123 instructions can refer to them. We seed the array with zero and
2124 the value being multiplied. */
2125 int num_subexprs
= 2;
2126 rtx subexprs
[tilegx_multiply_insn_seq_MAX_OPERATIONS
+ 2];
2127 subexprs
[0] = const0_rtx
;
2130 /* Determine how many instructions we are going to generate. */
2131 num_ops
= tilegx_multiply_get_num_ops (seq
);
2132 gcc_assert (num_ops
> 0
2133 && num_ops
<= tilegx_multiply_insn_seq_MAX_OPERATIONS
);
2135 for (i
= 0; i
< num_ops
; i
++)
2137 const struct tilegx_multiply_insn_seq_entry
*entry
= &seq
->op
[i
];
2139 /* Figure out where to store the output of this instruction. */
2140 const bool is_last_op
= (i
+ 1 == num_ops
);
2141 rtx out
= is_last_op
? result
: gen_reg_rtx (DImode
);
2143 enum insn_code opcode
= tilegx_multiply_get_opcode (entry
);
2144 if (opcode
== CODE_FOR_ashldi3
)
2146 /* Handle shift by immediate. This is a special case because
2147 the meaning of the second operand is a constant shift
2148 count rather than an operand index. */
2150 /* Make sure the shift count is in range. Zero should not
2152 const int shift_count
= entry
->rhs
;
2153 gcc_assert (shift_count
> 0 && shift_count
< 64);
2155 /* Emit the actual instruction. */
2156 emit_insn (GEN_FCN (opcode
)
2157 (out
, subexprs
[entry
->lhs
],
2158 gen_rtx_CONST_INT (DImode
, shift_count
)));
2162 /* Handle a normal two-operand instruction, such as add or
2165 /* Make sure we are referring to a previously computed
2167 gcc_assert (entry
->rhs
< num_subexprs
);
2169 /* Emit the actual instruction. */
2170 emit_insn (GEN_FCN (opcode
)
2171 (out
, subexprs
[entry
->lhs
], subexprs
[entry
->rhs
]));
2174 /* Record this subexpression for use by later expressions. */
2175 subexprs
[num_subexprs
++] = out
;
2180 /* bsearch helper function. */
2182 tilegx_compare_multipliers (const void *key
, const void *t
)
2185 (*(const long long *) key
2186 - ((const struct tilegx_multiply_insn_seq
*) t
)->multiplier
);
2187 return (delta
< 0) ? -1 : (delta
> 0);
2191 /* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none
2193 static const struct tilegx_multiply_insn_seq
*
2194 tilegx_find_multiply_insn_seq_for_constant (long long multiplier
)
2196 return ((const struct tilegx_multiply_insn_seq
*)
2197 bsearch (&multiplier
, tilegx_multiply_insn_seq_table
,
2198 tilegx_multiply_insn_seq_table_size
,
2199 sizeof tilegx_multiply_insn_seq_table
[0],
2200 tilegx_compare_multipliers
));
2204 /* Try to a expand constant multiply in DImode by looking it up in a
2205 precompiled table. OP0 is the result operand, OP1 is the source
2206 operand, and MULTIPLIER is the value of the constant. Return true
2209 tilegx_expand_const_muldi (rtx op0
, rtx op1
, long long multiplier
)
2211 /* See if we have precomputed an efficient way to multiply by this
2213 const struct tilegx_multiply_insn_seq
*seq
=
2214 tilegx_find_multiply_insn_seq_for_constant (multiplier
);
2217 tilegx_expand_constant_multiply_given_sequence (op0
, op1
, seq
);
2225 /* Expand the muldi pattern. */
2227 tilegx_expand_muldi (rtx op0
, rtx op1
, rtx op2
)
2229 if (CONST_INT_P (op2
))
2231 HOST_WIDE_INT n
= trunc_int_for_mode (INTVAL (op2
), DImode
);
2232 return tilegx_expand_const_muldi (op0
, op1
, n
);
2238 /* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the
2239 operands, and SIGN is true if it's a signed multiply, and false if
2240 it's an unsigned multiply. */
2242 tilegx_expand_high_multiply (rtx result
, rtx op1
, rtx op2
, bool sign
)
2244 rtx tmp0
= gen_reg_rtx (DImode
);
2245 rtx tmp1
= gen_reg_rtx (DImode
);
2246 rtx tmp2
= gen_reg_rtx (DImode
);
2247 rtx tmp3
= gen_reg_rtx (DImode
);
2248 rtx tmp4
= gen_reg_rtx (DImode
);
2249 rtx tmp5
= gen_reg_rtx (DImode
);
2250 rtx tmp6
= gen_reg_rtx (DImode
);
2251 rtx tmp7
= gen_reg_rtx (DImode
);
2252 rtx tmp8
= gen_reg_rtx (DImode
);
2253 rtx tmp9
= gen_reg_rtx (DImode
);
2254 rtx tmp10
= gen_reg_rtx (DImode
);
2255 rtx tmp11
= gen_reg_rtx (DImode
);
2256 rtx tmp12
= gen_reg_rtx (DImode
);
2257 rtx tmp13
= gen_reg_rtx (DImode
);
2258 rtx result_lo
= gen_reg_rtx (DImode
);
2262 emit_insn (gen_insn_mul_hs_lu (tmp0
, op1
, op2
));
2263 emit_insn (gen_insn_mul_hs_lu (tmp1
, op2
, op1
));
2264 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2265 emit_insn (gen_insn_mul_hs_hs (tmp3
, op1
, op2
));
2269 emit_insn (gen_insn_mul_hu_lu (tmp0
, op1
, op2
));
2270 emit_insn (gen_insn_mul_hu_lu (tmp1
, op2
, op1
));
2271 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2272 emit_insn (gen_insn_mul_hu_hu (tmp3
, op1
, op2
));
2275 emit_move_insn (tmp4
, (gen_rtx_ASHIFT (DImode
, tmp0
, GEN_INT (32))));
2277 emit_move_insn (tmp5
, (gen_rtx_ASHIFT (DImode
, tmp1
, GEN_INT (32))));
2279 emit_move_insn (tmp6
, (gen_rtx_PLUS (DImode
, tmp4
, tmp5
)));
2280 emit_move_insn (result_lo
, (gen_rtx_PLUS (DImode
, tmp2
, tmp6
)));
2282 emit_move_insn (tmp7
, gen_rtx_LTU (DImode
, tmp6
, tmp4
));
2283 emit_move_insn (tmp8
, gen_rtx_LTU (DImode
, result_lo
, tmp2
));
2287 emit_move_insn (tmp9
, (gen_rtx_ASHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2288 emit_move_insn (tmp10
, (gen_rtx_ASHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2292 emit_move_insn (tmp9
, (gen_rtx_LSHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2293 emit_move_insn (tmp10
, (gen_rtx_LSHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2296 emit_move_insn (tmp11
, (gen_rtx_PLUS (DImode
, tmp3
, tmp7
)));
2297 emit_move_insn (tmp12
, (gen_rtx_PLUS (DImode
, tmp8
, tmp9
)));
2298 emit_move_insn (tmp13
, (gen_rtx_PLUS (DImode
, tmp11
, tmp12
)));
2299 emit_move_insn (result
, (gen_rtx_PLUS (DImode
, tmp13
, tmp10
)));
2303 /* Implement smuldi3_highpart. */
2305 tilegx_expand_smuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2307 tilegx_expand_high_multiply (op0
, op1
, op2
, true);
2311 /* Implement umuldi3_highpart. */
2313 tilegx_expand_umuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2315 tilegx_expand_high_multiply (op0
, op1
, op2
, false);
2320 /* Compare and branches */
2322 /* Produce the rtx yielding a bool for a floating point
2325 tilegx_emit_fp_setcc (rtx res
, enum rtx_code code
, machine_mode mode
,
2328 /* TODO: Certain compares again constants can be done using entirely
2329 integer operations. But you have to get the special cases right
2330 e.g. NaN, +0 == -0, etc. */
2334 rtx a
= force_reg (DImode
, gen_lowpart (DImode
, op0
));
2335 rtx b
= force_reg (DImode
, gen_lowpart (DImode
, op1
));
2337 flags
= gen_reg_rtx (DImode
);
2341 emit_insn (gen_insn_fsingle_add1 (flags
, a
, b
));
2345 gcc_assert (mode
== DFmode
);
2346 emit_insn (gen_insn_fdouble_add_flags (flags
, a
, b
));
2351 case EQ
: flag_index
= 30; break;
2352 case NE
: flag_index
= 31; break;
2353 case LE
: flag_index
= 27; break;
2354 case LT
: flag_index
= 26; break;
2355 case GE
: flag_index
= 29; break;
2356 case GT
: flag_index
= 28; break;
2357 default: gcc_unreachable ();
2360 gcc_assert (GET_MODE (res
) == DImode
);
2361 emit_move_insn (res
, gen_rtx_ZERO_EXTRACT (DImode
, flags
, GEN_INT (1),
2362 GEN_INT (flag_index
)));
2367 /* Certain simplifications can be done to make invalid setcc
2368 operations valid. Return the final comparison, or NULL if we can't
2371 tilegx_emit_setcc_internal (rtx res
, enum rtx_code code
, rtx op0
, rtx op1
,
2372 machine_mode cmp_mode
)
2377 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2378 return tilegx_emit_fp_setcc (res
, code
, cmp_mode
, op0
, op1
);
2380 /* The general case: fold the comparison code to the types of
2381 compares that we have, choosing the branch as necessary. */
2391 /* We have these compares. */
2398 /* We do not have these compares, so we reverse the
2404 /* We should not have called this with any other code. */
2410 code
= swap_condition (code
);
2411 tmp
= op0
, op0
= op1
, op1
= tmp
;
2414 if (!reg_or_0_operand (op0
, cmp_mode
))
2415 op0
= force_reg (cmp_mode
, op0
);
2417 if (!CONST_INT_P (op1
) && !register_operand (op1
, cmp_mode
))
2418 op1
= force_reg (cmp_mode
, op1
);
2420 /* Return the setcc comparison. */
2421 emit_insn (gen_rtx_SET (res
, gen_rtx_fmt_ee (code
, DImode
, op0
, op1
)));
2427 /* Implement cstore patterns. */
2429 tilegx_emit_setcc (rtx operands
[], machine_mode cmp_mode
)
2432 tilegx_emit_setcc_internal (operands
[0], GET_CODE (operands
[1]),
2433 operands
[2], operands
[3], cmp_mode
);
2437 /* Return whether CODE is a signed comparison. */
2439 signed_compare_p (enum rtx_code code
)
2441 return (code
== EQ
|| code
== NE
|| code
== LT
|| code
== LE
2442 || code
== GT
|| code
== GE
);
2446 /* Generate the comparison for a DImode conditional branch. */
2448 tilegx_emit_cc_test (enum rtx_code code
, rtx op0
, rtx op1
,
2449 machine_mode cmp_mode
, bool eq_ne_only
)
2451 enum rtx_code branch_code
;
2454 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2456 /* Compute a boolean saying whether the comparison is true. */
2457 temp
= gen_reg_rtx (DImode
);
2458 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2460 /* Test that flag. */
2461 return gen_rtx_fmt_ee (NE
, VOIDmode
, temp
, const0_rtx
);
2464 /* Check for a compare against zero using a comparison we can do
2466 if (op1
== const0_rtx
2467 && (code
== EQ
|| code
== NE
2468 || (!eq_ne_only
&& signed_compare_p (code
))))
2470 op0
= force_reg (cmp_mode
, op0
);
2471 return gen_rtx_fmt_ee (code
, VOIDmode
, op0
, const0_rtx
);
2474 /* The general case: fold the comparison code to the types of
2475 compares that we have, choosing the branch as necessary. */
2483 /* We have these compares. */
2492 /* These must be reversed (except NE, but let's
2494 code
= reverse_condition (code
);
2502 if (CONST_INT_P (op1
) && (!satisfies_constraint_I (op1
) || code
== LEU
))
2504 HOST_WIDE_INT n
= INTVAL (op1
);
2509 /* Subtract off the value we want to compare against and see
2510 if we get zero. This is cheaper than creating a constant
2511 in a register. Except that subtracting -128 is more
2512 expensive than seqi to -128, so we leave that alone. */
2513 /* ??? Don't do this when comparing against symbols,
2514 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2515 0), which will be declared false out of hand (at least
2518 && add_operand (GEN_INT (-n
), DImode
)
2519 && !(symbolic_operand (op0
, VOIDmode
)
2520 || (REG_P (op0
) && REG_POINTER (op0
))))
2522 /* TODO: Use a SIMD add immediate to hit zero for tiled
2523 constants in a single instruction. */
2524 if (GET_MODE (op0
) != DImode
)
2526 /* Convert to DImode so we can use addli. Note that
2527 this will not actually generate any code because
2528 sign extension from SI -> DI is a no-op. I don't
2529 know if it's safe just to make a paradoxical
2530 subreg here though. */
2531 rtx temp2
= gen_reg_rtx (DImode
);
2532 emit_insn (gen_extendsidi2 (temp2
, op0
));
2537 op0
= force_reg (DImode
, op0
);
2539 temp
= gen_reg_rtx (DImode
);
2540 emit_move_insn (temp
, gen_rtx_PLUS (DImode
, op0
, GEN_INT (-n
)));
2541 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2542 VOIDmode
, temp
, const0_rtx
);
2552 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2553 We use arithmetic shift right because it's a 3-wide op,
2554 while logical shift right is not. */
2556 int first
= exact_log2 (code
== LTU
? n
: n
+ 1);
2559 op0
= force_reg (cmp_mode
, op0
);
2560 temp
= gen_reg_rtx (cmp_mode
);
2561 emit_move_insn (temp
,
2562 gen_rtx_ASHIFTRT (cmp_mode
, op0
,
2564 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2565 VOIDmode
, temp
, const0_rtx
);
2575 /* Compute a flag saying whether we should branch. */
2576 temp
= gen_reg_rtx (DImode
);
2577 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2579 /* Return the branch comparison. */
2580 return gen_rtx_fmt_ee (branch_code
, VOIDmode
, temp
, const0_rtx
);
2584 /* Generate the comparison for a conditional branch. */
2586 tilegx_emit_conditional_branch (rtx operands
[], machine_mode cmp_mode
)
2589 tilegx_emit_cc_test (GET_CODE (operands
[0]), operands
[1], operands
[2],
2591 rtx branch_rtx
= gen_rtx_SET (pc_rtx
,
2592 gen_rtx_IF_THEN_ELSE (VOIDmode
, cmp_rtx
,
2597 emit_jump_insn (branch_rtx
);
2601 /* Implement the mov<mode>cc pattern. */
2603 tilegx_emit_conditional_move (rtx cmp
)
2606 tilegx_emit_cc_test (GET_CODE (cmp
), XEXP (cmp
, 0), XEXP (cmp
, 1),
2607 GET_MODE (XEXP (cmp
, 0)), true);
2611 /* Return true if INSN is annotated with a REG_BR_PROB note that
2612 indicates it's a branch that's predicted taken. */
2614 cbranch_predicted_p (rtx_insn
*insn
)
2616 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2620 int pred_val
= XINT (x
, 0);
2622 return pred_val
>= REG_BR_PROB_BASE
/ 2;
2629 /* Output assembly code for a specific branch instruction, appending
2630 the branch prediction flag to the opcode if appropriate. */
2632 tilegx_output_simple_cbranch_with_opcode (rtx_insn
*insn
, const char *opcode
,
2633 int regop
, bool reverse_predicted
)
2635 static char buf
[64];
2636 sprintf (buf
, "%s%s\t%%r%d, %%l0", opcode
,
2637 (cbranch_predicted_p (insn
) ^ reverse_predicted
) ? "t" : "",
2643 /* Output assembly code for a specific branch instruction, appending
2644 the branch prediction flag to the opcode if appropriate. */
2646 tilegx_output_cbranch_with_opcode (rtx_insn
*insn
, rtx
*operands
,
2648 const char *rev_opcode
, int regop
)
2650 const char *branch_if_false
;
2651 rtx taken
, not_taken
;
2652 bool is_simple_branch
;
2654 gcc_assert (LABEL_P (operands
[0]));
2656 is_simple_branch
= true;
2657 if (INSN_ADDRESSES_SET_P ())
2659 int from_addr
= INSN_ADDRESSES (INSN_UID (insn
));
2660 int to_addr
= INSN_ADDRESSES (INSN_UID (operands
[0]));
2661 int delta
= to_addr
- from_addr
;
2662 is_simple_branch
= IN_RANGE (delta
, -524288, 524280);
2665 if (is_simple_branch
)
2667 /* Just a simple conditional branch. */
2669 tilegx_output_simple_cbranch_with_opcode (insn
, opcode
, regop
, false);
2672 /* Generate a reversed branch around a direct jump. This fallback
2673 does not use branch-likely instructions. */
2674 not_taken
= gen_label_rtx ();
2675 taken
= operands
[0];
2677 /* Generate the reversed branch to NOT_TAKEN. */
2678 operands
[0] = not_taken
;
2680 tilegx_output_simple_cbranch_with_opcode (insn
, rev_opcode
, regop
, true);
2681 output_asm_insn (branch_if_false
, operands
);
2683 output_asm_insn ("j\t%l0", &taken
);
2685 /* Output NOT_TAKEN. */
2686 targetm
.asm_out
.internal_label (asm_out_file
, "L",
2687 CODE_LABEL_NUMBER (not_taken
));
2692 /* Output assembly code for a conditional branch instruction. */
2694 tilegx_output_cbranch (rtx_insn
*insn
, rtx
*operands
, bool reversed
)
2696 enum rtx_code code
= GET_CODE (operands
[1]);
2698 const char *rev_opcode
;
2701 code
= reverse_condition (code
);
2707 rev_opcode
= "beqz";
2711 rev_opcode
= "bnez";
2715 rev_opcode
= "bltz";
2719 rev_opcode
= "blez";
2723 rev_opcode
= "bgtz";
2727 rev_opcode
= "bgez";
2733 return tilegx_output_cbranch_with_opcode (insn
, operands
, opcode
,
2738 /* Implement the tablejump pattern. */
2740 tilegx_expand_tablejump (rtx op0
, rtx op1
)
2744 rtx temp
= gen_reg_rtx (Pmode
);
2745 rtx temp2
= gen_reg_rtx (Pmode
);
2747 tilegx_compute_pcrel_address (temp
, gen_rtx_LABEL_REF (Pmode
, op1
));
2748 emit_move_insn (temp2
,
2749 gen_rtx_PLUS (Pmode
,
2750 convert_to_mode (Pmode
, op0
, false),
2755 emit_jump_insn (gen_tablejump_aux (op0
, op1
));
2759 /* Emit barrier before an atomic, as needed for the memory MODEL. */
2761 tilegx_pre_atomic_barrier (enum memmodel model
)
2763 if (need_atomic_barrier_p (model
, true))
2764 emit_insn (gen_memory_barrier ());
2768 /* Emit barrier after an atomic, as needed for the memory MODEL. */
2770 tilegx_post_atomic_barrier (enum memmodel model
)
2772 if (need_atomic_barrier_p (model
, false))
2773 emit_insn (gen_memory_barrier ());
2778 /* Expand a builtin vector binary op, by calling gen function GEN with
2779 operands in the proper modes. DEST is converted to DEST_MODE, and
2780 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2782 tilegx_expand_builtin_vector_binop (rtx (*gen
) (rtx
, rtx
, rtx
),
2783 machine_mode dest_mode
,
2785 machine_mode src_mode
,
2786 rtx src0
, rtx src1
, bool do_src1
)
2788 dest
= gen_lowpart (dest_mode
, dest
);
2790 if (src0
== const0_rtx
)
2791 src0
= CONST0_RTX (src_mode
);
2793 src0
= gen_lowpart (src_mode
, src0
);
2797 if (src1
== const0_rtx
)
2798 src1
= CONST0_RTX (src_mode
);
2800 src1
= gen_lowpart (src_mode
, src1
);
2803 emit_insn ((*gen
) (dest
, src0
, src1
));
2811 struct tile_builtin_info
2813 enum insn_code icode
;
2817 static struct tile_builtin_info tilegx_builtin_info
[TILEGX_BUILTIN_max
] = {
2818 { CODE_FOR_adddi3
, NULL
}, /* add */
2819 { CODE_FOR_addsi3
, NULL
}, /* addx */
2820 { CODE_FOR_ssaddsi3
, NULL
}, /* addxsc */
2821 { CODE_FOR_anddi3
, NULL
}, /* and */
2822 { CODE_FOR_insn_bfexts
, NULL
}, /* bfexts */
2823 { CODE_FOR_insn_bfextu
, NULL
}, /* bfextu */
2824 { CODE_FOR_insn_bfins
, NULL
}, /* bfins */
2825 { CODE_FOR_clzdi2
, NULL
}, /* clz */
2826 { CODE_FOR_insn_cmoveqz
, NULL
}, /* cmoveqz */
2827 { CODE_FOR_insn_cmovnez
, NULL
}, /* cmovnez */
2828 { CODE_FOR_insn_cmpeq_didi
, NULL
}, /* cmpeq */
2829 { CODE_FOR_insn_cmpexch
, NULL
}, /* cmpexch */
2830 { CODE_FOR_insn_cmpexch4
, NULL
}, /* cmpexch4 */
2831 { CODE_FOR_insn_cmples_didi
, NULL
}, /* cmples */
2832 { CODE_FOR_insn_cmpleu_didi
, NULL
}, /* cmpleu */
2833 { CODE_FOR_insn_cmplts_didi
, NULL
}, /* cmplts */
2834 { CODE_FOR_insn_cmpltu_didi
, NULL
}, /* cmpltu */
2835 { CODE_FOR_insn_cmpne_didi
, NULL
}, /* cmpne */
2836 { CODE_FOR_insn_cmul
, NULL
}, /* cmul */
2837 { CODE_FOR_insn_cmula
, NULL
}, /* cmula */
2838 { CODE_FOR_insn_cmulaf
, NULL
}, /* cmulaf */
2839 { CODE_FOR_insn_cmulf
, NULL
}, /* cmulf */
2840 { CODE_FOR_insn_cmulfr
, NULL
}, /* cmulfr */
2841 { CODE_FOR_insn_cmulh
, NULL
}, /* cmulh */
2842 { CODE_FOR_insn_cmulhr
, NULL
}, /* cmulhr */
2843 { CODE_FOR_insn_crc32_32
, NULL
}, /* crc32_32 */
2844 { CODE_FOR_insn_crc32_8
, NULL
}, /* crc32_8 */
2845 { CODE_FOR_ctzdi2
, NULL
}, /* ctz */
2846 { CODE_FOR_insn_dblalign
, NULL
}, /* dblalign */
2847 { CODE_FOR_insn_dblalign2
, NULL
}, /* dblalign2 */
2848 { CODE_FOR_insn_dblalign4
, NULL
}, /* dblalign4 */
2849 { CODE_FOR_insn_dblalign6
, NULL
}, /* dblalign6 */
2850 { CODE_FOR_insn_drain
, NULL
}, /* drain */
2851 { CODE_FOR_insn_dtlbpr
, NULL
}, /* dtlbpr */
2852 { CODE_FOR_insn_exch
, NULL
}, /* exch */
2853 { CODE_FOR_insn_exch4
, NULL
}, /* exch4 */
2854 { CODE_FOR_insn_fdouble_add_flags
, NULL
}, /* fdouble_add_flags */
2855 { CODE_FOR_insn_fdouble_addsub
, NULL
}, /* fdouble_addsub */
2856 { CODE_FOR_insn_fdouble_mul_flags
, NULL
}, /* fdouble_mul_flags */
2857 { CODE_FOR_insn_fdouble_pack1
, NULL
}, /* fdouble_pack1 */
2858 { CODE_FOR_insn_fdouble_pack2
, NULL
}, /* fdouble_pack2 */
2859 { CODE_FOR_insn_fdouble_sub_flags
, NULL
}, /* fdouble_sub_flags */
2860 { CODE_FOR_insn_fdouble_unpack_max
, NULL
}, /* fdouble_unpack_max */
2861 { CODE_FOR_insn_fdouble_unpack_min
, NULL
}, /* fdouble_unpack_min */
2862 { CODE_FOR_insn_fetchadd
, NULL
}, /* fetchadd */
2863 { CODE_FOR_insn_fetchadd4
, NULL
}, /* fetchadd4 */
2864 { CODE_FOR_insn_fetchaddgez
, NULL
}, /* fetchaddgez */
2865 { CODE_FOR_insn_fetchaddgez4
, NULL
}, /* fetchaddgez4 */
2866 { CODE_FOR_insn_fetchand
, NULL
}, /* fetchand */
2867 { CODE_FOR_insn_fetchand4
, NULL
}, /* fetchand4 */
2868 { CODE_FOR_insn_fetchor
, NULL
}, /* fetchor */
2869 { CODE_FOR_insn_fetchor4
, NULL
}, /* fetchor4 */
2870 { CODE_FOR_insn_finv
, NULL
}, /* finv */
2871 { CODE_FOR_insn_flush
, NULL
}, /* flush */
2872 { CODE_FOR_insn_flushwb
, NULL
}, /* flushwb */
2873 { CODE_FOR_insn_fnop
, NULL
}, /* fnop */
2874 { CODE_FOR_insn_fsingle_add1
, NULL
}, /* fsingle_add1 */
2875 { CODE_FOR_insn_fsingle_addsub2
, NULL
}, /* fsingle_addsub2 */
2876 { CODE_FOR_insn_fsingle_mul1
, NULL
}, /* fsingle_mul1 */
2877 { CODE_FOR_insn_fsingle_mul2
, NULL
}, /* fsingle_mul2 */
2878 { CODE_FOR_insn_fsingle_pack1
, NULL
}, /* fsingle_pack1 */
2879 { CODE_FOR_insn_fsingle_pack2
, NULL
}, /* fsingle_pack2 */
2880 { CODE_FOR_insn_fsingle_sub1
, NULL
}, /* fsingle_sub1 */
2881 { CODE_FOR_insn_icoh
, NULL
}, /* icoh */
2882 { CODE_FOR_insn_ill
, NULL
}, /* ill */
2883 { CODE_FOR_insn_info
, NULL
}, /* info */
2884 { CODE_FOR_insn_infol
, NULL
}, /* infol */
2885 { CODE_FOR_insn_inv
, NULL
}, /* inv */
2886 { CODE_FOR_insn_ld
, NULL
}, /* ld */
2887 { CODE_FOR_insn_ld1s
, NULL
}, /* ld1s */
2888 { CODE_FOR_insn_ld1u
, NULL
}, /* ld1u */
2889 { CODE_FOR_insn_ld2s
, NULL
}, /* ld2s */
2890 { CODE_FOR_insn_ld2u
, NULL
}, /* ld2u */
2891 { CODE_FOR_insn_ld4s
, NULL
}, /* ld4s */
2892 { CODE_FOR_insn_ld4u
, NULL
}, /* ld4u */
2893 { CODE_FOR_insn_ldna
, NULL
}, /* ldna */
2894 { CODE_FOR_insn_ldnt
, NULL
}, /* ldnt */
2895 { CODE_FOR_insn_ldnt1s
, NULL
}, /* ldnt1s */
2896 { CODE_FOR_insn_ldnt1u
, NULL
}, /* ldnt1u */
2897 { CODE_FOR_insn_ldnt2s
, NULL
}, /* ldnt2s */
2898 { CODE_FOR_insn_ldnt2u
, NULL
}, /* ldnt2u */
2899 { CODE_FOR_insn_ldnt4s
, NULL
}, /* ldnt4s */
2900 { CODE_FOR_insn_ldnt4u
, NULL
}, /* ldnt4u */
2901 { CODE_FOR_insn_ld_L2
, NULL
}, /* ld_L2 */
2902 { CODE_FOR_insn_ld1s_L2
, NULL
}, /* ld1s_L2 */
2903 { CODE_FOR_insn_ld1u_L2
, NULL
}, /* ld1u_L2 */
2904 { CODE_FOR_insn_ld2s_L2
, NULL
}, /* ld2s_L2 */
2905 { CODE_FOR_insn_ld2u_L2
, NULL
}, /* ld2u_L2 */
2906 { CODE_FOR_insn_ld4s_L2
, NULL
}, /* ld4s_L2 */
2907 { CODE_FOR_insn_ld4u_L2
, NULL
}, /* ld4u_L2 */
2908 { CODE_FOR_insn_ldna_L2
, NULL
}, /* ldna_L2 */
2909 { CODE_FOR_insn_ldnt_L2
, NULL
}, /* ldnt_L2 */
2910 { CODE_FOR_insn_ldnt1s_L2
, NULL
}, /* ldnt1s_L2 */
2911 { CODE_FOR_insn_ldnt1u_L2
, NULL
}, /* ldnt1u_L2 */
2912 { CODE_FOR_insn_ldnt2s_L2
, NULL
}, /* ldnt2s_L2 */
2913 { CODE_FOR_insn_ldnt2u_L2
, NULL
}, /* ldnt2u_L2 */
2914 { CODE_FOR_insn_ldnt4s_L2
, NULL
}, /* ldnt4s_L2 */
2915 { CODE_FOR_insn_ldnt4u_L2
, NULL
}, /* ldnt4u_L2 */
2916 { CODE_FOR_insn_ld_miss
, NULL
}, /* ld_miss */
2917 { CODE_FOR_insn_ld1s_miss
, NULL
}, /* ld1s_miss */
2918 { CODE_FOR_insn_ld1u_miss
, NULL
}, /* ld1u_miss */
2919 { CODE_FOR_insn_ld2s_miss
, NULL
}, /* ld2s_miss */
2920 { CODE_FOR_insn_ld2u_miss
, NULL
}, /* ld2u_miss */
2921 { CODE_FOR_insn_ld4s_miss
, NULL
}, /* ld4s_miss */
2922 { CODE_FOR_insn_ld4u_miss
, NULL
}, /* ld4u_miss */
2923 { CODE_FOR_insn_ldna_miss
, NULL
}, /* ldna_miss */
2924 { CODE_FOR_insn_ldnt_miss
, NULL
}, /* ldnt_miss */
2925 { CODE_FOR_insn_ldnt1s_miss
, NULL
}, /* ldnt1s_miss */
2926 { CODE_FOR_insn_ldnt1u_miss
, NULL
}, /* ldnt1u_miss */
2927 { CODE_FOR_insn_ldnt2s_miss
, NULL
}, /* ldnt2s_miss */
2928 { CODE_FOR_insn_ldnt2u_miss
, NULL
}, /* ldnt2u_miss */
2929 { CODE_FOR_insn_ldnt4s_miss
, NULL
}, /* ldnt4s_miss */
2930 { CODE_FOR_insn_ldnt4u_miss
, NULL
}, /* ldnt4u_miss */
2931 { CODE_FOR_insn_lnk
, NULL
}, /* lnk */
2932 { CODE_FOR_memory_barrier
, NULL
}, /* mf */
2933 { CODE_FOR_insn_mfspr
, NULL
}, /* mfspr */
2934 { CODE_FOR_insn_mm
, NULL
}, /* mm */
2935 { CODE_FOR_insn_mnz
, NULL
}, /* mnz */
2936 { CODE_FOR_movdi
, NULL
}, /* move */
2937 { CODE_FOR_insn_mtspr
, NULL
}, /* mtspr */
2938 { CODE_FOR_insn_mul_hs_hs
, NULL
}, /* mul_hs_hs */
2939 { CODE_FOR_insn_mul_hs_hu
, NULL
}, /* mul_hs_hu */
2940 { CODE_FOR_insn_mul_hs_ls
, NULL
}, /* mul_hs_ls */
2941 { CODE_FOR_insn_mul_hs_lu
, NULL
}, /* mul_hs_lu */
2942 { CODE_FOR_insn_mul_hu_hu
, NULL
}, /* mul_hu_hu */
2943 { CODE_FOR_insn_mul_hu_ls
, NULL
}, /* mul_hu_ls */
2944 { CODE_FOR_insn_mul_hu_lu
, NULL
}, /* mul_hu_lu */
2945 { CODE_FOR_insn_mul_ls_ls
, NULL
}, /* mul_ls_ls */
2946 { CODE_FOR_insn_mul_ls_lu
, NULL
}, /* mul_ls_lu */
2947 { CODE_FOR_insn_mul_lu_lu
, NULL
}, /* mul_lu_lu */
2948 { CODE_FOR_insn_mula_hs_hs
, NULL
}, /* mula_hs_hs */
2949 { CODE_FOR_insn_mula_hs_hu
, NULL
}, /* mula_hs_hu */
2950 { CODE_FOR_insn_mula_hs_ls
, NULL
}, /* mula_hs_ls */
2951 { CODE_FOR_insn_mula_hs_lu
, NULL
}, /* mula_hs_lu */
2952 { CODE_FOR_insn_mula_hu_hu
, NULL
}, /* mula_hu_hu */
2953 { CODE_FOR_insn_mula_hu_ls
, NULL
}, /* mula_hu_ls */
2954 { CODE_FOR_insn_mula_hu_lu
, NULL
}, /* mula_hu_lu */
2955 { CODE_FOR_insn_mula_ls_ls
, NULL
}, /* mula_ls_ls */
2956 { CODE_FOR_insn_mula_ls_lu
, NULL
}, /* mula_ls_lu */
2957 { CODE_FOR_insn_mula_lu_lu
, NULL
}, /* mula_lu_lu */
2958 { CODE_FOR_insn_mulax
, NULL
}, /* mulax */
2959 { CODE_FOR_mulsi3
, NULL
}, /* mulx */
2960 { CODE_FOR_insn_mz
, NULL
}, /* mz */
2961 { CODE_FOR_insn_nap
, NULL
}, /* nap */
2962 { CODE_FOR_nop
, NULL
}, /* nop */
2963 { CODE_FOR_insn_nor_di
, NULL
}, /* nor */
2964 { CODE_FOR_iordi3
, NULL
}, /* or */
2965 { CODE_FOR_popcountdi2
, NULL
}, /* pcnt */
2966 { CODE_FOR_insn_prefetch_l1
, NULL
}, /* prefetch_l1 */
2967 { CODE_FOR_insn_prefetch_l1_fault
, NULL
}, /* prefetch_l1_fault */
2968 { CODE_FOR_insn_prefetch_l2
, NULL
}, /* prefetch_l2 */
2969 { CODE_FOR_insn_prefetch_l2_fault
, NULL
}, /* prefetch_l2_fault */
2970 { CODE_FOR_insn_prefetch_l3
, NULL
}, /* prefetch_l3 */
2971 { CODE_FOR_insn_prefetch_l3_fault
, NULL
}, /* prefetch_l3_fault */
2972 { CODE_FOR_insn_revbits
, NULL
}, /* revbits */
2973 { CODE_FOR_bswapdi2
, NULL
}, /* revbytes */
2974 { CODE_FOR_rotldi3
, NULL
}, /* rotl */
2975 { CODE_FOR_ashldi3
, NULL
}, /* shl */
2976 { CODE_FOR_insn_shl16insli
, NULL
}, /* shl16insli */
2977 { CODE_FOR_insn_shl1add
, NULL
}, /* shl1add */
2978 { CODE_FOR_insn_shl1addx
, NULL
}, /* shl1addx */
2979 { CODE_FOR_insn_shl2add
, NULL
}, /* shl2add */
2980 { CODE_FOR_insn_shl2addx
, NULL
}, /* shl2addx */
2981 { CODE_FOR_insn_shl3add
, NULL
}, /* shl3add */
2982 { CODE_FOR_insn_shl3addx
, NULL
}, /* shl3addx */
2983 { CODE_FOR_ashlsi3
, NULL
}, /* shlx */
2984 { CODE_FOR_ashrdi3
, NULL
}, /* shrs */
2985 { CODE_FOR_lshrdi3
, NULL
}, /* shru */
2986 { CODE_FOR_lshrsi3
, NULL
}, /* shrux */
2987 { CODE_FOR_insn_shufflebytes
, NULL
}, /* shufflebytes */
2988 { CODE_FOR_insn_shufflebytes1
, NULL
}, /* shufflebytes1 */
2989 { CODE_FOR_insn_st
, NULL
}, /* st */
2990 { CODE_FOR_insn_st1
, NULL
}, /* st1 */
2991 { CODE_FOR_insn_st2
, NULL
}, /* st2 */
2992 { CODE_FOR_insn_st4
, NULL
}, /* st4 */
2993 { CODE_FOR_insn_stnt
, NULL
}, /* stnt */
2994 { CODE_FOR_insn_stnt1
, NULL
}, /* stnt1 */
2995 { CODE_FOR_insn_stnt2
, NULL
}, /* stnt2 */
2996 { CODE_FOR_insn_stnt4
, NULL
}, /* stnt4 */
2997 { CODE_FOR_subdi3
, NULL
}, /* sub */
2998 { CODE_FOR_subsi3
, NULL
}, /* subx */
2999 { CODE_FOR_sssubsi3
, NULL
}, /* subxsc */
3000 { CODE_FOR_insn_tblidxb0
, NULL
}, /* tblidxb0 */
3001 { CODE_FOR_insn_tblidxb1
, NULL
}, /* tblidxb1 */
3002 { CODE_FOR_insn_tblidxb2
, NULL
}, /* tblidxb2 */
3003 { CODE_FOR_insn_tblidxb3
, NULL
}, /* tblidxb3 */
3004 { CODE_FOR_insn_v1add
, NULL
}, /* v1add */
3005 { CODE_FOR_insn_v1addi
, NULL
}, /* v1addi */
3006 { CODE_FOR_insn_v1adduc
, NULL
}, /* v1adduc */
3007 { CODE_FOR_insn_v1adiffu
, NULL
}, /* v1adiffu */
3008 { CODE_FOR_insn_v1avgu
, NULL
}, /* v1avgu */
3009 { CODE_FOR_insn_v1cmpeq
, NULL
}, /* v1cmpeq */
3010 { CODE_FOR_insn_v1cmpeqi
, NULL
}, /* v1cmpeqi */
3011 { CODE_FOR_insn_v1cmples
, NULL
}, /* v1cmples */
3012 { CODE_FOR_insn_v1cmpleu
, NULL
}, /* v1cmpleu */
3013 { CODE_FOR_insn_v1cmplts
, NULL
}, /* v1cmplts */
3014 { CODE_FOR_insn_v1cmpltsi
, NULL
}, /* v1cmpltsi */
3015 { CODE_FOR_insn_v1cmpltu
, NULL
}, /* v1cmpltu */
3016 { CODE_FOR_insn_v1cmpltui
, NULL
}, /* v1cmpltui */
3017 { CODE_FOR_insn_v1cmpne
, NULL
}, /* v1cmpne */
3018 { CODE_FOR_insn_v1ddotpu
, NULL
}, /* v1ddotpu */
3019 { CODE_FOR_insn_v1ddotpua
, NULL
}, /* v1ddotpua */
3020 { CODE_FOR_insn_v1ddotpus
, NULL
}, /* v1ddotpus */
3021 { CODE_FOR_insn_v1ddotpusa
, NULL
}, /* v1ddotpusa */
3022 { CODE_FOR_insn_v1dotp
, NULL
}, /* v1dotp */
3023 { CODE_FOR_insn_v1dotpa
, NULL
}, /* v1dotpa */
3024 { CODE_FOR_insn_v1dotpu
, NULL
}, /* v1dotpu */
3025 { CODE_FOR_insn_v1dotpua
, NULL
}, /* v1dotpua */
3026 { CODE_FOR_insn_v1dotpus
, NULL
}, /* v1dotpus */
3027 { CODE_FOR_insn_v1dotpusa
, NULL
}, /* v1dotpusa */
3028 { CODE_FOR_insn_v1int_h
, NULL
}, /* v1int_h */
3029 { CODE_FOR_insn_v1int_l
, NULL
}, /* v1int_l */
3030 { CODE_FOR_insn_v1maxu
, NULL
}, /* v1maxu */
3031 { CODE_FOR_insn_v1maxui
, NULL
}, /* v1maxui */
3032 { CODE_FOR_insn_v1minu
, NULL
}, /* v1minu */
3033 { CODE_FOR_insn_v1minui
, NULL
}, /* v1minui */
3034 { CODE_FOR_insn_v1mnz
, NULL
}, /* v1mnz */
3035 { CODE_FOR_insn_v1multu
, NULL
}, /* v1multu */
3036 { CODE_FOR_insn_v1mulu
, NULL
}, /* v1mulu */
3037 { CODE_FOR_insn_v1mulus
, NULL
}, /* v1mulus */
3038 { CODE_FOR_insn_v1mz
, NULL
}, /* v1mz */
3039 { CODE_FOR_insn_v1sadau
, NULL
}, /* v1sadau */
3040 { CODE_FOR_insn_v1sadu
, NULL
}, /* v1sadu */
3041 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shl */
3042 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shli */
3043 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrs */
3044 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrsi */
3045 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shru */
3046 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shrui */
3047 { CODE_FOR_insn_v1sub
, NULL
}, /* v1sub */
3048 { CODE_FOR_insn_v1subuc
, NULL
}, /* v1subuc */
3049 { CODE_FOR_insn_v2add
, NULL
}, /* v2add */
3050 { CODE_FOR_insn_v2addi
, NULL
}, /* v2addi */
3051 { CODE_FOR_insn_v2addsc
, NULL
}, /* v2addsc */
3052 { CODE_FOR_insn_v2adiffs
, NULL
}, /* v2adiffs */
3053 { CODE_FOR_insn_v2avgs
, NULL
}, /* v2avgs */
3054 { CODE_FOR_insn_v2cmpeq
, NULL
}, /* v2cmpeq */
3055 { CODE_FOR_insn_v2cmpeqi
, NULL
}, /* v2cmpeqi */
3056 { CODE_FOR_insn_v2cmples
, NULL
}, /* v2cmples */
3057 { CODE_FOR_insn_v2cmpleu
, NULL
}, /* v2cmpleu */
3058 { CODE_FOR_insn_v2cmplts
, NULL
}, /* v2cmplts */
3059 { CODE_FOR_insn_v2cmpltsi
, NULL
}, /* v2cmpltsi */
3060 { CODE_FOR_insn_v2cmpltu
, NULL
}, /* v2cmpltu */
3061 { CODE_FOR_insn_v2cmpltui
, NULL
}, /* v2cmpltui */
3062 { CODE_FOR_insn_v2cmpne
, NULL
}, /* v2cmpne */
3063 { CODE_FOR_insn_v2dotp
, NULL
}, /* v2dotp */
3064 { CODE_FOR_insn_v2dotpa
, NULL
}, /* v2dotpa */
3065 { CODE_FOR_insn_v2int_h
, NULL
}, /* v2int_h */
3066 { CODE_FOR_insn_v2int_l
, NULL
}, /* v2int_l */
3067 { CODE_FOR_insn_v2maxs
, NULL
}, /* v2maxs */
3068 { CODE_FOR_insn_v2maxsi
, NULL
}, /* v2maxsi */
3069 { CODE_FOR_insn_v2mins
, NULL
}, /* v2mins */
3070 { CODE_FOR_insn_v2minsi
, NULL
}, /* v2minsi */
3071 { CODE_FOR_insn_v2mnz
, NULL
}, /* v2mnz */
3072 { CODE_FOR_insn_v2mulfsc
, NULL
}, /* v2mulfsc */
3073 { CODE_FOR_insn_v2muls
, NULL
}, /* v2muls */
3074 { CODE_FOR_insn_v2mults
, NULL
}, /* v2mults */
3075 { CODE_FOR_insn_v2mz
, NULL
}, /* v2mz */
3076 { CODE_FOR_insn_v2packh
, NULL
}, /* v2packh */
3077 { CODE_FOR_insn_v2packl
, NULL
}, /* v2packl */
3078 { CODE_FOR_insn_v2packuc
, NULL
}, /* v2packuc */
3079 { CODE_FOR_insn_v2sadas
, NULL
}, /* v2sadas */
3080 { CODE_FOR_insn_v2sadau
, NULL
}, /* v2sadau */
3081 { CODE_FOR_insn_v2sads
, NULL
}, /* v2sads */
3082 { CODE_FOR_insn_v2sadu
, NULL
}, /* v2sadu */
3083 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shl */
3084 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shli */
3085 { CODE_FOR_insn_v2shlsc
, NULL
}, /* v2shlsc */
3086 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrs */
3087 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrsi */
3088 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shru */
3089 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shrui */
3090 { CODE_FOR_insn_v2sub
, NULL
}, /* v2sub */
3091 { CODE_FOR_insn_v2subsc
, NULL
}, /* v2subsc */
3092 { CODE_FOR_insn_v4add
, NULL
}, /* v4add */
3093 { CODE_FOR_insn_v4addsc
, NULL
}, /* v4addsc */
3094 { CODE_FOR_insn_v4int_h
, NULL
}, /* v4int_h */
3095 { CODE_FOR_insn_v4int_l
, NULL
}, /* v4int_l */
3096 { CODE_FOR_insn_v4packsc
, NULL
}, /* v4packsc */
3097 { CODE_FOR_insn_v4shl
, NULL
}, /* v4shl */
3098 { CODE_FOR_insn_v4shlsc
, NULL
}, /* v4shlsc */
3099 { CODE_FOR_insn_v4shrs
, NULL
}, /* v4shrs */
3100 { CODE_FOR_insn_v4shru
, NULL
}, /* v4shru */
3101 { CODE_FOR_insn_v4sub
, NULL
}, /* v4sub */
3102 { CODE_FOR_insn_v4subsc
, NULL
}, /* v4subsc */
3103 { CODE_FOR_insn_wh64
, NULL
}, /* wh64 */
3104 { CODE_FOR_xordi3
, NULL
}, /* xor */
3105 { CODE_FOR_tilegx_network_barrier
, NULL
}, /* network_barrier */
3106 { CODE_FOR_tilegx_idn0_receive
, NULL
}, /* idn0_receive */
3107 { CODE_FOR_tilegx_idn1_receive
, NULL
}, /* idn1_receive */
3108 { CODE_FOR_tilegx_idn_send
, NULL
}, /* idn_send */
3109 { CODE_FOR_tilegx_udn0_receive
, NULL
}, /* udn0_receive */
3110 { CODE_FOR_tilegx_udn1_receive
, NULL
}, /* udn1_receive */
3111 { CODE_FOR_tilegx_udn2_receive
, NULL
}, /* udn2_receive */
3112 { CODE_FOR_tilegx_udn3_receive
, NULL
}, /* udn3_receive */
3113 { CODE_FOR_tilegx_udn_send
, NULL
}, /* udn_send */
3117 struct tilegx_builtin_def
3120 enum tilegx_builtin code
;
3122 /* The first character is the return type. Subsequent characters
3123 are the argument types. See char_to_type. */
3128 static const struct tilegx_builtin_def tilegx_builtins
[] = {
3129 { "__insn_add", TILEGX_INSN_ADD
, true, "lll" },
3130 { "__insn_addi", TILEGX_INSN_ADD
, true, "lll" },
3131 { "__insn_addli", TILEGX_INSN_ADD
, true, "lll" },
3132 { "__insn_addx", TILEGX_INSN_ADDX
, true, "iii" },
3133 { "__insn_addxi", TILEGX_INSN_ADDX
, true, "iii" },
3134 { "__insn_addxli", TILEGX_INSN_ADDX
, true, "iii" },
3135 { "__insn_addxsc", TILEGX_INSN_ADDXSC
, true, "iii" },
3136 { "__insn_and", TILEGX_INSN_AND
, true, "lll" },
3137 { "__insn_andi", TILEGX_INSN_AND
, true, "lll" },
3138 { "__insn_bfexts", TILEGX_INSN_BFEXTS
, true, "llll" },
3139 { "__insn_bfextu", TILEGX_INSN_BFEXTU
, true, "llll" },
3140 { "__insn_bfins", TILEGX_INSN_BFINS
, true, "lllll"},
3141 { "__insn_clz", TILEGX_INSN_CLZ
, true, "ll" },
3142 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ
, true, "llll" },
3143 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ
, true, "llll" },
3144 { "__insn_cmpeq", TILEGX_INSN_CMPEQ
, true, "lll" },
3145 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ
, true, "lll" },
3146 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH
, false, "lpl" },
3147 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4
, false, "ipi" },
3148 { "__insn_cmples", TILEGX_INSN_CMPLES
, true, "lll" },
3149 { "__insn_cmpleu", TILEGX_INSN_CMPLEU
, true, "lll" },
3150 { "__insn_cmplts", TILEGX_INSN_CMPLTS
, true, "lll" },
3151 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS
, true, "lll" },
3152 { "__insn_cmpltu", TILEGX_INSN_CMPLTU
, true, "lll" },
3153 { "__insn_cmpltui", TILEGX_INSN_CMPLTU
, true, "lll" },
3154 { "__insn_cmpne", TILEGX_INSN_CMPNE
, true, "lll" },
3155 { "__insn_cmul", TILEGX_INSN_CMUL
, true, "lll" },
3156 { "__insn_cmula", TILEGX_INSN_CMULA
, true, "llll" },
3157 { "__insn_cmulaf", TILEGX_INSN_CMULAF
, true, "llll" },
3158 { "__insn_cmulf", TILEGX_INSN_CMULF
, true, "lll" },
3159 { "__insn_cmulfr", TILEGX_INSN_CMULFR
, true, "lll" },
3160 { "__insn_cmulh", TILEGX_INSN_CMULH
, true, "lll" },
3161 { "__insn_cmulhr", TILEGX_INSN_CMULHR
, true, "lll" },
3162 { "__insn_crc32_32", TILEGX_INSN_CRC32_32
, true, "lll" },
3163 { "__insn_crc32_8", TILEGX_INSN_CRC32_8
, true, "lll" },
3164 { "__insn_ctz", TILEGX_INSN_CTZ
, true, "ll" },
3165 { "__insn_dblalign", TILEGX_INSN_DBLALIGN
, true, "lllk" },
3166 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2
, true, "lll" },
3167 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4
, true, "lll" },
3168 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6
, true, "lll" },
3169 { "__insn_drain", TILEGX_INSN_DRAIN
, false, "v" },
3170 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR
, false, "vl" },
3171 { "__insn_exch", TILEGX_INSN_EXCH
, false, "lpl" },
3172 { "__insn_exch4", TILEGX_INSN_EXCH4
, false, "ipi" },
3173 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS
, true, "lll" },
3174 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB
, true, "llll" },
3175 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS
, true, "lll" },
3176 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1
, true, "lll" },
3177 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2
, true, "llll" },
3178 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS
, true, "lll" },
3179 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX
, true, "lll" },
3180 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN
, true, "lll" },
3181 { "__insn_fetchadd", TILEGX_INSN_FETCHADD
, false, "lpl" },
3182 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4
, false, "ipi" },
3183 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ
, false, "lpl" },
3184 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4
, false, "ipi" },
3185 { "__insn_fetchand", TILEGX_INSN_FETCHAND
, false, "lpl" },
3186 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4
, false, "ipi" },
3187 { "__insn_fetchor", TILEGX_INSN_FETCHOR
, false, "lpl" },
3188 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4
, false, "ipi" },
3189 { "__insn_finv", TILEGX_INSN_FINV
, false, "vk" },
3190 { "__insn_flush", TILEGX_INSN_FLUSH
, false, "vk" },
3191 { "__insn_flushwb", TILEGX_INSN_FLUSHWB
, false, "v" },
3192 { "__insn_fnop", TILEGX_INSN_FNOP
, false, "v" },
3193 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1
, true, "lll" },
3194 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2
, true, "llll" },
3195 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1
, true, "lll" },
3196 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2
, true, "lll" },
3197 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1
, true, "ll" },
3198 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2
, true, "lll" },
3199 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1
, true, "lll" },
3200 { "__insn_icoh", TILEGX_INSN_ICOH
, false, "vk" },
3201 { "__insn_ill", TILEGX_INSN_ILL
, false, "v" },
3202 { "__insn_info", TILEGX_INSN_INFO
, false, "vl" },
3203 { "__insn_infol", TILEGX_INSN_INFOL
, false, "vl" },
3204 { "__insn_inv", TILEGX_INSN_INV
, false, "vp" },
3205 { "__insn_ld", TILEGX_INSN_LD
, false, "lk" },
3206 { "__insn_ld1s", TILEGX_INSN_LD1S
, false, "lk" },
3207 { "__insn_ld1u", TILEGX_INSN_LD1U
, false, "lk" },
3208 { "__insn_ld2s", TILEGX_INSN_LD2S
, false, "lk" },
3209 { "__insn_ld2u", TILEGX_INSN_LD2U
, false, "lk" },
3210 { "__insn_ld4s", TILEGX_INSN_LD4S
, false, "lk" },
3211 { "__insn_ld4u", TILEGX_INSN_LD4U
, false, "lk" },
3212 { "__insn_ldna", TILEGX_INSN_LDNA
, false, "lk" },
3213 { "__insn_ldnt", TILEGX_INSN_LDNT
, false, "lk" },
3214 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S
, false, "lk" },
3215 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U
, false, "lk" },
3216 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S
, false, "lk" },
3217 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U
, false, "lk" },
3218 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S
, false, "lk" },
3219 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U
, false, "lk" },
3220 { "__insn_ld_L2", TILEGX_INSN_LD_L2
, false, "lk" },
3221 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2
, false, "lk" },
3222 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2
, false, "lk" },
3223 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2
, false, "lk" },
3224 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2
, false, "lk" },
3225 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2
, false, "lk" },
3226 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2
, false, "lk" },
3227 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2
, false, "lk" },
3228 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2
, false, "lk" },
3229 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2
, false, "lk" },
3230 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2
, false, "lk" },
3231 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2
, false, "lk" },
3232 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2
, false, "lk" },
3233 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2
, false, "lk" },
3234 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2
, false, "lk" },
3235 { "__insn_ld_miss", TILEGX_INSN_LD_MISS
, false, "lk" },
3236 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS
, false, "lk" },
3237 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS
, false, "lk" },
3238 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS
, false, "lk" },
3239 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS
, false, "lk" },
3240 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS
, false, "lk" },
3241 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS
, false, "lk" },
3242 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS
, false, "lk" },
3243 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS
, false, "lk" },
3244 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS
, false, "lk" },
3245 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS
, false, "lk" },
3246 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS
, false, "lk" },
3247 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS
, false, "lk" },
3248 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS
, false, "lk" },
3249 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS
, false, "lk" },
3250 { "__insn_lnk", TILEGX_INSN_LNK
, true, "l" },
3251 { "__insn_mf", TILEGX_INSN_MF
, false, "v" },
3252 { "__insn_mfspr", TILEGX_INSN_MFSPR
, false, "ll" },
3253 { "__insn_mm", TILEGX_INSN_MM
, true, "lllll"},
3254 { "__insn_mnz", TILEGX_INSN_MNZ
, true, "lll" },
3255 { "__insn_move", TILEGX_INSN_MOVE
, true, "ll" },
3256 { "__insn_movei", TILEGX_INSN_MOVE
, true, "ll" },
3257 { "__insn_moveli", TILEGX_INSN_MOVE
, true, "ll" },
3258 { "__insn_mtspr", TILEGX_INSN_MTSPR
, false, "vll" },
3259 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS
, true, "lll" },
3260 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU
, true, "lll" },
3261 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS
, true, "lll" },
3262 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU
, true, "lll" },
3263 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU
, true, "lll" },
3264 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS
, true, "lll" },
3265 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU
, true, "lll" },
3266 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS
, true, "lll" },
3267 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU
, true, "lll" },
3268 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU
, true, "lll" },
3269 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS
, true, "llll" },
3270 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU
, true, "llll" },
3271 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS
, true, "llll" },
3272 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU
, true, "llll" },
3273 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU
, true, "llll" },
3274 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS
, true, "llll" },
3275 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU
, true, "llll" },
3276 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS
, true, "llll" },
3277 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU
, true, "llll" },
3278 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU
, true, "llll" },
3279 { "__insn_mulax", TILEGX_INSN_MULAX
, true, "iiii" },
3280 { "__insn_mulx", TILEGX_INSN_MULX
, true, "iii" },
3281 { "__insn_mz", TILEGX_INSN_MZ
, true, "lll" },
3282 { "__insn_nap", TILEGX_INSN_NAP
, false, "v" },
3283 { "__insn_nop", TILEGX_INSN_NOP
, true, "v" },
3284 { "__insn_nor", TILEGX_INSN_NOR
, true, "lll" },
3285 { "__insn_or", TILEGX_INSN_OR
, true, "lll" },
3286 { "__insn_ori", TILEGX_INSN_OR
, true, "lll" },
3287 { "__insn_pcnt", TILEGX_INSN_PCNT
, true, "ll" },
3288 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3289 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3290 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT
, false, "vk" },
3291 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2
, false, "vk" },
3292 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT
, false, "vk" },
3293 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3
, false, "vk" },
3294 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT
, false, "vk" },
3295 { "__insn_revbits", TILEGX_INSN_REVBITS
, true, "ll" },
3296 { "__insn_revbytes", TILEGX_INSN_REVBYTES
, true, "ll" },
3297 { "__insn_rotl", TILEGX_INSN_ROTL
, true, "lli" },
3298 { "__insn_rotli", TILEGX_INSN_ROTL
, true, "lli" },
3299 { "__insn_shl", TILEGX_INSN_SHL
, true, "lli" },
3300 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI
, true, "lll" },
3301 { "__insn_shl1add", TILEGX_INSN_SHL1ADD
, true, "lll" },
3302 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX
, true, "iii" },
3303 { "__insn_shl2add", TILEGX_INSN_SHL2ADD
, true, "lll" },
3304 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX
, true, "iii" },
3305 { "__insn_shl3add", TILEGX_INSN_SHL3ADD
, true, "lll" },
3306 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX
, true, "iii" },
3307 { "__insn_shli", TILEGX_INSN_SHL
, true, "lli" },
3308 { "__insn_shlx", TILEGX_INSN_SHLX
, true, "iii" },
3309 { "__insn_shlxi", TILEGX_INSN_SHLX
, true, "iii" },
3310 { "__insn_shrs", TILEGX_INSN_SHRS
, true, "lli" },
3311 { "__insn_shrsi", TILEGX_INSN_SHRS
, true, "lli" },
3312 { "__insn_shru", TILEGX_INSN_SHRU
, true, "lli" },
3313 { "__insn_shrui", TILEGX_INSN_SHRU
, true, "lli" },
3314 { "__insn_shrux", TILEGX_INSN_SHRUX
, true, "iii" },
3315 { "__insn_shruxi", TILEGX_INSN_SHRUX
, true, "iii" },
3316 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES
, true, "llll" },
3317 { "__insn_shufflebytes1", TILEGX_INSN_SHUFFLEBYTES1
, true, "lll" },
3318 { "__insn_st", TILEGX_INSN_ST
, false, "vpl" },
3319 { "__insn_st1", TILEGX_INSN_ST1
, false, "vpl" },
3320 { "__insn_st2", TILEGX_INSN_ST2
, false, "vpl" },
3321 { "__insn_st4", TILEGX_INSN_ST4
, false, "vpl" },
3322 { "__insn_stnt", TILEGX_INSN_STNT
, false, "vpl" },
3323 { "__insn_stnt1", TILEGX_INSN_STNT1
, false, "vpl" },
3324 { "__insn_stnt2", TILEGX_INSN_STNT2
, false, "vpl" },
3325 { "__insn_stnt4", TILEGX_INSN_STNT4
, false, "vpl" },
3326 { "__insn_sub", TILEGX_INSN_SUB
, true, "lll" },
3327 { "__insn_subx", TILEGX_INSN_SUBX
, true, "iii" },
3328 { "__insn_subxsc", TILEGX_INSN_SUBXSC
, true, "iii" },
3329 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0
, true, "lll" },
3330 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1
, true, "lll" },
3331 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2
, true, "lll" },
3332 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3
, true, "lll" },
3333 { "__insn_v1add", TILEGX_INSN_V1ADD
, true, "lll" },
3334 { "__insn_v1addi", TILEGX_INSN_V1ADDI
, true, "lll" },
3335 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC
, true, "lll" },
3336 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU
, true, "lll" },
3337 { "__insn_v1avgu", TILEGX_INSN_V1AVGU
, true, "lll" },
3338 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ
, true, "lll" },
3339 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI
, true, "lll" },
3340 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES
, true, "lll" },
3341 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU
, true, "lll" },
3342 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS
, true, "lll" },
3343 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI
, true, "lll" },
3344 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU
, true, "lll" },
3345 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI
, true, "lll" },
3346 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE
, true, "lll" },
3347 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU
, true, "lll" },
3348 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA
, true, "llll" },
3349 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS
, true, "lll" },
3350 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA
, true, "llll" },
3351 { "__insn_v1dotp", TILEGX_INSN_V1DOTP
, true, "lll" },
3352 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA
, true, "llll" },
3353 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU
, true, "lll" },
3354 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA
, true, "llll" },
3355 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS
, true, "lll" },
3356 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA
, true, "llll" },
3357 { "__insn_v1int_h", TILEGX_INSN_V1INT_H
, true, "lll" },
3358 { "__insn_v1int_l", TILEGX_INSN_V1INT_L
, true, "lll" },
3359 { "__insn_v1maxu", TILEGX_INSN_V1MAXU
, true, "lll" },
3360 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI
, true, "lll" },
3361 { "__insn_v1minu", TILEGX_INSN_V1MINU
, true, "lll" },
3362 { "__insn_v1minui", TILEGX_INSN_V1MINUI
, true, "lll" },
3363 { "__insn_v1mnz", TILEGX_INSN_V1MNZ
, true, "lll" },
3364 { "__insn_v1multu", TILEGX_INSN_V1MULTU
, true, "lll" },
3365 { "__insn_v1mulu", TILEGX_INSN_V1MULU
, true, "lll" },
3366 { "__insn_v1mulus", TILEGX_INSN_V1MULUS
, true, "lll" },
3367 { "__insn_v1mz", TILEGX_INSN_V1MZ
, true, "lll" },
3368 { "__insn_v1sadau", TILEGX_INSN_V1SADAU
, true, "llll" },
3369 { "__insn_v1sadu", TILEGX_INSN_V1SADU
, true, "lll" },
3370 { "__insn_v1shl", TILEGX_INSN_V1SHL
, true, "lll" },
3371 { "__insn_v1shli", TILEGX_INSN_V1SHLI
, true, "lll" },
3372 { "__insn_v1shrs", TILEGX_INSN_V1SHRS
, true, "lll" },
3373 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI
, true, "lll" },
3374 { "__insn_v1shru", TILEGX_INSN_V1SHRU
, true, "lll" },
3375 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI
, true, "lll" },
3376 { "__insn_v1sub", TILEGX_INSN_V1SUB
, true, "lll" },
3377 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC
, true, "lll" },
3378 { "__insn_v2add", TILEGX_INSN_V2ADD
, true, "lll" },
3379 { "__insn_v2addi", TILEGX_INSN_V2ADDI
, true, "lll" },
3380 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC
, true, "lll" },
3381 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS
, true, "lll" },
3382 { "__insn_v2avgs", TILEGX_INSN_V2AVGS
, true, "lll" },
3383 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ
, true, "lll" },
3384 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI
, true, "lll" },
3385 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES
, true, "lll" },
3386 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU
, true, "lll" },
3387 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS
, true, "lll" },
3388 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI
, true, "lll" },
3389 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU
, true, "lll" },
3390 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI
, true, "lll" },
3391 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE
, true, "lll" },
3392 { "__insn_v2dotp", TILEGX_INSN_V2DOTP
, true, "lll" },
3393 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA
, true, "llll" },
3394 { "__insn_v2int_h", TILEGX_INSN_V2INT_H
, true, "lll" },
3395 { "__insn_v2int_l", TILEGX_INSN_V2INT_L
, true, "lll" },
3396 { "__insn_v2maxs", TILEGX_INSN_V2MAXS
, true, "lll" },
3397 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI
, true, "lll" },
3398 { "__insn_v2mins", TILEGX_INSN_V2MINS
, true, "lll" },
3399 { "__insn_v2minsi", TILEGX_INSN_V2MINSI
, true, "lll" },
3400 { "__insn_v2mnz", TILEGX_INSN_V2MNZ
, true, "lll" },
3401 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC
, true, "lll" },
3402 { "__insn_v2muls", TILEGX_INSN_V2MULS
, true, "lll" },
3403 { "__insn_v2mults", TILEGX_INSN_V2MULTS
, true, "lll" },
3404 { "__insn_v2mz", TILEGX_INSN_V2MZ
, true, "lll" },
3405 { "__insn_v2packh", TILEGX_INSN_V2PACKH
, true, "lll" },
3406 { "__insn_v2packl", TILEGX_INSN_V2PACKL
, true, "lll" },
3407 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC
, true, "lll" },
3408 { "__insn_v2sadas", TILEGX_INSN_V2SADAS
, true, "llll" },
3409 { "__insn_v2sadau", TILEGX_INSN_V2SADAU
, true, "llll" },
3410 { "__insn_v2sads", TILEGX_INSN_V2SADS
, true, "lll" },
3411 { "__insn_v2sadu", TILEGX_INSN_V2SADU
, true, "lll" },
3412 { "__insn_v2shl", TILEGX_INSN_V2SHL
, true, "lll" },
3413 { "__insn_v2shli", TILEGX_INSN_V2SHLI
, true, "lll" },
3414 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC
, true, "lll" },
3415 { "__insn_v2shrs", TILEGX_INSN_V2SHRS
, true, "lll" },
3416 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI
, true, "lll" },
3417 { "__insn_v2shru", TILEGX_INSN_V2SHRU
, true, "lll" },
3418 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI
, true, "lll" },
3419 { "__insn_v2sub", TILEGX_INSN_V2SUB
, true, "lll" },
3420 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC
, true, "lll" },
3421 { "__insn_v4add", TILEGX_INSN_V4ADD
, true, "lll" },
3422 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC
, true, "lll" },
3423 { "__insn_v4int_h", TILEGX_INSN_V4INT_H
, true, "lll" },
3424 { "__insn_v4int_l", TILEGX_INSN_V4INT_L
, true, "lll" },
3425 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC
, true, "lll" },
3426 { "__insn_v4shl", TILEGX_INSN_V4SHL
, true, "lll" },
3427 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC
, true, "lll" },
3428 { "__insn_v4shrs", TILEGX_INSN_V4SHRS
, true, "lll" },
3429 { "__insn_v4shru", TILEGX_INSN_V4SHRU
, true, "lll" },
3430 { "__insn_v4sub", TILEGX_INSN_V4SUB
, true, "lll" },
3431 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC
, true, "lll" },
3432 { "__insn_wh64", TILEGX_INSN_WH64
, false, "vp" },
3433 { "__insn_xor", TILEGX_INSN_XOR
, true, "lll" },
3434 { "__insn_xori", TILEGX_INSN_XOR
, true, "lll" },
3435 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER
, false, "v" },
3436 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE
, false, "l" },
3437 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE
, false, "l" },
3438 { "__tile_idn_send", TILEGX_IDN_SEND
, false, "vl" },
3439 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE
, false, "l" },
3440 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE
, false, "l" },
3441 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE
, false, "l" },
3442 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE
, false, "l" },
3443 { "__tile_udn_send", TILEGX_UDN_SEND
, false, "vl" },
3447 /* Convert a character in a builtin type string to a tree type. */
3449 char_to_type (char c
)
3451 static tree volatile_ptr_type_node
= NULL
;
3452 static tree volatile_const_ptr_type_node
= NULL
;
3454 if (volatile_ptr_type_node
== NULL
)
3456 volatile_ptr_type_node
=
3457 build_pointer_type (build_qualified_type (void_type_node
,
3458 TYPE_QUAL_VOLATILE
));
3459 volatile_const_ptr_type_node
=
3460 build_pointer_type (build_qualified_type (void_type_node
,
3462 | TYPE_QUAL_VOLATILE
));
3468 return void_type_node
;
3470 return unsigned_type_node
;
3472 return long_long_unsigned_type_node
;
3474 return volatile_ptr_type_node
;
3476 return volatile_const_ptr_type_node
;
3483 /* Implement TARGET_INIT_BUILTINS. */
3485 tilegx_init_builtins (void)
3489 for (i
= 0; i
< ARRAY_SIZE (tilegx_builtins
); i
++)
3491 const struct tilegx_builtin_def
*p
= &tilegx_builtins
[i
];
3492 tree ftype
, ret_type
, arg_type_list
= void_list_node
;
3496 for (j
= strlen (p
->type
) - 1; j
> 0; j
--)
3499 tree_cons (NULL_TREE
, char_to_type (p
->type
[j
]), arg_type_list
);
3502 ret_type
= char_to_type (p
->type
[0]);
3504 ftype
= build_function_type (ret_type
, arg_type_list
);
3506 decl
= add_builtin_function (p
->name
, ftype
, p
->code
, BUILT_IN_MD
,
3510 TREE_READONLY (decl
) = 1;
3511 TREE_NOTHROW (decl
) = 1;
3513 if (tilegx_builtin_info
[p
->code
].fndecl
== NULL
)
3514 tilegx_builtin_info
[p
->code
].fndecl
= decl
;
3519 /* Implement TARGET_EXPAND_BUILTIN. */
3521 tilegx_expand_builtin (tree exp
,
3523 rtx subtarget ATTRIBUTE_UNUSED
,
3524 machine_mode mode ATTRIBUTE_UNUSED
,
3525 int ignore ATTRIBUTE_UNUSED
)
3527 #define MAX_BUILTIN_ARGS 4
3529 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
3530 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
3532 call_expr_arg_iterator iter
;
3533 enum insn_code icode
;
3534 rtx op
[MAX_BUILTIN_ARGS
+ 1], pat
;
3539 if (fcode
>= TILEGX_BUILTIN_max
)
3540 internal_error ("bad builtin fcode");
3541 icode
= tilegx_builtin_info
[fcode
].icode
;
3543 internal_error ("bad builtin icode");
3545 nonvoid
= TREE_TYPE (TREE_TYPE (fndecl
)) != void_type_node
;
3548 FOR_EACH_CALL_EXPR_ARG (arg
, iter
, exp
)
3550 const struct insn_operand_data
*insn_op
;
3552 if (arg
== error_mark_node
)
3554 if (opnum
> MAX_BUILTIN_ARGS
)
3557 insn_op
= &insn_data
[icode
].operand
[opnum
];
3559 op
[opnum
] = expand_expr (arg
, NULL_RTX
, insn_op
->mode
, EXPAND_NORMAL
);
3561 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3563 machine_mode opmode
= insn_op
->mode
;
3565 /* pointer_operand and pmode_register_operand operands do
3566 not specify a mode, so use the operand's mode instead
3567 (which should always be right by the time we get here,
3568 except for constants, which are VOIDmode). */
3569 if (opmode
== VOIDmode
)
3571 machine_mode m
= GET_MODE (op
[opnum
]);
3572 gcc_assert (m
== Pmode
|| m
== VOIDmode
);
3576 op
[opnum
] = copy_to_mode_reg (opmode
, op
[opnum
]);
3579 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3581 /* We still failed to meet the predicate even after moving
3582 into a register. Assume we needed an immediate. */
3583 error_at (EXPR_LOCATION (exp
),
3584 "operand must be an immediate of the right size");
3593 machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
3595 || GET_MODE (target
) != tmode
3596 || !(*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
3598 if (tmode
== VOIDmode
)
3600 /* get the mode from the return type. */
3601 tmode
= TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl
)));
3603 target
= gen_reg_rtx (tmode
);
3608 fn
= GEN_FCN (icode
);
3612 pat
= fn (NULL_RTX
);
3618 pat
= fn (op
[0], op
[1]);
3621 pat
= fn (op
[0], op
[1], op
[2]);
3624 pat
= fn (op
[0], op
[1], op
[2], op
[3]);
3627 pat
= fn (op
[0], op
[1], op
[2], op
[3], op
[4]);
3635 /* If we are generating a prefetch, tell the scheduler not to move
3637 if (GET_CODE (pat
) == PREFETCH
)
3638 PREFETCH_SCHEDULE_BARRIER_P (pat
) = true;
3649 /* Implement TARGET_BUILTIN_DECL. */
3651 tilegx_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
3653 if (code
>= TILEGX_BUILTIN_max
)
3654 return error_mark_node
;
3656 return tilegx_builtin_info
[code
].fndecl
;
3663 /* Return whether REGNO needs to be saved in the stack frame. */
3665 need_to_save_reg (unsigned int regno
)
3667 if (!fixed_regs
[regno
] && !call_used_regs
[regno
]
3668 && df_regs_ever_live_p (regno
))
3672 && (regno
== PIC_OFFSET_TABLE_REGNUM
3673 || regno
== TILEGX_PIC_TEXT_LABEL_REGNUM
)
3674 && (crtl
->uses_pic_offset_table
|| crtl
->saves_all_registers
))
3677 if (crtl
->calls_eh_return
)
3680 for (i
= 0; EH_RETURN_DATA_REGNO (i
) != INVALID_REGNUM
; i
++)
3682 if (regno
== EH_RETURN_DATA_REGNO (i
))
3691 /* Return the size of the register savev area. This function is only
3692 correct starting with local register allocation */
3694 tilegx_saved_regs_size (void)
3696 int reg_save_size
= 0;
3698 int offset_to_frame
;
3701 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
3702 if (need_to_save_reg (regno
))
3703 reg_save_size
+= UNITS_PER_WORD
;
3705 /* Pad out the register save area if necessary to make
3706 frame_pointer_rtx be as aligned as the stack pointer. */
3707 offset_to_frame
= crtl
->args
.pretend_args_size
+ reg_save_size
;
3708 align_mask
= (STACK_BOUNDARY
/ BITS_PER_UNIT
) - 1;
3709 reg_save_size
+= (-offset_to_frame
) & align_mask
;
3711 return reg_save_size
;
3715 /* Round up frame size SIZE. */
3717 round_frame_size (int size
)
3719 return ((size
+ STACK_BOUNDARY
/ BITS_PER_UNIT
- 1)
3720 & -STACK_BOUNDARY
/ BITS_PER_UNIT
);
3724 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3725 emit the corresponding REG_CFA_OFFSET note described by CFA and
3726 CFA_OFFSET. Return the emitted insn. */
3728 frame_emit_store (int regno
, int regno_note
, rtx addr
, rtx cfa
,
3731 rtx reg
= gen_rtx_REG (DImode
, regno
);
3732 rtx mem
= gen_frame_mem (DImode
, addr
);
3733 rtx mov
= gen_movdi (mem
, reg
);
3735 /* Describe what just happened in a way that dwarf understands. We
3736 use temporary registers to hold the address to make scheduling
3737 easier, and use the REG_CFA_OFFSET to describe the address as an
3738 offset from the CFA. */
3739 rtx reg_note
= gen_rtx_REG (DImode
, regno_note
);
3740 rtx cfa_relative_addr
= gen_rtx_PLUS (Pmode
, cfa
, GEN_INT (cfa_offset
));
3741 rtx cfa_relative_mem
= gen_frame_mem (DImode
, cfa_relative_addr
);
3742 rtx real
= gen_rtx_SET (cfa_relative_mem
, reg_note
);
3743 add_reg_note (mov
, REG_CFA_OFFSET
, real
);
3745 return emit_insn (mov
);
3749 /* Emit a load in the stack frame to load REGNO from address ADDR.
3750 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3751 non-null. Return the emitted insn. */
3753 frame_emit_load (int regno
, rtx addr
, rtx
*cfa_restores
)
3755 rtx reg
= gen_rtx_REG (DImode
, regno
);
3756 rtx mem
= gen_frame_mem (DImode
, addr
);
3758 *cfa_restores
= alloc_reg_note (REG_CFA_RESTORE
, reg
, *cfa_restores
);
3759 return emit_insn (gen_movdi (reg
, mem
));
3763 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3764 including sequences. */
3766 set_frame_related_p (void)
3768 rtx_insn
*seq
= get_insns ();
3779 while (insn
!= NULL_RTX
)
3781 RTX_FRAME_RELATED_P (insn
) = 1;
3782 insn
= NEXT_INSN (insn
);
3784 seq
= emit_insn (seq
);
3788 seq
= emit_insn (seq
);
3789 RTX_FRAME_RELATED_P (seq
) = 1;
3795 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3797 /* This emits code for 'sp += offset'.
3799 The ABI only allows us to modify 'sp' in a single 'addi' or
3800 'addli', so the backtracer understands it. Larger amounts cannot
3801 use those instructions, so are added by placing the offset into a
3802 large register and using 'add'.
3804 This happens after reload, so we need to expand it ourselves. */
3806 emit_sp_adjust (int offset
, int *next_scratch_regno
, bool frame_related
,
3810 rtx imm_rtx
= GEN_INT (offset
);
3814 if (satisfies_constraint_J (imm_rtx
))
3816 /* We can add this using a single immediate add. */
3821 rtx tmp
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3822 tilegx_expand_set_const64 (tmp
, imm_rtx
);
3826 /* Actually adjust the stack pointer. */
3828 pat
= gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3830 pat
= gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3832 insn
= emit_insn (pat
);
3833 REG_NOTES (insn
) = reg_notes
;
3835 /* Describe what just happened in a way that dwarf understands. */
3838 rtx real
= gen_rtx_SET (stack_pointer_rtx
,
3839 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3841 RTX_FRAME_RELATED_P (insn
) = 1;
3842 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, real
);
3849 /* Return whether the current function is leaf. This takes into
3850 account whether the function calls tls_get_addr. */
3852 tilegx_current_function_is_leaf (void)
3854 return crtl
->is_leaf
&& !cfun
->machine
->calls_tls_get_addr
;
3858 /* Return the frame size. */
3860 compute_total_frame_size (void)
3862 int total_size
= (get_frame_size () + tilegx_saved_regs_size ()
3863 + crtl
->outgoing_args_size
3864 + crtl
->args
.pretend_args_size
);
3866 if (!tilegx_current_function_is_leaf () || cfun
->calls_alloca
)
3868 /* Make room for save area in callee. */
3869 total_size
+= STACK_POINTER_OFFSET
;
3872 return round_frame_size (total_size
);
3876 /* Return nonzero if this function is known to have a null epilogue.
3877 This allows the optimizer to omit jumps to jumps if no stack was
3880 tilegx_can_use_return_insn_p (void)
3882 return (reload_completed
3883 && cfun
->static_chain_decl
== 0
3884 && compute_total_frame_size () == 0
3885 && tilegx_current_function_is_leaf ()
3886 && !crtl
->profile
&& !df_regs_ever_live_p (TILEGX_LINK_REGNUM
));
3890 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3891 is a frame pointer, it computes the value relative to
3892 that. Otherwise it uses the stack pointer. */
3894 compute_frame_addr (int offset_from_fp
, int *next_scratch_regno
)
3896 rtx base_reg_rtx
, tmp_reg_rtx
, offset_rtx
;
3897 int offset_from_base
;
3899 if (frame_pointer_needed
)
3901 base_reg_rtx
= hard_frame_pointer_rtx
;
3902 offset_from_base
= offset_from_fp
;
3906 int offset_from_sp
= compute_total_frame_size () + offset_from_fp
;
3907 offset_from_base
= offset_from_sp
;
3908 base_reg_rtx
= stack_pointer_rtx
;
3911 if (offset_from_base
== 0)
3912 return base_reg_rtx
;
3914 /* Compute the new value of the stack pointer. */
3915 tmp_reg_rtx
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3916 offset_rtx
= GEN_INT (offset_from_base
);
3918 if (!add_operand (offset_rtx
, Pmode
))
3920 expand_set_cint64 (tmp_reg_rtx
, offset_rtx
);
3921 offset_rtx
= tmp_reg_rtx
;
3924 emit_insn (gen_rtx_SET (tmp_reg_rtx
,
3925 gen_rtx_PLUS (Pmode
, base_reg_rtx
, offset_rtx
)));
3931 /* The stack frame looks like this:
3936 AP -> +-------------+
3940 HFP -> +-------------+
3942 | reg save | crtl->args.pretend_args_size bytes
3945 | saved regs | tilegx_saved_regs_size() bytes
3946 FP -> +-------------+
3948 | vars | get_frame_size() bytes
3952 | stack args | crtl->outgoing_args_size bytes
3954 | HFP | ptr_size bytes (only here if nonleaf / alloca)
3956 | callee lr | ptr_size bytes (only here if nonleaf / alloca)
3958 SP -> +-------------+
3962 For functions with a frame larger than 32767 bytes, or which use
3963 alloca (), r52 is used as a frame pointer. Otherwise there is no
3966 FP is saved at SP+ptr_size before calling a subroutine so the callee
3969 tilegx_expand_prologue (void)
3971 #define ROUND_ROBIN_SIZE 4
3972 /* We round-robin through four scratch registers to hold temporary
3973 addresses for saving registers, to make instruction scheduling
3975 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
3976 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
3979 unsigned int which_scratch
;
3980 int offset
, start_offset
, regno
;
3982 /* A register that holds a copy of the incoming fp. */
3983 int fp_copy_regno
= -1;
3985 /* A register that holds a copy of the incoming sp. */
3986 int sp_copy_regno
= -1;
3988 /* Next scratch register number to hand out (postdecrementing). */
3989 int next_scratch_regno
= 29;
3991 int total_size
= compute_total_frame_size ();
3993 if (flag_stack_usage_info
)
3994 current_function_static_stack_size
= total_size
;
3996 /* Save lr first in its special location because code after this
3997 might use the link register as a scratch register. */
3998 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
) || crtl
->calls_eh_return
)
3999 FRP (frame_emit_store (TILEGX_LINK_REGNUM
, TILEGX_LINK_REGNUM
,
4000 stack_pointer_rtx
, stack_pointer_rtx
, 0));
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. It is a
4346 member of fixed_regs, and therefore must be member of
4347 call_used_regs, but it is not a member of call_really_used_regs[]
4348 because it is not clobbered by a call. */
4349 if (TILEGX_PIC_TEXT_LABEL_REGNUM
!= INVALID_REGNUM
)
4351 fixed_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4352 call_used_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4354 if (PIC_OFFSET_TABLE_REGNUM
!= INVALID_REGNUM
)
4356 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4357 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4362 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
4364 tilegx_frame_pointer_required (void)
4366 return crtl
->calls_eh_return
|| cfun
->calls_alloca
;
4371 /* Scheduling and reorg */
4373 /* Return the length of INSN. LENGTH is the initial length computed
4374 by attributes in the machine-description file. This is where we
4375 account for bundles. */
4377 tilegx_adjust_insn_length (rtx_insn
*insn
, int length
)
4379 machine_mode mode
= GET_MODE (insn
);
4381 /* A non-termininating instruction in a bundle has length 0. */
4385 /* By default, there is not length adjustment. */
4390 /* Implement TARGET_SCHED_ISSUE_RATE. */
4392 tilegx_issue_rate (void)
4398 /* Return the rtx for the jump target. */
4400 get_jump_target (rtx branch
)
4402 if (CALL_P (branch
))
4405 call
= PATTERN (branch
);
4407 if (GET_CODE (call
) == PARALLEL
)
4408 call
= XVECEXP (call
, 0, 0);
4410 if (GET_CODE (call
) == SET
)
4411 call
= SET_SRC (call
);
4413 if (GET_CODE (call
) == CALL
)
4414 return XEXP (XEXP (call
, 0), 0);
4420 /* Implement TARGET_SCHED_ADJUST_COST. */
4422 tilegx_sched_adjust_cost (rtx_insn
*insn
, int dep_type
, rtx_insn
*dep_insn
,
4423 int cost
, unsigned int)
4425 /* If we have a true dependence, INSN is a call, and DEP_INSN
4426 defines a register that is needed by the call (argument or stack
4427 pointer) , set its latency to 0 so that it can be bundled with
4428 the call. Explicitly check for and exclude the case when
4429 DEP_INSN defines the target of the jump. */
4430 if (CALL_P (insn
) && dep_type
== REG_DEP_TRUE
)
4432 rtx target
= get_jump_target (insn
);
4433 if (!REG_P (target
) || !set_of (target
, dep_insn
))
4441 /* Skip over irrelevant NOTEs and such and look for the next insn we
4442 would consider bundling. */
4444 next_insn_to_bundle (rtx_insn
*r
, rtx_insn
*end
)
4446 for (; r
!= end
; r
= NEXT_INSN (r
))
4448 if (NONDEBUG_INSN_P (r
)
4449 && GET_CODE (PATTERN (r
)) != USE
4450 && GET_CODE (PATTERN (r
)) != CLOBBER
)
4458 /* Go through all insns, and use the information generated during
4459 scheduling to generate SEQUENCEs to represent bundles of
4460 instructions issued simultaneously. */
4462 tilegx_gen_bundles (void)
4465 FOR_EACH_BB_FN (bb
, cfun
)
4467 rtx_insn
*insn
, *next
, *prev
;
4468 rtx_insn
*end
= NEXT_INSN (BB_END (bb
));
4471 for (insn
= next_insn_to_bundle (BB_HEAD (bb
), end
); insn
;
4472 prev
= insn
, insn
= next
)
4474 next
= next_insn_to_bundle (NEXT_INSN (insn
), end
);
4476 /* Never wrap {} around inline asm. */
4477 if (GET_CODE (PATTERN (insn
)) != ASM_INPUT
)
4479 if (next
== NULL_RTX
|| GET_MODE (next
) == TImode
4480 /* NOTE: The scheduler incorrectly believes a call
4481 insn can execute in the same cycle as the insn
4482 after the call. This is of course impossible.
4483 Really we need to fix the scheduler somehow, so
4484 the code after the call gets scheduled
4488 /* Mark current insn as the end of a bundle. */
4489 PUT_MODE (insn
, QImode
);
4493 /* Mark it as part of a bundle. */
4494 PUT_MODE (insn
, SImode
);
4498 /* Delete barrier insns, because they can mess up the
4499 emitting of bundle braces. If it is end-of-bundle, then
4500 the previous insn must be marked end-of-bundle. */
4501 if (get_attr_type (insn
) == TYPE_NOTHING
) {
4502 if (GET_MODE (insn
) == QImode
&& prev
!= NULL
4503 && GET_MODE (prev
) == SImode
)
4505 PUT_MODE (prev
, QImode
);
4514 /* Replace OLD_INSN with NEW_INSN. */
4516 replace_insns (rtx_insn
*old_insn
, rtx_insn
*new_insns
)
4519 emit_insn_before (new_insns
, old_insn
);
4521 delete_insn (old_insn
);
4525 /* Returns true if INSN is the first instruction of a pc-relative
4526 address compuatation. */
4528 match_pcrel_step1 (rtx insn
)
4530 rtx pattern
= PATTERN (insn
);
4533 if (GET_CODE (pattern
) != SET
)
4536 src
= SET_SRC (pattern
);
4538 return (GET_CODE (src
) == CONST
4539 && GET_CODE (XEXP (src
, 0)) == UNSPEC
4540 && XINT (XEXP (src
, 0), 1) == UNSPEC_HW1_LAST_PCREL
);
4544 /* Do the first replacement step in tilegx_fixup_pcrel_references. */
4546 replace_mov_pcrel_step1 (rtx_insn
*insn
)
4548 rtx pattern
= PATTERN (insn
);
4551 rtx_insn
*new_insns
;
4553 gcc_assert (GET_CODE (pattern
) == SET
);
4554 opnds
[0] = SET_DEST (pattern
);
4556 gcc_assert (GET_CODE (SET_SRC (pattern
)) == CONST
);
4558 unspec
= XEXP (SET_SRC (pattern
), 0);
4559 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4560 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW1_LAST_PCREL
);
4561 opnds
[1] = XVECEXP (unspec
, 0, 0);
4563 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4564 if (GET_CODE (opnds
[1]) != SYMBOL_REF
)
4572 emit_insn (gen_mov_got32_step1_32bit (opnds
[0], opnds
[1]));
4574 emit_insn (gen_mov_got32_step1 (opnds
[0], opnds
[1]));
4577 new_insns
= get_insns ();
4580 replace_insns (insn
, new_insns
);
4584 /* Returns true if INSN is the second instruction of a pc-relative
4585 address compuatation. */
4587 match_pcrel_step2 (rtx_insn
*insn
)
4594 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli_32bit
)
4599 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli
)
4603 unspec
= SET_SRC (PATTERN (insn
));
4604 addr
= XVECEXP (unspec
, 0, 1);
4606 return (GET_CODE (addr
) == CONST
4607 && GET_CODE (XEXP (addr
, 0)) == UNSPEC
4608 && XINT (XEXP (addr
, 0), 1) == UNSPEC_HW0_PCREL
);
4612 /* Do the second replacement step in tilegx_fixup_pcrel_references. */
4614 replace_mov_pcrel_step2 (rtx_insn
*insn
)
4616 rtx pattern
= PATTERN (insn
);
4620 rtx_insn
*new_insns
;
4621 rtx got_rtx
= tilegx_got_rtx ();
4623 gcc_assert (GET_CODE (pattern
) == SET
);
4624 opnds
[0] = SET_DEST (pattern
);
4626 unspec
= SET_SRC (pattern
);
4627 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4628 gcc_assert (XINT (unspec
, 1) == UNSPEC_INSN_ADDR_SHL16INSLI
);
4630 opnds
[1] = XVECEXP (unspec
, 0, 0);
4632 addr
= XVECEXP (unspec
, 0, 1);
4633 gcc_assert (GET_CODE (addr
) == CONST
);
4635 unspec
= XEXP (addr
, 0);
4636 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4637 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW0_PCREL
);
4638 opnds
[2] = XVECEXP (unspec
, 0, 0);
4640 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4641 if (GET_CODE (opnds
[2]) != SYMBOL_REF
)
4649 emit_insn (gen_add_got16_32bit (opnds
[0], got_rtx
, opnds
[2]));
4651 emit_insn (gen_add_got16 (opnds
[0], got_rtx
, opnds
[2]));
4656 emit_insn (gen_mov_got32_step2_32bit
4657 (opnds
[0], opnds
[1], opnds
[2]));
4659 emit_insn (gen_mov_got32_step2 (opnds
[0], opnds
[1], opnds
[2]));
4662 new_insns
= get_insns ();
4665 replace_insns (insn
, new_insns
);
4669 /* Do the third replacement step in tilegx_fixup_pcrel_references. */
4671 replace_mov_pcrel_step3 (rtx_insn
*insn
)
4673 rtx pattern
= PATTERN (insn
);
4676 rtx_insn
*new_insns
;
4677 rtx got_rtx
= tilegx_got_rtx ();
4678 rtx text_label_rtx
= tilegx_text_label_rtx ();
4680 gcc_assert (GET_CODE (pattern
) == SET
);
4681 opnds
[0] = SET_DEST (pattern
);
4683 unspec
= SET_SRC (pattern
);
4684 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4685 gcc_assert (XINT (unspec
, 1) == UNSPEC_MOV_PCREL_STEP3
);
4689 if (XVECEXP (unspec
, 0, 0) == text_label_rtx
)
4690 opnds
[2] = XVECEXP (unspec
, 0, 1);
4693 gcc_assert (XVECEXP (unspec
, 0, 1) == text_label_rtx
);
4694 opnds
[2] = XVECEXP (unspec
, 0, 0);
4697 opnds
[3] = XVECEXP (unspec
, 0, 2);
4699 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4700 if (GET_CODE (opnds
[3]) != SYMBOL_REF
)
4707 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[2]));
4711 emit_move_insn (opnds
[0], gen_rtx_PLUS (Pmode
, opnds
[1], opnds
[2]));
4712 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[0]));
4715 new_insns
= get_insns ();
4718 replace_insns (insn
, new_insns
);
4722 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4723 going through the GOT when the symbol is local to the compilation
4724 unit. But such a symbol requires that the common text_label that
4725 we generate at the beginning of the function be in the same section
4726 as the reference to the SYMBOL_REF. This may not be true if we
4727 generate hot/cold sections. This function looks for such cases and
4728 replaces such references with the longer sequence going through the
4731 We expect following instruction sequence:
4732 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4733 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4734 add<x> tmp3, txt_label_reg, tmp2 [3]
4736 If we're compiling -fpic, we replace with the following sequence
4737 (the numbers in brackets match the instructions they're replacing
4740 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4741 ld<4> tmp3, tmp2 [3]
4743 If we're compiling -fPIC, we replace the first instruction with:
4745 moveli tmp1, hw1_last_got(x) [1]
4746 shl16insli tmp2, tmp1, hw0_got(x) [2]
4747 add<x> tmp3, got_reg, tmp2 [3]
4748 ld<4> tmp3, tmp3 [3]
4750 Note that we're careful to disturb the instruction sequence as
4751 little as possible, since it's very late in the compilation
4754 tilegx_fixup_pcrel_references (void)
4756 rtx_insn
*insn
, *next_insn
;
4757 bool same_section_as_entry
= true;
4759 for (insn
= get_insns (); insn
; insn
= next_insn
)
4761 next_insn
= NEXT_INSN (insn
);
4763 if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_SWITCH_TEXT_SECTIONS
)
4765 same_section_as_entry
= !same_section_as_entry
;
4769 if (same_section_as_entry
)
4773 && GET_CODE (PATTERN (insn
)) != USE
4774 && GET_CODE (PATTERN (insn
)) != CLOBBER
))
4779 if (match_pcrel_step1 (insn
))
4780 replace_mov_pcrel_step1 (insn
);
4781 else if (match_pcrel_step2 (insn
))
4782 replace_mov_pcrel_step2 (insn
);
4783 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3_32bit
)
4784 replace_mov_pcrel_step3 (insn
);
4788 if (match_pcrel_step1 (insn
))
4789 replace_mov_pcrel_step1 (insn
);
4790 else if (match_pcrel_step2 (insn
))
4791 replace_mov_pcrel_step2 (insn
);
4792 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3
)
4793 replace_mov_pcrel_step3 (insn
);
4799 /* Ensure that no var tracking notes are emitted in the middle of a
4800 three-instruction bundle. */
4802 reorder_var_tracking_notes (void)
4805 FOR_EACH_BB_FN (bb
, cfun
)
4807 rtx_insn
*insn
, *next
;
4808 rtx_insn
*queue
= NULL
;
4809 bool in_bundle
= false;
4811 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4813 next
= NEXT_INSN (insn
);
4817 /* Emit queued up notes at the last instruction of a
4819 if (GET_MODE (insn
) == QImode
)
4823 rtx_insn
*next_queue
= PREV_INSN (queue
);
4824 SET_PREV_INSN (NEXT_INSN (insn
)) = queue
;
4825 SET_NEXT_INSN (queue
) = NEXT_INSN (insn
);
4826 SET_NEXT_INSN (insn
) = queue
;
4827 SET_PREV_INSN (queue
) = insn
;
4832 else if (GET_MODE (insn
) == SImode
)
4835 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4839 rtx_insn
*prev
= PREV_INSN (insn
);
4840 SET_PREV_INSN (next
) = prev
;
4841 SET_NEXT_INSN (prev
) = next
;
4843 SET_PREV_INSN (insn
) = queue
;
4852 /* Perform machine dependent operations on the rtl chain INSNS. */
4856 /* We are freeing block_for_insn in the toplev to keep compatibility
4857 with old MDEP_REORGS that are not CFG based. Recompute it
4859 compute_bb_for_insn ();
4861 if (flag_reorder_blocks_and_partition
)
4863 tilegx_fixup_pcrel_references ();
4866 if (flag_schedule_insns_after_reload
)
4870 timevar_push (TV_SCHED2
);
4872 timevar_pop (TV_SCHED2
);
4874 /* Examine the schedule to group into bundles. */
4875 tilegx_gen_bundles ();
4880 if (flag_var_tracking
)
4882 timevar_push (TV_VAR_TRACKING
);
4883 variable_tracking_main ();
4884 reorder_var_tracking_notes ();
4885 timevar_pop (TV_VAR_TRACKING
);
4888 df_finish_pass (false);
4895 /* Select a format to encode pointers in exception handling data.
4896 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4897 GLOBAL is true if the symbol may be affected by dynamic
4900 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED
, int global
)
4902 int type
= TARGET_32BIT
? DW_EH_PE_sdata4
: DW_EH_PE_sdata8
;
4903 return (global
? DW_EH_PE_indirect
: 0) | DW_EH_PE_pcrel
| type
;
4907 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4909 tilegx_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
4910 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
4913 rtx this_rtx
, funexp
, addend
;
4916 /* Pretend to be a post-reload pass while generating rtl. */
4917 reload_completed
= 1;
4919 /* Mark the end of the (empty) prologue. */
4920 emit_note (NOTE_INSN_PROLOGUE_END
);
4922 /* Find the "this" pointer. If the function returns a structure,
4923 the structure return pointer is in $1. */
4924 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
4925 this_rtx
= gen_rtx_REG (Pmode
, 1);
4927 this_rtx
= gen_rtx_REG (Pmode
, 0);
4929 /* Add DELTA to THIS_RTX. */
4930 if (!(delta
>= -32868 && delta
<= 32767))
4932 addend
= gen_rtx_REG (Pmode
, 29);
4933 emit_move_insn (addend
, GEN_INT (delta
));
4936 addend
= GEN_INT (delta
);
4939 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, addend
));
4941 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, addend
));
4943 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4948 tmp
= gen_rtx_REG (Pmode
, 29);
4949 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, this_rtx
));
4951 if (!(vcall_offset
>= -32868 && vcall_offset
<= 32767))
4953 addend
= gen_rtx_REG (Pmode
, 28);
4954 emit_move_insn (addend
, GEN_INT (vcall_offset
));
4957 addend
= GEN_INT (vcall_offset
);
4960 emit_insn (gen_addsi3 (tmp
, tmp
, addend
));
4962 emit_insn (gen_adddi3 (tmp
, tmp
, addend
));
4964 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, tmp
));
4967 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, tmp
));
4969 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, tmp
));
4972 /* Generate a tail call to the target function. */
4973 if (!TREE_USED (function
))
4975 assemble_external (function
);
4976 TREE_USED (function
) = 1;
4978 funexp
= XEXP (DECL_RTL (function
), 0);
4979 funexp
= gen_rtx_MEM (FUNCTION_MODE
, funexp
);
4980 insn
= emit_call_insn (gen_sibcall (funexp
, const0_rtx
));
4981 SIBLING_CALL_P (insn
) = 1;
4983 /* Run just enough of rest_of_compilation to get the insns emitted.
4984 There's not really enough bulk here to make other passes such as
4985 instruction scheduling worth while. Note that use_thunk calls
4986 assemble_start_function and assemble_end_function.
4988 We don't currently bundle, but the instruciton sequence is all
4989 serial except for the tail call, so we're only wasting one cycle.
4991 insn
= get_insns ();
4992 shorten_branches (insn
);
4993 final_start_function (insn
, file
, 1);
4994 final (insn
, file
, 1);
4995 final_end_function ();
4997 /* Stop pretending to be a post-reload pass. */
4998 reload_completed
= 0;
5002 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
5004 tilegx_asm_trampoline_template (FILE *file
)
5006 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
5009 fprintf (file
, "\tlnk r10\n");
5010 fprintf (file
, "\taddxi r10, r10, 32\n");
5011 fprintf (file
, "\tld4s_add r11, r10, %d\n", ptr_mode_size
);
5012 fprintf (file
, "\tld4s r10, r10\n");
5013 fprintf (file
, "\tjr r11\n");
5014 fprintf (file
, "\t.word 0 # <function address>\n");
5015 fprintf (file
, "\t.word 0 # <static chain value>\n");
5019 fprintf (file
, "\tlnk r10\n");
5020 fprintf (file
, "\taddi r10, r10, 32\n");
5021 fprintf (file
, "\tld_add r11, r10, %d\n", ptr_mode_size
);
5022 fprintf (file
, "\tld r10, r10\n");
5023 fprintf (file
, "\tjr r11\n");
5024 fprintf (file
, "\t.quad 0 # <function address>\n");
5025 fprintf (file
, "\t.quad 0 # <static chain value>\n");
5030 /* Implement TARGET_TRAMPOLINE_INIT. */
5032 tilegx_trampoline_init (rtx m_tramp
, tree fndecl
, rtx static_chain
)
5036 rtx begin_addr
, end_addr
;
5037 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
5039 fnaddr
= copy_to_reg (XEXP (DECL_RTL (fndecl
), 0));
5040 chaddr
= copy_to_reg (static_chain
);
5042 emit_block_move (m_tramp
, assemble_trampoline_template (),
5043 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
5045 mem
= adjust_address (m_tramp
, ptr_mode
,
5046 TRAMPOLINE_SIZE
- 2 * ptr_mode_size
);
5047 emit_move_insn (mem
, fnaddr
);
5048 mem
= adjust_address (m_tramp
, ptr_mode
,
5049 TRAMPOLINE_SIZE
- ptr_mode_size
);
5050 emit_move_insn (mem
, chaddr
);
5052 /* Get pointers to the beginning and end of the code block. */
5053 begin_addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
5054 end_addr
= force_reg (Pmode
, plus_constant (Pmode
, XEXP (m_tramp
, 0),
5057 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__clear_cache"),
5058 LCT_NORMAL
, VOIDmode
, 2, begin_addr
, Pmode
,
5063 /* Implement TARGET_PRINT_OPERAND. */
5065 tilegx_print_operand (FILE *file
, rtx x
, int code
)
5070 /* Print the compare operator opcode for conditional moves. */
5071 switch (GET_CODE (x
))
5080 output_operand_lossage ("invalid %%c operand");
5085 /* Print the compare operator opcode for conditional moves. */
5086 switch (GET_CODE (x
))
5095 output_operand_lossage ("invalid %%C operand");
5101 /* Print the compare operator opcode for conditional moves. */
5102 switch (GET_CODE (x
))
5111 output_operand_lossage ("invalid %%d operand");
5118 /* Print the compare operator opcode for conditional moves. */
5119 switch (GET_CODE (x
))
5128 output_operand_lossage ("invalid %%D operand");
5135 if (GET_CODE (x
) == CONST
5136 && GET_CODE (XEXP (x
, 0)) == UNSPEC
)
5138 rtx addr
= XVECEXP (XEXP (x
, 0), 0, 0);
5139 int unspec
= XINT (XEXP (x
, 0), 1);
5140 const char *opstr
= NULL
;
5144 case UNSPEC_HW0_PCREL
:
5148 case UNSPEC_HW1_PCREL
:
5157 case UNSPEC_HW0_LAST
:
5160 case UNSPEC_HW1_LAST
:
5161 case UNSPEC_HW1_LAST_PCREL
:
5164 case UNSPEC_HW2_LAST
:
5165 case UNSPEC_HW2_LAST_PCREL
:
5168 case UNSPEC_HW0_GOT
:
5171 case UNSPEC_HW0_LAST_GOT
:
5172 opstr
= "hw0_last_got";
5174 case UNSPEC_HW1_LAST_GOT
:
5175 opstr
= "hw1_last_got";
5177 case UNSPEC_HW0_TLS_GD
:
5178 opstr
= "hw0_tls_gd";
5180 case UNSPEC_HW1_LAST_TLS_GD
:
5181 opstr
= "hw1_last_tls_gd";
5183 case UNSPEC_HW0_TLS_IE
:
5184 opstr
= "hw0_tls_ie";
5186 case UNSPEC_HW1_LAST_TLS_IE
:
5187 opstr
= "hw1_last_tls_ie";
5189 case UNSPEC_HW0_TLS_LE
:
5190 opstr
= "hw0_tls_le";
5192 case UNSPEC_HW1_LAST_TLS_LE
:
5193 opstr
= "hw1_last_tls_le";
5195 case UNSPEC_HW0_PLT_PCREL
:
5198 case UNSPEC_HW1_PLT_PCREL
:
5201 case UNSPEC_HW1_LAST_PLT_PCREL
:
5202 opstr
= "hw1_last_plt";
5204 case UNSPEC_HW2_LAST_PLT_PCREL
:
5205 opstr
= "hw2_last_plt";
5208 output_operand_lossage ("invalid %%H specifier");
5211 fputs (opstr
, file
);
5213 output_addr_const (file
, addr
);
5215 if (unspec
== UNSPEC_HW0_PCREL
5216 || unspec
== UNSPEC_HW1_PCREL
5217 || unspec
== UNSPEC_HW1_LAST_PCREL
5218 || unspec
== UNSPEC_HW2_LAST_PCREL
5219 || unspec
== UNSPEC_HW0_PLT_PCREL
5220 || unspec
== UNSPEC_HW1_PLT_PCREL
5221 || unspec
== UNSPEC_HW1_LAST_PLT_PCREL
5222 || unspec
== UNSPEC_HW2_LAST_PLT_PCREL
)
5224 rtx addr2
= XVECEXP (XEXP (x
, 0), 0, 1);
5225 fputs (" - " , file
);
5226 output_addr_const (file
, addr2
);
5232 else if (symbolic_operand (x
, VOIDmode
))
5234 output_addr_const (file
, x
);
5242 /* Print the low 16 bits of a constant. */
5244 if (CONST_INT_P (x
))
5246 else if (GET_CODE (x
) == CONST_DOUBLE
)
5247 i
= CONST_DOUBLE_LOW (x
);
5250 output_operand_lossage ("invalid %%h operand");
5253 i
= trunc_int_for_mode (i
, HImode
);
5254 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5259 /* Print an auto-inc memory operand. */
5262 output_operand_lossage ("invalid %%I operand");
5266 output_memory_autoinc_first
= true;
5267 output_address (GET_MODE (x
), XEXP (x
, 0));
5271 /* Print an auto-inc memory operand. */
5274 output_operand_lossage ("invalid %%i operand");
5278 output_memory_autoinc_first
= false;
5279 output_address (GET_MODE (x
), XEXP (x
, 0));
5284 /* Print the low 8 bits of a constant. */
5286 if (CONST_INT_P (x
))
5288 else if (GET_CODE (x
) == CONST_DOUBLE
)
5289 i
= CONST_DOUBLE_LOW (x
);
5290 else if (GET_CODE (x
) == CONST_VECTOR
5291 && CONST_INT_P (CONST_VECTOR_ELT (x
, 0)))
5292 i
= INTVAL (CONST_VECTOR_ELT (x
, 0));
5295 output_operand_lossage ("invalid %%j operand");
5298 i
= trunc_int_for_mode (i
, QImode
);
5299 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5305 /* Print a constant plus one. */
5306 if (!CONST_INT_P (x
))
5308 output_operand_lossage ("invalid %%P operand");
5311 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (x
) + 1);
5318 /* Print a bfextu-style bit range. */
5319 int first_bit
, last_bit
;
5320 HOST_WIDE_INT flip
= (code
== 'm') ? ~0 : 0;
5322 if (!CONST_INT_P (x
)
5323 || !tilegx_bitfield_operand_p (INTVAL (x
) ^ flip
,
5324 &first_bit
, &last_bit
))
5326 output_operand_lossage ("invalid %%%c operand", code
);
5330 fprintf (file
, "%d, %d", first_bit
, last_bit
);
5336 const char *reg
= NULL
;
5338 /* Print a network register. */
5339 if (!CONST_INT_P (x
))
5341 output_operand_lossage ("invalid %%N operand");
5347 case TILEGX_NETREG_IDN0
: reg
= "idn0"; break;
5348 case TILEGX_NETREG_IDN1
: reg
= "idn1"; break;
5349 case TILEGX_NETREG_UDN0
: reg
= "udn0"; break;
5350 case TILEGX_NETREG_UDN1
: reg
= "udn1"; break;
5351 case TILEGX_NETREG_UDN2
: reg
= "udn2"; break;
5352 case TILEGX_NETREG_UDN3
: reg
= "udn3"; break;
5357 fprintf (file
, reg
);
5362 if (GET_CODE (x
) == SYMBOL_REF
)
5364 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5365 fprintf (file
, "plt(");
5366 output_addr_const (file
, x
);
5367 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5368 fprintf (file
, ")");
5371 output_addr_const (file
, x
);
5375 /* In this case we need a register. Use 'zero' if the operand
5378 || (GET_MODE (x
) != VOIDmode
&& x
== CONST0_RTX (GET_MODE (x
))))
5380 fputs ("zero", file
);
5383 else if (!REG_P (x
))
5385 output_operand_lossage ("invalid operand for 'r' specifier");
5393 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
5398 output_address (VOIDmode
, XEXP (x
, 0));
5403 output_addr_const (file
, x
);
5409 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5414 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5416 tilegx_print_operand_address (FILE *file
, machine_mode mode
, rtx addr
)
5418 if (GET_CODE (addr
) == POST_DEC
5419 || GET_CODE (addr
) == POST_INC
)
5421 int offset
= GET_MODE_SIZE (mode
);
5423 gcc_assert (mode
!= VOIDmode
);
5425 if (output_memory_autoinc_first
)
5426 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5428 fprintf (file
, "%d",
5429 GET_CODE (addr
) == POST_DEC
? -offset
: offset
);
5431 else if (GET_CODE (addr
) == POST_MODIFY
)
5433 gcc_assert (mode
!= VOIDmode
);
5435 gcc_assert (GET_CODE (XEXP (addr
, 1)) == PLUS
);
5437 if (output_memory_autoinc_first
)
5438 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5440 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
,
5441 INTVAL (XEXP (XEXP (addr
, 1), 1)));
5444 tilegx_print_operand (file
, addr
, 'r');
5448 /* Machine mode of current insn, for determining curly brace
5450 static machine_mode insn_mode
;
5453 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5455 tilegx_final_prescan_insn (rtx_insn
*insn
)
5457 /* Record this for tilegx_asm_output_opcode to examine. */
5458 insn_mode
= GET_MODE (insn
);
5462 /* While emitting asm, are we currently inside '{' for a bundle? */
5463 static bool tilegx_in_bundle
= false;
5465 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5466 appropriate given the bundling information recorded by
5467 tilegx_gen_bundles. */
5469 tilegx_asm_output_opcode (FILE *stream
, const char *code
)
5471 bool pseudo
= !strcmp (code
, "pseudo");
5473 if (!tilegx_in_bundle
&& insn_mode
== SImode
)
5475 /* Start a new bundle. */
5476 fprintf (stream
, "{\n\t");
5477 tilegx_in_bundle
= true;
5480 if (tilegx_in_bundle
&& insn_mode
== QImode
)
5482 /* Close an existing bundle. */
5483 static char buf
[100];
5485 gcc_assert (strlen (code
) + 3 + 1 < sizeof (buf
));
5487 strcpy (buf
, pseudo
? "" : code
);
5488 strcat (buf
, "\n\t}");
5489 tilegx_in_bundle
= false;
5495 return pseudo
? "" : code
;
5500 /* Output assembler code to FILE to increment profiler label # LABELNO
5501 for profiling a function entry. */
5503 tilegx_function_profiler (FILE *file
, int labelno ATTRIBUTE_UNUSED
)
5505 if (tilegx_in_bundle
)
5507 fprintf (file
, "\t}\n");
5516 "\t}\n", MCOUNT_NAME
);
5524 "\t}\n", MCOUNT_NAME
);
5527 tilegx_in_bundle
= false;
5531 /* Implement TARGET_ASM_FILE_END. */
5533 tilegx_file_end (void)
5535 if (NEED_INDICATE_EXEC_STACK
)
5536 file_end_indicate_exec_stack ();
5541 #undef TARGET_HAVE_TLS
5542 #define TARGET_HAVE_TLS HAVE_AS_TLS
5544 #undef TARGET_OPTION_OVERRIDE
5545 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5547 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5548 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5550 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5551 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5553 #undef TARGET_CANNOT_FORCE_CONST_MEM
5554 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5556 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5557 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5559 #undef TARGET_PASS_BY_REFERENCE
5560 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5562 #undef TARGET_RETURN_IN_MSB
5563 #define TARGET_RETURN_IN_MSB tilegx_return_in_msb
5565 #undef TARGET_RETURN_IN_MEMORY
5566 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5568 #undef TARGET_MODE_REP_EXTENDED
5569 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5571 #undef TARGET_FUNCTION_ARG_BOUNDARY
5572 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5574 #undef TARGET_FUNCTION_ARG
5575 #define TARGET_FUNCTION_ARG tilegx_function_arg
5577 #undef TARGET_FUNCTION_ARG_ADVANCE
5578 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5580 #undef TARGET_FUNCTION_VALUE
5581 #define TARGET_FUNCTION_VALUE tilegx_function_value
5583 #undef TARGET_LIBCALL_VALUE
5584 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5586 #undef TARGET_FUNCTION_VALUE_REGNO_P
5587 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5589 #undef TARGET_PROMOTE_FUNCTION_MODE
5590 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5592 #undef TARGET_PROMOTE_PROTOTYPES
5593 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5595 #undef TARGET_BUILD_BUILTIN_VA_LIST
5596 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5598 #undef TARGET_EXPAND_BUILTIN_VA_START
5599 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5601 #undef TARGET_SETUP_INCOMING_VARARGS
5602 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5604 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5605 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5607 #undef TARGET_RTX_COSTS
5608 #define TARGET_RTX_COSTS tilegx_rtx_costs
5610 #undef TARGET_EXPAND_TO_RTL_HOOK
5611 #define TARGET_EXPAND_TO_RTL_HOOK tilegx_expand_to_rtl_hook
5613 #undef TARGET_SHIFT_TRUNCATION_MASK
5614 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5616 #undef TARGET_INIT_LIBFUNCS
5617 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5619 /* Limit to what we can reach in one addli. */
5620 #undef TARGET_MIN_ANCHOR_OFFSET
5621 #define TARGET_MIN_ANCHOR_OFFSET -32768
5622 #undef TARGET_MAX_ANCHOR_OFFSET
5623 #define TARGET_MAX_ANCHOR_OFFSET 32767
5625 #undef TARGET_LEGITIMATE_CONSTANT_P
5626 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5629 #define TARGET_LRA_P hook_bool_void_false
5631 #undef TARGET_LEGITIMATE_ADDRESS_P
5632 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5634 #undef TARGET_LEGITIMIZE_ADDRESS
5635 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5637 #undef TARGET_DELEGITIMIZE_ADDRESS
5638 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5640 #undef TARGET_INIT_BUILTINS
5641 #define TARGET_INIT_BUILTINS tilegx_init_builtins
5643 #undef TARGET_BUILTIN_DECL
5644 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5646 #undef TARGET_EXPAND_BUILTIN
5647 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5649 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5650 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5652 #undef TARGET_FRAME_POINTER_REQUIRED
5653 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5655 #undef TARGET_DELAY_SCHED2
5656 #define TARGET_DELAY_SCHED2 true
5658 #undef TARGET_DELAY_VARTRACK
5659 #define TARGET_DELAY_VARTRACK true
5661 #undef TARGET_SCHED_ISSUE_RATE
5662 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5664 #undef TARGET_SCHED_ADJUST_COST
5665 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5667 #undef TARGET_MACHINE_DEPENDENT_REORG
5668 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5670 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5671 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5672 hook_bool_const_tree_hwi_hwi_const_tree_true
5674 #undef TARGET_ASM_OUTPUT_MI_THUNK
5675 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5677 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5678 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5680 #undef TARGET_TRAMPOLINE_INIT
5681 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5683 #undef TARGET_PRINT_OPERAND
5684 #define TARGET_PRINT_OPERAND tilegx_print_operand
5686 #undef TARGET_PRINT_OPERAND_ADDRESS
5687 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5689 #undef TARGET_ASM_FILE_END
5690 #define TARGET_ASM_FILE_END tilegx_file_end
5692 #undef TARGET_ASM_ALIGNED_DI_OP
5693 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5695 #undef TARGET_CAN_USE_DOLOOP_P
5696 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
5698 struct gcc_target targetm
= TARGET_INITIALIZER
;
5700 #include "gt-tilegx.h"