1 /* Subroutines used for code generation on the Tilera TILE-Gx.
2 Copyright (C) 2011-2017 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"
32 #include "stringpool.h"
39 #include "diagnostic.h"
41 #include "insn-attr.h"
47 #include "langhooks.h"
49 #include "tm-constrs.h"
51 #include "fold-const.h"
52 #include "stor-layout.h"
54 #include "tilegx-builtins.h"
55 #include "tilegx-multiply.h"
58 /* This file should be included last. */
59 #include "target-def.h"
61 /* SYMBOL_REF for GOT */
62 static GTY(()) rtx g_got_symbol
= NULL
;
64 /* Report whether we're printing out the first address fragment of a
65 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
66 TARGET_PRINT_OPERAND_ADDRESS. */
67 static bool output_memory_autoinc_first
;
73 /* Implement TARGET_OPTION_OVERRIDE. */
75 tilegx_option_override (void)
77 if (global_options_set
.x_tilegx_cmodel
)
79 switch (tilegx_cmodel
)
84 tilegx_cmodel
= CM_SMALL_PIC
;
90 tilegx_cmodel
= CM_LARGE_PIC
;
98 tilegx_cmodel
= flag_pic
? CM_SMALL_PIC
: CM_SMALL
;
100 /* When modulo scheduling is enabled, we still rely on regular
101 scheduler for bundling. */
102 if (flag_modulo_sched
)
103 flag_resched_modulo_sched
= 1;
108 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
110 tilegx_scalar_mode_supported_p (machine_mode mode
)
131 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
133 tilegx_vector_mode_supported_p (machine_mode mode
)
135 return mode
== V8QImode
|| mode
== V4HImode
|| mode
== V2SImode
;
139 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
141 tilegx_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
,
142 rtx x ATTRIBUTE_UNUSED
)
148 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
150 tilegx_function_ok_for_sibcall (tree decl
, tree exp ATTRIBUTE_UNUSED
)
152 return (tilegx_cmodel
!= CM_LARGE
&& tilegx_cmodel
!= CM_LARGE_PIC
157 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
158 passed by reference. */
160 tilegx_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED
,
161 machine_mode mode ATTRIBUTE_UNUSED
,
162 const_tree type
, bool named ATTRIBUTE_UNUSED
)
164 return (type
&& TYPE_SIZE (type
)
165 && TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
);
169 /* Implement TARGET_RETURN_IN_MSB. We return a value in the most
170 significant part of a register if:
171 - the target is big-endian; and
172 - the value has an aggregate type (e.g., structure or union). */
174 tilegx_return_in_msb (const_tree valtype
)
176 return (TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (valtype
));
180 /* Implement TARGET_RETURN_IN_MEMORY. */
182 tilegx_return_in_memory (const_tree type
, const_tree fndecl ATTRIBUTE_UNUSED
)
184 return !IN_RANGE (int_size_in_bytes (type
),
185 0, TILEGX_NUM_RETURN_REGS
* UNITS_PER_WORD
);
189 /* Implement TARGET_MODE_REP_EXTENDED. */
191 tilegx_mode_rep_extended (machine_mode mode
, machine_mode mode_rep
)
193 /* SImode register values are sign-extended to DImode. */
194 if (mode
== SImode
&& mode_rep
== DImode
)
201 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
203 tilegx_function_arg_boundary (machine_mode mode
, const_tree type
)
205 unsigned int alignment
;
207 alignment
= type
? TYPE_ALIGN (type
) : GET_MODE_ALIGNMENT (mode
);
208 if (alignment
< PARM_BOUNDARY
)
209 alignment
= PARM_BOUNDARY
;
210 if (alignment
> STACK_BOUNDARY
)
211 alignment
= STACK_BOUNDARY
;
216 /* Implement TARGET_FUNCTION_ARG. */
218 tilegx_function_arg (cumulative_args_t cum_v
,
220 const_tree type
, bool named ATTRIBUTE_UNUSED
)
222 CUMULATIVE_ARGS cum
= *get_cumulative_args (cum_v
);
223 int byte_size
= ((mode
== BLKmode
)
224 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
225 bool doubleword_aligned_p
;
227 if (cum
>= TILEGX_NUM_ARG_REGS
)
230 /* See whether the argument has doubleword alignment. */
231 doubleword_aligned_p
=
232 tilegx_function_arg_boundary (mode
, type
) > BITS_PER_WORD
;
234 if (doubleword_aligned_p
)
237 /* The ABI does not allow parameters to be passed partially in reg
238 and partially in stack. */
239 if ((cum
+ (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
)
240 > TILEGX_NUM_ARG_REGS
)
243 return gen_rtx_REG (mode
, cum
);
247 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
249 tilegx_function_arg_advance (cumulative_args_t cum_v
,
251 const_tree type
, bool named ATTRIBUTE_UNUSED
)
253 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
255 int byte_size
= ((mode
== BLKmode
)
256 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
257 int word_size
= (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
258 bool doubleword_aligned_p
;
260 /* See whether the argument has doubleword alignment. */
261 doubleword_aligned_p
=
262 tilegx_function_arg_boundary (mode
, type
) > BITS_PER_WORD
;
264 if (doubleword_aligned_p
)
267 /* If the current argument does not fit in the pretend_args space,
269 if (*cum
< TILEGX_NUM_ARG_REGS
270 && *cum
+ word_size
> TILEGX_NUM_ARG_REGS
)
271 *cum
= TILEGX_NUM_ARG_REGS
;
277 /* Implement TARGET_FUNCTION_VALUE. */
279 tilegx_function_value (const_tree valtype
, const_tree fn_decl_or_type
,
280 bool outgoing ATTRIBUTE_UNUSED
)
285 mode
= TYPE_MODE (valtype
);
286 unsigned_p
= TYPE_UNSIGNED (valtype
);
288 mode
= promote_function_mode (valtype
, mode
, &unsigned_p
,
291 return gen_rtx_REG (mode
, 0);
295 /* Implement TARGET_LIBCALL_VALUE. */
297 tilegx_libcall_value (machine_mode mode
,
298 const_rtx fun ATTRIBUTE_UNUSED
)
300 return gen_rtx_REG (mode
, 0);
304 /* Implement FUNCTION_VALUE_REGNO_P. */
306 tilegx_function_value_regno_p (const unsigned int regno
)
308 return regno
< TILEGX_NUM_RETURN_REGS
;
312 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
314 tilegx_build_builtin_va_list (void)
316 tree f_args
, f_skip
, record
, type_decl
;
319 record
= lang_hooks
.types
.make_type (RECORD_TYPE
);
321 type_decl
= build_decl (BUILTINS_LOCATION
, TYPE_DECL
,
322 get_identifier ("__va_list_tag"), record
);
324 f_args
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
325 get_identifier ("__args"), ptr_type_node
);
326 f_skip
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
327 get_identifier ("__skip"), ptr_type_node
);
329 DECL_FIELD_CONTEXT (f_args
) = record
;
331 DECL_FIELD_CONTEXT (f_skip
) = record
;
333 TREE_CHAIN (record
) = type_decl
;
334 TYPE_NAME (record
) = type_decl
;
335 TYPE_FIELDS (record
) = f_args
;
336 TREE_CHAIN (f_args
) = f_skip
;
338 /* We know this is being padded and we want it too. It is an
339 internal type so hide the warnings from the user. */
343 layout_type (record
);
347 /* The correct type is an array type of one element. */
352 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
354 tilegx_va_start (tree valist
, rtx nextarg ATTRIBUTE_UNUSED
)
359 f_args
= TYPE_FIELDS (TREE_TYPE (valist
));
360 f_skip
= TREE_CHAIN (f_args
);
363 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
365 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
367 /* Find the __args area. */
368 t
= make_tree (TREE_TYPE (args
), virtual_incoming_args_rtx
);
369 t
= fold_build_pointer_plus_hwi (t
,
371 (crtl
->args
.info
- TILEGX_NUM_ARG_REGS
));
373 if (crtl
->args
.pretend_args_size
> 0)
374 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
376 t
= build2 (MODIFY_EXPR
, TREE_TYPE (args
), args
, t
);
377 TREE_SIDE_EFFECTS (t
) = 1;
378 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
380 /* Find the __skip area. */
381 t
= make_tree (TREE_TYPE (skip
), virtual_incoming_args_rtx
);
382 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
383 t
= build2 (MODIFY_EXPR
, TREE_TYPE (skip
), skip
, t
);
384 TREE_SIDE_EFFECTS (t
) = 1;
385 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
389 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
391 tilegx_setup_incoming_varargs (cumulative_args_t cum
,
393 tree type
, int *pretend_args
, int no_rtl
)
395 CUMULATIVE_ARGS local_cum
= *get_cumulative_args (cum
);
398 /* The caller has advanced CUM up to, but not beyond, the last named
399 argument. Advance a local copy of CUM past the last "real" named
400 argument, to find out how many registers are left over. */
401 targetm
.calls
.function_arg_advance (pack_cumulative_args (&local_cum
),
403 first_reg
= local_cum
;
405 if (local_cum
< TILEGX_NUM_ARG_REGS
)
407 *pretend_args
= UNITS_PER_WORD
* (TILEGX_NUM_ARG_REGS
- first_reg
);
411 alias_set_type set
= get_varargs_alias_set ();
413 gen_rtx_MEM (BLKmode
, plus_constant (Pmode
,
414 virtual_incoming_args_rtx
,
415 -STACK_POINTER_OFFSET
-
417 (TILEGX_NUM_ARG_REGS
-
419 MEM_NOTRAP_P (tmp
) = 1;
420 set_mem_alias_set (tmp
, set
);
421 move_block_from_reg (first_reg
, tmp
,
422 TILEGX_NUM_ARG_REGS
- first_reg
);
430 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
431 the va_list structure VALIST as required to retrieve an argument of
432 type TYPE, and returning that argument.
434 ret = va_arg(VALIST, TYPE);
436 generates code equivalent to:
438 paddedsize = (sizeof(TYPE) + 7) & -8;
439 if ( (VALIST.__args + paddedsize > VALIST.__skip)
440 & (VALIST.__args <= VALIST.__skip))
441 addr = VALIST.__skip + STACK_POINTER_OFFSET;
443 addr = VALIST.__args;
444 VALIST.__args = addr + paddedsize;
445 if (BYTES_BIG_ENDIAN)
446 ret = *(TYPE *)(addr + paddedsize - sizeof(TYPE));
451 tilegx_gimplify_va_arg_expr (tree valist
, tree type
, gimple_seq
*pre_p
,
452 gimple_seq
*post_p ATTRIBUTE_UNUSED
)
456 HOST_WIDE_INT size
, rsize
;
458 bool pass_by_reference_p
;
460 f_args
= TYPE_FIELDS (va_list_type_node
);
461 f_skip
= TREE_CHAIN (f_args
);
464 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
466 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
468 addr
= create_tmp_var (ptr_type_node
, "va_arg");
470 /* If an object is dynamically sized, a pointer to it is passed
471 instead of the object itself. */
472 pass_by_reference_p
= pass_by_reference (NULL
, TYPE_MODE (type
), type
,
475 if (pass_by_reference_p
)
476 type
= build_pointer_type (type
);
478 size
= int_size_in_bytes (type
);
479 rsize
= ((size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
) * UNITS_PER_WORD
;
481 /* If the alignment of the type is greater than the default for a
482 parameter, align to the STACK_BOUNDARY. */
483 if (TYPE_ALIGN (type
) > PARM_BOUNDARY
)
485 /* Assert the only case we generate code for: when
486 stack boundary = 2 * parm boundary. */
487 gcc_assert (STACK_BOUNDARY
== PARM_BOUNDARY
* 2);
489 tmp
= build2 (BIT_AND_EXPR
, sizetype
,
490 fold_convert (sizetype
, unshare_expr (args
)),
491 size_int (PARM_BOUNDARY
/ 8));
492 tmp
= build2 (POINTER_PLUS_EXPR
, ptr_type_node
,
493 unshare_expr (args
), tmp
);
495 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
498 /* Build conditional expression to calculate addr. The expression
499 will be gimplified later. */
500 tmp
= fold_build_pointer_plus_hwi (unshare_expr (args
), rsize
);
501 tmp
= build2 (TRUTH_AND_EXPR
, boolean_type_node
,
502 build2 (GT_EXPR
, boolean_type_node
, tmp
, unshare_expr (skip
)),
503 build2 (LE_EXPR
, boolean_type_node
, unshare_expr (args
),
504 unshare_expr (skip
)));
506 tmp
= build3 (COND_EXPR
, ptr_type_node
, tmp
,
507 build2 (POINTER_PLUS_EXPR
, ptr_type_node
, unshare_expr (skip
),
508 size_int (STACK_POINTER_OFFSET
)),
509 unshare_expr (args
));
511 /* Adjust the address of va_arg if it is in big endian mode. */
512 if (BYTES_BIG_ENDIAN
&& rsize
> size
)
513 tmp
= fold_build_pointer_plus_hwi (tmp
, rsize
- size
);
514 gimplify_assign (addr
, tmp
, pre_p
);
516 /* Update VALIST.__args. */
518 if (BYTES_BIG_ENDIAN
&& rsize
> size
)
519 tmp
= fold_build_pointer_plus_hwi (addr
, size
);
521 tmp
= fold_build_pointer_plus_hwi (addr
, rsize
);
522 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
524 addr
= fold_convert (build_pointer_type (type
), addr
);
526 if (pass_by_reference_p
)
527 addr
= build_va_arg_indirect_ref (addr
);
529 return build_va_arg_indirect_ref (addr
);
534 /* Implement TARGET_RTX_COSTS. */
536 tilegx_rtx_costs (rtx x
, machine_mode mode
, int outer_code
, int opno
,
537 int *total
, bool speed
)
539 int code
= GET_CODE (x
);
544 /* If this is an 8-bit constant, return zero since it can be
545 used nearly anywhere with no cost. If it is a valid operand
546 for an ADD or AND, likewise return 0 if we know it will be
547 used in that context. Otherwise, return 2 since it might be
548 used there later. All other constants take at least two
550 if (satisfies_constraint_I (x
))
555 else if (outer_code
== PLUS
&& add_operand (x
, VOIDmode
))
557 /* Slightly penalize large constants even though we can add
558 them in one instruction, because it forces the use of
559 2-wide bundling mode. */
563 else if (move_operand (x
, SImode
))
565 /* We can materialize in one move. */
566 *total
= COSTS_N_INSNS (1);
571 /* We can materialize in two moves. */
572 *total
= COSTS_N_INSNS (2);
581 *total
= COSTS_N_INSNS (2);
585 *total
= COSTS_N_INSNS (4);
593 /* If outer-code was a sign or zero extension, a cost of
594 COSTS_N_INSNS (1) was already added in, so account for
596 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
597 *total
= COSTS_N_INSNS (1);
599 *total
= COSTS_N_INSNS (2);
603 /* Convey that shl[123]add are efficient. */
604 if (GET_CODE (XEXP (x
, 0)) == MULT
605 && cint_248_operand (XEXP (XEXP (x
, 0), 1), VOIDmode
))
607 *total
= (rtx_cost (XEXP (XEXP (x
, 0), 0), mode
,
608 (enum rtx_code
) outer_code
, opno
, speed
)
609 + rtx_cost (XEXP (x
, 1), mode
,
610 (enum rtx_code
) outer_code
, opno
, speed
)
611 + COSTS_N_INSNS (1));
617 *total
= COSTS_N_INSNS (2);
624 /* These are handled by software and are very expensive. */
625 *total
= COSTS_N_INSNS (100);
629 case UNSPEC_VOLATILE
:
631 int num
= XINT (x
, 1);
633 if (num
<= TILEGX_LAST_LATENCY_1_INSN
)
634 *total
= COSTS_N_INSNS (1);
635 else if (num
<= TILEGX_LAST_LATENCY_2_INSN
)
636 *total
= COSTS_N_INSNS (2);
637 else if (num
> TILEGX_LAST_LATENCY_INSN
)
639 if (num
== UNSPEC_NON_TEMPORAL
)
641 /* These are basically loads. */
642 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
643 *total
= COSTS_N_INSNS (1);
645 *total
= COSTS_N_INSNS (2);
649 if (outer_code
== PLUS
)
652 *total
= COSTS_N_INSNS (1);
659 case UNSPEC_BLOCKAGE
:
660 case UNSPEC_NETWORK_BARRIER
:
665 case UNSPEC_LNK_AND_LABEL
:
667 case UNSPEC_MOV_PCREL_STEP3
:
668 case UNSPEC_NETWORK_RECEIVE
:
669 case UNSPEC_NETWORK_SEND
:
670 case UNSPEC_SPR_MOVE
:
671 case UNSPEC_TLS_GD_ADD
:
672 *total
= COSTS_N_INSNS (1);
675 case UNSPEC_TLS_IE_LOAD
:
677 *total
= COSTS_N_INSNS (2);
681 *total
= COSTS_N_INSNS (3);
685 *total
= COSTS_N_INSNS (4);
689 case UNSPEC_INSN_CMPEXCH
:
690 case UNSPEC_LATENCY_L2
:
691 *total
= COSTS_N_INSNS (11);
694 case UNSPEC_TLS_GD_CALL
:
695 *total
= COSTS_N_INSNS (30);
698 case UNSPEC_LATENCY_MISS
:
699 *total
= COSTS_N_INSNS (80);
703 *total
= COSTS_N_INSNS (1);
718 /* Create a temporary variable to hold a partial result, to enable
721 create_temp_reg_if_possible (machine_mode mode
, rtx default_reg
)
723 return can_create_pseudo_p () ? gen_reg_rtx (mode
) : default_reg
;
727 /* Functions to save and restore machine-specific function data. */
728 static struct machine_function
*
729 tilegx_init_machine_status (void)
731 return ggc_cleared_alloc
<machine_function
> ();
735 /* Do anything needed before RTL is emitted for each function. */
737 tilegx_init_expanders (void)
739 /* Arrange to initialize and mark the machine per-function
741 init_machine_status
= tilegx_init_machine_status
;
743 if (cfun
&& cfun
->machine
&& flag_pic
)
745 static int label_num
= 0;
747 char text_label_name
[32];
749 struct machine_function
*machine
= cfun
->machine
;
751 ASM_GENERATE_INTERNAL_LABEL (text_label_name
, "L_PICLNK", label_num
++);
753 machine
->text_label_symbol
=
754 gen_rtx_SYMBOL_REF (Pmode
, ggc_strdup (text_label_name
));
756 machine
->text_label_rtx
=
757 gen_rtx_REG (Pmode
, TILEGX_PIC_TEXT_LABEL_REGNUM
);
759 machine
->got_rtx
= gen_rtx_REG (Pmode
, PIC_OFFSET_TABLE_REGNUM
);
761 machine
->calls_tls_get_addr
= false;
766 /* Implement TARGET_EXPAND_TO_RTL_HOOK. */
768 tilegx_expand_to_rtl_hook (void)
770 /* Exclude earlier sets of crtl->uses_pic_offset_table, because we
771 only care about uses actually emitted. */
772 crtl
->uses_pic_offset_table
= 0;
776 /* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode
777 matching insns and therefore guarantee that the shift count is
778 modulo 64. SImode shifts sometimes use the 64 bit version so do
779 not hold such guarantee. */
780 static unsigned HOST_WIDE_INT
781 tilegx_shift_truncation_mask (machine_mode mode
)
783 return mode
== DImode
? 63 : 0;
787 /* Implement TARGET_INIT_LIBFUNCS. */
789 tilegx_init_libfuncs (void)
791 /* We need to explicitly generate these libfunc's to support
792 conversion of divide by constant to multiply (the divide stubs in
793 tilegx.md exist also for this reason). Normally we'd expect gcc
794 to lazily generate them when they are needed, but for some reason
795 it's set up to only generate them if the mode is the word
797 set_optab_libfunc (sdiv_optab
, SImode
, "__divsi3");
798 set_optab_libfunc (udiv_optab
, SImode
, "__udivsi3");
799 set_optab_libfunc (smod_optab
, SImode
, "__modsi3");
800 set_optab_libfunc (umod_optab
, SImode
, "__umodsi3");
804 /* Return true if X contains a thread-local symbol. */
806 tilegx_tls_referenced_p (rtx x
)
808 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == PLUS
)
809 x
= XEXP (XEXP (x
, 0), 0);
811 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
))
814 /* That's all we handle in tilegx_legitimize_tls_address for
820 /* Return true if X requires a scratch register. It is given that
821 flag_pic is on and that X satisfies CONSTANT_P. */
823 tilegx_pic_address_needs_scratch (rtx x
)
825 if (GET_CODE (x
) == CONST
826 && GET_CODE (XEXP (x
, 0)) == PLUS
827 && (GET_CODE (XEXP (XEXP (x
, 0), 0)) == SYMBOL_REF
828 || GET_CODE (XEXP (XEXP (x
, 0), 0)) == LABEL_REF
)
829 && (CONST_INT_P (XEXP (XEXP (x
, 0), 1))))
836 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
837 which we are willing to load the value into a register via a move
838 pattern. TLS cannot be treated as a constant because it can
839 include a function call. */
841 tilegx_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
843 switch (GET_CODE (x
))
847 return !tilegx_tls_referenced_p (x
);
855 /* Return true if the constant value X is a legitimate general operand
856 when generating PIC code. It is given that flag_pic is on and that
857 X satisfies CONSTANT_P. */
859 tilegx_legitimate_pic_operand_p (rtx x
)
861 if (tilegx_pic_address_needs_scratch (x
))
864 if (tilegx_tls_referenced_p (x
))
871 /* Return true if the rtx X can be used as an address operand. */
873 tilegx_legitimate_address_p (machine_mode
ARG_UNUSED (mode
), rtx x
,
876 if (GET_CODE (x
) == SUBREG
)
879 switch (GET_CODE (x
))
883 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
890 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
893 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
896 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
899 if (!satisfies_constraint_I (XEXP (XEXP (x
, 1), 1)))
912 /* Check if x is a valid reg. */
917 return REGNO_OK_FOR_BASE_P (REGNO (x
));
923 /* Return the rtx containing SYMBOL_REF to the text label. */
925 tilegx_text_label_symbol (void)
927 return cfun
->machine
->text_label_symbol
;
931 /* Return the register storing the value of the text label. */
933 tilegx_text_label_rtx (void)
935 return cfun
->machine
->text_label_rtx
;
939 /* Return the register storing the value of the global offset
942 tilegx_got_rtx (void)
944 return cfun
->machine
->got_rtx
;
948 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
950 tilegx_got_symbol (void)
952 if (g_got_symbol
== NULL
)
953 g_got_symbol
= gen_rtx_SYMBOL_REF (Pmode
, "_GLOBAL_OFFSET_TABLE_");
959 /* Return a reference to the got to be used by tls references. */
961 tilegx_tls_got (void)
966 crtl
->uses_pic_offset_table
= 1;
967 return tilegx_got_rtx ();
970 temp
= gen_reg_rtx (Pmode
);
971 emit_move_insn (temp
, tilegx_got_symbol ());
977 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
978 this (thread-local) address. */
980 tilegx_legitimize_tls_address (rtx addr
)
984 gcc_assert (can_create_pseudo_p ());
986 if (GET_CODE (addr
) == SYMBOL_REF
)
987 switch (SYMBOL_REF_TLS_MODEL (addr
))
989 case TLS_MODEL_GLOBAL_DYNAMIC
:
990 case TLS_MODEL_LOCAL_DYNAMIC
:
992 rtx r0
, temp
, temp2
, temp3
, got
;
994 ret
= gen_reg_rtx (Pmode
);
995 r0
= gen_rtx_REG (Pmode
, 0);
996 temp
= gen_reg_rtx (Pmode
);
997 temp2
= gen_reg_rtx (Pmode
);
998 temp3
= gen_reg_rtx (Pmode
);
1000 got
= tilegx_tls_got ();
1003 emit_insn (gen_mov_tls_gd_step1_32bit (temp
, addr
));
1004 emit_insn (gen_mov_tls_gd_step2_32bit (temp2
, temp
, addr
));
1005 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
1009 emit_insn (gen_mov_tls_gd_step1 (temp
, addr
));
1010 emit_insn (gen_mov_tls_gd_step2 (temp2
, temp
, addr
));
1011 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
1014 emit_move_insn (r0
, temp2
);
1018 emit_insn (gen_tls_gd_call_32bit (addr
));
1022 emit_insn (gen_tls_gd_call (addr
));
1025 emit_move_insn (temp3
, r0
);
1029 last
= emit_insn (gen_tls_gd_add_32bit (ret
, temp3
, addr
));
1031 last
= emit_insn (gen_tls_gd_add (ret
, temp3
, addr
));
1033 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1036 case TLS_MODEL_INITIAL_EXEC
:
1038 rtx temp
, temp2
, temp3
, got
;
1041 ret
= gen_reg_rtx (Pmode
);
1042 temp
= gen_reg_rtx (Pmode
);
1043 temp2
= gen_reg_rtx (Pmode
);
1044 temp3
= gen_reg_rtx (Pmode
);
1046 got
= tilegx_tls_got ();
1049 emit_insn (gen_mov_tls_ie_step1_32bit (temp
, addr
));
1050 emit_insn (gen_mov_tls_ie_step2_32bit (temp2
, temp
, addr
));
1051 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
1052 emit_insn (gen_tls_ie_load_32bit (temp3
, temp2
, addr
));
1056 emit_insn (gen_mov_tls_ie_step1 (temp
, addr
));
1057 emit_insn (gen_mov_tls_ie_step2 (temp2
, temp
, addr
));
1058 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
1059 emit_insn (gen_tls_ie_load (temp3
, temp2
, addr
));
1064 gen_rtx_PLUS (Pmode
,
1066 THREAD_POINTER_REGNUM
),
1068 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1071 case TLS_MODEL_LOCAL_EXEC
:
1076 ret
= gen_reg_rtx (Pmode
);
1077 temp
= gen_reg_rtx (Pmode
);
1078 temp2
= gen_reg_rtx (Pmode
);
1082 emit_insn (gen_mov_tls_le_step1_32bit (temp
, addr
));
1083 emit_insn (gen_mov_tls_le_step2_32bit (temp2
, temp
, addr
));
1087 emit_insn (gen_mov_tls_le_step1 (temp
, addr
));
1088 emit_insn (gen_mov_tls_le_step2 (temp2
, temp
, addr
));
1092 emit_move_insn (ret
,
1093 gen_rtx_PLUS (Pmode
,
1095 THREAD_POINTER_REGNUM
),
1097 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1103 else if (GET_CODE (addr
) == CONST
)
1107 gcc_assert (GET_CODE (XEXP (addr
, 0)) == PLUS
);
1109 base
= tilegx_legitimize_tls_address (XEXP (XEXP (addr
, 0), 0));
1110 offset
= XEXP (XEXP (addr
, 0), 1);
1112 base
= force_operand (base
, NULL_RTX
);
1113 ret
= force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1122 /* Returns a register that points to ADDR, a symbolic address, by
1123 computing its address relative to tilegx_text_label_symbol. */
1125 tilegx_compute_pcrel_address (rtx result
, rtx addr
)
1127 rtx text_label_symbol
= tilegx_text_label_symbol ();
1128 rtx text_label_rtx
= tilegx_text_label_rtx ();
1129 rtx temp
, temp2
, temp3
;
1131 temp
= create_temp_reg_if_possible (Pmode
, result
);
1132 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1136 emit_insn (gen_mov_pcrel_step1_32bit (temp
, addr
, text_label_symbol
));
1137 emit_insn (gen_mov_pcrel_step2_32bit (temp2
, temp
, addr
,
1138 text_label_symbol
));
1139 emit_insn (gen_mov_pcrel_step3_32bit (result
, temp2
,
1141 addr
, text_label_symbol
));
1143 else if (tilegx_cmodel
== CM_LARGE_PIC
)
1145 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1146 emit_insn (gen_mov_large_pcrel_step1 (temp
, addr
, text_label_symbol
));
1147 emit_insn (gen_mov_large_pcrel_step2 (temp2
, temp
, addr
,
1148 text_label_symbol
));
1149 emit_insn (gen_mov_large_pcrel_step3 (temp3
, temp2
, addr
,
1150 text_label_symbol
));
1151 emit_insn (gen_mov_large_pcrel_step4 (result
, temp3
,
1153 addr
, text_label_symbol
));
1157 emit_insn (gen_mov_pcrel_step1 (temp
, addr
, text_label_symbol
));
1158 emit_insn (gen_mov_pcrel_step2 (temp2
, temp
, addr
, text_label_symbol
));
1159 emit_insn (gen_mov_pcrel_step3 (result
, temp2
,
1161 addr
, text_label_symbol
));
1166 /* Returns a register that points to the plt entry of ADDR, a symbolic
1167 address, by computing its address relative to
1168 tilegx_text_label_symbol. */
1170 tilegx_compute_pcrel_plt_address (rtx result
, rtx addr
)
1172 rtx text_label_symbol
= tilegx_text_label_symbol ();
1173 rtx text_label_rtx
= tilegx_text_label_rtx ();
1174 rtx temp
, temp2
, temp3
;
1176 temp
= create_temp_reg_if_possible (Pmode
, result
);
1177 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1181 emit_insn (gen_mov_plt_pcrel_step1_32bit (temp
, addr
,
1182 text_label_symbol
));
1183 emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2
, temp
, addr
,
1184 text_label_symbol
));
1185 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp2
, text_label_rtx
));
1189 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1191 emit_insn (gen_mov_plt_pcrel_step1 (temp
, addr
, text_label_symbol
));
1192 emit_insn (gen_mov_plt_pcrel_step2 (temp2
, temp
, addr
,
1193 text_label_symbol
));
1194 emit_insn (gen_mov_plt_pcrel_step3 (temp3
, temp2
, addr
,
1195 text_label_symbol
));
1196 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp3
, text_label_rtx
));
1201 /* Legitimize PIC addresses. If the address is already
1202 position-independent, we return ORIG. Newly generated
1203 position-independent addresses go into a reg. This is REG if
1204 nonzero, otherwise we allocate register(s) as necessary. */
1206 tilegx_legitimize_pic_address (rtx orig
,
1207 machine_mode mode ATTRIBUTE_UNUSED
,
1210 if (GET_CODE (orig
) == SYMBOL_REF
)
1212 rtx address
, pic_ref
;
1216 gcc_assert (can_create_pseudo_p ());
1217 reg
= gen_reg_rtx (Pmode
);
1220 if (SYMBOL_REF_LOCAL_P (orig
))
1222 /* If not during reload, allocate another temp reg here for
1223 loading in the address, so that these instructions can be
1224 optimized properly. */
1225 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1226 tilegx_compute_pcrel_address (temp_reg
, orig
);
1228 /* Note: this is conservative. We use the text_label but we
1229 don't use the pic_offset_table. However, in some cases
1230 we may need the pic_offset_table (see
1231 tilegx_fixup_pcrel_references). */
1232 crtl
->uses_pic_offset_table
= 1;
1236 emit_move_insn (reg
, address
);
1241 /* If not during reload, allocate another temp reg here for
1242 loading in the address, so that these instructions can be
1243 optimized properly. */
1244 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1246 gcc_assert (flag_pic
);
1251 emit_insn (gen_add_got16_32bit (temp_reg
,
1257 emit_insn (gen_add_got16 (temp_reg
,
1258 tilegx_got_rtx (), orig
));
1263 rtx temp_reg2
= create_temp_reg_if_possible (Pmode
, reg
);
1264 rtx temp_reg3
= create_temp_reg_if_possible (Pmode
, reg
);
1267 emit_insn (gen_mov_got32_step1_32bit (temp_reg3
, orig
));
1268 emit_insn (gen_mov_got32_step2_32bit
1269 (temp_reg2
, temp_reg3
, orig
));
1273 emit_insn (gen_mov_got32_step1 (temp_reg3
, orig
));
1274 emit_insn (gen_mov_got32_step2 (temp_reg2
, temp_reg3
,
1277 emit_move_insn (temp_reg
,
1278 gen_rtx_PLUS (Pmode
,
1279 tilegx_got_rtx (), temp_reg2
));
1284 pic_ref
= gen_const_mem (Pmode
, address
);
1285 crtl
->uses_pic_offset_table
= 1;
1286 emit_move_insn (reg
, pic_ref
);
1287 /* The following put a REG_EQUAL note on this insn, so that
1288 it can be optimized by loop. But it causes the label to
1289 be optimized away. */
1290 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1294 else if (GET_CODE (orig
) == CONST
)
1298 if (GET_CODE (XEXP (orig
, 0)) == PLUS
1299 && XEXP (XEXP (orig
, 0), 0) == tilegx_got_rtx ())
1304 gcc_assert (can_create_pseudo_p ());
1305 reg
= gen_reg_rtx (Pmode
);
1308 gcc_assert (GET_CODE (XEXP (orig
, 0)) == PLUS
);
1309 base
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 0),
1311 offset
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 1), Pmode
,
1312 base
== reg
? 0 : reg
);
1314 if (CONST_INT_P (offset
))
1316 if (can_create_pseudo_p ())
1317 offset
= force_reg (Pmode
, offset
);
1319 /* If we reach here, then something is seriously wrong. */
1323 if (can_create_pseudo_p ())
1324 return force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1328 else if (GET_CODE (orig
) == LABEL_REF
)
1335 gcc_assert (can_create_pseudo_p ());
1336 reg
= gen_reg_rtx (Pmode
);
1339 /* If not during reload, allocate another temp reg here for
1340 loading in the address, so that these instructions can be
1341 optimized properly. */
1342 temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1343 tilegx_compute_pcrel_address (temp_reg
, orig
);
1345 /* Note: this is conservative. We use the text_label but we
1346 don't use the pic_offset_table. */
1347 crtl
->uses_pic_offset_table
= 1;
1351 emit_move_insn (reg
, address
);
1360 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1362 tilegx_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
1365 if (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
1366 && symbolic_operand (x
, Pmode
) && tilegx_tls_referenced_p (x
))
1368 return tilegx_legitimize_tls_address (x
);
1372 return tilegx_legitimize_pic_address (x
, mode
, 0);
1379 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1381 tilegx_delegitimize_address (rtx x
)
1383 x
= delegitimize_mem_from_attrs (x
);
1385 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == UNSPEC
)
1387 switch (XINT (XEXP (x
, 0), 1))
1393 case UNSPEC_HW0_LAST
:
1394 case UNSPEC_HW1_LAST
:
1395 case UNSPEC_HW2_LAST
:
1396 case UNSPEC_HW0_PCREL
:
1397 case UNSPEC_HW1_PCREL
:
1398 case UNSPEC_HW1_LAST_PCREL
:
1399 case UNSPEC_HW2_LAST_PCREL
:
1400 case UNSPEC_HW0_PLT_PCREL
:
1401 case UNSPEC_HW1_PLT_PCREL
:
1402 case UNSPEC_HW1_LAST_PLT_PCREL
:
1403 case UNSPEC_HW2_LAST_PLT_PCREL
:
1404 case UNSPEC_HW0_GOT
:
1405 case UNSPEC_HW0_LAST_GOT
:
1406 case UNSPEC_HW1_LAST_GOT
:
1407 case UNSPEC_HW0_TLS_GD
:
1408 case UNSPEC_HW1_LAST_TLS_GD
:
1409 case UNSPEC_HW0_TLS_IE
:
1410 case UNSPEC_HW1_LAST_TLS_IE
:
1411 case UNSPEC_HW0_TLS_LE
:
1412 case UNSPEC_HW1_LAST_TLS_LE
:
1413 x
= XVECEXP (XEXP (x
, 0), 0, 0);
1422 /* Emit code to load the PIC register. */
1424 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED
)
1426 int orig_flag_pic
= flag_pic
;
1428 rtx got_symbol
= tilegx_got_symbol ();
1429 rtx text_label_symbol
= tilegx_text_label_symbol ();
1430 rtx text_label_rtx
= tilegx_text_label_rtx ();
1435 emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx
,
1436 text_label_symbol
));
1440 emit_insn (gen_insn_lnk_and_label (text_label_rtx
, text_label_symbol
));
1443 tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol
);
1445 flag_pic
= orig_flag_pic
;
1447 /* Need to emit this whether or not we obey regdecls, since
1448 setjmp/longjmp can cause life info to screw up. ??? In the case
1449 where we don't obey regdecls, this is not sufficient since we may
1450 not fall out the bottom. */
1451 emit_use (tilegx_got_rtx ());
1455 /* Return the simd variant of the constant NUM of mode MODE, by
1456 replicating it to fill an interger of mode DImode. NUM is first
1457 truncated to fit in MODE. */
1459 tilegx_simd_int (rtx num
, machine_mode mode
)
1461 HOST_WIDE_INT n
= 0;
1463 gcc_assert (CONST_INT_P (num
));
1470 n
= 0x0101010101010101LL
* (n
& 0x000000FF);
1473 n
= 0x0001000100010001LL
* (n
& 0x0000FFFF);
1476 n
= 0x0000000100000001LL
* (n
& 0xFFFFFFFF);
1488 /* Returns true iff VAL can be moved into a register in one
1489 instruction. And if it can, it emits the code to move the constant
1492 If THREE_WIDE_ONLY is true, this insists on an instruction that
1493 works in a bundle containing three instructions. */
1495 expand_set_cint64_one_inst (rtx dest_reg
,
1496 HOST_WIDE_INT val
, bool three_wide_only
)
1498 if (val
== trunc_int_for_mode (val
, QImode
))
1501 emit_move_insn (dest_reg
, GEN_INT (val
));
1504 else if (!three_wide_only
)
1506 /* Test for the following constraints: J, K, N, P. We avoid
1507 generating an rtx and using existing predicates because we
1508 can be testing and rejecting a lot of constants, and GEN_INT
1510 if ((val
>= -32768 && val
<= 65535)
1511 || ((val
== (val
& 0xFF) * 0x0101010101010101LL
))
1512 || (val
== ((trunc_int_for_mode (val
, QImode
) & 0xFFFF)
1513 * 0x0001000100010001LL
)))
1515 emit_move_insn (dest_reg
, GEN_INT (val
));
1524 /* Implement DImode rotatert. */
1525 static HOST_WIDE_INT
1526 rotate_right (HOST_WIDE_INT n
, int count
)
1528 unsigned HOST_WIDE_INT x
= n
& 0xFFFFFFFFFFFFFFFFULL
;
1531 return ((x
>> count
) | (x
<< (64 - count
))) & 0xFFFFFFFFFFFFFFFFULL
;
1535 /* Return true iff n contains exactly one contiguous sequence of 1
1536 bits, possibly wrapping around from high bits to low bits. */
1538 tilegx_bitfield_operand_p (HOST_WIDE_INT n
, int *first_bit
, int *last_bit
)
1545 for (i
= 0; i
< 64; i
++)
1547 unsigned HOST_WIDE_INT x
= rotate_right (n
, i
);
1551 /* See if x is a power of two minus one, i.e. only consecutive 1
1552 bits starting from bit 0. */
1553 if ((x
& (x
+ 1)) == 0)
1555 if (first_bit
!= NULL
)
1557 if (last_bit
!= NULL
)
1558 *last_bit
= (i
+ exact_log2 (x
^ (x
>> 1))) & 63;
1568 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1570 expand_set_cint64 (rtx dest_reg
, rtx src_val
)
1573 int leading_zeroes
, trailing_zeroes
;
1574 int three_wide_only
;
1575 int shift
, ins_shift
, zero_cluster_shift
;
1578 gcc_assert (CONST_INT_P (src_val
));
1579 val
= trunc_int_for_mode (INTVAL (src_val
), GET_MODE (dest_reg
));
1581 /* See if we can generate the constant in one instruction. */
1582 if (expand_set_cint64_one_inst (dest_reg
, val
, false))
1585 /* Force the destination to DImode so we can use DImode instructions
1586 to create it. This both allows instructions like rotl, and
1587 certain efficient 3-wide instructions. */
1588 subreg
= simplify_gen_subreg (DImode
, dest_reg
, GET_MODE (dest_reg
), 0);
1589 gcc_assert (subreg
!= NULL
);
1592 temp
= create_temp_reg_if_possible (DImode
, dest_reg
);
1594 leading_zeroes
= 63 - floor_log2 (val
& 0xFFFFFFFFFFFFFFFFULL
);
1595 trailing_zeroes
= exact_log2 (val
& -val
);
1597 /* First try all three-wide instructions that generate a constant
1598 (i.e. movei) followed by various shifts and rotates. If none of
1599 those work, try various two-wide ways of generating a constant
1600 followed by various shifts and rotates. */
1601 for (three_wide_only
= 1; three_wide_only
>= 0; three_wide_only
--)
1605 if (expand_set_cint64_one_inst (temp
, val
>> trailing_zeroes
,
1608 /* 0xFFFFFFFFFFFFA500 becomes:
1609 movei temp, 0xFFFFFFFFFFFFFFA5
1610 shli dest, temp, 8 */
1611 emit_move_insn (dest_reg
,
1612 gen_rtx_ASHIFT (DImode
, temp
,
1613 GEN_INT (trailing_zeroes
)));
1617 if (expand_set_cint64_one_inst (temp
, val
<< leading_zeroes
,
1620 /* 0x7FFFFFFFFFFFFFFF becomes:
1622 shrui dest, temp, 1 */
1623 emit_move_insn (dest_reg
,
1624 gen_rtx_LSHIFTRT (DImode
, temp
,
1625 GEN_INT (leading_zeroes
)));
1629 /* Try rotating a one-instruction immediate. */
1630 for (count
= 1; count
< 64; count
++)
1632 HOST_WIDE_INT r
= rotate_right (val
, count
);
1633 if (expand_set_cint64_one_inst (temp
, r
, three_wide_only
))
1635 /* 0xFFFFFFFFFFA5FFFF becomes:
1636 movei temp, 0xFFFFFFFFFFFFFFA5
1637 rotli dest, temp, 16 */
1638 emit_move_insn (dest_reg
,
1639 gen_rtx_ROTATE (DImode
, temp
, GEN_INT (count
)));
1645 /* There are two cases here to produce a large constant.
1646 In the most general case, we do this:
1649 shl16insli x, x, hw2(NUM)
1650 shl16insli x, x, hw1(NUM)
1651 shl16insli x, x, hw0(NUM)
1653 However, we can sometimes do better. shl16insli is a poor way to
1654 insert 16 zero bits, because simply shifting left by 16 has more
1655 bundling freedom. So if we see any contiguous aligned sequence
1656 of 16 or more zero bits (below the highest set bit), it is always
1657 more efficient to materialize the bits above the zero bits, then
1658 left shift to put in the zeroes, then insert whatever bits
1659 remain. For example, we might end up with:
1661 movei x, NUM >> (37 + 16)
1663 shl16insli x, x, hw0(NUM) */
1665 zero_cluster_shift
= -1;
1667 for (shift
= 0; shift
< 48 - leading_zeroes
; shift
+= 16)
1669 HOST_WIDE_INT x
= val
>> shift
;
1671 /* Find the least significant group of 16 aligned zero bits. */
1672 if ((x
& 0xFFFF) == 0x0000)
1674 /* Grab any following zero bits as well. */
1675 zero_cluster_shift
= exact_log2 (x
& -x
);
1676 shift
+= zero_cluster_shift
;
1681 if (zero_cluster_shift
>= 0)
1683 unsigned HOST_WIDE_INT leftover
;
1685 /* Recursively create the constant above the lowest 16 zero
1687 expand_set_cint64 (temp
, GEN_INT (val
>> shift
));
1689 /* See if we can easily insert the remaining bits, or if we need
1690 to fall through to the more general case. */
1691 leftover
= val
- ((val
>> shift
) << shift
);
1694 /* A simple left shift is enough. */
1695 emit_move_insn (dest_reg
,
1696 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1699 else if (leftover
<= 32767)
1701 /* Left shift into position then add in the leftover. */
1702 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1703 emit_move_insn (temp2
,
1704 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1705 emit_move_insn (dest_reg
,
1706 gen_rtx_PLUS (DImode
, temp2
, GEN_INT (leftover
)));
1711 /* Shift in the batch of >= 16 zeroes we detected earlier.
1712 After this, shift will be aligned mod 16 so the final
1713 loop can use shl16insli. */
1714 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1715 rtx shift_count_rtx
= GEN_INT (zero_cluster_shift
);
1717 emit_move_insn (temp2
,
1718 gen_rtx_ASHIFT (DImode
, temp
, shift_count_rtx
));
1720 shift
-= zero_cluster_shift
;
1726 /* Set as many high 16-bit blocks as we can with a single
1727 instruction. We'll insert the remaining 16-bit blocks
1729 for (shift
= 16;; shift
+= 16)
1731 gcc_assert (shift
< 64);
1732 if (expand_set_cint64_one_inst (temp
, val
>> shift
, false))
1737 /* At this point, temp == val >> shift, shift % 16 == 0, and we
1738 still need to insert any bits of 'val' below 'shift'. Those bits
1739 are guaranteed to not have 16 contiguous zeroes. */
1741 gcc_assert ((shift
& 15) == 0);
1743 for (ins_shift
= shift
- 16; ins_shift
>= 0; ins_shift
-= 16)
1746 HOST_WIDE_INT bits
= (val
>> ins_shift
) & 0xFFFF;
1747 gcc_assert (bits
!= 0);
1749 /* On the last iteration we need to store into dest_reg. */
1753 result
= create_temp_reg_if_possible (DImode
, dest_reg
);
1755 emit_insn (gen_insn_shl16insli (result
, temp
, GEN_INT (bits
)));
1762 /* Load OP1, a 64-bit constant, into OP0, a register. We know it
1763 can't be done in one insn when we get here, the move expander
1766 tilegx_expand_set_const64 (rtx op0
, rtx op1
)
1768 if (CONST_INT_P (op1
))
1770 /* TODO: I don't know if we want to split large constants
1771 now, or wait until later (with a define_split).
1773 Does splitting early help CSE? Does it harm other
1774 optimizations that might fold loads? */
1775 expand_set_cint64 (op0
, op1
);
1779 rtx temp
= create_temp_reg_if_possible (Pmode
, op0
);
1783 /* Generate the 2-insn sequence to materialize a symbolic
1785 emit_insn (gen_mov_address_32bit_step1 (temp
, op1
));
1786 emit_insn (gen_mov_address_32bit_step2 (op0
, temp
, op1
));
1790 /* Generate the 3-insn sequence to materialize a symbolic
1791 address. Note that this assumes that virtual addresses
1792 fit in 48 signed bits, which is currently true. */
1793 rtx temp2
= create_temp_reg_if_possible (Pmode
, op0
);
1794 emit_insn (gen_mov_address_step1 (temp
, op1
));
1795 emit_insn (gen_mov_address_step2 (temp2
, temp
, op1
));
1796 emit_insn (gen_mov_address_step3 (op0
, temp2
, op1
));
1802 /* Expand a move instruction. Return true if all work is done. */
1804 tilegx_expand_mov (machine_mode mode
, rtx
*operands
)
1806 /* Handle sets of MEM first. */
1807 if (MEM_P (operands
[0]))
1809 if (can_create_pseudo_p ())
1810 operands
[0] = validize_mem (operands
[0]);
1812 if (reg_or_0_operand (operands
[1], mode
))
1815 if (!reload_in_progress
)
1816 operands
[1] = force_reg (mode
, operands
[1]);
1819 /* Fixup TLS cases. */
1820 if (CONSTANT_P (operands
[1]) && tilegx_tls_referenced_p (operands
[1]))
1822 operands
[1] = tilegx_legitimize_tls_address (operands
[1]);
1826 /* Fixup PIC cases. */
1827 if (flag_pic
&& CONSTANT_P (operands
[1]))
1829 if (tilegx_pic_address_needs_scratch (operands
[1]))
1830 operands
[1] = tilegx_legitimize_pic_address (operands
[1], mode
, 0);
1832 if (symbolic_operand (operands
[1], mode
))
1834 operands
[1] = tilegx_legitimize_pic_address (operands
[1],
1836 (reload_in_progress
?
1843 /* Accept non-constants and valid constants unmodified. */
1844 if (!CONSTANT_P (operands
[1]) || move_operand (operands
[1], mode
))
1847 /* Split large integers. */
1848 tilegx_expand_set_const64 (operands
[0], operands
[1]);
1853 /* Expand unaligned loads. */
1855 tilegx_expand_unaligned_load (rtx dest_reg
, rtx mem
, HOST_WIDE_INT bitsize
,
1856 HOST_WIDE_INT bit_offset
, bool sign
)
1859 rtx addr_lo
, addr_hi
;
1860 rtx mem_lo
, mem_hi
, hi
;
1861 rtx mema
, wide_result
;
1862 int last_byte_offset
;
1863 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1865 mode
= GET_MODE (dest_reg
);
1867 if (bitsize
== 2 * BITS_PER_UNIT
&& (bit_offset
% BITS_PER_UNIT
) == 0)
1869 rtx mem_left
, mem_right
;
1870 rtx left
= gen_reg_rtx (mode
);
1872 /* When just loading a two byte value, we can load the two bytes
1873 individually and combine them efficiently. */
1875 mem_lo
= adjust_address (mem
, QImode
, byte_offset
);
1876 mem_hi
= adjust_address (mem
, QImode
, byte_offset
+ 1);
1878 if (BYTES_BIG_ENDIAN
)
1891 /* Do a signed load of the second byte and use bfins to set
1892 the high bits of the result. */
1893 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, dest_reg
),
1895 emit_insn (gen_extendqidi2 (gen_lowpart (DImode
, left
), mem_left
));
1896 emit_insn (gen_insv (gen_lowpart (DImode
, dest_reg
),
1897 GEN_INT (64 - 8), GEN_INT (8),
1898 gen_lowpart (DImode
, left
)));
1902 /* Do two unsigned loads and use v1int_l to interleave
1904 rtx right
= gen_reg_rtx (mode
);
1905 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, right
),
1907 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, left
),
1909 emit_insn (gen_insn_v1int_l (gen_lowpart (DImode
, dest_reg
),
1910 gen_lowpart (DImode
, left
),
1911 gen_lowpart (DImode
, right
)));
1917 mema
= XEXP (mem
, 0);
1919 /* AND addresses cannot be in any alias set, since they may
1920 implicitly alias surrounding code. Ideally we'd have some alias
1921 set that covered all types except those with alignment 8 or
1923 addr_lo
= force_reg (Pmode
, plus_constant (Pmode
, mema
, byte_offset
));
1924 mem_lo
= change_address (mem
, mode
,
1925 gen_rtx_AND (GET_MODE (mema
), addr_lo
,
1927 set_mem_alias_set (mem_lo
, 0);
1929 /* Load the high word at an address that will not fault if the low
1930 address is aligned and at the very end of a page. */
1931 last_byte_offset
= (bit_offset
+ bitsize
- 1) / BITS_PER_UNIT
;
1932 addr_hi
= force_reg (Pmode
, plus_constant (Pmode
, mema
, last_byte_offset
));
1933 mem_hi
= change_address (mem
, mode
,
1934 gen_rtx_AND (GET_MODE (mema
), addr_hi
,
1936 set_mem_alias_set (mem_hi
, 0);
1940 addr_lo
= make_safe_from (addr_lo
, dest_reg
);
1941 wide_result
= dest_reg
;
1945 wide_result
= gen_reg_rtx (mode
);
1948 /* Load hi first in case dest_reg is used in mema. */
1949 hi
= gen_reg_rtx (mode
);
1950 emit_move_insn (hi
, mem_hi
);
1951 emit_move_insn (wide_result
, mem_lo
);
1953 emit_insn (gen_insn_dblalign (gen_lowpart (DImode
, wide_result
),
1954 gen_lowpart (DImode
, wide_result
),
1955 gen_lowpart (DImode
, hi
), addr_lo
));
1960 extract_bit_field (gen_lowpart (DImode
, wide_result
),
1961 bitsize
, bit_offset
% BITS_PER_UNIT
,
1962 !sign
, gen_lowpart (DImode
, dest_reg
),
1963 DImode
, DImode
, false, NULL
);
1965 if (extracted
!= dest_reg
)
1966 emit_move_insn (dest_reg
, gen_lowpart (DImode
, extracted
));
1971 /* Expand unaligned stores. */
1973 tilegx_expand_unaligned_store (rtx mem
, rtx src
, HOST_WIDE_INT bitsize
,
1974 HOST_WIDE_INT bit_offset
)
1976 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1977 HOST_WIDE_INT bytesize
= bitsize
/ BITS_PER_UNIT
;
1978 HOST_WIDE_INT shift_init
, shift_increment
, shift_amt
;
1983 shift_init
= BYTES_BIG_ENDIAN
? (bitsize
- BITS_PER_UNIT
) : 0;
1984 shift_increment
= BYTES_BIG_ENDIAN
? -BITS_PER_UNIT
: BITS_PER_UNIT
;
1986 for (i
= 0, shift_amt
= shift_init
;
1988 i
++, shift_amt
+= shift_increment
)
1990 mem_addr
= adjust_address (mem
, QImode
, byte_offset
+ i
);
1994 store_val
= expand_simple_binop (DImode
, LSHIFTRT
,
1995 gen_lowpart (DImode
, src
),
1996 GEN_INT (shift_amt
), NULL
, 1,
1998 store_val
= gen_lowpart (QImode
, store_val
);
2002 store_val
= gen_lowpart (QImode
, src
);
2005 emit_move_insn (mem_addr
, store_val
);
2010 /* Implement the movmisalign patterns. One of the operands is a
2011 memory that is not naturally aligned. Emit instructions to load
2014 tilegx_expand_movmisalign (machine_mode mode
, rtx
*operands
)
2016 if (MEM_P (operands
[1]))
2020 if (register_operand (operands
[0], mode
))
2023 tmp
= gen_reg_rtx (mode
);
2025 tilegx_expand_unaligned_load (tmp
, operands
[1], GET_MODE_BITSIZE (mode
),
2028 if (tmp
!= operands
[0])
2029 emit_move_insn (operands
[0], tmp
);
2031 else if (MEM_P (operands
[0]))
2033 if (!reg_or_0_operand (operands
[1], mode
))
2034 operands
[1] = force_reg (mode
, operands
[1]);
2036 tilegx_expand_unaligned_store (operands
[0], operands
[1],
2037 GET_MODE_BITSIZE (mode
), 0);
2045 /* Implement the allocate_stack pattern (alloca). */
2047 tilegx_allocate_stack (rtx op0
, rtx op1
)
2049 /* Technically the correct way to initialize chain_loc is with
2050 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
2051 * sets the alias_set to that of a frame reference. Some of our
2052 * tests rely on some unsafe assumption about when the chaining
2053 * update is done, we need to be conservative about reordering the
2054 * chaining instructions.
2056 rtx fp_addr
= gen_reg_rtx (Pmode
);
2057 rtx fp_value
= gen_reg_rtx (Pmode
);
2060 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2061 GEN_INT (UNITS_PER_WORD
)));
2063 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
2065 emit_move_insn (fp_value
, fp_loc
);
2067 op1
= force_reg (Pmode
, op1
);
2069 emit_move_insn (stack_pointer_rtx
,
2070 gen_rtx_MINUS (Pmode
, stack_pointer_rtx
, op1
));
2072 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2073 GEN_INT (UNITS_PER_WORD
)));
2075 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
2077 emit_move_insn (fp_loc
, fp_value
);
2079 emit_move_insn (op0
, virtual_stack_dynamic_rtx
);
2087 /* Returns the insn_code in ENTRY. */
2088 static enum insn_code
2089 tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry
2092 return tilegx_multiply_insn_seq_decode_opcode
[entry
->compressed_opcode
];
2096 /* Returns the length of the 'op' array. */
2098 tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq
*seq
)
2100 /* The array either uses all of its allocated slots or is terminated
2101 by a bogus opcode. Either way, the array size is the index of the
2102 last valid opcode plus one. */
2104 for (i
= tilegx_multiply_insn_seq_MAX_OPERATIONS
- 1; i
>= 0; i
--)
2105 if (tilegx_multiply_get_opcode (&seq
->op
[i
]) != CODE_FOR_nothing
)
2108 /* An empty array is not allowed. */
2113 /* We precompute a number of expression trees for multiplying by
2114 constants. This generates code for such an expression tree by
2115 walking through the nodes in the tree (which are conveniently
2116 pre-linearized) and emitting an instruction for each one. */
2118 tilegx_expand_constant_multiply_given_sequence (rtx result
, rtx src
,
2120 tilegx_multiply_insn_seq
*seq
)
2125 /* Keep track of the subexpressions computed so far, so later
2126 instructions can refer to them. We seed the array with zero and
2127 the value being multiplied. */
2128 int num_subexprs
= 2;
2129 rtx subexprs
[tilegx_multiply_insn_seq_MAX_OPERATIONS
+ 2];
2130 subexprs
[0] = const0_rtx
;
2133 /* Determine how many instructions we are going to generate. */
2134 num_ops
= tilegx_multiply_get_num_ops (seq
);
2135 gcc_assert (num_ops
> 0
2136 && num_ops
<= tilegx_multiply_insn_seq_MAX_OPERATIONS
);
2138 for (i
= 0; i
< num_ops
; i
++)
2140 const struct tilegx_multiply_insn_seq_entry
*entry
= &seq
->op
[i
];
2142 /* Figure out where to store the output of this instruction. */
2143 const bool is_last_op
= (i
+ 1 == num_ops
);
2144 rtx out
= is_last_op
? result
: gen_reg_rtx (DImode
);
2146 enum insn_code opcode
= tilegx_multiply_get_opcode (entry
);
2147 if (opcode
== CODE_FOR_ashldi3
)
2149 /* Handle shift by immediate. This is a special case because
2150 the meaning of the second operand is a constant shift
2151 count rather than an operand index. */
2153 /* Make sure the shift count is in range. Zero should not
2155 const int shift_count
= entry
->rhs
;
2156 gcc_assert (shift_count
> 0 && shift_count
< 64);
2158 /* Emit the actual instruction. */
2159 emit_insn (GEN_FCN (opcode
)
2160 (out
, subexprs
[entry
->lhs
],
2161 gen_rtx_CONST_INT (DImode
, shift_count
)));
2165 /* Handle a normal two-operand instruction, such as add or
2168 /* Make sure we are referring to a previously computed
2170 gcc_assert (entry
->rhs
< num_subexprs
);
2172 /* Emit the actual instruction. */
2173 emit_insn (GEN_FCN (opcode
)
2174 (out
, subexprs
[entry
->lhs
], subexprs
[entry
->rhs
]));
2177 /* Record this subexpression for use by later expressions. */
2178 subexprs
[num_subexprs
++] = out
;
2183 /* bsearch helper function. */
2185 tilegx_compare_multipliers (const void *key
, const void *t
)
2188 (*(const long long *) key
2189 - ((const struct tilegx_multiply_insn_seq
*) t
)->multiplier
);
2190 return (delta
< 0) ? -1 : (delta
> 0);
2194 /* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none
2196 static const struct tilegx_multiply_insn_seq
*
2197 tilegx_find_multiply_insn_seq_for_constant (long long multiplier
)
2199 return ((const struct tilegx_multiply_insn_seq
*)
2200 bsearch (&multiplier
, tilegx_multiply_insn_seq_table
,
2201 tilegx_multiply_insn_seq_table_size
,
2202 sizeof tilegx_multiply_insn_seq_table
[0],
2203 tilegx_compare_multipliers
));
2207 /* Try to a expand constant multiply in DImode by looking it up in a
2208 precompiled table. OP0 is the result operand, OP1 is the source
2209 operand, and MULTIPLIER is the value of the constant. Return true
2212 tilegx_expand_const_muldi (rtx op0
, rtx op1
, long long multiplier
)
2214 /* See if we have precomputed an efficient way to multiply by this
2216 const struct tilegx_multiply_insn_seq
*seq
=
2217 tilegx_find_multiply_insn_seq_for_constant (multiplier
);
2220 tilegx_expand_constant_multiply_given_sequence (op0
, op1
, seq
);
2228 /* Expand the muldi pattern. */
2230 tilegx_expand_muldi (rtx op0
, rtx op1
, rtx op2
)
2232 if (CONST_INT_P (op2
))
2234 HOST_WIDE_INT n
= trunc_int_for_mode (INTVAL (op2
), DImode
);
2235 return tilegx_expand_const_muldi (op0
, op1
, n
);
2241 /* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the
2242 operands, and SIGN is true if it's a signed multiply, and false if
2243 it's an unsigned multiply. */
2245 tilegx_expand_high_multiply (rtx result
, rtx op1
, rtx op2
, bool sign
)
2247 rtx tmp0
= gen_reg_rtx (DImode
);
2248 rtx tmp1
= gen_reg_rtx (DImode
);
2249 rtx tmp2
= gen_reg_rtx (DImode
);
2250 rtx tmp3
= gen_reg_rtx (DImode
);
2251 rtx tmp4
= gen_reg_rtx (DImode
);
2252 rtx tmp5
= gen_reg_rtx (DImode
);
2253 rtx tmp6
= gen_reg_rtx (DImode
);
2254 rtx tmp7
= gen_reg_rtx (DImode
);
2255 rtx tmp8
= gen_reg_rtx (DImode
);
2256 rtx tmp9
= gen_reg_rtx (DImode
);
2257 rtx tmp10
= gen_reg_rtx (DImode
);
2258 rtx tmp11
= gen_reg_rtx (DImode
);
2259 rtx tmp12
= gen_reg_rtx (DImode
);
2260 rtx tmp13
= gen_reg_rtx (DImode
);
2261 rtx result_lo
= gen_reg_rtx (DImode
);
2265 emit_insn (gen_insn_mul_hs_lu (tmp0
, op1
, op2
));
2266 emit_insn (gen_insn_mul_hs_lu (tmp1
, op2
, op1
));
2267 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2268 emit_insn (gen_insn_mul_hs_hs (tmp3
, op1
, op2
));
2272 emit_insn (gen_insn_mul_hu_lu (tmp0
, op1
, op2
));
2273 emit_insn (gen_insn_mul_hu_lu (tmp1
, op2
, op1
));
2274 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2275 emit_insn (gen_insn_mul_hu_hu (tmp3
, op1
, op2
));
2278 emit_move_insn (tmp4
, (gen_rtx_ASHIFT (DImode
, tmp0
, GEN_INT (32))));
2280 emit_move_insn (tmp5
, (gen_rtx_ASHIFT (DImode
, tmp1
, GEN_INT (32))));
2282 emit_move_insn (tmp6
, (gen_rtx_PLUS (DImode
, tmp4
, tmp5
)));
2283 emit_move_insn (result_lo
, (gen_rtx_PLUS (DImode
, tmp2
, tmp6
)));
2285 emit_move_insn (tmp7
, gen_rtx_LTU (DImode
, tmp6
, tmp4
));
2286 emit_move_insn (tmp8
, gen_rtx_LTU (DImode
, result_lo
, tmp2
));
2290 emit_move_insn (tmp9
, (gen_rtx_ASHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2291 emit_move_insn (tmp10
, (gen_rtx_ASHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2295 emit_move_insn (tmp9
, (gen_rtx_LSHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2296 emit_move_insn (tmp10
, (gen_rtx_LSHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2299 emit_move_insn (tmp11
, (gen_rtx_PLUS (DImode
, tmp3
, tmp7
)));
2300 emit_move_insn (tmp12
, (gen_rtx_PLUS (DImode
, tmp8
, tmp9
)));
2301 emit_move_insn (tmp13
, (gen_rtx_PLUS (DImode
, tmp11
, tmp12
)));
2302 emit_move_insn (result
, (gen_rtx_PLUS (DImode
, tmp13
, tmp10
)));
2306 /* Implement smuldi3_highpart. */
2308 tilegx_expand_smuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2310 tilegx_expand_high_multiply (op0
, op1
, op2
, true);
2314 /* Implement umuldi3_highpart. */
2316 tilegx_expand_umuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2318 tilegx_expand_high_multiply (op0
, op1
, op2
, false);
2323 /* Compare and branches */
2325 /* Produce the rtx yielding a bool for a floating point
2328 tilegx_emit_fp_setcc (rtx res
, enum rtx_code code
, machine_mode mode
,
2331 /* TODO: Certain compares again constants can be done using entirely
2332 integer operations. But you have to get the special cases right
2333 e.g. NaN, +0 == -0, etc. */
2337 rtx a
= force_reg (DImode
, gen_lowpart (DImode
, op0
));
2338 rtx b
= force_reg (DImode
, gen_lowpart (DImode
, op1
));
2340 flags
= gen_reg_rtx (DImode
);
2344 emit_insn (gen_insn_fsingle_add1 (flags
, a
, b
));
2348 gcc_assert (mode
== DFmode
);
2349 emit_insn (gen_insn_fdouble_add_flags (flags
, a
, b
));
2354 case EQ
: flag_index
= 30; break;
2355 case NE
: flag_index
= 31; break;
2356 case LE
: flag_index
= 27; break;
2357 case LT
: flag_index
= 26; break;
2358 case GE
: flag_index
= 29; break;
2359 case GT
: flag_index
= 28; break;
2360 default: gcc_unreachable ();
2363 gcc_assert (GET_MODE (res
) == DImode
);
2364 emit_move_insn (res
, gen_rtx_ZERO_EXTRACT (DImode
, flags
, GEN_INT (1),
2365 GEN_INT (flag_index
)));
2370 /* Certain simplifications can be done to make invalid setcc
2371 operations valid. Return the final comparison, or NULL if we can't
2374 tilegx_emit_setcc_internal (rtx res
, enum rtx_code code
, rtx op0
, rtx op1
,
2375 machine_mode cmp_mode
)
2380 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2381 return tilegx_emit_fp_setcc (res
, code
, cmp_mode
, op0
, op1
);
2383 /* The general case: fold the comparison code to the types of
2384 compares that we have, choosing the branch as necessary. */
2394 /* We have these compares. */
2401 /* We do not have these compares, so we reverse the
2407 /* We should not have called this with any other code. */
2413 code
= swap_condition (code
);
2414 tmp
= op0
, op0
= op1
, op1
= tmp
;
2417 if (!reg_or_0_operand (op0
, cmp_mode
))
2418 op0
= force_reg (cmp_mode
, op0
);
2420 if (!CONST_INT_P (op1
) && !register_operand (op1
, cmp_mode
))
2421 op1
= force_reg (cmp_mode
, op1
);
2423 /* Return the setcc comparison. */
2424 emit_insn (gen_rtx_SET (res
, gen_rtx_fmt_ee (code
, DImode
, op0
, op1
)));
2430 /* Implement cstore patterns. */
2432 tilegx_emit_setcc (rtx operands
[], machine_mode cmp_mode
)
2435 tilegx_emit_setcc_internal (operands
[0], GET_CODE (operands
[1]),
2436 operands
[2], operands
[3], cmp_mode
);
2440 /* Return whether CODE is a signed comparison. */
2442 signed_compare_p (enum rtx_code code
)
2444 return (code
== EQ
|| code
== NE
|| code
== LT
|| code
== LE
2445 || code
== GT
|| code
== GE
);
2449 /* Generate the comparison for a DImode conditional branch. */
2451 tilegx_emit_cc_test (enum rtx_code code
, rtx op0
, rtx op1
,
2452 machine_mode cmp_mode
, bool eq_ne_only
)
2454 enum rtx_code branch_code
;
2457 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2459 /* Compute a boolean saying whether the comparison is true. */
2460 temp
= gen_reg_rtx (DImode
);
2461 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2463 /* Test that flag. */
2464 return gen_rtx_fmt_ee (NE
, VOIDmode
, temp
, const0_rtx
);
2467 /* Check for a compare against zero using a comparison we can do
2469 if (op1
== const0_rtx
2470 && (code
== EQ
|| code
== NE
2471 || (!eq_ne_only
&& signed_compare_p (code
))))
2473 op0
= force_reg (cmp_mode
, op0
);
2474 return gen_rtx_fmt_ee (code
, VOIDmode
, op0
, const0_rtx
);
2477 /* The general case: fold the comparison code to the types of
2478 compares that we have, choosing the branch as necessary. */
2486 /* We have these compares. */
2495 /* These must be reversed (except NE, but let's
2497 code
= reverse_condition (code
);
2505 if (CONST_INT_P (op1
) && (!satisfies_constraint_I (op1
) || code
== LEU
))
2507 HOST_WIDE_INT n
= INTVAL (op1
);
2512 /* Subtract off the value we want to compare against and see
2513 if we get zero. This is cheaper than creating a constant
2514 in a register. Except that subtracting -128 is more
2515 expensive than seqi to -128, so we leave that alone. */
2516 /* ??? Don't do this when comparing against symbols,
2517 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2518 0), which will be declared false out of hand (at least
2521 && add_operand (GEN_INT (-n
), DImode
)
2522 && !(symbolic_operand (op0
, VOIDmode
)
2523 || (REG_P (op0
) && REG_POINTER (op0
))))
2525 /* TODO: Use a SIMD add immediate to hit zero for tiled
2526 constants in a single instruction. */
2527 if (GET_MODE (op0
) != DImode
)
2529 /* Convert to DImode so we can use addli. Note that
2530 this will not actually generate any code because
2531 sign extension from SI -> DI is a no-op. I don't
2532 know if it's safe just to make a paradoxical
2533 subreg here though. */
2534 rtx temp2
= gen_reg_rtx (DImode
);
2535 emit_insn (gen_extendsidi2 (temp2
, op0
));
2540 op0
= force_reg (DImode
, op0
);
2542 temp
= gen_reg_rtx (DImode
);
2543 emit_move_insn (temp
, gen_rtx_PLUS (DImode
, op0
, GEN_INT (-n
)));
2544 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2545 VOIDmode
, temp
, const0_rtx
);
2555 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2556 We use arithmetic shift right because it's a 3-wide op,
2557 while logical shift right is not. */
2559 int first
= exact_log2 (code
== LTU
? n
: n
+ 1);
2562 op0
= force_reg (cmp_mode
, op0
);
2563 temp
= gen_reg_rtx (cmp_mode
);
2564 emit_move_insn (temp
,
2565 gen_rtx_ASHIFTRT (cmp_mode
, op0
,
2567 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2568 VOIDmode
, temp
, const0_rtx
);
2578 /* Compute a flag saying whether we should branch. */
2579 temp
= gen_reg_rtx (DImode
);
2580 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2582 /* Return the branch comparison. */
2583 return gen_rtx_fmt_ee (branch_code
, VOIDmode
, temp
, const0_rtx
);
2587 /* Generate the comparison for a conditional branch. */
2589 tilegx_emit_conditional_branch (rtx operands
[], machine_mode cmp_mode
)
2592 tilegx_emit_cc_test (GET_CODE (operands
[0]), operands
[1], operands
[2],
2594 rtx branch_rtx
= gen_rtx_SET (pc_rtx
,
2595 gen_rtx_IF_THEN_ELSE (VOIDmode
, cmp_rtx
,
2600 emit_jump_insn (branch_rtx
);
2604 /* Implement the mov<mode>cc pattern. */
2606 tilegx_emit_conditional_move (rtx cmp
)
2609 tilegx_emit_cc_test (GET_CODE (cmp
), XEXP (cmp
, 0), XEXP (cmp
, 1),
2610 GET_MODE (XEXP (cmp
, 0)), true);
2614 /* Return true if INSN is annotated with a REG_BR_PROB note that
2615 indicates it's a branch that's predicted taken. */
2617 cbranch_predicted_p (rtx_insn
*insn
)
2619 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2623 return profile_probability::from_reg_br_prob_note (XINT (x
, 0))
2624 >= profile_probability::even ();
2631 /* Output assembly code for a specific branch instruction, appending
2632 the branch prediction flag to the opcode if appropriate. */
2634 tilegx_output_simple_cbranch_with_opcode (rtx_insn
*insn
, const char *opcode
,
2635 int regop
, bool reverse_predicted
)
2637 static char buf
[64];
2638 sprintf (buf
, "%s%s\t%%r%d, %%l0", opcode
,
2639 (cbranch_predicted_p (insn
) ^ reverse_predicted
) ? "t" : "",
2645 /* Output assembly code for a specific branch instruction, appending
2646 the branch prediction flag to the opcode if appropriate. */
2648 tilegx_output_cbranch_with_opcode (rtx_insn
*insn
, rtx
*operands
,
2650 const char *rev_opcode
, int regop
)
2652 const char *branch_if_false
;
2653 rtx taken
, not_taken
;
2654 bool is_simple_branch
;
2656 gcc_assert (LABEL_P (operands
[0]));
2658 is_simple_branch
= true;
2659 if (INSN_ADDRESSES_SET_P ())
2661 int from_addr
= INSN_ADDRESSES (INSN_UID (insn
));
2662 int to_addr
= INSN_ADDRESSES (INSN_UID (operands
[0]));
2663 int delta
= to_addr
- from_addr
;
2664 is_simple_branch
= IN_RANGE (delta
, -524288, 524280);
2667 if (is_simple_branch
)
2669 /* Just a simple conditional branch. */
2671 tilegx_output_simple_cbranch_with_opcode (insn
, opcode
, regop
, false);
2674 /* Generate a reversed branch around a direct jump. This fallback
2675 does not use branch-likely instructions. */
2676 not_taken
= gen_label_rtx ();
2677 taken
= operands
[0];
2679 /* Generate the reversed branch to NOT_TAKEN. */
2680 operands
[0] = not_taken
;
2682 tilegx_output_simple_cbranch_with_opcode (insn
, rev_opcode
, regop
, true);
2683 output_asm_insn (branch_if_false
, operands
);
2685 output_asm_insn ("j\t%l0", &taken
);
2687 /* Output NOT_TAKEN. */
2688 targetm
.asm_out
.internal_label (asm_out_file
, "L",
2689 CODE_LABEL_NUMBER (not_taken
));
2694 /* Output assembly code for a conditional branch instruction. */
2696 tilegx_output_cbranch (rtx_insn
*insn
, rtx
*operands
, bool reversed
)
2698 enum rtx_code code
= GET_CODE (operands
[1]);
2700 const char *rev_opcode
;
2703 code
= reverse_condition (code
);
2709 rev_opcode
= "beqz";
2713 rev_opcode
= "bnez";
2717 rev_opcode
= "bltz";
2721 rev_opcode
= "blez";
2725 rev_opcode
= "bgtz";
2729 rev_opcode
= "bgez";
2735 return tilegx_output_cbranch_with_opcode (insn
, operands
, opcode
,
2740 /* Implement the tablejump pattern. */
2742 tilegx_expand_tablejump (rtx op0
, rtx op1
)
2746 rtx temp
= gen_reg_rtx (Pmode
);
2747 rtx temp2
= gen_reg_rtx (Pmode
);
2749 tilegx_compute_pcrel_address (temp
, gen_rtx_LABEL_REF (Pmode
, op1
));
2750 emit_move_insn (temp2
,
2751 gen_rtx_PLUS (Pmode
,
2752 convert_to_mode (Pmode
, op0
, false),
2757 emit_jump_insn (gen_tablejump_aux (op0
, op1
));
2761 /* Emit barrier before an atomic, as needed for the memory MODEL. */
2763 tilegx_pre_atomic_barrier (enum memmodel model
)
2765 if (need_atomic_barrier_p (model
, true))
2766 emit_insn (gen_memory_barrier ());
2770 /* Emit barrier after an atomic, as needed for the memory MODEL. */
2772 tilegx_post_atomic_barrier (enum memmodel model
)
2774 if (need_atomic_barrier_p (model
, false))
2775 emit_insn (gen_memory_barrier ());
2780 /* Expand a builtin vector binary op, by calling gen function GEN with
2781 operands in the proper modes. DEST is converted to DEST_MODE, and
2782 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2784 tilegx_expand_builtin_vector_binop (rtx (*gen
) (rtx
, rtx
, rtx
),
2785 machine_mode dest_mode
,
2787 machine_mode src_mode
,
2788 rtx src0
, rtx src1
, bool do_src1
)
2790 dest
= gen_lowpart (dest_mode
, dest
);
2792 if (src0
== const0_rtx
)
2793 src0
= CONST0_RTX (src_mode
);
2795 src0
= gen_lowpart (src_mode
, src0
);
2799 if (src1
== const0_rtx
)
2800 src1
= CONST0_RTX (src_mode
);
2802 src1
= gen_lowpart (src_mode
, src1
);
2805 emit_insn ((*gen
) (dest
, src0
, src1
));
2813 struct tile_builtin_info
2815 enum insn_code icode
;
2819 static struct tile_builtin_info tilegx_builtin_info
[TILEGX_BUILTIN_max
] = {
2820 { CODE_FOR_adddi3
, NULL
}, /* add */
2821 { CODE_FOR_addsi3
, NULL
}, /* addx */
2822 { CODE_FOR_ssaddsi3
, NULL
}, /* addxsc */
2823 { CODE_FOR_anddi3
, NULL
}, /* and */
2824 { CODE_FOR_insn_bfexts
, NULL
}, /* bfexts */
2825 { CODE_FOR_insn_bfextu
, NULL
}, /* bfextu */
2826 { CODE_FOR_insn_bfins
, NULL
}, /* bfins */
2827 { CODE_FOR_clzdi2
, NULL
}, /* clz */
2828 { CODE_FOR_insn_cmoveqz
, NULL
}, /* cmoveqz */
2829 { CODE_FOR_insn_cmovnez
, NULL
}, /* cmovnez */
2830 { CODE_FOR_insn_cmpeq_didi
, NULL
}, /* cmpeq */
2831 { CODE_FOR_insn_cmpexch
, NULL
}, /* cmpexch */
2832 { CODE_FOR_insn_cmpexch4
, NULL
}, /* cmpexch4 */
2833 { CODE_FOR_insn_cmples_didi
, NULL
}, /* cmples */
2834 { CODE_FOR_insn_cmpleu_didi
, NULL
}, /* cmpleu */
2835 { CODE_FOR_insn_cmplts_didi
, NULL
}, /* cmplts */
2836 { CODE_FOR_insn_cmpltu_didi
, NULL
}, /* cmpltu */
2837 { CODE_FOR_insn_cmpne_didi
, NULL
}, /* cmpne */
2838 { CODE_FOR_insn_cmul
, NULL
}, /* cmul */
2839 { CODE_FOR_insn_cmula
, NULL
}, /* cmula */
2840 { CODE_FOR_insn_cmulaf
, NULL
}, /* cmulaf */
2841 { CODE_FOR_insn_cmulf
, NULL
}, /* cmulf */
2842 { CODE_FOR_insn_cmulfr
, NULL
}, /* cmulfr */
2843 { CODE_FOR_insn_cmulh
, NULL
}, /* cmulh */
2844 { CODE_FOR_insn_cmulhr
, NULL
}, /* cmulhr */
2845 { CODE_FOR_insn_crc32_32
, NULL
}, /* crc32_32 */
2846 { CODE_FOR_insn_crc32_8
, NULL
}, /* crc32_8 */
2847 { CODE_FOR_ctzdi2
, NULL
}, /* ctz */
2848 { CODE_FOR_insn_dblalign
, NULL
}, /* dblalign */
2849 { CODE_FOR_insn_dblalign2
, NULL
}, /* dblalign2 */
2850 { CODE_FOR_insn_dblalign4
, NULL
}, /* dblalign4 */
2851 { CODE_FOR_insn_dblalign6
, NULL
}, /* dblalign6 */
2852 { CODE_FOR_insn_drain
, NULL
}, /* drain */
2853 { CODE_FOR_insn_dtlbpr
, NULL
}, /* dtlbpr */
2854 { CODE_FOR_insn_exch
, NULL
}, /* exch */
2855 { CODE_FOR_insn_exch4
, NULL
}, /* exch4 */
2856 { CODE_FOR_insn_fdouble_add_flags
, NULL
}, /* fdouble_add_flags */
2857 { CODE_FOR_insn_fdouble_addsub
, NULL
}, /* fdouble_addsub */
2858 { CODE_FOR_insn_fdouble_mul_flags
, NULL
}, /* fdouble_mul_flags */
2859 { CODE_FOR_insn_fdouble_pack1
, NULL
}, /* fdouble_pack1 */
2860 { CODE_FOR_insn_fdouble_pack2
, NULL
}, /* fdouble_pack2 */
2861 { CODE_FOR_insn_fdouble_sub_flags
, NULL
}, /* fdouble_sub_flags */
2862 { CODE_FOR_insn_fdouble_unpack_max
, NULL
}, /* fdouble_unpack_max */
2863 { CODE_FOR_insn_fdouble_unpack_min
, NULL
}, /* fdouble_unpack_min */
2864 { CODE_FOR_insn_fetchadd
, NULL
}, /* fetchadd */
2865 { CODE_FOR_insn_fetchadd4
, NULL
}, /* fetchadd4 */
2866 { CODE_FOR_insn_fetchaddgez
, NULL
}, /* fetchaddgez */
2867 { CODE_FOR_insn_fetchaddgez4
, NULL
}, /* fetchaddgez4 */
2868 { CODE_FOR_insn_fetchand
, NULL
}, /* fetchand */
2869 { CODE_FOR_insn_fetchand4
, NULL
}, /* fetchand4 */
2870 { CODE_FOR_insn_fetchor
, NULL
}, /* fetchor */
2871 { CODE_FOR_insn_fetchor4
, NULL
}, /* fetchor4 */
2872 { CODE_FOR_insn_finv
, NULL
}, /* finv */
2873 { CODE_FOR_insn_flush
, NULL
}, /* flush */
2874 { CODE_FOR_insn_flushwb
, NULL
}, /* flushwb */
2875 { CODE_FOR_insn_fnop
, NULL
}, /* fnop */
2876 { CODE_FOR_insn_fsingle_add1
, NULL
}, /* fsingle_add1 */
2877 { CODE_FOR_insn_fsingle_addsub2
, NULL
}, /* fsingle_addsub2 */
2878 { CODE_FOR_insn_fsingle_mul1
, NULL
}, /* fsingle_mul1 */
2879 { CODE_FOR_insn_fsingle_mul2
, NULL
}, /* fsingle_mul2 */
2880 { CODE_FOR_insn_fsingle_pack1
, NULL
}, /* fsingle_pack1 */
2881 { CODE_FOR_insn_fsingle_pack2
, NULL
}, /* fsingle_pack2 */
2882 { CODE_FOR_insn_fsingle_sub1
, NULL
}, /* fsingle_sub1 */
2883 { CODE_FOR_insn_icoh
, NULL
}, /* icoh */
2884 { CODE_FOR_insn_ill
, NULL
}, /* ill */
2885 { CODE_FOR_insn_info
, NULL
}, /* info */
2886 { CODE_FOR_insn_infol
, NULL
}, /* infol */
2887 { CODE_FOR_insn_inv
, NULL
}, /* inv */
2888 { CODE_FOR_insn_ld
, NULL
}, /* ld */
2889 { CODE_FOR_insn_ld1s
, NULL
}, /* ld1s */
2890 { CODE_FOR_insn_ld1u
, NULL
}, /* ld1u */
2891 { CODE_FOR_insn_ld2s
, NULL
}, /* ld2s */
2892 { CODE_FOR_insn_ld2u
, NULL
}, /* ld2u */
2893 { CODE_FOR_insn_ld4s
, NULL
}, /* ld4s */
2894 { CODE_FOR_insn_ld4u
, NULL
}, /* ld4u */
2895 { CODE_FOR_insn_ldna
, NULL
}, /* ldna */
2896 { CODE_FOR_insn_ldnt
, NULL
}, /* ldnt */
2897 { CODE_FOR_insn_ldnt1s
, NULL
}, /* ldnt1s */
2898 { CODE_FOR_insn_ldnt1u
, NULL
}, /* ldnt1u */
2899 { CODE_FOR_insn_ldnt2s
, NULL
}, /* ldnt2s */
2900 { CODE_FOR_insn_ldnt2u
, NULL
}, /* ldnt2u */
2901 { CODE_FOR_insn_ldnt4s
, NULL
}, /* ldnt4s */
2902 { CODE_FOR_insn_ldnt4u
, NULL
}, /* ldnt4u */
2903 { CODE_FOR_insn_ld_L2
, NULL
}, /* ld_L2 */
2904 { CODE_FOR_insn_ld1s_L2
, NULL
}, /* ld1s_L2 */
2905 { CODE_FOR_insn_ld1u_L2
, NULL
}, /* ld1u_L2 */
2906 { CODE_FOR_insn_ld2s_L2
, NULL
}, /* ld2s_L2 */
2907 { CODE_FOR_insn_ld2u_L2
, NULL
}, /* ld2u_L2 */
2908 { CODE_FOR_insn_ld4s_L2
, NULL
}, /* ld4s_L2 */
2909 { CODE_FOR_insn_ld4u_L2
, NULL
}, /* ld4u_L2 */
2910 { CODE_FOR_insn_ldna_L2
, NULL
}, /* ldna_L2 */
2911 { CODE_FOR_insn_ldnt_L2
, NULL
}, /* ldnt_L2 */
2912 { CODE_FOR_insn_ldnt1s_L2
, NULL
}, /* ldnt1s_L2 */
2913 { CODE_FOR_insn_ldnt1u_L2
, NULL
}, /* ldnt1u_L2 */
2914 { CODE_FOR_insn_ldnt2s_L2
, NULL
}, /* ldnt2s_L2 */
2915 { CODE_FOR_insn_ldnt2u_L2
, NULL
}, /* ldnt2u_L2 */
2916 { CODE_FOR_insn_ldnt4s_L2
, NULL
}, /* ldnt4s_L2 */
2917 { CODE_FOR_insn_ldnt4u_L2
, NULL
}, /* ldnt4u_L2 */
2918 { CODE_FOR_insn_ld_miss
, NULL
}, /* ld_miss */
2919 { CODE_FOR_insn_ld1s_miss
, NULL
}, /* ld1s_miss */
2920 { CODE_FOR_insn_ld1u_miss
, NULL
}, /* ld1u_miss */
2921 { CODE_FOR_insn_ld2s_miss
, NULL
}, /* ld2s_miss */
2922 { CODE_FOR_insn_ld2u_miss
, NULL
}, /* ld2u_miss */
2923 { CODE_FOR_insn_ld4s_miss
, NULL
}, /* ld4s_miss */
2924 { CODE_FOR_insn_ld4u_miss
, NULL
}, /* ld4u_miss */
2925 { CODE_FOR_insn_ldna_miss
, NULL
}, /* ldna_miss */
2926 { CODE_FOR_insn_ldnt_miss
, NULL
}, /* ldnt_miss */
2927 { CODE_FOR_insn_ldnt1s_miss
, NULL
}, /* ldnt1s_miss */
2928 { CODE_FOR_insn_ldnt1u_miss
, NULL
}, /* ldnt1u_miss */
2929 { CODE_FOR_insn_ldnt2s_miss
, NULL
}, /* ldnt2s_miss */
2930 { CODE_FOR_insn_ldnt2u_miss
, NULL
}, /* ldnt2u_miss */
2931 { CODE_FOR_insn_ldnt4s_miss
, NULL
}, /* ldnt4s_miss */
2932 { CODE_FOR_insn_ldnt4u_miss
, NULL
}, /* ldnt4u_miss */
2933 { CODE_FOR_insn_lnk
, NULL
}, /* lnk */
2934 { CODE_FOR_memory_barrier
, NULL
}, /* mf */
2935 { CODE_FOR_insn_mfspr
, NULL
}, /* mfspr */
2936 { CODE_FOR_insn_mm
, NULL
}, /* mm */
2937 { CODE_FOR_insn_mnz
, NULL
}, /* mnz */
2938 { CODE_FOR_movdi
, NULL
}, /* move */
2939 { CODE_FOR_insn_mtspr
, NULL
}, /* mtspr */
2940 { CODE_FOR_insn_mul_hs_hs
, NULL
}, /* mul_hs_hs */
2941 { CODE_FOR_insn_mul_hs_hu
, NULL
}, /* mul_hs_hu */
2942 { CODE_FOR_insn_mul_hs_ls
, NULL
}, /* mul_hs_ls */
2943 { CODE_FOR_insn_mul_hs_lu
, NULL
}, /* mul_hs_lu */
2944 { CODE_FOR_insn_mul_hu_hu
, NULL
}, /* mul_hu_hu */
2945 { CODE_FOR_insn_mul_hu_ls
, NULL
}, /* mul_hu_ls */
2946 { CODE_FOR_insn_mul_hu_lu
, NULL
}, /* mul_hu_lu */
2947 { CODE_FOR_insn_mul_ls_ls
, NULL
}, /* mul_ls_ls */
2948 { CODE_FOR_insn_mul_ls_lu
, NULL
}, /* mul_ls_lu */
2949 { CODE_FOR_insn_mul_lu_lu
, NULL
}, /* mul_lu_lu */
2950 { CODE_FOR_insn_mula_hs_hs
, NULL
}, /* mula_hs_hs */
2951 { CODE_FOR_insn_mula_hs_hu
, NULL
}, /* mula_hs_hu */
2952 { CODE_FOR_insn_mula_hs_ls
, NULL
}, /* mula_hs_ls */
2953 { CODE_FOR_insn_mula_hs_lu
, NULL
}, /* mula_hs_lu */
2954 { CODE_FOR_insn_mula_hu_hu
, NULL
}, /* mula_hu_hu */
2955 { CODE_FOR_insn_mula_hu_ls
, NULL
}, /* mula_hu_ls */
2956 { CODE_FOR_insn_mula_hu_lu
, NULL
}, /* mula_hu_lu */
2957 { CODE_FOR_insn_mula_ls_ls
, NULL
}, /* mula_ls_ls */
2958 { CODE_FOR_insn_mula_ls_lu
, NULL
}, /* mula_ls_lu */
2959 { CODE_FOR_insn_mula_lu_lu
, NULL
}, /* mula_lu_lu */
2960 { CODE_FOR_insn_mulax
, NULL
}, /* mulax */
2961 { CODE_FOR_mulsi3
, NULL
}, /* mulx */
2962 { CODE_FOR_insn_mz
, NULL
}, /* mz */
2963 { CODE_FOR_insn_nap
, NULL
}, /* nap */
2964 { CODE_FOR_nop
, NULL
}, /* nop */
2965 { CODE_FOR_insn_nor_di
, NULL
}, /* nor */
2966 { CODE_FOR_iordi3
, NULL
}, /* or */
2967 { CODE_FOR_popcountdi2
, NULL
}, /* pcnt */
2968 { CODE_FOR_insn_prefetch_l1
, NULL
}, /* prefetch_l1 */
2969 { CODE_FOR_insn_prefetch_l1_fault
, NULL
}, /* prefetch_l1_fault */
2970 { CODE_FOR_insn_prefetch_l2
, NULL
}, /* prefetch_l2 */
2971 { CODE_FOR_insn_prefetch_l2_fault
, NULL
}, /* prefetch_l2_fault */
2972 { CODE_FOR_insn_prefetch_l3
, NULL
}, /* prefetch_l3 */
2973 { CODE_FOR_insn_prefetch_l3_fault
, NULL
}, /* prefetch_l3_fault */
2974 { CODE_FOR_insn_revbits
, NULL
}, /* revbits */
2975 { CODE_FOR_bswapdi2
, NULL
}, /* revbytes */
2976 { CODE_FOR_rotldi3
, NULL
}, /* rotl */
2977 { CODE_FOR_ashldi3
, NULL
}, /* shl */
2978 { CODE_FOR_insn_shl16insli
, NULL
}, /* shl16insli */
2979 { CODE_FOR_insn_shl1add
, NULL
}, /* shl1add */
2980 { CODE_FOR_insn_shl1addx
, NULL
}, /* shl1addx */
2981 { CODE_FOR_insn_shl2add
, NULL
}, /* shl2add */
2982 { CODE_FOR_insn_shl2addx
, NULL
}, /* shl2addx */
2983 { CODE_FOR_insn_shl3add
, NULL
}, /* shl3add */
2984 { CODE_FOR_insn_shl3addx
, NULL
}, /* shl3addx */
2985 { CODE_FOR_ashlsi3
, NULL
}, /* shlx */
2986 { CODE_FOR_ashrdi3
, NULL
}, /* shrs */
2987 { CODE_FOR_lshrdi3
, NULL
}, /* shru */
2988 { CODE_FOR_lshrsi3
, NULL
}, /* shrux */
2989 { CODE_FOR_insn_shufflebytes
, NULL
}, /* shufflebytes */
2990 { CODE_FOR_insn_shufflebytes1
, NULL
}, /* shufflebytes1 */
2991 { CODE_FOR_insn_st
, NULL
}, /* st */
2992 { CODE_FOR_insn_st1
, NULL
}, /* st1 */
2993 { CODE_FOR_insn_st2
, NULL
}, /* st2 */
2994 { CODE_FOR_insn_st4
, NULL
}, /* st4 */
2995 { CODE_FOR_insn_stnt
, NULL
}, /* stnt */
2996 { CODE_FOR_insn_stnt1
, NULL
}, /* stnt1 */
2997 { CODE_FOR_insn_stnt2
, NULL
}, /* stnt2 */
2998 { CODE_FOR_insn_stnt4
, NULL
}, /* stnt4 */
2999 { CODE_FOR_subdi3
, NULL
}, /* sub */
3000 { CODE_FOR_subsi3
, NULL
}, /* subx */
3001 { CODE_FOR_sssubsi3
, NULL
}, /* subxsc */
3002 { CODE_FOR_insn_tblidxb0
, NULL
}, /* tblidxb0 */
3003 { CODE_FOR_insn_tblidxb1
, NULL
}, /* tblidxb1 */
3004 { CODE_FOR_insn_tblidxb2
, NULL
}, /* tblidxb2 */
3005 { CODE_FOR_insn_tblidxb3
, NULL
}, /* tblidxb3 */
3006 { CODE_FOR_insn_v1add
, NULL
}, /* v1add */
3007 { CODE_FOR_insn_v1addi
, NULL
}, /* v1addi */
3008 { CODE_FOR_insn_v1adduc
, NULL
}, /* v1adduc */
3009 { CODE_FOR_insn_v1adiffu
, NULL
}, /* v1adiffu */
3010 { CODE_FOR_insn_v1avgu
, NULL
}, /* v1avgu */
3011 { CODE_FOR_insn_v1cmpeq
, NULL
}, /* v1cmpeq */
3012 { CODE_FOR_insn_v1cmpeqi
, NULL
}, /* v1cmpeqi */
3013 { CODE_FOR_insn_v1cmples
, NULL
}, /* v1cmples */
3014 { CODE_FOR_insn_v1cmpleu
, NULL
}, /* v1cmpleu */
3015 { CODE_FOR_insn_v1cmplts
, NULL
}, /* v1cmplts */
3016 { CODE_FOR_insn_v1cmpltsi
, NULL
}, /* v1cmpltsi */
3017 { CODE_FOR_insn_v1cmpltu
, NULL
}, /* v1cmpltu */
3018 { CODE_FOR_insn_v1cmpltui
, NULL
}, /* v1cmpltui */
3019 { CODE_FOR_insn_v1cmpne
, NULL
}, /* v1cmpne */
3020 { CODE_FOR_insn_v1ddotpu
, NULL
}, /* v1ddotpu */
3021 { CODE_FOR_insn_v1ddotpua
, NULL
}, /* v1ddotpua */
3022 { CODE_FOR_insn_v1ddotpus
, NULL
}, /* v1ddotpus */
3023 { CODE_FOR_insn_v1ddotpusa
, NULL
}, /* v1ddotpusa */
3024 { CODE_FOR_insn_v1dotp
, NULL
}, /* v1dotp */
3025 { CODE_FOR_insn_v1dotpa
, NULL
}, /* v1dotpa */
3026 { CODE_FOR_insn_v1dotpu
, NULL
}, /* v1dotpu */
3027 { CODE_FOR_insn_v1dotpua
, NULL
}, /* v1dotpua */
3028 { CODE_FOR_insn_v1dotpus
, NULL
}, /* v1dotpus */
3029 { CODE_FOR_insn_v1dotpusa
, NULL
}, /* v1dotpusa */
3030 { CODE_FOR_insn_v1int_h
, NULL
}, /* v1int_h */
3031 { CODE_FOR_insn_v1int_l
, NULL
}, /* v1int_l */
3032 { CODE_FOR_insn_v1maxu
, NULL
}, /* v1maxu */
3033 { CODE_FOR_insn_v1maxui
, NULL
}, /* v1maxui */
3034 { CODE_FOR_insn_v1minu
, NULL
}, /* v1minu */
3035 { CODE_FOR_insn_v1minui
, NULL
}, /* v1minui */
3036 { CODE_FOR_insn_v1mnz
, NULL
}, /* v1mnz */
3037 { CODE_FOR_insn_v1multu
, NULL
}, /* v1multu */
3038 { CODE_FOR_insn_v1mulu
, NULL
}, /* v1mulu */
3039 { CODE_FOR_insn_v1mulus
, NULL
}, /* v1mulus */
3040 { CODE_FOR_insn_v1mz
, NULL
}, /* v1mz */
3041 { CODE_FOR_insn_v1sadau
, NULL
}, /* v1sadau */
3042 { CODE_FOR_insn_v1sadu
, NULL
}, /* v1sadu */
3043 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shl */
3044 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shli */
3045 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrs */
3046 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrsi */
3047 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shru */
3048 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shrui */
3049 { CODE_FOR_insn_v1sub
, NULL
}, /* v1sub */
3050 { CODE_FOR_insn_v1subuc
, NULL
}, /* v1subuc */
3051 { CODE_FOR_insn_v2add
, NULL
}, /* v2add */
3052 { CODE_FOR_insn_v2addi
, NULL
}, /* v2addi */
3053 { CODE_FOR_insn_v2addsc
, NULL
}, /* v2addsc */
3054 { CODE_FOR_insn_v2adiffs
, NULL
}, /* v2adiffs */
3055 { CODE_FOR_insn_v2avgs
, NULL
}, /* v2avgs */
3056 { CODE_FOR_insn_v2cmpeq
, NULL
}, /* v2cmpeq */
3057 { CODE_FOR_insn_v2cmpeqi
, NULL
}, /* v2cmpeqi */
3058 { CODE_FOR_insn_v2cmples
, NULL
}, /* v2cmples */
3059 { CODE_FOR_insn_v2cmpleu
, NULL
}, /* v2cmpleu */
3060 { CODE_FOR_insn_v2cmplts
, NULL
}, /* v2cmplts */
3061 { CODE_FOR_insn_v2cmpltsi
, NULL
}, /* v2cmpltsi */
3062 { CODE_FOR_insn_v2cmpltu
, NULL
}, /* v2cmpltu */
3063 { CODE_FOR_insn_v2cmpltui
, NULL
}, /* v2cmpltui */
3064 { CODE_FOR_insn_v2cmpne
, NULL
}, /* v2cmpne */
3065 { CODE_FOR_insn_v2dotp
, NULL
}, /* v2dotp */
3066 { CODE_FOR_insn_v2dotpa
, NULL
}, /* v2dotpa */
3067 { CODE_FOR_insn_v2int_h
, NULL
}, /* v2int_h */
3068 { CODE_FOR_insn_v2int_l
, NULL
}, /* v2int_l */
3069 { CODE_FOR_insn_v2maxs
, NULL
}, /* v2maxs */
3070 { CODE_FOR_insn_v2maxsi
, NULL
}, /* v2maxsi */
3071 { CODE_FOR_insn_v2mins
, NULL
}, /* v2mins */
3072 { CODE_FOR_insn_v2minsi
, NULL
}, /* v2minsi */
3073 { CODE_FOR_insn_v2mnz
, NULL
}, /* v2mnz */
3074 { CODE_FOR_insn_v2mulfsc
, NULL
}, /* v2mulfsc */
3075 { CODE_FOR_insn_v2muls
, NULL
}, /* v2muls */
3076 { CODE_FOR_insn_v2mults
, NULL
}, /* v2mults */
3077 { CODE_FOR_insn_v2mz
, NULL
}, /* v2mz */
3078 { CODE_FOR_insn_v2packh
, NULL
}, /* v2packh */
3079 { CODE_FOR_insn_v2packl
, NULL
}, /* v2packl */
3080 { CODE_FOR_insn_v2packuc
, NULL
}, /* v2packuc */
3081 { CODE_FOR_insn_v2sadas
, NULL
}, /* v2sadas */
3082 { CODE_FOR_insn_v2sadau
, NULL
}, /* v2sadau */
3083 { CODE_FOR_insn_v2sads
, NULL
}, /* v2sads */
3084 { CODE_FOR_insn_v2sadu
, NULL
}, /* v2sadu */
3085 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shl */
3086 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shli */
3087 { CODE_FOR_insn_v2shlsc
, NULL
}, /* v2shlsc */
3088 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrs */
3089 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrsi */
3090 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shru */
3091 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shrui */
3092 { CODE_FOR_insn_v2sub
, NULL
}, /* v2sub */
3093 { CODE_FOR_insn_v2subsc
, NULL
}, /* v2subsc */
3094 { CODE_FOR_insn_v4add
, NULL
}, /* v4add */
3095 { CODE_FOR_insn_v4addsc
, NULL
}, /* v4addsc */
3096 { CODE_FOR_insn_v4int_h
, NULL
}, /* v4int_h */
3097 { CODE_FOR_insn_v4int_l
, NULL
}, /* v4int_l */
3098 { CODE_FOR_insn_v4packsc
, NULL
}, /* v4packsc */
3099 { CODE_FOR_insn_v4shl
, NULL
}, /* v4shl */
3100 { CODE_FOR_insn_v4shlsc
, NULL
}, /* v4shlsc */
3101 { CODE_FOR_insn_v4shrs
, NULL
}, /* v4shrs */
3102 { CODE_FOR_insn_v4shru
, NULL
}, /* v4shru */
3103 { CODE_FOR_insn_v4sub
, NULL
}, /* v4sub */
3104 { CODE_FOR_insn_v4subsc
, NULL
}, /* v4subsc */
3105 { CODE_FOR_insn_wh64
, NULL
}, /* wh64 */
3106 { CODE_FOR_xordi3
, NULL
}, /* xor */
3107 { CODE_FOR_tilegx_network_barrier
, NULL
}, /* network_barrier */
3108 { CODE_FOR_tilegx_idn0_receive
, NULL
}, /* idn0_receive */
3109 { CODE_FOR_tilegx_idn1_receive
, NULL
}, /* idn1_receive */
3110 { CODE_FOR_tilegx_idn_send
, NULL
}, /* idn_send */
3111 { CODE_FOR_tilegx_udn0_receive
, NULL
}, /* udn0_receive */
3112 { CODE_FOR_tilegx_udn1_receive
, NULL
}, /* udn1_receive */
3113 { CODE_FOR_tilegx_udn2_receive
, NULL
}, /* udn2_receive */
3114 { CODE_FOR_tilegx_udn3_receive
, NULL
}, /* udn3_receive */
3115 { CODE_FOR_tilegx_udn_send
, NULL
}, /* udn_send */
3119 struct tilegx_builtin_def
3122 enum tilegx_builtin code
;
3124 /* The first character is the return type. Subsequent characters
3125 are the argument types. See char_to_type. */
3130 static const struct tilegx_builtin_def tilegx_builtins
[] = {
3131 { "__insn_add", TILEGX_INSN_ADD
, true, "lll" },
3132 { "__insn_addi", TILEGX_INSN_ADD
, true, "lll" },
3133 { "__insn_addli", TILEGX_INSN_ADD
, true, "lll" },
3134 { "__insn_addx", TILEGX_INSN_ADDX
, true, "iii" },
3135 { "__insn_addxi", TILEGX_INSN_ADDX
, true, "iii" },
3136 { "__insn_addxli", TILEGX_INSN_ADDX
, true, "iii" },
3137 { "__insn_addxsc", TILEGX_INSN_ADDXSC
, true, "iii" },
3138 { "__insn_and", TILEGX_INSN_AND
, true, "lll" },
3139 { "__insn_andi", TILEGX_INSN_AND
, true, "lll" },
3140 { "__insn_bfexts", TILEGX_INSN_BFEXTS
, true, "llll" },
3141 { "__insn_bfextu", TILEGX_INSN_BFEXTU
, true, "llll" },
3142 { "__insn_bfins", TILEGX_INSN_BFINS
, true, "lllll"},
3143 { "__insn_clz", TILEGX_INSN_CLZ
, true, "ll" },
3144 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ
, true, "llll" },
3145 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ
, true, "llll" },
3146 { "__insn_cmpeq", TILEGX_INSN_CMPEQ
, true, "lll" },
3147 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ
, true, "lll" },
3148 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH
, false, "lpl" },
3149 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4
, false, "ipi" },
3150 { "__insn_cmples", TILEGX_INSN_CMPLES
, true, "lll" },
3151 { "__insn_cmpleu", TILEGX_INSN_CMPLEU
, true, "lll" },
3152 { "__insn_cmplts", TILEGX_INSN_CMPLTS
, true, "lll" },
3153 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS
, true, "lll" },
3154 { "__insn_cmpltu", TILEGX_INSN_CMPLTU
, true, "lll" },
3155 { "__insn_cmpltui", TILEGX_INSN_CMPLTU
, true, "lll" },
3156 { "__insn_cmpne", TILEGX_INSN_CMPNE
, true, "lll" },
3157 { "__insn_cmul", TILEGX_INSN_CMUL
, true, "lll" },
3158 { "__insn_cmula", TILEGX_INSN_CMULA
, true, "llll" },
3159 { "__insn_cmulaf", TILEGX_INSN_CMULAF
, true, "llll" },
3160 { "__insn_cmulf", TILEGX_INSN_CMULF
, true, "lll" },
3161 { "__insn_cmulfr", TILEGX_INSN_CMULFR
, true, "lll" },
3162 { "__insn_cmulh", TILEGX_INSN_CMULH
, true, "lll" },
3163 { "__insn_cmulhr", TILEGX_INSN_CMULHR
, true, "lll" },
3164 { "__insn_crc32_32", TILEGX_INSN_CRC32_32
, true, "lll" },
3165 { "__insn_crc32_8", TILEGX_INSN_CRC32_8
, true, "lll" },
3166 { "__insn_ctz", TILEGX_INSN_CTZ
, true, "ll" },
3167 { "__insn_dblalign", TILEGX_INSN_DBLALIGN
, true, "lllk" },
3168 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2
, true, "lll" },
3169 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4
, true, "lll" },
3170 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6
, true, "lll" },
3171 { "__insn_drain", TILEGX_INSN_DRAIN
, false, "v" },
3172 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR
, false, "vl" },
3173 { "__insn_exch", TILEGX_INSN_EXCH
, false, "lpl" },
3174 { "__insn_exch4", TILEGX_INSN_EXCH4
, false, "ipi" },
3175 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS
, true, "lll" },
3176 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB
, true, "llll" },
3177 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS
, true, "lll" },
3178 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1
, true, "lll" },
3179 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2
, true, "llll" },
3180 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS
, true, "lll" },
3181 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX
, true, "lll" },
3182 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN
, true, "lll" },
3183 { "__insn_fetchadd", TILEGX_INSN_FETCHADD
, false, "lpl" },
3184 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4
, false, "ipi" },
3185 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ
, false, "lpl" },
3186 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4
, false, "ipi" },
3187 { "__insn_fetchand", TILEGX_INSN_FETCHAND
, false, "lpl" },
3188 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4
, false, "ipi" },
3189 { "__insn_fetchor", TILEGX_INSN_FETCHOR
, false, "lpl" },
3190 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4
, false, "ipi" },
3191 { "__insn_finv", TILEGX_INSN_FINV
, false, "vk" },
3192 { "__insn_flush", TILEGX_INSN_FLUSH
, false, "vk" },
3193 { "__insn_flushwb", TILEGX_INSN_FLUSHWB
, false, "v" },
3194 { "__insn_fnop", TILEGX_INSN_FNOP
, false, "v" },
3195 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1
, true, "lll" },
3196 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2
, true, "llll" },
3197 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1
, true, "lll" },
3198 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2
, true, "lll" },
3199 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1
, true, "ll" },
3200 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2
, true, "lll" },
3201 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1
, true, "lll" },
3202 { "__insn_icoh", TILEGX_INSN_ICOH
, false, "vk" },
3203 { "__insn_ill", TILEGX_INSN_ILL
, false, "v" },
3204 { "__insn_info", TILEGX_INSN_INFO
, false, "vl" },
3205 { "__insn_infol", TILEGX_INSN_INFOL
, false, "vl" },
3206 { "__insn_inv", TILEGX_INSN_INV
, false, "vp" },
3207 { "__insn_ld", TILEGX_INSN_LD
, false, "lk" },
3208 { "__insn_ld1s", TILEGX_INSN_LD1S
, false, "lk" },
3209 { "__insn_ld1u", TILEGX_INSN_LD1U
, false, "lk" },
3210 { "__insn_ld2s", TILEGX_INSN_LD2S
, false, "lk" },
3211 { "__insn_ld2u", TILEGX_INSN_LD2U
, false, "lk" },
3212 { "__insn_ld4s", TILEGX_INSN_LD4S
, false, "lk" },
3213 { "__insn_ld4u", TILEGX_INSN_LD4U
, false, "lk" },
3214 { "__insn_ldna", TILEGX_INSN_LDNA
, false, "lk" },
3215 { "__insn_ldnt", TILEGX_INSN_LDNT
, false, "lk" },
3216 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S
, false, "lk" },
3217 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U
, false, "lk" },
3218 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S
, false, "lk" },
3219 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U
, false, "lk" },
3220 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S
, false, "lk" },
3221 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U
, false, "lk" },
3222 { "__insn_ld_L2", TILEGX_INSN_LD_L2
, false, "lk" },
3223 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2
, false, "lk" },
3224 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2
, false, "lk" },
3225 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2
, false, "lk" },
3226 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2
, false, "lk" },
3227 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2
, false, "lk" },
3228 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2
, false, "lk" },
3229 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2
, false, "lk" },
3230 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2
, false, "lk" },
3231 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2
, false, "lk" },
3232 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2
, false, "lk" },
3233 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2
, false, "lk" },
3234 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2
, false, "lk" },
3235 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2
, false, "lk" },
3236 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2
, false, "lk" },
3237 { "__insn_ld_miss", TILEGX_INSN_LD_MISS
, false, "lk" },
3238 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS
, false, "lk" },
3239 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS
, false, "lk" },
3240 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS
, false, "lk" },
3241 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS
, false, "lk" },
3242 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS
, false, "lk" },
3243 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS
, false, "lk" },
3244 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS
, false, "lk" },
3245 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS
, false, "lk" },
3246 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS
, false, "lk" },
3247 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS
, false, "lk" },
3248 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS
, false, "lk" },
3249 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS
, false, "lk" },
3250 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS
, false, "lk" },
3251 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS
, false, "lk" },
3252 { "__insn_lnk", TILEGX_INSN_LNK
, true, "l" },
3253 { "__insn_mf", TILEGX_INSN_MF
, false, "v" },
3254 { "__insn_mfspr", TILEGX_INSN_MFSPR
, false, "ll" },
3255 { "__insn_mm", TILEGX_INSN_MM
, true, "lllll"},
3256 { "__insn_mnz", TILEGX_INSN_MNZ
, true, "lll" },
3257 { "__insn_move", TILEGX_INSN_MOVE
, true, "ll" },
3258 { "__insn_movei", TILEGX_INSN_MOVE
, true, "ll" },
3259 { "__insn_moveli", TILEGX_INSN_MOVE
, true, "ll" },
3260 { "__insn_mtspr", TILEGX_INSN_MTSPR
, false, "vll" },
3261 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS
, true, "lll" },
3262 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU
, true, "lll" },
3263 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS
, true, "lll" },
3264 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU
, true, "lll" },
3265 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU
, true, "lll" },
3266 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS
, true, "lll" },
3267 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU
, true, "lll" },
3268 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS
, true, "lll" },
3269 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU
, true, "lll" },
3270 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU
, true, "lll" },
3271 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS
, true, "llll" },
3272 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU
, true, "llll" },
3273 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS
, true, "llll" },
3274 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU
, true, "llll" },
3275 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU
, true, "llll" },
3276 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS
, true, "llll" },
3277 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU
, true, "llll" },
3278 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS
, true, "llll" },
3279 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU
, true, "llll" },
3280 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU
, true, "llll" },
3281 { "__insn_mulax", TILEGX_INSN_MULAX
, true, "iiii" },
3282 { "__insn_mulx", TILEGX_INSN_MULX
, true, "iii" },
3283 { "__insn_mz", TILEGX_INSN_MZ
, true, "lll" },
3284 { "__insn_nap", TILEGX_INSN_NAP
, false, "v" },
3285 { "__insn_nop", TILEGX_INSN_NOP
, true, "v" },
3286 { "__insn_nor", TILEGX_INSN_NOR
, true, "lll" },
3287 { "__insn_or", TILEGX_INSN_OR
, true, "lll" },
3288 { "__insn_ori", TILEGX_INSN_OR
, true, "lll" },
3289 { "__insn_pcnt", TILEGX_INSN_PCNT
, true, "ll" },
3290 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3291 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3292 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT
, false, "vk" },
3293 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2
, false, "vk" },
3294 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT
, false, "vk" },
3295 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3
, false, "vk" },
3296 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT
, false, "vk" },
3297 { "__insn_revbits", TILEGX_INSN_REVBITS
, true, "ll" },
3298 { "__insn_revbytes", TILEGX_INSN_REVBYTES
, true, "ll" },
3299 { "__insn_rotl", TILEGX_INSN_ROTL
, true, "lli" },
3300 { "__insn_rotli", TILEGX_INSN_ROTL
, true, "lli" },
3301 { "__insn_shl", TILEGX_INSN_SHL
, true, "lli" },
3302 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI
, true, "lll" },
3303 { "__insn_shl1add", TILEGX_INSN_SHL1ADD
, true, "lll" },
3304 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX
, true, "iii" },
3305 { "__insn_shl2add", TILEGX_INSN_SHL2ADD
, true, "lll" },
3306 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX
, true, "iii" },
3307 { "__insn_shl3add", TILEGX_INSN_SHL3ADD
, true, "lll" },
3308 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX
, true, "iii" },
3309 { "__insn_shli", TILEGX_INSN_SHL
, true, "lli" },
3310 { "__insn_shlx", TILEGX_INSN_SHLX
, true, "iii" },
3311 { "__insn_shlxi", TILEGX_INSN_SHLX
, true, "iii" },
3312 { "__insn_shrs", TILEGX_INSN_SHRS
, true, "lli" },
3313 { "__insn_shrsi", TILEGX_INSN_SHRS
, true, "lli" },
3314 { "__insn_shru", TILEGX_INSN_SHRU
, true, "lli" },
3315 { "__insn_shrui", TILEGX_INSN_SHRU
, true, "lli" },
3316 { "__insn_shrux", TILEGX_INSN_SHRUX
, true, "iii" },
3317 { "__insn_shruxi", TILEGX_INSN_SHRUX
, true, "iii" },
3318 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES
, true, "llll" },
3319 { "__insn_shufflebytes1", TILEGX_INSN_SHUFFLEBYTES1
, true, "lll" },
3320 { "__insn_st", TILEGX_INSN_ST
, false, "vpl" },
3321 { "__insn_st1", TILEGX_INSN_ST1
, false, "vpl" },
3322 { "__insn_st2", TILEGX_INSN_ST2
, false, "vpl" },
3323 { "__insn_st4", TILEGX_INSN_ST4
, false, "vpl" },
3324 { "__insn_stnt", TILEGX_INSN_STNT
, false, "vpl" },
3325 { "__insn_stnt1", TILEGX_INSN_STNT1
, false, "vpl" },
3326 { "__insn_stnt2", TILEGX_INSN_STNT2
, false, "vpl" },
3327 { "__insn_stnt4", TILEGX_INSN_STNT4
, false, "vpl" },
3328 { "__insn_sub", TILEGX_INSN_SUB
, true, "lll" },
3329 { "__insn_subx", TILEGX_INSN_SUBX
, true, "iii" },
3330 { "__insn_subxsc", TILEGX_INSN_SUBXSC
, true, "iii" },
3331 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0
, true, "lll" },
3332 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1
, true, "lll" },
3333 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2
, true, "lll" },
3334 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3
, true, "lll" },
3335 { "__insn_v1add", TILEGX_INSN_V1ADD
, true, "lll" },
3336 { "__insn_v1addi", TILEGX_INSN_V1ADDI
, true, "lll" },
3337 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC
, true, "lll" },
3338 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU
, true, "lll" },
3339 { "__insn_v1avgu", TILEGX_INSN_V1AVGU
, true, "lll" },
3340 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ
, true, "lll" },
3341 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI
, true, "lll" },
3342 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES
, true, "lll" },
3343 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU
, true, "lll" },
3344 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS
, true, "lll" },
3345 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI
, true, "lll" },
3346 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU
, true, "lll" },
3347 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI
, true, "lll" },
3348 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE
, true, "lll" },
3349 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU
, true, "lll" },
3350 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA
, true, "llll" },
3351 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS
, true, "lll" },
3352 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA
, true, "llll" },
3353 { "__insn_v1dotp", TILEGX_INSN_V1DOTP
, true, "lll" },
3354 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA
, true, "llll" },
3355 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU
, true, "lll" },
3356 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA
, true, "llll" },
3357 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS
, true, "lll" },
3358 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA
, true, "llll" },
3359 { "__insn_v1int_h", TILEGX_INSN_V1INT_H
, true, "lll" },
3360 { "__insn_v1int_l", TILEGX_INSN_V1INT_L
, true, "lll" },
3361 { "__insn_v1maxu", TILEGX_INSN_V1MAXU
, true, "lll" },
3362 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI
, true, "lll" },
3363 { "__insn_v1minu", TILEGX_INSN_V1MINU
, true, "lll" },
3364 { "__insn_v1minui", TILEGX_INSN_V1MINUI
, true, "lll" },
3365 { "__insn_v1mnz", TILEGX_INSN_V1MNZ
, true, "lll" },
3366 { "__insn_v1multu", TILEGX_INSN_V1MULTU
, true, "lll" },
3367 { "__insn_v1mulu", TILEGX_INSN_V1MULU
, true, "lll" },
3368 { "__insn_v1mulus", TILEGX_INSN_V1MULUS
, true, "lll" },
3369 { "__insn_v1mz", TILEGX_INSN_V1MZ
, true, "lll" },
3370 { "__insn_v1sadau", TILEGX_INSN_V1SADAU
, true, "llll" },
3371 { "__insn_v1sadu", TILEGX_INSN_V1SADU
, true, "lll" },
3372 { "__insn_v1shl", TILEGX_INSN_V1SHL
, true, "lll" },
3373 { "__insn_v1shli", TILEGX_INSN_V1SHLI
, true, "lll" },
3374 { "__insn_v1shrs", TILEGX_INSN_V1SHRS
, true, "lll" },
3375 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI
, true, "lll" },
3376 { "__insn_v1shru", TILEGX_INSN_V1SHRU
, true, "lll" },
3377 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI
, true, "lll" },
3378 { "__insn_v1sub", TILEGX_INSN_V1SUB
, true, "lll" },
3379 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC
, true, "lll" },
3380 { "__insn_v2add", TILEGX_INSN_V2ADD
, true, "lll" },
3381 { "__insn_v2addi", TILEGX_INSN_V2ADDI
, true, "lll" },
3382 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC
, true, "lll" },
3383 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS
, true, "lll" },
3384 { "__insn_v2avgs", TILEGX_INSN_V2AVGS
, true, "lll" },
3385 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ
, true, "lll" },
3386 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI
, true, "lll" },
3387 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES
, true, "lll" },
3388 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU
, true, "lll" },
3389 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS
, true, "lll" },
3390 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI
, true, "lll" },
3391 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU
, true, "lll" },
3392 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI
, true, "lll" },
3393 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE
, true, "lll" },
3394 { "__insn_v2dotp", TILEGX_INSN_V2DOTP
, true, "lll" },
3395 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA
, true, "llll" },
3396 { "__insn_v2int_h", TILEGX_INSN_V2INT_H
, true, "lll" },
3397 { "__insn_v2int_l", TILEGX_INSN_V2INT_L
, true, "lll" },
3398 { "__insn_v2maxs", TILEGX_INSN_V2MAXS
, true, "lll" },
3399 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI
, true, "lll" },
3400 { "__insn_v2mins", TILEGX_INSN_V2MINS
, true, "lll" },
3401 { "__insn_v2minsi", TILEGX_INSN_V2MINSI
, true, "lll" },
3402 { "__insn_v2mnz", TILEGX_INSN_V2MNZ
, true, "lll" },
3403 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC
, true, "lll" },
3404 { "__insn_v2muls", TILEGX_INSN_V2MULS
, true, "lll" },
3405 { "__insn_v2mults", TILEGX_INSN_V2MULTS
, true, "lll" },
3406 { "__insn_v2mz", TILEGX_INSN_V2MZ
, true, "lll" },
3407 { "__insn_v2packh", TILEGX_INSN_V2PACKH
, true, "lll" },
3408 { "__insn_v2packl", TILEGX_INSN_V2PACKL
, true, "lll" },
3409 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC
, true, "lll" },
3410 { "__insn_v2sadas", TILEGX_INSN_V2SADAS
, true, "llll" },
3411 { "__insn_v2sadau", TILEGX_INSN_V2SADAU
, true, "llll" },
3412 { "__insn_v2sads", TILEGX_INSN_V2SADS
, true, "lll" },
3413 { "__insn_v2sadu", TILEGX_INSN_V2SADU
, true, "lll" },
3414 { "__insn_v2shl", TILEGX_INSN_V2SHL
, true, "lll" },
3415 { "__insn_v2shli", TILEGX_INSN_V2SHLI
, true, "lll" },
3416 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC
, true, "lll" },
3417 { "__insn_v2shrs", TILEGX_INSN_V2SHRS
, true, "lll" },
3418 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI
, true, "lll" },
3419 { "__insn_v2shru", TILEGX_INSN_V2SHRU
, true, "lll" },
3420 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI
, true, "lll" },
3421 { "__insn_v2sub", TILEGX_INSN_V2SUB
, true, "lll" },
3422 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC
, true, "lll" },
3423 { "__insn_v4add", TILEGX_INSN_V4ADD
, true, "lll" },
3424 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC
, true, "lll" },
3425 { "__insn_v4int_h", TILEGX_INSN_V4INT_H
, true, "lll" },
3426 { "__insn_v4int_l", TILEGX_INSN_V4INT_L
, true, "lll" },
3427 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC
, true, "lll" },
3428 { "__insn_v4shl", TILEGX_INSN_V4SHL
, true, "lll" },
3429 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC
, true, "lll" },
3430 { "__insn_v4shrs", TILEGX_INSN_V4SHRS
, true, "lll" },
3431 { "__insn_v4shru", TILEGX_INSN_V4SHRU
, true, "lll" },
3432 { "__insn_v4sub", TILEGX_INSN_V4SUB
, true, "lll" },
3433 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC
, true, "lll" },
3434 { "__insn_wh64", TILEGX_INSN_WH64
, false, "vp" },
3435 { "__insn_xor", TILEGX_INSN_XOR
, true, "lll" },
3436 { "__insn_xori", TILEGX_INSN_XOR
, true, "lll" },
3437 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER
, false, "v" },
3438 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE
, false, "l" },
3439 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE
, false, "l" },
3440 { "__tile_idn_send", TILEGX_IDN_SEND
, false, "vl" },
3441 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE
, false, "l" },
3442 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE
, false, "l" },
3443 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE
, false, "l" },
3444 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE
, false, "l" },
3445 { "__tile_udn_send", TILEGX_UDN_SEND
, false, "vl" },
3449 /* Convert a character in a builtin type string to a tree type. */
3451 char_to_type (char c
)
3453 static tree volatile_ptr_type_node
= NULL
;
3454 static tree volatile_const_ptr_type_node
= NULL
;
3456 if (volatile_ptr_type_node
== NULL
)
3458 volatile_ptr_type_node
=
3459 build_pointer_type (build_qualified_type (void_type_node
,
3460 TYPE_QUAL_VOLATILE
));
3461 volatile_const_ptr_type_node
=
3462 build_pointer_type (build_qualified_type (void_type_node
,
3464 | TYPE_QUAL_VOLATILE
));
3470 return void_type_node
;
3472 return unsigned_type_node
;
3474 return long_long_unsigned_type_node
;
3476 return volatile_ptr_type_node
;
3478 return volatile_const_ptr_type_node
;
3485 /* Implement TARGET_INIT_BUILTINS. */
3487 tilegx_init_builtins (void)
3491 for (i
= 0; i
< ARRAY_SIZE (tilegx_builtins
); i
++)
3493 const struct tilegx_builtin_def
*p
= &tilegx_builtins
[i
];
3494 tree ftype
, ret_type
, arg_type_list
= void_list_node
;
3498 for (j
= strlen (p
->type
) - 1; j
> 0; j
--)
3501 tree_cons (NULL_TREE
, char_to_type (p
->type
[j
]), arg_type_list
);
3504 ret_type
= char_to_type (p
->type
[0]);
3506 ftype
= build_function_type (ret_type
, arg_type_list
);
3508 decl
= add_builtin_function (p
->name
, ftype
, p
->code
, BUILT_IN_MD
,
3512 TREE_READONLY (decl
) = 1;
3513 TREE_NOTHROW (decl
) = 1;
3515 if (tilegx_builtin_info
[p
->code
].fndecl
== NULL
)
3516 tilegx_builtin_info
[p
->code
].fndecl
= decl
;
3521 /* Implement TARGET_EXPAND_BUILTIN. */
3523 tilegx_expand_builtin (tree exp
,
3525 rtx subtarget ATTRIBUTE_UNUSED
,
3526 machine_mode mode ATTRIBUTE_UNUSED
,
3527 int ignore ATTRIBUTE_UNUSED
)
3529 #define MAX_BUILTIN_ARGS 4
3531 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
3532 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
3534 call_expr_arg_iterator iter
;
3535 enum insn_code icode
;
3536 rtx op
[MAX_BUILTIN_ARGS
+ 1], pat
;
3541 if (fcode
>= TILEGX_BUILTIN_max
)
3542 internal_error ("bad builtin fcode");
3543 icode
= tilegx_builtin_info
[fcode
].icode
;
3545 internal_error ("bad builtin icode");
3547 nonvoid
= TREE_TYPE (TREE_TYPE (fndecl
)) != void_type_node
;
3550 FOR_EACH_CALL_EXPR_ARG (arg
, iter
, exp
)
3552 const struct insn_operand_data
*insn_op
;
3554 if (arg
== error_mark_node
)
3556 if (opnum
> MAX_BUILTIN_ARGS
)
3559 insn_op
= &insn_data
[icode
].operand
[opnum
];
3561 op
[opnum
] = expand_expr (arg
, NULL_RTX
, insn_op
->mode
, EXPAND_NORMAL
);
3563 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3565 machine_mode opmode
= insn_op
->mode
;
3567 /* pointer_operand and pmode_register_operand operands do
3568 not specify a mode, so use the operand's mode instead
3569 (which should always be right by the time we get here,
3570 except for constants, which are VOIDmode). */
3571 if (opmode
== VOIDmode
)
3573 machine_mode m
= GET_MODE (op
[opnum
]);
3574 gcc_assert (m
== Pmode
|| m
== VOIDmode
);
3578 op
[opnum
] = copy_to_mode_reg (opmode
, op
[opnum
]);
3581 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3583 /* We still failed to meet the predicate even after moving
3584 into a register. Assume we needed an immediate. */
3585 error_at (EXPR_LOCATION (exp
),
3586 "operand must be an immediate of the right size");
3595 machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
3597 || GET_MODE (target
) != tmode
3598 || !(*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
3600 if (tmode
== VOIDmode
)
3602 /* get the mode from the return type. */
3603 tmode
= TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl
)));
3605 target
= gen_reg_rtx (tmode
);
3610 fn
= GEN_FCN (icode
);
3614 pat
= fn (NULL_RTX
);
3620 pat
= fn (op
[0], op
[1]);
3623 pat
= fn (op
[0], op
[1], op
[2]);
3626 pat
= fn (op
[0], op
[1], op
[2], op
[3]);
3629 pat
= fn (op
[0], op
[1], op
[2], op
[3], op
[4]);
3637 /* If we are generating a prefetch, tell the scheduler not to move
3639 if (GET_CODE (pat
) == PREFETCH
)
3640 PREFETCH_SCHEDULE_BARRIER_P (pat
) = true;
3651 /* Implement TARGET_BUILTIN_DECL. */
3653 tilegx_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
3655 if (code
>= TILEGX_BUILTIN_max
)
3656 return error_mark_node
;
3658 return tilegx_builtin_info
[code
].fndecl
;
3665 /* Return whether REGNO needs to be saved in the stack frame. */
3667 need_to_save_reg (unsigned int regno
)
3669 if (!fixed_regs
[regno
] && !call_used_regs
[regno
]
3670 && df_regs_ever_live_p (regno
))
3674 && (regno
== PIC_OFFSET_TABLE_REGNUM
3675 || regno
== TILEGX_PIC_TEXT_LABEL_REGNUM
)
3676 && (crtl
->uses_pic_offset_table
|| crtl
->saves_all_registers
))
3679 if (crtl
->calls_eh_return
)
3682 for (i
= 0; EH_RETURN_DATA_REGNO (i
) != INVALID_REGNUM
; i
++)
3684 if (regno
== EH_RETURN_DATA_REGNO (i
))
3693 /* Return the size of the register savev area. This function is only
3694 correct starting with local register allocation */
3696 tilegx_saved_regs_size (void)
3698 int reg_save_size
= 0;
3700 int offset_to_frame
;
3703 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
3704 if (need_to_save_reg (regno
))
3705 reg_save_size
+= UNITS_PER_WORD
;
3707 /* Pad out the register save area if necessary to make
3708 frame_pointer_rtx be as aligned as the stack pointer. */
3709 offset_to_frame
= crtl
->args
.pretend_args_size
+ reg_save_size
;
3710 align_mask
= (STACK_BOUNDARY
/ BITS_PER_UNIT
) - 1;
3711 reg_save_size
+= (-offset_to_frame
) & align_mask
;
3713 return reg_save_size
;
3717 /* Round up frame size SIZE. */
3719 round_frame_size (int size
)
3721 return ((size
+ STACK_BOUNDARY
/ BITS_PER_UNIT
- 1)
3722 & -STACK_BOUNDARY
/ BITS_PER_UNIT
);
3726 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3727 emit the corresponding REG_CFA_OFFSET note described by CFA and
3728 CFA_OFFSET. Return the emitted insn. */
3730 frame_emit_store (int regno
, int regno_note
, rtx addr
, rtx cfa
,
3733 rtx reg
= gen_rtx_REG (DImode
, regno
);
3734 rtx mem
= gen_frame_mem (DImode
, addr
);
3735 rtx mov
= gen_movdi (mem
, reg
);
3737 /* Describe what just happened in a way that dwarf understands. We
3738 use temporary registers to hold the address to make scheduling
3739 easier, and use the REG_CFA_OFFSET to describe the address as an
3740 offset from the CFA. */
3741 rtx reg_note
= gen_rtx_REG (DImode
, regno_note
);
3742 rtx cfa_relative_addr
= gen_rtx_PLUS (Pmode
, cfa
, GEN_INT (cfa_offset
));
3743 rtx cfa_relative_mem
= gen_frame_mem (DImode
, cfa_relative_addr
);
3744 rtx real
= gen_rtx_SET (cfa_relative_mem
, reg_note
);
3745 add_reg_note (mov
, REG_CFA_OFFSET
, real
);
3747 return emit_insn (mov
);
3751 /* Emit a load in the stack frame to load REGNO from address ADDR.
3752 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3753 non-null. Return the emitted insn. */
3755 frame_emit_load (int regno
, rtx addr
, rtx
*cfa_restores
)
3757 rtx reg
= gen_rtx_REG (DImode
, regno
);
3758 rtx mem
= gen_frame_mem (DImode
, addr
);
3760 *cfa_restores
= alloc_reg_note (REG_CFA_RESTORE
, reg
, *cfa_restores
);
3761 return emit_insn (gen_movdi (reg
, mem
));
3765 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3766 including sequences. */
3768 set_frame_related_p (void)
3770 rtx_insn
*seq
= get_insns ();
3781 while (insn
!= NULL_RTX
)
3783 RTX_FRAME_RELATED_P (insn
) = 1;
3784 insn
= NEXT_INSN (insn
);
3786 seq
= emit_insn (seq
);
3790 seq
= emit_insn (seq
);
3791 RTX_FRAME_RELATED_P (seq
) = 1;
3797 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3799 /* This emits code for 'sp += offset'.
3801 The ABI only allows us to modify 'sp' in a single 'addi' or
3802 'addli', so the backtracer understands it. Larger amounts cannot
3803 use those instructions, so are added by placing the offset into a
3804 large register and using 'add'.
3806 This happens after reload, so we need to expand it ourselves. */
3808 emit_sp_adjust (int offset
, int *next_scratch_regno
, bool frame_related
,
3812 rtx imm_rtx
= GEN_INT (offset
);
3816 if (satisfies_constraint_J (imm_rtx
))
3818 /* We can add this using a single immediate add. */
3823 rtx tmp
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3824 tilegx_expand_set_const64 (tmp
, imm_rtx
);
3828 /* Actually adjust the stack pointer. */
3830 pat
= gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3832 pat
= gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3834 insn
= emit_insn (pat
);
3835 REG_NOTES (insn
) = reg_notes
;
3837 /* Describe what just happened in a way that dwarf understands. */
3840 rtx real
= gen_rtx_SET (stack_pointer_rtx
,
3841 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3843 RTX_FRAME_RELATED_P (insn
) = 1;
3844 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, real
);
3851 /* Return whether the current function is leaf. This takes into
3852 account whether the function calls tls_get_addr. */
3854 tilegx_current_function_is_leaf (void)
3856 return crtl
->is_leaf
&& !cfun
->machine
->calls_tls_get_addr
;
3860 /* Return the frame size. */
3862 compute_total_frame_size (void)
3864 int total_size
= (get_frame_size () + tilegx_saved_regs_size ()
3865 + crtl
->outgoing_args_size
3866 + crtl
->args
.pretend_args_size
);
3868 if (!tilegx_current_function_is_leaf () || cfun
->calls_alloca
)
3870 /* Make room for save area in callee. */
3871 total_size
+= STACK_POINTER_OFFSET
;
3874 return round_frame_size (total_size
);
3878 /* Return nonzero if this function is known to have a null epilogue.
3879 This allows the optimizer to omit jumps to jumps if no stack was
3882 tilegx_can_use_return_insn_p (void)
3884 return (reload_completed
3885 && !cfun
->static_chain_decl
3886 && !compute_total_frame_size ()
3887 && tilegx_current_function_is_leaf ()
3888 && !crtl
->profile
&& !df_regs_ever_live_p (TILEGX_LINK_REGNUM
));
3892 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3893 is a frame pointer, it computes the value relative to
3894 that. Otherwise it uses the stack pointer. */
3896 compute_frame_addr (int offset_from_fp
, int *next_scratch_regno
)
3898 rtx base_reg_rtx
, tmp_reg_rtx
, offset_rtx
;
3899 int offset_from_base
;
3901 if (frame_pointer_needed
)
3903 base_reg_rtx
= hard_frame_pointer_rtx
;
3904 offset_from_base
= offset_from_fp
;
3908 int offset_from_sp
= compute_total_frame_size () + offset_from_fp
;
3909 offset_from_base
= offset_from_sp
;
3910 base_reg_rtx
= stack_pointer_rtx
;
3913 if (offset_from_base
== 0)
3914 return base_reg_rtx
;
3916 /* Compute the new value of the stack pointer. */
3917 tmp_reg_rtx
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3918 offset_rtx
= GEN_INT (offset_from_base
);
3920 if (!add_operand (offset_rtx
, Pmode
))
3922 expand_set_cint64 (tmp_reg_rtx
, offset_rtx
);
3923 offset_rtx
= tmp_reg_rtx
;
3926 emit_insn (gen_rtx_SET (tmp_reg_rtx
,
3927 gen_rtx_PLUS (Pmode
, base_reg_rtx
, offset_rtx
)));
3933 /* The stack frame looks like this:
3938 AP -> +-------------+
3942 HFP -> +-------------+
3944 | reg save | crtl->args.pretend_args_size bytes
3947 | saved regs | tilegx_saved_regs_size() bytes
3948 FP -> +-------------+
3950 | vars | get_frame_size() bytes
3954 | stack args | crtl->outgoing_args_size bytes
3956 | HFP | ptr_size bytes (only here if nonleaf / alloca)
3958 | callee lr | ptr_size bytes (only here if nonleaf / alloca)
3960 SP -> +-------------+
3964 For functions with a frame larger than 32767 bytes, or which use
3965 alloca (), r52 is used as a frame pointer. Otherwise there is no
3968 FP is saved at SP+ptr_size before calling a subroutine so the callee
3971 tilegx_expand_prologue (void)
3973 #define ROUND_ROBIN_SIZE 4
3974 /* We round-robin through four scratch registers to hold temporary
3975 addresses for saving registers, to make instruction scheduling
3977 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
3978 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
3981 unsigned int which_scratch
;
3982 int offset
, start_offset
, regno
;
3984 /* A register that holds a copy of the incoming fp. */
3985 int fp_copy_regno
= -1;
3987 /* A register that holds a copy of the incoming sp. */
3988 int sp_copy_regno
= -1;
3990 /* Next scratch register number to hand out (postdecrementing). */
3991 int next_scratch_regno
= 29;
3993 int total_size
= compute_total_frame_size ();
3995 if (flag_stack_usage_info
)
3996 current_function_static_stack_size
= total_size
;
3998 /* Save lr first in its special location because code after this
3999 might use the link register as a scratch register. */
4000 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
) || crtl
->calls_eh_return
)
4002 FRP (frame_emit_store (TILEGX_LINK_REGNUM
, TILEGX_LINK_REGNUM
,
4003 stack_pointer_rtx
, stack_pointer_rtx
, 0));
4004 emit_insn (gen_blockage ());
4007 if (total_size
== 0)
4009 /* Load the PIC register if needed. */
4010 if (flag_pic
&& crtl
->uses_pic_offset_table
)
4011 load_pic_register (false);
4016 cfa
= stack_pointer_rtx
;
4018 if (frame_pointer_needed
)
4020 fp_copy_regno
= next_scratch_regno
--;
4022 /* Copy the old frame pointer aside so we can save it later. */
4024 FRP (emit_move_insn (gen_rtx_REG (word_mode
, fp_copy_regno
),
4025 gen_lowpart (word_mode
, hard_frame_pointer_rtx
)));
4026 add_reg_note (insn
, REG_CFA_REGISTER
, NULL_RTX
);
4028 /* Set up the frame pointer. */
4029 insn
= FRP (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
4030 add_reg_note (insn
, REG_CFA_DEF_CFA
, hard_frame_pointer_rtx
);
4031 cfa
= hard_frame_pointer_rtx
;
4032 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM
) = STACK_BOUNDARY
;
4034 /* fp holds a copy of the incoming sp, in case we need to store
4036 sp_copy_regno
= HARD_FRAME_POINTER_REGNUM
;
4038 else if (!tilegx_current_function_is_leaf ())
4040 /* Copy the old stack pointer aside so we can save it later. */
4041 sp_copy_regno
= next_scratch_regno
--;
4042 emit_move_insn (gen_rtx_REG (Pmode
, sp_copy_regno
),
4046 if (tilegx_current_function_is_leaf ())
4048 /* No need to store chain pointer to caller's frame. */
4049 emit_sp_adjust (-total_size
, &next_scratch_regno
,
4050 !frame_pointer_needed
, NULL_RTX
);
4054 /* Save the frame pointer (incoming sp value) to support
4055 backtracing. First we need to create an rtx with the store
4057 rtx chain_addr
= gen_rtx_REG (Pmode
, next_scratch_regno
--);
4058 rtx size_rtx
= GEN_INT (-(total_size
- UNITS_PER_WORD
));
4060 if (add_operand (size_rtx
, Pmode
))
4062 /* Expose more parallelism by computing this value from the
4063 original stack pointer, not the one after we have pushed
4065 rtx p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, size_rtx
);
4066 emit_insn (gen_rtx_SET (chain_addr
, p
));
4067 emit_sp_adjust (-total_size
, &next_scratch_regno
,
4068 !frame_pointer_needed
, NULL_RTX
);
4072 /* The stack frame is large, so just store the incoming sp
4073 value at *(new_sp + UNITS_PER_WORD). */
4075 emit_sp_adjust (-total_size
, &next_scratch_regno
,
4076 !frame_pointer_needed
, NULL_RTX
);
4077 p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
4078 GEN_INT (UNITS_PER_WORD
));
4079 emit_insn (gen_rtx_SET (chain_addr
, p
));
4082 /* Save our frame pointer for backtrace chaining. */
4083 emit_insn (gen_movdi (gen_frame_mem (DImode
, chain_addr
),
4084 gen_rtx_REG (DImode
, sp_copy_regno
)));
4087 /* Compute where to start storing registers we need to save. */
4088 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
4089 offset
= start_offset
;
4091 /* Store all registers that need saving. */
4093 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
4094 if (need_to_save_reg (regno
))
4096 rtx r
= reg_save_addr
[which_scratch
];
4098 int cfa_offset
= frame_pointer_needed
? offset
: total_size
+ offset
;
4102 int prev_scratch_regno
= next_scratch_regno
;
4103 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4104 if (prev_scratch_regno
!= next_scratch_regno
)
4105 reg_save_addr
[which_scratch
] = r
;
4109 /* Advance to the next stack slot to store this
4111 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4112 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4113 emit_insn (gen_rtx_SET (r
, p
));
4116 /* Save this register to the stack (but use the old fp value
4117 we copied aside if appropriate). */
4119 (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4120 ? fp_copy_regno
: regno
;
4121 FRP (frame_emit_store (from_regno
, regno
, r
, cfa
, cfa_offset
));
4123 offset
-= UNITS_PER_WORD
;
4124 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4127 /* If profiling, force that to happen after the frame is set up. */
4129 emit_insn (gen_blockage ());
4131 /* Load the PIC register if needed. */
4132 if (flag_pic
&& crtl
->uses_pic_offset_table
)
4133 load_pic_register (false);
4137 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
4138 true for a sibcall_epilogue pattern, and false for an epilogue
4141 tilegx_expand_epilogue (bool sibcall_p
)
4143 /* We round-robin through four scratch registers to hold temporary
4144 addresses for saving registers, to make instruction scheduling
4146 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
4147 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
4149 rtx_insn
*last_insn
, *insn
;
4150 unsigned int which_scratch
;
4151 int offset
, start_offset
, regno
;
4152 rtx cfa_restores
= NULL_RTX
;
4154 /* A register that holds a copy of the incoming fp. */
4155 int fp_copy_regno
= -1;
4157 /* Next scratch register number to hand out (postdecrementing). */
4158 int next_scratch_regno
= 29;
4160 int total_size
= compute_total_frame_size ();
4162 last_insn
= get_last_insn ();
4164 /* Load lr first since we are going to need it first. */
4166 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
))
4168 insn
= frame_emit_load (TILEGX_LINK_REGNUM
,
4169 compute_frame_addr (0, &next_scratch_regno
),
4173 if (total_size
== 0)
4177 RTX_FRAME_RELATED_P (insn
) = 1;
4178 REG_NOTES (insn
) = cfa_restores
;
4183 /* Compute where to start restoring registers. */
4184 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
4185 offset
= start_offset
;
4187 if (frame_pointer_needed
)
4188 fp_copy_regno
= next_scratch_regno
--;
4190 /* Restore all callee-saved registers. */
4192 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
4193 if (need_to_save_reg (regno
))
4195 rtx r
= reg_save_addr
[which_scratch
];
4198 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4199 reg_save_addr
[which_scratch
] = r
;
4203 /* Advance to the next stack slot to store this register. */
4204 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4205 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4206 emit_insn (gen_rtx_SET (r
, p
));
4209 if (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4210 frame_emit_load (fp_copy_regno
, r
, NULL
);
4212 frame_emit_load (regno
, r
, &cfa_restores
);
4214 offset
-= UNITS_PER_WORD
;
4215 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4218 if (!tilegx_current_function_is_leaf ())
4220 alloc_reg_note (REG_CFA_RESTORE
, stack_pointer_rtx
, cfa_restores
);
4222 emit_insn (gen_blockage ());
4224 if (frame_pointer_needed
)
4226 /* Restore the old stack pointer by copying from the frame
4230 insn
= emit_insn (gen_sp_restore_32bit (stack_pointer_rtx
,
4231 hard_frame_pointer_rtx
));
4235 insn
= emit_insn (gen_sp_restore (stack_pointer_rtx
,
4236 hard_frame_pointer_rtx
));
4238 RTX_FRAME_RELATED_P (insn
) = 1;
4239 REG_NOTES (insn
) = cfa_restores
;
4240 add_reg_note (insn
, REG_CFA_DEF_CFA
, stack_pointer_rtx
);
4244 insn
= emit_sp_adjust (total_size
, &next_scratch_regno
, true,
4248 if (crtl
->calls_eh_return
)
4251 emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
,
4252 EH_RETURN_STACKADJ_RTX
));
4254 emit_insn (gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
,
4255 EH_RETURN_STACKADJ_RTX
));
4258 /* Restore the old frame pointer. */
4259 if (frame_pointer_needed
)
4261 insn
= emit_move_insn (gen_lowpart (DImode
, hard_frame_pointer_rtx
),
4262 gen_rtx_REG (DImode
, fp_copy_regno
));
4263 add_reg_note (insn
, REG_CFA_RESTORE
, hard_frame_pointer_rtx
);
4266 /* Mark the pic registers as live outside of the function. */
4269 emit_use (cfun
->machine
->text_label_rtx
);
4270 emit_use (cfun
->machine
->got_rtx
);
4276 emit_jump_insn (gen__return ());
4280 emit_use (gen_rtx_REG (Pmode
, TILEGX_LINK_REGNUM
));
4283 /* Mark all insns we just emitted as frame-related. */
4284 for (; last_insn
!= NULL_RTX
; last_insn
= next_insn (last_insn
))
4285 RTX_FRAME_RELATED_P (last_insn
) = 1;
4288 #undef ROUND_ROBIN_SIZE
4291 /* Implement INITIAL_ELIMINATION_OFFSET. */
4293 tilegx_initial_elimination_offset (int from
, int to
)
4295 int total_size
= compute_total_frame_size ();
4297 if (from
== FRAME_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4299 return (total_size
- crtl
->args
.pretend_args_size
4300 - tilegx_saved_regs_size ());
4302 else if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4304 return -(crtl
->args
.pretend_args_size
+ tilegx_saved_regs_size ());
4306 else if (from
== ARG_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4308 return STACK_POINTER_OFFSET
+ total_size
;
4310 else if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4312 return STACK_POINTER_OFFSET
;
4319 /* Return an RTX indicating where the return address to the calling
4320 function can be found. */
4322 tilegx_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
4327 return get_hard_reg_initial_val (Pmode
, TILEGX_LINK_REGNUM
);
4331 /* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to
4332 prevent it from being deleted. */
4334 tilegx_eh_return_handler_rtx (void)
4336 rtx tmp
= gen_frame_mem (Pmode
, hard_frame_pointer_rtx
);
4337 MEM_VOLATILE_P (tmp
) = true;
4345 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
4347 tilegx_conditional_register_usage (void)
4349 global_regs
[TILEGX_NETORDER_REGNUM
] = 1;
4350 /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
4351 member of fixed_regs, and therefore must be member of
4352 call_used_regs, but it is not a member of call_really_used_regs[]
4353 because it is not clobbered by a call. */
4354 if (TILEGX_PIC_TEXT_LABEL_REGNUM
!= INVALID_REGNUM
)
4356 fixed_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4357 call_used_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4359 if (PIC_OFFSET_TABLE_REGNUM
!= INVALID_REGNUM
)
4361 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4362 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4367 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
4369 tilegx_frame_pointer_required (void)
4371 return crtl
->calls_eh_return
|| cfun
->calls_alloca
;
4376 /* Scheduling and reorg */
4378 /* Return the length of INSN. LENGTH is the initial length computed
4379 by attributes in the machine-description file. This is where we
4380 account for bundles. */
4382 tilegx_adjust_insn_length (rtx_insn
*insn
, int length
)
4384 machine_mode mode
= GET_MODE (insn
);
4386 /* A non-termininating instruction in a bundle has length 0. */
4390 /* By default, there is not length adjustment. */
4395 /* Implement TARGET_SCHED_ISSUE_RATE. */
4397 tilegx_issue_rate (void)
4403 /* Return the rtx for the jump target. */
4405 get_jump_target (rtx branch
)
4407 if (CALL_P (branch
))
4410 call
= PATTERN (branch
);
4412 if (GET_CODE (call
) == PARALLEL
)
4413 call
= XVECEXP (call
, 0, 0);
4415 if (GET_CODE (call
) == SET
)
4416 call
= SET_SRC (call
);
4418 if (GET_CODE (call
) == CALL
)
4419 return XEXP (XEXP (call
, 0), 0);
4425 /* Implement TARGET_SCHED_ADJUST_COST. */
4427 tilegx_sched_adjust_cost (rtx_insn
*insn
, int dep_type
, rtx_insn
*dep_insn
,
4428 int cost
, unsigned int)
4430 /* If we have a true dependence, INSN is a call, and DEP_INSN
4431 defines a register that is needed by the call (argument or stack
4432 pointer) , set its latency to 0 so that it can be bundled with
4433 the call. Explicitly check for and exclude the case when
4434 DEP_INSN defines the target of the jump. */
4435 if (CALL_P (insn
) && dep_type
== REG_DEP_TRUE
)
4437 rtx target
= get_jump_target (insn
);
4438 if (!REG_P (target
) || !set_of (target
, dep_insn
))
4446 /* Skip over irrelevant NOTEs and such and look for the next insn we
4447 would consider bundling. */
4449 next_insn_to_bundle (rtx_insn
*r
, rtx_insn
*end
)
4451 for (; r
!= end
; r
= NEXT_INSN (r
))
4453 if (NONDEBUG_INSN_P (r
)
4454 && GET_CODE (PATTERN (r
)) != USE
4455 && GET_CODE (PATTERN (r
)) != CLOBBER
)
4463 /* Go through all insns, and use the information generated during
4464 scheduling to generate SEQUENCEs to represent bundles of
4465 instructions issued simultaneously. */
4467 tilegx_gen_bundles (void)
4470 FOR_EACH_BB_FN (bb
, cfun
)
4472 rtx_insn
*insn
, *next
, *prev
;
4473 rtx_insn
*end
= NEXT_INSN (BB_END (bb
));
4476 for (insn
= next_insn_to_bundle (BB_HEAD (bb
), end
); insn
; insn
= next
)
4478 next
= next_insn_to_bundle (NEXT_INSN (insn
), end
);
4480 /* Never wrap {} around inline asm. */
4481 if (GET_CODE (PATTERN (insn
)) != ASM_INPUT
)
4483 if (next
== NULL_RTX
|| GET_MODE (next
) == TImode
4484 /* NOTE: The scheduler incorrectly believes a call
4485 insn can execute in the same cycle as the insn
4486 after the call. This is of course impossible.
4487 Really we need to fix the scheduler somehow, so
4488 the code after the call gets scheduled
4492 /* Mark current insn as the end of a bundle. */
4493 PUT_MODE (insn
, QImode
);
4497 /* Mark it as part of a bundle. */
4498 PUT_MODE (insn
, SImode
);
4502 /* Delete barrier insns, because they can mess up the
4503 emitting of bundle braces. If it is end-of-bundle, then
4504 the previous insn must be marked end-of-bundle. */
4505 if (get_attr_type (insn
) == TYPE_NOTHING
) {
4506 if (GET_MODE (insn
) == QImode
&& prev
!= NULL
4507 && GET_MODE (prev
) == SImode
)
4509 PUT_MODE (prev
, QImode
);
4513 // Note: prev remains the same for next iteration.
4522 /* Replace OLD_INSN with NEW_INSN. */
4524 replace_insns (rtx_insn
*old_insn
, rtx_insn
*new_insns
)
4527 emit_insn_before (new_insns
, old_insn
);
4529 delete_insn (old_insn
);
4533 /* Returns true if INSN is the first instruction of a pc-relative
4534 address compuatation. */
4536 match_pcrel_step1 (rtx insn
)
4538 rtx pattern
= PATTERN (insn
);
4541 if (GET_CODE (pattern
) != SET
)
4544 src
= SET_SRC (pattern
);
4546 return (GET_CODE (src
) == CONST
4547 && GET_CODE (XEXP (src
, 0)) == UNSPEC
4548 && XINT (XEXP (src
, 0), 1) == UNSPEC_HW1_LAST_PCREL
);
4552 /* Do the first replacement step in tilegx_fixup_pcrel_references. */
4554 replace_mov_pcrel_step1 (rtx_insn
*insn
)
4556 rtx pattern
= PATTERN (insn
);
4559 rtx_insn
*new_insns
;
4561 gcc_assert (GET_CODE (pattern
) == SET
);
4562 opnds
[0] = SET_DEST (pattern
);
4564 gcc_assert (GET_CODE (SET_SRC (pattern
)) == CONST
);
4566 unspec
= XEXP (SET_SRC (pattern
), 0);
4567 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4568 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW1_LAST_PCREL
);
4569 opnds
[1] = XVECEXP (unspec
, 0, 0);
4571 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4572 if (GET_CODE (opnds
[1]) != SYMBOL_REF
)
4580 emit_insn (gen_mov_got32_step1_32bit (opnds
[0], opnds
[1]));
4582 emit_insn (gen_mov_got32_step1 (opnds
[0], opnds
[1]));
4585 new_insns
= get_insns ();
4588 replace_insns (insn
, new_insns
);
4592 /* Returns true if INSN is the second instruction of a pc-relative
4593 address compuatation. */
4595 match_pcrel_step2 (rtx_insn
*insn
)
4602 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli_32bit
)
4607 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli
)
4611 unspec
= SET_SRC (PATTERN (insn
));
4612 addr
= XVECEXP (unspec
, 0, 1);
4614 return (GET_CODE (addr
) == CONST
4615 && GET_CODE (XEXP (addr
, 0)) == UNSPEC
4616 && XINT (XEXP (addr
, 0), 1) == UNSPEC_HW0_PCREL
);
4620 /* Do the second replacement step in tilegx_fixup_pcrel_references. */
4622 replace_mov_pcrel_step2 (rtx_insn
*insn
)
4624 rtx pattern
= PATTERN (insn
);
4628 rtx_insn
*new_insns
;
4629 rtx got_rtx
= tilegx_got_rtx ();
4631 gcc_assert (GET_CODE (pattern
) == SET
);
4632 opnds
[0] = SET_DEST (pattern
);
4634 unspec
= SET_SRC (pattern
);
4635 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4636 gcc_assert (XINT (unspec
, 1) == UNSPEC_INSN_ADDR_SHL16INSLI
);
4638 opnds
[1] = XVECEXP (unspec
, 0, 0);
4640 addr
= XVECEXP (unspec
, 0, 1);
4641 gcc_assert (GET_CODE (addr
) == CONST
);
4643 unspec
= XEXP (addr
, 0);
4644 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4645 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW0_PCREL
);
4646 opnds
[2] = XVECEXP (unspec
, 0, 0);
4648 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4649 if (GET_CODE (opnds
[2]) != SYMBOL_REF
)
4657 emit_insn (gen_add_got16_32bit (opnds
[0], got_rtx
, opnds
[2]));
4659 emit_insn (gen_add_got16 (opnds
[0], got_rtx
, opnds
[2]));
4664 emit_insn (gen_mov_got32_step2_32bit
4665 (opnds
[0], opnds
[1], opnds
[2]));
4667 emit_insn (gen_mov_got32_step2 (opnds
[0], opnds
[1], opnds
[2]));
4670 new_insns
= get_insns ();
4673 replace_insns (insn
, new_insns
);
4677 /* Do the third replacement step in tilegx_fixup_pcrel_references. */
4679 replace_mov_pcrel_step3 (rtx_insn
*insn
)
4681 rtx pattern
= PATTERN (insn
);
4684 rtx_insn
*new_insns
;
4685 rtx got_rtx
= tilegx_got_rtx ();
4686 rtx text_label_rtx
= tilegx_text_label_rtx ();
4688 gcc_assert (GET_CODE (pattern
) == SET
);
4689 opnds
[0] = SET_DEST (pattern
);
4691 unspec
= SET_SRC (pattern
);
4692 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4693 gcc_assert (XINT (unspec
, 1) == UNSPEC_MOV_PCREL_STEP3
);
4697 if (XVECEXP (unspec
, 0, 0) == text_label_rtx
)
4698 opnds
[2] = XVECEXP (unspec
, 0, 1);
4701 gcc_assert (XVECEXP (unspec
, 0, 1) == text_label_rtx
);
4702 opnds
[2] = XVECEXP (unspec
, 0, 0);
4705 opnds
[3] = XVECEXP (unspec
, 0, 2);
4707 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4708 if (GET_CODE (opnds
[3]) != SYMBOL_REF
)
4715 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[2]));
4719 emit_move_insn (opnds
[0], gen_rtx_PLUS (Pmode
, opnds
[1], opnds
[2]));
4720 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[0]));
4723 new_insns
= get_insns ();
4726 replace_insns (insn
, new_insns
);
4730 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4731 going through the GOT when the symbol is local to the compilation
4732 unit. But such a symbol requires that the common text_label that
4733 we generate at the beginning of the function be in the same section
4734 as the reference to the SYMBOL_REF. This may not be true if we
4735 generate hot/cold sections. This function looks for such cases and
4736 replaces such references with the longer sequence going through the
4739 We expect following instruction sequence:
4740 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4741 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4742 add<x> tmp3, txt_label_reg, tmp2 [3]
4744 If we're compiling -fpic, we replace with the following sequence
4745 (the numbers in brackets match the instructions they're replacing
4748 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4749 ld<4> tmp3, tmp2 [3]
4751 If we're compiling -fPIC, we replace the first instruction with:
4753 moveli tmp1, hw1_last_got(x) [1]
4754 shl16insli tmp2, tmp1, hw0_got(x) [2]
4755 add<x> tmp3, got_reg, tmp2 [3]
4756 ld<4> tmp3, tmp3 [3]
4758 Note that we're careful to disturb the instruction sequence as
4759 little as possible, since it's very late in the compilation
4762 tilegx_fixup_pcrel_references (void)
4764 rtx_insn
*insn
, *next_insn
;
4765 bool same_section_as_entry
= true;
4767 for (insn
= get_insns (); insn
; insn
= next_insn
)
4769 next_insn
= NEXT_INSN (insn
);
4771 if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_SWITCH_TEXT_SECTIONS
)
4773 same_section_as_entry
= !same_section_as_entry
;
4777 if (same_section_as_entry
)
4781 && GET_CODE (PATTERN (insn
)) != USE
4782 && GET_CODE (PATTERN (insn
)) != CLOBBER
))
4787 if (match_pcrel_step1 (insn
))
4788 replace_mov_pcrel_step1 (insn
);
4789 else if (match_pcrel_step2 (insn
))
4790 replace_mov_pcrel_step2 (insn
);
4791 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3_32bit
)
4792 replace_mov_pcrel_step3 (insn
);
4796 if (match_pcrel_step1 (insn
))
4797 replace_mov_pcrel_step1 (insn
);
4798 else if (match_pcrel_step2 (insn
))
4799 replace_mov_pcrel_step2 (insn
);
4800 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3
)
4801 replace_mov_pcrel_step3 (insn
);
4807 /* Ensure that no var tracking notes are emitted in the middle of a
4808 three-instruction bundle. */
4810 reorder_var_tracking_notes (void)
4813 FOR_EACH_BB_FN (bb
, cfun
)
4815 rtx_insn
*insn
, *next
;
4816 rtx_insn
*queue
= NULL
;
4817 bool in_bundle
= false;
4819 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4821 next
= NEXT_INSN (insn
);
4825 /* Emit queued up notes at the last instruction of a
4827 if (GET_MODE (insn
) == QImode
)
4831 rtx_insn
*next_queue
= PREV_INSN (queue
);
4832 SET_PREV_INSN (NEXT_INSN (insn
)) = queue
;
4833 SET_NEXT_INSN (queue
) = NEXT_INSN (insn
);
4834 SET_NEXT_INSN (insn
) = queue
;
4835 SET_PREV_INSN (queue
) = insn
;
4840 else if (GET_MODE (insn
) == SImode
)
4843 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4847 rtx_insn
*prev
= PREV_INSN (insn
);
4848 SET_PREV_INSN (next
) = prev
;
4849 SET_NEXT_INSN (prev
) = next
;
4851 SET_PREV_INSN (insn
) = queue
;
4860 /* Perform machine dependent operations on the rtl chain INSNS. */
4864 /* We are freeing block_for_insn in the toplev to keep compatibility
4865 with old MDEP_REORGS that are not CFG based. Recompute it
4867 compute_bb_for_insn ();
4869 if (flag_reorder_blocks_and_partition
)
4871 tilegx_fixup_pcrel_references ();
4874 if (flag_schedule_insns_after_reload
)
4878 timevar_push (TV_SCHED2
);
4880 timevar_pop (TV_SCHED2
);
4882 /* Examine the schedule to group into bundles. */
4883 tilegx_gen_bundles ();
4888 if (flag_var_tracking
)
4890 timevar_push (TV_VAR_TRACKING
);
4891 variable_tracking_main ();
4892 reorder_var_tracking_notes ();
4893 timevar_pop (TV_VAR_TRACKING
);
4896 df_finish_pass (false);
4903 /* Select a format to encode pointers in exception handling data.
4904 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4905 GLOBAL is true if the symbol may be affected by dynamic
4908 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED
, int global
)
4910 int type
= TARGET_32BIT
? DW_EH_PE_sdata4
: DW_EH_PE_sdata8
;
4911 return (global
? DW_EH_PE_indirect
: 0) | DW_EH_PE_pcrel
| type
;
4915 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4917 tilegx_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
4918 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
4921 rtx this_rtx
, funexp
, addend
;
4924 /* Pretend to be a post-reload pass while generating rtl. */
4925 reload_completed
= 1;
4927 /* Mark the end of the (empty) prologue. */
4928 emit_note (NOTE_INSN_PROLOGUE_END
);
4930 /* Find the "this" pointer. If the function returns a structure,
4931 the structure return pointer is in $1. */
4932 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
4933 this_rtx
= gen_rtx_REG (Pmode
, 1);
4935 this_rtx
= gen_rtx_REG (Pmode
, 0);
4937 /* Add DELTA to THIS_RTX. */
4938 if (!(delta
>= -32868 && delta
<= 32767))
4940 addend
= gen_rtx_REG (Pmode
, 29);
4941 emit_move_insn (addend
, GEN_INT (delta
));
4944 addend
= GEN_INT (delta
);
4947 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, addend
));
4949 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, addend
));
4951 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4956 tmp
= gen_rtx_REG (Pmode
, 29);
4957 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, this_rtx
));
4959 if (!(vcall_offset
>= -32868 && vcall_offset
<= 32767))
4961 addend
= gen_rtx_REG (Pmode
, 28);
4962 emit_move_insn (addend
, GEN_INT (vcall_offset
));
4965 addend
= GEN_INT (vcall_offset
);
4968 emit_insn (gen_addsi3 (tmp
, tmp
, addend
));
4970 emit_insn (gen_adddi3 (tmp
, tmp
, addend
));
4972 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, tmp
));
4975 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, tmp
));
4977 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, tmp
));
4980 /* Generate a tail call to the target function. */
4981 if (!TREE_USED (function
))
4983 assemble_external (function
);
4984 TREE_USED (function
) = 1;
4986 funexp
= XEXP (DECL_RTL (function
), 0);
4987 funexp
= gen_rtx_MEM (FUNCTION_MODE
, funexp
);
4988 insn
= emit_call_insn (gen_sibcall (funexp
, const0_rtx
));
4989 SIBLING_CALL_P (insn
) = 1;
4991 /* Run just enough of rest_of_compilation to get the insns emitted.
4992 There's not really enough bulk here to make other passes such as
4993 instruction scheduling worth while. Note that use_thunk calls
4994 assemble_start_function and assemble_end_function.
4996 We don't currently bundle, but the instruciton sequence is all
4997 serial except for the tail call, so we're only wasting one cycle.
4999 insn
= get_insns ();
5000 shorten_branches (insn
);
5001 final_start_function (insn
, file
, 1);
5002 final (insn
, file
, 1);
5003 final_end_function ();
5005 /* Stop pretending to be a post-reload pass. */
5006 reload_completed
= 0;
5010 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
5012 tilegx_asm_trampoline_template (FILE *file
)
5014 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
5017 fprintf (file
, "\tlnk r10\n");
5018 fprintf (file
, "\taddxi r10, r10, 32\n");
5019 fprintf (file
, "\tld4s_add r11, r10, %d\n", ptr_mode_size
);
5020 fprintf (file
, "\tld4s r10, r10\n");
5021 fprintf (file
, "\tjr r11\n");
5022 fprintf (file
, "\t.word 0 # <function address>\n");
5023 fprintf (file
, "\t.word 0 # <static chain value>\n");
5027 fprintf (file
, "\tlnk r10\n");
5028 fprintf (file
, "\taddi r10, r10, 32\n");
5029 fprintf (file
, "\tld_add r11, r10, %d\n", ptr_mode_size
);
5030 fprintf (file
, "\tld r10, r10\n");
5031 fprintf (file
, "\tjr r11\n");
5032 fprintf (file
, "\t.quad 0 # <function address>\n");
5033 fprintf (file
, "\t.quad 0 # <static chain value>\n");
5038 /* Implement TARGET_TRAMPOLINE_INIT. */
5040 tilegx_trampoline_init (rtx m_tramp
, tree fndecl
, rtx static_chain
)
5044 rtx begin_addr
, end_addr
;
5045 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
5047 fnaddr
= copy_to_reg (XEXP (DECL_RTL (fndecl
), 0));
5048 chaddr
= copy_to_reg (static_chain
);
5050 emit_block_move (m_tramp
, assemble_trampoline_template (),
5051 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
5053 mem
= adjust_address (m_tramp
, ptr_mode
,
5054 TRAMPOLINE_SIZE
- 2 * ptr_mode_size
);
5055 emit_move_insn (mem
, fnaddr
);
5056 mem
= adjust_address (m_tramp
, ptr_mode
,
5057 TRAMPOLINE_SIZE
- ptr_mode_size
);
5058 emit_move_insn (mem
, chaddr
);
5060 /* Get pointers to the beginning and end of the code block. */
5061 begin_addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
5062 end_addr
= force_reg (Pmode
, plus_constant (Pmode
, XEXP (m_tramp
, 0),
5065 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__clear_cache"),
5066 LCT_NORMAL
, VOIDmode
, 2, begin_addr
, Pmode
,
5071 /* Implement TARGET_PRINT_OPERAND. */
5073 tilegx_print_operand (FILE *file
, rtx x
, int code
)
5078 /* Print the compare operator opcode for conditional moves. */
5079 switch (GET_CODE (x
))
5088 output_operand_lossage ("invalid %%c operand");
5093 /* Print the compare operator opcode for conditional moves. */
5094 switch (GET_CODE (x
))
5103 output_operand_lossage ("invalid %%C operand");
5109 /* Print the compare operator opcode for conditional moves. */
5110 switch (GET_CODE (x
))
5119 output_operand_lossage ("invalid %%d operand");
5126 /* Print the compare operator opcode for conditional moves. */
5127 switch (GET_CODE (x
))
5136 output_operand_lossage ("invalid %%D operand");
5143 if (GET_CODE (x
) == CONST
5144 && GET_CODE (XEXP (x
, 0)) == UNSPEC
)
5146 rtx addr
= XVECEXP (XEXP (x
, 0), 0, 0);
5147 int unspec
= XINT (XEXP (x
, 0), 1);
5148 const char *opstr
= NULL
;
5152 case UNSPEC_HW0_PCREL
:
5156 case UNSPEC_HW1_PCREL
:
5165 case UNSPEC_HW0_LAST
:
5168 case UNSPEC_HW1_LAST
:
5169 case UNSPEC_HW1_LAST_PCREL
:
5172 case UNSPEC_HW2_LAST
:
5173 case UNSPEC_HW2_LAST_PCREL
:
5176 case UNSPEC_HW0_GOT
:
5179 case UNSPEC_HW0_LAST_GOT
:
5180 opstr
= "hw0_last_got";
5182 case UNSPEC_HW1_LAST_GOT
:
5183 opstr
= "hw1_last_got";
5185 case UNSPEC_HW0_TLS_GD
:
5186 opstr
= "hw0_tls_gd";
5188 case UNSPEC_HW1_LAST_TLS_GD
:
5189 opstr
= "hw1_last_tls_gd";
5191 case UNSPEC_HW0_TLS_IE
:
5192 opstr
= "hw0_tls_ie";
5194 case UNSPEC_HW1_LAST_TLS_IE
:
5195 opstr
= "hw1_last_tls_ie";
5197 case UNSPEC_HW0_TLS_LE
:
5198 opstr
= "hw0_tls_le";
5200 case UNSPEC_HW1_LAST_TLS_LE
:
5201 opstr
= "hw1_last_tls_le";
5203 case UNSPEC_HW0_PLT_PCREL
:
5206 case UNSPEC_HW1_PLT_PCREL
:
5209 case UNSPEC_HW1_LAST_PLT_PCREL
:
5210 opstr
= "hw1_last_plt";
5212 case UNSPEC_HW2_LAST_PLT_PCREL
:
5213 opstr
= "hw2_last_plt";
5216 output_operand_lossage ("invalid %%H specifier");
5219 fputs (opstr
, file
);
5221 output_addr_const (file
, addr
);
5223 if (unspec
== UNSPEC_HW0_PCREL
5224 || unspec
== UNSPEC_HW1_PCREL
5225 || unspec
== UNSPEC_HW1_LAST_PCREL
5226 || unspec
== UNSPEC_HW2_LAST_PCREL
5227 || unspec
== UNSPEC_HW0_PLT_PCREL
5228 || unspec
== UNSPEC_HW1_PLT_PCREL
5229 || unspec
== UNSPEC_HW1_LAST_PLT_PCREL
5230 || unspec
== UNSPEC_HW2_LAST_PLT_PCREL
)
5232 rtx addr2
= XVECEXP (XEXP (x
, 0), 0, 1);
5233 fputs (" - " , file
);
5234 output_addr_const (file
, addr2
);
5240 else if (symbolic_operand (x
, VOIDmode
))
5242 output_addr_const (file
, x
);
5250 /* Print the low 16 bits of a constant. */
5252 if (CONST_INT_P (x
))
5254 else if (GET_CODE (x
) == CONST_DOUBLE
)
5255 i
= CONST_DOUBLE_LOW (x
);
5258 output_operand_lossage ("invalid %%h operand");
5261 i
= trunc_int_for_mode (i
, HImode
);
5262 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5267 /* Print an auto-inc memory operand. */
5270 output_operand_lossage ("invalid %%I operand");
5274 output_memory_autoinc_first
= true;
5275 output_address (GET_MODE (x
), XEXP (x
, 0));
5279 /* Print an auto-inc memory operand. */
5282 output_operand_lossage ("invalid %%i operand");
5286 output_memory_autoinc_first
= false;
5287 output_address (GET_MODE (x
), XEXP (x
, 0));
5292 /* Print the low 8 bits of a constant. */
5294 if (CONST_INT_P (x
))
5296 else if (GET_CODE (x
) == CONST_DOUBLE
)
5297 i
= CONST_DOUBLE_LOW (x
);
5298 else if (GET_CODE (x
) == CONST_VECTOR
5299 && CONST_INT_P (CONST_VECTOR_ELT (x
, 0)))
5300 i
= INTVAL (CONST_VECTOR_ELT (x
, 0));
5303 output_operand_lossage ("invalid %%j operand");
5306 i
= trunc_int_for_mode (i
, QImode
);
5307 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5313 /* Print a constant plus one. */
5314 if (!CONST_INT_P (x
))
5316 output_operand_lossage ("invalid %%P operand");
5319 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (x
) + 1);
5326 /* Print a bfextu-style bit range. */
5327 int first_bit
, last_bit
;
5328 HOST_WIDE_INT flip
= (code
== 'm') ? ~0 : 0;
5330 if (!CONST_INT_P (x
)
5331 || !tilegx_bitfield_operand_p (INTVAL (x
) ^ flip
,
5332 &first_bit
, &last_bit
))
5334 output_operand_lossage ("invalid %%%c operand", code
);
5338 fprintf (file
, "%d, %d", first_bit
, last_bit
);
5344 const char *reg
= NULL
;
5346 /* Print a network register. */
5347 if (!CONST_INT_P (x
))
5349 output_operand_lossage ("invalid %%N operand");
5355 case TILEGX_NETREG_IDN0
: reg
= "idn0"; break;
5356 case TILEGX_NETREG_IDN1
: reg
= "idn1"; break;
5357 case TILEGX_NETREG_UDN0
: reg
= "udn0"; break;
5358 case TILEGX_NETREG_UDN1
: reg
= "udn1"; break;
5359 case TILEGX_NETREG_UDN2
: reg
= "udn2"; break;
5360 case TILEGX_NETREG_UDN3
: reg
= "udn3"; break;
5365 fprintf (file
, reg
);
5370 if (GET_CODE (x
) == SYMBOL_REF
)
5372 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5373 fprintf (file
, "plt(");
5374 output_addr_const (file
, x
);
5375 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5376 fprintf (file
, ")");
5379 output_addr_const (file
, x
);
5383 /* In this case we need a register. Use 'zero' if the operand
5386 || (GET_MODE (x
) != VOIDmode
&& x
== CONST0_RTX (GET_MODE (x
))))
5388 fputs ("zero", file
);
5391 else if (!REG_P (x
))
5393 output_operand_lossage ("invalid operand for 'r' specifier");
5401 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
5406 output_address (VOIDmode
, XEXP (x
, 0));
5411 output_addr_const (file
, x
);
5417 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5422 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5424 tilegx_print_operand_address (FILE *file
, machine_mode mode
, rtx addr
)
5426 if (GET_CODE (addr
) == POST_DEC
5427 || GET_CODE (addr
) == POST_INC
)
5429 int offset
= GET_MODE_SIZE (mode
);
5431 gcc_assert (mode
!= VOIDmode
);
5433 if (output_memory_autoinc_first
)
5434 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5436 fprintf (file
, "%d",
5437 GET_CODE (addr
) == POST_DEC
? -offset
: offset
);
5439 else if (GET_CODE (addr
) == POST_MODIFY
)
5441 gcc_assert (mode
!= VOIDmode
);
5443 gcc_assert (GET_CODE (XEXP (addr
, 1)) == PLUS
);
5445 if (output_memory_autoinc_first
)
5446 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5448 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
,
5449 INTVAL (XEXP (XEXP (addr
, 1), 1)));
5452 tilegx_print_operand (file
, addr
, 'r');
5456 /* Machine mode of current insn, for determining curly brace
5458 static machine_mode insn_mode
;
5461 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5463 tilegx_final_prescan_insn (rtx_insn
*insn
)
5465 /* Record this for tilegx_asm_output_opcode to examine. */
5466 insn_mode
= GET_MODE (insn
);
5470 /* While emitting asm, are we currently inside '{' for a bundle? */
5471 static bool tilegx_in_bundle
= false;
5473 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5474 appropriate given the bundling information recorded by
5475 tilegx_gen_bundles. */
5477 tilegx_asm_output_opcode (FILE *stream
, const char *code
)
5479 bool pseudo
= !strcmp (code
, "pseudo");
5481 if (!tilegx_in_bundle
&& insn_mode
== SImode
)
5483 /* Start a new bundle. */
5484 fprintf (stream
, "{\n\t");
5485 tilegx_in_bundle
= true;
5488 if (tilegx_in_bundle
&& insn_mode
== QImode
)
5490 /* Close an existing bundle. */
5491 static char buf
[100];
5493 gcc_assert (strlen (code
) + 3 + 1 < sizeof (buf
));
5495 strcpy (buf
, pseudo
? "" : code
);
5496 strcat (buf
, "\n\t}");
5497 tilegx_in_bundle
= false;
5503 return pseudo
? "" : code
;
5508 /* Output assembler code to FILE to increment profiler label # LABELNO
5509 for profiling a function entry. */
5511 tilegx_function_profiler (FILE *file
, int labelno ATTRIBUTE_UNUSED
)
5513 if (tilegx_in_bundle
)
5515 fprintf (file
, "\t}\n");
5518 if (cfun
->static_chain_decl
)
5522 "\taddi\tsp, sp, -16\n"
5533 "\t}\n", MCOUNT_NAME
);
5541 "\t}\n", MCOUNT_NAME
);
5544 if (cfun
->static_chain_decl
)
5547 "\taddi\tsp, sp, 16\n"
5551 tilegx_in_bundle
= false;
5555 /* Implement TARGET_ASM_FILE_END. */
5557 tilegx_file_end (void)
5559 if (NEED_INDICATE_EXEC_STACK
)
5560 file_end_indicate_exec_stack ();
5565 #undef TARGET_HAVE_TLS
5566 #define TARGET_HAVE_TLS HAVE_AS_TLS
5568 #undef TARGET_OPTION_OVERRIDE
5569 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5571 #ifdef TARGET_THREAD_SSP_OFFSET
5572 #undef TARGET_STACK_PROTECT_GUARD
5573 #define TARGET_STACK_PROTECT_GUARD hook_tree_void_null
5576 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5577 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5579 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5580 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5582 #undef TARGET_CANNOT_FORCE_CONST_MEM
5583 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5585 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5586 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5588 #undef TARGET_PASS_BY_REFERENCE
5589 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5591 #undef TARGET_RETURN_IN_MSB
5592 #define TARGET_RETURN_IN_MSB tilegx_return_in_msb
5594 #undef TARGET_RETURN_IN_MEMORY
5595 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5597 #undef TARGET_MODE_REP_EXTENDED
5598 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5600 #undef TARGET_FUNCTION_ARG_BOUNDARY
5601 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5603 #undef TARGET_FUNCTION_ARG
5604 #define TARGET_FUNCTION_ARG tilegx_function_arg
5606 #undef TARGET_FUNCTION_ARG_ADVANCE
5607 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5609 #undef TARGET_FUNCTION_VALUE
5610 #define TARGET_FUNCTION_VALUE tilegx_function_value
5612 #undef TARGET_LIBCALL_VALUE
5613 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5615 #undef TARGET_FUNCTION_VALUE_REGNO_P
5616 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5618 #undef TARGET_PROMOTE_FUNCTION_MODE
5619 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5621 #undef TARGET_PROMOTE_PROTOTYPES
5622 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5624 #undef TARGET_BUILD_BUILTIN_VA_LIST
5625 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5627 #undef TARGET_EXPAND_BUILTIN_VA_START
5628 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5630 #undef TARGET_SETUP_INCOMING_VARARGS
5631 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5633 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5634 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5636 #undef TARGET_RTX_COSTS
5637 #define TARGET_RTX_COSTS tilegx_rtx_costs
5639 #undef TARGET_EXPAND_TO_RTL_HOOK
5640 #define TARGET_EXPAND_TO_RTL_HOOK tilegx_expand_to_rtl_hook
5642 #undef TARGET_SHIFT_TRUNCATION_MASK
5643 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5645 #undef TARGET_INIT_LIBFUNCS
5646 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5648 /* Limit to what we can reach in one addli. */
5649 #undef TARGET_MIN_ANCHOR_OFFSET
5650 #define TARGET_MIN_ANCHOR_OFFSET -32768
5651 #undef TARGET_MAX_ANCHOR_OFFSET
5652 #define TARGET_MAX_ANCHOR_OFFSET 32767
5654 #undef TARGET_LEGITIMATE_CONSTANT_P
5655 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5658 #define TARGET_LRA_P hook_bool_void_false
5660 #undef TARGET_LEGITIMATE_ADDRESS_P
5661 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5663 #undef TARGET_LEGITIMIZE_ADDRESS
5664 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5666 #undef TARGET_DELEGITIMIZE_ADDRESS
5667 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5669 #undef TARGET_INIT_BUILTINS
5670 #define TARGET_INIT_BUILTINS tilegx_init_builtins
5672 #undef TARGET_BUILTIN_DECL
5673 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5675 #undef TARGET_EXPAND_BUILTIN
5676 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5678 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5679 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5681 #undef TARGET_FRAME_POINTER_REQUIRED
5682 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5684 #undef TARGET_DELAY_SCHED2
5685 #define TARGET_DELAY_SCHED2 true
5687 #undef TARGET_DELAY_VARTRACK
5688 #define TARGET_DELAY_VARTRACK true
5690 #undef TARGET_SCHED_ISSUE_RATE
5691 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5693 #undef TARGET_SCHED_ADJUST_COST
5694 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5696 #undef TARGET_MACHINE_DEPENDENT_REORG
5697 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5699 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5700 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5701 hook_bool_const_tree_hwi_hwi_const_tree_true
5703 #undef TARGET_ASM_OUTPUT_MI_THUNK
5704 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5706 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5707 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5709 #undef TARGET_TRAMPOLINE_INIT
5710 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5712 #undef TARGET_PRINT_OPERAND
5713 #define TARGET_PRINT_OPERAND tilegx_print_operand
5715 #undef TARGET_PRINT_OPERAND_ADDRESS
5716 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5718 #undef TARGET_ASM_FILE_END
5719 #define TARGET_ASM_FILE_END tilegx_file_end
5721 #undef TARGET_ASM_ALIGNED_DI_OP
5722 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5724 #undef TARGET_CAN_USE_DOLOOP_P
5725 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
5727 struct gcc_target targetm
= TARGET_INITIALIZER
;
5729 #include "gt-tilegx.h"