1 /* Subroutines used for code generation on the Tilera TILE-Gx.
2 Copyright (C) 2011-2013 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"
27 #include "insn-config.h"
29 #include "insn-attr.h"
32 #include "langhooks.h"
34 #include "sched-int.h"
36 #include "tm-constrs.h"
38 #include "target-def.h"
43 #include "pointer-set.h"
44 #include "hash-table.h"
47 #include "basic-block.h"
48 #include "tree-ssa-alias.h"
49 #include "internal-fn.h"
50 #include "gimple-fold.h"
52 #include "gimple-expr.h"
55 #include "stringpool.h"
56 #include "stor-layout.h"
61 #include "tilegx-builtins.h"
62 #include "tilegx-multiply.h"
63 #include "diagnostic.h"
65 /* SYMBOL_REF for GOT */
66 static GTY(()) rtx g_got_symbol
= NULL
;
68 /* In case of a POST_INC or POST_DEC memory reference, we must report
69 the mode of the memory reference from TARGET_PRINT_OPERAND to
70 TARGET_PRINT_OPERAND_ADDRESS. */
71 static enum machine_mode output_memory_reference_mode
;
73 /* Report whether we're printing out the first address fragment of a
74 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
75 TARGET_PRINT_OPERAND_ADDRESS. */
76 static bool output_memory_autoinc_first
;
82 /* Implement TARGET_OPTION_OVERRIDE. */
84 tilegx_option_override (void)
86 if (global_options_set
.x_tilegx_cmodel
)
88 switch (tilegx_cmodel
)
93 tilegx_cmodel
= CM_SMALL_PIC
;
99 tilegx_cmodel
= CM_LARGE_PIC
;
107 tilegx_cmodel
= flag_pic
? CM_SMALL_PIC
: CM_SMALL
;
109 /* When modulo scheduling is enabled, we still rely on regular
110 scheduler for bundling. */
111 if (flag_modulo_sched
)
112 flag_resched_modulo_sched
= 1;
117 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
119 tilegx_scalar_mode_supported_p (enum machine_mode mode
)
140 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
142 tilegx_vector_mode_supported_p (enum machine_mode mode
)
144 return mode
== V8QImode
|| mode
== V4HImode
|| mode
== V2SImode
;
148 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
150 tilegx_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED
,
151 rtx x ATTRIBUTE_UNUSED
)
157 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
159 tilegx_function_ok_for_sibcall (tree decl
, tree exp ATTRIBUTE_UNUSED
)
161 return (tilegx_cmodel
!= CM_LARGE
&& tilegx_cmodel
!= CM_LARGE_PIC
166 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
167 passed by reference. */
169 tilegx_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED
,
170 enum machine_mode mode ATTRIBUTE_UNUSED
,
171 const_tree type
, bool named ATTRIBUTE_UNUSED
)
173 return (type
&& TYPE_SIZE (type
)
174 && TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
);
178 /* Implement TARGET_RETURN_IN_MEMORY. */
180 tilegx_return_in_memory (const_tree type
, const_tree fndecl ATTRIBUTE_UNUSED
)
182 return !IN_RANGE (int_size_in_bytes (type
),
183 0, TILEGX_NUM_RETURN_REGS
* UNITS_PER_WORD
);
187 /* Implement TARGET_MODE_REP_EXTENDED. */
189 tilegx_mode_rep_extended (enum machine_mode mode
, enum machine_mode mode_rep
)
191 /* SImode register values are sign-extended to DImode. */
192 if (mode
== SImode
&& mode_rep
== DImode
)
199 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
201 tilegx_function_arg_boundary (enum machine_mode mode
, const_tree type
)
203 unsigned int alignment
;
205 alignment
= type
? TYPE_ALIGN (type
) : GET_MODE_ALIGNMENT (mode
);
206 if (alignment
< PARM_BOUNDARY
)
207 alignment
= PARM_BOUNDARY
;
208 if (alignment
> STACK_BOUNDARY
)
209 alignment
= STACK_BOUNDARY
;
214 /* Implement TARGET_FUNCTION_ARG. */
216 tilegx_function_arg (cumulative_args_t cum_v
,
217 enum machine_mode mode
,
218 const_tree type
, bool named ATTRIBUTE_UNUSED
)
220 CUMULATIVE_ARGS cum
= *get_cumulative_args (cum_v
);
221 int byte_size
= ((mode
== BLKmode
)
222 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
224 if (cum
>= TILEGX_NUM_ARG_REGS
)
227 /* The ABI does not allow parameters to be passed partially in reg
228 and partially in stack. */
229 if ((cum
+ (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
)
230 > TILEGX_NUM_ARG_REGS
)
233 return gen_rtx_REG (mode
, cum
);
237 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
239 tilegx_function_arg_advance (cumulative_args_t cum_v
,
240 enum machine_mode mode
,
241 const_tree type
, bool named ATTRIBUTE_UNUSED
)
243 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
245 int byte_size
= ((mode
== BLKmode
)
246 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
247 int word_size
= (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
249 /* If the current argument does not fit in the pretend_args space,
251 if (*cum
< TILEGX_NUM_ARG_REGS
252 && *cum
+ word_size
> TILEGX_NUM_ARG_REGS
)
253 *cum
= TILEGX_NUM_ARG_REGS
;
259 /* Implement TARGET_FUNCTION_VALUE. */
261 tilegx_function_value (const_tree valtype
, const_tree fn_decl_or_type
,
262 bool outgoing ATTRIBUTE_UNUSED
)
264 enum machine_mode mode
;
267 mode
= TYPE_MODE (valtype
);
268 unsigned_p
= TYPE_UNSIGNED (valtype
);
270 mode
= promote_function_mode (valtype
, mode
, &unsigned_p
,
273 return gen_rtx_REG (mode
, 0);
277 /* Implement TARGET_LIBCALL_VALUE. */
279 tilegx_libcall_value (enum machine_mode mode
,
280 const_rtx fun ATTRIBUTE_UNUSED
)
282 return gen_rtx_REG (mode
, 0);
286 /* Implement FUNCTION_VALUE_REGNO_P. */
288 tilegx_function_value_regno_p (const unsigned int regno
)
290 return regno
< TILEGX_NUM_RETURN_REGS
;
294 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
296 tilegx_build_builtin_va_list (void)
298 tree f_args
, f_skip
, record
, type_decl
;
301 record
= lang_hooks
.types
.make_type (RECORD_TYPE
);
303 type_decl
= build_decl (BUILTINS_LOCATION
, TYPE_DECL
,
304 get_identifier ("__va_list_tag"), record
);
306 f_args
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
307 get_identifier ("__args"), ptr_type_node
);
308 f_skip
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
309 get_identifier ("__skip"), ptr_type_node
);
311 DECL_FIELD_CONTEXT (f_args
) = record
;
313 DECL_FIELD_CONTEXT (f_skip
) = record
;
315 TREE_CHAIN (record
) = type_decl
;
316 TYPE_NAME (record
) = type_decl
;
317 TYPE_FIELDS (record
) = f_args
;
318 TREE_CHAIN (f_args
) = f_skip
;
320 /* We know this is being padded and we want it too. It is an
321 internal type so hide the warnings from the user. */
325 layout_type (record
);
329 /* The correct type is an array type of one element. */
334 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
336 tilegx_va_start (tree valist
, rtx nextarg ATTRIBUTE_UNUSED
)
341 f_args
= TYPE_FIELDS (TREE_TYPE (valist
));
342 f_skip
= TREE_CHAIN (f_args
);
345 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
347 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
349 /* Find the __args area. */
350 t
= make_tree (TREE_TYPE (args
), virtual_incoming_args_rtx
);
351 t
= fold_build_pointer_plus_hwi (t
,
353 (crtl
->args
.info
- TILEGX_NUM_ARG_REGS
));
355 if (crtl
->args
.pretend_args_size
> 0)
356 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
358 t
= build2 (MODIFY_EXPR
, TREE_TYPE (args
), args
, t
);
359 TREE_SIDE_EFFECTS (t
) = 1;
360 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
362 /* Find the __skip area. */
363 t
= make_tree (TREE_TYPE (skip
), virtual_incoming_args_rtx
);
364 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
365 t
= build2 (MODIFY_EXPR
, TREE_TYPE (skip
), skip
, t
);
366 TREE_SIDE_EFFECTS (t
) = 1;
367 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
371 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
373 tilegx_setup_incoming_varargs (cumulative_args_t cum
,
374 enum machine_mode mode
,
375 tree type
, int *pretend_args
, int no_rtl
)
377 CUMULATIVE_ARGS local_cum
= *get_cumulative_args (cum
);
380 /* The caller has advanced CUM up to, but not beyond, the last named
381 argument. Advance a local copy of CUM past the last "real" named
382 argument, to find out how many registers are left over. */
383 targetm
.calls
.function_arg_advance (pack_cumulative_args (&local_cum
),
385 first_reg
= local_cum
;
387 if (local_cum
< TILEGX_NUM_ARG_REGS
)
389 *pretend_args
= UNITS_PER_WORD
* (TILEGX_NUM_ARG_REGS
- first_reg
);
393 alias_set_type set
= get_varargs_alias_set ();
395 gen_rtx_MEM (BLKmode
, plus_constant (Pmode
,
396 virtual_incoming_args_rtx
,
397 -STACK_POINTER_OFFSET
-
399 (TILEGX_NUM_ARG_REGS
-
401 MEM_NOTRAP_P (tmp
) = 1;
402 set_mem_alias_set (tmp
, set
);
403 move_block_from_reg (first_reg
, tmp
,
404 TILEGX_NUM_ARG_REGS
- first_reg
);
412 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
413 the va_list structure VALIST as required to retrieve an argument of
414 type TYPE, and returning that argument.
416 ret = va_arg(VALIST, TYPE);
418 generates code equivalent to:
420 paddedsize = (sizeof(TYPE) + 3) & -4;
421 if ( (VALIST.__args + paddedsize > VALIST.__skip)
422 & (VALIST.__args <= VALIST.__skip))
423 addr = VALIST.__skip + STACK_POINTER_OFFSET;
425 addr = VALIST.__args;
426 VALIST.__args = addr + paddedsize;
430 tilegx_gimplify_va_arg_expr (tree valist
, tree type
, gimple_seq
*pre_p
,
431 gimple_seq
*post_p ATTRIBUTE_UNUSED
)
435 HOST_WIDE_INT size
, rsize
;
437 bool pass_by_reference_p
;
439 f_args
= TYPE_FIELDS (va_list_type_node
);
440 f_skip
= TREE_CHAIN (f_args
);
443 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
445 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
447 addr
= create_tmp_var (ptr_type_node
, "va_arg");
449 /* If an object is dynamically sized, a pointer to it is passed
450 instead of the object itself. */
451 pass_by_reference_p
= pass_by_reference (NULL
, TYPE_MODE (type
), type
,
454 if (pass_by_reference_p
)
455 type
= build_pointer_type (type
);
457 size
= int_size_in_bytes (type
);
458 rsize
= ((size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
) * UNITS_PER_WORD
;
460 /* Assert alignment assumption. */
461 gcc_assert (STACK_BOUNDARY
== PARM_BOUNDARY
);
463 /* Build conditional expression to calculate addr. The expression
464 will be gimplified later. */
465 tmp
= fold_build_pointer_plus_hwi (unshare_expr (args
), rsize
);
466 tmp
= build2 (TRUTH_AND_EXPR
, boolean_type_node
,
467 build2 (GT_EXPR
, boolean_type_node
, tmp
, unshare_expr (skip
)),
468 build2 (LE_EXPR
, boolean_type_node
, unshare_expr (args
),
469 unshare_expr (skip
)));
471 tmp
= build3 (COND_EXPR
, ptr_type_node
, tmp
,
472 build2 (POINTER_PLUS_EXPR
, ptr_type_node
, unshare_expr (skip
),
473 size_int (STACK_POINTER_OFFSET
)),
474 unshare_expr (args
));
476 gimplify_assign (addr
, tmp
, pre_p
);
478 /* Update VALIST.__args. */
479 tmp
= fold_build_pointer_plus_hwi (addr
, rsize
);
480 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
482 addr
= fold_convert (build_pointer_type (type
), addr
);
484 if (pass_by_reference_p
)
485 addr
= build_va_arg_indirect_ref (addr
);
487 return build_va_arg_indirect_ref (addr
);
492 /* Implement TARGET_RTX_COSTS. */
494 tilegx_rtx_costs (rtx x
, int code
, int outer_code
, int opno
, int *total
,
500 /* If this is an 8-bit constant, return zero since it can be
501 used nearly anywhere with no cost. If it is a valid operand
502 for an ADD or AND, likewise return 0 if we know it will be
503 used in that context. Otherwise, return 2 since it might be
504 used there later. All other constants take at least two
506 if (satisfies_constraint_I (x
))
511 else if (outer_code
== PLUS
&& add_operand (x
, VOIDmode
))
513 /* Slightly penalize large constants even though we can add
514 them in one instruction, because it forces the use of
515 2-wide bundling mode. */
519 else if (move_operand (x
, SImode
))
521 /* We can materialize in one move. */
522 *total
= COSTS_N_INSNS (1);
527 /* We can materialize in two moves. */
528 *total
= COSTS_N_INSNS (2);
537 *total
= COSTS_N_INSNS (2);
541 *total
= COSTS_N_INSNS (4);
549 /* If outer-code was a sign or zero extension, a cost of
550 COSTS_N_INSNS (1) was already added in, so account for
552 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
553 *total
= COSTS_N_INSNS (1);
555 *total
= COSTS_N_INSNS (2);
559 /* Convey that shl[123]add are efficient. */
560 if (GET_CODE (XEXP (x
, 0)) == MULT
561 && cint_248_operand (XEXP (XEXP (x
, 0), 1), VOIDmode
))
563 *total
= (rtx_cost (XEXP (XEXP (x
, 0), 0),
564 (enum rtx_code
) outer_code
, opno
, speed
)
565 + rtx_cost (XEXP (x
, 1),
566 (enum rtx_code
) outer_code
, opno
, speed
)
567 + COSTS_N_INSNS (1));
573 *total
= COSTS_N_INSNS (2);
580 /* These are handled by software and are very expensive. */
581 *total
= COSTS_N_INSNS (100);
585 case UNSPEC_VOLATILE
:
587 int num
= XINT (x
, 1);
589 if (num
<= TILEGX_LAST_LATENCY_1_INSN
)
590 *total
= COSTS_N_INSNS (1);
591 else if (num
<= TILEGX_LAST_LATENCY_2_INSN
)
592 *total
= COSTS_N_INSNS (2);
593 else if (num
> TILEGX_LAST_LATENCY_INSN
)
595 if (num
== UNSPEC_NON_TEMPORAL
)
597 /* These are basically loads. */
598 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
599 *total
= COSTS_N_INSNS (1);
601 *total
= COSTS_N_INSNS (2);
605 if (outer_code
== PLUS
)
608 *total
= COSTS_N_INSNS (1);
615 case UNSPEC_BLOCKAGE
:
616 case UNSPEC_NETWORK_BARRIER
:
621 case UNSPEC_LNK_AND_LABEL
:
623 case UNSPEC_MOV_PCREL_STEP3
:
624 case UNSPEC_NETWORK_RECEIVE
:
625 case UNSPEC_NETWORK_SEND
:
626 case UNSPEC_SPR_MOVE
:
627 case UNSPEC_TLS_GD_ADD
:
628 *total
= COSTS_N_INSNS (1);
631 case UNSPEC_TLS_IE_LOAD
:
633 *total
= COSTS_N_INSNS (2);
637 *total
= COSTS_N_INSNS (3);
641 *total
= COSTS_N_INSNS (4);
645 case UNSPEC_INSN_CMPEXCH
:
646 case UNSPEC_LATENCY_L2
:
647 *total
= COSTS_N_INSNS (11);
650 case UNSPEC_TLS_GD_CALL
:
651 *total
= COSTS_N_INSNS (30);
654 case UNSPEC_LATENCY_MISS
:
655 *total
= COSTS_N_INSNS (80);
659 *total
= COSTS_N_INSNS (1);
674 /* Create a temporary variable to hold a partial result, to enable
677 create_temp_reg_if_possible (enum machine_mode mode
, rtx default_reg
)
679 return can_create_pseudo_p () ? gen_reg_rtx (mode
) : default_reg
;
683 /* Functions to save and restore machine-specific function data. */
684 static struct machine_function
*
685 tilegx_init_machine_status (void)
687 return ggc_alloc_cleared_machine_function ();
691 /* Do anything needed before RTL is emitted for each function. */
693 tilegx_init_expanders (void)
695 /* Arrange to initialize and mark the machine per-function
697 init_machine_status
= tilegx_init_machine_status
;
699 if (cfun
&& cfun
->machine
&& flag_pic
)
701 static int label_num
= 0;
703 char text_label_name
[32];
705 struct machine_function
*machine
= cfun
->machine
;
707 ASM_GENERATE_INTERNAL_LABEL (text_label_name
, "L_PICLNK", label_num
++);
709 machine
->text_label_symbol
=
710 gen_rtx_SYMBOL_REF (Pmode
, ggc_strdup (text_label_name
));
712 machine
->text_label_rtx
=
713 gen_rtx_REG (Pmode
, TILEGX_PIC_TEXT_LABEL_REGNUM
);
715 machine
->got_rtx
= gen_rtx_REG (Pmode
, PIC_OFFSET_TABLE_REGNUM
);
717 machine
->calls_tls_get_addr
= false;
722 /* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode
723 matching insns and therefore guarantee that the shift count is
724 modulo 64. SImode shifts sometimes use the 64 bit version so do
725 not hold such guarantee. */
726 static unsigned HOST_WIDE_INT
727 tilegx_shift_truncation_mask (enum machine_mode mode
)
729 return mode
== DImode
? 63 : 0;
733 /* Implement TARGET_INIT_LIBFUNCS. */
735 tilegx_init_libfuncs (void)
737 /* We need to explicitly generate these libfunc's to support
738 conversion of divide by constant to multiply (the divide stubs in
739 tilegx.md exist also for this reason). Normally we'd expect gcc
740 to lazily generate them when they are needed, but for some reason
741 it's set up to only generate them if the mode is the word
743 set_optab_libfunc (sdiv_optab
, SImode
, "__divsi3");
744 set_optab_libfunc (udiv_optab
, SImode
, "__udivsi3");
745 set_optab_libfunc (smod_optab
, SImode
, "__modsi3");
746 set_optab_libfunc (umod_optab
, SImode
, "__umodsi3");
750 /* Return true if X contains a thread-local symbol. */
752 tilegx_tls_referenced_p (rtx x
)
754 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == PLUS
)
755 x
= XEXP (XEXP (x
, 0), 0);
757 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
))
760 /* That's all we handle in tilegx_legitimize_tls_address for
766 /* Return true if X requires a scratch register. It is given that
767 flag_pic is on and that X satisfies CONSTANT_P. */
769 tilegx_pic_address_needs_scratch (rtx x
)
771 if (GET_CODE (x
) == CONST
772 && GET_CODE (XEXP (x
, 0)) == PLUS
773 && (GET_CODE (XEXP (XEXP (x
, 0), 0)) == SYMBOL_REF
774 || GET_CODE (XEXP (XEXP (x
, 0), 0)) == LABEL_REF
)
775 && (CONST_INT_P (XEXP (XEXP (x
, 0), 1))))
782 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
783 which we are willing to load the value into a register via a move
784 pattern. TLS cannot be treated as a constant because it can
785 include a function call. */
787 tilegx_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
789 switch (GET_CODE (x
))
793 return !tilegx_tls_referenced_p (x
);
801 /* Return true if the constant value X is a legitimate general operand
802 when generating PIC code. It is given that flag_pic is on and that
803 X satisfies CONSTANT_P. */
805 tilegx_legitimate_pic_operand_p (rtx x
)
807 if (tilegx_pic_address_needs_scratch (x
))
810 if (tilegx_tls_referenced_p (x
))
817 /* Return true if the rtx X can be used as an address operand. */
819 tilegx_legitimate_address_p (enum machine_mode
ARG_UNUSED (mode
), rtx x
,
822 if (GET_CODE (x
) == SUBREG
)
825 switch (GET_CODE (x
))
829 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
836 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
839 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
842 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
845 if (!satisfies_constraint_I (XEXP (XEXP (x
, 1), 1)))
858 /* Check if x is a valid reg. */
863 return REGNO_OK_FOR_BASE_P (REGNO (x
));
869 /* Return the rtx containing SYMBOL_REF to the text label. */
871 tilegx_text_label_symbol (void)
873 return cfun
->machine
->text_label_symbol
;
877 /* Return the register storing the value of the text label. */
879 tilegx_text_label_rtx (void)
881 return cfun
->machine
->text_label_rtx
;
885 /* Return the register storing the value of the global offset
888 tilegx_got_rtx (void)
890 return cfun
->machine
->got_rtx
;
894 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
896 tilegx_got_symbol (void)
898 if (g_got_symbol
== NULL
)
899 g_got_symbol
= gen_rtx_SYMBOL_REF (Pmode
, "_GLOBAL_OFFSET_TABLE_");
905 /* Return a reference to the got to be used by tls references. */
907 tilegx_tls_got (void)
912 crtl
->uses_pic_offset_table
= 1;
913 return tilegx_got_rtx ();
916 temp
= gen_reg_rtx (Pmode
);
917 emit_move_insn (temp
, tilegx_got_symbol ());
923 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
924 this (thread-local) address. */
926 tilegx_legitimize_tls_address (rtx addr
)
930 gcc_assert (can_create_pseudo_p ());
932 if (GET_CODE (addr
) == SYMBOL_REF
)
933 switch (SYMBOL_REF_TLS_MODEL (addr
))
935 case TLS_MODEL_GLOBAL_DYNAMIC
:
936 case TLS_MODEL_LOCAL_DYNAMIC
:
938 rtx r0
, temp
, temp2
, temp3
, got
, last
;
940 ret
= gen_reg_rtx (Pmode
);
941 r0
= gen_rtx_REG (Pmode
, 0);
942 temp
= gen_reg_rtx (Pmode
);
943 temp2
= gen_reg_rtx (Pmode
);
944 temp3
= gen_reg_rtx (Pmode
);
946 got
= tilegx_tls_got ();
949 emit_insn (gen_mov_tls_gd_step1_32bit (temp
, addr
));
950 emit_insn (gen_mov_tls_gd_step2_32bit (temp2
, temp
, addr
));
951 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
955 emit_insn (gen_mov_tls_gd_step1 (temp
, addr
));
956 emit_insn (gen_mov_tls_gd_step2 (temp2
, temp
, addr
));
957 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
960 emit_move_insn (r0
, temp2
);
964 emit_insn (gen_tls_gd_call_32bit (addr
));
968 emit_insn (gen_tls_gd_call (addr
));
971 emit_move_insn (temp3
, r0
);
974 last
= emit_insn (gen_tls_gd_add_32bit (ret
, temp3
, addr
));
976 last
= emit_insn (gen_tls_gd_add (ret
, temp3
, addr
));
978 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
981 case TLS_MODEL_INITIAL_EXEC
:
983 rtx temp
, temp2
, temp3
, got
, last
;
985 ret
= gen_reg_rtx (Pmode
);
986 temp
= gen_reg_rtx (Pmode
);
987 temp2
= gen_reg_rtx (Pmode
);
988 temp3
= gen_reg_rtx (Pmode
);
990 got
= tilegx_tls_got ();
993 emit_insn (gen_mov_tls_ie_step1_32bit (temp
, addr
));
994 emit_insn (gen_mov_tls_ie_step2_32bit (temp2
, temp
, addr
));
995 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
996 emit_insn (gen_tls_ie_load_32bit (temp3
, temp2
, addr
));
1000 emit_insn (gen_mov_tls_ie_step1 (temp
, addr
));
1001 emit_insn (gen_mov_tls_ie_step2 (temp2
, temp
, addr
));
1002 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
1003 emit_insn (gen_tls_ie_load (temp3
, temp2
, addr
));
1008 gen_rtx_PLUS (Pmode
,
1010 THREAD_POINTER_REGNUM
),
1012 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1015 case TLS_MODEL_LOCAL_EXEC
:
1017 rtx temp
, temp2
, last
;
1019 ret
= gen_reg_rtx (Pmode
);
1020 temp
= gen_reg_rtx (Pmode
);
1021 temp2
= gen_reg_rtx (Pmode
);
1025 emit_insn (gen_mov_tls_le_step1_32bit (temp
, addr
));
1026 emit_insn (gen_mov_tls_le_step2_32bit (temp2
, temp
, addr
));
1030 emit_insn (gen_mov_tls_le_step1 (temp
, addr
));
1031 emit_insn (gen_mov_tls_le_step2 (temp2
, temp
, addr
));
1035 emit_move_insn (ret
,
1036 gen_rtx_PLUS (Pmode
,
1038 THREAD_POINTER_REGNUM
),
1040 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1046 else if (GET_CODE (addr
) == CONST
)
1050 gcc_assert (GET_CODE (XEXP (addr
, 0)) == PLUS
);
1052 base
= tilegx_legitimize_tls_address (XEXP (XEXP (addr
, 0), 0));
1053 offset
= XEXP (XEXP (addr
, 0), 1);
1055 base
= force_operand (base
, NULL_RTX
);
1056 ret
= force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1065 /* Returns a register that points to ADDR, a symbolic address, by
1066 computing its address relative to tilegx_text_label_symbol. */
1068 tilegx_compute_pcrel_address (rtx result
, rtx addr
)
1070 rtx text_label_symbol
= tilegx_text_label_symbol ();
1071 rtx text_label_rtx
= tilegx_text_label_rtx ();
1072 rtx temp
, temp2
, temp3
;
1074 temp
= create_temp_reg_if_possible (Pmode
, result
);
1075 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1079 emit_insn (gen_mov_pcrel_step1_32bit (temp
, addr
, text_label_symbol
));
1080 emit_insn (gen_mov_pcrel_step2_32bit (temp2
, temp
, addr
,
1081 text_label_symbol
));
1082 emit_insn (gen_mov_pcrel_step3_32bit (result
, temp2
,
1084 addr
, text_label_symbol
));
1086 else if (tilegx_cmodel
== CM_LARGE_PIC
)
1088 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1089 emit_insn (gen_mov_large_pcrel_step1 (temp
, addr
, text_label_symbol
));
1090 emit_insn (gen_mov_large_pcrel_step2 (temp2
, temp
, addr
,
1091 text_label_symbol
));
1092 emit_insn (gen_mov_large_pcrel_step3 (temp3
, temp2
, addr
,
1093 text_label_symbol
));
1094 emit_insn (gen_mov_large_pcrel_step4 (result
, temp3
,
1096 addr
, text_label_symbol
));
1100 emit_insn (gen_mov_pcrel_step1 (temp
, addr
, text_label_symbol
));
1101 emit_insn (gen_mov_pcrel_step2 (temp2
, temp
, addr
, text_label_symbol
));
1102 emit_insn (gen_mov_pcrel_step3 (result
, temp2
,
1104 addr
, text_label_symbol
));
1109 /* Returns a register that points to the plt entry of ADDR, a symbolic
1110 address, by computing its address relative to
1111 tilegx_text_label_symbol. */
1113 tilegx_compute_pcrel_plt_address (rtx result
, rtx addr
)
1115 rtx text_label_symbol
= tilegx_text_label_symbol ();
1116 rtx text_label_rtx
= tilegx_text_label_rtx ();
1117 rtx temp
, temp2
, temp3
;
1119 temp
= create_temp_reg_if_possible (Pmode
, result
);
1120 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1124 emit_insn (gen_mov_plt_pcrel_step1_32bit (temp
, addr
,
1125 text_label_symbol
));
1126 emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2
, temp
, addr
,
1127 text_label_symbol
));
1128 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp2
, text_label_rtx
));
1132 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1134 emit_insn (gen_mov_plt_pcrel_step1 (temp
, addr
, text_label_symbol
));
1135 emit_insn (gen_mov_plt_pcrel_step2 (temp2
, temp
, addr
,
1136 text_label_symbol
));
1137 emit_insn (gen_mov_plt_pcrel_step3 (temp3
, temp2
, addr
,
1138 text_label_symbol
));
1139 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp3
, text_label_rtx
));
1144 /* Legitimize PIC addresses. If the address is already
1145 position-independent, we return ORIG. Newly generated
1146 position-independent addresses go into a reg. This is REG if
1147 nonzero, otherwise we allocate register(s) as necessary. */
1149 tilegx_legitimize_pic_address (rtx orig
,
1150 enum machine_mode mode ATTRIBUTE_UNUSED
,
1153 if (GET_CODE (orig
) == SYMBOL_REF
)
1155 rtx address
, pic_ref
;
1159 gcc_assert (can_create_pseudo_p ());
1160 reg
= gen_reg_rtx (Pmode
);
1163 if (SYMBOL_REF_LOCAL_P (orig
))
1165 /* If not during reload, allocate another temp reg here for
1166 loading in the address, so that these instructions can be
1167 optimized properly. */
1168 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1169 tilegx_compute_pcrel_address (temp_reg
, orig
);
1171 /* Note: this is conservative. We use the text_label but we
1172 don't use the pic_offset_table. However, in some cases
1173 we may need the pic_offset_table (see
1174 tilegx_fixup_pcrel_references). */
1175 crtl
->uses_pic_offset_table
= 1;
1179 emit_move_insn (reg
, address
);
1184 /* If not during reload, allocate another temp reg here for
1185 loading in the address, so that these instructions can be
1186 optimized properly. */
1187 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1189 gcc_assert (flag_pic
);
1194 emit_insn (gen_add_got16_32bit (temp_reg
,
1200 emit_insn (gen_add_got16 (temp_reg
,
1201 tilegx_got_rtx (), orig
));
1206 rtx temp_reg2
= create_temp_reg_if_possible (Pmode
, reg
);
1207 rtx temp_reg3
= create_temp_reg_if_possible (Pmode
, reg
);
1210 emit_insn (gen_mov_got32_step1_32bit (temp_reg3
, orig
));
1211 emit_insn (gen_mov_got32_step2_32bit
1212 (temp_reg2
, temp_reg3
, orig
));
1216 emit_insn (gen_mov_got32_step1 (temp_reg3
, orig
));
1217 emit_insn (gen_mov_got32_step2 (temp_reg2
, temp_reg3
,
1220 emit_move_insn (temp_reg
,
1221 gen_rtx_PLUS (Pmode
,
1222 tilegx_got_rtx (), temp_reg2
));
1227 pic_ref
= gen_const_mem (Pmode
, address
);
1228 crtl
->uses_pic_offset_table
= 1;
1229 emit_move_insn (reg
, pic_ref
);
1230 /* The following put a REG_EQUAL note on this insn, so that
1231 it can be optimized by loop. But it causes the label to
1232 be optimized away. */
1233 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1237 else if (GET_CODE (orig
) == CONST
)
1241 if (GET_CODE (XEXP (orig
, 0)) == PLUS
1242 && XEXP (XEXP (orig
, 0), 0) == tilegx_got_rtx ())
1247 gcc_assert (can_create_pseudo_p ());
1248 reg
= gen_reg_rtx (Pmode
);
1251 gcc_assert (GET_CODE (XEXP (orig
, 0)) == PLUS
);
1252 base
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 0),
1254 offset
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 1), Pmode
,
1255 base
== reg
? 0 : reg
);
1257 if (CONST_INT_P (offset
))
1259 if (can_create_pseudo_p ())
1260 offset
= force_reg (Pmode
, offset
);
1262 /* If we reach here, then something is seriously wrong. */
1266 if (can_create_pseudo_p ())
1267 return force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1271 else if (GET_CODE (orig
) == LABEL_REF
)
1278 gcc_assert (can_create_pseudo_p ());
1279 reg
= gen_reg_rtx (Pmode
);
1282 /* If not during reload, allocate another temp reg here for
1283 loading in the address, so that these instructions can be
1284 optimized properly. */
1285 temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1286 tilegx_compute_pcrel_address (temp_reg
, orig
);
1288 /* Note: this is conservative. We use the text_label but we
1289 don't use the pic_offset_table. */
1290 crtl
->uses_pic_offset_table
= 1;
1294 emit_move_insn (reg
, address
);
1303 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1305 tilegx_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
1306 enum machine_mode mode
)
1308 if (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
1309 && symbolic_operand (x
, Pmode
) && tilegx_tls_referenced_p (x
))
1311 return tilegx_legitimize_tls_address (x
);
1315 return tilegx_legitimize_pic_address (x
, mode
, 0);
1322 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1324 tilegx_delegitimize_address (rtx x
)
1326 x
= delegitimize_mem_from_attrs (x
);
1328 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == UNSPEC
)
1330 switch (XINT (XEXP (x
, 0), 1))
1336 case UNSPEC_HW0_LAST
:
1337 case UNSPEC_HW1_LAST
:
1338 case UNSPEC_HW2_LAST
:
1339 case UNSPEC_HW0_PCREL
:
1340 case UNSPEC_HW1_PCREL
:
1341 case UNSPEC_HW1_LAST_PCREL
:
1342 case UNSPEC_HW2_LAST_PCREL
:
1343 case UNSPEC_HW0_PLT_PCREL
:
1344 case UNSPEC_HW1_PLT_PCREL
:
1345 case UNSPEC_HW1_LAST_PLT_PCREL
:
1346 case UNSPEC_HW2_LAST_PLT_PCREL
:
1347 case UNSPEC_HW0_GOT
:
1348 case UNSPEC_HW0_LAST_GOT
:
1349 case UNSPEC_HW1_LAST_GOT
:
1350 case UNSPEC_HW0_TLS_GD
:
1351 case UNSPEC_HW1_LAST_TLS_GD
:
1352 case UNSPEC_HW0_TLS_IE
:
1353 case UNSPEC_HW1_LAST_TLS_IE
:
1354 case UNSPEC_HW0_TLS_LE
:
1355 case UNSPEC_HW1_LAST_TLS_LE
:
1356 x
= XVECEXP (XEXP (x
, 0), 0, 0);
1365 /* Emit code to load the PIC register. */
1367 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED
)
1369 int orig_flag_pic
= flag_pic
;
1371 rtx got_symbol
= tilegx_got_symbol ();
1372 rtx text_label_symbol
= tilegx_text_label_symbol ();
1373 rtx text_label_rtx
= tilegx_text_label_rtx ();
1378 emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx
,
1379 text_label_symbol
));
1383 emit_insn (gen_insn_lnk_and_label (text_label_rtx
, text_label_symbol
));
1386 tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol
);
1388 flag_pic
= orig_flag_pic
;
1390 /* Need to emit this whether or not we obey regdecls, since
1391 setjmp/longjmp can cause life info to screw up. ??? In the case
1392 where we don't obey regdecls, this is not sufficient since we may
1393 not fall out the bottom. */
1394 emit_use (tilegx_got_rtx ());
1398 /* Return the simd variant of the constant NUM of mode MODE, by
1399 replicating it to fill an interger of mode DImode. NUM is first
1400 truncated to fit in MODE. */
1402 tilegx_simd_int (rtx num
, enum machine_mode mode
)
1404 HOST_WIDE_INT n
= 0;
1406 gcc_assert (CONST_INT_P (num
));
1413 n
= 0x0101010101010101LL
* (n
& 0x000000FF);
1416 n
= 0x0001000100010001LL
* (n
& 0x0000FFFF);
1419 n
= 0x0000000100000001LL
* (n
& 0xFFFFFFFF);
1431 /* Returns true iff VAL can be moved into a register in one
1432 instruction. And if it can, it emits the code to move the constant
1435 If THREE_WIDE_ONLY is true, this insists on an instruction that
1436 works in a bundle containing three instructions. */
1438 expand_set_cint64_one_inst (rtx dest_reg
,
1439 HOST_WIDE_INT val
, bool three_wide_only
)
1441 if (val
== trunc_int_for_mode (val
, QImode
))
1444 emit_move_insn (dest_reg
, GEN_INT (val
));
1447 else if (!three_wide_only
)
1449 /* Test for the following constraints: J, K, N, P. We avoid
1450 generating an rtx and using existing predicates because we
1451 can be testing and rejecting a lot of constants, and GEN_INT
1453 if ((val
>= -32768 && val
<= 65535)
1454 || ((val
== (val
& 0xFF) * 0x0101010101010101LL
))
1455 || (val
== ((trunc_int_for_mode (val
, QImode
) & 0xFFFF)
1456 * 0x0001000100010001LL
)))
1458 emit_move_insn (dest_reg
, GEN_INT (val
));
1467 /* Implement DImode rotatert. */
1468 static HOST_WIDE_INT
1469 rotate_right (HOST_WIDE_INT n
, int count
)
1471 unsigned HOST_WIDE_INT x
= n
& 0xFFFFFFFFFFFFFFFFULL
;
1474 return ((x
>> count
) | (x
<< (64 - count
))) & 0xFFFFFFFFFFFFFFFFULL
;
1478 /* Return true iff n contains exactly one contiguous sequence of 1
1479 bits, possibly wrapping around from high bits to low bits. */
1481 tilegx_bitfield_operand_p (HOST_WIDE_INT n
, int *first_bit
, int *last_bit
)
1488 for (i
= 0; i
< 64; i
++)
1490 unsigned HOST_WIDE_INT x
= rotate_right (n
, i
);
1494 /* See if x is a power of two minus one, i.e. only consecutive 1
1495 bits starting from bit 0. */
1496 if ((x
& (x
+ 1)) == 0)
1498 if (first_bit
!= NULL
)
1500 if (last_bit
!= NULL
)
1501 *last_bit
= (i
+ exact_log2 (x
^ (x
>> 1))) & 63;
1511 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1513 expand_set_cint64 (rtx dest_reg
, rtx src_val
)
1516 int leading_zeroes
, trailing_zeroes
;
1517 int three_wide_only
;
1518 int shift
, ins_shift
, zero_cluster_shift
;
1521 gcc_assert (CONST_INT_P (src_val
));
1522 val
= trunc_int_for_mode (INTVAL (src_val
), GET_MODE (dest_reg
));
1524 /* See if we can generate the constant in one instruction. */
1525 if (expand_set_cint64_one_inst (dest_reg
, val
, false))
1528 /* Force the destination to DImode so we can use DImode instructions
1529 to create it. This both allows instructions like rotl, and
1530 certain efficient 3-wide instructions. */
1531 subreg
= simplify_gen_subreg (DImode
, dest_reg
, GET_MODE (dest_reg
), 0);
1532 gcc_assert (subreg
!= NULL
);
1535 temp
= create_temp_reg_if_possible (DImode
, dest_reg
);
1537 leading_zeroes
= 63 - floor_log2 (val
& 0xFFFFFFFFFFFFFFFFULL
);
1538 trailing_zeroes
= exact_log2 (val
& -val
);
1540 /* First try all three-wide instructions that generate a constant
1541 (i.e. movei) followed by various shifts and rotates. If none of
1542 those work, try various two-wide ways of generating a constant
1543 followed by various shifts and rotates. */
1544 for (three_wide_only
= 1; three_wide_only
>= 0; three_wide_only
--)
1548 if (expand_set_cint64_one_inst (temp
, val
>> trailing_zeroes
,
1551 /* 0xFFFFFFFFFFFFA500 becomes:
1552 movei temp, 0xFFFFFFFFFFFFFFA5
1553 shli dest, temp, 8 */
1554 emit_move_insn (dest_reg
,
1555 gen_rtx_ASHIFT (DImode
, temp
,
1556 GEN_INT (trailing_zeroes
)));
1560 if (expand_set_cint64_one_inst (temp
, val
<< leading_zeroes
,
1563 /* 0x7FFFFFFFFFFFFFFF becomes:
1565 shrui dest, temp, 1 */
1566 emit_move_insn (dest_reg
,
1567 gen_rtx_LSHIFTRT (DImode
, temp
,
1568 GEN_INT (leading_zeroes
)));
1572 /* Try rotating a one-instruction immediate. */
1573 for (count
= 1; count
< 64; count
++)
1575 HOST_WIDE_INT r
= rotate_right (val
, count
);
1576 if (expand_set_cint64_one_inst (temp
, r
, three_wide_only
))
1578 /* 0xFFFFFFFFFFA5FFFF becomes:
1579 movei temp, 0xFFFFFFFFFFFFFFA5
1580 rotli dest, temp, 16 */
1581 emit_move_insn (dest_reg
,
1582 gen_rtx_ROTATE (DImode
, temp
, GEN_INT (count
)));
1588 /* There are two cases here to produce a large constant.
1589 In the most general case, we do this:
1592 shl16insli x, x, hw2(NUM)
1593 shl16insli x, x, hw1(NUM)
1594 shl16insli x, x, hw0(NUM)
1596 However, we can sometimes do better. shl16insli is a poor way to
1597 insert 16 zero bits, because simply shifting left by 16 has more
1598 bundling freedom. So if we see any contiguous aligned sequence
1599 of 16 or more zero bits (below the highest set bit), it is always
1600 more efficient to materialize the bits above the zero bits, then
1601 left shift to put in the zeroes, then insert whatever bits
1602 remain. For example, we might end up with:
1604 movei x, NUM >> (37 + 16)
1606 shl16insli x, x, hw0(NUM) */
1608 zero_cluster_shift
= -1;
1610 for (shift
= 0; shift
< 48 - leading_zeroes
; shift
+= 16)
1612 HOST_WIDE_INT x
= val
>> shift
;
1614 /* Find the least significant group of 16 aligned zero bits. */
1615 if ((x
& 0xFFFF) == 0x0000)
1617 /* Grab any following zero bits as well. */
1618 zero_cluster_shift
= exact_log2 (x
& -x
);
1619 shift
+= zero_cluster_shift
;
1624 if (zero_cluster_shift
>= 0)
1626 unsigned HOST_WIDE_INT leftover
;
1628 /* Recursively create the constant above the lowest 16 zero
1630 expand_set_cint64 (temp
, GEN_INT (val
>> shift
));
1632 /* See if we can easily insert the remaining bits, or if we need
1633 to fall through to the more general case. */
1634 leftover
= val
- ((val
>> shift
) << shift
);
1637 /* A simple left shift is enough. */
1638 emit_move_insn (dest_reg
,
1639 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1642 else if (leftover
<= 32767)
1644 /* Left shift into position then add in the leftover. */
1645 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1646 emit_move_insn (temp2
,
1647 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1648 emit_move_insn (dest_reg
,
1649 gen_rtx_PLUS (DImode
, temp2
, GEN_INT (leftover
)));
1654 /* Shift in the batch of >= 16 zeroes we detected earlier.
1655 After this, shift will be aligned mod 16 so the final
1656 loop can use shl16insli. */
1657 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1658 rtx shift_count_rtx
= GEN_INT (zero_cluster_shift
);
1660 emit_move_insn (temp2
,
1661 gen_rtx_ASHIFT (DImode
, temp
, shift_count_rtx
));
1663 shift
-= zero_cluster_shift
;
1669 /* Set as many high 16-bit blocks as we can with a single
1670 instruction. We'll insert the remaining 16-bit blocks
1672 for (shift
= 16;; shift
+= 16)
1674 gcc_assert (shift
< 64);
1675 if (expand_set_cint64_one_inst (temp
, val
>> shift
, false))
1680 /* At this point, temp == val >> shift, shift % 16 == 0, and we
1681 still need to insert any bits of 'val' below 'shift'. Those bits
1682 are guaranteed to not have 16 contiguous zeroes. */
1684 gcc_assert ((shift
& 15) == 0);
1686 for (ins_shift
= shift
- 16; ins_shift
>= 0; ins_shift
-= 16)
1689 HOST_WIDE_INT bits
= (val
>> ins_shift
) & 0xFFFF;
1690 gcc_assert (bits
!= 0);
1692 /* On the last iteration we need to store into dest_reg. */
1696 result
= create_temp_reg_if_possible (DImode
, dest_reg
);
1698 emit_insn (gen_insn_shl16insli (result
, temp
, GEN_INT (bits
)));
1705 /* Load OP1, a 64-bit constant, into OP0, a register. We know it
1706 can't be done in one insn when we get here, the move expander
1709 tilegx_expand_set_const64 (rtx op0
, rtx op1
)
1711 if (CONST_INT_P (op1
))
1713 /* TODO: I don't know if we want to split large constants
1714 now, or wait until later (with a define_split).
1716 Does splitting early help CSE? Does it harm other
1717 optimizations that might fold loads? */
1718 expand_set_cint64 (op0
, op1
);
1722 rtx temp
= create_temp_reg_if_possible (Pmode
, op0
);
1726 /* Generate the 2-insn sequence to materialize a symbolic
1728 emit_insn (gen_mov_address_32bit_step1 (temp
, op1
));
1729 emit_insn (gen_mov_address_32bit_step2 (op0
, temp
, op1
));
1733 /* Generate the 3-insn sequence to materialize a symbolic
1734 address. Note that this assumes that virtual addresses
1735 fit in 48 signed bits, which is currently true. */
1736 rtx temp2
= create_temp_reg_if_possible (Pmode
, op0
);
1737 emit_insn (gen_mov_address_step1 (temp
, op1
));
1738 emit_insn (gen_mov_address_step2 (temp2
, temp
, op1
));
1739 emit_insn (gen_mov_address_step3 (op0
, temp2
, op1
));
1745 /* Expand a move instruction. Return true if all work is done. */
1747 tilegx_expand_mov (enum machine_mode mode
, rtx
*operands
)
1749 /* Handle sets of MEM first. */
1750 if (MEM_P (operands
[0]))
1752 if (can_create_pseudo_p ())
1753 operands
[0] = validize_mem (operands
[0]);
1755 if (reg_or_0_operand (operands
[1], mode
))
1758 if (!reload_in_progress
)
1759 operands
[1] = force_reg (mode
, operands
[1]);
1762 /* Fixup TLS cases. */
1763 if (CONSTANT_P (operands
[1]) && tilegx_tls_referenced_p (operands
[1]))
1765 operands
[1] = tilegx_legitimize_tls_address (operands
[1]);
1769 /* Fixup PIC cases. */
1770 if (flag_pic
&& CONSTANT_P (operands
[1]))
1772 if (tilegx_pic_address_needs_scratch (operands
[1]))
1773 operands
[1] = tilegx_legitimize_pic_address (operands
[1], mode
, 0);
1775 if (symbolic_operand (operands
[1], mode
))
1777 operands
[1] = tilegx_legitimize_pic_address (operands
[1],
1779 (reload_in_progress
?
1786 /* Accept non-constants and valid constants unmodified. */
1787 if (!CONSTANT_P (operands
[1]) || move_operand (operands
[1], mode
))
1790 /* Split large integers. */
1791 tilegx_expand_set_const64 (operands
[0], operands
[1]);
1796 /* Expand unaligned loads. */
1798 tilegx_expand_unaligned_load (rtx dest_reg
, rtx mem
, HOST_WIDE_INT bitsize
,
1799 HOST_WIDE_INT bit_offset
, bool sign
)
1801 enum machine_mode mode
;
1802 rtx addr_lo
, addr_hi
;
1803 rtx mem_lo
, mem_hi
, hi
;
1804 rtx mema
, wide_result
;
1805 int last_byte_offset
;
1806 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1808 mode
= GET_MODE (dest_reg
);
1810 hi
= gen_reg_rtx (mode
);
1812 if (bitsize
== 2 * BITS_PER_UNIT
&& (bit_offset
% BITS_PER_UNIT
) == 0)
1814 /* When just loading a two byte value, we can load the two bytes
1815 individually and combine them efficiently. */
1817 mem_lo
= adjust_address (mem
, QImode
, byte_offset
);
1818 mem_hi
= adjust_address (mem
, QImode
, byte_offset
+ 1);
1822 /* Do a signed load of the second byte and use bfins to set
1823 the high bits of the result. */
1824 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, dest_reg
),
1826 emit_insn (gen_extendqidi2 (gen_lowpart (DImode
, hi
), mem_hi
));
1827 emit_insn (gen_insv (gen_lowpart (DImode
, dest_reg
),
1828 GEN_INT (64 - 8), GEN_INT (8),
1829 gen_lowpart (DImode
, hi
)));
1833 /* Do two unsigned loads and use v1int_l to interleave
1835 rtx lo
= gen_reg_rtx (mode
);
1836 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, lo
),
1838 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, hi
),
1840 emit_insn (gen_insn_v1int_l (gen_lowpart (DImode
, dest_reg
),
1841 gen_lowpart (DImode
, hi
),
1842 gen_lowpart (DImode
, lo
)));
1848 mema
= XEXP (mem
, 0);
1850 /* AND addresses cannot be in any alias set, since they may
1851 implicitly alias surrounding code. Ideally we'd have some alias
1852 set that covered all types except those with alignment 8 or
1854 addr_lo
= force_reg (Pmode
, plus_constant (Pmode
, mema
, byte_offset
));
1855 mem_lo
= change_address (mem
, mode
,
1856 gen_rtx_AND (GET_MODE (mema
), addr_lo
,
1858 set_mem_alias_set (mem_lo
, 0);
1860 /* Load the high word at an address that will not fault if the low
1861 address is aligned and at the very end of a page. */
1862 last_byte_offset
= (bit_offset
+ bitsize
- 1) / BITS_PER_UNIT
;
1863 addr_hi
= force_reg (Pmode
, plus_constant (Pmode
, mema
, last_byte_offset
));
1864 mem_hi
= change_address (mem
, mode
,
1865 gen_rtx_AND (GET_MODE (mema
), addr_hi
,
1867 set_mem_alias_set (mem_hi
, 0);
1871 addr_lo
= make_safe_from (addr_lo
, dest_reg
);
1872 wide_result
= dest_reg
;
1876 wide_result
= gen_reg_rtx (mode
);
1879 /* Load hi first in case dest_reg is used in mema. */
1880 emit_move_insn (hi
, mem_hi
);
1881 emit_move_insn (wide_result
, mem_lo
);
1883 emit_insn (gen_insn_dblalign (gen_lowpart (DImode
, wide_result
),
1884 gen_lowpart (DImode
, wide_result
),
1885 gen_lowpart (DImode
, hi
), addr_lo
));
1890 extract_bit_field (gen_lowpart (DImode
, wide_result
),
1891 bitsize
, bit_offset
% BITS_PER_UNIT
,
1892 !sign
, gen_lowpart (DImode
, dest_reg
),
1895 if (extracted
!= dest_reg
)
1896 emit_move_insn (dest_reg
, gen_lowpart (DImode
, extracted
));
1901 /* Expand unaligned stores. */
1903 tilegx_expand_unaligned_store (rtx mem
, rtx src
, HOST_WIDE_INT bitsize
,
1904 HOST_WIDE_INT bit_offset
)
1906 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1907 HOST_WIDE_INT bytesize
= bitsize
/ BITS_PER_UNIT
;
1908 HOST_WIDE_INT shift_amt
;
1913 for (i
= 0, shift_amt
= 0; i
< bytesize
; i
++, shift_amt
+= BITS_PER_UNIT
)
1915 mem_addr
= adjust_address (mem
, QImode
, byte_offset
+ i
);
1919 store_val
= expand_simple_binop (DImode
, LSHIFTRT
,
1920 gen_lowpart (DImode
, src
),
1921 GEN_INT (shift_amt
), NULL
, 1,
1923 store_val
= gen_lowpart (QImode
, store_val
);
1927 store_val
= gen_lowpart (QImode
, src
);
1930 emit_move_insn (mem_addr
, store_val
);
1935 /* Implement the movmisalign patterns. One of the operands is a
1936 memory that is not naturally aligned. Emit instructions to load
1939 tilegx_expand_movmisalign (enum machine_mode mode
, rtx
*operands
)
1941 if (MEM_P (operands
[1]))
1945 if (register_operand (operands
[0], mode
))
1948 tmp
= gen_reg_rtx (mode
);
1950 tilegx_expand_unaligned_load (tmp
, operands
[1], GET_MODE_BITSIZE (mode
),
1953 if (tmp
!= operands
[0])
1954 emit_move_insn (operands
[0], tmp
);
1956 else if (MEM_P (operands
[0]))
1958 if (!reg_or_0_operand (operands
[1], mode
))
1959 operands
[1] = force_reg (mode
, operands
[1]);
1961 tilegx_expand_unaligned_store (operands
[0], operands
[1],
1962 GET_MODE_BITSIZE (mode
), 0);
1970 /* Implement the allocate_stack pattern (alloca). */
1972 tilegx_allocate_stack (rtx op0
, rtx op1
)
1974 /* Technically the correct way to initialize chain_loc is with
1975 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
1976 * sets the alias_set to that of a frame reference. Some of our
1977 * tests rely on some unsafe assumption about when the chaining
1978 * update is done, we need to be conservative about reordering the
1979 * chaining instructions.
1981 rtx fp_addr
= gen_reg_rtx (Pmode
);
1982 rtx fp_value
= gen_reg_rtx (Pmode
);
1985 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
1986 GEN_INT (UNITS_PER_WORD
)));
1988 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
1990 emit_move_insn (fp_value
, fp_loc
);
1992 op1
= force_reg (Pmode
, op1
);
1994 emit_move_insn (stack_pointer_rtx
,
1995 gen_rtx_MINUS (Pmode
, stack_pointer_rtx
, op1
));
1997 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
1998 GEN_INT (UNITS_PER_WORD
)));
2000 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
2002 emit_move_insn (fp_loc
, fp_value
);
2004 emit_move_insn (op0
, virtual_stack_dynamic_rtx
);
2012 /* Returns the insn_code in ENTRY. */
2013 static enum insn_code
2014 tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry
2017 return tilegx_multiply_insn_seq_decode_opcode
[entry
->compressed_opcode
];
2021 /* Returns the length of the 'op' array. */
2023 tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq
*seq
)
2025 /* The array either uses all of its allocated slots or is terminated
2026 by a bogus opcode. Either way, the array size is the index of the
2027 last valid opcode plus one. */
2029 for (i
= tilegx_multiply_insn_seq_MAX_OPERATIONS
- 1; i
>= 0; i
--)
2030 if (tilegx_multiply_get_opcode (&seq
->op
[i
]) != CODE_FOR_nothing
)
2033 /* An empty array is not allowed. */
2038 /* We precompute a number of expression trees for multiplying by
2039 constants. This generates code for such an expression tree by
2040 walking through the nodes in the tree (which are conveniently
2041 pre-linearized) and emitting an instruction for each one. */
2043 tilegx_expand_constant_multiply_given_sequence (rtx result
, rtx src
,
2045 tilegx_multiply_insn_seq
*seq
)
2050 /* Keep track of the subexpressions computed so far, so later
2051 instructions can refer to them. We seed the array with zero and
2052 the value being multiplied. */
2053 int num_subexprs
= 2;
2054 rtx subexprs
[tilegx_multiply_insn_seq_MAX_OPERATIONS
+ 2];
2055 subexprs
[0] = const0_rtx
;
2058 /* Determine how many instructions we are going to generate. */
2059 num_ops
= tilegx_multiply_get_num_ops (seq
);
2060 gcc_assert (num_ops
> 0
2061 && num_ops
<= tilegx_multiply_insn_seq_MAX_OPERATIONS
);
2063 for (i
= 0; i
< num_ops
; i
++)
2065 const struct tilegx_multiply_insn_seq_entry
*entry
= &seq
->op
[i
];
2067 /* Figure out where to store the output of this instruction. */
2068 const bool is_last_op
= (i
+ 1 == num_ops
);
2069 rtx out
= is_last_op
? result
: gen_reg_rtx (DImode
);
2071 enum insn_code opcode
= tilegx_multiply_get_opcode (entry
);
2072 if (opcode
== CODE_FOR_ashldi3
)
2074 /* Handle shift by immediate. This is a special case because
2075 the meaning of the second operand is a constant shift
2076 count rather than an operand index. */
2078 /* Make sure the shift count is in range. Zero should not
2080 const int shift_count
= entry
->rhs
;
2081 gcc_assert (shift_count
> 0 && shift_count
< 64);
2083 /* Emit the actual instruction. */
2084 emit_insn (GEN_FCN (opcode
)
2085 (out
, subexprs
[entry
->lhs
],
2086 gen_rtx_CONST_INT (DImode
, shift_count
)));
2090 /* Handle a normal two-operand instruction, such as add or
2093 /* Make sure we are referring to a previously computed
2095 gcc_assert (entry
->rhs
< num_subexprs
);
2097 /* Emit the actual instruction. */
2098 emit_insn (GEN_FCN (opcode
)
2099 (out
, subexprs
[entry
->lhs
], subexprs
[entry
->rhs
]));
2102 /* Record this subexpression for use by later expressions. */
2103 subexprs
[num_subexprs
++] = out
;
2108 /* bsearch helper function. */
2110 tilegx_compare_multipliers (const void *key
, const void *t
)
2113 (*(const long long *) key
2114 - ((const struct tilegx_multiply_insn_seq
*) t
)->multiplier
);
2115 return (delta
< 0) ? -1 : (delta
> 0);
2119 /* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none
2121 static const struct tilegx_multiply_insn_seq
*
2122 tilegx_find_multiply_insn_seq_for_constant (long long multiplier
)
2124 return ((const struct tilegx_multiply_insn_seq
*)
2125 bsearch (&multiplier
, tilegx_multiply_insn_seq_table
,
2126 tilegx_multiply_insn_seq_table_size
,
2127 sizeof tilegx_multiply_insn_seq_table
[0],
2128 tilegx_compare_multipliers
));
2132 /* Try to a expand constant multiply in DImode by looking it up in a
2133 precompiled table. OP0 is the result operand, OP1 is the source
2134 operand, and MULTIPLIER is the value of the constant. Return true
2137 tilegx_expand_const_muldi (rtx op0
, rtx op1
, long long multiplier
)
2139 /* See if we have precomputed an efficient way to multiply by this
2141 const struct tilegx_multiply_insn_seq
*seq
=
2142 tilegx_find_multiply_insn_seq_for_constant (multiplier
);
2145 tilegx_expand_constant_multiply_given_sequence (op0
, op1
, seq
);
2153 /* Expand the muldi pattern. */
2155 tilegx_expand_muldi (rtx op0
, rtx op1
, rtx op2
)
2157 if (CONST_INT_P (op2
))
2159 HOST_WIDE_INT n
= trunc_int_for_mode (INTVAL (op2
), DImode
);
2160 return tilegx_expand_const_muldi (op0
, op1
, n
);
2166 /* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the
2167 operands, and SIGN is true if it's a signed multiply, and false if
2168 it's an unsigned multiply. */
2170 tilegx_expand_high_multiply (rtx result
, rtx op1
, rtx op2
, bool sign
)
2172 rtx tmp0
= gen_reg_rtx (DImode
);
2173 rtx tmp1
= gen_reg_rtx (DImode
);
2174 rtx tmp2
= gen_reg_rtx (DImode
);
2175 rtx tmp3
= gen_reg_rtx (DImode
);
2176 rtx tmp4
= gen_reg_rtx (DImode
);
2177 rtx tmp5
= gen_reg_rtx (DImode
);
2178 rtx tmp6
= gen_reg_rtx (DImode
);
2179 rtx tmp7
= gen_reg_rtx (DImode
);
2180 rtx tmp8
= gen_reg_rtx (DImode
);
2181 rtx tmp9
= gen_reg_rtx (DImode
);
2182 rtx tmp10
= gen_reg_rtx (DImode
);
2183 rtx tmp11
= gen_reg_rtx (DImode
);
2184 rtx tmp12
= gen_reg_rtx (DImode
);
2185 rtx tmp13
= gen_reg_rtx (DImode
);
2186 rtx result_lo
= gen_reg_rtx (DImode
);
2190 emit_insn (gen_insn_mul_hs_lu (tmp0
, op1
, op2
));
2191 emit_insn (gen_insn_mul_hs_lu (tmp1
, op2
, op1
));
2192 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2193 emit_insn (gen_insn_mul_hs_hs (tmp3
, op1
, op2
));
2197 emit_insn (gen_insn_mul_hu_lu (tmp0
, op1
, op2
));
2198 emit_insn (gen_insn_mul_hu_lu (tmp1
, op2
, op1
));
2199 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2200 emit_insn (gen_insn_mul_hu_hu (tmp3
, op1
, op2
));
2203 emit_move_insn (tmp4
, (gen_rtx_ASHIFT (DImode
, tmp0
, GEN_INT (32))));
2205 emit_move_insn (tmp5
, (gen_rtx_ASHIFT (DImode
, tmp1
, GEN_INT (32))));
2207 emit_move_insn (tmp6
, (gen_rtx_PLUS (DImode
, tmp4
, tmp5
)));
2208 emit_move_insn (result_lo
, (gen_rtx_PLUS (DImode
, tmp2
, tmp6
)));
2210 emit_move_insn (tmp7
, gen_rtx_LTU (DImode
, tmp6
, tmp4
));
2211 emit_move_insn (tmp8
, gen_rtx_LTU (DImode
, result_lo
, tmp2
));
2215 emit_move_insn (tmp9
, (gen_rtx_ASHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2216 emit_move_insn (tmp10
, (gen_rtx_ASHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2220 emit_move_insn (tmp9
, (gen_rtx_LSHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2221 emit_move_insn (tmp10
, (gen_rtx_LSHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2224 emit_move_insn (tmp11
, (gen_rtx_PLUS (DImode
, tmp3
, tmp7
)));
2225 emit_move_insn (tmp12
, (gen_rtx_PLUS (DImode
, tmp8
, tmp9
)));
2226 emit_move_insn (tmp13
, (gen_rtx_PLUS (DImode
, tmp11
, tmp12
)));
2227 emit_move_insn (result
, (gen_rtx_PLUS (DImode
, tmp13
, tmp10
)));
2231 /* Implement smuldi3_highpart. */
2233 tilegx_expand_smuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2235 tilegx_expand_high_multiply (op0
, op1
, op2
, true);
2239 /* Implement umuldi3_highpart. */
2241 tilegx_expand_umuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2243 tilegx_expand_high_multiply (op0
, op1
, op2
, false);
2248 /* Compare and branches */
2250 /* Produce the rtx yielding a bool for a floating point
2253 tilegx_emit_fp_setcc (rtx res
, enum rtx_code code
, enum machine_mode mode
,
2256 /* TODO: Certain compares again constants can be done using entirely
2257 integer operations. But you have to get the special cases right
2258 e.g. NaN, +0 == -0, etc. */
2262 rtx a
= force_reg (DImode
, gen_lowpart (DImode
, op0
));
2263 rtx b
= force_reg (DImode
, gen_lowpart (DImode
, op1
));
2265 flags
= gen_reg_rtx (DImode
);
2269 emit_insn (gen_insn_fsingle_add1 (flags
, a
, b
));
2273 gcc_assert (mode
== DFmode
);
2274 emit_insn (gen_insn_fdouble_add_flags (flags
, a
, b
));
2279 case EQ
: flag_index
= 30; break;
2280 case NE
: flag_index
= 31; break;
2281 case LE
: flag_index
= 27; break;
2282 case LT
: flag_index
= 26; break;
2283 case GE
: flag_index
= 29; break;
2284 case GT
: flag_index
= 28; break;
2285 default: gcc_unreachable ();
2288 gcc_assert (GET_MODE (res
) == DImode
);
2289 emit_move_insn (res
, gen_rtx_ZERO_EXTRACT (DImode
, flags
, GEN_INT (1),
2290 GEN_INT (flag_index
)));
2295 /* Certain simplifications can be done to make invalid setcc
2296 operations valid. Return the final comparison, or NULL if we can't
2299 tilegx_emit_setcc_internal (rtx res
, enum rtx_code code
, rtx op0
, rtx op1
,
2300 enum machine_mode cmp_mode
)
2305 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2306 return tilegx_emit_fp_setcc (res
, code
, cmp_mode
, op0
, op1
);
2308 /* The general case: fold the comparison code to the types of
2309 compares that we have, choosing the branch as necessary. */
2319 /* We have these compares. */
2326 /* We do not have these compares, so we reverse the
2332 /* We should not have called this with any other code. */
2338 code
= swap_condition (code
);
2339 tmp
= op0
, op0
= op1
, op1
= tmp
;
2342 if (!reg_or_0_operand (op0
, cmp_mode
))
2343 op0
= force_reg (cmp_mode
, op0
);
2345 if (!CONST_INT_P (op1
) && !register_operand (op1
, cmp_mode
))
2346 op1
= force_reg (cmp_mode
, op1
);
2348 /* Return the setcc comparison. */
2349 emit_insn (gen_rtx_SET (VOIDmode
, res
,
2350 gen_rtx_fmt_ee (code
, DImode
, op0
, op1
)));
2356 /* Implement cstore patterns. */
2358 tilegx_emit_setcc (rtx operands
[], enum machine_mode cmp_mode
)
2361 tilegx_emit_setcc_internal (operands
[0], GET_CODE (operands
[1]),
2362 operands
[2], operands
[3], cmp_mode
);
2366 /* Return whether CODE is a signed comparison. */
2368 signed_compare_p (enum rtx_code code
)
2370 return (code
== EQ
|| code
== NE
|| code
== LT
|| code
== LE
2371 || code
== GT
|| code
== GE
);
2375 /* Generate the comparison for a DImode conditional branch. */
2377 tilegx_emit_cc_test (enum rtx_code code
, rtx op0
, rtx op1
,
2378 enum machine_mode cmp_mode
, bool eq_ne_only
)
2380 enum rtx_code branch_code
;
2383 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2385 /* Compute a boolean saying whether the comparison is true. */
2386 temp
= gen_reg_rtx (DImode
);
2387 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2389 /* Test that flag. */
2390 return gen_rtx_fmt_ee (NE
, VOIDmode
, temp
, const0_rtx
);
2393 /* Check for a compare against zero using a comparison we can do
2395 if (op1
== const0_rtx
2396 && (code
== EQ
|| code
== NE
2397 || (!eq_ne_only
&& signed_compare_p (code
))))
2399 op0
= force_reg (cmp_mode
, op0
);
2400 return gen_rtx_fmt_ee (code
, VOIDmode
, op0
, const0_rtx
);
2403 /* The general case: fold the comparison code to the types of
2404 compares that we have, choosing the branch as necessary. */
2412 /* We have these compares. */
2421 /* These must be reversed (except NE, but let's
2423 code
= reverse_condition (code
);
2431 if (CONST_INT_P (op1
) && (!satisfies_constraint_I (op1
) || code
== LEU
))
2433 HOST_WIDE_INT n
= INTVAL (op1
);
2438 /* Subtract off the value we want to compare against and see
2439 if we get zero. This is cheaper than creating a constant
2440 in a register. Except that subtracting -128 is more
2441 expensive than seqi to -128, so we leave that alone. */
2442 /* ??? Don't do this when comparing against symbols,
2443 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2444 0), which will be declared false out of hand (at least
2447 && add_operand (GEN_INT (-n
), DImode
)
2448 && !(symbolic_operand (op0
, VOIDmode
)
2449 || (REG_P (op0
) && REG_POINTER (op0
))))
2451 /* TODO: Use a SIMD add immediate to hit zero for tiled
2452 constants in a single instruction. */
2453 if (GET_MODE (op0
) != DImode
)
2455 /* Convert to DImode so we can use addli. Note that
2456 this will not actually generate any code because
2457 sign extension from SI -> DI is a no-op. I don't
2458 know if it's safe just to make a paradoxical
2459 subreg here though. */
2460 rtx temp2
= gen_reg_rtx (DImode
);
2461 emit_insn (gen_extendsidi2 (temp2
, op0
));
2466 op0
= force_reg (DImode
, op0
);
2468 temp
= gen_reg_rtx (DImode
);
2469 emit_move_insn (temp
, gen_rtx_PLUS (DImode
, op0
, GEN_INT (-n
)));
2470 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2471 VOIDmode
, temp
, const0_rtx
);
2481 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2482 We use arithmetic shift right because it's a 3-wide op,
2483 while logical shift right is not. */
2485 int first
= exact_log2 (code
== LTU
? n
: n
+ 1);
2488 op0
= force_reg (cmp_mode
, op0
);
2489 temp
= gen_reg_rtx (cmp_mode
);
2490 emit_move_insn (temp
,
2491 gen_rtx_ASHIFTRT (cmp_mode
, op0
,
2493 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2494 VOIDmode
, temp
, const0_rtx
);
2504 /* Compute a flag saying whether we should branch. */
2505 temp
= gen_reg_rtx (DImode
);
2506 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2508 /* Return the branch comparison. */
2509 return gen_rtx_fmt_ee (branch_code
, VOIDmode
, temp
, const0_rtx
);
2513 /* Generate the comparison for a conditional branch. */
2515 tilegx_emit_conditional_branch (rtx operands
[], enum machine_mode cmp_mode
)
2518 tilegx_emit_cc_test (GET_CODE (operands
[0]), operands
[1], operands
[2],
2520 rtx branch_rtx
= gen_rtx_SET (VOIDmode
, pc_rtx
,
2521 gen_rtx_IF_THEN_ELSE (VOIDmode
, cmp_rtx
,
2526 emit_jump_insn (branch_rtx
);
2530 /* Implement the mov<mode>cc pattern. */
2532 tilegx_emit_conditional_move (rtx cmp
)
2535 tilegx_emit_cc_test (GET_CODE (cmp
), XEXP (cmp
, 0), XEXP (cmp
, 1),
2536 GET_MODE (XEXP (cmp
, 0)), true);
2540 /* Return true if INSN is annotated with a REG_BR_PROB note that
2541 indicates it's a branch that's predicted taken. */
2543 cbranch_predicted_p (rtx insn
)
2545 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2549 int pred_val
= XINT (x
, 0);
2551 return pred_val
>= REG_BR_PROB_BASE
/ 2;
2558 /* Output assembly code for a specific branch instruction, appending
2559 the branch prediction flag to the opcode if appropriate. */
2561 tilegx_output_simple_cbranch_with_opcode (rtx insn
, const char *opcode
,
2562 int regop
, bool reverse_predicted
)
2564 static char buf
[64];
2565 sprintf (buf
, "%s%s\t%%r%d, %%l0", opcode
,
2566 (cbranch_predicted_p (insn
) ^ reverse_predicted
) ? "t" : "",
2572 /* Output assembly code for a specific branch instruction, appending
2573 the branch prediction flag to the opcode if appropriate. */
2575 tilegx_output_cbranch_with_opcode (rtx insn
, rtx
*operands
,
2577 const char *rev_opcode
, int regop
)
2579 const char *branch_if_false
;
2580 rtx taken
, not_taken
;
2581 bool is_simple_branch
;
2583 gcc_assert (LABEL_P (operands
[0]));
2585 is_simple_branch
= true;
2586 if (INSN_ADDRESSES_SET_P ())
2588 int from_addr
= INSN_ADDRESSES (INSN_UID (insn
));
2589 int to_addr
= INSN_ADDRESSES (INSN_UID (operands
[0]));
2590 int delta
= to_addr
- from_addr
;
2591 is_simple_branch
= IN_RANGE (delta
, -524288, 524280);
2594 if (is_simple_branch
)
2596 /* Just a simple conditional branch. */
2598 tilegx_output_simple_cbranch_with_opcode (insn
, opcode
, regop
, false);
2601 /* Generate a reversed branch around a direct jump. This fallback
2602 does not use branch-likely instructions. */
2603 not_taken
= gen_label_rtx ();
2604 taken
= operands
[0];
2606 /* Generate the reversed branch to NOT_TAKEN. */
2607 operands
[0] = not_taken
;
2609 tilegx_output_simple_cbranch_with_opcode (insn
, rev_opcode
, regop
, true);
2610 output_asm_insn (branch_if_false
, operands
);
2612 output_asm_insn ("j\t%l0", &taken
);
2614 /* Output NOT_TAKEN. */
2615 targetm
.asm_out
.internal_label (asm_out_file
, "L",
2616 CODE_LABEL_NUMBER (not_taken
));
2621 /* Output assembly code for a conditional branch instruction. */
2623 tilegx_output_cbranch (rtx insn
, rtx
*operands
, bool reversed
)
2625 enum rtx_code code
= GET_CODE (operands
[1]);
2627 const char *rev_opcode
;
2630 code
= reverse_condition (code
);
2636 rev_opcode
= "beqz";
2640 rev_opcode
= "bnez";
2644 rev_opcode
= "bltz";
2648 rev_opcode
= "blez";
2652 rev_opcode
= "bgtz";
2656 rev_opcode
= "bgez";
2662 return tilegx_output_cbranch_with_opcode (insn
, operands
, opcode
,
2667 /* Implement the tablejump pattern. */
2669 tilegx_expand_tablejump (rtx op0
, rtx op1
)
2673 rtx temp
= gen_reg_rtx (Pmode
);
2674 rtx temp2
= gen_reg_rtx (Pmode
);
2676 tilegx_compute_pcrel_address (temp
, gen_rtx_LABEL_REF (Pmode
, op1
));
2677 emit_move_insn (temp2
,
2678 gen_rtx_PLUS (Pmode
,
2679 convert_to_mode (Pmode
, op0
, false),
2684 emit_jump_insn (gen_tablejump_aux (op0
, op1
));
2688 /* Emit barrier before an atomic, as needed for the memory MODEL. */
2690 tilegx_pre_atomic_barrier (enum memmodel model
)
2692 if (need_atomic_barrier_p (model
, true))
2693 emit_insn (gen_memory_barrier ());
2697 /* Emit barrier after an atomic, as needed for the memory MODEL. */
2699 tilegx_post_atomic_barrier (enum memmodel model
)
2701 if (need_atomic_barrier_p (model
, false))
2702 emit_insn (gen_memory_barrier ());
2707 /* Expand a builtin vector binary op, by calling gen function GEN with
2708 operands in the proper modes. DEST is converted to DEST_MODE, and
2709 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2711 tilegx_expand_builtin_vector_binop (rtx (*gen
) (rtx
, rtx
, rtx
),
2712 enum machine_mode dest_mode
,
2714 enum machine_mode src_mode
,
2715 rtx src0
, rtx src1
, bool do_src1
)
2717 dest
= gen_lowpart (dest_mode
, dest
);
2719 if (src0
== const0_rtx
)
2720 src0
= CONST0_RTX (src_mode
);
2722 src0
= gen_lowpart (src_mode
, src0
);
2726 if (src1
== const0_rtx
)
2727 src1
= CONST0_RTX (src_mode
);
2729 src1
= gen_lowpart (src_mode
, src1
);
2732 emit_insn ((*gen
) (dest
, src0
, src1
));
2740 struct tile_builtin_info
2742 enum insn_code icode
;
2746 static struct tile_builtin_info tilegx_builtin_info
[TILEGX_BUILTIN_max
] = {
2747 { CODE_FOR_adddi3
, NULL
}, /* add */
2748 { CODE_FOR_addsi3
, NULL
}, /* addx */
2749 { CODE_FOR_ssaddsi3
, NULL
}, /* addxsc */
2750 { CODE_FOR_anddi3
, NULL
}, /* and */
2751 { CODE_FOR_insn_bfexts
, NULL
}, /* bfexts */
2752 { CODE_FOR_insn_bfextu
, NULL
}, /* bfextu */
2753 { CODE_FOR_insn_bfins
, NULL
}, /* bfins */
2754 { CODE_FOR_clzdi2
, NULL
}, /* clz */
2755 { CODE_FOR_insn_cmoveqz
, NULL
}, /* cmoveqz */
2756 { CODE_FOR_insn_cmovnez
, NULL
}, /* cmovnez */
2757 { CODE_FOR_insn_cmpeq_didi
, NULL
}, /* cmpeq */
2758 { CODE_FOR_insn_cmpexch
, NULL
}, /* cmpexch */
2759 { CODE_FOR_insn_cmpexch4
, NULL
}, /* cmpexch4 */
2760 { CODE_FOR_insn_cmples_didi
, NULL
}, /* cmples */
2761 { CODE_FOR_insn_cmpleu_didi
, NULL
}, /* cmpleu */
2762 { CODE_FOR_insn_cmplts_didi
, NULL
}, /* cmplts */
2763 { CODE_FOR_insn_cmpltu_didi
, NULL
}, /* cmpltu */
2764 { CODE_FOR_insn_cmpne_didi
, NULL
}, /* cmpne */
2765 { CODE_FOR_insn_cmul
, NULL
}, /* cmul */
2766 { CODE_FOR_insn_cmula
, NULL
}, /* cmula */
2767 { CODE_FOR_insn_cmulaf
, NULL
}, /* cmulaf */
2768 { CODE_FOR_insn_cmulf
, NULL
}, /* cmulf */
2769 { CODE_FOR_insn_cmulfr
, NULL
}, /* cmulfr */
2770 { CODE_FOR_insn_cmulh
, NULL
}, /* cmulh */
2771 { CODE_FOR_insn_cmulhr
, NULL
}, /* cmulhr */
2772 { CODE_FOR_insn_crc32_32
, NULL
}, /* crc32_32 */
2773 { CODE_FOR_insn_crc32_8
, NULL
}, /* crc32_8 */
2774 { CODE_FOR_ctzdi2
, NULL
}, /* ctz */
2775 { CODE_FOR_insn_dblalign
, NULL
}, /* dblalign */
2776 { CODE_FOR_insn_dblalign2
, NULL
}, /* dblalign2 */
2777 { CODE_FOR_insn_dblalign4
, NULL
}, /* dblalign4 */
2778 { CODE_FOR_insn_dblalign6
, NULL
}, /* dblalign6 */
2779 { CODE_FOR_insn_drain
, NULL
}, /* drain */
2780 { CODE_FOR_insn_dtlbpr
, NULL
}, /* dtlbpr */
2781 { CODE_FOR_insn_exch
, NULL
}, /* exch */
2782 { CODE_FOR_insn_exch4
, NULL
}, /* exch4 */
2783 { CODE_FOR_insn_fdouble_add_flags
, NULL
}, /* fdouble_add_flags */
2784 { CODE_FOR_insn_fdouble_addsub
, NULL
}, /* fdouble_addsub */
2785 { CODE_FOR_insn_fdouble_mul_flags
, NULL
}, /* fdouble_mul_flags */
2786 { CODE_FOR_insn_fdouble_pack1
, NULL
}, /* fdouble_pack1 */
2787 { CODE_FOR_insn_fdouble_pack2
, NULL
}, /* fdouble_pack2 */
2788 { CODE_FOR_insn_fdouble_sub_flags
, NULL
}, /* fdouble_sub_flags */
2789 { CODE_FOR_insn_fdouble_unpack_max
, NULL
}, /* fdouble_unpack_max */
2790 { CODE_FOR_insn_fdouble_unpack_min
, NULL
}, /* fdouble_unpack_min */
2791 { CODE_FOR_insn_fetchadd
, NULL
}, /* fetchadd */
2792 { CODE_FOR_insn_fetchadd4
, NULL
}, /* fetchadd4 */
2793 { CODE_FOR_insn_fetchaddgez
, NULL
}, /* fetchaddgez */
2794 { CODE_FOR_insn_fetchaddgez4
, NULL
}, /* fetchaddgez4 */
2795 { CODE_FOR_insn_fetchand
, NULL
}, /* fetchand */
2796 { CODE_FOR_insn_fetchand4
, NULL
}, /* fetchand4 */
2797 { CODE_FOR_insn_fetchor
, NULL
}, /* fetchor */
2798 { CODE_FOR_insn_fetchor4
, NULL
}, /* fetchor4 */
2799 { CODE_FOR_insn_finv
, NULL
}, /* finv */
2800 { CODE_FOR_insn_flush
, NULL
}, /* flush */
2801 { CODE_FOR_insn_flushwb
, NULL
}, /* flushwb */
2802 { CODE_FOR_insn_fnop
, NULL
}, /* fnop */
2803 { CODE_FOR_insn_fsingle_add1
, NULL
}, /* fsingle_add1 */
2804 { CODE_FOR_insn_fsingle_addsub2
, NULL
}, /* fsingle_addsub2 */
2805 { CODE_FOR_insn_fsingle_mul1
, NULL
}, /* fsingle_mul1 */
2806 { CODE_FOR_insn_fsingle_mul2
, NULL
}, /* fsingle_mul2 */
2807 { CODE_FOR_insn_fsingle_pack1
, NULL
}, /* fsingle_pack1 */
2808 { CODE_FOR_insn_fsingle_pack2
, NULL
}, /* fsingle_pack2 */
2809 { CODE_FOR_insn_fsingle_sub1
, NULL
}, /* fsingle_sub1 */
2810 { CODE_FOR_insn_icoh
, NULL
}, /* icoh */
2811 { CODE_FOR_insn_ill
, NULL
}, /* ill */
2812 { CODE_FOR_insn_info
, NULL
}, /* info */
2813 { CODE_FOR_insn_infol
, NULL
}, /* infol */
2814 { CODE_FOR_insn_inv
, NULL
}, /* inv */
2815 { CODE_FOR_insn_ld
, NULL
}, /* ld */
2816 { CODE_FOR_insn_ld1s
, NULL
}, /* ld1s */
2817 { CODE_FOR_insn_ld1u
, NULL
}, /* ld1u */
2818 { CODE_FOR_insn_ld2s
, NULL
}, /* ld2s */
2819 { CODE_FOR_insn_ld2u
, NULL
}, /* ld2u */
2820 { CODE_FOR_insn_ld4s
, NULL
}, /* ld4s */
2821 { CODE_FOR_insn_ld4u
, NULL
}, /* ld4u */
2822 { CODE_FOR_insn_ldna
, NULL
}, /* ldna */
2823 { CODE_FOR_insn_ldnt
, NULL
}, /* ldnt */
2824 { CODE_FOR_insn_ldnt1s
, NULL
}, /* ldnt1s */
2825 { CODE_FOR_insn_ldnt1u
, NULL
}, /* ldnt1u */
2826 { CODE_FOR_insn_ldnt2s
, NULL
}, /* ldnt2s */
2827 { CODE_FOR_insn_ldnt2u
, NULL
}, /* ldnt2u */
2828 { CODE_FOR_insn_ldnt4s
, NULL
}, /* ldnt4s */
2829 { CODE_FOR_insn_ldnt4u
, NULL
}, /* ldnt4u */
2830 { CODE_FOR_insn_ld_L2
, NULL
}, /* ld_L2 */
2831 { CODE_FOR_insn_ld1s_L2
, NULL
}, /* ld1s_L2 */
2832 { CODE_FOR_insn_ld1u_L2
, NULL
}, /* ld1u_L2 */
2833 { CODE_FOR_insn_ld2s_L2
, NULL
}, /* ld2s_L2 */
2834 { CODE_FOR_insn_ld2u_L2
, NULL
}, /* ld2u_L2 */
2835 { CODE_FOR_insn_ld4s_L2
, NULL
}, /* ld4s_L2 */
2836 { CODE_FOR_insn_ld4u_L2
, NULL
}, /* ld4u_L2 */
2837 { CODE_FOR_insn_ldna_L2
, NULL
}, /* ldna_L2 */
2838 { CODE_FOR_insn_ldnt_L2
, NULL
}, /* ldnt_L2 */
2839 { CODE_FOR_insn_ldnt1s_L2
, NULL
}, /* ldnt1s_L2 */
2840 { CODE_FOR_insn_ldnt1u_L2
, NULL
}, /* ldnt1u_L2 */
2841 { CODE_FOR_insn_ldnt2s_L2
, NULL
}, /* ldnt2s_L2 */
2842 { CODE_FOR_insn_ldnt2u_L2
, NULL
}, /* ldnt2u_L2 */
2843 { CODE_FOR_insn_ldnt4s_L2
, NULL
}, /* ldnt4s_L2 */
2844 { CODE_FOR_insn_ldnt4u_L2
, NULL
}, /* ldnt4u_L2 */
2845 { CODE_FOR_insn_ld_miss
, NULL
}, /* ld_miss */
2846 { CODE_FOR_insn_ld1s_miss
, NULL
}, /* ld1s_miss */
2847 { CODE_FOR_insn_ld1u_miss
, NULL
}, /* ld1u_miss */
2848 { CODE_FOR_insn_ld2s_miss
, NULL
}, /* ld2s_miss */
2849 { CODE_FOR_insn_ld2u_miss
, NULL
}, /* ld2u_miss */
2850 { CODE_FOR_insn_ld4s_miss
, NULL
}, /* ld4s_miss */
2851 { CODE_FOR_insn_ld4u_miss
, NULL
}, /* ld4u_miss */
2852 { CODE_FOR_insn_ldna_miss
, NULL
}, /* ldna_miss */
2853 { CODE_FOR_insn_ldnt_miss
, NULL
}, /* ldnt_miss */
2854 { CODE_FOR_insn_ldnt1s_miss
, NULL
}, /* ldnt1s_miss */
2855 { CODE_FOR_insn_ldnt1u_miss
, NULL
}, /* ldnt1u_miss */
2856 { CODE_FOR_insn_ldnt2s_miss
, NULL
}, /* ldnt2s_miss */
2857 { CODE_FOR_insn_ldnt2u_miss
, NULL
}, /* ldnt2u_miss */
2858 { CODE_FOR_insn_ldnt4s_miss
, NULL
}, /* ldnt4s_miss */
2859 { CODE_FOR_insn_ldnt4u_miss
, NULL
}, /* ldnt4u_miss */
2860 { CODE_FOR_insn_lnk
, NULL
}, /* lnk */
2861 { CODE_FOR_memory_barrier
, NULL
}, /* mf */
2862 { CODE_FOR_insn_mfspr
, NULL
}, /* mfspr */
2863 { CODE_FOR_insn_mm
, NULL
}, /* mm */
2864 { CODE_FOR_insn_mnz
, NULL
}, /* mnz */
2865 { CODE_FOR_movdi
, NULL
}, /* move */
2866 { CODE_FOR_insn_mtspr
, NULL
}, /* mtspr */
2867 { CODE_FOR_insn_mul_hs_hs
, NULL
}, /* mul_hs_hs */
2868 { CODE_FOR_insn_mul_hs_hu
, NULL
}, /* mul_hs_hu */
2869 { CODE_FOR_insn_mul_hs_ls
, NULL
}, /* mul_hs_ls */
2870 { CODE_FOR_insn_mul_hs_lu
, NULL
}, /* mul_hs_lu */
2871 { CODE_FOR_insn_mul_hu_hu
, NULL
}, /* mul_hu_hu */
2872 { CODE_FOR_insn_mul_hu_ls
, NULL
}, /* mul_hu_ls */
2873 { CODE_FOR_insn_mul_hu_lu
, NULL
}, /* mul_hu_lu */
2874 { CODE_FOR_insn_mul_ls_ls
, NULL
}, /* mul_ls_ls */
2875 { CODE_FOR_insn_mul_ls_lu
, NULL
}, /* mul_ls_lu */
2876 { CODE_FOR_insn_mul_lu_lu
, NULL
}, /* mul_lu_lu */
2877 { CODE_FOR_insn_mula_hs_hs
, NULL
}, /* mula_hs_hs */
2878 { CODE_FOR_insn_mula_hs_hu
, NULL
}, /* mula_hs_hu */
2879 { CODE_FOR_insn_mula_hs_ls
, NULL
}, /* mula_hs_ls */
2880 { CODE_FOR_insn_mula_hs_lu
, NULL
}, /* mula_hs_lu */
2881 { CODE_FOR_insn_mula_hu_hu
, NULL
}, /* mula_hu_hu */
2882 { CODE_FOR_insn_mula_hu_ls
, NULL
}, /* mula_hu_ls */
2883 { CODE_FOR_insn_mula_hu_lu
, NULL
}, /* mula_hu_lu */
2884 { CODE_FOR_insn_mula_ls_ls
, NULL
}, /* mula_ls_ls */
2885 { CODE_FOR_insn_mula_ls_lu
, NULL
}, /* mula_ls_lu */
2886 { CODE_FOR_insn_mula_lu_lu
, NULL
}, /* mula_lu_lu */
2887 { CODE_FOR_insn_mulax
, NULL
}, /* mulax */
2888 { CODE_FOR_mulsi3
, NULL
}, /* mulx */
2889 { CODE_FOR_insn_mz
, NULL
}, /* mz */
2890 { CODE_FOR_insn_nap
, NULL
}, /* nap */
2891 { CODE_FOR_nop
, NULL
}, /* nop */
2892 { CODE_FOR_insn_nor_di
, NULL
}, /* nor */
2893 { CODE_FOR_iordi3
, NULL
}, /* or */
2894 { CODE_FOR_popcountdi2
, NULL
}, /* pcnt */
2895 { CODE_FOR_insn_prefetch_l1
, NULL
}, /* prefetch_l1 */
2896 { CODE_FOR_insn_prefetch_l1_fault
, NULL
}, /* prefetch_l1_fault */
2897 { CODE_FOR_insn_prefetch_l2
, NULL
}, /* prefetch_l2 */
2898 { CODE_FOR_insn_prefetch_l2_fault
, NULL
}, /* prefetch_l2_fault */
2899 { CODE_FOR_insn_prefetch_l3
, NULL
}, /* prefetch_l3 */
2900 { CODE_FOR_insn_prefetch_l3_fault
, NULL
}, /* prefetch_l3_fault */
2901 { CODE_FOR_insn_revbits
, NULL
}, /* revbits */
2902 { CODE_FOR_bswapdi2
, NULL
}, /* revbytes */
2903 { CODE_FOR_rotldi3
, NULL
}, /* rotl */
2904 { CODE_FOR_ashldi3
, NULL
}, /* shl */
2905 { CODE_FOR_insn_shl16insli
, NULL
}, /* shl16insli */
2906 { CODE_FOR_insn_shl1add
, NULL
}, /* shl1add */
2907 { CODE_FOR_insn_shl1addx
, NULL
}, /* shl1addx */
2908 { CODE_FOR_insn_shl2add
, NULL
}, /* shl2add */
2909 { CODE_FOR_insn_shl2addx
, NULL
}, /* shl2addx */
2910 { CODE_FOR_insn_shl3add
, NULL
}, /* shl3add */
2911 { CODE_FOR_insn_shl3addx
, NULL
}, /* shl3addx */
2912 { CODE_FOR_ashlsi3
, NULL
}, /* shlx */
2913 { CODE_FOR_ashrdi3
, NULL
}, /* shrs */
2914 { CODE_FOR_lshrdi3
, NULL
}, /* shru */
2915 { CODE_FOR_lshrsi3
, NULL
}, /* shrux */
2916 { CODE_FOR_insn_shufflebytes
, NULL
}, /* shufflebytes */
2917 { CODE_FOR_insn_shufflebytes1
, NULL
}, /* shufflebytes1 */
2918 { CODE_FOR_insn_st
, NULL
}, /* st */
2919 { CODE_FOR_insn_st1
, NULL
}, /* st1 */
2920 { CODE_FOR_insn_st2
, NULL
}, /* st2 */
2921 { CODE_FOR_insn_st4
, NULL
}, /* st4 */
2922 { CODE_FOR_insn_stnt
, NULL
}, /* stnt */
2923 { CODE_FOR_insn_stnt1
, NULL
}, /* stnt1 */
2924 { CODE_FOR_insn_stnt2
, NULL
}, /* stnt2 */
2925 { CODE_FOR_insn_stnt4
, NULL
}, /* stnt4 */
2926 { CODE_FOR_subdi3
, NULL
}, /* sub */
2927 { CODE_FOR_subsi3
, NULL
}, /* subx */
2928 { CODE_FOR_sssubsi3
, NULL
}, /* subxsc */
2929 { CODE_FOR_insn_tblidxb0
, NULL
}, /* tblidxb0 */
2930 { CODE_FOR_insn_tblidxb1
, NULL
}, /* tblidxb1 */
2931 { CODE_FOR_insn_tblidxb2
, NULL
}, /* tblidxb2 */
2932 { CODE_FOR_insn_tblidxb3
, NULL
}, /* tblidxb3 */
2933 { CODE_FOR_insn_v1add
, NULL
}, /* v1add */
2934 { CODE_FOR_insn_v1addi
, NULL
}, /* v1addi */
2935 { CODE_FOR_insn_v1adduc
, NULL
}, /* v1adduc */
2936 { CODE_FOR_insn_v1adiffu
, NULL
}, /* v1adiffu */
2937 { CODE_FOR_insn_v1avgu
, NULL
}, /* v1avgu */
2938 { CODE_FOR_insn_v1cmpeq
, NULL
}, /* v1cmpeq */
2939 { CODE_FOR_insn_v1cmpeqi
, NULL
}, /* v1cmpeqi */
2940 { CODE_FOR_insn_v1cmples
, NULL
}, /* v1cmples */
2941 { CODE_FOR_insn_v1cmpleu
, NULL
}, /* v1cmpleu */
2942 { CODE_FOR_insn_v1cmplts
, NULL
}, /* v1cmplts */
2943 { CODE_FOR_insn_v1cmpltsi
, NULL
}, /* v1cmpltsi */
2944 { CODE_FOR_insn_v1cmpltu
, NULL
}, /* v1cmpltu */
2945 { CODE_FOR_insn_v1cmpltui
, NULL
}, /* v1cmpltui */
2946 { CODE_FOR_insn_v1cmpne
, NULL
}, /* v1cmpne */
2947 { CODE_FOR_insn_v1ddotpu
, NULL
}, /* v1ddotpu */
2948 { CODE_FOR_insn_v1ddotpua
, NULL
}, /* v1ddotpua */
2949 { CODE_FOR_insn_v1ddotpus
, NULL
}, /* v1ddotpus */
2950 { CODE_FOR_insn_v1ddotpusa
, NULL
}, /* v1ddotpusa */
2951 { CODE_FOR_insn_v1dotp
, NULL
}, /* v1dotp */
2952 { CODE_FOR_insn_v1dotpa
, NULL
}, /* v1dotpa */
2953 { CODE_FOR_insn_v1dotpu
, NULL
}, /* v1dotpu */
2954 { CODE_FOR_insn_v1dotpua
, NULL
}, /* v1dotpua */
2955 { CODE_FOR_insn_v1dotpus
, NULL
}, /* v1dotpus */
2956 { CODE_FOR_insn_v1dotpusa
, NULL
}, /* v1dotpusa */
2957 { CODE_FOR_insn_v1int_h
, NULL
}, /* v1int_h */
2958 { CODE_FOR_insn_v1int_l
, NULL
}, /* v1int_l */
2959 { CODE_FOR_insn_v1maxu
, NULL
}, /* v1maxu */
2960 { CODE_FOR_insn_v1maxui
, NULL
}, /* v1maxui */
2961 { CODE_FOR_insn_v1minu
, NULL
}, /* v1minu */
2962 { CODE_FOR_insn_v1minui
, NULL
}, /* v1minui */
2963 { CODE_FOR_insn_v1mnz
, NULL
}, /* v1mnz */
2964 { CODE_FOR_insn_v1multu
, NULL
}, /* v1multu */
2965 { CODE_FOR_insn_v1mulu
, NULL
}, /* v1mulu */
2966 { CODE_FOR_insn_v1mulus
, NULL
}, /* v1mulus */
2967 { CODE_FOR_insn_v1mz
, NULL
}, /* v1mz */
2968 { CODE_FOR_insn_v1sadau
, NULL
}, /* v1sadau */
2969 { CODE_FOR_insn_v1sadu
, NULL
}, /* v1sadu */
2970 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shl */
2971 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shli */
2972 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrs */
2973 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrsi */
2974 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shru */
2975 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shrui */
2976 { CODE_FOR_insn_v1sub
, NULL
}, /* v1sub */
2977 { CODE_FOR_insn_v1subuc
, NULL
}, /* v1subuc */
2978 { CODE_FOR_insn_v2add
, NULL
}, /* v2add */
2979 { CODE_FOR_insn_v2addi
, NULL
}, /* v2addi */
2980 { CODE_FOR_insn_v2addsc
, NULL
}, /* v2addsc */
2981 { CODE_FOR_insn_v2adiffs
, NULL
}, /* v2adiffs */
2982 { CODE_FOR_insn_v2avgs
, NULL
}, /* v2avgs */
2983 { CODE_FOR_insn_v2cmpeq
, NULL
}, /* v2cmpeq */
2984 { CODE_FOR_insn_v2cmpeqi
, NULL
}, /* v2cmpeqi */
2985 { CODE_FOR_insn_v2cmples
, NULL
}, /* v2cmples */
2986 { CODE_FOR_insn_v2cmpleu
, NULL
}, /* v2cmpleu */
2987 { CODE_FOR_insn_v2cmplts
, NULL
}, /* v2cmplts */
2988 { CODE_FOR_insn_v2cmpltsi
, NULL
}, /* v2cmpltsi */
2989 { CODE_FOR_insn_v2cmpltu
, NULL
}, /* v2cmpltu */
2990 { CODE_FOR_insn_v2cmpltui
, NULL
}, /* v2cmpltui */
2991 { CODE_FOR_insn_v2cmpne
, NULL
}, /* v2cmpne */
2992 { CODE_FOR_insn_v2dotp
, NULL
}, /* v2dotp */
2993 { CODE_FOR_insn_v2dotpa
, NULL
}, /* v2dotpa */
2994 { CODE_FOR_insn_v2int_h
, NULL
}, /* v2int_h */
2995 { CODE_FOR_insn_v2int_l
, NULL
}, /* v2int_l */
2996 { CODE_FOR_insn_v2maxs
, NULL
}, /* v2maxs */
2997 { CODE_FOR_insn_v2maxsi
, NULL
}, /* v2maxsi */
2998 { CODE_FOR_insn_v2mins
, NULL
}, /* v2mins */
2999 { CODE_FOR_insn_v2minsi
, NULL
}, /* v2minsi */
3000 { CODE_FOR_insn_v2mnz
, NULL
}, /* v2mnz */
3001 { CODE_FOR_insn_v2mulfsc
, NULL
}, /* v2mulfsc */
3002 { CODE_FOR_insn_v2muls
, NULL
}, /* v2muls */
3003 { CODE_FOR_insn_v2mults
, NULL
}, /* v2mults */
3004 { CODE_FOR_insn_v2mz
, NULL
}, /* v2mz */
3005 { CODE_FOR_insn_v2packh
, NULL
}, /* v2packh */
3006 { CODE_FOR_insn_v2packl
, NULL
}, /* v2packl */
3007 { CODE_FOR_insn_v2packuc
, NULL
}, /* v2packuc */
3008 { CODE_FOR_insn_v2sadas
, NULL
}, /* v2sadas */
3009 { CODE_FOR_insn_v2sadau
, NULL
}, /* v2sadau */
3010 { CODE_FOR_insn_v2sads
, NULL
}, /* v2sads */
3011 { CODE_FOR_insn_v2sadu
, NULL
}, /* v2sadu */
3012 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shl */
3013 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shli */
3014 { CODE_FOR_insn_v2shlsc
, NULL
}, /* v2shlsc */
3015 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrs */
3016 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrsi */
3017 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shru */
3018 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shrui */
3019 { CODE_FOR_insn_v2sub
, NULL
}, /* v2sub */
3020 { CODE_FOR_insn_v2subsc
, NULL
}, /* v2subsc */
3021 { CODE_FOR_insn_v4add
, NULL
}, /* v4add */
3022 { CODE_FOR_insn_v4addsc
, NULL
}, /* v4addsc */
3023 { CODE_FOR_insn_v4int_h
, NULL
}, /* v4int_h */
3024 { CODE_FOR_insn_v4int_l
, NULL
}, /* v4int_l */
3025 { CODE_FOR_insn_v4packsc
, NULL
}, /* v4packsc */
3026 { CODE_FOR_insn_v4shl
, NULL
}, /* v4shl */
3027 { CODE_FOR_insn_v4shlsc
, NULL
}, /* v4shlsc */
3028 { CODE_FOR_insn_v4shrs
, NULL
}, /* v4shrs */
3029 { CODE_FOR_insn_v4shru
, NULL
}, /* v4shru */
3030 { CODE_FOR_insn_v4sub
, NULL
}, /* v4sub */
3031 { CODE_FOR_insn_v4subsc
, NULL
}, /* v4subsc */
3032 { CODE_FOR_insn_wh64
, NULL
}, /* wh64 */
3033 { CODE_FOR_xordi3
, NULL
}, /* xor */
3034 { CODE_FOR_tilegx_network_barrier
, NULL
}, /* network_barrier */
3035 { CODE_FOR_tilegx_idn0_receive
, NULL
}, /* idn0_receive */
3036 { CODE_FOR_tilegx_idn1_receive
, NULL
}, /* idn1_receive */
3037 { CODE_FOR_tilegx_idn_send
, NULL
}, /* idn_send */
3038 { CODE_FOR_tilegx_udn0_receive
, NULL
}, /* udn0_receive */
3039 { CODE_FOR_tilegx_udn1_receive
, NULL
}, /* udn1_receive */
3040 { CODE_FOR_tilegx_udn2_receive
, NULL
}, /* udn2_receive */
3041 { CODE_FOR_tilegx_udn3_receive
, NULL
}, /* udn3_receive */
3042 { CODE_FOR_tilegx_udn_send
, NULL
}, /* udn_send */
3046 struct tilegx_builtin_def
3049 enum tilegx_builtin code
;
3051 /* The first character is the return type. Subsequent characters
3052 are the argument types. See char_to_type. */
3057 static const struct tilegx_builtin_def tilegx_builtins
[] = {
3058 { "__insn_add", TILEGX_INSN_ADD
, true, "lll" },
3059 { "__insn_addi", TILEGX_INSN_ADD
, true, "lll" },
3060 { "__insn_addli", TILEGX_INSN_ADD
, true, "lll" },
3061 { "__insn_addx", TILEGX_INSN_ADDX
, true, "iii" },
3062 { "__insn_addxi", TILEGX_INSN_ADDX
, true, "iii" },
3063 { "__insn_addxli", TILEGX_INSN_ADDX
, true, "iii" },
3064 { "__insn_addxsc", TILEGX_INSN_ADDXSC
, true, "iii" },
3065 { "__insn_and", TILEGX_INSN_AND
, true, "lll" },
3066 { "__insn_andi", TILEGX_INSN_AND
, true, "lll" },
3067 { "__insn_bfexts", TILEGX_INSN_BFEXTS
, true, "llll" },
3068 { "__insn_bfextu", TILEGX_INSN_BFEXTU
, true, "llll" },
3069 { "__insn_bfins", TILEGX_INSN_BFINS
, true, "lllll"},
3070 { "__insn_clz", TILEGX_INSN_CLZ
, true, "ll" },
3071 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ
, true, "llll" },
3072 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ
, true, "llll" },
3073 { "__insn_cmpeq", TILEGX_INSN_CMPEQ
, true, "lll" },
3074 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ
, true, "lll" },
3075 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH
, false, "lpl" },
3076 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4
, false, "ipi" },
3077 { "__insn_cmples", TILEGX_INSN_CMPLES
, true, "lll" },
3078 { "__insn_cmpleu", TILEGX_INSN_CMPLEU
, true, "lll" },
3079 { "__insn_cmplts", TILEGX_INSN_CMPLTS
, true, "lll" },
3080 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS
, true, "lll" },
3081 { "__insn_cmpltu", TILEGX_INSN_CMPLTU
, true, "lll" },
3082 { "__insn_cmpltui", TILEGX_INSN_CMPLTU
, true, "lll" },
3083 { "__insn_cmpne", TILEGX_INSN_CMPNE
, true, "lll" },
3084 { "__insn_cmul", TILEGX_INSN_CMUL
, true, "lll" },
3085 { "__insn_cmula", TILEGX_INSN_CMULA
, true, "llll" },
3086 { "__insn_cmulaf", TILEGX_INSN_CMULAF
, true, "llll" },
3087 { "__insn_cmulf", TILEGX_INSN_CMULF
, true, "lll" },
3088 { "__insn_cmulfr", TILEGX_INSN_CMULFR
, true, "lll" },
3089 { "__insn_cmulh", TILEGX_INSN_CMULH
, true, "lll" },
3090 { "__insn_cmulhr", TILEGX_INSN_CMULHR
, true, "lll" },
3091 { "__insn_crc32_32", TILEGX_INSN_CRC32_32
, true, "lll" },
3092 { "__insn_crc32_8", TILEGX_INSN_CRC32_8
, true, "lll" },
3093 { "__insn_ctz", TILEGX_INSN_CTZ
, true, "ll" },
3094 { "__insn_dblalign", TILEGX_INSN_DBLALIGN
, true, "lllk" },
3095 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2
, true, "lll" },
3096 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4
, true, "lll" },
3097 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6
, true, "lll" },
3098 { "__insn_drain", TILEGX_INSN_DRAIN
, false, "v" },
3099 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR
, false, "vl" },
3100 { "__insn_exch", TILEGX_INSN_EXCH
, false, "lpl" },
3101 { "__insn_exch4", TILEGX_INSN_EXCH4
, false, "ipi" },
3102 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS
, true, "lll" },
3103 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB
, true, "llll" },
3104 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS
, true, "lll" },
3105 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1
, true, "lll" },
3106 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2
, true, "llll" },
3107 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS
, true, "lll" },
3108 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX
, true, "lll" },
3109 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN
, true, "lll" },
3110 { "__insn_fetchadd", TILEGX_INSN_FETCHADD
, false, "lpl" },
3111 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4
, false, "ipi" },
3112 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ
, false, "lpl" },
3113 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4
, false, "ipi" },
3114 { "__insn_fetchand", TILEGX_INSN_FETCHAND
, false, "lpl" },
3115 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4
, false, "ipi" },
3116 { "__insn_fetchor", TILEGX_INSN_FETCHOR
, false, "lpl" },
3117 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4
, false, "ipi" },
3118 { "__insn_finv", TILEGX_INSN_FINV
, false, "vk" },
3119 { "__insn_flush", TILEGX_INSN_FLUSH
, false, "vk" },
3120 { "__insn_flushwb", TILEGX_INSN_FLUSHWB
, false, "v" },
3121 { "__insn_fnop", TILEGX_INSN_FNOP
, false, "v" },
3122 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1
, true, "lll" },
3123 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2
, true, "llll" },
3124 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1
, true, "lll" },
3125 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2
, true, "lll" },
3126 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1
, true, "ll" },
3127 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2
, true, "lll" },
3128 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1
, true, "lll" },
3129 { "__insn_icoh", TILEGX_INSN_ICOH
, false, "vk" },
3130 { "__insn_ill", TILEGX_INSN_ILL
, false, "v" },
3131 { "__insn_info", TILEGX_INSN_INFO
, false, "vl" },
3132 { "__insn_infol", TILEGX_INSN_INFOL
, false, "vl" },
3133 { "__insn_inv", TILEGX_INSN_INV
, false, "vp" },
3134 { "__insn_ld", TILEGX_INSN_LD
, false, "lk" },
3135 { "__insn_ld1s", TILEGX_INSN_LD1S
, false, "lk" },
3136 { "__insn_ld1u", TILEGX_INSN_LD1U
, false, "lk" },
3137 { "__insn_ld2s", TILEGX_INSN_LD2S
, false, "lk" },
3138 { "__insn_ld2u", TILEGX_INSN_LD2U
, false, "lk" },
3139 { "__insn_ld4s", TILEGX_INSN_LD4S
, false, "lk" },
3140 { "__insn_ld4u", TILEGX_INSN_LD4U
, false, "lk" },
3141 { "__insn_ldna", TILEGX_INSN_LDNA
, false, "lk" },
3142 { "__insn_ldnt", TILEGX_INSN_LDNT
, false, "lk" },
3143 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S
, false, "lk" },
3144 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U
, false, "lk" },
3145 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S
, false, "lk" },
3146 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U
, false, "lk" },
3147 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S
, false, "lk" },
3148 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U
, false, "lk" },
3149 { "__insn_ld_L2", TILEGX_INSN_LD_L2
, false, "lk" },
3150 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2
, false, "lk" },
3151 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2
, false, "lk" },
3152 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2
, false, "lk" },
3153 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2
, false, "lk" },
3154 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2
, false, "lk" },
3155 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2
, false, "lk" },
3156 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2
, false, "lk" },
3157 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2
, false, "lk" },
3158 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2
, false, "lk" },
3159 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2
, false, "lk" },
3160 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2
, false, "lk" },
3161 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2
, false, "lk" },
3162 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2
, false, "lk" },
3163 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2
, false, "lk" },
3164 { "__insn_ld_miss", TILEGX_INSN_LD_MISS
, false, "lk" },
3165 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS
, false, "lk" },
3166 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS
, false, "lk" },
3167 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS
, false, "lk" },
3168 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS
, false, "lk" },
3169 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS
, false, "lk" },
3170 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS
, false, "lk" },
3171 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS
, false, "lk" },
3172 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS
, false, "lk" },
3173 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS
, false, "lk" },
3174 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS
, false, "lk" },
3175 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS
, false, "lk" },
3176 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS
, false, "lk" },
3177 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS
, false, "lk" },
3178 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS
, false, "lk" },
3179 { "__insn_lnk", TILEGX_INSN_LNK
, true, "l" },
3180 { "__insn_mf", TILEGX_INSN_MF
, false, "v" },
3181 { "__insn_mfspr", TILEGX_INSN_MFSPR
, false, "ll" },
3182 { "__insn_mm", TILEGX_INSN_MM
, true, "lllll"},
3183 { "__insn_mnz", TILEGX_INSN_MNZ
, true, "lll" },
3184 { "__insn_move", TILEGX_INSN_MOVE
, true, "ll" },
3185 { "__insn_movei", TILEGX_INSN_MOVE
, true, "ll" },
3186 { "__insn_moveli", TILEGX_INSN_MOVE
, true, "ll" },
3187 { "__insn_mtspr", TILEGX_INSN_MTSPR
, false, "vll" },
3188 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS
, true, "lll" },
3189 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU
, true, "lll" },
3190 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS
, true, "lll" },
3191 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU
, true, "lll" },
3192 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU
, true, "lll" },
3193 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS
, true, "lll" },
3194 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU
, true, "lll" },
3195 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS
, true, "lll" },
3196 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU
, true, "lll" },
3197 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU
, true, "lll" },
3198 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS
, true, "llll" },
3199 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU
, true, "llll" },
3200 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS
, true, "llll" },
3201 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU
, true, "llll" },
3202 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU
, true, "llll" },
3203 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS
, true, "llll" },
3204 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU
, true, "llll" },
3205 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS
, true, "llll" },
3206 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU
, true, "llll" },
3207 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU
, true, "llll" },
3208 { "__insn_mulax", TILEGX_INSN_MULAX
, true, "iiii" },
3209 { "__insn_mulx", TILEGX_INSN_MULX
, true, "iii" },
3210 { "__insn_mz", TILEGX_INSN_MZ
, true, "lll" },
3211 { "__insn_nap", TILEGX_INSN_NAP
, false, "v" },
3212 { "__insn_nop", TILEGX_INSN_NOP
, true, "v" },
3213 { "__insn_nor", TILEGX_INSN_NOR
, true, "lll" },
3214 { "__insn_or", TILEGX_INSN_OR
, true, "lll" },
3215 { "__insn_ori", TILEGX_INSN_OR
, true, "lll" },
3216 { "__insn_pcnt", TILEGX_INSN_PCNT
, true, "ll" },
3217 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3218 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3219 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT
, false, "vk" },
3220 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2
, false, "vk" },
3221 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT
, false, "vk" },
3222 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3
, false, "vk" },
3223 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT
, false, "vk" },
3224 { "__insn_revbits", TILEGX_INSN_REVBITS
, true, "ll" },
3225 { "__insn_revbytes", TILEGX_INSN_REVBYTES
, true, "ll" },
3226 { "__insn_rotl", TILEGX_INSN_ROTL
, true, "lli" },
3227 { "__insn_rotli", TILEGX_INSN_ROTL
, true, "lli" },
3228 { "__insn_shl", TILEGX_INSN_SHL
, true, "lli" },
3229 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI
, true, "lll" },
3230 { "__insn_shl1add", TILEGX_INSN_SHL1ADD
, true, "lll" },
3231 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX
, true, "iii" },
3232 { "__insn_shl2add", TILEGX_INSN_SHL2ADD
, true, "lll" },
3233 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX
, true, "iii" },
3234 { "__insn_shl3add", TILEGX_INSN_SHL3ADD
, true, "lll" },
3235 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX
, true, "iii" },
3236 { "__insn_shli", TILEGX_INSN_SHL
, true, "lli" },
3237 { "__insn_shlx", TILEGX_INSN_SHLX
, true, "iii" },
3238 { "__insn_shlxi", TILEGX_INSN_SHLX
, true, "iii" },
3239 { "__insn_shrs", TILEGX_INSN_SHRS
, true, "lli" },
3240 { "__insn_shrsi", TILEGX_INSN_SHRS
, true, "lli" },
3241 { "__insn_shru", TILEGX_INSN_SHRU
, true, "lli" },
3242 { "__insn_shrui", TILEGX_INSN_SHRU
, true, "lli" },
3243 { "__insn_shrux", TILEGX_INSN_SHRUX
, true, "iii" },
3244 { "__insn_shruxi", TILEGX_INSN_SHRUX
, true, "iii" },
3245 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES
, true, "llll" },
3246 { "__insn_shufflebytes1", TILEGX_INSN_SHUFFLEBYTES1
, true, "lll" },
3247 { "__insn_st", TILEGX_INSN_ST
, false, "vpl" },
3248 { "__insn_st1", TILEGX_INSN_ST1
, false, "vpl" },
3249 { "__insn_st2", TILEGX_INSN_ST2
, false, "vpl" },
3250 { "__insn_st4", TILEGX_INSN_ST4
, false, "vpl" },
3251 { "__insn_stnt", TILEGX_INSN_STNT
, false, "vpl" },
3252 { "__insn_stnt1", TILEGX_INSN_STNT1
, false, "vpl" },
3253 { "__insn_stnt2", TILEGX_INSN_STNT2
, false, "vpl" },
3254 { "__insn_stnt4", TILEGX_INSN_STNT4
, false, "vpl" },
3255 { "__insn_sub", TILEGX_INSN_SUB
, true, "lll" },
3256 { "__insn_subx", TILEGX_INSN_SUBX
, true, "iii" },
3257 { "__insn_subxsc", TILEGX_INSN_SUBXSC
, true, "iii" },
3258 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0
, true, "lll" },
3259 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1
, true, "lll" },
3260 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2
, true, "lll" },
3261 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3
, true, "lll" },
3262 { "__insn_v1add", TILEGX_INSN_V1ADD
, true, "lll" },
3263 { "__insn_v1addi", TILEGX_INSN_V1ADDI
, true, "lll" },
3264 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC
, true, "lll" },
3265 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU
, true, "lll" },
3266 { "__insn_v1avgu", TILEGX_INSN_V1AVGU
, true, "lll" },
3267 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ
, true, "lll" },
3268 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI
, true, "lll" },
3269 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES
, true, "lll" },
3270 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU
, true, "lll" },
3271 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS
, true, "lll" },
3272 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI
, true, "lll" },
3273 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU
, true, "lll" },
3274 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI
, true, "lll" },
3275 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE
, true, "lll" },
3276 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU
, true, "lll" },
3277 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA
, true, "llll" },
3278 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS
, true, "lll" },
3279 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA
, true, "llll" },
3280 { "__insn_v1dotp", TILEGX_INSN_V1DOTP
, true, "lll" },
3281 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA
, true, "llll" },
3282 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU
, true, "lll" },
3283 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA
, true, "llll" },
3284 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS
, true, "lll" },
3285 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA
, true, "llll" },
3286 { "__insn_v1int_h", TILEGX_INSN_V1INT_H
, true, "lll" },
3287 { "__insn_v1int_l", TILEGX_INSN_V1INT_L
, true, "lll" },
3288 { "__insn_v1maxu", TILEGX_INSN_V1MAXU
, true, "lll" },
3289 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI
, true, "lll" },
3290 { "__insn_v1minu", TILEGX_INSN_V1MINU
, true, "lll" },
3291 { "__insn_v1minui", TILEGX_INSN_V1MINUI
, true, "lll" },
3292 { "__insn_v1mnz", TILEGX_INSN_V1MNZ
, true, "lll" },
3293 { "__insn_v1multu", TILEGX_INSN_V1MULTU
, true, "lll" },
3294 { "__insn_v1mulu", TILEGX_INSN_V1MULU
, true, "lll" },
3295 { "__insn_v1mulus", TILEGX_INSN_V1MULUS
, true, "lll" },
3296 { "__insn_v1mz", TILEGX_INSN_V1MZ
, true, "lll" },
3297 { "__insn_v1sadau", TILEGX_INSN_V1SADAU
, true, "llll" },
3298 { "__insn_v1sadu", TILEGX_INSN_V1SADU
, true, "lll" },
3299 { "__insn_v1shl", TILEGX_INSN_V1SHL
, true, "lll" },
3300 { "__insn_v1shli", TILEGX_INSN_V1SHLI
, true, "lll" },
3301 { "__insn_v1shrs", TILEGX_INSN_V1SHRS
, true, "lll" },
3302 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI
, true, "lll" },
3303 { "__insn_v1shru", TILEGX_INSN_V1SHRU
, true, "lll" },
3304 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI
, true, "lll" },
3305 { "__insn_v1sub", TILEGX_INSN_V1SUB
, true, "lll" },
3306 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC
, true, "lll" },
3307 { "__insn_v2add", TILEGX_INSN_V2ADD
, true, "lll" },
3308 { "__insn_v2addi", TILEGX_INSN_V2ADDI
, true, "lll" },
3309 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC
, true, "lll" },
3310 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS
, true, "lll" },
3311 { "__insn_v2avgs", TILEGX_INSN_V2AVGS
, true, "lll" },
3312 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ
, true, "lll" },
3313 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI
, true, "lll" },
3314 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES
, true, "lll" },
3315 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU
, true, "lll" },
3316 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS
, true, "lll" },
3317 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI
, true, "lll" },
3318 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU
, true, "lll" },
3319 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI
, true, "lll" },
3320 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE
, true, "lll" },
3321 { "__insn_v2dotp", TILEGX_INSN_V2DOTP
, true, "lll" },
3322 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA
, true, "llll" },
3323 { "__insn_v2int_h", TILEGX_INSN_V2INT_H
, true, "lll" },
3324 { "__insn_v2int_l", TILEGX_INSN_V2INT_L
, true, "lll" },
3325 { "__insn_v2maxs", TILEGX_INSN_V2MAXS
, true, "lll" },
3326 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI
, true, "lll" },
3327 { "__insn_v2mins", TILEGX_INSN_V2MINS
, true, "lll" },
3328 { "__insn_v2minsi", TILEGX_INSN_V2MINSI
, true, "lll" },
3329 { "__insn_v2mnz", TILEGX_INSN_V2MNZ
, true, "lll" },
3330 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC
, true, "lll" },
3331 { "__insn_v2muls", TILEGX_INSN_V2MULS
, true, "lll" },
3332 { "__insn_v2mults", TILEGX_INSN_V2MULTS
, true, "lll" },
3333 { "__insn_v2mz", TILEGX_INSN_V2MZ
, true, "lll" },
3334 { "__insn_v2packh", TILEGX_INSN_V2PACKH
, true, "lll" },
3335 { "__insn_v2packl", TILEGX_INSN_V2PACKL
, true, "lll" },
3336 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC
, true, "lll" },
3337 { "__insn_v2sadas", TILEGX_INSN_V2SADAS
, true, "llll" },
3338 { "__insn_v2sadau", TILEGX_INSN_V2SADAU
, true, "llll" },
3339 { "__insn_v2sads", TILEGX_INSN_V2SADS
, true, "lll" },
3340 { "__insn_v2sadu", TILEGX_INSN_V2SADU
, true, "lll" },
3341 { "__insn_v2shl", TILEGX_INSN_V2SHL
, true, "lll" },
3342 { "__insn_v2shli", TILEGX_INSN_V2SHLI
, true, "lll" },
3343 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC
, true, "lll" },
3344 { "__insn_v2shrs", TILEGX_INSN_V2SHRS
, true, "lll" },
3345 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI
, true, "lll" },
3346 { "__insn_v2shru", TILEGX_INSN_V2SHRU
, true, "lll" },
3347 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI
, true, "lll" },
3348 { "__insn_v2sub", TILEGX_INSN_V2SUB
, true, "lll" },
3349 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC
, true, "lll" },
3350 { "__insn_v4add", TILEGX_INSN_V4ADD
, true, "lll" },
3351 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC
, true, "lll" },
3352 { "__insn_v4int_h", TILEGX_INSN_V4INT_H
, true, "lll" },
3353 { "__insn_v4int_l", TILEGX_INSN_V4INT_L
, true, "lll" },
3354 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC
, true, "lll" },
3355 { "__insn_v4shl", TILEGX_INSN_V4SHL
, true, "lll" },
3356 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC
, true, "lll" },
3357 { "__insn_v4shrs", TILEGX_INSN_V4SHRS
, true, "lll" },
3358 { "__insn_v4shru", TILEGX_INSN_V4SHRU
, true, "lll" },
3359 { "__insn_v4sub", TILEGX_INSN_V4SUB
, true, "lll" },
3360 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC
, true, "lll" },
3361 { "__insn_wh64", TILEGX_INSN_WH64
, false, "vp" },
3362 { "__insn_xor", TILEGX_INSN_XOR
, true, "lll" },
3363 { "__insn_xori", TILEGX_INSN_XOR
, true, "lll" },
3364 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER
, false, "v" },
3365 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE
, false, "l" },
3366 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE
, false, "l" },
3367 { "__tile_idn_send", TILEGX_IDN_SEND
, false, "vl" },
3368 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE
, false, "l" },
3369 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE
, false, "l" },
3370 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE
, false, "l" },
3371 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE
, false, "l" },
3372 { "__tile_udn_send", TILEGX_UDN_SEND
, false, "vl" },
3376 /* Convert a character in a builtin type string to a tree type. */
3378 char_to_type (char c
)
3380 static tree volatile_ptr_type_node
= NULL
;
3381 static tree volatile_const_ptr_type_node
= NULL
;
3383 if (volatile_ptr_type_node
== NULL
)
3385 volatile_ptr_type_node
=
3386 build_pointer_type (build_qualified_type (void_type_node
,
3387 TYPE_QUAL_VOLATILE
));
3388 volatile_const_ptr_type_node
=
3389 build_pointer_type (build_qualified_type (void_type_node
,
3391 | TYPE_QUAL_VOLATILE
));
3397 return void_type_node
;
3399 return unsigned_type_node
;
3401 return long_long_unsigned_type_node
;
3403 return volatile_ptr_type_node
;
3405 return volatile_const_ptr_type_node
;
3412 /* Implement TARGET_INIT_BUILTINS. */
3414 tilegx_init_builtins (void)
3418 for (i
= 0; i
< ARRAY_SIZE (tilegx_builtins
); i
++)
3420 const struct tilegx_builtin_def
*p
= &tilegx_builtins
[i
];
3421 tree ftype
, ret_type
, arg_type_list
= void_list_node
;
3425 for (j
= strlen (p
->type
) - 1; j
> 0; j
--)
3428 tree_cons (NULL_TREE
, char_to_type (p
->type
[j
]), arg_type_list
);
3431 ret_type
= char_to_type (p
->type
[0]);
3433 ftype
= build_function_type (ret_type
, arg_type_list
);
3435 decl
= add_builtin_function (p
->name
, ftype
, p
->code
, BUILT_IN_MD
,
3439 TREE_READONLY (decl
) = 1;
3440 TREE_NOTHROW (decl
) = 1;
3442 if (tilegx_builtin_info
[p
->code
].fndecl
== NULL
)
3443 tilegx_builtin_info
[p
->code
].fndecl
= decl
;
3448 /* Implement TARGET_EXPAND_BUILTIN. */
3450 tilegx_expand_builtin (tree exp
,
3452 rtx subtarget ATTRIBUTE_UNUSED
,
3453 enum machine_mode mode ATTRIBUTE_UNUSED
,
3454 int ignore ATTRIBUTE_UNUSED
)
3456 #define MAX_BUILTIN_ARGS 4
3458 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
3459 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
3461 call_expr_arg_iterator iter
;
3462 enum insn_code icode
;
3463 rtx op
[MAX_BUILTIN_ARGS
+ 1], pat
;
3468 if (fcode
>= TILEGX_BUILTIN_max
)
3469 internal_error ("bad builtin fcode");
3470 icode
= tilegx_builtin_info
[fcode
].icode
;
3472 internal_error ("bad builtin icode");
3474 nonvoid
= TREE_TYPE (TREE_TYPE (fndecl
)) != void_type_node
;
3477 FOR_EACH_CALL_EXPR_ARG (arg
, iter
, exp
)
3479 const struct insn_operand_data
*insn_op
;
3481 if (arg
== error_mark_node
)
3483 if (opnum
> MAX_BUILTIN_ARGS
)
3486 insn_op
= &insn_data
[icode
].operand
[opnum
];
3488 op
[opnum
] = expand_expr (arg
, NULL_RTX
, insn_op
->mode
, EXPAND_NORMAL
);
3490 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3492 enum machine_mode opmode
= insn_op
->mode
;
3494 /* pointer_operand and pmode_register_operand operands do
3495 not specify a mode, so use the operand's mode instead
3496 (which should always be right by the time we get here,
3497 except for constants, which are VOIDmode). */
3498 if (opmode
== VOIDmode
)
3500 enum machine_mode m
= GET_MODE (op
[opnum
]);
3501 gcc_assert (m
== Pmode
|| m
== VOIDmode
);
3505 op
[opnum
] = copy_to_mode_reg (opmode
, op
[opnum
]);
3508 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3510 /* We still failed to meet the predicate even after moving
3511 into a register. Assume we needed an immediate. */
3512 error_at (EXPR_LOCATION (exp
),
3513 "operand must be an immediate of the right size");
3522 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
3524 || GET_MODE (target
) != tmode
3525 || !(*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
3527 if (tmode
== VOIDmode
)
3529 /* get the mode from the return type. */
3530 tmode
= TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl
)));
3532 target
= gen_reg_rtx (tmode
);
3537 fn
= GEN_FCN (icode
);
3541 pat
= fn (NULL_RTX
);
3547 pat
= fn (op
[0], op
[1]);
3550 pat
= fn (op
[0], op
[1], op
[2]);
3553 pat
= fn (op
[0], op
[1], op
[2], op
[3]);
3556 pat
= fn (op
[0], op
[1], op
[2], op
[3], op
[4]);
3572 /* Implement TARGET_BUILTIN_DECL. */
3574 tilegx_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
3576 if (code
>= TILEGX_BUILTIN_max
)
3577 return error_mark_node
;
3579 return tilegx_builtin_info
[code
].fndecl
;
3586 /* Return whether REGNO needs to be saved in the stack frame. */
3588 need_to_save_reg (unsigned int regno
)
3590 if (!fixed_regs
[regno
] && !call_used_regs
[regno
]
3591 && df_regs_ever_live_p (regno
))
3595 && (regno
== PIC_OFFSET_TABLE_REGNUM
3596 || regno
== TILEGX_PIC_TEXT_LABEL_REGNUM
)
3597 && (crtl
->uses_pic_offset_table
|| crtl
->saves_all_registers
))
3600 if (crtl
->calls_eh_return
)
3603 for (i
= 0; EH_RETURN_DATA_REGNO (i
) != INVALID_REGNUM
; i
++)
3605 if (regno
== EH_RETURN_DATA_REGNO (i
))
3614 /* Return the size of the register savev area. This function is only
3615 correct starting with local register allocation */
3617 tilegx_saved_regs_size (void)
3619 int reg_save_size
= 0;
3621 int offset_to_frame
;
3624 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
3625 if (need_to_save_reg (regno
))
3626 reg_save_size
+= UNITS_PER_WORD
;
3628 /* Pad out the register save area if necessary to make
3629 frame_pointer_rtx be as aligned as the stack pointer. */
3630 offset_to_frame
= crtl
->args
.pretend_args_size
+ reg_save_size
;
3631 align_mask
= (STACK_BOUNDARY
/ BITS_PER_UNIT
) - 1;
3632 reg_save_size
+= (-offset_to_frame
) & align_mask
;
3634 return reg_save_size
;
3638 /* Round up frame size SIZE. */
3640 round_frame_size (int size
)
3642 return ((size
+ STACK_BOUNDARY
/ BITS_PER_UNIT
- 1)
3643 & -STACK_BOUNDARY
/ BITS_PER_UNIT
);
3647 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3648 emit the corresponding REG_CFA_OFFSET note described by CFA and
3649 CFA_OFFSET. Return the emitted insn. */
3651 frame_emit_store (int regno
, int regno_note
, rtx addr
, rtx cfa
,
3654 rtx reg
= gen_rtx_REG (DImode
, regno
);
3655 rtx mem
= gen_frame_mem (DImode
, addr
);
3656 rtx mov
= gen_movdi (mem
, reg
);
3658 /* Describe what just happened in a way that dwarf understands. We
3659 use temporary registers to hold the address to make scheduling
3660 easier, and use the REG_CFA_OFFSET to describe the address as an
3661 offset from the CFA. */
3662 rtx reg_note
= gen_rtx_REG (DImode
, regno_note
);
3663 rtx cfa_relative_addr
= gen_rtx_PLUS (Pmode
, cfa
, GEN_INT (cfa_offset
));
3664 rtx cfa_relative_mem
= gen_frame_mem (DImode
, cfa_relative_addr
);
3665 rtx real
= gen_rtx_SET (VOIDmode
, cfa_relative_mem
, reg_note
);
3666 add_reg_note (mov
, REG_CFA_OFFSET
, real
);
3668 return emit_insn (mov
);
3672 /* Emit a load in the stack frame to load REGNO from address ADDR.
3673 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3674 non-null. Return the emitted insn. */
3676 frame_emit_load (int regno
, rtx addr
, rtx
*cfa_restores
)
3678 rtx reg
= gen_rtx_REG (DImode
, regno
);
3679 rtx mem
= gen_frame_mem (DImode
, addr
);
3681 *cfa_restores
= alloc_reg_note (REG_CFA_RESTORE
, reg
, *cfa_restores
);
3682 return emit_insn (gen_movdi (reg
, mem
));
3686 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3687 including sequences. */
3689 set_frame_related_p (void)
3691 rtx seq
= get_insns ();
3702 while (insn
!= NULL_RTX
)
3704 RTX_FRAME_RELATED_P (insn
) = 1;
3705 insn
= NEXT_INSN (insn
);
3707 seq
= emit_insn (seq
);
3711 seq
= emit_insn (seq
);
3712 RTX_FRAME_RELATED_P (seq
) = 1;
3718 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3720 /* This emits code for 'sp += offset'.
3722 The ABI only allows us to modify 'sp' in a single 'addi' or
3723 'addli', so the backtracer understands it. Larger amounts cannot
3724 use those instructions, so are added by placing the offset into a
3725 large register and using 'add'.
3727 This happens after reload, so we need to expand it ourselves. */
3729 emit_sp_adjust (int offset
, int *next_scratch_regno
, bool frame_related
,
3733 rtx imm_rtx
= GEN_INT (offset
);
3736 if (satisfies_constraint_J (imm_rtx
))
3738 /* We can add this using a single immediate add. */
3743 rtx tmp
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3744 tilegx_expand_set_const64 (tmp
, imm_rtx
);
3748 /* Actually adjust the stack pointer. */
3750 insn
= gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3752 insn
= gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3754 insn
= emit_insn (insn
);
3755 REG_NOTES (insn
) = reg_notes
;
3757 /* Describe what just happened in a way that dwarf understands. */
3760 rtx real
= gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
3761 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3763 RTX_FRAME_RELATED_P (insn
) = 1;
3764 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, real
);
3771 /* Return whether the current function is leaf. This takes into
3772 account whether the function calls tls_get_addr. */
3774 tilegx_current_function_is_leaf (void)
3776 return crtl
->is_leaf
&& !cfun
->machine
->calls_tls_get_addr
;
3780 /* Return the frame size. */
3782 compute_total_frame_size (void)
3784 int total_size
= (get_frame_size () + tilegx_saved_regs_size ()
3785 + crtl
->outgoing_args_size
3786 + crtl
->args
.pretend_args_size
);
3788 if (!tilegx_current_function_is_leaf () || cfun
->calls_alloca
)
3790 /* Make room for save area in callee. */
3791 total_size
+= STACK_POINTER_OFFSET
;
3794 return round_frame_size (total_size
);
3798 /* Return nonzero if this function is known to have a null epilogue.
3799 This allows the optimizer to omit jumps to jumps if no stack was
3802 tilegx_can_use_return_insn_p (void)
3804 return (reload_completed
3805 && cfun
->static_chain_decl
== 0
3806 && compute_total_frame_size () == 0
3807 && tilegx_current_function_is_leaf ()
3808 && !crtl
->profile
&& !df_regs_ever_live_p (TILEGX_LINK_REGNUM
));
3812 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3813 is a frame pointer, it computes the value relative to
3814 that. Otherwise it uses the stack pointer. */
3816 compute_frame_addr (int offset_from_fp
, int *next_scratch_regno
)
3818 rtx base_reg_rtx
, tmp_reg_rtx
, offset_rtx
;
3819 int offset_from_base
;
3821 if (frame_pointer_needed
)
3823 base_reg_rtx
= hard_frame_pointer_rtx
;
3824 offset_from_base
= offset_from_fp
;
3828 int offset_from_sp
= compute_total_frame_size () + offset_from_fp
;
3829 offset_from_base
= offset_from_sp
;
3830 base_reg_rtx
= stack_pointer_rtx
;
3833 if (offset_from_base
== 0)
3834 return base_reg_rtx
;
3836 /* Compute the new value of the stack pointer. */
3837 tmp_reg_rtx
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3838 offset_rtx
= GEN_INT (offset_from_base
);
3840 if (!add_operand (offset_rtx
, Pmode
))
3842 expand_set_cint64 (tmp_reg_rtx
, offset_rtx
);
3843 offset_rtx
= tmp_reg_rtx
;
3846 emit_insn (gen_rtx_SET (VOIDmode
, tmp_reg_rtx
,
3847 gen_rtx_PLUS (Pmode
, base_reg_rtx
, offset_rtx
)));
3853 /* The stack frame looks like this:
3858 AP -> +-------------+
3862 HFP -> +-------------+
3864 | reg save | crtl->args.pretend_args_size bytes
3867 | saved regs | tilegx_saved_regs_size() bytes
3868 FP -> +-------------+
3870 | vars | get_frame_size() bytes
3874 | stack args | crtl->outgoing_args_size bytes
3876 | HFP | ptr_size bytes (only here if nonleaf / alloca)
3878 | callee lr | ptr_size bytes (only here if nonleaf / alloca)
3880 SP -> +-------------+
3884 For functions with a frame larger than 32767 bytes, or which use
3885 alloca (), r52 is used as a frame pointer. Otherwise there is no
3888 FP is saved at SP+ptr_size before calling a subroutine so the callee
3891 tilegx_expand_prologue (void)
3893 #define ROUND_ROBIN_SIZE 4
3894 /* We round-robin through four scratch registers to hold temporary
3895 addresses for saving registers, to make instruction scheduling
3897 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
3898 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
3901 unsigned int which_scratch
;
3902 int offset
, start_offset
, regno
;
3904 /* A register that holds a copy of the incoming fp. */
3905 int fp_copy_regno
= -1;
3907 /* A register that holds a copy of the incoming sp. */
3908 int sp_copy_regno
= -1;
3910 /* Next scratch register number to hand out (postdecrementing). */
3911 int next_scratch_regno
= 29;
3913 int total_size
= compute_total_frame_size ();
3915 if (flag_stack_usage_info
)
3916 current_function_static_stack_size
= total_size
;
3918 /* Save lr first in its special location because code after this
3919 might use the link register as a scratch register. */
3920 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
) || crtl
->calls_eh_return
)
3921 FRP (frame_emit_store (TILEGX_LINK_REGNUM
, TILEGX_LINK_REGNUM
,
3922 stack_pointer_rtx
, stack_pointer_rtx
, 0));
3924 if (total_size
== 0)
3926 /* Load the PIC register if needed. */
3927 if (flag_pic
&& crtl
->uses_pic_offset_table
)
3928 load_pic_register (false);
3933 cfa
= stack_pointer_rtx
;
3935 if (frame_pointer_needed
)
3937 fp_copy_regno
= next_scratch_regno
--;
3939 /* Copy the old frame pointer aside so we can save it later. */
3941 FRP (emit_move_insn (gen_rtx_REG (word_mode
, fp_copy_regno
),
3942 gen_lowpart (word_mode
, hard_frame_pointer_rtx
)));
3943 add_reg_note (insn
, REG_CFA_REGISTER
, NULL_RTX
);
3945 /* Set up the frame pointer. */
3946 insn
= FRP (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
3947 add_reg_note (insn
, REG_CFA_DEF_CFA
, hard_frame_pointer_rtx
);
3948 cfa
= hard_frame_pointer_rtx
;
3949 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM
) = STACK_BOUNDARY
;
3951 /* fp holds a copy of the incoming sp, in case we need to store
3953 sp_copy_regno
= HARD_FRAME_POINTER_REGNUM
;
3955 else if (!tilegx_current_function_is_leaf ())
3957 /* Copy the old stack pointer aside so we can save it later. */
3958 sp_copy_regno
= next_scratch_regno
--;
3959 emit_move_insn (gen_rtx_REG (Pmode
, sp_copy_regno
),
3963 if (tilegx_current_function_is_leaf ())
3965 /* No need to store chain pointer to caller's frame. */
3966 emit_sp_adjust (-total_size
, &next_scratch_regno
,
3967 !frame_pointer_needed
, NULL_RTX
);
3971 /* Save the frame pointer (incoming sp value) to support
3972 backtracing. First we need to create an rtx with the store
3974 rtx chain_addr
= gen_rtx_REG (Pmode
, next_scratch_regno
--);
3975 rtx size_rtx
= GEN_INT (-(total_size
- UNITS_PER_WORD
));
3977 if (add_operand (size_rtx
, Pmode
))
3979 /* Expose more parallelism by computing this value from the
3980 original stack pointer, not the one after we have pushed
3982 rtx p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, size_rtx
);
3983 emit_insn (gen_rtx_SET (VOIDmode
, chain_addr
, p
));
3984 emit_sp_adjust (-total_size
, &next_scratch_regno
,
3985 !frame_pointer_needed
, NULL_RTX
);
3989 /* The stack frame is large, so just store the incoming sp
3990 value at *(new_sp + UNITS_PER_WORD). */
3992 emit_sp_adjust (-total_size
, &next_scratch_regno
,
3993 !frame_pointer_needed
, NULL_RTX
);
3994 p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3995 GEN_INT (UNITS_PER_WORD
));
3996 emit_insn (gen_rtx_SET (VOIDmode
, chain_addr
, p
));
3999 /* Save our frame pointer for backtrace chaining. */
4000 emit_insn (gen_movdi (gen_frame_mem (DImode
, chain_addr
),
4001 gen_rtx_REG (DImode
, sp_copy_regno
)));
4004 /* Compute where to start storing registers we need to save. */
4005 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
4006 offset
= start_offset
;
4008 /* Store all registers that need saving. */
4010 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
4011 if (need_to_save_reg (regno
))
4013 rtx r
= reg_save_addr
[which_scratch
];
4015 int cfa_offset
= frame_pointer_needed
? offset
: total_size
+ offset
;
4019 int prev_scratch_regno
= next_scratch_regno
;
4020 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4021 if (prev_scratch_regno
!= next_scratch_regno
)
4022 reg_save_addr
[which_scratch
] = r
;
4026 /* Advance to the next stack slot to store this
4028 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4029 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4030 emit_insn (gen_rtx_SET (VOIDmode
, r
, p
));
4033 /* Save this register to the stack (but use the old fp value
4034 we copied aside if appropriate). */
4036 (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4037 ? fp_copy_regno
: regno
;
4038 FRP (frame_emit_store (from_regno
, regno
, r
, cfa
, cfa_offset
));
4040 offset
-= UNITS_PER_WORD
;
4041 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4044 /* If profiling, force that to happen after the frame is set up. */
4046 emit_insn (gen_blockage ());
4048 /* Load the PIC register if needed. */
4049 if (flag_pic
&& crtl
->uses_pic_offset_table
)
4050 load_pic_register (false);
4054 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
4055 true for a sibcall_epilogue pattern, and false for an epilogue
4058 tilegx_expand_epilogue (bool sibcall_p
)
4060 /* We round-robin through four scratch registers to hold temporary
4061 addresses for saving registers, to make instruction scheduling
4063 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
4064 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
4066 rtx last_insn
, insn
;
4067 unsigned int which_scratch
;
4068 int offset
, start_offset
, regno
;
4069 rtx cfa_restores
= NULL_RTX
;
4071 /* A register that holds a copy of the incoming fp. */
4072 int fp_copy_regno
= -1;
4074 /* Next scratch register number to hand out (postdecrementing). */
4075 int next_scratch_regno
= 29;
4077 int total_size
= compute_total_frame_size ();
4079 last_insn
= get_last_insn ();
4081 /* Load lr first since we are going to need it first. */
4083 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
))
4085 insn
= frame_emit_load (TILEGX_LINK_REGNUM
,
4086 compute_frame_addr (0, &next_scratch_regno
),
4090 if (total_size
== 0)
4094 RTX_FRAME_RELATED_P (insn
) = 1;
4095 REG_NOTES (insn
) = cfa_restores
;
4100 /* Compute where to start restoring registers. */
4101 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
4102 offset
= start_offset
;
4104 if (frame_pointer_needed
)
4105 fp_copy_regno
= next_scratch_regno
--;
4107 /* Restore all callee-saved registers. */
4109 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
4110 if (need_to_save_reg (regno
))
4112 rtx r
= reg_save_addr
[which_scratch
];
4115 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4116 reg_save_addr
[which_scratch
] = r
;
4120 /* Advance to the next stack slot to store this register. */
4121 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4122 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4123 emit_insn (gen_rtx_SET (VOIDmode
, r
, p
));
4126 if (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4127 frame_emit_load (fp_copy_regno
, r
, NULL
);
4129 frame_emit_load (regno
, r
, &cfa_restores
);
4131 offset
-= UNITS_PER_WORD
;
4132 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4135 if (!tilegx_current_function_is_leaf ())
4137 alloc_reg_note (REG_CFA_RESTORE
, stack_pointer_rtx
, cfa_restores
);
4139 emit_insn (gen_blockage ());
4141 if (frame_pointer_needed
)
4143 /* Restore the old stack pointer by copying from the frame
4147 insn
= emit_insn (gen_sp_restore_32bit (stack_pointer_rtx
,
4148 hard_frame_pointer_rtx
));
4152 insn
= emit_insn (gen_sp_restore (stack_pointer_rtx
,
4153 hard_frame_pointer_rtx
));
4155 RTX_FRAME_RELATED_P (insn
) = 1;
4156 REG_NOTES (insn
) = cfa_restores
;
4157 add_reg_note (insn
, REG_CFA_DEF_CFA
, stack_pointer_rtx
);
4161 insn
= emit_sp_adjust (total_size
, &next_scratch_regno
, true,
4165 if (crtl
->calls_eh_return
)
4168 emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
,
4169 EH_RETURN_STACKADJ_RTX
));
4171 emit_insn (gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
,
4172 EH_RETURN_STACKADJ_RTX
));
4175 /* Restore the old frame pointer. */
4176 if (frame_pointer_needed
)
4178 insn
= emit_move_insn (gen_lowpart (DImode
, hard_frame_pointer_rtx
),
4179 gen_rtx_REG (DImode
, fp_copy_regno
));
4180 add_reg_note (insn
, REG_CFA_RESTORE
, hard_frame_pointer_rtx
);
4183 /* Mark the pic registers as live outside of the function. */
4186 emit_use (cfun
->machine
->text_label_rtx
);
4187 emit_use (cfun
->machine
->got_rtx
);
4193 emit_jump_insn (gen__return ());
4197 emit_use (gen_rtx_REG (Pmode
, TILEGX_LINK_REGNUM
));
4200 /* Mark all insns we just emitted as frame-related. */
4201 for (; last_insn
!= NULL_RTX
; last_insn
= next_insn (last_insn
))
4202 RTX_FRAME_RELATED_P (last_insn
) = 1;
4205 #undef ROUND_ROBIN_SIZE
4208 /* Implement INITIAL_ELIMINATION_OFFSET. */
4210 tilegx_initial_elimination_offset (int from
, int to
)
4212 int total_size
= compute_total_frame_size ();
4214 if (from
== FRAME_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4216 return (total_size
- crtl
->args
.pretend_args_size
4217 - tilegx_saved_regs_size ());
4219 else if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4221 return -(crtl
->args
.pretend_args_size
+ tilegx_saved_regs_size ());
4223 else if (from
== ARG_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4225 return STACK_POINTER_OFFSET
+ total_size
;
4227 else if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4229 return STACK_POINTER_OFFSET
;
4236 /* Return an RTX indicating where the return address to the calling
4237 function can be found. */
4239 tilegx_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
4244 return get_hard_reg_initial_val (Pmode
, TILEGX_LINK_REGNUM
);
4248 /* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to
4249 prevent it from being deleted. */
4251 tilegx_eh_return_handler_rtx (void)
4253 rtx tmp
= gen_frame_mem (Pmode
, hard_frame_pointer_rtx
);
4254 MEM_VOLATILE_P (tmp
) = true;
4262 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
4264 tilegx_conditional_register_usage (void)
4266 global_regs
[TILEGX_NETORDER_REGNUM
] = 1;
4267 /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
4268 member of fixed_regs, and therefore must be member of
4269 call_used_regs, but it is not a member of call_really_used_regs[]
4270 because it is not clobbered by a call. */
4271 if (TILEGX_PIC_TEXT_LABEL_REGNUM
!= INVALID_REGNUM
)
4273 fixed_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4274 call_used_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4276 if (PIC_OFFSET_TABLE_REGNUM
!= INVALID_REGNUM
)
4278 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4279 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4284 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
4286 tilegx_frame_pointer_required (void)
4288 return crtl
->calls_eh_return
|| cfun
->calls_alloca
;
4293 /* Scheduling and reorg */
4295 /* Return the length of INSN. LENGTH is the initial length computed
4296 by attributes in the machine-description file. This is where we
4297 account for bundles. */
4299 tilegx_adjust_insn_length (rtx insn
, int length
)
4301 enum machine_mode mode
= GET_MODE (insn
);
4303 /* A non-termininating instruction in a bundle has length 0. */
4307 /* By default, there is not length adjustment. */
4312 /* Implement TARGET_SCHED_ISSUE_RATE. */
4314 tilegx_issue_rate (void)
4320 /* Return the rtx for the jump target. */
4322 get_jump_target (rtx branch
)
4324 if (CALL_P (branch
))
4327 call
= PATTERN (branch
);
4329 if (GET_CODE (call
) == PARALLEL
)
4330 call
= XVECEXP (call
, 0, 0);
4332 if (GET_CODE (call
) == SET
)
4333 call
= SET_SRC (call
);
4335 if (GET_CODE (call
) == CALL
)
4336 return XEXP (XEXP (call
, 0), 0);
4342 /* Implement TARGET_SCHED_ADJUST_COST. */
4344 tilegx_sched_adjust_cost (rtx insn
, rtx link
, rtx dep_insn
, int cost
)
4346 /* If we have a true dependence, INSN is a call, and DEP_INSN
4347 defines a register that is needed by the call (argument or stack
4348 pointer) , set its latency to 0 so that it can be bundled with
4349 the call. Explicitly check for and exclude the case when
4350 DEP_INSN defines the target of the jump. */
4351 if (CALL_P (insn
) && REG_NOTE_KIND (link
) == REG_DEP_TRUE
)
4353 rtx target
= get_jump_target (insn
);
4354 if (!REG_P (target
) || !set_of (target
, dep_insn
))
4362 /* Skip over irrelevant NOTEs and such and look for the next insn we
4363 would consider bundling. */
4365 next_insn_to_bundle (rtx r
, rtx end
)
4367 for (; r
!= end
; r
= NEXT_INSN (r
))
4369 if (NONDEBUG_INSN_P (r
)
4370 && GET_CODE (PATTERN (r
)) != USE
4371 && GET_CODE (PATTERN (r
)) != CLOBBER
)
4379 /* Go through all insns, and use the information generated during
4380 scheduling to generate SEQUENCEs to represent bundles of
4381 instructions issued simultaneously. */
4383 tilegx_gen_bundles (void)
4389 rtx end
= NEXT_INSN (BB_END (bb
));
4391 for (insn
= next_insn_to_bundle (BB_HEAD (bb
), end
); insn
; insn
= next
)
4393 next
= next_insn_to_bundle (NEXT_INSN (insn
), end
);
4395 /* Never wrap {} around inline asm. */
4396 if (GET_CODE (PATTERN (insn
)) != ASM_INPUT
)
4398 if (next
== NULL_RTX
|| GET_MODE (next
) == TImode
4399 /* NOTE: The scheduler incorrectly believes a call
4400 insn can execute in the same cycle as the insn
4401 after the call. This is of course impossible.
4402 Really we need to fix the scheduler somehow, so
4403 the code after the call gets scheduled
4407 /* Mark current insn as the end of a bundle. */
4408 PUT_MODE (insn
, QImode
);
4412 /* Mark it as part of a bundle. */
4413 PUT_MODE (insn
, SImode
);
4421 /* Replace OLD_INSN with NEW_INSN. */
4423 replace_insns (rtx old_insn
, rtx new_insns
)
4426 emit_insn_before (new_insns
, old_insn
);
4428 delete_insn (old_insn
);
4432 /* Returns true if INSN is the first instruction of a pc-relative
4433 address compuatation. */
4435 match_pcrel_step1 (rtx insn
)
4437 rtx pattern
= PATTERN (insn
);
4440 if (GET_CODE (pattern
) != SET
)
4443 src
= SET_SRC (pattern
);
4445 return (GET_CODE (src
) == CONST
4446 && GET_CODE (XEXP (src
, 0)) == UNSPEC
4447 && XINT (XEXP (src
, 0), 1) == UNSPEC_HW1_LAST_PCREL
);
4451 /* Do the first replacement step in tilegx_fixup_pcrel_references. */
4453 replace_mov_pcrel_step1 (rtx insn
)
4455 rtx pattern
= PATTERN (insn
);
4460 gcc_assert (GET_CODE (pattern
) == SET
);
4461 opnds
[0] = SET_DEST (pattern
);
4463 gcc_assert (GET_CODE (SET_SRC (pattern
)) == CONST
);
4465 unspec
= XEXP (SET_SRC (pattern
), 0);
4466 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4467 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW1_LAST_PCREL
);
4468 opnds
[1] = XVECEXP (unspec
, 0, 0);
4470 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4471 if (GET_CODE (opnds
[1]) != SYMBOL_REF
)
4479 emit_insn (gen_mov_got32_step1_32bit (opnds
[0], opnds
[1]));
4481 emit_insn (gen_mov_got32_step1 (opnds
[0], opnds
[1]));
4484 new_insns
= get_insns ();
4487 replace_insns (insn
, new_insns
);
4491 /* Returns true if INSN is the second instruction of a pc-relative
4492 address compuatation. */
4494 match_pcrel_step2 (rtx insn
)
4501 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli_32bit
)
4506 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli
)
4510 unspec
= SET_SRC (PATTERN (insn
));
4511 addr
= XVECEXP (unspec
, 0, 1);
4513 return (GET_CODE (addr
) == CONST
4514 && GET_CODE (XEXP (addr
, 0)) == UNSPEC
4515 && XINT (XEXP (addr
, 0), 1) == UNSPEC_HW0_PCREL
);
4519 /* Do the second replacement step in tilegx_fixup_pcrel_references. */
4521 replace_mov_pcrel_step2 (rtx insn
)
4523 rtx pattern
= PATTERN (insn
);
4528 rtx got_rtx
= tilegx_got_rtx ();
4530 gcc_assert (GET_CODE (pattern
) == SET
);
4531 opnds
[0] = SET_DEST (pattern
);
4533 unspec
= SET_SRC (pattern
);
4534 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4535 gcc_assert (XINT (unspec
, 1) == UNSPEC_INSN_ADDR_SHL16INSLI
);
4537 opnds
[1] = XVECEXP (unspec
, 0, 0);
4539 addr
= XVECEXP (unspec
, 0, 1);
4540 gcc_assert (GET_CODE (addr
) == CONST
);
4542 unspec
= XEXP (addr
, 0);
4543 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4544 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW0_PCREL
);
4545 opnds
[2] = XVECEXP (unspec
, 0, 0);
4547 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4548 if (GET_CODE (opnds
[2]) != SYMBOL_REF
)
4556 emit_insn (gen_add_got16_32bit (opnds
[0], got_rtx
, opnds
[2]));
4558 emit_insn (gen_add_got16 (opnds
[0], got_rtx
, opnds
[2]));
4563 emit_insn (gen_mov_got32_step2_32bit
4564 (opnds
[0], opnds
[1], opnds
[2]));
4566 emit_insn (gen_mov_got32_step2 (opnds
[0], opnds
[1], opnds
[2]));
4569 new_insns
= get_insns ();
4572 replace_insns (insn
, new_insns
);
4576 /* Do the third replacement step in tilegx_fixup_pcrel_references. */
4578 replace_mov_pcrel_step3 (rtx insn
)
4580 rtx pattern
= PATTERN (insn
);
4584 rtx got_rtx
= tilegx_got_rtx ();
4585 rtx text_label_rtx
= tilegx_text_label_rtx ();
4587 gcc_assert (GET_CODE (pattern
) == SET
);
4588 opnds
[0] = SET_DEST (pattern
);
4590 unspec
= SET_SRC (pattern
);
4591 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4592 gcc_assert (XINT (unspec
, 1) == UNSPEC_MOV_PCREL_STEP3
);
4596 if (XVECEXP (unspec
, 0, 0) == text_label_rtx
)
4597 opnds
[2] = XVECEXP (unspec
, 0, 1);
4600 gcc_assert (XVECEXP (unspec
, 0, 1) == text_label_rtx
);
4601 opnds
[2] = XVECEXP (unspec
, 0, 0);
4604 opnds
[3] = XVECEXP (unspec
, 0, 2);
4606 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4607 if (GET_CODE (opnds
[3]) != SYMBOL_REF
)
4614 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[2]));
4618 emit_move_insn (opnds
[0], gen_rtx_PLUS (Pmode
, opnds
[1], opnds
[2]));
4619 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[0]));
4622 new_insns
= get_insns ();
4625 replace_insns (insn
, new_insns
);
4629 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4630 going through the GOT when the symbol is local to the compilation
4631 unit. But such a symbol requires that the common text_label that
4632 we generate at the beginning of the function be in the same section
4633 as the reference to the SYMBOL_REF. This may not be true if we
4634 generate hot/cold sections. This function looks for such cases and
4635 replaces such references with the longer sequence going through the
4638 We expect following instruction sequence:
4639 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4640 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4641 add<x> tmp3, txt_label_reg, tmp2 [3]
4643 If we're compiling -fpic, we replace with the following sequence
4644 (the numbers in brackets match the instructions they're replacing
4647 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4648 ld<4> tmp3, tmp2 [3]
4650 If we're compiling -fPIC, we replace the first instruction with:
4652 moveli tmp1, hw1_last_got(x) [1]
4653 shl16insli tmp2, tmp1, hw0_got(x) [2]
4654 add<x> tmp3, got_reg, tmp2 [3]
4655 ld<4> tmp3, tmp3 [3]
4657 Note that we're careful to disturb the instruction sequence as
4658 little as possible, since it's very late in the compilation
4661 tilegx_fixup_pcrel_references (void)
4663 rtx insn
, next_insn
;
4664 bool same_section_as_entry
= true;
4666 for (insn
= get_insns (); insn
; insn
= next_insn
)
4668 next_insn
= NEXT_INSN (insn
);
4670 if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_SWITCH_TEXT_SECTIONS
)
4672 same_section_as_entry
= !same_section_as_entry
;
4676 if (same_section_as_entry
)
4680 && GET_CODE (PATTERN (insn
)) != USE
4681 && GET_CODE (PATTERN (insn
)) != CLOBBER
))
4686 if (match_pcrel_step1 (insn
))
4687 replace_mov_pcrel_step1 (insn
);
4688 else if (match_pcrel_step2 (insn
))
4689 replace_mov_pcrel_step2 (insn
);
4690 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3_32bit
)
4691 replace_mov_pcrel_step3 (insn
);
4695 if (match_pcrel_step1 (insn
))
4696 replace_mov_pcrel_step1 (insn
);
4697 else if (match_pcrel_step2 (insn
))
4698 replace_mov_pcrel_step2 (insn
);
4699 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3
)
4700 replace_mov_pcrel_step3 (insn
);
4706 /* Ensure that no var tracking notes are emitted in the middle of a
4707 three-instruction bundle. */
4709 reorder_var_tracking_notes (void)
4715 rtx queue
= NULL_RTX
;
4716 bool in_bundle
= false;
4718 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4720 next
= NEXT_INSN (insn
);
4724 /* Emit queued up notes at the last instruction of a
4726 if (GET_MODE (insn
) == QImode
)
4730 rtx next_queue
= PREV_INSN (queue
);
4731 PREV_INSN (NEXT_INSN (insn
)) = queue
;
4732 NEXT_INSN (queue
) = NEXT_INSN (insn
);
4733 NEXT_INSN (insn
) = queue
;
4734 PREV_INSN (queue
) = insn
;
4739 else if (GET_MODE (insn
) == SImode
)
4742 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4746 rtx prev
= PREV_INSN (insn
);
4747 PREV_INSN (next
) = prev
;
4748 NEXT_INSN (prev
) = next
;
4750 PREV_INSN (insn
) = queue
;
4759 /* Perform machine dependent operations on the rtl chain INSNS. */
4763 /* We are freeing block_for_insn in the toplev to keep compatibility
4764 with old MDEP_REORGS that are not CFG based. Recompute it
4766 compute_bb_for_insn ();
4768 if (flag_reorder_blocks_and_partition
)
4770 tilegx_fixup_pcrel_references ();
4773 if (flag_schedule_insns_after_reload
)
4777 timevar_push (TV_SCHED2
);
4779 timevar_pop (TV_SCHED2
);
4781 /* Examine the schedule to group into bundles. */
4782 tilegx_gen_bundles ();
4787 if (flag_var_tracking
)
4789 timevar_push (TV_VAR_TRACKING
);
4790 variable_tracking_main ();
4791 reorder_var_tracking_notes ();
4792 timevar_pop (TV_VAR_TRACKING
);
4795 df_finish_pass (false);
4802 /* Select a format to encode pointers in exception handling data.
4803 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4804 GLOBAL is true if the symbol may be affected by dynamic
4807 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED
, int global
)
4809 int type
= TARGET_32BIT
? DW_EH_PE_sdata4
: DW_EH_PE_sdata8
;
4810 return (global
? DW_EH_PE_indirect
: 0) | DW_EH_PE_pcrel
| type
;
4814 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4816 tilegx_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
4817 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
4820 rtx this_rtx
, insn
, funexp
, addend
;
4822 /* Pretend to be a post-reload pass while generating rtl. */
4823 reload_completed
= 1;
4825 /* Mark the end of the (empty) prologue. */
4826 emit_note (NOTE_INSN_PROLOGUE_END
);
4828 /* Find the "this" pointer. If the function returns a structure,
4829 the structure return pointer is in $1. */
4830 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
4831 this_rtx
= gen_rtx_REG (Pmode
, 1);
4833 this_rtx
= gen_rtx_REG (Pmode
, 0);
4835 /* Add DELTA to THIS_RTX. */
4836 if (!(delta
>= -32868 && delta
<= 32767))
4838 addend
= gen_rtx_REG (Pmode
, 29);
4839 emit_move_insn (addend
, GEN_INT (delta
));
4842 addend
= GEN_INT (delta
);
4845 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, addend
));
4847 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, addend
));
4849 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4854 tmp
= gen_rtx_REG (Pmode
, 29);
4855 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, this_rtx
));
4857 if (!(vcall_offset
>= -32868 && vcall_offset
<= 32767))
4859 addend
= gen_rtx_REG (Pmode
, 28);
4860 emit_move_insn (addend
, GEN_INT (vcall_offset
));
4863 addend
= GEN_INT (vcall_offset
);
4866 emit_insn (gen_addsi3 (tmp
, tmp
, addend
));
4868 emit_insn (gen_adddi3 (tmp
, tmp
, addend
));
4870 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, tmp
));
4873 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, tmp
));
4875 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, tmp
));
4878 /* Generate a tail call to the target function. */
4879 if (!TREE_USED (function
))
4881 assemble_external (function
);
4882 TREE_USED (function
) = 1;
4884 funexp
= XEXP (DECL_RTL (function
), 0);
4885 funexp
= gen_rtx_MEM (FUNCTION_MODE
, funexp
);
4886 insn
= emit_call_insn (gen_sibcall (funexp
, const0_rtx
));
4887 SIBLING_CALL_P (insn
) = 1;
4889 /* Run just enough of rest_of_compilation to get the insns emitted.
4890 There's not really enough bulk here to make other passes such as
4891 instruction scheduling worth while. Note that use_thunk calls
4892 assemble_start_function and assemble_end_function.
4894 We don't currently bundle, but the instruciton sequence is all
4895 serial except for the tail call, so we're only wasting one cycle.
4897 insn
= get_insns ();
4898 shorten_branches (insn
);
4899 final_start_function (insn
, file
, 1);
4900 final (insn
, file
, 1);
4901 final_end_function ();
4903 /* Stop pretending to be a post-reload pass. */
4904 reload_completed
= 0;
4908 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
4910 tilegx_asm_trampoline_template (FILE *file
)
4912 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
4915 fprintf (file
, "\tlnk r10\n");
4916 fprintf (file
, "\taddxi r10, r10, 32\n");
4917 fprintf (file
, "\tld4s_add r11, r10, %d\n", ptr_mode_size
);
4918 fprintf (file
, "\tld4s r10, r10\n");
4919 fprintf (file
, "\tjr r11\n");
4920 fprintf (file
, "\t.word 0 # <function address>\n");
4921 fprintf (file
, "\t.word 0 # <static chain value>\n");
4925 fprintf (file
, "\tlnk r10\n");
4926 fprintf (file
, "\taddi r10, r10, 32\n");
4927 fprintf (file
, "\tld_add r11, r10, %d\n", ptr_mode_size
);
4928 fprintf (file
, "\tld r10, r10\n");
4929 fprintf (file
, "\tjr r11\n");
4930 fprintf (file
, "\t.quad 0 # <function address>\n");
4931 fprintf (file
, "\t.quad 0 # <static chain value>\n");
4936 /* Implement TARGET_TRAMPOLINE_INIT. */
4938 tilegx_trampoline_init (rtx m_tramp
, tree fndecl
, rtx static_chain
)
4942 rtx begin_addr
, end_addr
;
4943 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
4945 fnaddr
= copy_to_reg (XEXP (DECL_RTL (fndecl
), 0));
4946 chaddr
= copy_to_reg (static_chain
);
4948 emit_block_move (m_tramp
, assemble_trampoline_template (),
4949 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
4951 mem
= adjust_address (m_tramp
, ptr_mode
,
4952 TRAMPOLINE_SIZE
- 2 * ptr_mode_size
);
4953 emit_move_insn (mem
, fnaddr
);
4954 mem
= adjust_address (m_tramp
, ptr_mode
,
4955 TRAMPOLINE_SIZE
- ptr_mode_size
);
4956 emit_move_insn (mem
, chaddr
);
4958 /* Get pointers to the beginning and end of the code block. */
4959 begin_addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
4960 end_addr
= force_reg (Pmode
, plus_constant (Pmode
, XEXP (m_tramp
, 0),
4963 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__clear_cache"),
4964 LCT_NORMAL
, VOIDmode
, 2, begin_addr
, Pmode
,
4969 /* Implement TARGET_PRINT_OPERAND. */
4971 tilegx_print_operand (FILE *file
, rtx x
, int code
)
4976 /* Print the compare operator opcode for conditional moves. */
4977 switch (GET_CODE (x
))
4986 output_operand_lossage ("invalid %%c operand");
4991 /* Print the compare operator opcode for conditional moves. */
4992 switch (GET_CODE (x
))
5001 output_operand_lossage ("invalid %%C operand");
5007 /* Print the compare operator opcode for conditional moves. */
5008 switch (GET_CODE (x
))
5017 output_operand_lossage ("invalid %%d operand");
5024 /* Print the compare operator opcode for conditional moves. */
5025 switch (GET_CODE (x
))
5034 output_operand_lossage ("invalid %%D operand");
5041 if (GET_CODE (x
) == CONST
5042 && GET_CODE (XEXP (x
, 0)) == UNSPEC
)
5044 rtx addr
= XVECEXP (XEXP (x
, 0), 0, 0);
5045 int unspec
= XINT (XEXP (x
, 0), 1);
5046 const char *opstr
= NULL
;
5050 case UNSPEC_HW0_PCREL
:
5054 case UNSPEC_HW1_PCREL
:
5063 case UNSPEC_HW0_LAST
:
5066 case UNSPEC_HW1_LAST
:
5067 case UNSPEC_HW1_LAST_PCREL
:
5070 case UNSPEC_HW2_LAST
:
5071 case UNSPEC_HW2_LAST_PCREL
:
5074 case UNSPEC_HW0_GOT
:
5077 case UNSPEC_HW0_LAST_GOT
:
5078 opstr
= "hw0_last_got";
5080 case UNSPEC_HW1_LAST_GOT
:
5081 opstr
= "hw1_last_got";
5083 case UNSPEC_HW0_TLS_GD
:
5084 opstr
= "hw0_tls_gd";
5086 case UNSPEC_HW1_LAST_TLS_GD
:
5087 opstr
= "hw1_last_tls_gd";
5089 case UNSPEC_HW0_TLS_IE
:
5090 opstr
= "hw0_tls_ie";
5092 case UNSPEC_HW1_LAST_TLS_IE
:
5093 opstr
= "hw1_last_tls_ie";
5095 case UNSPEC_HW0_TLS_LE
:
5096 opstr
= "hw0_tls_le";
5098 case UNSPEC_HW1_LAST_TLS_LE
:
5099 opstr
= "hw1_last_tls_le";
5101 case UNSPEC_HW0_PLT_PCREL
:
5104 case UNSPEC_HW1_PLT_PCREL
:
5107 case UNSPEC_HW1_LAST_PLT_PCREL
:
5108 opstr
= "hw1_last_plt";
5110 case UNSPEC_HW2_LAST_PLT_PCREL
:
5111 opstr
= "hw2_last_plt";
5114 output_operand_lossage ("invalid %%H specifier");
5117 fputs (opstr
, file
);
5119 output_addr_const (file
, addr
);
5121 if (unspec
== UNSPEC_HW0_PCREL
5122 || unspec
== UNSPEC_HW1_PCREL
5123 || unspec
== UNSPEC_HW1_LAST_PCREL
5124 || unspec
== UNSPEC_HW2_LAST_PCREL
5125 || unspec
== UNSPEC_HW0_PLT_PCREL
5126 || unspec
== UNSPEC_HW1_PLT_PCREL
5127 || unspec
== UNSPEC_HW1_LAST_PLT_PCREL
5128 || unspec
== UNSPEC_HW2_LAST_PLT_PCREL
)
5130 rtx addr2
= XVECEXP (XEXP (x
, 0), 0, 1);
5131 fputs (" - " , file
);
5132 output_addr_const (file
, addr2
);
5138 else if (symbolic_operand (x
, VOIDmode
))
5140 output_addr_const (file
, x
);
5148 /* Print the low 16 bits of a constant. */
5150 if (CONST_INT_P (x
))
5152 else if (GET_CODE (x
) == CONST_DOUBLE
)
5153 i
= CONST_DOUBLE_LOW (x
);
5156 output_operand_lossage ("invalid %%h operand");
5159 i
= trunc_int_for_mode (i
, HImode
);
5160 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5165 /* Print an auto-inc memory operand. */
5168 output_operand_lossage ("invalid %%I operand");
5172 output_memory_reference_mode
= GET_MODE (x
);
5173 output_memory_autoinc_first
= true;
5174 output_address (XEXP (x
, 0));
5175 output_memory_reference_mode
= VOIDmode
;
5179 /* Print an auto-inc memory operand. */
5182 output_operand_lossage ("invalid %%i operand");
5186 output_memory_reference_mode
= GET_MODE (x
);
5187 output_memory_autoinc_first
= false;
5188 output_address (XEXP (x
, 0));
5189 output_memory_reference_mode
= VOIDmode
;
5194 /* Print the low 8 bits of a constant. */
5196 if (CONST_INT_P (x
))
5198 else if (GET_CODE (x
) == CONST_DOUBLE
)
5199 i
= CONST_DOUBLE_LOW (x
);
5200 else if (GET_CODE (x
) == CONST_VECTOR
5201 && CONST_INT_P (CONST_VECTOR_ELT (x
, 0)))
5202 i
= INTVAL (CONST_VECTOR_ELT (x
, 0));
5205 output_operand_lossage ("invalid %%j operand");
5208 i
= trunc_int_for_mode (i
, QImode
);
5209 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5215 /* Print a constant plus one. */
5216 if (!CONST_INT_P (x
))
5218 output_operand_lossage ("invalid %%P operand");
5221 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (x
) + 1);
5228 /* Print a bfextu-style bit range. */
5229 int first_bit
, last_bit
;
5230 HOST_WIDE_INT flip
= (code
== 'm') ? ~0 : 0;
5232 if (!CONST_INT_P (x
)
5233 || !tilegx_bitfield_operand_p (INTVAL (x
) ^ flip
,
5234 &first_bit
, &last_bit
))
5236 output_operand_lossage ("invalid %%%c operand", code
);
5240 fprintf (file
, "%d, %d", first_bit
, last_bit
);
5246 const char *reg
= NULL
;
5248 /* Print a network register. */
5249 if (!CONST_INT_P (x
))
5251 output_operand_lossage ("invalid %%N operand");
5257 case TILEGX_NETREG_IDN0
: reg
= "idn0"; break;
5258 case TILEGX_NETREG_IDN1
: reg
= "idn1"; break;
5259 case TILEGX_NETREG_UDN0
: reg
= "udn0"; break;
5260 case TILEGX_NETREG_UDN1
: reg
= "udn1"; break;
5261 case TILEGX_NETREG_UDN2
: reg
= "udn2"; break;
5262 case TILEGX_NETREG_UDN3
: reg
= "udn3"; break;
5267 fprintf (file
, reg
);
5272 if (GET_CODE (x
) == SYMBOL_REF
)
5274 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5275 fprintf (file
, "plt(");
5276 output_addr_const (file
, x
);
5277 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5278 fprintf (file
, ")");
5281 output_addr_const (file
, x
);
5285 /* In this case we need a register. Use 'zero' if the operand
5288 || (GET_MODE (x
) != VOIDmode
&& x
== CONST0_RTX (GET_MODE (x
))))
5290 fputs ("zero", file
);
5293 else if (!REG_P (x
))
5295 output_operand_lossage ("invalid operand for 'r' specifier");
5303 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
5308 output_memory_reference_mode
= VOIDmode
;
5309 output_address (XEXP (x
, 0));
5314 output_addr_const (file
, x
);
5320 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5325 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5327 tilegx_print_operand_address (FILE *file
, rtx addr
)
5329 if (GET_CODE (addr
) == POST_DEC
5330 || GET_CODE (addr
) == POST_INC
)
5332 int offset
= GET_MODE_SIZE (output_memory_reference_mode
);
5334 gcc_assert (output_memory_reference_mode
!= VOIDmode
);
5336 if (output_memory_autoinc_first
)
5337 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5339 fprintf (file
, "%d",
5340 GET_CODE (addr
) == POST_DEC
? -offset
: offset
);
5342 else if (GET_CODE (addr
) == POST_MODIFY
)
5344 gcc_assert (output_memory_reference_mode
!= VOIDmode
);
5346 gcc_assert (GET_CODE (XEXP (addr
, 1)) == PLUS
);
5348 if (output_memory_autoinc_first
)
5349 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5351 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
,
5352 INTVAL (XEXP (XEXP (addr
, 1), 1)));
5355 tilegx_print_operand (file
, addr
, 'r');
5359 /* Machine mode of current insn, for determining curly brace
5361 static enum machine_mode insn_mode
;
5364 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5366 tilegx_final_prescan_insn (rtx insn
)
5368 /* Record this for tilegx_asm_output_opcode to examine. */
5369 insn_mode
= GET_MODE (insn
);
5373 /* While emitting asm, are we currently inside '{' for a bundle? */
5374 static bool tilegx_in_bundle
= false;
5376 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5377 appropriate given the bundling information recorded by
5378 tilegx_gen_bundles. */
5380 tilegx_asm_output_opcode (FILE *stream
, const char *code
)
5382 bool pseudo
= !strcmp (code
, "pseudo");
5384 if (!tilegx_in_bundle
&& insn_mode
== SImode
)
5386 /* Start a new bundle. */
5387 fprintf (stream
, "{\n\t");
5388 tilegx_in_bundle
= true;
5391 if (tilegx_in_bundle
&& insn_mode
== QImode
)
5393 /* Close an existing bundle. */
5394 static char buf
[100];
5396 gcc_assert (strlen (code
) + 3 + 1 < sizeof (buf
));
5398 strcpy (buf
, pseudo
? "" : code
);
5399 strcat (buf
, "\n\t}");
5400 tilegx_in_bundle
= false;
5406 return pseudo
? "" : code
;
5411 /* Output assembler code to FILE to increment profiler label # LABELNO
5412 for profiling a function entry. */
5414 tilegx_function_profiler (FILE *file
, int labelno ATTRIBUTE_UNUSED
)
5416 if (tilegx_in_bundle
)
5418 fprintf (file
, "\t}\n");
5427 "\t}\n", MCOUNT_NAME
);
5435 "\t}\n", MCOUNT_NAME
);
5438 tilegx_in_bundle
= false;
5442 /* Implement TARGET_ASM_FILE_END. */
5444 tilegx_file_end (void)
5446 if (NEED_INDICATE_EXEC_STACK
)
5447 file_end_indicate_exec_stack ();
5452 #undef TARGET_HAVE_TLS
5453 #define TARGET_HAVE_TLS HAVE_AS_TLS
5455 #undef TARGET_OPTION_OVERRIDE
5456 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5458 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5459 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5461 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5462 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5464 #undef TARGET_CANNOT_FORCE_CONST_MEM
5465 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5467 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5468 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5470 #undef TARGET_PASS_BY_REFERENCE
5471 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5473 #undef TARGET_RETURN_IN_MEMORY
5474 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5476 #undef TARGET_MODE_REP_EXTENDED
5477 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5479 #undef TARGET_FUNCTION_ARG_BOUNDARY
5480 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5482 #undef TARGET_FUNCTION_ARG
5483 #define TARGET_FUNCTION_ARG tilegx_function_arg
5485 #undef TARGET_FUNCTION_ARG_ADVANCE
5486 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5488 #undef TARGET_FUNCTION_VALUE
5489 #define TARGET_FUNCTION_VALUE tilegx_function_value
5491 #undef TARGET_LIBCALL_VALUE
5492 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5494 #undef TARGET_FUNCTION_VALUE_REGNO_P
5495 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5497 #undef TARGET_PROMOTE_FUNCTION_MODE
5498 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5500 #undef TARGET_PROMOTE_PROTOTYPES
5501 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5503 #undef TARGET_BUILD_BUILTIN_VA_LIST
5504 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5506 #undef TARGET_EXPAND_BUILTIN_VA_START
5507 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5509 #undef TARGET_SETUP_INCOMING_VARARGS
5510 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5512 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5513 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5515 #undef TARGET_RTX_COSTS
5516 #define TARGET_RTX_COSTS tilegx_rtx_costs
5518 #undef TARGET_SHIFT_TRUNCATION_MASK
5519 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5521 #undef TARGET_INIT_LIBFUNCS
5522 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5524 /* Limit to what we can reach in one addli. */
5525 #undef TARGET_MIN_ANCHOR_OFFSET
5526 #define TARGET_MIN_ANCHOR_OFFSET -32768
5527 #undef TARGET_MAX_ANCHOR_OFFSET
5528 #define TARGET_MAX_ANCHOR_OFFSET 32767
5530 #undef TARGET_LEGITIMATE_CONSTANT_P
5531 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5533 #undef TARGET_LEGITIMATE_ADDRESS_P
5534 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5536 #undef TARGET_LEGITIMIZE_ADDRESS
5537 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5539 #undef TARGET_DELEGITIMIZE_ADDRESS
5540 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5542 #undef TARGET_INIT_BUILTINS
5543 #define TARGET_INIT_BUILTINS tilegx_init_builtins
5545 #undef TARGET_BUILTIN_DECL
5546 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5548 #undef TARGET_EXPAND_BUILTIN
5549 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5551 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5552 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5554 #undef TARGET_FRAME_POINTER_REQUIRED
5555 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5557 #undef TARGET_DELAY_SCHED2
5558 #define TARGET_DELAY_SCHED2 true
5560 #undef TARGET_DELAY_VARTRACK
5561 #define TARGET_DELAY_VARTRACK true
5563 #undef TARGET_SCHED_ISSUE_RATE
5564 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5566 #undef TARGET_SCHED_ADJUST_COST
5567 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5569 #undef TARGET_MACHINE_DEPENDENT_REORG
5570 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5572 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5573 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5574 hook_bool_const_tree_hwi_hwi_const_tree_true
5576 #undef TARGET_ASM_OUTPUT_MI_THUNK
5577 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5579 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5580 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5582 #undef TARGET_TRAMPOLINE_INIT
5583 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5585 #undef TARGET_PRINT_OPERAND
5586 #define TARGET_PRINT_OPERAND tilegx_print_operand
5588 #undef TARGET_PRINT_OPERAND_ADDRESS
5589 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5591 #undef TARGET_ASM_FILE_END
5592 #define TARGET_ASM_FILE_END tilegx_file_end
5594 #undef TARGET_ASM_ALIGNED_DI_OP
5595 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5597 #undef TARGET_CAN_USE_DOLOOP_P
5598 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
5600 struct gcc_target targetm
= TARGET_INITIALIZER
;
5602 #include "gt-tilegx.h"