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"
45 #include "tilegx-builtins.h"
46 #include "tilegx-multiply.h"
47 #include "diagnostic.h"
49 /* SYMBOL_REF for GOT */
50 static GTY(()) rtx g_got_symbol
= NULL
;
52 /* In case of a POST_INC or POST_DEC memory reference, we must report
53 the mode of the memory reference from TARGET_PRINT_OPERAND to
54 TARGET_PRINT_OPERAND_ADDRESS. */
55 static enum machine_mode output_memory_reference_mode
;
57 /* Report whether we're printing out the first address fragment of a
58 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
59 TARGET_PRINT_OPERAND_ADDRESS. */
60 static bool output_memory_autoinc_first
;
66 /* Implement TARGET_OPTION_OVERRIDE. */
68 tilegx_option_override (void)
70 if (global_options_set
.x_tilegx_cmodel
)
72 switch (tilegx_cmodel
)
77 tilegx_cmodel
= CM_SMALL_PIC
;
83 tilegx_cmodel
= CM_LARGE_PIC
;
91 tilegx_cmodel
= flag_pic
? CM_SMALL_PIC
: CM_SMALL
;
93 /* When modulo scheduling is enabled, we still rely on regular
94 scheduler for bundling. */
95 if (flag_modulo_sched
)
96 flag_resched_modulo_sched
= 1;
101 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
103 tilegx_scalar_mode_supported_p (enum machine_mode mode
)
124 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
126 tilegx_vector_mode_supported_p (enum machine_mode mode
)
128 return mode
== V8QImode
|| mode
== V4HImode
|| mode
== V2SImode
;
132 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
134 tilegx_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED
,
135 rtx x ATTRIBUTE_UNUSED
)
141 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
143 tilegx_function_ok_for_sibcall (tree decl
, tree exp ATTRIBUTE_UNUSED
)
145 return (tilegx_cmodel
!= CM_LARGE
&& tilegx_cmodel
!= CM_LARGE_PIC
150 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
151 passed by reference. */
153 tilegx_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED
,
154 enum machine_mode mode ATTRIBUTE_UNUSED
,
155 const_tree type
, bool named ATTRIBUTE_UNUSED
)
157 return (type
&& TYPE_SIZE (type
)
158 && TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
);
162 /* Implement TARGET_RETURN_IN_MEMORY. */
164 tilegx_return_in_memory (const_tree type
, const_tree fndecl ATTRIBUTE_UNUSED
)
166 return !IN_RANGE (int_size_in_bytes (type
),
167 0, TILEGX_NUM_RETURN_REGS
* UNITS_PER_WORD
);
171 /* Implement TARGET_MODE_REP_EXTENDED. */
173 tilegx_mode_rep_extended (enum machine_mode mode
, enum machine_mode mode_rep
)
175 /* SImode register values are sign-extended to DImode. */
176 if (mode
== SImode
&& mode_rep
== DImode
)
183 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
185 tilegx_function_arg_boundary (enum machine_mode mode
, const_tree type
)
187 unsigned int alignment
;
189 alignment
= type
? TYPE_ALIGN (type
) : GET_MODE_ALIGNMENT (mode
);
190 if (alignment
< PARM_BOUNDARY
)
191 alignment
= PARM_BOUNDARY
;
192 if (alignment
> STACK_BOUNDARY
)
193 alignment
= STACK_BOUNDARY
;
198 /* Implement TARGET_FUNCTION_ARG. */
200 tilegx_function_arg (cumulative_args_t cum_v
,
201 enum machine_mode mode
,
202 const_tree type
, bool named ATTRIBUTE_UNUSED
)
204 CUMULATIVE_ARGS cum
= *get_cumulative_args (cum_v
);
205 int byte_size
= ((mode
== BLKmode
)
206 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
208 if (cum
>= TILEGX_NUM_ARG_REGS
)
211 /* The ABI does not allow parameters to be passed partially in reg
212 and partially in stack. */
213 if ((cum
+ (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
)
214 > TILEGX_NUM_ARG_REGS
)
217 return gen_rtx_REG (mode
, cum
);
221 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
223 tilegx_function_arg_advance (cumulative_args_t cum_v
,
224 enum machine_mode mode
,
225 const_tree type
, bool named ATTRIBUTE_UNUSED
)
227 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
229 int byte_size
= ((mode
== BLKmode
)
230 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
231 int word_size
= (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
233 /* If the current argument does not fit in the pretend_args space,
235 if (*cum
< TILEGX_NUM_ARG_REGS
236 && *cum
+ word_size
> TILEGX_NUM_ARG_REGS
)
237 *cum
= TILEGX_NUM_ARG_REGS
;
243 /* Implement TARGET_FUNCTION_VALUE. */
245 tilegx_function_value (const_tree valtype
, const_tree fn_decl_or_type
,
246 bool outgoing ATTRIBUTE_UNUSED
)
248 enum machine_mode mode
;
251 mode
= TYPE_MODE (valtype
);
252 unsigned_p
= TYPE_UNSIGNED (valtype
);
254 mode
= promote_function_mode (valtype
, mode
, &unsigned_p
,
257 return gen_rtx_REG (mode
, 0);
261 /* Implement TARGET_LIBCALL_VALUE. */
263 tilegx_libcall_value (enum machine_mode mode
,
264 const_rtx fun ATTRIBUTE_UNUSED
)
266 return gen_rtx_REG (mode
, 0);
270 /* Implement FUNCTION_VALUE_REGNO_P. */
272 tilegx_function_value_regno_p (const unsigned int regno
)
274 return regno
< TILEGX_NUM_RETURN_REGS
;
278 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
280 tilegx_build_builtin_va_list (void)
282 tree f_args
, f_skip
, record
, type_decl
;
285 record
= lang_hooks
.types
.make_type (RECORD_TYPE
);
287 type_decl
= build_decl (BUILTINS_LOCATION
, TYPE_DECL
,
288 get_identifier ("__va_list_tag"), record
);
290 f_args
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
291 get_identifier ("__args"), ptr_type_node
);
292 f_skip
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
293 get_identifier ("__skip"), ptr_type_node
);
295 DECL_FIELD_CONTEXT (f_args
) = record
;
297 DECL_FIELD_CONTEXT (f_skip
) = record
;
299 TREE_CHAIN (record
) = type_decl
;
300 TYPE_NAME (record
) = type_decl
;
301 TYPE_FIELDS (record
) = f_args
;
302 TREE_CHAIN (f_args
) = f_skip
;
304 /* We know this is being padded and we want it too. It is an
305 internal type so hide the warnings from the user. */
309 layout_type (record
);
313 /* The correct type is an array type of one element. */
318 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
320 tilegx_va_start (tree valist
, rtx nextarg ATTRIBUTE_UNUSED
)
325 f_args
= TYPE_FIELDS (TREE_TYPE (valist
));
326 f_skip
= TREE_CHAIN (f_args
);
329 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
331 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
333 /* Find the __args area. */
334 t
= make_tree (TREE_TYPE (args
), virtual_incoming_args_rtx
);
335 t
= fold_build_pointer_plus_hwi (t
,
337 (crtl
->args
.info
- TILEGX_NUM_ARG_REGS
));
339 if (crtl
->args
.pretend_args_size
> 0)
340 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
342 t
= build2 (MODIFY_EXPR
, TREE_TYPE (args
), args
, t
);
343 TREE_SIDE_EFFECTS (t
) = 1;
344 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
346 /* Find the __skip area. */
347 t
= make_tree (TREE_TYPE (skip
), virtual_incoming_args_rtx
);
348 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
349 t
= build2 (MODIFY_EXPR
, TREE_TYPE (skip
), skip
, t
);
350 TREE_SIDE_EFFECTS (t
) = 1;
351 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
355 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
357 tilegx_setup_incoming_varargs (cumulative_args_t cum
,
358 enum machine_mode mode
,
359 tree type
, int *pretend_args
, int no_rtl
)
361 CUMULATIVE_ARGS local_cum
= *get_cumulative_args (cum
);
364 /* The caller has advanced CUM up to, but not beyond, the last named
365 argument. Advance a local copy of CUM past the last "real" named
366 argument, to find out how many registers are left over. */
367 targetm
.calls
.function_arg_advance (pack_cumulative_args (&local_cum
),
369 first_reg
= local_cum
;
371 if (local_cum
< TILEGX_NUM_ARG_REGS
)
373 *pretend_args
= UNITS_PER_WORD
* (TILEGX_NUM_ARG_REGS
- first_reg
);
377 alias_set_type set
= get_varargs_alias_set ();
379 gen_rtx_MEM (BLKmode
, plus_constant (Pmode
,
380 virtual_incoming_args_rtx
,
381 -STACK_POINTER_OFFSET
-
383 (TILEGX_NUM_ARG_REGS
-
385 MEM_NOTRAP_P (tmp
) = 1;
386 set_mem_alias_set (tmp
, set
);
387 move_block_from_reg (first_reg
, tmp
,
388 TILEGX_NUM_ARG_REGS
- first_reg
);
396 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
397 the va_list structure VALIST as required to retrieve an argument of
398 type TYPE, and returning that argument.
400 ret = va_arg(VALIST, TYPE);
402 generates code equivalent to:
404 paddedsize = (sizeof(TYPE) + 3) & -4;
405 if ( (VALIST.__args + paddedsize > VALIST.__skip)
406 & (VALIST.__args <= VALIST.__skip))
407 addr = VALIST.__skip + STACK_POINTER_OFFSET;
409 addr = VALIST.__args;
410 VALIST.__args = addr + paddedsize;
414 tilegx_gimplify_va_arg_expr (tree valist
, tree type
, gimple_seq
*pre_p
,
415 gimple_seq
*post_p ATTRIBUTE_UNUSED
)
419 HOST_WIDE_INT size
, rsize
;
421 bool pass_by_reference_p
;
423 f_args
= TYPE_FIELDS (va_list_type_node
);
424 f_skip
= TREE_CHAIN (f_args
);
427 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
429 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
431 addr
= create_tmp_var (ptr_type_node
, "va_arg");
433 /* If an object is dynamically sized, a pointer to it is passed
434 instead of the object itself. */
435 pass_by_reference_p
= pass_by_reference (NULL
, TYPE_MODE (type
), type
,
438 if (pass_by_reference_p
)
439 type
= build_pointer_type (type
);
441 size
= int_size_in_bytes (type
);
442 rsize
= ((size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
) * UNITS_PER_WORD
;
444 /* Assert alignment assumption. */
445 gcc_assert (STACK_BOUNDARY
== PARM_BOUNDARY
);
447 /* Build conditional expression to calculate addr. The expression
448 will be gimplified later. */
449 tmp
= fold_build_pointer_plus_hwi (unshare_expr (args
), rsize
);
450 tmp
= build2 (TRUTH_AND_EXPR
, boolean_type_node
,
451 build2 (GT_EXPR
, boolean_type_node
, tmp
, unshare_expr (skip
)),
452 build2 (LE_EXPR
, boolean_type_node
, unshare_expr (args
),
453 unshare_expr (skip
)));
455 tmp
= build3 (COND_EXPR
, ptr_type_node
, tmp
,
456 build2 (POINTER_PLUS_EXPR
, ptr_type_node
, unshare_expr (skip
),
457 size_int (STACK_POINTER_OFFSET
)),
458 unshare_expr (args
));
460 gimplify_assign (addr
, tmp
, pre_p
);
462 /* Update VALIST.__args. */
463 tmp
= fold_build_pointer_plus_hwi (addr
, rsize
);
464 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
466 addr
= fold_convert (build_pointer_type (type
), addr
);
468 if (pass_by_reference_p
)
469 addr
= build_va_arg_indirect_ref (addr
);
471 return build_va_arg_indirect_ref (addr
);
476 /* Implement TARGET_RTX_COSTS. */
478 tilegx_rtx_costs (rtx x
, int code
, int outer_code
, int opno
, int *total
,
484 /* If this is an 8-bit constant, return zero since it can be
485 used nearly anywhere with no cost. If it is a valid operand
486 for an ADD or AND, likewise return 0 if we know it will be
487 used in that context. Otherwise, return 2 since it might be
488 used there later. All other constants take at least two
490 if (satisfies_constraint_I (x
))
495 else if (outer_code
== PLUS
&& add_operand (x
, VOIDmode
))
497 /* Slightly penalize large constants even though we can add
498 them in one instruction, because it forces the use of
499 2-wide bundling mode. */
503 else if (move_operand (x
, SImode
))
505 /* We can materialize in one move. */
506 *total
= COSTS_N_INSNS (1);
511 /* We can materialize in two moves. */
512 *total
= COSTS_N_INSNS (2);
521 *total
= COSTS_N_INSNS (2);
525 *total
= COSTS_N_INSNS (4);
533 /* If outer-code was a sign or zero extension, a cost of
534 COSTS_N_INSNS (1) was already added in, so account for
536 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
537 *total
= COSTS_N_INSNS (1);
539 *total
= COSTS_N_INSNS (2);
543 /* Convey that shl[123]add are efficient. */
544 if (GET_CODE (XEXP (x
, 0)) == MULT
545 && cint_248_operand (XEXP (XEXP (x
, 0), 1), VOIDmode
))
547 *total
= (rtx_cost (XEXP (XEXP (x
, 0), 0),
548 (enum rtx_code
) outer_code
, opno
, speed
)
549 + rtx_cost (XEXP (x
, 1),
550 (enum rtx_code
) outer_code
, opno
, speed
)
551 + COSTS_N_INSNS (1));
557 *total
= COSTS_N_INSNS (2);
564 /* These are handled by software and are very expensive. */
565 *total
= COSTS_N_INSNS (100);
569 case UNSPEC_VOLATILE
:
571 int num
= XINT (x
, 1);
573 if (num
<= TILEGX_LAST_LATENCY_1_INSN
)
574 *total
= COSTS_N_INSNS (1);
575 else if (num
<= TILEGX_LAST_LATENCY_2_INSN
)
576 *total
= COSTS_N_INSNS (2);
577 else if (num
> TILEGX_LAST_LATENCY_INSN
)
579 if (num
== UNSPEC_NON_TEMPORAL
)
581 /* These are basically loads. */
582 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
583 *total
= COSTS_N_INSNS (1);
585 *total
= COSTS_N_INSNS (2);
589 if (outer_code
== PLUS
)
592 *total
= COSTS_N_INSNS (1);
599 case UNSPEC_BLOCKAGE
:
600 case UNSPEC_NETWORK_BARRIER
:
605 case UNSPEC_LNK_AND_LABEL
:
607 case UNSPEC_MOV_PCREL_STEP3
:
608 case UNSPEC_NETWORK_RECEIVE
:
609 case UNSPEC_NETWORK_SEND
:
610 case UNSPEC_SPR_MOVE
:
611 case UNSPEC_TLS_GD_ADD
:
612 *total
= COSTS_N_INSNS (1);
615 case UNSPEC_TLS_IE_LOAD
:
617 *total
= COSTS_N_INSNS (2);
621 *total
= COSTS_N_INSNS (3);
625 *total
= COSTS_N_INSNS (4);
629 case UNSPEC_INSN_CMPEXCH
:
630 case UNSPEC_LATENCY_L2
:
631 *total
= COSTS_N_INSNS (11);
634 case UNSPEC_TLS_GD_CALL
:
635 *total
= COSTS_N_INSNS (30);
638 case UNSPEC_LATENCY_MISS
:
639 *total
= COSTS_N_INSNS (80);
643 *total
= COSTS_N_INSNS (1);
658 /* Create a temporary variable to hold a partial result, to enable
661 create_temp_reg_if_possible (enum machine_mode mode
, rtx default_reg
)
663 return can_create_pseudo_p () ? gen_reg_rtx (mode
) : default_reg
;
667 /* Functions to save and restore machine-specific function data. */
668 static struct machine_function
*
669 tilegx_init_machine_status (void)
671 return ggc_alloc_cleared_machine_function ();
675 /* Do anything needed before RTL is emitted for each function. */
677 tilegx_init_expanders (void)
679 /* Arrange to initialize and mark the machine per-function
681 init_machine_status
= tilegx_init_machine_status
;
683 if (cfun
&& cfun
->machine
&& flag_pic
)
685 static int label_num
= 0;
687 char text_label_name
[32];
689 struct machine_function
*machine
= cfun
->machine
;
691 ASM_GENERATE_INTERNAL_LABEL (text_label_name
, "L_PICLNK", label_num
++);
693 machine
->text_label_symbol
=
694 gen_rtx_SYMBOL_REF (Pmode
, ggc_strdup (text_label_name
));
696 machine
->text_label_rtx
=
697 gen_rtx_REG (Pmode
, TILEGX_PIC_TEXT_LABEL_REGNUM
);
699 machine
->got_rtx
= gen_rtx_REG (Pmode
, PIC_OFFSET_TABLE_REGNUM
);
701 machine
->calls_tls_get_addr
= false;
706 /* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode
707 matching insns and therefore guarantee that the shift count is
708 modulo 64. SImode shifts sometimes use the 64 bit version so do
709 not hold such guarantee. */
710 static unsigned HOST_WIDE_INT
711 tilegx_shift_truncation_mask (enum machine_mode mode
)
713 return mode
== DImode
? 63 : 0;
717 /* Implement TARGET_INIT_LIBFUNCS. */
719 tilegx_init_libfuncs (void)
721 /* We need to explicitly generate these libfunc's to support
722 conversion of divide by constant to multiply (the divide stubs in
723 tilegx.md exist also for this reason). Normally we'd expect gcc
724 to lazily generate them when they are needed, but for some reason
725 it's set up to only generate them if the mode is the word
727 set_optab_libfunc (sdiv_optab
, SImode
, "__divsi3");
728 set_optab_libfunc (udiv_optab
, SImode
, "__udivsi3");
729 set_optab_libfunc (smod_optab
, SImode
, "__modsi3");
730 set_optab_libfunc (umod_optab
, SImode
, "__umodsi3");
734 /* Return true if X contains a thread-local symbol. */
736 tilegx_tls_referenced_p (rtx x
)
738 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == PLUS
)
739 x
= XEXP (XEXP (x
, 0), 0);
741 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
))
744 /* That's all we handle in tilegx_legitimize_tls_address for
750 /* Return true if X requires a scratch register. It is given that
751 flag_pic is on and that X satisfies CONSTANT_P. */
753 tilegx_pic_address_needs_scratch (rtx x
)
755 if (GET_CODE (x
) == CONST
756 && GET_CODE (XEXP (x
, 0)) == PLUS
757 && (GET_CODE (XEXP (XEXP (x
, 0), 0)) == SYMBOL_REF
758 || GET_CODE (XEXP (XEXP (x
, 0), 0)) == LABEL_REF
)
759 && (CONST_INT_P (XEXP (XEXP (x
, 0), 1))))
766 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
767 which we are willing to load the value into a register via a move
768 pattern. TLS cannot be treated as a constant because it can
769 include a function call. */
771 tilegx_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
773 switch (GET_CODE (x
))
777 return !tilegx_tls_referenced_p (x
);
785 /* Return true if the constant value X is a legitimate general operand
786 when generating PIC code. It is given that flag_pic is on and that
787 X satisfies CONSTANT_P. */
789 tilegx_legitimate_pic_operand_p (rtx x
)
791 if (tilegx_pic_address_needs_scratch (x
))
794 if (tilegx_tls_referenced_p (x
))
801 /* Return true if the rtx X can be used as an address operand. */
803 tilegx_legitimate_address_p (enum machine_mode
ARG_UNUSED (mode
), rtx x
,
806 if (GET_CODE (x
) == SUBREG
)
809 switch (GET_CODE (x
))
813 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
820 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
823 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
826 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
829 if (!satisfies_constraint_I (XEXP (XEXP (x
, 1), 1)))
842 /* Check if x is a valid reg. */
847 return REGNO_OK_FOR_BASE_P (REGNO (x
));
853 /* Return the rtx containing SYMBOL_REF to the text label. */
855 tilegx_text_label_symbol (void)
857 return cfun
->machine
->text_label_symbol
;
861 /* Return the register storing the value of the text label. */
863 tilegx_text_label_rtx (void)
865 return cfun
->machine
->text_label_rtx
;
869 /* Return the register storing the value of the global offset
872 tilegx_got_rtx (void)
874 return cfun
->machine
->got_rtx
;
878 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
880 tilegx_got_symbol (void)
882 if (g_got_symbol
== NULL
)
883 g_got_symbol
= gen_rtx_SYMBOL_REF (Pmode
, "_GLOBAL_OFFSET_TABLE_");
889 /* Return a reference to the got to be used by tls references. */
891 tilegx_tls_got (void)
896 crtl
->uses_pic_offset_table
= 1;
897 return tilegx_got_rtx ();
900 temp
= gen_reg_rtx (Pmode
);
901 emit_move_insn (temp
, tilegx_got_symbol ());
907 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
908 this (thread-local) address. */
910 tilegx_legitimize_tls_address (rtx addr
)
914 gcc_assert (can_create_pseudo_p ());
916 if (GET_CODE (addr
) == SYMBOL_REF
)
917 switch (SYMBOL_REF_TLS_MODEL (addr
))
919 case TLS_MODEL_GLOBAL_DYNAMIC
:
920 case TLS_MODEL_LOCAL_DYNAMIC
:
922 rtx r0
, temp
, temp2
, temp3
, got
, last
;
924 ret
= gen_reg_rtx (Pmode
);
925 r0
= gen_rtx_REG (Pmode
, 0);
926 temp
= gen_reg_rtx (Pmode
);
927 temp2
= gen_reg_rtx (Pmode
);
928 temp3
= gen_reg_rtx (Pmode
);
930 got
= tilegx_tls_got ();
933 emit_insn (gen_mov_tls_gd_step1_32bit (temp
, addr
));
934 emit_insn (gen_mov_tls_gd_step2_32bit (temp2
, temp
, addr
));
935 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
939 emit_insn (gen_mov_tls_gd_step1 (temp
, addr
));
940 emit_insn (gen_mov_tls_gd_step2 (temp2
, temp
, addr
));
941 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
944 emit_move_insn (r0
, temp2
);
948 emit_insn (gen_tls_gd_call_32bit (addr
));
952 emit_insn (gen_tls_gd_call (addr
));
955 emit_move_insn (temp3
, r0
);
958 last
= emit_insn (gen_tls_gd_add_32bit (ret
, temp3
, addr
));
960 last
= emit_insn (gen_tls_gd_add (ret
, temp3
, addr
));
962 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
965 case TLS_MODEL_INITIAL_EXEC
:
967 rtx temp
, temp2
, temp3
, got
, last
;
969 ret
= gen_reg_rtx (Pmode
);
970 temp
= gen_reg_rtx (Pmode
);
971 temp2
= gen_reg_rtx (Pmode
);
972 temp3
= gen_reg_rtx (Pmode
);
974 got
= tilegx_tls_got ();
977 emit_insn (gen_mov_tls_ie_step1_32bit (temp
, addr
));
978 emit_insn (gen_mov_tls_ie_step2_32bit (temp2
, temp
, addr
));
979 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
980 emit_insn (gen_tls_ie_load_32bit (temp3
, temp2
, addr
));
984 emit_insn (gen_mov_tls_ie_step1 (temp
, addr
));
985 emit_insn (gen_mov_tls_ie_step2 (temp2
, temp
, addr
));
986 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
987 emit_insn (gen_tls_ie_load (temp3
, temp2
, addr
));
994 THREAD_POINTER_REGNUM
),
996 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
999 case TLS_MODEL_LOCAL_EXEC
:
1001 rtx temp
, temp2
, last
;
1003 ret
= gen_reg_rtx (Pmode
);
1004 temp
= gen_reg_rtx (Pmode
);
1005 temp2
= gen_reg_rtx (Pmode
);
1009 emit_insn (gen_mov_tls_le_step1_32bit (temp
, addr
));
1010 emit_insn (gen_mov_tls_le_step2_32bit (temp2
, temp
, addr
));
1014 emit_insn (gen_mov_tls_le_step1 (temp
, addr
));
1015 emit_insn (gen_mov_tls_le_step2 (temp2
, temp
, addr
));
1019 emit_move_insn (ret
,
1020 gen_rtx_PLUS (Pmode
,
1022 THREAD_POINTER_REGNUM
),
1024 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1030 else if (GET_CODE (addr
) == CONST
)
1034 gcc_assert (GET_CODE (XEXP (addr
, 0)) == PLUS
);
1036 base
= tilegx_legitimize_tls_address (XEXP (XEXP (addr
, 0), 0));
1037 offset
= XEXP (XEXP (addr
, 0), 1);
1039 base
= force_operand (base
, NULL_RTX
);
1040 ret
= force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1049 /* Returns a register that points to ADDR, a symbolic address, by
1050 computing its address relative to tilegx_text_label_symbol. */
1052 tilegx_compute_pcrel_address (rtx result
, rtx addr
)
1054 rtx text_label_symbol
= tilegx_text_label_symbol ();
1055 rtx text_label_rtx
= tilegx_text_label_rtx ();
1056 rtx temp
, temp2
, temp3
;
1058 temp
= create_temp_reg_if_possible (Pmode
, result
);
1059 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1063 emit_insn (gen_mov_pcrel_step1_32bit (temp
, addr
, text_label_symbol
));
1064 emit_insn (gen_mov_pcrel_step2_32bit (temp2
, temp
, addr
,
1065 text_label_symbol
));
1066 emit_insn (gen_mov_pcrel_step3_32bit (result
, temp2
,
1068 addr
, text_label_symbol
));
1070 else if (tilegx_cmodel
== CM_LARGE_PIC
)
1072 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1073 emit_insn (gen_mov_large_pcrel_step1 (temp
, addr
, text_label_symbol
));
1074 emit_insn (gen_mov_large_pcrel_step2 (temp2
, temp
, addr
,
1075 text_label_symbol
));
1076 emit_insn (gen_mov_large_pcrel_step3 (temp3
, temp2
, addr
,
1077 text_label_symbol
));
1078 emit_insn (gen_mov_large_pcrel_step4 (result
, temp3
,
1080 addr
, text_label_symbol
));
1084 emit_insn (gen_mov_pcrel_step1 (temp
, addr
, text_label_symbol
));
1085 emit_insn (gen_mov_pcrel_step2 (temp2
, temp
, addr
, text_label_symbol
));
1086 emit_insn (gen_mov_pcrel_step3 (result
, temp2
,
1088 addr
, text_label_symbol
));
1093 /* Returns a register that points to the plt entry of ADDR, a symbolic
1094 address, by computing its address relative to
1095 tilegx_text_label_symbol. */
1097 tilegx_compute_pcrel_plt_address (rtx result
, rtx addr
)
1099 rtx text_label_symbol
= tilegx_text_label_symbol ();
1100 rtx text_label_rtx
= tilegx_text_label_rtx ();
1101 rtx temp
, temp2
, temp3
;
1103 temp
= create_temp_reg_if_possible (Pmode
, result
);
1104 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1108 emit_insn (gen_mov_plt_pcrel_step1_32bit (temp
, addr
,
1109 text_label_symbol
));
1110 emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2
, temp
, addr
,
1111 text_label_symbol
));
1112 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp2
, text_label_rtx
));
1116 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1118 emit_insn (gen_mov_plt_pcrel_step1 (temp
, addr
, text_label_symbol
));
1119 emit_insn (gen_mov_plt_pcrel_step2 (temp2
, temp
, addr
,
1120 text_label_symbol
));
1121 emit_insn (gen_mov_plt_pcrel_step3 (temp3
, temp2
, addr
,
1122 text_label_symbol
));
1123 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp3
, text_label_rtx
));
1128 /* Legitimize PIC addresses. If the address is already
1129 position-independent, we return ORIG. Newly generated
1130 position-independent addresses go into a reg. This is REG if
1131 nonzero, otherwise we allocate register(s) as necessary. */
1133 tilegx_legitimize_pic_address (rtx orig
,
1134 enum machine_mode mode ATTRIBUTE_UNUSED
,
1137 if (GET_CODE (orig
) == SYMBOL_REF
)
1139 rtx address
, pic_ref
;
1143 gcc_assert (can_create_pseudo_p ());
1144 reg
= gen_reg_rtx (Pmode
);
1147 if (SYMBOL_REF_LOCAL_P (orig
))
1149 /* If not during reload, allocate another temp reg here for
1150 loading in the address, so that these instructions can be
1151 optimized properly. */
1152 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1153 tilegx_compute_pcrel_address (temp_reg
, orig
);
1155 /* Note: this is conservative. We use the text_label but we
1156 don't use the pic_offset_table. However, in some cases
1157 we may need the pic_offset_table (see
1158 tilegx_fixup_pcrel_references). */
1159 crtl
->uses_pic_offset_table
= 1;
1163 emit_move_insn (reg
, address
);
1168 /* If not during reload, allocate another temp reg here for
1169 loading in the address, so that these instructions can be
1170 optimized properly. */
1171 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1173 gcc_assert (flag_pic
);
1178 emit_insn (gen_add_got16_32bit (temp_reg
,
1184 emit_insn (gen_add_got16 (temp_reg
,
1185 tilegx_got_rtx (), orig
));
1190 rtx temp_reg2
= create_temp_reg_if_possible (Pmode
, reg
);
1191 rtx temp_reg3
= create_temp_reg_if_possible (Pmode
, reg
);
1194 emit_insn (gen_mov_got32_step1_32bit (temp_reg3
, orig
));
1195 emit_insn (gen_mov_got32_step2_32bit
1196 (temp_reg2
, temp_reg3
, orig
));
1200 emit_insn (gen_mov_got32_step1 (temp_reg3
, orig
));
1201 emit_insn (gen_mov_got32_step2 (temp_reg2
, temp_reg3
,
1204 emit_move_insn (temp_reg
,
1205 gen_rtx_PLUS (Pmode
,
1206 tilegx_got_rtx (), temp_reg2
));
1211 pic_ref
= gen_const_mem (Pmode
, address
);
1212 crtl
->uses_pic_offset_table
= 1;
1213 emit_move_insn (reg
, pic_ref
);
1214 /* The following put a REG_EQUAL note on this insn, so that
1215 it can be optimized by loop. But it causes the label to
1216 be optimized away. */
1217 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1221 else if (GET_CODE (orig
) == CONST
)
1225 if (GET_CODE (XEXP (orig
, 0)) == PLUS
1226 && XEXP (XEXP (orig
, 0), 0) == tilegx_got_rtx ())
1231 gcc_assert (can_create_pseudo_p ());
1232 reg
= gen_reg_rtx (Pmode
);
1235 gcc_assert (GET_CODE (XEXP (orig
, 0)) == PLUS
);
1236 base
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 0),
1238 offset
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 1), Pmode
,
1239 base
== reg
? 0 : reg
);
1241 if (CONST_INT_P (offset
))
1243 if (can_create_pseudo_p ())
1244 offset
= force_reg (Pmode
, offset
);
1246 /* If we reach here, then something is seriously wrong. */
1250 if (can_create_pseudo_p ())
1251 return force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1255 else if (GET_CODE (orig
) == LABEL_REF
)
1262 gcc_assert (can_create_pseudo_p ());
1263 reg
= gen_reg_rtx (Pmode
);
1266 /* If not during reload, allocate another temp reg here for
1267 loading in the address, so that these instructions can be
1268 optimized properly. */
1269 temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1270 tilegx_compute_pcrel_address (temp_reg
, orig
);
1272 /* Note: this is conservative. We use the text_label but we
1273 don't use the pic_offset_table. */
1274 crtl
->uses_pic_offset_table
= 1;
1278 emit_move_insn (reg
, address
);
1287 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1289 tilegx_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
1290 enum machine_mode mode
)
1292 if (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
1293 && symbolic_operand (x
, Pmode
) && tilegx_tls_referenced_p (x
))
1295 return tilegx_legitimize_tls_address (x
);
1299 return tilegx_legitimize_pic_address (x
, mode
, 0);
1306 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1308 tilegx_delegitimize_address (rtx x
)
1310 x
= delegitimize_mem_from_attrs (x
);
1312 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == UNSPEC
)
1314 switch (XINT (XEXP (x
, 0), 1))
1320 case UNSPEC_HW0_LAST
:
1321 case UNSPEC_HW1_LAST
:
1322 case UNSPEC_HW2_LAST
:
1323 case UNSPEC_HW0_PCREL
:
1324 case UNSPEC_HW1_PCREL
:
1325 case UNSPEC_HW1_LAST_PCREL
:
1326 case UNSPEC_HW2_LAST_PCREL
:
1327 case UNSPEC_HW0_PLT_PCREL
:
1328 case UNSPEC_HW1_PLT_PCREL
:
1329 case UNSPEC_HW1_LAST_PLT_PCREL
:
1330 case UNSPEC_HW2_LAST_PLT_PCREL
:
1331 case UNSPEC_HW0_GOT
:
1332 case UNSPEC_HW0_LAST_GOT
:
1333 case UNSPEC_HW1_LAST_GOT
:
1334 case UNSPEC_HW0_TLS_GD
:
1335 case UNSPEC_HW1_LAST_TLS_GD
:
1336 case UNSPEC_HW0_TLS_IE
:
1337 case UNSPEC_HW1_LAST_TLS_IE
:
1338 case UNSPEC_HW0_TLS_LE
:
1339 case UNSPEC_HW1_LAST_TLS_LE
:
1340 x
= XVECEXP (XEXP (x
, 0), 0, 0);
1349 /* Emit code to load the PIC register. */
1351 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED
)
1353 int orig_flag_pic
= flag_pic
;
1355 rtx got_symbol
= tilegx_got_symbol ();
1356 rtx text_label_symbol
= tilegx_text_label_symbol ();
1357 rtx text_label_rtx
= tilegx_text_label_rtx ();
1362 emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx
,
1363 text_label_symbol
));
1367 emit_insn (gen_insn_lnk_and_label (text_label_rtx
, text_label_symbol
));
1370 tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol
);
1372 flag_pic
= orig_flag_pic
;
1374 /* Need to emit this whether or not we obey regdecls, since
1375 setjmp/longjmp can cause life info to screw up. ??? In the case
1376 where we don't obey regdecls, this is not sufficient since we may
1377 not fall out the bottom. */
1378 emit_use (tilegx_got_rtx ());
1382 /* Return the simd variant of the constant NUM of mode MODE, by
1383 replicating it to fill an interger of mode DImode. NUM is first
1384 truncated to fit in MODE. */
1386 tilegx_simd_int (rtx num
, enum machine_mode mode
)
1388 HOST_WIDE_INT n
= 0;
1390 gcc_assert (CONST_INT_P (num
));
1397 n
= 0x0101010101010101LL
* (n
& 0x000000FF);
1400 n
= 0x0001000100010001LL
* (n
& 0x0000FFFF);
1403 n
= 0x0000000100000001LL
* (n
& 0xFFFFFFFF);
1415 /* Returns true iff VAL can be moved into a register in one
1416 instruction. And if it can, it emits the code to move the constant
1419 If THREE_WIDE_ONLY is true, this insists on an instruction that
1420 works in a bundle containing three instructions. */
1422 expand_set_cint64_one_inst (rtx dest_reg
,
1423 HOST_WIDE_INT val
, bool three_wide_only
)
1425 if (val
== trunc_int_for_mode (val
, QImode
))
1428 emit_move_insn (dest_reg
, GEN_INT (val
));
1431 else if (!three_wide_only
)
1433 /* Test for the following constraints: J, K, N, P. We avoid
1434 generating an rtx and using existing predicates because we
1435 can be testing and rejecting a lot of constants, and GEN_INT
1437 if ((val
>= -32768 && val
<= 65535)
1438 || ((val
== (val
& 0xFF) * 0x0101010101010101LL
))
1439 || (val
== ((trunc_int_for_mode (val
, QImode
) & 0xFFFF)
1440 * 0x0001000100010001LL
)))
1442 emit_move_insn (dest_reg
, GEN_INT (val
));
1451 /* Implement DImode rotatert. */
1452 static HOST_WIDE_INT
1453 rotate_right (HOST_WIDE_INT n
, int count
)
1455 unsigned HOST_WIDE_INT x
= n
& 0xFFFFFFFFFFFFFFFFULL
;
1458 return ((x
>> count
) | (x
<< (64 - count
))) & 0xFFFFFFFFFFFFFFFFULL
;
1462 /* Return true iff n contains exactly one contiguous sequence of 1
1463 bits, possibly wrapping around from high bits to low bits. */
1465 tilegx_bitfield_operand_p (HOST_WIDE_INT n
, int *first_bit
, int *last_bit
)
1472 for (i
= 0; i
< 64; i
++)
1474 unsigned HOST_WIDE_INT x
= rotate_right (n
, i
);
1478 /* See if x is a power of two minus one, i.e. only consecutive 1
1479 bits starting from bit 0. */
1480 if ((x
& (x
+ 1)) == 0)
1482 if (first_bit
!= NULL
)
1484 if (last_bit
!= NULL
)
1485 *last_bit
= (i
+ exact_log2 (x
^ (x
>> 1))) & 63;
1495 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1497 expand_set_cint64 (rtx dest_reg
, rtx src_val
)
1500 int leading_zeroes
, trailing_zeroes
;
1501 int three_wide_only
;
1502 int shift
, ins_shift
, zero_cluster_shift
;
1505 gcc_assert (CONST_INT_P (src_val
));
1506 val
= trunc_int_for_mode (INTVAL (src_val
), GET_MODE (dest_reg
));
1508 /* See if we can generate the constant in one instruction. */
1509 if (expand_set_cint64_one_inst (dest_reg
, val
, false))
1512 /* Force the destination to DImode so we can use DImode instructions
1513 to create it. This both allows instructions like rotl, and
1514 certain efficient 3-wide instructions. */
1515 subreg
= simplify_gen_subreg (DImode
, dest_reg
, GET_MODE (dest_reg
), 0);
1516 gcc_assert (subreg
!= NULL
);
1519 temp
= create_temp_reg_if_possible (DImode
, dest_reg
);
1521 leading_zeroes
= 63 - floor_log2 (val
& 0xFFFFFFFFFFFFFFFFULL
);
1522 trailing_zeroes
= exact_log2 (val
& -val
);
1524 /* First try all three-wide instructions that generate a constant
1525 (i.e. movei) followed by various shifts and rotates. If none of
1526 those work, try various two-wide ways of generating a constant
1527 followed by various shifts and rotates. */
1528 for (three_wide_only
= 1; three_wide_only
>= 0; three_wide_only
--)
1532 if (expand_set_cint64_one_inst (temp
, val
>> trailing_zeroes
,
1535 /* 0xFFFFFFFFFFFFA500 becomes:
1536 movei temp, 0xFFFFFFFFFFFFFFA5
1537 shli dest, temp, 8 */
1538 emit_move_insn (dest_reg
,
1539 gen_rtx_ASHIFT (DImode
, temp
,
1540 GEN_INT (trailing_zeroes
)));
1544 if (expand_set_cint64_one_inst (temp
, val
<< leading_zeroes
,
1547 /* 0x7FFFFFFFFFFFFFFF becomes:
1549 shrui dest, temp, 1 */
1550 emit_move_insn (dest_reg
,
1551 gen_rtx_LSHIFTRT (DImode
, temp
,
1552 GEN_INT (leading_zeroes
)));
1556 /* Try rotating a one-instruction immediate. */
1557 for (count
= 1; count
< 64; count
++)
1559 HOST_WIDE_INT r
= rotate_right (val
, count
);
1560 if (expand_set_cint64_one_inst (temp
, r
, three_wide_only
))
1562 /* 0xFFFFFFFFFFA5FFFF becomes:
1563 movei temp, 0xFFFFFFFFFFFFFFA5
1564 rotli dest, temp, 16 */
1565 emit_move_insn (dest_reg
,
1566 gen_rtx_ROTATE (DImode
, temp
, GEN_INT (count
)));
1572 /* There are two cases here to produce a large constant.
1573 In the most general case, we do this:
1576 shl16insli x, x, hw2(NUM)
1577 shl16insli x, x, hw1(NUM)
1578 shl16insli x, x, hw0(NUM)
1580 However, we can sometimes do better. shl16insli is a poor way to
1581 insert 16 zero bits, because simply shifting left by 16 has more
1582 bundling freedom. So if we see any contiguous aligned sequence
1583 of 16 or more zero bits (below the highest set bit), it is always
1584 more efficient to materialize the bits above the zero bits, then
1585 left shift to put in the zeroes, then insert whatever bits
1586 remain. For example, we might end up with:
1588 movei x, NUM >> (37 + 16)
1590 shl16insli x, x, hw0(NUM) */
1592 zero_cluster_shift
= -1;
1594 for (shift
= 0; shift
< 48 - leading_zeroes
; shift
+= 16)
1596 HOST_WIDE_INT x
= val
>> shift
;
1598 /* Find the least significant group of 16 aligned zero bits. */
1599 if ((x
& 0xFFFF) == 0x0000)
1601 /* Grab any following zero bits as well. */
1602 zero_cluster_shift
= exact_log2 (x
& -x
);
1603 shift
+= zero_cluster_shift
;
1608 if (zero_cluster_shift
>= 0)
1610 unsigned HOST_WIDE_INT leftover
;
1612 /* Recursively create the constant above the lowest 16 zero
1614 expand_set_cint64 (temp
, GEN_INT (val
>> shift
));
1616 /* See if we can easily insert the remaining bits, or if we need
1617 to fall through to the more general case. */
1618 leftover
= val
- ((val
>> shift
) << shift
);
1621 /* A simple left shift is enough. */
1622 emit_move_insn (dest_reg
,
1623 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1626 else if (leftover
<= 32767)
1628 /* Left shift into position then add in the leftover. */
1629 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1630 emit_move_insn (temp2
,
1631 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1632 emit_move_insn (dest_reg
,
1633 gen_rtx_PLUS (DImode
, temp2
, GEN_INT (leftover
)));
1638 /* Shift in the batch of >= 16 zeroes we detected earlier.
1639 After this, shift will be aligned mod 16 so the final
1640 loop can use shl16insli. */
1641 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1642 rtx shift_count_rtx
= GEN_INT (zero_cluster_shift
);
1644 emit_move_insn (temp2
,
1645 gen_rtx_ASHIFT (DImode
, temp
, shift_count_rtx
));
1647 shift
-= zero_cluster_shift
;
1653 /* Set as many high 16-bit blocks as we can with a single
1654 instruction. We'll insert the remaining 16-bit blocks
1656 for (shift
= 16;; shift
+= 16)
1658 gcc_assert (shift
< 64);
1659 if (expand_set_cint64_one_inst (temp
, val
>> shift
, false))
1664 /* At this point, temp == val >> shift, shift % 16 == 0, and we
1665 still need to insert any bits of 'val' below 'shift'. Those bits
1666 are guaranteed to not have 16 contiguous zeroes. */
1668 gcc_assert ((shift
& 15) == 0);
1670 for (ins_shift
= shift
- 16; ins_shift
>= 0; ins_shift
-= 16)
1673 HOST_WIDE_INT bits
= (val
>> ins_shift
) & 0xFFFF;
1674 gcc_assert (bits
!= 0);
1676 /* On the last iteration we need to store into dest_reg. */
1680 result
= create_temp_reg_if_possible (DImode
, dest_reg
);
1682 emit_insn (gen_insn_shl16insli (result
, temp
, GEN_INT (bits
)));
1689 /* Load OP1, a 64-bit constant, into OP0, a register. We know it
1690 can't be done in one insn when we get here, the move expander
1693 tilegx_expand_set_const64 (rtx op0
, rtx op1
)
1695 if (CONST_INT_P (op1
))
1697 /* TODO: I don't know if we want to split large constants
1698 now, or wait until later (with a define_split).
1700 Does splitting early help CSE? Does it harm other
1701 optimizations that might fold loads? */
1702 expand_set_cint64 (op0
, op1
);
1706 rtx temp
= create_temp_reg_if_possible (Pmode
, op0
);
1710 /* Generate the 2-insn sequence to materialize a symbolic
1712 emit_insn (gen_mov_address_32bit_step1 (temp
, op1
));
1713 emit_insn (gen_mov_address_32bit_step2 (op0
, temp
, op1
));
1717 /* Generate the 3-insn sequence to materialize a symbolic
1718 address. Note that this assumes that virtual addresses
1719 fit in 48 signed bits, which is currently true. */
1720 rtx temp2
= create_temp_reg_if_possible (Pmode
, op0
);
1721 emit_insn (gen_mov_address_step1 (temp
, op1
));
1722 emit_insn (gen_mov_address_step2 (temp2
, temp
, op1
));
1723 emit_insn (gen_mov_address_step3 (op0
, temp2
, op1
));
1729 /* Expand a move instruction. Return true if all work is done. */
1731 tilegx_expand_mov (enum machine_mode mode
, rtx
*operands
)
1733 /* Handle sets of MEM first. */
1734 if (MEM_P (operands
[0]))
1736 if (can_create_pseudo_p ())
1737 operands
[0] = validize_mem (operands
[0]);
1739 if (reg_or_0_operand (operands
[1], mode
))
1742 if (!reload_in_progress
)
1743 operands
[1] = force_reg (mode
, operands
[1]);
1746 /* Fixup TLS cases. */
1747 if (CONSTANT_P (operands
[1]) && tilegx_tls_referenced_p (operands
[1]))
1749 operands
[1] = tilegx_legitimize_tls_address (operands
[1]);
1753 /* Fixup PIC cases. */
1754 if (flag_pic
&& CONSTANT_P (operands
[1]))
1756 if (tilegx_pic_address_needs_scratch (operands
[1]))
1757 operands
[1] = tilegx_legitimize_pic_address (operands
[1], mode
, 0);
1759 if (symbolic_operand (operands
[1], mode
))
1761 operands
[1] = tilegx_legitimize_pic_address (operands
[1],
1763 (reload_in_progress
?
1770 /* Accept non-constants and valid constants unmodified. */
1771 if (!CONSTANT_P (operands
[1]) || move_operand (operands
[1], mode
))
1774 /* Split large integers. */
1775 tilegx_expand_set_const64 (operands
[0], operands
[1]);
1780 /* Expand unaligned loads. */
1782 tilegx_expand_unaligned_load (rtx dest_reg
, rtx mem
, HOST_WIDE_INT bitsize
,
1783 HOST_WIDE_INT bit_offset
, bool sign
)
1785 enum machine_mode mode
;
1786 rtx addr_lo
, addr_hi
;
1787 rtx mem_lo
, mem_hi
, hi
;
1788 rtx mema
, wide_result
;
1789 int last_byte_offset
;
1790 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1792 mode
= GET_MODE (dest_reg
);
1794 hi
= gen_reg_rtx (mode
);
1796 if (bitsize
== 2 * BITS_PER_UNIT
&& (bit_offset
% BITS_PER_UNIT
) == 0)
1798 /* When just loading a two byte value, we can load the two bytes
1799 individually and combine them efficiently. */
1801 mem_lo
= adjust_address (mem
, QImode
, byte_offset
);
1802 mem_hi
= adjust_address (mem
, QImode
, byte_offset
+ 1);
1806 /* Do a signed load of the second byte and use bfins to set
1807 the high bits of the result. */
1808 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, dest_reg
),
1810 emit_insn (gen_extendqidi2 (gen_lowpart (DImode
, hi
), mem_hi
));
1811 emit_insn (gen_insv (gen_lowpart (DImode
, dest_reg
),
1812 GEN_INT (64 - 8), GEN_INT (8),
1813 gen_lowpart (DImode
, hi
)));
1817 /* Do two unsigned loads and use v1int_l to interleave
1819 rtx lo
= gen_reg_rtx (mode
);
1820 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, lo
),
1822 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, hi
),
1824 emit_insn (gen_insn_v1int_l (gen_lowpart (DImode
, dest_reg
),
1825 gen_lowpart (DImode
, hi
),
1826 gen_lowpart (DImode
, lo
)));
1832 mema
= XEXP (mem
, 0);
1834 /* AND addresses cannot be in any alias set, since they may
1835 implicitly alias surrounding code. Ideally we'd have some alias
1836 set that covered all types except those with alignment 8 or
1838 addr_lo
= force_reg (Pmode
, plus_constant (Pmode
, mema
, byte_offset
));
1839 mem_lo
= change_address (mem
, mode
,
1840 gen_rtx_AND (GET_MODE (mema
), addr_lo
,
1842 set_mem_alias_set (mem_lo
, 0);
1844 /* Load the high word at an address that will not fault if the low
1845 address is aligned and at the very end of a page. */
1846 last_byte_offset
= (bit_offset
+ bitsize
- 1) / BITS_PER_UNIT
;
1847 addr_hi
= force_reg (Pmode
, plus_constant (Pmode
, mema
, last_byte_offset
));
1848 mem_hi
= change_address (mem
, mode
,
1849 gen_rtx_AND (GET_MODE (mema
), addr_hi
,
1851 set_mem_alias_set (mem_hi
, 0);
1855 addr_lo
= make_safe_from (addr_lo
, dest_reg
);
1856 wide_result
= dest_reg
;
1860 wide_result
= gen_reg_rtx (mode
);
1863 /* Load hi first in case dest_reg is used in mema. */
1864 emit_move_insn (hi
, mem_hi
);
1865 emit_move_insn (wide_result
, mem_lo
);
1867 emit_insn (gen_insn_dblalign (gen_lowpart (DImode
, wide_result
),
1868 gen_lowpart (DImode
, wide_result
),
1869 gen_lowpart (DImode
, hi
), addr_lo
));
1874 extract_bit_field (gen_lowpart (DImode
, wide_result
),
1875 bitsize
, bit_offset
% BITS_PER_UNIT
,
1876 !sign
, gen_lowpart (DImode
, dest_reg
),
1879 if (extracted
!= dest_reg
)
1880 emit_move_insn (dest_reg
, gen_lowpart (DImode
, extracted
));
1885 /* Expand unaligned stores. */
1887 tilegx_expand_unaligned_store (rtx mem
, rtx src
, HOST_WIDE_INT bitsize
,
1888 HOST_WIDE_INT bit_offset
)
1890 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1891 HOST_WIDE_INT bytesize
= bitsize
/ BITS_PER_UNIT
;
1892 HOST_WIDE_INT shift_amt
;
1897 for (i
= 0, shift_amt
= 0; i
< bytesize
; i
++, shift_amt
+= BITS_PER_UNIT
)
1899 mem_addr
= adjust_address (mem
, QImode
, byte_offset
+ i
);
1903 store_val
= expand_simple_binop (DImode
, LSHIFTRT
,
1904 gen_lowpart (DImode
, src
),
1905 GEN_INT (shift_amt
), NULL
, 1,
1907 store_val
= gen_lowpart (QImode
, store_val
);
1911 store_val
= gen_lowpart (QImode
, src
);
1914 emit_move_insn (mem_addr
, store_val
);
1919 /* Implement the movmisalign patterns. One of the operands is a
1920 memory that is not naturally aligned. Emit instructions to load
1923 tilegx_expand_movmisalign (enum machine_mode mode
, rtx
*operands
)
1925 if (MEM_P (operands
[1]))
1929 if (register_operand (operands
[0], mode
))
1932 tmp
= gen_reg_rtx (mode
);
1934 tilegx_expand_unaligned_load (tmp
, operands
[1], GET_MODE_BITSIZE (mode
),
1937 if (tmp
!= operands
[0])
1938 emit_move_insn (operands
[0], tmp
);
1940 else if (MEM_P (operands
[0]))
1942 if (!reg_or_0_operand (operands
[1], mode
))
1943 operands
[1] = force_reg (mode
, operands
[1]);
1945 tilegx_expand_unaligned_store (operands
[0], operands
[1],
1946 GET_MODE_BITSIZE (mode
), 0);
1954 /* Implement the allocate_stack pattern (alloca). */
1956 tilegx_allocate_stack (rtx op0
, rtx op1
)
1958 /* Technically the correct way to initialize chain_loc is with
1959 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
1960 * sets the alias_set to that of a frame reference. Some of our
1961 * tests rely on some unsafe assumption about when the chaining
1962 * update is done, we need to be conservative about reordering the
1963 * chaining instructions.
1965 rtx fp_addr
= gen_reg_rtx (Pmode
);
1966 rtx fp_value
= gen_reg_rtx (Pmode
);
1969 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
1970 GEN_INT (UNITS_PER_WORD
)));
1972 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
1974 emit_move_insn (fp_value
, fp_loc
);
1976 op1
= force_reg (Pmode
, op1
);
1978 emit_move_insn (stack_pointer_rtx
,
1979 gen_rtx_MINUS (Pmode
, stack_pointer_rtx
, op1
));
1981 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
1982 GEN_INT (UNITS_PER_WORD
)));
1984 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
1986 emit_move_insn (fp_loc
, fp_value
);
1988 emit_move_insn (op0
, virtual_stack_dynamic_rtx
);
1996 /* Returns the insn_code in ENTRY. */
1997 static enum insn_code
1998 tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry
2001 return tilegx_multiply_insn_seq_decode_opcode
[entry
->compressed_opcode
];
2005 /* Returns the length of the 'op' array. */
2007 tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq
*seq
)
2009 /* The array either uses all of its allocated slots or is terminated
2010 by a bogus opcode. Either way, the array size is the index of the
2011 last valid opcode plus one. */
2013 for (i
= tilegx_multiply_insn_seq_MAX_OPERATIONS
- 1; i
>= 0; i
--)
2014 if (tilegx_multiply_get_opcode (&seq
->op
[i
]) != CODE_FOR_nothing
)
2017 /* An empty array is not allowed. */
2022 /* We precompute a number of expression trees for multiplying by
2023 constants. This generates code for such an expression tree by
2024 walking through the nodes in the tree (which are conveniently
2025 pre-linearized) and emitting an instruction for each one. */
2027 tilegx_expand_constant_multiply_given_sequence (rtx result
, rtx src
,
2029 tilegx_multiply_insn_seq
*seq
)
2034 /* Keep track of the subexpressions computed so far, so later
2035 instructions can refer to them. We seed the array with zero and
2036 the value being multiplied. */
2037 int num_subexprs
= 2;
2038 rtx subexprs
[tilegx_multiply_insn_seq_MAX_OPERATIONS
+ 2];
2039 subexprs
[0] = const0_rtx
;
2042 /* Determine how many instructions we are going to generate. */
2043 num_ops
= tilegx_multiply_get_num_ops (seq
);
2044 gcc_assert (num_ops
> 0
2045 && num_ops
<= tilegx_multiply_insn_seq_MAX_OPERATIONS
);
2047 for (i
= 0; i
< num_ops
; i
++)
2049 const struct tilegx_multiply_insn_seq_entry
*entry
= &seq
->op
[i
];
2051 /* Figure out where to store the output of this instruction. */
2052 const bool is_last_op
= (i
+ 1 == num_ops
);
2053 rtx out
= is_last_op
? result
: gen_reg_rtx (DImode
);
2055 enum insn_code opcode
= tilegx_multiply_get_opcode (entry
);
2056 if (opcode
== CODE_FOR_ashldi3
)
2058 /* Handle shift by immediate. This is a special case because
2059 the meaning of the second operand is a constant shift
2060 count rather than an operand index. */
2062 /* Make sure the shift count is in range. Zero should not
2064 const int shift_count
= entry
->rhs
;
2065 gcc_assert (shift_count
> 0 && shift_count
< 64);
2067 /* Emit the actual instruction. */
2068 emit_insn (GEN_FCN (opcode
)
2069 (out
, subexprs
[entry
->lhs
],
2070 gen_rtx_CONST_INT (DImode
, shift_count
)));
2074 /* Handle a normal two-operand instruction, such as add or
2077 /* Make sure we are referring to a previously computed
2079 gcc_assert (entry
->rhs
< num_subexprs
);
2081 /* Emit the actual instruction. */
2082 emit_insn (GEN_FCN (opcode
)
2083 (out
, subexprs
[entry
->lhs
], subexprs
[entry
->rhs
]));
2086 /* Record this subexpression for use by later expressions. */
2087 subexprs
[num_subexprs
++] = out
;
2092 /* bsearch helper function. */
2094 tilegx_compare_multipliers (const void *key
, const void *t
)
2097 (*(const long long *) key
2098 - ((const struct tilegx_multiply_insn_seq
*) t
)->multiplier
);
2099 return (delta
< 0) ? -1 : (delta
> 0);
2103 /* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none
2105 static const struct tilegx_multiply_insn_seq
*
2106 tilegx_find_multiply_insn_seq_for_constant (long long multiplier
)
2108 return ((const struct tilegx_multiply_insn_seq
*)
2109 bsearch (&multiplier
, tilegx_multiply_insn_seq_table
,
2110 tilegx_multiply_insn_seq_table_size
,
2111 sizeof tilegx_multiply_insn_seq_table
[0],
2112 tilegx_compare_multipliers
));
2116 /* Try to a expand constant multiply in DImode by looking it up in a
2117 precompiled table. OP0 is the result operand, OP1 is the source
2118 operand, and MULTIPLIER is the value of the constant. Return true
2121 tilegx_expand_const_muldi (rtx op0
, rtx op1
, long long multiplier
)
2123 /* See if we have precomputed an efficient way to multiply by this
2125 const struct tilegx_multiply_insn_seq
*seq
=
2126 tilegx_find_multiply_insn_seq_for_constant (multiplier
);
2129 tilegx_expand_constant_multiply_given_sequence (op0
, op1
, seq
);
2137 /* Expand the muldi pattern. */
2139 tilegx_expand_muldi (rtx op0
, rtx op1
, rtx op2
)
2141 if (CONST_INT_P (op2
))
2143 HOST_WIDE_INT n
= trunc_int_for_mode (INTVAL (op2
), DImode
);
2144 return tilegx_expand_const_muldi (op0
, op1
, n
);
2150 /* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the
2151 operands, and SIGN is true if it's a signed multiply, and false if
2152 it's an unsigned multiply. */
2154 tilegx_expand_high_multiply (rtx result
, rtx op1
, rtx op2
, bool sign
)
2156 rtx tmp0
= gen_reg_rtx (DImode
);
2157 rtx tmp1
= gen_reg_rtx (DImode
);
2158 rtx tmp2
= gen_reg_rtx (DImode
);
2159 rtx tmp3
= gen_reg_rtx (DImode
);
2160 rtx tmp4
= gen_reg_rtx (DImode
);
2161 rtx tmp5
= gen_reg_rtx (DImode
);
2162 rtx tmp6
= gen_reg_rtx (DImode
);
2163 rtx tmp7
= gen_reg_rtx (DImode
);
2164 rtx tmp8
= gen_reg_rtx (DImode
);
2165 rtx tmp9
= gen_reg_rtx (DImode
);
2166 rtx tmp10
= gen_reg_rtx (DImode
);
2167 rtx tmp11
= gen_reg_rtx (DImode
);
2168 rtx tmp12
= gen_reg_rtx (DImode
);
2169 rtx tmp13
= gen_reg_rtx (DImode
);
2170 rtx result_lo
= gen_reg_rtx (DImode
);
2174 emit_insn (gen_insn_mul_hs_lu (tmp0
, op1
, op2
));
2175 emit_insn (gen_insn_mul_hs_lu (tmp1
, op2
, op1
));
2176 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2177 emit_insn (gen_insn_mul_hs_hs (tmp3
, op1
, op2
));
2181 emit_insn (gen_insn_mul_hu_lu (tmp0
, op1
, op2
));
2182 emit_insn (gen_insn_mul_hu_lu (tmp1
, op2
, op1
));
2183 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2184 emit_insn (gen_insn_mul_hu_hu (tmp3
, op1
, op2
));
2187 emit_move_insn (tmp4
, (gen_rtx_ASHIFT (DImode
, tmp0
, GEN_INT (32))));
2189 emit_move_insn (tmp5
, (gen_rtx_ASHIFT (DImode
, tmp1
, GEN_INT (32))));
2191 emit_move_insn (tmp6
, (gen_rtx_PLUS (DImode
, tmp4
, tmp5
)));
2192 emit_move_insn (result_lo
, (gen_rtx_PLUS (DImode
, tmp2
, tmp6
)));
2194 emit_move_insn (tmp7
, gen_rtx_LTU (DImode
, tmp6
, tmp4
));
2195 emit_move_insn (tmp8
, gen_rtx_LTU (DImode
, result_lo
, tmp2
));
2199 emit_move_insn (tmp9
, (gen_rtx_ASHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2200 emit_move_insn (tmp10
, (gen_rtx_ASHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2204 emit_move_insn (tmp9
, (gen_rtx_LSHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2205 emit_move_insn (tmp10
, (gen_rtx_LSHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2208 emit_move_insn (tmp11
, (gen_rtx_PLUS (DImode
, tmp3
, tmp7
)));
2209 emit_move_insn (tmp12
, (gen_rtx_PLUS (DImode
, tmp8
, tmp9
)));
2210 emit_move_insn (tmp13
, (gen_rtx_PLUS (DImode
, tmp11
, tmp12
)));
2211 emit_move_insn (result
, (gen_rtx_PLUS (DImode
, tmp13
, tmp10
)));
2215 /* Implement smuldi3_highpart. */
2217 tilegx_expand_smuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2219 tilegx_expand_high_multiply (op0
, op1
, op2
, true);
2223 /* Implement umuldi3_highpart. */
2225 tilegx_expand_umuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2227 tilegx_expand_high_multiply (op0
, op1
, op2
, false);
2232 /* Compare and branches */
2234 /* Produce the rtx yielding a bool for a floating point
2237 tilegx_emit_fp_setcc (rtx res
, enum rtx_code code
, enum machine_mode mode
,
2240 /* TODO: Certain compares again constants can be done using entirely
2241 integer operations. But you have to get the special cases right
2242 e.g. NaN, +0 == -0, etc. */
2246 rtx a
= force_reg (DImode
, gen_lowpart (DImode
, op0
));
2247 rtx b
= force_reg (DImode
, gen_lowpart (DImode
, op1
));
2249 flags
= gen_reg_rtx (DImode
);
2253 emit_insn (gen_insn_fsingle_add1 (flags
, a
, b
));
2257 gcc_assert (mode
== DFmode
);
2258 emit_insn (gen_insn_fdouble_add_flags (flags
, a
, b
));
2263 case EQ
: flag_index
= 30; break;
2264 case NE
: flag_index
= 31; break;
2265 case LE
: flag_index
= 27; break;
2266 case LT
: flag_index
= 26; break;
2267 case GE
: flag_index
= 29; break;
2268 case GT
: flag_index
= 28; break;
2269 default: gcc_unreachable ();
2272 gcc_assert (GET_MODE (res
) == DImode
);
2273 emit_move_insn (res
, gen_rtx_ZERO_EXTRACT (DImode
, flags
, GEN_INT (1),
2274 GEN_INT (flag_index
)));
2279 /* Certain simplifications can be done to make invalid setcc
2280 operations valid. Return the final comparison, or NULL if we can't
2283 tilegx_emit_setcc_internal (rtx res
, enum rtx_code code
, rtx op0
, rtx op1
,
2284 enum machine_mode cmp_mode
)
2289 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2290 return tilegx_emit_fp_setcc (res
, code
, cmp_mode
, op0
, op1
);
2292 /* The general case: fold the comparison code to the types of
2293 compares that we have, choosing the branch as necessary. */
2303 /* We have these compares. */
2310 /* We do not have these compares, so we reverse the
2316 /* We should not have called this with any other code. */
2322 code
= swap_condition (code
);
2323 tmp
= op0
, op0
= op1
, op1
= tmp
;
2326 if (!reg_or_0_operand (op0
, cmp_mode
))
2327 op0
= force_reg (cmp_mode
, op0
);
2329 if (!CONST_INT_P (op1
) && !register_operand (op1
, cmp_mode
))
2330 op1
= force_reg (cmp_mode
, op1
);
2332 /* Return the setcc comparison. */
2333 emit_insn (gen_rtx_SET (VOIDmode
, res
,
2334 gen_rtx_fmt_ee (code
, DImode
, op0
, op1
)));
2340 /* Implement cstore patterns. */
2342 tilegx_emit_setcc (rtx operands
[], enum machine_mode cmp_mode
)
2345 tilegx_emit_setcc_internal (operands
[0], GET_CODE (operands
[1]),
2346 operands
[2], operands
[3], cmp_mode
);
2350 /* Return whether CODE is a signed comparison. */
2352 signed_compare_p (enum rtx_code code
)
2354 return (code
== EQ
|| code
== NE
|| code
== LT
|| code
== LE
2355 || code
== GT
|| code
== GE
);
2359 /* Generate the comparison for a DImode conditional branch. */
2361 tilegx_emit_cc_test (enum rtx_code code
, rtx op0
, rtx op1
,
2362 enum machine_mode cmp_mode
, bool eq_ne_only
)
2364 enum rtx_code branch_code
;
2367 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2369 /* Compute a boolean saying whether the comparison is true. */
2370 temp
= gen_reg_rtx (DImode
);
2371 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2373 /* Test that flag. */
2374 return gen_rtx_fmt_ee (NE
, VOIDmode
, temp
, const0_rtx
);
2377 /* Check for a compare against zero using a comparison we can do
2379 if (op1
== const0_rtx
2380 && (code
== EQ
|| code
== NE
2381 || (!eq_ne_only
&& signed_compare_p (code
))))
2383 op0
= force_reg (cmp_mode
, op0
);
2384 return gen_rtx_fmt_ee (code
, VOIDmode
, op0
, const0_rtx
);
2387 /* The general case: fold the comparison code to the types of
2388 compares that we have, choosing the branch as necessary. */
2396 /* We have these compares. */
2405 /* These must be reversed (except NE, but let's
2407 code
= reverse_condition (code
);
2415 if (CONST_INT_P (op1
) && (!satisfies_constraint_I (op1
) || code
== LEU
))
2417 HOST_WIDE_INT n
= INTVAL (op1
);
2422 /* Subtract off the value we want to compare against and see
2423 if we get zero. This is cheaper than creating a constant
2424 in a register. Except that subtracting -128 is more
2425 expensive than seqi to -128, so we leave that alone. */
2426 /* ??? Don't do this when comparing against symbols,
2427 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2428 0), which will be declared false out of hand (at least
2431 && add_operand (GEN_INT (-n
), DImode
)
2432 && !(symbolic_operand (op0
, VOIDmode
)
2433 || (REG_P (op0
) && REG_POINTER (op0
))))
2435 /* TODO: Use a SIMD add immediate to hit zero for tiled
2436 constants in a single instruction. */
2437 if (GET_MODE (op0
) != DImode
)
2439 /* Convert to DImode so we can use addli. Note that
2440 this will not actually generate any code because
2441 sign extension from SI -> DI is a no-op. I don't
2442 know if it's safe just to make a paradoxical
2443 subreg here though. */
2444 rtx temp2
= gen_reg_rtx (DImode
);
2445 emit_insn (gen_extendsidi2 (temp2
, op0
));
2450 op0
= force_reg (DImode
, op0
);
2452 temp
= gen_reg_rtx (DImode
);
2453 emit_move_insn (temp
, gen_rtx_PLUS (DImode
, op0
, GEN_INT (-n
)));
2454 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2455 VOIDmode
, temp
, const0_rtx
);
2465 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2466 We use arithmetic shift right because it's a 3-wide op,
2467 while logical shift right is not. */
2469 int first
= exact_log2 (code
== LTU
? n
: n
+ 1);
2472 op0
= force_reg (cmp_mode
, op0
);
2473 temp
= gen_reg_rtx (cmp_mode
);
2474 emit_move_insn (temp
,
2475 gen_rtx_ASHIFTRT (cmp_mode
, op0
,
2477 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2478 VOIDmode
, temp
, const0_rtx
);
2488 /* Compute a flag saying whether we should branch. */
2489 temp
= gen_reg_rtx (DImode
);
2490 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2492 /* Return the branch comparison. */
2493 return gen_rtx_fmt_ee (branch_code
, VOIDmode
, temp
, const0_rtx
);
2497 /* Generate the comparison for a conditional branch. */
2499 tilegx_emit_conditional_branch (rtx operands
[], enum machine_mode cmp_mode
)
2502 tilegx_emit_cc_test (GET_CODE (operands
[0]), operands
[1], operands
[2],
2504 rtx branch_rtx
= gen_rtx_SET (VOIDmode
, pc_rtx
,
2505 gen_rtx_IF_THEN_ELSE (VOIDmode
, cmp_rtx
,
2510 emit_jump_insn (branch_rtx
);
2514 /* Implement the mov<mode>cc pattern. */
2516 tilegx_emit_conditional_move (rtx cmp
)
2519 tilegx_emit_cc_test (GET_CODE (cmp
), XEXP (cmp
, 0), XEXP (cmp
, 1),
2520 GET_MODE (XEXP (cmp
, 0)), true);
2524 /* Return true if INSN is annotated with a REG_BR_PROB note that
2525 indicates it's a branch that's predicted taken. */
2527 cbranch_predicted_p (rtx insn
)
2529 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2533 int pred_val
= XINT (x
, 0);
2535 return pred_val
>= REG_BR_PROB_BASE
/ 2;
2542 /* Output assembly code for a specific branch instruction, appending
2543 the branch prediction flag to the opcode if appropriate. */
2545 tilegx_output_simple_cbranch_with_opcode (rtx insn
, const char *opcode
,
2546 int regop
, bool reverse_predicted
)
2548 static char buf
[64];
2549 sprintf (buf
, "%s%s\t%%r%d, %%l0", opcode
,
2550 (cbranch_predicted_p (insn
) ^ reverse_predicted
) ? "t" : "",
2556 /* Output assembly code for a specific branch instruction, appending
2557 the branch prediction flag to the opcode if appropriate. */
2559 tilegx_output_cbranch_with_opcode (rtx insn
, rtx
*operands
,
2561 const char *rev_opcode
, int regop
)
2563 const char *branch_if_false
;
2564 rtx taken
, not_taken
;
2565 bool is_simple_branch
;
2567 gcc_assert (LABEL_P (operands
[0]));
2569 is_simple_branch
= true;
2570 if (INSN_ADDRESSES_SET_P ())
2572 int from_addr
= INSN_ADDRESSES (INSN_UID (insn
));
2573 int to_addr
= INSN_ADDRESSES (INSN_UID (operands
[0]));
2574 int delta
= to_addr
- from_addr
;
2575 is_simple_branch
= IN_RANGE (delta
, -524288, 524280);
2578 if (is_simple_branch
)
2580 /* Just a simple conditional branch. */
2582 tilegx_output_simple_cbranch_with_opcode (insn
, opcode
, regop
, false);
2585 /* Generate a reversed branch around a direct jump. This fallback
2586 does not use branch-likely instructions. */
2587 not_taken
= gen_label_rtx ();
2588 taken
= operands
[0];
2590 /* Generate the reversed branch to NOT_TAKEN. */
2591 operands
[0] = not_taken
;
2593 tilegx_output_simple_cbranch_with_opcode (insn
, rev_opcode
, regop
, true);
2594 output_asm_insn (branch_if_false
, operands
);
2596 output_asm_insn ("j\t%l0", &taken
);
2598 /* Output NOT_TAKEN. */
2599 targetm
.asm_out
.internal_label (asm_out_file
, "L",
2600 CODE_LABEL_NUMBER (not_taken
));
2605 /* Output assembly code for a conditional branch instruction. */
2607 tilegx_output_cbranch (rtx insn
, rtx
*operands
, bool reversed
)
2609 enum rtx_code code
= GET_CODE (operands
[1]);
2611 const char *rev_opcode
;
2614 code
= reverse_condition (code
);
2620 rev_opcode
= "beqz";
2624 rev_opcode
= "bnez";
2628 rev_opcode
= "bltz";
2632 rev_opcode
= "blez";
2636 rev_opcode
= "bgtz";
2640 rev_opcode
= "bgez";
2646 return tilegx_output_cbranch_with_opcode (insn
, operands
, opcode
,
2651 /* Implement the tablejump pattern. */
2653 tilegx_expand_tablejump (rtx op0
, rtx op1
)
2657 rtx temp
= gen_reg_rtx (Pmode
);
2658 rtx temp2
= gen_reg_rtx (Pmode
);
2660 tilegx_compute_pcrel_address (temp
, gen_rtx_LABEL_REF (Pmode
, op1
));
2661 emit_move_insn (temp2
,
2662 gen_rtx_PLUS (Pmode
,
2663 convert_to_mode (Pmode
, op0
, false),
2668 emit_jump_insn (gen_tablejump_aux (op0
, op1
));
2672 /* Emit barrier before an atomic, as needed for the memory MODEL. */
2674 tilegx_pre_atomic_barrier (enum memmodel model
)
2676 if (need_atomic_barrier_p (model
, true))
2677 emit_insn (gen_memory_barrier ());
2681 /* Emit barrier after an atomic, as needed for the memory MODEL. */
2683 tilegx_post_atomic_barrier (enum memmodel model
)
2685 if (need_atomic_barrier_p (model
, false))
2686 emit_insn (gen_memory_barrier ());
2691 /* Expand a builtin vector binary op, by calling gen function GEN with
2692 operands in the proper modes. DEST is converted to DEST_MODE, and
2693 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2695 tilegx_expand_builtin_vector_binop (rtx (*gen
) (rtx
, rtx
, rtx
),
2696 enum machine_mode dest_mode
,
2698 enum machine_mode src_mode
,
2699 rtx src0
, rtx src1
, bool do_src1
)
2701 dest
= gen_lowpart (dest_mode
, dest
);
2703 if (src0
== const0_rtx
)
2704 src0
= CONST0_RTX (src_mode
);
2706 src0
= gen_lowpart (src_mode
, src0
);
2710 if (src1
== const0_rtx
)
2711 src1
= CONST0_RTX (src_mode
);
2713 src1
= gen_lowpart (src_mode
, src1
);
2716 emit_insn ((*gen
) (dest
, src0
, src1
));
2724 struct tile_builtin_info
2726 enum insn_code icode
;
2730 static struct tile_builtin_info tilegx_builtin_info
[TILEGX_BUILTIN_max
] = {
2731 { CODE_FOR_adddi3
, NULL
}, /* add */
2732 { CODE_FOR_addsi3
, NULL
}, /* addx */
2733 { CODE_FOR_ssaddsi3
, NULL
}, /* addxsc */
2734 { CODE_FOR_anddi3
, NULL
}, /* and */
2735 { CODE_FOR_insn_bfexts
, NULL
}, /* bfexts */
2736 { CODE_FOR_insn_bfextu
, NULL
}, /* bfextu */
2737 { CODE_FOR_insn_bfins
, NULL
}, /* bfins */
2738 { CODE_FOR_clzdi2
, NULL
}, /* clz */
2739 { CODE_FOR_insn_cmoveqz
, NULL
}, /* cmoveqz */
2740 { CODE_FOR_insn_cmovnez
, NULL
}, /* cmovnez */
2741 { CODE_FOR_insn_cmpeq_didi
, NULL
}, /* cmpeq */
2742 { CODE_FOR_insn_cmpexch
, NULL
}, /* cmpexch */
2743 { CODE_FOR_insn_cmpexch4
, NULL
}, /* cmpexch4 */
2744 { CODE_FOR_insn_cmples_didi
, NULL
}, /* cmples */
2745 { CODE_FOR_insn_cmpleu_didi
, NULL
}, /* cmpleu */
2746 { CODE_FOR_insn_cmplts_didi
, NULL
}, /* cmplts */
2747 { CODE_FOR_insn_cmpltu_didi
, NULL
}, /* cmpltu */
2748 { CODE_FOR_insn_cmpne_didi
, NULL
}, /* cmpne */
2749 { CODE_FOR_insn_cmul
, NULL
}, /* cmul */
2750 { CODE_FOR_insn_cmula
, NULL
}, /* cmula */
2751 { CODE_FOR_insn_cmulaf
, NULL
}, /* cmulaf */
2752 { CODE_FOR_insn_cmulf
, NULL
}, /* cmulf */
2753 { CODE_FOR_insn_cmulfr
, NULL
}, /* cmulfr */
2754 { CODE_FOR_insn_cmulh
, NULL
}, /* cmulh */
2755 { CODE_FOR_insn_cmulhr
, NULL
}, /* cmulhr */
2756 { CODE_FOR_insn_crc32_32
, NULL
}, /* crc32_32 */
2757 { CODE_FOR_insn_crc32_8
, NULL
}, /* crc32_8 */
2758 { CODE_FOR_ctzdi2
, NULL
}, /* ctz */
2759 { CODE_FOR_insn_dblalign
, NULL
}, /* dblalign */
2760 { CODE_FOR_insn_dblalign2
, NULL
}, /* dblalign2 */
2761 { CODE_FOR_insn_dblalign4
, NULL
}, /* dblalign4 */
2762 { CODE_FOR_insn_dblalign6
, NULL
}, /* dblalign6 */
2763 { CODE_FOR_insn_drain
, NULL
}, /* drain */
2764 { CODE_FOR_insn_dtlbpr
, NULL
}, /* dtlbpr */
2765 { CODE_FOR_insn_exch
, NULL
}, /* exch */
2766 { CODE_FOR_insn_exch4
, NULL
}, /* exch4 */
2767 { CODE_FOR_insn_fdouble_add_flags
, NULL
}, /* fdouble_add_flags */
2768 { CODE_FOR_insn_fdouble_addsub
, NULL
}, /* fdouble_addsub */
2769 { CODE_FOR_insn_fdouble_mul_flags
, NULL
}, /* fdouble_mul_flags */
2770 { CODE_FOR_insn_fdouble_pack1
, NULL
}, /* fdouble_pack1 */
2771 { CODE_FOR_insn_fdouble_pack2
, NULL
}, /* fdouble_pack2 */
2772 { CODE_FOR_insn_fdouble_sub_flags
, NULL
}, /* fdouble_sub_flags */
2773 { CODE_FOR_insn_fdouble_unpack_max
, NULL
}, /* fdouble_unpack_max */
2774 { CODE_FOR_insn_fdouble_unpack_min
, NULL
}, /* fdouble_unpack_min */
2775 { CODE_FOR_insn_fetchadd
, NULL
}, /* fetchadd */
2776 { CODE_FOR_insn_fetchadd4
, NULL
}, /* fetchadd4 */
2777 { CODE_FOR_insn_fetchaddgez
, NULL
}, /* fetchaddgez */
2778 { CODE_FOR_insn_fetchaddgez4
, NULL
}, /* fetchaddgez4 */
2779 { CODE_FOR_insn_fetchand
, NULL
}, /* fetchand */
2780 { CODE_FOR_insn_fetchand4
, NULL
}, /* fetchand4 */
2781 { CODE_FOR_insn_fetchor
, NULL
}, /* fetchor */
2782 { CODE_FOR_insn_fetchor4
, NULL
}, /* fetchor4 */
2783 { CODE_FOR_insn_finv
, NULL
}, /* finv */
2784 { CODE_FOR_insn_flush
, NULL
}, /* flush */
2785 { CODE_FOR_insn_flushwb
, NULL
}, /* flushwb */
2786 { CODE_FOR_insn_fnop
, NULL
}, /* fnop */
2787 { CODE_FOR_insn_fsingle_add1
, NULL
}, /* fsingle_add1 */
2788 { CODE_FOR_insn_fsingle_addsub2
, NULL
}, /* fsingle_addsub2 */
2789 { CODE_FOR_insn_fsingle_mul1
, NULL
}, /* fsingle_mul1 */
2790 { CODE_FOR_insn_fsingle_mul2
, NULL
}, /* fsingle_mul2 */
2791 { CODE_FOR_insn_fsingle_pack1
, NULL
}, /* fsingle_pack1 */
2792 { CODE_FOR_insn_fsingle_pack2
, NULL
}, /* fsingle_pack2 */
2793 { CODE_FOR_insn_fsingle_sub1
, NULL
}, /* fsingle_sub1 */
2794 { CODE_FOR_insn_icoh
, NULL
}, /* icoh */
2795 { CODE_FOR_insn_ill
, NULL
}, /* ill */
2796 { CODE_FOR_insn_info
, NULL
}, /* info */
2797 { CODE_FOR_insn_infol
, NULL
}, /* infol */
2798 { CODE_FOR_insn_inv
, NULL
}, /* inv */
2799 { CODE_FOR_insn_ld
, NULL
}, /* ld */
2800 { CODE_FOR_insn_ld1s
, NULL
}, /* ld1s */
2801 { CODE_FOR_insn_ld1u
, NULL
}, /* ld1u */
2802 { CODE_FOR_insn_ld2s
, NULL
}, /* ld2s */
2803 { CODE_FOR_insn_ld2u
, NULL
}, /* ld2u */
2804 { CODE_FOR_insn_ld4s
, NULL
}, /* ld4s */
2805 { CODE_FOR_insn_ld4u
, NULL
}, /* ld4u */
2806 { CODE_FOR_insn_ldna
, NULL
}, /* ldna */
2807 { CODE_FOR_insn_ldnt
, NULL
}, /* ldnt */
2808 { CODE_FOR_insn_ldnt1s
, NULL
}, /* ldnt1s */
2809 { CODE_FOR_insn_ldnt1u
, NULL
}, /* ldnt1u */
2810 { CODE_FOR_insn_ldnt2s
, NULL
}, /* ldnt2s */
2811 { CODE_FOR_insn_ldnt2u
, NULL
}, /* ldnt2u */
2812 { CODE_FOR_insn_ldnt4s
, NULL
}, /* ldnt4s */
2813 { CODE_FOR_insn_ldnt4u
, NULL
}, /* ldnt4u */
2814 { CODE_FOR_insn_ld_L2
, NULL
}, /* ld_L2 */
2815 { CODE_FOR_insn_ld1s_L2
, NULL
}, /* ld1s_L2 */
2816 { CODE_FOR_insn_ld1u_L2
, NULL
}, /* ld1u_L2 */
2817 { CODE_FOR_insn_ld2s_L2
, NULL
}, /* ld2s_L2 */
2818 { CODE_FOR_insn_ld2u_L2
, NULL
}, /* ld2u_L2 */
2819 { CODE_FOR_insn_ld4s_L2
, NULL
}, /* ld4s_L2 */
2820 { CODE_FOR_insn_ld4u_L2
, NULL
}, /* ld4u_L2 */
2821 { CODE_FOR_insn_ldna_L2
, NULL
}, /* ldna_L2 */
2822 { CODE_FOR_insn_ldnt_L2
, NULL
}, /* ldnt_L2 */
2823 { CODE_FOR_insn_ldnt1s_L2
, NULL
}, /* ldnt1s_L2 */
2824 { CODE_FOR_insn_ldnt1u_L2
, NULL
}, /* ldnt1u_L2 */
2825 { CODE_FOR_insn_ldnt2s_L2
, NULL
}, /* ldnt2s_L2 */
2826 { CODE_FOR_insn_ldnt2u_L2
, NULL
}, /* ldnt2u_L2 */
2827 { CODE_FOR_insn_ldnt4s_L2
, NULL
}, /* ldnt4s_L2 */
2828 { CODE_FOR_insn_ldnt4u_L2
, NULL
}, /* ldnt4u_L2 */
2829 { CODE_FOR_insn_ld_miss
, NULL
}, /* ld_miss */
2830 { CODE_FOR_insn_ld1s_miss
, NULL
}, /* ld1s_miss */
2831 { CODE_FOR_insn_ld1u_miss
, NULL
}, /* ld1u_miss */
2832 { CODE_FOR_insn_ld2s_miss
, NULL
}, /* ld2s_miss */
2833 { CODE_FOR_insn_ld2u_miss
, NULL
}, /* ld2u_miss */
2834 { CODE_FOR_insn_ld4s_miss
, NULL
}, /* ld4s_miss */
2835 { CODE_FOR_insn_ld4u_miss
, NULL
}, /* ld4u_miss */
2836 { CODE_FOR_insn_ldna_miss
, NULL
}, /* ldna_miss */
2837 { CODE_FOR_insn_ldnt_miss
, NULL
}, /* ldnt_miss */
2838 { CODE_FOR_insn_ldnt1s_miss
, NULL
}, /* ldnt1s_miss */
2839 { CODE_FOR_insn_ldnt1u_miss
, NULL
}, /* ldnt1u_miss */
2840 { CODE_FOR_insn_ldnt2s_miss
, NULL
}, /* ldnt2s_miss */
2841 { CODE_FOR_insn_ldnt2u_miss
, NULL
}, /* ldnt2u_miss */
2842 { CODE_FOR_insn_ldnt4s_miss
, NULL
}, /* ldnt4s_miss */
2843 { CODE_FOR_insn_ldnt4u_miss
, NULL
}, /* ldnt4u_miss */
2844 { CODE_FOR_insn_lnk
, NULL
}, /* lnk */
2845 { CODE_FOR_memory_barrier
, NULL
}, /* mf */
2846 { CODE_FOR_insn_mfspr
, NULL
}, /* mfspr */
2847 { CODE_FOR_insn_mm
, NULL
}, /* mm */
2848 { CODE_FOR_insn_mnz
, NULL
}, /* mnz */
2849 { CODE_FOR_movdi
, NULL
}, /* move */
2850 { CODE_FOR_insn_mtspr
, NULL
}, /* mtspr */
2851 { CODE_FOR_insn_mul_hs_hs
, NULL
}, /* mul_hs_hs */
2852 { CODE_FOR_insn_mul_hs_hu
, NULL
}, /* mul_hs_hu */
2853 { CODE_FOR_insn_mul_hs_ls
, NULL
}, /* mul_hs_ls */
2854 { CODE_FOR_insn_mul_hs_lu
, NULL
}, /* mul_hs_lu */
2855 { CODE_FOR_insn_mul_hu_hu
, NULL
}, /* mul_hu_hu */
2856 { CODE_FOR_insn_mul_hu_ls
, NULL
}, /* mul_hu_ls */
2857 { CODE_FOR_insn_mul_hu_lu
, NULL
}, /* mul_hu_lu */
2858 { CODE_FOR_insn_mul_ls_ls
, NULL
}, /* mul_ls_ls */
2859 { CODE_FOR_insn_mul_ls_lu
, NULL
}, /* mul_ls_lu */
2860 { CODE_FOR_insn_mul_lu_lu
, NULL
}, /* mul_lu_lu */
2861 { CODE_FOR_insn_mula_hs_hs
, NULL
}, /* mula_hs_hs */
2862 { CODE_FOR_insn_mula_hs_hu
, NULL
}, /* mula_hs_hu */
2863 { CODE_FOR_insn_mula_hs_ls
, NULL
}, /* mula_hs_ls */
2864 { CODE_FOR_insn_mula_hs_lu
, NULL
}, /* mula_hs_lu */
2865 { CODE_FOR_insn_mula_hu_hu
, NULL
}, /* mula_hu_hu */
2866 { CODE_FOR_insn_mula_hu_ls
, NULL
}, /* mula_hu_ls */
2867 { CODE_FOR_insn_mula_hu_lu
, NULL
}, /* mula_hu_lu */
2868 { CODE_FOR_insn_mula_ls_ls
, NULL
}, /* mula_ls_ls */
2869 { CODE_FOR_insn_mula_ls_lu
, NULL
}, /* mula_ls_lu */
2870 { CODE_FOR_insn_mula_lu_lu
, NULL
}, /* mula_lu_lu */
2871 { CODE_FOR_insn_mulax
, NULL
}, /* mulax */
2872 { CODE_FOR_mulsi3
, NULL
}, /* mulx */
2873 { CODE_FOR_insn_mz
, NULL
}, /* mz */
2874 { CODE_FOR_insn_nap
, NULL
}, /* nap */
2875 { CODE_FOR_nop
, NULL
}, /* nop */
2876 { CODE_FOR_insn_nor_di
, NULL
}, /* nor */
2877 { CODE_FOR_iordi3
, NULL
}, /* or */
2878 { CODE_FOR_popcountdi2
, NULL
}, /* pcnt */
2879 { CODE_FOR_insn_prefetch_l1
, NULL
}, /* prefetch_l1 */
2880 { CODE_FOR_insn_prefetch_l1_fault
, NULL
}, /* prefetch_l1_fault */
2881 { CODE_FOR_insn_prefetch_l2
, NULL
}, /* prefetch_l2 */
2882 { CODE_FOR_insn_prefetch_l2_fault
, NULL
}, /* prefetch_l2_fault */
2883 { CODE_FOR_insn_prefetch_l3
, NULL
}, /* prefetch_l3 */
2884 { CODE_FOR_insn_prefetch_l3_fault
, NULL
}, /* prefetch_l3_fault */
2885 { CODE_FOR_insn_revbits
, NULL
}, /* revbits */
2886 { CODE_FOR_bswapdi2
, NULL
}, /* revbytes */
2887 { CODE_FOR_rotldi3
, NULL
}, /* rotl */
2888 { CODE_FOR_ashldi3
, NULL
}, /* shl */
2889 { CODE_FOR_insn_shl16insli
, NULL
}, /* shl16insli */
2890 { CODE_FOR_insn_shl1add
, NULL
}, /* shl1add */
2891 { CODE_FOR_insn_shl1addx
, NULL
}, /* shl1addx */
2892 { CODE_FOR_insn_shl2add
, NULL
}, /* shl2add */
2893 { CODE_FOR_insn_shl2addx
, NULL
}, /* shl2addx */
2894 { CODE_FOR_insn_shl3add
, NULL
}, /* shl3add */
2895 { CODE_FOR_insn_shl3addx
, NULL
}, /* shl3addx */
2896 { CODE_FOR_ashlsi3
, NULL
}, /* shlx */
2897 { CODE_FOR_ashrdi3
, NULL
}, /* shrs */
2898 { CODE_FOR_lshrdi3
, NULL
}, /* shru */
2899 { CODE_FOR_lshrsi3
, NULL
}, /* shrux */
2900 { CODE_FOR_insn_shufflebytes
, NULL
}, /* shufflebytes */
2901 { CODE_FOR_insn_shufflebytes1
, NULL
}, /* shufflebytes1 */
2902 { CODE_FOR_insn_st
, NULL
}, /* st */
2903 { CODE_FOR_insn_st1
, NULL
}, /* st1 */
2904 { CODE_FOR_insn_st2
, NULL
}, /* st2 */
2905 { CODE_FOR_insn_st4
, NULL
}, /* st4 */
2906 { CODE_FOR_insn_stnt
, NULL
}, /* stnt */
2907 { CODE_FOR_insn_stnt1
, NULL
}, /* stnt1 */
2908 { CODE_FOR_insn_stnt2
, NULL
}, /* stnt2 */
2909 { CODE_FOR_insn_stnt4
, NULL
}, /* stnt4 */
2910 { CODE_FOR_subdi3
, NULL
}, /* sub */
2911 { CODE_FOR_subsi3
, NULL
}, /* subx */
2912 { CODE_FOR_sssubsi3
, NULL
}, /* subxsc */
2913 { CODE_FOR_insn_tblidxb0
, NULL
}, /* tblidxb0 */
2914 { CODE_FOR_insn_tblidxb1
, NULL
}, /* tblidxb1 */
2915 { CODE_FOR_insn_tblidxb2
, NULL
}, /* tblidxb2 */
2916 { CODE_FOR_insn_tblidxb3
, NULL
}, /* tblidxb3 */
2917 { CODE_FOR_insn_v1add
, NULL
}, /* v1add */
2918 { CODE_FOR_insn_v1addi
, NULL
}, /* v1addi */
2919 { CODE_FOR_insn_v1adduc
, NULL
}, /* v1adduc */
2920 { CODE_FOR_insn_v1adiffu
, NULL
}, /* v1adiffu */
2921 { CODE_FOR_insn_v1avgu
, NULL
}, /* v1avgu */
2922 { CODE_FOR_insn_v1cmpeq
, NULL
}, /* v1cmpeq */
2923 { CODE_FOR_insn_v1cmpeqi
, NULL
}, /* v1cmpeqi */
2924 { CODE_FOR_insn_v1cmples
, NULL
}, /* v1cmples */
2925 { CODE_FOR_insn_v1cmpleu
, NULL
}, /* v1cmpleu */
2926 { CODE_FOR_insn_v1cmplts
, NULL
}, /* v1cmplts */
2927 { CODE_FOR_insn_v1cmpltsi
, NULL
}, /* v1cmpltsi */
2928 { CODE_FOR_insn_v1cmpltu
, NULL
}, /* v1cmpltu */
2929 { CODE_FOR_insn_v1cmpltui
, NULL
}, /* v1cmpltui */
2930 { CODE_FOR_insn_v1cmpne
, NULL
}, /* v1cmpne */
2931 { CODE_FOR_insn_v1ddotpu
, NULL
}, /* v1ddotpu */
2932 { CODE_FOR_insn_v1ddotpua
, NULL
}, /* v1ddotpua */
2933 { CODE_FOR_insn_v1ddotpus
, NULL
}, /* v1ddotpus */
2934 { CODE_FOR_insn_v1ddotpusa
, NULL
}, /* v1ddotpusa */
2935 { CODE_FOR_insn_v1dotp
, NULL
}, /* v1dotp */
2936 { CODE_FOR_insn_v1dotpa
, NULL
}, /* v1dotpa */
2937 { CODE_FOR_insn_v1dotpu
, NULL
}, /* v1dotpu */
2938 { CODE_FOR_insn_v1dotpua
, NULL
}, /* v1dotpua */
2939 { CODE_FOR_insn_v1dotpus
, NULL
}, /* v1dotpus */
2940 { CODE_FOR_insn_v1dotpusa
, NULL
}, /* v1dotpusa */
2941 { CODE_FOR_insn_v1int_h
, NULL
}, /* v1int_h */
2942 { CODE_FOR_insn_v1int_l
, NULL
}, /* v1int_l */
2943 { CODE_FOR_insn_v1maxu
, NULL
}, /* v1maxu */
2944 { CODE_FOR_insn_v1maxui
, NULL
}, /* v1maxui */
2945 { CODE_FOR_insn_v1minu
, NULL
}, /* v1minu */
2946 { CODE_FOR_insn_v1minui
, NULL
}, /* v1minui */
2947 { CODE_FOR_insn_v1mnz
, NULL
}, /* v1mnz */
2948 { CODE_FOR_insn_v1multu
, NULL
}, /* v1multu */
2949 { CODE_FOR_insn_v1mulu
, NULL
}, /* v1mulu */
2950 { CODE_FOR_insn_v1mulus
, NULL
}, /* v1mulus */
2951 { CODE_FOR_insn_v1mz
, NULL
}, /* v1mz */
2952 { CODE_FOR_insn_v1sadau
, NULL
}, /* v1sadau */
2953 { CODE_FOR_insn_v1sadu
, NULL
}, /* v1sadu */
2954 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shl */
2955 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shli */
2956 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrs */
2957 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrsi */
2958 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shru */
2959 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shrui */
2960 { CODE_FOR_insn_v1sub
, NULL
}, /* v1sub */
2961 { CODE_FOR_insn_v1subuc
, NULL
}, /* v1subuc */
2962 { CODE_FOR_insn_v2add
, NULL
}, /* v2add */
2963 { CODE_FOR_insn_v2addi
, NULL
}, /* v2addi */
2964 { CODE_FOR_insn_v2addsc
, NULL
}, /* v2addsc */
2965 { CODE_FOR_insn_v2adiffs
, NULL
}, /* v2adiffs */
2966 { CODE_FOR_insn_v2avgs
, NULL
}, /* v2avgs */
2967 { CODE_FOR_insn_v2cmpeq
, NULL
}, /* v2cmpeq */
2968 { CODE_FOR_insn_v2cmpeqi
, NULL
}, /* v2cmpeqi */
2969 { CODE_FOR_insn_v2cmples
, NULL
}, /* v2cmples */
2970 { CODE_FOR_insn_v2cmpleu
, NULL
}, /* v2cmpleu */
2971 { CODE_FOR_insn_v2cmplts
, NULL
}, /* v2cmplts */
2972 { CODE_FOR_insn_v2cmpltsi
, NULL
}, /* v2cmpltsi */
2973 { CODE_FOR_insn_v2cmpltu
, NULL
}, /* v2cmpltu */
2974 { CODE_FOR_insn_v2cmpltui
, NULL
}, /* v2cmpltui */
2975 { CODE_FOR_insn_v2cmpne
, NULL
}, /* v2cmpne */
2976 { CODE_FOR_insn_v2dotp
, NULL
}, /* v2dotp */
2977 { CODE_FOR_insn_v2dotpa
, NULL
}, /* v2dotpa */
2978 { CODE_FOR_insn_v2int_h
, NULL
}, /* v2int_h */
2979 { CODE_FOR_insn_v2int_l
, NULL
}, /* v2int_l */
2980 { CODE_FOR_insn_v2maxs
, NULL
}, /* v2maxs */
2981 { CODE_FOR_insn_v2maxsi
, NULL
}, /* v2maxsi */
2982 { CODE_FOR_insn_v2mins
, NULL
}, /* v2mins */
2983 { CODE_FOR_insn_v2minsi
, NULL
}, /* v2minsi */
2984 { CODE_FOR_insn_v2mnz
, NULL
}, /* v2mnz */
2985 { CODE_FOR_insn_v2mulfsc
, NULL
}, /* v2mulfsc */
2986 { CODE_FOR_insn_v2muls
, NULL
}, /* v2muls */
2987 { CODE_FOR_insn_v2mults
, NULL
}, /* v2mults */
2988 { CODE_FOR_insn_v2mz
, NULL
}, /* v2mz */
2989 { CODE_FOR_insn_v2packh
, NULL
}, /* v2packh */
2990 { CODE_FOR_insn_v2packl
, NULL
}, /* v2packl */
2991 { CODE_FOR_insn_v2packuc
, NULL
}, /* v2packuc */
2992 { CODE_FOR_insn_v2sadas
, NULL
}, /* v2sadas */
2993 { CODE_FOR_insn_v2sadau
, NULL
}, /* v2sadau */
2994 { CODE_FOR_insn_v2sads
, NULL
}, /* v2sads */
2995 { CODE_FOR_insn_v2sadu
, NULL
}, /* v2sadu */
2996 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shl */
2997 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shli */
2998 { CODE_FOR_insn_v2shlsc
, NULL
}, /* v2shlsc */
2999 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrs */
3000 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrsi */
3001 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shru */
3002 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shrui */
3003 { CODE_FOR_insn_v2sub
, NULL
}, /* v2sub */
3004 { CODE_FOR_insn_v2subsc
, NULL
}, /* v2subsc */
3005 { CODE_FOR_insn_v4add
, NULL
}, /* v4add */
3006 { CODE_FOR_insn_v4addsc
, NULL
}, /* v4addsc */
3007 { CODE_FOR_insn_v4int_h
, NULL
}, /* v4int_h */
3008 { CODE_FOR_insn_v4int_l
, NULL
}, /* v4int_l */
3009 { CODE_FOR_insn_v4packsc
, NULL
}, /* v4packsc */
3010 { CODE_FOR_insn_v4shl
, NULL
}, /* v4shl */
3011 { CODE_FOR_insn_v4shlsc
, NULL
}, /* v4shlsc */
3012 { CODE_FOR_insn_v4shrs
, NULL
}, /* v4shrs */
3013 { CODE_FOR_insn_v4shru
, NULL
}, /* v4shru */
3014 { CODE_FOR_insn_v4sub
, NULL
}, /* v4sub */
3015 { CODE_FOR_insn_v4subsc
, NULL
}, /* v4subsc */
3016 { CODE_FOR_insn_wh64
, NULL
}, /* wh64 */
3017 { CODE_FOR_xordi3
, NULL
}, /* xor */
3018 { CODE_FOR_tilegx_network_barrier
, NULL
}, /* network_barrier */
3019 { CODE_FOR_tilegx_idn0_receive
, NULL
}, /* idn0_receive */
3020 { CODE_FOR_tilegx_idn1_receive
, NULL
}, /* idn1_receive */
3021 { CODE_FOR_tilegx_idn_send
, NULL
}, /* idn_send */
3022 { CODE_FOR_tilegx_udn0_receive
, NULL
}, /* udn0_receive */
3023 { CODE_FOR_tilegx_udn1_receive
, NULL
}, /* udn1_receive */
3024 { CODE_FOR_tilegx_udn2_receive
, NULL
}, /* udn2_receive */
3025 { CODE_FOR_tilegx_udn3_receive
, NULL
}, /* udn3_receive */
3026 { CODE_FOR_tilegx_udn_send
, NULL
}, /* udn_send */
3030 struct tilegx_builtin_def
3033 enum tilegx_builtin code
;
3035 /* The first character is the return type. Subsequent characters
3036 are the argument types. See char_to_type. */
3041 static const struct tilegx_builtin_def tilegx_builtins
[] = {
3042 { "__insn_add", TILEGX_INSN_ADD
, true, "lll" },
3043 { "__insn_addi", TILEGX_INSN_ADD
, true, "lll" },
3044 { "__insn_addli", TILEGX_INSN_ADD
, true, "lll" },
3045 { "__insn_addx", TILEGX_INSN_ADDX
, true, "iii" },
3046 { "__insn_addxi", TILEGX_INSN_ADDX
, true, "iii" },
3047 { "__insn_addxli", TILEGX_INSN_ADDX
, true, "iii" },
3048 { "__insn_addxsc", TILEGX_INSN_ADDXSC
, true, "iii" },
3049 { "__insn_and", TILEGX_INSN_AND
, true, "lll" },
3050 { "__insn_andi", TILEGX_INSN_AND
, true, "lll" },
3051 { "__insn_bfexts", TILEGX_INSN_BFEXTS
, true, "llll" },
3052 { "__insn_bfextu", TILEGX_INSN_BFEXTU
, true, "llll" },
3053 { "__insn_bfins", TILEGX_INSN_BFINS
, true, "lllll"},
3054 { "__insn_clz", TILEGX_INSN_CLZ
, true, "ll" },
3055 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ
, true, "llll" },
3056 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ
, true, "llll" },
3057 { "__insn_cmpeq", TILEGX_INSN_CMPEQ
, true, "lll" },
3058 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ
, true, "lll" },
3059 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH
, false, "lpl" },
3060 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4
, false, "ipi" },
3061 { "__insn_cmples", TILEGX_INSN_CMPLES
, true, "lll" },
3062 { "__insn_cmpleu", TILEGX_INSN_CMPLEU
, true, "lll" },
3063 { "__insn_cmplts", TILEGX_INSN_CMPLTS
, true, "lll" },
3064 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS
, true, "lll" },
3065 { "__insn_cmpltu", TILEGX_INSN_CMPLTU
, true, "lll" },
3066 { "__insn_cmpltui", TILEGX_INSN_CMPLTU
, true, "lll" },
3067 { "__insn_cmpne", TILEGX_INSN_CMPNE
, true, "lll" },
3068 { "__insn_cmul", TILEGX_INSN_CMUL
, true, "lll" },
3069 { "__insn_cmula", TILEGX_INSN_CMULA
, true, "llll" },
3070 { "__insn_cmulaf", TILEGX_INSN_CMULAF
, true, "llll" },
3071 { "__insn_cmulf", TILEGX_INSN_CMULF
, true, "lll" },
3072 { "__insn_cmulfr", TILEGX_INSN_CMULFR
, true, "lll" },
3073 { "__insn_cmulh", TILEGX_INSN_CMULH
, true, "lll" },
3074 { "__insn_cmulhr", TILEGX_INSN_CMULHR
, true, "lll" },
3075 { "__insn_crc32_32", TILEGX_INSN_CRC32_32
, true, "lll" },
3076 { "__insn_crc32_8", TILEGX_INSN_CRC32_8
, true, "lll" },
3077 { "__insn_ctz", TILEGX_INSN_CTZ
, true, "ll" },
3078 { "__insn_dblalign", TILEGX_INSN_DBLALIGN
, true, "lllk" },
3079 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2
, true, "lll" },
3080 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4
, true, "lll" },
3081 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6
, true, "lll" },
3082 { "__insn_drain", TILEGX_INSN_DRAIN
, false, "v" },
3083 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR
, false, "vl" },
3084 { "__insn_exch", TILEGX_INSN_EXCH
, false, "lpl" },
3085 { "__insn_exch4", TILEGX_INSN_EXCH4
, false, "ipi" },
3086 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS
, true, "lll" },
3087 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB
, true, "llll" },
3088 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS
, true, "lll" },
3089 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1
, true, "lll" },
3090 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2
, true, "llll" },
3091 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS
, true, "lll" },
3092 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX
, true, "lll" },
3093 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN
, true, "lll" },
3094 { "__insn_fetchadd", TILEGX_INSN_FETCHADD
, false, "lpl" },
3095 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4
, false, "ipi" },
3096 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ
, false, "lpl" },
3097 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4
, false, "ipi" },
3098 { "__insn_fetchand", TILEGX_INSN_FETCHAND
, false, "lpl" },
3099 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4
, false, "ipi" },
3100 { "__insn_fetchor", TILEGX_INSN_FETCHOR
, false, "lpl" },
3101 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4
, false, "ipi" },
3102 { "__insn_finv", TILEGX_INSN_FINV
, false, "vk" },
3103 { "__insn_flush", TILEGX_INSN_FLUSH
, false, "vk" },
3104 { "__insn_flushwb", TILEGX_INSN_FLUSHWB
, false, "v" },
3105 { "__insn_fnop", TILEGX_INSN_FNOP
, false, "v" },
3106 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1
, true, "lll" },
3107 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2
, true, "llll" },
3108 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1
, true, "lll" },
3109 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2
, true, "lll" },
3110 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1
, true, "ll" },
3111 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2
, true, "lll" },
3112 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1
, true, "lll" },
3113 { "__insn_icoh", TILEGX_INSN_ICOH
, false, "vk" },
3114 { "__insn_ill", TILEGX_INSN_ILL
, false, "v" },
3115 { "__insn_info", TILEGX_INSN_INFO
, false, "vl" },
3116 { "__insn_infol", TILEGX_INSN_INFOL
, false, "vl" },
3117 { "__insn_inv", TILEGX_INSN_INV
, false, "vp" },
3118 { "__insn_ld", TILEGX_INSN_LD
, false, "lk" },
3119 { "__insn_ld1s", TILEGX_INSN_LD1S
, false, "lk" },
3120 { "__insn_ld1u", TILEGX_INSN_LD1U
, false, "lk" },
3121 { "__insn_ld2s", TILEGX_INSN_LD2S
, false, "lk" },
3122 { "__insn_ld2u", TILEGX_INSN_LD2U
, false, "lk" },
3123 { "__insn_ld4s", TILEGX_INSN_LD4S
, false, "lk" },
3124 { "__insn_ld4u", TILEGX_INSN_LD4U
, false, "lk" },
3125 { "__insn_ldna", TILEGX_INSN_LDNA
, false, "lk" },
3126 { "__insn_ldnt", TILEGX_INSN_LDNT
, false, "lk" },
3127 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S
, false, "lk" },
3128 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U
, false, "lk" },
3129 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S
, false, "lk" },
3130 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U
, false, "lk" },
3131 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S
, false, "lk" },
3132 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U
, false, "lk" },
3133 { "__insn_ld_L2", TILEGX_INSN_LD_L2
, false, "lk" },
3134 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2
, false, "lk" },
3135 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2
, false, "lk" },
3136 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2
, false, "lk" },
3137 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2
, false, "lk" },
3138 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2
, false, "lk" },
3139 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2
, false, "lk" },
3140 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2
, false, "lk" },
3141 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2
, false, "lk" },
3142 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2
, false, "lk" },
3143 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2
, false, "lk" },
3144 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2
, false, "lk" },
3145 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2
, false, "lk" },
3146 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2
, false, "lk" },
3147 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2
, false, "lk" },
3148 { "__insn_ld_miss", TILEGX_INSN_LD_MISS
, false, "lk" },
3149 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS
, false, "lk" },
3150 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS
, false, "lk" },
3151 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS
, false, "lk" },
3152 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS
, false, "lk" },
3153 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS
, false, "lk" },
3154 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS
, false, "lk" },
3155 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS
, false, "lk" },
3156 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS
, false, "lk" },
3157 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS
, false, "lk" },
3158 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS
, false, "lk" },
3159 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS
, false, "lk" },
3160 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS
, false, "lk" },
3161 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS
, false, "lk" },
3162 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS
, false, "lk" },
3163 { "__insn_lnk", TILEGX_INSN_LNK
, true, "l" },
3164 { "__insn_mf", TILEGX_INSN_MF
, false, "v" },
3165 { "__insn_mfspr", TILEGX_INSN_MFSPR
, false, "ll" },
3166 { "__insn_mm", TILEGX_INSN_MM
, true, "lllll"},
3167 { "__insn_mnz", TILEGX_INSN_MNZ
, true, "lll" },
3168 { "__insn_move", TILEGX_INSN_MOVE
, true, "ll" },
3169 { "__insn_movei", TILEGX_INSN_MOVE
, true, "ll" },
3170 { "__insn_moveli", TILEGX_INSN_MOVE
, true, "ll" },
3171 { "__insn_mtspr", TILEGX_INSN_MTSPR
, false, "vll" },
3172 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS
, true, "lll" },
3173 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU
, true, "lll" },
3174 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS
, true, "lll" },
3175 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU
, true, "lll" },
3176 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU
, true, "lll" },
3177 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS
, true, "lll" },
3178 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU
, true, "lll" },
3179 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS
, true, "lll" },
3180 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU
, true, "lll" },
3181 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU
, true, "lll" },
3182 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS
, true, "llll" },
3183 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU
, true, "llll" },
3184 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS
, true, "llll" },
3185 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU
, true, "llll" },
3186 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU
, true, "llll" },
3187 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS
, true, "llll" },
3188 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU
, true, "llll" },
3189 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS
, true, "llll" },
3190 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU
, true, "llll" },
3191 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU
, true, "llll" },
3192 { "__insn_mulax", TILEGX_INSN_MULAX
, true, "iiii" },
3193 { "__insn_mulx", TILEGX_INSN_MULX
, true, "iii" },
3194 { "__insn_mz", TILEGX_INSN_MZ
, true, "lll" },
3195 { "__insn_nap", TILEGX_INSN_NAP
, false, "v" },
3196 { "__insn_nop", TILEGX_INSN_NOP
, true, "v" },
3197 { "__insn_nor", TILEGX_INSN_NOR
, true, "lll" },
3198 { "__insn_or", TILEGX_INSN_OR
, true, "lll" },
3199 { "__insn_ori", TILEGX_INSN_OR
, true, "lll" },
3200 { "__insn_pcnt", TILEGX_INSN_PCNT
, true, "ll" },
3201 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3202 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3203 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT
, false, "vk" },
3204 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2
, false, "vk" },
3205 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT
, false, "vk" },
3206 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3
, false, "vk" },
3207 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT
, false, "vk" },
3208 { "__insn_revbits", TILEGX_INSN_REVBITS
, true, "ll" },
3209 { "__insn_revbytes", TILEGX_INSN_REVBYTES
, true, "ll" },
3210 { "__insn_rotl", TILEGX_INSN_ROTL
, true, "lli" },
3211 { "__insn_rotli", TILEGX_INSN_ROTL
, true, "lli" },
3212 { "__insn_shl", TILEGX_INSN_SHL
, true, "lli" },
3213 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI
, true, "lll" },
3214 { "__insn_shl1add", TILEGX_INSN_SHL1ADD
, true, "lll" },
3215 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX
, true, "iii" },
3216 { "__insn_shl2add", TILEGX_INSN_SHL2ADD
, true, "lll" },
3217 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX
, true, "iii" },
3218 { "__insn_shl3add", TILEGX_INSN_SHL3ADD
, true, "lll" },
3219 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX
, true, "iii" },
3220 { "__insn_shli", TILEGX_INSN_SHL
, true, "lli" },
3221 { "__insn_shlx", TILEGX_INSN_SHLX
, true, "iii" },
3222 { "__insn_shlxi", TILEGX_INSN_SHLX
, true, "iii" },
3223 { "__insn_shrs", TILEGX_INSN_SHRS
, true, "lli" },
3224 { "__insn_shrsi", TILEGX_INSN_SHRS
, true, "lli" },
3225 { "__insn_shru", TILEGX_INSN_SHRU
, true, "lli" },
3226 { "__insn_shrui", TILEGX_INSN_SHRU
, true, "lli" },
3227 { "__insn_shrux", TILEGX_INSN_SHRUX
, true, "iii" },
3228 { "__insn_shruxi", TILEGX_INSN_SHRUX
, true, "iii" },
3229 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES
, true, "llll" },
3230 { "__insn_shufflebytes1", TILEGX_INSN_SHUFFLEBYTES1
, true, "lll" },
3231 { "__insn_st", TILEGX_INSN_ST
, false, "vpl" },
3232 { "__insn_st1", TILEGX_INSN_ST1
, false, "vpl" },
3233 { "__insn_st2", TILEGX_INSN_ST2
, false, "vpl" },
3234 { "__insn_st4", TILEGX_INSN_ST4
, false, "vpl" },
3235 { "__insn_stnt", TILEGX_INSN_STNT
, false, "vpl" },
3236 { "__insn_stnt1", TILEGX_INSN_STNT1
, false, "vpl" },
3237 { "__insn_stnt2", TILEGX_INSN_STNT2
, false, "vpl" },
3238 { "__insn_stnt4", TILEGX_INSN_STNT4
, false, "vpl" },
3239 { "__insn_sub", TILEGX_INSN_SUB
, true, "lll" },
3240 { "__insn_subx", TILEGX_INSN_SUBX
, true, "iii" },
3241 { "__insn_subxsc", TILEGX_INSN_SUBXSC
, true, "iii" },
3242 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0
, true, "lll" },
3243 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1
, true, "lll" },
3244 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2
, true, "lll" },
3245 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3
, true, "lll" },
3246 { "__insn_v1add", TILEGX_INSN_V1ADD
, true, "lll" },
3247 { "__insn_v1addi", TILEGX_INSN_V1ADDI
, true, "lll" },
3248 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC
, true, "lll" },
3249 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU
, true, "lll" },
3250 { "__insn_v1avgu", TILEGX_INSN_V1AVGU
, true, "lll" },
3251 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ
, true, "lll" },
3252 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI
, true, "lll" },
3253 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES
, true, "lll" },
3254 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU
, true, "lll" },
3255 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS
, true, "lll" },
3256 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI
, true, "lll" },
3257 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU
, true, "lll" },
3258 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI
, true, "lll" },
3259 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE
, true, "lll" },
3260 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU
, true, "lll" },
3261 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA
, true, "llll" },
3262 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS
, true, "lll" },
3263 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA
, true, "llll" },
3264 { "__insn_v1dotp", TILEGX_INSN_V1DOTP
, true, "lll" },
3265 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA
, true, "llll" },
3266 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU
, true, "lll" },
3267 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA
, true, "llll" },
3268 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS
, true, "lll" },
3269 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA
, true, "llll" },
3270 { "__insn_v1int_h", TILEGX_INSN_V1INT_H
, true, "lll" },
3271 { "__insn_v1int_l", TILEGX_INSN_V1INT_L
, true, "lll" },
3272 { "__insn_v1maxu", TILEGX_INSN_V1MAXU
, true, "lll" },
3273 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI
, true, "lll" },
3274 { "__insn_v1minu", TILEGX_INSN_V1MINU
, true, "lll" },
3275 { "__insn_v1minui", TILEGX_INSN_V1MINUI
, true, "lll" },
3276 { "__insn_v1mnz", TILEGX_INSN_V1MNZ
, true, "lll" },
3277 { "__insn_v1multu", TILEGX_INSN_V1MULTU
, true, "lll" },
3278 { "__insn_v1mulu", TILEGX_INSN_V1MULU
, true, "lll" },
3279 { "__insn_v1mulus", TILEGX_INSN_V1MULUS
, true, "lll" },
3280 { "__insn_v1mz", TILEGX_INSN_V1MZ
, true, "lll" },
3281 { "__insn_v1sadau", TILEGX_INSN_V1SADAU
, true, "llll" },
3282 { "__insn_v1sadu", TILEGX_INSN_V1SADU
, true, "lll" },
3283 { "__insn_v1shl", TILEGX_INSN_V1SHL
, true, "lll" },
3284 { "__insn_v1shli", TILEGX_INSN_V1SHLI
, true, "lll" },
3285 { "__insn_v1shrs", TILEGX_INSN_V1SHRS
, true, "lll" },
3286 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI
, true, "lll" },
3287 { "__insn_v1shru", TILEGX_INSN_V1SHRU
, true, "lll" },
3288 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI
, true, "lll" },
3289 { "__insn_v1sub", TILEGX_INSN_V1SUB
, true, "lll" },
3290 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC
, true, "lll" },
3291 { "__insn_v2add", TILEGX_INSN_V2ADD
, true, "lll" },
3292 { "__insn_v2addi", TILEGX_INSN_V2ADDI
, true, "lll" },
3293 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC
, true, "lll" },
3294 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS
, true, "lll" },
3295 { "__insn_v2avgs", TILEGX_INSN_V2AVGS
, true, "lll" },
3296 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ
, true, "lll" },
3297 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI
, true, "lll" },
3298 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES
, true, "lll" },
3299 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU
, true, "lll" },
3300 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS
, true, "lll" },
3301 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI
, true, "lll" },
3302 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU
, true, "lll" },
3303 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI
, true, "lll" },
3304 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE
, true, "lll" },
3305 { "__insn_v2dotp", TILEGX_INSN_V2DOTP
, true, "lll" },
3306 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA
, true, "llll" },
3307 { "__insn_v2int_h", TILEGX_INSN_V2INT_H
, true, "lll" },
3308 { "__insn_v2int_l", TILEGX_INSN_V2INT_L
, true, "lll" },
3309 { "__insn_v2maxs", TILEGX_INSN_V2MAXS
, true, "lll" },
3310 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI
, true, "lll" },
3311 { "__insn_v2mins", TILEGX_INSN_V2MINS
, true, "lll" },
3312 { "__insn_v2minsi", TILEGX_INSN_V2MINSI
, true, "lll" },
3313 { "__insn_v2mnz", TILEGX_INSN_V2MNZ
, true, "lll" },
3314 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC
, true, "lll" },
3315 { "__insn_v2muls", TILEGX_INSN_V2MULS
, true, "lll" },
3316 { "__insn_v2mults", TILEGX_INSN_V2MULTS
, true, "lll" },
3317 { "__insn_v2mz", TILEGX_INSN_V2MZ
, true, "lll" },
3318 { "__insn_v2packh", TILEGX_INSN_V2PACKH
, true, "lll" },
3319 { "__insn_v2packl", TILEGX_INSN_V2PACKL
, true, "lll" },
3320 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC
, true, "lll" },
3321 { "__insn_v2sadas", TILEGX_INSN_V2SADAS
, true, "llll" },
3322 { "__insn_v2sadau", TILEGX_INSN_V2SADAU
, true, "llll" },
3323 { "__insn_v2sads", TILEGX_INSN_V2SADS
, true, "lll" },
3324 { "__insn_v2sadu", TILEGX_INSN_V2SADU
, true, "lll" },
3325 { "__insn_v2shl", TILEGX_INSN_V2SHL
, true, "lll" },
3326 { "__insn_v2shli", TILEGX_INSN_V2SHLI
, true, "lll" },
3327 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC
, true, "lll" },
3328 { "__insn_v2shrs", TILEGX_INSN_V2SHRS
, true, "lll" },
3329 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI
, true, "lll" },
3330 { "__insn_v2shru", TILEGX_INSN_V2SHRU
, true, "lll" },
3331 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI
, true, "lll" },
3332 { "__insn_v2sub", TILEGX_INSN_V2SUB
, true, "lll" },
3333 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC
, true, "lll" },
3334 { "__insn_v4add", TILEGX_INSN_V4ADD
, true, "lll" },
3335 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC
, true, "lll" },
3336 { "__insn_v4int_h", TILEGX_INSN_V4INT_H
, true, "lll" },
3337 { "__insn_v4int_l", TILEGX_INSN_V4INT_L
, true, "lll" },
3338 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC
, true, "lll" },
3339 { "__insn_v4shl", TILEGX_INSN_V4SHL
, true, "lll" },
3340 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC
, true, "lll" },
3341 { "__insn_v4shrs", TILEGX_INSN_V4SHRS
, true, "lll" },
3342 { "__insn_v4shru", TILEGX_INSN_V4SHRU
, true, "lll" },
3343 { "__insn_v4sub", TILEGX_INSN_V4SUB
, true, "lll" },
3344 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC
, true, "lll" },
3345 { "__insn_wh64", TILEGX_INSN_WH64
, false, "vp" },
3346 { "__insn_xor", TILEGX_INSN_XOR
, true, "lll" },
3347 { "__insn_xori", TILEGX_INSN_XOR
, true, "lll" },
3348 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER
, false, "v" },
3349 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE
, false, "l" },
3350 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE
, false, "l" },
3351 { "__tile_idn_send", TILEGX_IDN_SEND
, false, "vl" },
3352 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE
, false, "l" },
3353 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE
, false, "l" },
3354 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE
, false, "l" },
3355 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE
, false, "l" },
3356 { "__tile_udn_send", TILEGX_UDN_SEND
, false, "vl" },
3360 /* Convert a character in a builtin type string to a tree type. */
3362 char_to_type (char c
)
3364 static tree volatile_ptr_type_node
= NULL
;
3365 static tree volatile_const_ptr_type_node
= NULL
;
3367 if (volatile_ptr_type_node
== NULL
)
3369 volatile_ptr_type_node
=
3370 build_pointer_type (build_qualified_type (void_type_node
,
3371 TYPE_QUAL_VOLATILE
));
3372 volatile_const_ptr_type_node
=
3373 build_pointer_type (build_qualified_type (void_type_node
,
3375 | TYPE_QUAL_VOLATILE
));
3381 return void_type_node
;
3383 return unsigned_type_node
;
3385 return long_long_unsigned_type_node
;
3387 return volatile_ptr_type_node
;
3389 return volatile_const_ptr_type_node
;
3396 /* Implement TARGET_INIT_BUILTINS. */
3398 tilegx_init_builtins (void)
3402 for (i
= 0; i
< ARRAY_SIZE (tilegx_builtins
); i
++)
3404 const struct tilegx_builtin_def
*p
= &tilegx_builtins
[i
];
3405 tree ftype
, ret_type
, arg_type_list
= void_list_node
;
3409 for (j
= strlen (p
->type
) - 1; j
> 0; j
--)
3412 tree_cons (NULL_TREE
, char_to_type (p
->type
[j
]), arg_type_list
);
3415 ret_type
= char_to_type (p
->type
[0]);
3417 ftype
= build_function_type (ret_type
, arg_type_list
);
3419 decl
= add_builtin_function (p
->name
, ftype
, p
->code
, BUILT_IN_MD
,
3423 TREE_READONLY (decl
) = 1;
3424 TREE_NOTHROW (decl
) = 1;
3426 if (tilegx_builtin_info
[p
->code
].fndecl
== NULL
)
3427 tilegx_builtin_info
[p
->code
].fndecl
= decl
;
3432 /* Implement TARGET_EXPAND_BUILTIN. */
3434 tilegx_expand_builtin (tree exp
,
3436 rtx subtarget ATTRIBUTE_UNUSED
,
3437 enum machine_mode mode ATTRIBUTE_UNUSED
,
3438 int ignore ATTRIBUTE_UNUSED
)
3440 #define MAX_BUILTIN_ARGS 4
3442 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
3443 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
3445 call_expr_arg_iterator iter
;
3446 enum insn_code icode
;
3447 rtx op
[MAX_BUILTIN_ARGS
+ 1], pat
;
3452 if (fcode
>= TILEGX_BUILTIN_max
)
3453 internal_error ("bad builtin fcode");
3454 icode
= tilegx_builtin_info
[fcode
].icode
;
3456 internal_error ("bad builtin icode");
3458 nonvoid
= TREE_TYPE (TREE_TYPE (fndecl
)) != void_type_node
;
3461 FOR_EACH_CALL_EXPR_ARG (arg
, iter
, exp
)
3463 const struct insn_operand_data
*insn_op
;
3465 if (arg
== error_mark_node
)
3467 if (opnum
> MAX_BUILTIN_ARGS
)
3470 insn_op
= &insn_data
[icode
].operand
[opnum
];
3472 op
[opnum
] = expand_expr (arg
, NULL_RTX
, insn_op
->mode
, EXPAND_NORMAL
);
3474 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3476 enum machine_mode opmode
= insn_op
->mode
;
3478 /* pointer_operand and pmode_register_operand operands do
3479 not specify a mode, so use the operand's mode instead
3480 (which should always be right by the time we get here,
3481 except for constants, which are VOIDmode). */
3482 if (opmode
== VOIDmode
)
3484 enum machine_mode m
= GET_MODE (op
[opnum
]);
3485 gcc_assert (m
== Pmode
|| m
== VOIDmode
);
3489 op
[opnum
] = copy_to_mode_reg (opmode
, op
[opnum
]);
3492 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3494 /* We still failed to meet the predicate even after moving
3495 into a register. Assume we needed an immediate. */
3496 error_at (EXPR_LOCATION (exp
),
3497 "operand must be an immediate of the right size");
3506 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
3508 || GET_MODE (target
) != tmode
3509 || !(*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
3511 if (tmode
== VOIDmode
)
3513 /* get the mode from the return type. */
3514 tmode
= TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl
)));
3516 target
= gen_reg_rtx (tmode
);
3521 fn
= GEN_FCN (icode
);
3525 pat
= fn (NULL_RTX
);
3531 pat
= fn (op
[0], op
[1]);
3534 pat
= fn (op
[0], op
[1], op
[2]);
3537 pat
= fn (op
[0], op
[1], op
[2], op
[3]);
3540 pat
= fn (op
[0], op
[1], op
[2], op
[3], op
[4]);
3556 /* Implement TARGET_BUILTIN_DECL. */
3558 tilegx_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
3560 if (code
>= TILEGX_BUILTIN_max
)
3561 return error_mark_node
;
3563 return tilegx_builtin_info
[code
].fndecl
;
3570 /* Return whether REGNO needs to be saved in the stack frame. */
3572 need_to_save_reg (unsigned int regno
)
3574 if (!fixed_regs
[regno
] && !call_used_regs
[regno
]
3575 && df_regs_ever_live_p (regno
))
3579 && (regno
== PIC_OFFSET_TABLE_REGNUM
3580 || regno
== TILEGX_PIC_TEXT_LABEL_REGNUM
)
3581 && (crtl
->uses_pic_offset_table
|| crtl
->saves_all_registers
))
3584 if (crtl
->calls_eh_return
)
3587 for (i
= 0; EH_RETURN_DATA_REGNO (i
) != INVALID_REGNUM
; i
++)
3589 if (regno
== EH_RETURN_DATA_REGNO (i
))
3598 /* Return the size of the register savev area. This function is only
3599 correct starting with local register allocation */
3601 tilegx_saved_regs_size (void)
3603 int reg_save_size
= 0;
3605 int offset_to_frame
;
3608 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
3609 if (need_to_save_reg (regno
))
3610 reg_save_size
+= UNITS_PER_WORD
;
3612 /* Pad out the register save area if necessary to make
3613 frame_pointer_rtx be as aligned as the stack pointer. */
3614 offset_to_frame
= crtl
->args
.pretend_args_size
+ reg_save_size
;
3615 align_mask
= (STACK_BOUNDARY
/ BITS_PER_UNIT
) - 1;
3616 reg_save_size
+= (-offset_to_frame
) & align_mask
;
3618 return reg_save_size
;
3622 /* Round up frame size SIZE. */
3624 round_frame_size (int size
)
3626 return ((size
+ STACK_BOUNDARY
/ BITS_PER_UNIT
- 1)
3627 & -STACK_BOUNDARY
/ BITS_PER_UNIT
);
3631 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3632 emit the corresponding REG_CFA_OFFSET note described by CFA and
3633 CFA_OFFSET. Return the emitted insn. */
3635 frame_emit_store (int regno
, int regno_note
, rtx addr
, rtx cfa
,
3638 rtx reg
= gen_rtx_REG (DImode
, regno
);
3639 rtx mem
= gen_frame_mem (DImode
, addr
);
3640 rtx mov
= gen_movdi (mem
, reg
);
3642 /* Describe what just happened in a way that dwarf understands. We
3643 use temporary registers to hold the address to make scheduling
3644 easier, and use the REG_CFA_OFFSET to describe the address as an
3645 offset from the CFA. */
3646 rtx reg_note
= gen_rtx_REG (DImode
, regno_note
);
3647 rtx cfa_relative_addr
= gen_rtx_PLUS (Pmode
, cfa
, GEN_INT (cfa_offset
));
3648 rtx cfa_relative_mem
= gen_frame_mem (DImode
, cfa_relative_addr
);
3649 rtx real
= gen_rtx_SET (VOIDmode
, cfa_relative_mem
, reg_note
);
3650 add_reg_note (mov
, REG_CFA_OFFSET
, real
);
3652 return emit_insn (mov
);
3656 /* Emit a load in the stack frame to load REGNO from address ADDR.
3657 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3658 non-null. Return the emitted insn. */
3660 frame_emit_load (int regno
, rtx addr
, rtx
*cfa_restores
)
3662 rtx reg
= gen_rtx_REG (DImode
, regno
);
3663 rtx mem
= gen_frame_mem (DImode
, addr
);
3665 *cfa_restores
= alloc_reg_note (REG_CFA_RESTORE
, reg
, *cfa_restores
);
3666 return emit_insn (gen_movdi (reg
, mem
));
3670 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3671 including sequences. */
3673 set_frame_related_p (void)
3675 rtx seq
= get_insns ();
3686 while (insn
!= NULL_RTX
)
3688 RTX_FRAME_RELATED_P (insn
) = 1;
3689 insn
= NEXT_INSN (insn
);
3691 seq
= emit_insn (seq
);
3695 seq
= emit_insn (seq
);
3696 RTX_FRAME_RELATED_P (seq
) = 1;
3702 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3704 /* This emits code for 'sp += offset'.
3706 The ABI only allows us to modify 'sp' in a single 'addi' or
3707 'addli', so the backtracer understands it. Larger amounts cannot
3708 use those instructions, so are added by placing the offset into a
3709 large register and using 'add'.
3711 This happens after reload, so we need to expand it ourselves. */
3713 emit_sp_adjust (int offset
, int *next_scratch_regno
, bool frame_related
,
3717 rtx imm_rtx
= GEN_INT (offset
);
3720 if (satisfies_constraint_J (imm_rtx
))
3722 /* We can add this using a single immediate add. */
3727 rtx tmp
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3728 tilegx_expand_set_const64 (tmp
, imm_rtx
);
3732 /* Actually adjust the stack pointer. */
3734 insn
= gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3736 insn
= gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3738 insn
= emit_insn (insn
);
3739 REG_NOTES (insn
) = reg_notes
;
3741 /* Describe what just happened in a way that dwarf understands. */
3744 rtx real
= gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
3745 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3747 RTX_FRAME_RELATED_P (insn
) = 1;
3748 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, real
);
3755 /* Return whether the current function is leaf. This takes into
3756 account whether the function calls tls_get_addr. */
3758 tilegx_current_function_is_leaf (void)
3760 return crtl
->is_leaf
&& !cfun
->machine
->calls_tls_get_addr
;
3764 /* Return the frame size. */
3766 compute_total_frame_size (void)
3768 int total_size
= (get_frame_size () + tilegx_saved_regs_size ()
3769 + crtl
->outgoing_args_size
3770 + crtl
->args
.pretend_args_size
);
3772 if (!tilegx_current_function_is_leaf () || cfun
->calls_alloca
)
3774 /* Make room for save area in callee. */
3775 total_size
+= STACK_POINTER_OFFSET
;
3778 return round_frame_size (total_size
);
3782 /* Return nonzero if this function is known to have a null epilogue.
3783 This allows the optimizer to omit jumps to jumps if no stack was
3786 tilegx_can_use_return_insn_p (void)
3788 return (reload_completed
3789 && cfun
->static_chain_decl
== 0
3790 && compute_total_frame_size () == 0
3791 && tilegx_current_function_is_leaf ()
3792 && !crtl
->profile
&& !df_regs_ever_live_p (TILEGX_LINK_REGNUM
));
3796 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3797 is a frame pointer, it computes the value relative to
3798 that. Otherwise it uses the stack pointer. */
3800 compute_frame_addr (int offset_from_fp
, int *next_scratch_regno
)
3802 rtx base_reg_rtx
, tmp_reg_rtx
, offset_rtx
;
3803 int offset_from_base
;
3805 if (frame_pointer_needed
)
3807 base_reg_rtx
= hard_frame_pointer_rtx
;
3808 offset_from_base
= offset_from_fp
;
3812 int offset_from_sp
= compute_total_frame_size () + offset_from_fp
;
3813 offset_from_base
= offset_from_sp
;
3814 base_reg_rtx
= stack_pointer_rtx
;
3817 if (offset_from_base
== 0)
3818 return base_reg_rtx
;
3820 /* Compute the new value of the stack pointer. */
3821 tmp_reg_rtx
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3822 offset_rtx
= GEN_INT (offset_from_base
);
3824 if (!add_operand (offset_rtx
, Pmode
))
3826 expand_set_cint64 (tmp_reg_rtx
, offset_rtx
);
3827 offset_rtx
= tmp_reg_rtx
;
3830 emit_insn (gen_rtx_SET (VOIDmode
, tmp_reg_rtx
,
3831 gen_rtx_PLUS (Pmode
, base_reg_rtx
, offset_rtx
)));
3837 /* The stack frame looks like this:
3842 AP -> +-------------+
3846 HFP -> +-------------+
3848 | reg save | crtl->args.pretend_args_size bytes
3851 | saved regs | tilegx_saved_regs_size() bytes
3852 FP -> +-------------+
3854 | vars | get_frame_size() bytes
3858 | stack args | crtl->outgoing_args_size bytes
3860 | HFP | ptr_size bytes (only here if nonleaf / alloca)
3862 | callee lr | ptr_size bytes (only here if nonleaf / alloca)
3864 SP -> +-------------+
3868 For functions with a frame larger than 32767 bytes, or which use
3869 alloca (), r52 is used as a frame pointer. Otherwise there is no
3872 FP is saved at SP+ptr_size before calling a subroutine so the callee
3875 tilegx_expand_prologue (void)
3877 #define ROUND_ROBIN_SIZE 4
3878 /* We round-robin through four scratch registers to hold temporary
3879 addresses for saving registers, to make instruction scheduling
3881 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
3882 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
3885 unsigned int which_scratch
;
3886 int offset
, start_offset
, regno
;
3888 /* A register that holds a copy of the incoming fp. */
3889 int fp_copy_regno
= -1;
3891 /* A register that holds a copy of the incoming sp. */
3892 int sp_copy_regno
= -1;
3894 /* Next scratch register number to hand out (postdecrementing). */
3895 int next_scratch_regno
= 29;
3897 int total_size
= compute_total_frame_size ();
3899 if (flag_stack_usage_info
)
3900 current_function_static_stack_size
= total_size
;
3902 /* Save lr first in its special location because code after this
3903 might use the link register as a scratch register. */
3904 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
) || crtl
->calls_eh_return
)
3905 FRP (frame_emit_store (TILEGX_LINK_REGNUM
, TILEGX_LINK_REGNUM
,
3906 stack_pointer_rtx
, stack_pointer_rtx
, 0));
3908 if (total_size
== 0)
3910 /* Load the PIC register if needed. */
3911 if (flag_pic
&& crtl
->uses_pic_offset_table
)
3912 load_pic_register (false);
3917 cfa
= stack_pointer_rtx
;
3919 if (frame_pointer_needed
)
3921 fp_copy_regno
= next_scratch_regno
--;
3923 /* Copy the old frame pointer aside so we can save it later. */
3925 FRP (emit_move_insn (gen_rtx_REG (word_mode
, fp_copy_regno
),
3926 gen_lowpart (word_mode
, hard_frame_pointer_rtx
)));
3927 add_reg_note (insn
, REG_CFA_REGISTER
, NULL_RTX
);
3929 /* Set up the frame pointer. */
3930 insn
= FRP (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
3931 add_reg_note (insn
, REG_CFA_DEF_CFA
, hard_frame_pointer_rtx
);
3932 cfa
= hard_frame_pointer_rtx
;
3933 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM
) = STACK_BOUNDARY
;
3935 /* fp holds a copy of the incoming sp, in case we need to store
3937 sp_copy_regno
= HARD_FRAME_POINTER_REGNUM
;
3939 else if (!tilegx_current_function_is_leaf ())
3941 /* Copy the old stack pointer aside so we can save it later. */
3942 sp_copy_regno
= next_scratch_regno
--;
3943 emit_move_insn (gen_rtx_REG (Pmode
, sp_copy_regno
),
3947 if (tilegx_current_function_is_leaf ())
3949 /* No need to store chain pointer to caller's frame. */
3950 emit_sp_adjust (-total_size
, &next_scratch_regno
,
3951 !frame_pointer_needed
, NULL_RTX
);
3955 /* Save the frame pointer (incoming sp value) to support
3956 backtracing. First we need to create an rtx with the store
3958 rtx chain_addr
= gen_rtx_REG (Pmode
, next_scratch_regno
--);
3959 rtx size_rtx
= GEN_INT (-(total_size
- UNITS_PER_WORD
));
3961 if (add_operand (size_rtx
, Pmode
))
3963 /* Expose more parallelism by computing this value from the
3964 original stack pointer, not the one after we have pushed
3966 rtx p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, size_rtx
);
3967 emit_insn (gen_rtx_SET (VOIDmode
, chain_addr
, p
));
3968 emit_sp_adjust (-total_size
, &next_scratch_regno
,
3969 !frame_pointer_needed
, NULL_RTX
);
3973 /* The stack frame is large, so just store the incoming sp
3974 value at *(new_sp + UNITS_PER_WORD). */
3976 emit_sp_adjust (-total_size
, &next_scratch_regno
,
3977 !frame_pointer_needed
, NULL_RTX
);
3978 p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3979 GEN_INT (UNITS_PER_WORD
));
3980 emit_insn (gen_rtx_SET (VOIDmode
, chain_addr
, p
));
3983 /* Save our frame pointer for backtrace chaining. */
3984 emit_insn (gen_movdi (gen_frame_mem (DImode
, chain_addr
),
3985 gen_rtx_REG (DImode
, sp_copy_regno
)));
3988 /* Compute where to start storing registers we need to save. */
3989 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
3990 offset
= start_offset
;
3992 /* Store all registers that need saving. */
3994 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
3995 if (need_to_save_reg (regno
))
3997 rtx r
= reg_save_addr
[which_scratch
];
3999 int cfa_offset
= frame_pointer_needed
? offset
: total_size
+ offset
;
4003 int prev_scratch_regno
= next_scratch_regno
;
4004 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4005 if (prev_scratch_regno
!= next_scratch_regno
)
4006 reg_save_addr
[which_scratch
] = r
;
4010 /* Advance to the next stack slot to store this
4012 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4013 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4014 emit_insn (gen_rtx_SET (VOIDmode
, r
, p
));
4017 /* Save this register to the stack (but use the old fp value
4018 we copied aside if appropriate). */
4020 (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4021 ? fp_copy_regno
: regno
;
4022 FRP (frame_emit_store (from_regno
, regno
, r
, cfa
, cfa_offset
));
4024 offset
-= UNITS_PER_WORD
;
4025 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4028 /* If profiling, force that to happen after the frame is set up. */
4030 emit_insn (gen_blockage ());
4032 /* Load the PIC register if needed. */
4033 if (flag_pic
&& crtl
->uses_pic_offset_table
)
4034 load_pic_register (false);
4038 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
4039 true for a sibcall_epilogue pattern, and false for an epilogue
4042 tilegx_expand_epilogue (bool sibcall_p
)
4044 /* We round-robin through four scratch registers to hold temporary
4045 addresses for saving registers, to make instruction scheduling
4047 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
4048 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
4050 rtx last_insn
, insn
;
4051 unsigned int which_scratch
;
4052 int offset
, start_offset
, regno
;
4053 rtx cfa_restores
= NULL_RTX
;
4055 /* A register that holds a copy of the incoming fp. */
4056 int fp_copy_regno
= -1;
4058 /* Next scratch register number to hand out (postdecrementing). */
4059 int next_scratch_regno
= 29;
4061 int total_size
= compute_total_frame_size ();
4063 last_insn
= get_last_insn ();
4065 /* Load lr first since we are going to need it first. */
4067 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
))
4069 insn
= frame_emit_load (TILEGX_LINK_REGNUM
,
4070 compute_frame_addr (0, &next_scratch_regno
),
4074 if (total_size
== 0)
4078 RTX_FRAME_RELATED_P (insn
) = 1;
4079 REG_NOTES (insn
) = cfa_restores
;
4084 /* Compute where to start restoring registers. */
4085 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
4086 offset
= start_offset
;
4088 if (frame_pointer_needed
)
4089 fp_copy_regno
= next_scratch_regno
--;
4091 /* Restore all callee-saved registers. */
4093 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
4094 if (need_to_save_reg (regno
))
4096 rtx r
= reg_save_addr
[which_scratch
];
4099 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4100 reg_save_addr
[which_scratch
] = r
;
4104 /* Advance to the next stack slot to store this register. */
4105 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4106 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4107 emit_insn (gen_rtx_SET (VOIDmode
, r
, p
));
4110 if (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4111 frame_emit_load (fp_copy_regno
, r
, NULL
);
4113 frame_emit_load (regno
, r
, &cfa_restores
);
4115 offset
-= UNITS_PER_WORD
;
4116 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4119 if (!tilegx_current_function_is_leaf ())
4121 alloc_reg_note (REG_CFA_RESTORE
, stack_pointer_rtx
, cfa_restores
);
4123 emit_insn (gen_blockage ());
4125 if (frame_pointer_needed
)
4127 /* Restore the old stack pointer by copying from the frame
4131 insn
= emit_insn (gen_sp_restore_32bit (stack_pointer_rtx
,
4132 hard_frame_pointer_rtx
));
4136 insn
= emit_insn (gen_sp_restore (stack_pointer_rtx
,
4137 hard_frame_pointer_rtx
));
4139 RTX_FRAME_RELATED_P (insn
) = 1;
4140 REG_NOTES (insn
) = cfa_restores
;
4141 add_reg_note (insn
, REG_CFA_DEF_CFA
, stack_pointer_rtx
);
4145 insn
= emit_sp_adjust (total_size
, &next_scratch_regno
, true,
4149 if (crtl
->calls_eh_return
)
4152 emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
,
4153 EH_RETURN_STACKADJ_RTX
));
4155 emit_insn (gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
,
4156 EH_RETURN_STACKADJ_RTX
));
4159 /* Restore the old frame pointer. */
4160 if (frame_pointer_needed
)
4162 insn
= emit_move_insn (gen_lowpart (DImode
, hard_frame_pointer_rtx
),
4163 gen_rtx_REG (DImode
, fp_copy_regno
));
4164 add_reg_note (insn
, REG_CFA_RESTORE
, hard_frame_pointer_rtx
);
4167 /* Mark the pic registers as live outside of the function. */
4170 emit_use (cfun
->machine
->text_label_rtx
);
4171 emit_use (cfun
->machine
->got_rtx
);
4177 emit_jump_insn (gen__return ());
4181 emit_use (gen_rtx_REG (Pmode
, TILEGX_LINK_REGNUM
));
4184 /* Mark all insns we just emitted as frame-related. */
4185 for (; last_insn
!= NULL_RTX
; last_insn
= next_insn (last_insn
))
4186 RTX_FRAME_RELATED_P (last_insn
) = 1;
4189 #undef ROUND_ROBIN_SIZE
4192 /* Implement INITIAL_ELIMINATION_OFFSET. */
4194 tilegx_initial_elimination_offset (int from
, int to
)
4196 int total_size
= compute_total_frame_size ();
4198 if (from
== FRAME_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4200 return (total_size
- crtl
->args
.pretend_args_size
4201 - tilegx_saved_regs_size ());
4203 else if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4205 return -(crtl
->args
.pretend_args_size
+ tilegx_saved_regs_size ());
4207 else if (from
== ARG_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4209 return STACK_POINTER_OFFSET
+ total_size
;
4211 else if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4213 return STACK_POINTER_OFFSET
;
4220 /* Return an RTX indicating where the return address to the calling
4221 function can be found. */
4223 tilegx_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
4228 return get_hard_reg_initial_val (Pmode
, TILEGX_LINK_REGNUM
);
4232 /* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to
4233 prevent it from being deleted. */
4235 tilegx_eh_return_handler_rtx (void)
4237 rtx tmp
= gen_frame_mem (Pmode
, hard_frame_pointer_rtx
);
4238 MEM_VOLATILE_P (tmp
) = true;
4246 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
4248 tilegx_conditional_register_usage (void)
4250 global_regs
[TILEGX_NETORDER_REGNUM
] = 1;
4251 /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
4252 member of fixed_regs, and therefore must be member of
4253 call_used_regs, but it is not a member of call_really_used_regs[]
4254 because it is not clobbered by a call. */
4255 if (TILEGX_PIC_TEXT_LABEL_REGNUM
!= INVALID_REGNUM
)
4257 fixed_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4258 call_used_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4260 if (PIC_OFFSET_TABLE_REGNUM
!= INVALID_REGNUM
)
4262 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4263 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4268 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
4270 tilegx_frame_pointer_required (void)
4272 return crtl
->calls_eh_return
|| cfun
->calls_alloca
;
4277 /* Scheduling and reorg */
4279 /* Return the length of INSN. LENGTH is the initial length computed
4280 by attributes in the machine-description file. This is where we
4281 account for bundles. */
4283 tilegx_adjust_insn_length (rtx insn
, int length
)
4285 enum machine_mode mode
= GET_MODE (insn
);
4287 /* A non-termininating instruction in a bundle has length 0. */
4291 /* By default, there is not length adjustment. */
4296 /* Implement TARGET_SCHED_ISSUE_RATE. */
4298 tilegx_issue_rate (void)
4304 /* Return the rtx for the jump target. */
4306 get_jump_target (rtx branch
)
4308 if (CALL_P (branch
))
4311 call
= PATTERN (branch
);
4313 if (GET_CODE (call
) == PARALLEL
)
4314 call
= XVECEXP (call
, 0, 0);
4316 if (GET_CODE (call
) == SET
)
4317 call
= SET_SRC (call
);
4319 if (GET_CODE (call
) == CALL
)
4320 return XEXP (XEXP (call
, 0), 0);
4326 /* Implement TARGET_SCHED_ADJUST_COST. */
4328 tilegx_sched_adjust_cost (rtx insn
, rtx link
, rtx dep_insn
, int cost
)
4330 /* If we have a true dependence, INSN is a call, and DEP_INSN
4331 defines a register that is needed by the call (argument or stack
4332 pointer) , set its latency to 0 so that it can be bundled with
4333 the call. Explicitly check for and exclude the case when
4334 DEP_INSN defines the target of the jump. */
4335 if (CALL_P (insn
) && REG_NOTE_KIND (link
) == REG_DEP_TRUE
)
4337 rtx target
= get_jump_target (insn
);
4338 if (!REG_P (target
) || !set_of (target
, dep_insn
))
4346 /* Skip over irrelevant NOTEs and such and look for the next insn we
4347 would consider bundling. */
4349 next_insn_to_bundle (rtx r
, rtx end
)
4351 for (; r
!= end
; r
= NEXT_INSN (r
))
4353 if (NONDEBUG_INSN_P (r
)
4354 && GET_CODE (PATTERN (r
)) != USE
4355 && GET_CODE (PATTERN (r
)) != CLOBBER
)
4363 /* Go through all insns, and use the information generated during
4364 scheduling to generate SEQUENCEs to represent bundles of
4365 instructions issued simultaneously. */
4367 tilegx_gen_bundles (void)
4373 rtx end
= NEXT_INSN (BB_END (bb
));
4375 for (insn
= next_insn_to_bundle (BB_HEAD (bb
), end
); insn
; insn
= next
)
4377 next
= next_insn_to_bundle (NEXT_INSN (insn
), end
);
4379 /* Never wrap {} around inline asm. */
4380 if (GET_CODE (PATTERN (insn
)) != ASM_INPUT
)
4382 if (next
== NULL_RTX
|| GET_MODE (next
) == TImode
4383 /* NOTE: The scheduler incorrectly believes a call
4384 insn can execute in the same cycle as the insn
4385 after the call. This is of course impossible.
4386 Really we need to fix the scheduler somehow, so
4387 the code after the call gets scheduled
4391 /* Mark current insn as the end of a bundle. */
4392 PUT_MODE (insn
, QImode
);
4396 /* Mark it as part of a bundle. */
4397 PUT_MODE (insn
, SImode
);
4405 /* Replace OLD_INSN with NEW_INSN. */
4407 replace_insns (rtx old_insn
, rtx new_insns
)
4410 emit_insn_before (new_insns
, old_insn
);
4412 delete_insn (old_insn
);
4416 /* Returns true if INSN is the first instruction of a pc-relative
4417 address compuatation. */
4419 match_pcrel_step1 (rtx insn
)
4421 rtx pattern
= PATTERN (insn
);
4424 if (GET_CODE (pattern
) != SET
)
4427 src
= SET_SRC (pattern
);
4429 return (GET_CODE (src
) == CONST
4430 && GET_CODE (XEXP (src
, 0)) == UNSPEC
4431 && XINT (XEXP (src
, 0), 1) == UNSPEC_HW1_LAST_PCREL
);
4435 /* Do the first replacement step in tilegx_fixup_pcrel_references. */
4437 replace_mov_pcrel_step1 (rtx insn
)
4439 rtx pattern
= PATTERN (insn
);
4444 gcc_assert (GET_CODE (pattern
) == SET
);
4445 opnds
[0] = SET_DEST (pattern
);
4447 gcc_assert (GET_CODE (SET_SRC (pattern
)) == CONST
);
4449 unspec
= XEXP (SET_SRC (pattern
), 0);
4450 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4451 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW1_LAST_PCREL
);
4452 opnds
[1] = XVECEXP (unspec
, 0, 0);
4454 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4455 if (GET_CODE (opnds
[1]) != SYMBOL_REF
)
4463 emit_insn (gen_mov_got32_step1_32bit (opnds
[0], opnds
[1]));
4465 emit_insn (gen_mov_got32_step1 (opnds
[0], opnds
[1]));
4468 new_insns
= get_insns ();
4471 replace_insns (insn
, new_insns
);
4475 /* Returns true if INSN is the second instruction of a pc-relative
4476 address compuatation. */
4478 match_pcrel_step2 (rtx insn
)
4485 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli_32bit
)
4490 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli
)
4494 unspec
= SET_SRC (PATTERN (insn
));
4495 addr
= XVECEXP (unspec
, 0, 1);
4497 return (GET_CODE (addr
) == CONST
4498 && GET_CODE (XEXP (addr
, 0)) == UNSPEC
4499 && XINT (XEXP (addr
, 0), 1) == UNSPEC_HW0_PCREL
);
4503 /* Do the second replacement step in tilegx_fixup_pcrel_references. */
4505 replace_mov_pcrel_step2 (rtx insn
)
4507 rtx pattern
= PATTERN (insn
);
4512 rtx got_rtx
= tilegx_got_rtx ();
4514 gcc_assert (GET_CODE (pattern
) == SET
);
4515 opnds
[0] = SET_DEST (pattern
);
4517 unspec
= SET_SRC (pattern
);
4518 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4519 gcc_assert (XINT (unspec
, 1) == UNSPEC_INSN_ADDR_SHL16INSLI
);
4521 opnds
[1] = XVECEXP (unspec
, 0, 0);
4523 addr
= XVECEXP (unspec
, 0, 1);
4524 gcc_assert (GET_CODE (addr
) == CONST
);
4526 unspec
= XEXP (addr
, 0);
4527 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4528 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW0_PCREL
);
4529 opnds
[2] = XVECEXP (unspec
, 0, 0);
4531 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4532 if (GET_CODE (opnds
[2]) != SYMBOL_REF
)
4540 emit_insn (gen_add_got16_32bit (opnds
[0], got_rtx
, opnds
[2]));
4542 emit_insn (gen_add_got16 (opnds
[0], got_rtx
, opnds
[2]));
4547 emit_insn (gen_mov_got32_step2_32bit
4548 (opnds
[0], opnds
[1], opnds
[2]));
4550 emit_insn (gen_mov_got32_step2 (opnds
[0], opnds
[1], opnds
[2]));
4553 new_insns
= get_insns ();
4556 replace_insns (insn
, new_insns
);
4560 /* Do the third replacement step in tilegx_fixup_pcrel_references. */
4562 replace_mov_pcrel_step3 (rtx insn
)
4564 rtx pattern
= PATTERN (insn
);
4568 rtx got_rtx
= tilegx_got_rtx ();
4569 rtx text_label_rtx
= tilegx_text_label_rtx ();
4571 gcc_assert (GET_CODE (pattern
) == SET
);
4572 opnds
[0] = SET_DEST (pattern
);
4574 unspec
= SET_SRC (pattern
);
4575 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4576 gcc_assert (XINT (unspec
, 1) == UNSPEC_MOV_PCREL_STEP3
);
4580 if (XVECEXP (unspec
, 0, 0) == text_label_rtx
)
4581 opnds
[2] = XVECEXP (unspec
, 0, 1);
4584 gcc_assert (XVECEXP (unspec
, 0, 1) == text_label_rtx
);
4585 opnds
[2] = XVECEXP (unspec
, 0, 0);
4588 opnds
[3] = XVECEXP (unspec
, 0, 2);
4590 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4591 if (GET_CODE (opnds
[3]) != SYMBOL_REF
)
4598 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[2]));
4602 emit_move_insn (opnds
[0], gen_rtx_PLUS (Pmode
, opnds
[1], opnds
[2]));
4603 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[0]));
4606 new_insns
= get_insns ();
4609 replace_insns (insn
, new_insns
);
4613 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4614 going through the GOT when the symbol is local to the compilation
4615 unit. But such a symbol requires that the common text_label that
4616 we generate at the beginning of the function be in the same section
4617 as the reference to the SYMBOL_REF. This may not be true if we
4618 generate hot/cold sections. This function looks for such cases and
4619 replaces such references with the longer sequence going through the
4622 We expect following instruction sequence:
4623 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4624 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4625 add<x> tmp3, txt_label_reg, tmp2 [3]
4627 If we're compiling -fpic, we replace with the following sequence
4628 (the numbers in brackets match the instructions they're replacing
4631 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4632 ld<4> tmp3, tmp2 [3]
4634 If we're compiling -fPIC, we replace the first instruction with:
4636 moveli tmp1, hw1_last_got(x) [1]
4637 shl16insli tmp2, tmp1, hw0_got(x) [2]
4638 add<x> tmp3, got_reg, tmp2 [3]
4639 ld<4> tmp3, tmp3 [3]
4641 Note that we're careful to disturb the instruction sequence as
4642 little as possible, since it's very late in the compilation
4645 tilegx_fixup_pcrel_references (void)
4647 rtx insn
, next_insn
;
4648 bool same_section_as_entry
= true;
4650 for (insn
= get_insns (); insn
; insn
= next_insn
)
4652 next_insn
= NEXT_INSN (insn
);
4654 if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_SWITCH_TEXT_SECTIONS
)
4656 same_section_as_entry
= !same_section_as_entry
;
4660 if (same_section_as_entry
)
4664 && GET_CODE (PATTERN (insn
)) != USE
4665 && GET_CODE (PATTERN (insn
)) != CLOBBER
))
4670 if (match_pcrel_step1 (insn
))
4671 replace_mov_pcrel_step1 (insn
);
4672 else if (match_pcrel_step2 (insn
))
4673 replace_mov_pcrel_step2 (insn
);
4674 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3_32bit
)
4675 replace_mov_pcrel_step3 (insn
);
4679 if (match_pcrel_step1 (insn
))
4680 replace_mov_pcrel_step1 (insn
);
4681 else if (match_pcrel_step2 (insn
))
4682 replace_mov_pcrel_step2 (insn
);
4683 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3
)
4684 replace_mov_pcrel_step3 (insn
);
4690 /* Ensure that no var tracking notes are emitted in the middle of a
4691 three-instruction bundle. */
4693 reorder_var_tracking_notes (void)
4699 rtx queue
= NULL_RTX
;
4700 bool in_bundle
= false;
4702 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4704 next
= NEXT_INSN (insn
);
4708 /* Emit queued up notes at the last instruction of a
4710 if (GET_MODE (insn
) == QImode
)
4714 rtx next_queue
= PREV_INSN (queue
);
4715 PREV_INSN (NEXT_INSN (insn
)) = queue
;
4716 NEXT_INSN (queue
) = NEXT_INSN (insn
);
4717 NEXT_INSN (insn
) = queue
;
4718 PREV_INSN (queue
) = insn
;
4723 else if (GET_MODE (insn
) == SImode
)
4726 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4730 rtx prev
= PREV_INSN (insn
);
4731 PREV_INSN (next
) = prev
;
4732 NEXT_INSN (prev
) = next
;
4734 PREV_INSN (insn
) = queue
;
4743 /* Perform machine dependent operations on the rtl chain INSNS. */
4747 /* We are freeing block_for_insn in the toplev to keep compatibility
4748 with old MDEP_REORGS that are not CFG based. Recompute it
4750 compute_bb_for_insn ();
4752 if (flag_reorder_blocks_and_partition
)
4754 tilegx_fixup_pcrel_references ();
4757 if (flag_schedule_insns_after_reload
)
4761 timevar_push (TV_SCHED2
);
4763 timevar_pop (TV_SCHED2
);
4765 /* Examine the schedule to group into bundles. */
4766 tilegx_gen_bundles ();
4771 if (flag_var_tracking
)
4773 timevar_push (TV_VAR_TRACKING
);
4774 variable_tracking_main ();
4775 reorder_var_tracking_notes ();
4776 timevar_pop (TV_VAR_TRACKING
);
4779 df_finish_pass (false);
4786 /* Select a format to encode pointers in exception handling data.
4787 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4788 GLOBAL is true if the symbol may be affected by dynamic
4791 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED
, int global
)
4793 int type
= TARGET_32BIT
? DW_EH_PE_sdata4
: DW_EH_PE_sdata8
;
4794 return (global
? DW_EH_PE_indirect
: 0) | DW_EH_PE_pcrel
| type
;
4798 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4800 tilegx_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
4801 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
4804 rtx this_rtx
, insn
, funexp
, addend
;
4806 /* Pretend to be a post-reload pass while generating rtl. */
4807 reload_completed
= 1;
4809 /* Mark the end of the (empty) prologue. */
4810 emit_note (NOTE_INSN_PROLOGUE_END
);
4812 /* Find the "this" pointer. If the function returns a structure,
4813 the structure return pointer is in $1. */
4814 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
4815 this_rtx
= gen_rtx_REG (Pmode
, 1);
4817 this_rtx
= gen_rtx_REG (Pmode
, 0);
4819 /* Add DELTA to THIS_RTX. */
4820 if (!(delta
>= -32868 && delta
<= 32767))
4822 addend
= gen_rtx_REG (Pmode
, 29);
4823 emit_move_insn (addend
, GEN_INT (delta
));
4826 addend
= GEN_INT (delta
);
4829 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, addend
));
4831 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, addend
));
4833 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4838 tmp
= gen_rtx_REG (Pmode
, 29);
4839 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, this_rtx
));
4841 if (!(vcall_offset
>= -32868 && vcall_offset
<= 32767))
4843 addend
= gen_rtx_REG (Pmode
, 28);
4844 emit_move_insn (addend
, GEN_INT (vcall_offset
));
4847 addend
= GEN_INT (vcall_offset
);
4850 emit_insn (gen_addsi3 (tmp
, tmp
, addend
));
4852 emit_insn (gen_adddi3 (tmp
, tmp
, addend
));
4854 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, tmp
));
4857 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, tmp
));
4859 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, tmp
));
4862 /* Generate a tail call to the target function. */
4863 if (!TREE_USED (function
))
4865 assemble_external (function
);
4866 TREE_USED (function
) = 1;
4868 funexp
= XEXP (DECL_RTL (function
), 0);
4869 funexp
= gen_rtx_MEM (FUNCTION_MODE
, funexp
);
4870 insn
= emit_call_insn (gen_sibcall (funexp
, const0_rtx
));
4871 SIBLING_CALL_P (insn
) = 1;
4873 /* Run just enough of rest_of_compilation to get the insns emitted.
4874 There's not really enough bulk here to make other passes such as
4875 instruction scheduling worth while. Note that use_thunk calls
4876 assemble_start_function and assemble_end_function.
4878 We don't currently bundle, but the instruciton sequence is all
4879 serial except for the tail call, so we're only wasting one cycle.
4881 insn
= get_insns ();
4882 shorten_branches (insn
);
4883 final_start_function (insn
, file
, 1);
4884 final (insn
, file
, 1);
4885 final_end_function ();
4887 /* Stop pretending to be a post-reload pass. */
4888 reload_completed
= 0;
4892 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
4894 tilegx_asm_trampoline_template (FILE *file
)
4896 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
4899 fprintf (file
, "\tlnk r10\n");
4900 fprintf (file
, "\taddxi r10, r10, 32\n");
4901 fprintf (file
, "\tld4s_add r11, r10, %d\n", ptr_mode_size
);
4902 fprintf (file
, "\tld4s r10, r10\n");
4903 fprintf (file
, "\tjr r11\n");
4904 fprintf (file
, "\t.word 0 # <function address>\n");
4905 fprintf (file
, "\t.word 0 # <static chain value>\n");
4909 fprintf (file
, "\tlnk r10\n");
4910 fprintf (file
, "\taddi r10, r10, 32\n");
4911 fprintf (file
, "\tld_add r11, r10, %d\n", ptr_mode_size
);
4912 fprintf (file
, "\tld r10, r10\n");
4913 fprintf (file
, "\tjr r11\n");
4914 fprintf (file
, "\t.quad 0 # <function address>\n");
4915 fprintf (file
, "\t.quad 0 # <static chain value>\n");
4920 /* Implement TARGET_TRAMPOLINE_INIT. */
4922 tilegx_trampoline_init (rtx m_tramp
, tree fndecl
, rtx static_chain
)
4926 rtx begin_addr
, end_addr
;
4927 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
4929 fnaddr
= copy_to_reg (XEXP (DECL_RTL (fndecl
), 0));
4930 chaddr
= copy_to_reg (static_chain
);
4932 emit_block_move (m_tramp
, assemble_trampoline_template (),
4933 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
4935 mem
= adjust_address (m_tramp
, ptr_mode
,
4936 TRAMPOLINE_SIZE
- 2 * ptr_mode_size
);
4937 emit_move_insn (mem
, fnaddr
);
4938 mem
= adjust_address (m_tramp
, ptr_mode
,
4939 TRAMPOLINE_SIZE
- ptr_mode_size
);
4940 emit_move_insn (mem
, chaddr
);
4942 /* Get pointers to the beginning and end of the code block. */
4943 begin_addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
4944 end_addr
= force_reg (Pmode
, plus_constant (Pmode
, XEXP (m_tramp
, 0),
4947 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__clear_cache"),
4948 LCT_NORMAL
, VOIDmode
, 2, begin_addr
, Pmode
,
4953 /* Implement TARGET_PRINT_OPERAND. */
4955 tilegx_print_operand (FILE *file
, rtx x
, int code
)
4960 /* Print the compare operator opcode for conditional moves. */
4961 switch (GET_CODE (x
))
4970 output_operand_lossage ("invalid %%c operand");
4975 /* Print the compare operator opcode for conditional moves. */
4976 switch (GET_CODE (x
))
4985 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 %%d operand");
5008 /* Print the compare operator opcode for conditional moves. */
5009 switch (GET_CODE (x
))
5018 output_operand_lossage ("invalid %%D operand");
5025 if (GET_CODE (x
) == CONST
5026 && GET_CODE (XEXP (x
, 0)) == UNSPEC
)
5028 rtx addr
= XVECEXP (XEXP (x
, 0), 0, 0);
5029 int unspec
= XINT (XEXP (x
, 0), 1);
5030 const char *opstr
= NULL
;
5034 case UNSPEC_HW0_PCREL
:
5038 case UNSPEC_HW1_PCREL
:
5047 case UNSPEC_HW0_LAST
:
5050 case UNSPEC_HW1_LAST
:
5051 case UNSPEC_HW1_LAST_PCREL
:
5054 case UNSPEC_HW2_LAST
:
5055 case UNSPEC_HW2_LAST_PCREL
:
5058 case UNSPEC_HW0_GOT
:
5061 case UNSPEC_HW0_LAST_GOT
:
5062 opstr
= "hw0_last_got";
5064 case UNSPEC_HW1_LAST_GOT
:
5065 opstr
= "hw1_last_got";
5067 case UNSPEC_HW0_TLS_GD
:
5068 opstr
= "hw0_tls_gd";
5070 case UNSPEC_HW1_LAST_TLS_GD
:
5071 opstr
= "hw1_last_tls_gd";
5073 case UNSPEC_HW0_TLS_IE
:
5074 opstr
= "hw0_tls_ie";
5076 case UNSPEC_HW1_LAST_TLS_IE
:
5077 opstr
= "hw1_last_tls_ie";
5079 case UNSPEC_HW0_TLS_LE
:
5080 opstr
= "hw0_tls_le";
5082 case UNSPEC_HW1_LAST_TLS_LE
:
5083 opstr
= "hw1_last_tls_le";
5085 case UNSPEC_HW0_PLT_PCREL
:
5088 case UNSPEC_HW1_PLT_PCREL
:
5091 case UNSPEC_HW1_LAST_PLT_PCREL
:
5092 opstr
= "hw1_last_plt";
5094 case UNSPEC_HW2_LAST_PLT_PCREL
:
5095 opstr
= "hw2_last_plt";
5098 output_operand_lossage ("invalid %%H specifier");
5101 fputs (opstr
, file
);
5103 output_addr_const (file
, addr
);
5105 if (unspec
== UNSPEC_HW0_PCREL
5106 || unspec
== UNSPEC_HW1_PCREL
5107 || unspec
== UNSPEC_HW1_LAST_PCREL
5108 || unspec
== UNSPEC_HW2_LAST_PCREL
5109 || unspec
== UNSPEC_HW0_PLT_PCREL
5110 || unspec
== UNSPEC_HW1_PLT_PCREL
5111 || unspec
== UNSPEC_HW1_LAST_PLT_PCREL
5112 || unspec
== UNSPEC_HW2_LAST_PLT_PCREL
)
5114 rtx addr2
= XVECEXP (XEXP (x
, 0), 0, 1);
5115 fputs (" - " , file
);
5116 output_addr_const (file
, addr2
);
5122 else if (symbolic_operand (x
, VOIDmode
))
5124 output_addr_const (file
, x
);
5132 /* Print the low 16 bits of a constant. */
5134 if (CONST_INT_P (x
))
5136 else if (GET_CODE (x
) == CONST_DOUBLE
)
5137 i
= CONST_DOUBLE_LOW (x
);
5140 output_operand_lossage ("invalid %%h operand");
5143 i
= trunc_int_for_mode (i
, HImode
);
5144 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5149 /* Print an auto-inc memory operand. */
5152 output_operand_lossage ("invalid %%I operand");
5156 output_memory_reference_mode
= GET_MODE (x
);
5157 output_memory_autoinc_first
= true;
5158 output_address (XEXP (x
, 0));
5159 output_memory_reference_mode
= VOIDmode
;
5163 /* Print an auto-inc memory operand. */
5166 output_operand_lossage ("invalid %%i operand");
5170 output_memory_reference_mode
= GET_MODE (x
);
5171 output_memory_autoinc_first
= false;
5172 output_address (XEXP (x
, 0));
5173 output_memory_reference_mode
= VOIDmode
;
5178 /* Print the low 8 bits of a constant. */
5180 if (CONST_INT_P (x
))
5182 else if (GET_CODE (x
) == CONST_DOUBLE
)
5183 i
= CONST_DOUBLE_LOW (x
);
5184 else if (GET_CODE (x
) == CONST_VECTOR
5185 && CONST_INT_P (CONST_VECTOR_ELT (x
, 0)))
5186 i
= INTVAL (CONST_VECTOR_ELT (x
, 0));
5189 output_operand_lossage ("invalid %%j operand");
5192 i
= trunc_int_for_mode (i
, QImode
);
5193 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5199 /* Print a constant plus one. */
5200 if (!CONST_INT_P (x
))
5202 output_operand_lossage ("invalid %%P operand");
5205 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (x
) + 1);
5212 /* Print a bfextu-style bit range. */
5213 int first_bit
, last_bit
;
5214 HOST_WIDE_INT flip
= (code
== 'm') ? ~0 : 0;
5216 if (!CONST_INT_P (x
)
5217 || !tilegx_bitfield_operand_p (INTVAL (x
) ^ flip
,
5218 &first_bit
, &last_bit
))
5220 output_operand_lossage ("invalid %%%c operand", code
);
5224 fprintf (file
, "%d, %d", first_bit
, last_bit
);
5230 const char *reg
= NULL
;
5232 /* Print a network register. */
5233 if (!CONST_INT_P (x
))
5235 output_operand_lossage ("invalid %%N operand");
5241 case TILEGX_NETREG_IDN0
: reg
= "idn0"; break;
5242 case TILEGX_NETREG_IDN1
: reg
= "idn1"; break;
5243 case TILEGX_NETREG_UDN0
: reg
= "udn0"; break;
5244 case TILEGX_NETREG_UDN1
: reg
= "udn1"; break;
5245 case TILEGX_NETREG_UDN2
: reg
= "udn2"; break;
5246 case TILEGX_NETREG_UDN3
: reg
= "udn3"; break;
5251 fprintf (file
, reg
);
5256 if (GET_CODE (x
) == SYMBOL_REF
)
5258 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5259 fprintf (file
, "plt(");
5260 output_addr_const (file
, x
);
5261 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5262 fprintf (file
, ")");
5265 output_addr_const (file
, x
);
5269 /* In this case we need a register. Use 'zero' if the operand
5272 || (GET_MODE (x
) != VOIDmode
&& x
== CONST0_RTX (GET_MODE (x
))))
5274 fputs ("zero", file
);
5277 else if (!REG_P (x
))
5279 output_operand_lossage ("invalid operand for 'r' specifier");
5287 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
5292 output_memory_reference_mode
= VOIDmode
;
5293 output_address (XEXP (x
, 0));
5298 output_addr_const (file
, x
);
5304 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5309 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5311 tilegx_print_operand_address (FILE *file
, rtx addr
)
5313 if (GET_CODE (addr
) == POST_DEC
5314 || GET_CODE (addr
) == POST_INC
)
5316 int offset
= GET_MODE_SIZE (output_memory_reference_mode
);
5318 gcc_assert (output_memory_reference_mode
!= VOIDmode
);
5320 if (output_memory_autoinc_first
)
5321 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5323 fprintf (file
, "%d",
5324 GET_CODE (addr
) == POST_DEC
? -offset
: offset
);
5326 else if (GET_CODE (addr
) == POST_MODIFY
)
5328 gcc_assert (output_memory_reference_mode
!= VOIDmode
);
5330 gcc_assert (GET_CODE (XEXP (addr
, 1)) == PLUS
);
5332 if (output_memory_autoinc_first
)
5333 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5335 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
,
5336 INTVAL (XEXP (XEXP (addr
, 1), 1)));
5339 tilegx_print_operand (file
, addr
, 'r');
5343 /* Machine mode of current insn, for determining curly brace
5345 static enum machine_mode insn_mode
;
5348 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5350 tilegx_final_prescan_insn (rtx insn
)
5352 /* Record this for tilegx_asm_output_opcode to examine. */
5353 insn_mode
= GET_MODE (insn
);
5357 /* While emitting asm, are we currently inside '{' for a bundle? */
5358 static bool tilegx_in_bundle
= false;
5360 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5361 appropriate given the bundling information recorded by
5362 tilegx_gen_bundles. */
5364 tilegx_asm_output_opcode (FILE *stream
, const char *code
)
5366 bool pseudo
= !strcmp (code
, "pseudo");
5368 if (!tilegx_in_bundle
&& insn_mode
== SImode
)
5370 /* Start a new bundle. */
5371 fprintf (stream
, "{\n\t");
5372 tilegx_in_bundle
= true;
5375 if (tilegx_in_bundle
&& insn_mode
== QImode
)
5377 /* Close an existing bundle. */
5378 static char buf
[100];
5380 gcc_assert (strlen (code
) + 3 + 1 < sizeof (buf
));
5382 strcpy (buf
, pseudo
? "" : code
);
5383 strcat (buf
, "\n\t}");
5384 tilegx_in_bundle
= false;
5390 return pseudo
? "" : code
;
5395 /* Output assembler code to FILE to increment profiler label # LABELNO
5396 for profiling a function entry. */
5398 tilegx_function_profiler (FILE *file
, int labelno ATTRIBUTE_UNUSED
)
5400 if (tilegx_in_bundle
)
5402 fprintf (file
, "\t}\n");
5411 "\t}\n", MCOUNT_NAME
);
5419 "\t}\n", MCOUNT_NAME
);
5422 tilegx_in_bundle
= false;
5426 /* Implement TARGET_ASM_FILE_END. */
5428 tilegx_file_end (void)
5430 if (NEED_INDICATE_EXEC_STACK
)
5431 file_end_indicate_exec_stack ();
5436 #undef TARGET_HAVE_TLS
5437 #define TARGET_HAVE_TLS HAVE_AS_TLS
5439 #undef TARGET_OPTION_OVERRIDE
5440 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5442 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5443 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5445 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5446 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5448 #undef TARGET_CANNOT_FORCE_CONST_MEM
5449 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5451 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5452 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5454 #undef TARGET_PASS_BY_REFERENCE
5455 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5457 #undef TARGET_RETURN_IN_MEMORY
5458 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5460 #undef TARGET_MODE_REP_EXTENDED
5461 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5463 #undef TARGET_FUNCTION_ARG_BOUNDARY
5464 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5466 #undef TARGET_FUNCTION_ARG
5467 #define TARGET_FUNCTION_ARG tilegx_function_arg
5469 #undef TARGET_FUNCTION_ARG_ADVANCE
5470 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5472 #undef TARGET_FUNCTION_VALUE
5473 #define TARGET_FUNCTION_VALUE tilegx_function_value
5475 #undef TARGET_LIBCALL_VALUE
5476 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5478 #undef TARGET_FUNCTION_VALUE_REGNO_P
5479 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5481 #undef TARGET_PROMOTE_FUNCTION_MODE
5482 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5484 #undef TARGET_PROMOTE_PROTOTYPES
5485 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5487 #undef TARGET_BUILD_BUILTIN_VA_LIST
5488 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5490 #undef TARGET_EXPAND_BUILTIN_VA_START
5491 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5493 #undef TARGET_SETUP_INCOMING_VARARGS
5494 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5496 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5497 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5499 #undef TARGET_RTX_COSTS
5500 #define TARGET_RTX_COSTS tilegx_rtx_costs
5502 #undef TARGET_SHIFT_TRUNCATION_MASK
5503 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5505 #undef TARGET_INIT_LIBFUNCS
5506 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5508 /* Limit to what we can reach in one addli. */
5509 #undef TARGET_MIN_ANCHOR_OFFSET
5510 #define TARGET_MIN_ANCHOR_OFFSET -32768
5511 #undef TARGET_MAX_ANCHOR_OFFSET
5512 #define TARGET_MAX_ANCHOR_OFFSET 32767
5514 #undef TARGET_LEGITIMATE_CONSTANT_P
5515 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5517 #undef TARGET_LEGITIMATE_ADDRESS_P
5518 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5520 #undef TARGET_LEGITIMIZE_ADDRESS
5521 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5523 #undef TARGET_DELEGITIMIZE_ADDRESS
5524 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5526 #undef TARGET_INIT_BUILTINS
5527 #define TARGET_INIT_BUILTINS tilegx_init_builtins
5529 #undef TARGET_BUILTIN_DECL
5530 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5532 #undef TARGET_EXPAND_BUILTIN
5533 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5535 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5536 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5538 #undef TARGET_FRAME_POINTER_REQUIRED
5539 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5541 #undef TARGET_DELAY_SCHED2
5542 #define TARGET_DELAY_SCHED2 true
5544 #undef TARGET_DELAY_VARTRACK
5545 #define TARGET_DELAY_VARTRACK true
5547 #undef TARGET_SCHED_ISSUE_RATE
5548 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5550 #undef TARGET_SCHED_ADJUST_COST
5551 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5553 #undef TARGET_MACHINE_DEPENDENT_REORG
5554 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5556 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5557 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5558 hook_bool_const_tree_hwi_hwi_const_tree_true
5560 #undef TARGET_ASM_OUTPUT_MI_THUNK
5561 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5563 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5564 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5566 #undef TARGET_TRAMPOLINE_INIT
5567 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5569 #undef TARGET_PRINT_OPERAND
5570 #define TARGET_PRINT_OPERAND tilegx_print_operand
5572 #undef TARGET_PRINT_OPERAND_ADDRESS
5573 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5575 #undef TARGET_ASM_FILE_END
5576 #define TARGET_ASM_FILE_END tilegx_file_end
5578 #undef TARGET_ASM_ALIGNED_DI_OP
5579 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5582 struct gcc_target targetm
= TARGET_INITIALIZER
;
5584 #include "gt-tilegx.h"