1 /* Subroutines used for code generation on the Tilera TILE-Gx.
2 Copyright (C) 2011-2014 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 "dominance.h"
40 #include "cfgcleanup.h"
42 #include "basic-block.h"
43 #include "sched-int.h"
45 #include "tm-constrs.h"
47 #include "target-def.h"
52 #include "hard-reg-set.h"
58 #include "hash-table.h"
60 #include "tree-ssa-alias.h"
61 #include "internal-fn.h"
62 #include "gimple-fold.h"
64 #include "gimple-expr.h"
67 #include "stringpool.h"
68 #include "stor-layout.h"
73 #include "tilegx-builtins.h"
74 #include "tilegx-multiply.h"
75 #include "diagnostic.h"
78 /* SYMBOL_REF for GOT */
79 static GTY(()) rtx g_got_symbol
= NULL
;
81 /* In case of a POST_INC or POST_DEC memory reference, we must report
82 the mode of the memory reference from TARGET_PRINT_OPERAND to
83 TARGET_PRINT_OPERAND_ADDRESS. */
84 static machine_mode output_memory_reference_mode
;
86 /* Report whether we're printing out the first address fragment of a
87 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
88 TARGET_PRINT_OPERAND_ADDRESS. */
89 static bool output_memory_autoinc_first
;
95 /* Implement TARGET_OPTION_OVERRIDE. */
97 tilegx_option_override (void)
99 if (global_options_set
.x_tilegx_cmodel
)
101 switch (tilegx_cmodel
)
106 tilegx_cmodel
= CM_SMALL_PIC
;
112 tilegx_cmodel
= CM_LARGE_PIC
;
120 tilegx_cmodel
= flag_pic
? CM_SMALL_PIC
: CM_SMALL
;
122 /* When modulo scheduling is enabled, we still rely on regular
123 scheduler for bundling. */
124 if (flag_modulo_sched
)
125 flag_resched_modulo_sched
= 1;
130 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
132 tilegx_scalar_mode_supported_p (machine_mode mode
)
153 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
155 tilegx_vector_mode_supported_p (machine_mode mode
)
157 return mode
== V8QImode
|| mode
== V4HImode
|| mode
== V2SImode
;
161 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
163 tilegx_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
,
164 rtx x ATTRIBUTE_UNUSED
)
170 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
172 tilegx_function_ok_for_sibcall (tree decl
, tree exp ATTRIBUTE_UNUSED
)
174 return (tilegx_cmodel
!= CM_LARGE
&& tilegx_cmodel
!= CM_LARGE_PIC
179 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
180 passed by reference. */
182 tilegx_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED
,
183 machine_mode mode ATTRIBUTE_UNUSED
,
184 const_tree type
, bool named ATTRIBUTE_UNUSED
)
186 return (type
&& TYPE_SIZE (type
)
187 && TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
);
191 /* Implement TARGET_RETURN_IN_MSB. We return a value in the most
192 significant part of a register if:
193 - the target is big-endian; and
194 - the value has an aggregate type (e.g., structure or union). */
196 tilegx_return_in_msb (const_tree valtype
)
198 return (TARGET_BIG_ENDIAN
&& AGGREGATE_TYPE_P (valtype
));
202 /* Implement TARGET_RETURN_IN_MEMORY. */
204 tilegx_return_in_memory (const_tree type
, const_tree fndecl ATTRIBUTE_UNUSED
)
206 return !IN_RANGE (int_size_in_bytes (type
),
207 0, TILEGX_NUM_RETURN_REGS
* UNITS_PER_WORD
);
211 /* Implement TARGET_MODE_REP_EXTENDED. */
213 tilegx_mode_rep_extended (machine_mode mode
, machine_mode mode_rep
)
215 /* SImode register values are sign-extended to DImode. */
216 if (mode
== SImode
&& mode_rep
== DImode
)
223 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
225 tilegx_function_arg_boundary (machine_mode mode
, const_tree type
)
227 unsigned int alignment
;
229 alignment
= type
? TYPE_ALIGN (type
) : GET_MODE_ALIGNMENT (mode
);
230 if (alignment
< PARM_BOUNDARY
)
231 alignment
= PARM_BOUNDARY
;
232 if (alignment
> STACK_BOUNDARY
)
233 alignment
= STACK_BOUNDARY
;
238 /* Implement TARGET_FUNCTION_ARG. */
240 tilegx_function_arg (cumulative_args_t cum_v
,
242 const_tree type
, bool named ATTRIBUTE_UNUSED
)
244 CUMULATIVE_ARGS cum
= *get_cumulative_args (cum_v
);
245 int byte_size
= ((mode
== BLKmode
)
246 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
247 bool doubleword_aligned_p
;
249 if (cum
>= TILEGX_NUM_ARG_REGS
)
252 /* See whether the argument has doubleword alignment. */
253 doubleword_aligned_p
=
254 tilegx_function_arg_boundary (mode
, type
) > BITS_PER_WORD
;
256 if (doubleword_aligned_p
)
259 /* The ABI does not allow parameters to be passed partially in reg
260 and partially in stack. */
261 if ((cum
+ (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
)
262 > TILEGX_NUM_ARG_REGS
)
265 return gen_rtx_REG (mode
, cum
);
269 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
271 tilegx_function_arg_advance (cumulative_args_t cum_v
,
273 const_tree type
, bool named ATTRIBUTE_UNUSED
)
275 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
277 int byte_size
= ((mode
== BLKmode
)
278 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
279 int word_size
= (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
280 bool doubleword_aligned_p
;
282 /* See whether the argument has doubleword alignment. */
283 doubleword_aligned_p
=
284 tilegx_function_arg_boundary (mode
, type
) > BITS_PER_WORD
;
286 if (doubleword_aligned_p
)
289 /* If the current argument does not fit in the pretend_args space,
291 if (*cum
< TILEGX_NUM_ARG_REGS
292 && *cum
+ word_size
> TILEGX_NUM_ARG_REGS
)
293 *cum
= TILEGX_NUM_ARG_REGS
;
299 /* Implement TARGET_FUNCTION_VALUE. */
301 tilegx_function_value (const_tree valtype
, const_tree fn_decl_or_type
,
302 bool outgoing ATTRIBUTE_UNUSED
)
307 mode
= TYPE_MODE (valtype
);
308 unsigned_p
= TYPE_UNSIGNED (valtype
);
310 mode
= promote_function_mode (valtype
, mode
, &unsigned_p
,
313 return gen_rtx_REG (mode
, 0);
317 /* Implement TARGET_LIBCALL_VALUE. */
319 tilegx_libcall_value (machine_mode mode
,
320 const_rtx fun ATTRIBUTE_UNUSED
)
322 return gen_rtx_REG (mode
, 0);
326 /* Implement FUNCTION_VALUE_REGNO_P. */
328 tilegx_function_value_regno_p (const unsigned int regno
)
330 return regno
< TILEGX_NUM_RETURN_REGS
;
334 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
336 tilegx_build_builtin_va_list (void)
338 tree f_args
, f_skip
, record
, type_decl
;
341 record
= lang_hooks
.types
.make_type (RECORD_TYPE
);
343 type_decl
= build_decl (BUILTINS_LOCATION
, TYPE_DECL
,
344 get_identifier ("__va_list_tag"), record
);
346 f_args
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
347 get_identifier ("__args"), ptr_type_node
);
348 f_skip
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
349 get_identifier ("__skip"), ptr_type_node
);
351 DECL_FIELD_CONTEXT (f_args
) = record
;
353 DECL_FIELD_CONTEXT (f_skip
) = record
;
355 TREE_CHAIN (record
) = type_decl
;
356 TYPE_NAME (record
) = type_decl
;
357 TYPE_FIELDS (record
) = f_args
;
358 TREE_CHAIN (f_args
) = f_skip
;
360 /* We know this is being padded and we want it too. It is an
361 internal type so hide the warnings from the user. */
365 layout_type (record
);
369 /* The correct type is an array type of one element. */
374 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
376 tilegx_va_start (tree valist
, rtx nextarg ATTRIBUTE_UNUSED
)
381 f_args
= TYPE_FIELDS (TREE_TYPE (valist
));
382 f_skip
= TREE_CHAIN (f_args
);
385 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
387 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
389 /* Find the __args area. */
390 t
= make_tree (TREE_TYPE (args
), virtual_incoming_args_rtx
);
391 t
= fold_build_pointer_plus_hwi (t
,
393 (crtl
->args
.info
- TILEGX_NUM_ARG_REGS
));
395 if (crtl
->args
.pretend_args_size
> 0)
396 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
398 t
= build2 (MODIFY_EXPR
, TREE_TYPE (args
), args
, t
);
399 TREE_SIDE_EFFECTS (t
) = 1;
400 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
402 /* Find the __skip area. */
403 t
= make_tree (TREE_TYPE (skip
), virtual_incoming_args_rtx
);
404 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
405 t
= build2 (MODIFY_EXPR
, TREE_TYPE (skip
), skip
, t
);
406 TREE_SIDE_EFFECTS (t
) = 1;
407 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
411 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
413 tilegx_setup_incoming_varargs (cumulative_args_t cum
,
415 tree type
, int *pretend_args
, int no_rtl
)
417 CUMULATIVE_ARGS local_cum
= *get_cumulative_args (cum
);
420 /* The caller has advanced CUM up to, but not beyond, the last named
421 argument. Advance a local copy of CUM past the last "real" named
422 argument, to find out how many registers are left over. */
423 targetm
.calls
.function_arg_advance (pack_cumulative_args (&local_cum
),
425 first_reg
= local_cum
;
427 if (local_cum
< TILEGX_NUM_ARG_REGS
)
429 *pretend_args
= UNITS_PER_WORD
* (TILEGX_NUM_ARG_REGS
- first_reg
);
433 alias_set_type set
= get_varargs_alias_set ();
435 gen_rtx_MEM (BLKmode
, plus_constant (Pmode
,
436 virtual_incoming_args_rtx
,
437 -STACK_POINTER_OFFSET
-
439 (TILEGX_NUM_ARG_REGS
-
441 MEM_NOTRAP_P (tmp
) = 1;
442 set_mem_alias_set (tmp
, set
);
443 move_block_from_reg (first_reg
, tmp
,
444 TILEGX_NUM_ARG_REGS
- first_reg
);
452 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
453 the va_list structure VALIST as required to retrieve an argument of
454 type TYPE, and returning that argument.
456 ret = va_arg(VALIST, TYPE);
458 generates code equivalent to:
460 paddedsize = (sizeof(TYPE) + 7) & -8;
461 if ( (VALIST.__args + paddedsize > VALIST.__skip)
462 & (VALIST.__args <= VALIST.__skip))
463 addr = VALIST.__skip + STACK_POINTER_OFFSET;
465 addr = VALIST.__args;
466 VALIST.__args = addr + paddedsize;
467 if (BYTES_BIG_ENDIAN)
468 ret = *(TYPE *)(addr + paddedsize - sizeof(TYPE));
473 tilegx_gimplify_va_arg_expr (tree valist
, tree type
, gimple_seq
*pre_p
,
474 gimple_seq
*post_p ATTRIBUTE_UNUSED
)
478 HOST_WIDE_INT size
, rsize
;
480 bool pass_by_reference_p
;
482 f_args
= TYPE_FIELDS (va_list_type_node
);
483 f_skip
= TREE_CHAIN (f_args
);
486 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
488 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
490 addr
= create_tmp_var (ptr_type_node
, "va_arg");
492 /* If an object is dynamically sized, a pointer to it is passed
493 instead of the object itself. */
494 pass_by_reference_p
= pass_by_reference (NULL
, TYPE_MODE (type
), type
,
497 if (pass_by_reference_p
)
498 type
= build_pointer_type (type
);
500 size
= int_size_in_bytes (type
);
501 rsize
= ((size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
) * UNITS_PER_WORD
;
503 /* If the alignment of the type is greater than the default for a
504 parameter, align to the STACK_BOUNDARY. */
505 if (TYPE_ALIGN (type
) > PARM_BOUNDARY
)
507 /* Assert the only case we generate code for: when
508 stack boundary = 2 * parm boundary. */
509 gcc_assert (STACK_BOUNDARY
== PARM_BOUNDARY
* 2);
511 tmp
= build2 (BIT_AND_EXPR
, sizetype
,
512 fold_convert (sizetype
, unshare_expr (args
)),
513 size_int (PARM_BOUNDARY
/ 8));
514 tmp
= build2 (POINTER_PLUS_EXPR
, ptr_type_node
,
515 unshare_expr (args
), tmp
);
517 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
520 /* Build conditional expression to calculate addr. The expression
521 will be gimplified later. */
522 tmp
= fold_build_pointer_plus_hwi (unshare_expr (args
), rsize
);
523 tmp
= build2 (TRUTH_AND_EXPR
, boolean_type_node
,
524 build2 (GT_EXPR
, boolean_type_node
, tmp
, unshare_expr (skip
)),
525 build2 (LE_EXPR
, boolean_type_node
, unshare_expr (args
),
526 unshare_expr (skip
)));
528 tmp
= build3 (COND_EXPR
, ptr_type_node
, tmp
,
529 build2 (POINTER_PLUS_EXPR
, ptr_type_node
, unshare_expr (skip
),
530 size_int (STACK_POINTER_OFFSET
)),
531 unshare_expr (args
));
533 /* Adjust the address of va_arg if it is in big endian mode. */
534 if (BYTES_BIG_ENDIAN
&& rsize
> size
)
535 tmp
= fold_build_pointer_plus_hwi (tmp
, rsize
- size
);
536 gimplify_assign (addr
, tmp
, pre_p
);
538 /* Update VALIST.__args. */
540 if (BYTES_BIG_ENDIAN
&& rsize
> size
)
541 tmp
= fold_build_pointer_plus_hwi (addr
, size
);
543 tmp
= fold_build_pointer_plus_hwi (addr
, rsize
);
544 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
546 addr
= fold_convert (build_pointer_type (type
), addr
);
548 if (pass_by_reference_p
)
549 addr
= build_va_arg_indirect_ref (addr
);
551 return build_va_arg_indirect_ref (addr
);
556 /* Implement TARGET_RTX_COSTS. */
558 tilegx_rtx_costs (rtx x
, int code
, int outer_code
, int opno
, int *total
,
564 /* If this is an 8-bit constant, return zero since it can be
565 used nearly anywhere with no cost. If it is a valid operand
566 for an ADD or AND, likewise return 0 if we know it will be
567 used in that context. Otherwise, return 2 since it might be
568 used there later. All other constants take at least two
570 if (satisfies_constraint_I (x
))
575 else if (outer_code
== PLUS
&& add_operand (x
, VOIDmode
))
577 /* Slightly penalize large constants even though we can add
578 them in one instruction, because it forces the use of
579 2-wide bundling mode. */
583 else if (move_operand (x
, SImode
))
585 /* We can materialize in one move. */
586 *total
= COSTS_N_INSNS (1);
591 /* We can materialize in two moves. */
592 *total
= COSTS_N_INSNS (2);
601 *total
= COSTS_N_INSNS (2);
605 *total
= COSTS_N_INSNS (4);
613 /* If outer-code was a sign or zero extension, a cost of
614 COSTS_N_INSNS (1) was already added in, so account for
616 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
617 *total
= COSTS_N_INSNS (1);
619 *total
= COSTS_N_INSNS (2);
623 /* Convey that shl[123]add are efficient. */
624 if (GET_CODE (XEXP (x
, 0)) == MULT
625 && cint_248_operand (XEXP (XEXP (x
, 0), 1), VOIDmode
))
627 *total
= (rtx_cost (XEXP (XEXP (x
, 0), 0),
628 (enum rtx_code
) outer_code
, opno
, speed
)
629 + rtx_cost (XEXP (x
, 1),
630 (enum rtx_code
) outer_code
, opno
, speed
)
631 + COSTS_N_INSNS (1));
637 *total
= COSTS_N_INSNS (2);
644 /* These are handled by software and are very expensive. */
645 *total
= COSTS_N_INSNS (100);
649 case UNSPEC_VOLATILE
:
651 int num
= XINT (x
, 1);
653 if (num
<= TILEGX_LAST_LATENCY_1_INSN
)
654 *total
= COSTS_N_INSNS (1);
655 else if (num
<= TILEGX_LAST_LATENCY_2_INSN
)
656 *total
= COSTS_N_INSNS (2);
657 else if (num
> TILEGX_LAST_LATENCY_INSN
)
659 if (num
== UNSPEC_NON_TEMPORAL
)
661 /* These are basically loads. */
662 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
663 *total
= COSTS_N_INSNS (1);
665 *total
= COSTS_N_INSNS (2);
669 if (outer_code
== PLUS
)
672 *total
= COSTS_N_INSNS (1);
679 case UNSPEC_BLOCKAGE
:
680 case UNSPEC_NETWORK_BARRIER
:
685 case UNSPEC_LNK_AND_LABEL
:
687 case UNSPEC_MOV_PCREL_STEP3
:
688 case UNSPEC_NETWORK_RECEIVE
:
689 case UNSPEC_NETWORK_SEND
:
690 case UNSPEC_SPR_MOVE
:
691 case UNSPEC_TLS_GD_ADD
:
692 *total
= COSTS_N_INSNS (1);
695 case UNSPEC_TLS_IE_LOAD
:
697 *total
= COSTS_N_INSNS (2);
701 *total
= COSTS_N_INSNS (3);
705 *total
= COSTS_N_INSNS (4);
709 case UNSPEC_INSN_CMPEXCH
:
710 case UNSPEC_LATENCY_L2
:
711 *total
= COSTS_N_INSNS (11);
714 case UNSPEC_TLS_GD_CALL
:
715 *total
= COSTS_N_INSNS (30);
718 case UNSPEC_LATENCY_MISS
:
719 *total
= COSTS_N_INSNS (80);
723 *total
= COSTS_N_INSNS (1);
738 /* Create a temporary variable to hold a partial result, to enable
741 create_temp_reg_if_possible (machine_mode mode
, rtx default_reg
)
743 return can_create_pseudo_p () ? gen_reg_rtx (mode
) : default_reg
;
747 /* Functions to save and restore machine-specific function data. */
748 static struct machine_function
*
749 tilegx_init_machine_status (void)
751 return ggc_cleared_alloc
<machine_function
> ();
755 /* Do anything needed before RTL is emitted for each function. */
757 tilegx_init_expanders (void)
759 /* Arrange to initialize and mark the machine per-function
761 init_machine_status
= tilegx_init_machine_status
;
763 if (cfun
&& cfun
->machine
&& flag_pic
)
765 static int label_num
= 0;
767 char text_label_name
[32];
769 struct machine_function
*machine
= cfun
->machine
;
771 ASM_GENERATE_INTERNAL_LABEL (text_label_name
, "L_PICLNK", label_num
++);
773 machine
->text_label_symbol
=
774 gen_rtx_SYMBOL_REF (Pmode
, ggc_strdup (text_label_name
));
776 machine
->text_label_rtx
=
777 gen_rtx_REG (Pmode
, TILEGX_PIC_TEXT_LABEL_REGNUM
);
779 machine
->got_rtx
= gen_rtx_REG (Pmode
, PIC_OFFSET_TABLE_REGNUM
);
781 machine
->calls_tls_get_addr
= false;
786 /* Implement TARGET_EXPAND_TO_RTL_HOOK. */
788 tilegx_expand_to_rtl_hook (void)
790 /* Exclude earlier sets of crtl->uses_pic_offset_table, because we
791 only care about uses actually emitted. */
792 crtl
->uses_pic_offset_table
= 0;
796 /* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode
797 matching insns and therefore guarantee that the shift count is
798 modulo 64. SImode shifts sometimes use the 64 bit version so do
799 not hold such guarantee. */
800 static unsigned HOST_WIDE_INT
801 tilegx_shift_truncation_mask (machine_mode mode
)
803 return mode
== DImode
? 63 : 0;
807 /* Implement TARGET_INIT_LIBFUNCS. */
809 tilegx_init_libfuncs (void)
811 /* We need to explicitly generate these libfunc's to support
812 conversion of divide by constant to multiply (the divide stubs in
813 tilegx.md exist also for this reason). Normally we'd expect gcc
814 to lazily generate them when they are needed, but for some reason
815 it's set up to only generate them if the mode is the word
817 set_optab_libfunc (sdiv_optab
, SImode
, "__divsi3");
818 set_optab_libfunc (udiv_optab
, SImode
, "__udivsi3");
819 set_optab_libfunc (smod_optab
, SImode
, "__modsi3");
820 set_optab_libfunc (umod_optab
, SImode
, "__umodsi3");
824 /* Return true if X contains a thread-local symbol. */
826 tilegx_tls_referenced_p (rtx x
)
828 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == PLUS
)
829 x
= XEXP (XEXP (x
, 0), 0);
831 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
))
834 /* That's all we handle in tilegx_legitimize_tls_address for
840 /* Return true if X requires a scratch register. It is given that
841 flag_pic is on and that X satisfies CONSTANT_P. */
843 tilegx_pic_address_needs_scratch (rtx x
)
845 if (GET_CODE (x
) == CONST
846 && GET_CODE (XEXP (x
, 0)) == PLUS
847 && (GET_CODE (XEXP (XEXP (x
, 0), 0)) == SYMBOL_REF
848 || GET_CODE (XEXP (XEXP (x
, 0), 0)) == LABEL_REF
)
849 && (CONST_INT_P (XEXP (XEXP (x
, 0), 1))))
856 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
857 which we are willing to load the value into a register via a move
858 pattern. TLS cannot be treated as a constant because it can
859 include a function call. */
861 tilegx_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
863 switch (GET_CODE (x
))
867 return !tilegx_tls_referenced_p (x
);
875 /* Return true if the constant value X is a legitimate general operand
876 when generating PIC code. It is given that flag_pic is on and that
877 X satisfies CONSTANT_P. */
879 tilegx_legitimate_pic_operand_p (rtx x
)
881 if (tilegx_pic_address_needs_scratch (x
))
884 if (tilegx_tls_referenced_p (x
))
891 /* Return true if the rtx X can be used as an address operand. */
893 tilegx_legitimate_address_p (machine_mode
ARG_UNUSED (mode
), rtx x
,
896 if (GET_CODE (x
) == SUBREG
)
899 switch (GET_CODE (x
))
903 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
910 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
913 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
916 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
919 if (!satisfies_constraint_I (XEXP (XEXP (x
, 1), 1)))
932 /* Check if x is a valid reg. */
937 return REGNO_OK_FOR_BASE_P (REGNO (x
));
943 /* Return the rtx containing SYMBOL_REF to the text label. */
945 tilegx_text_label_symbol (void)
947 return cfun
->machine
->text_label_symbol
;
951 /* Return the register storing the value of the text label. */
953 tilegx_text_label_rtx (void)
955 return cfun
->machine
->text_label_rtx
;
959 /* Return the register storing the value of the global offset
962 tilegx_got_rtx (void)
964 return cfun
->machine
->got_rtx
;
968 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
970 tilegx_got_symbol (void)
972 if (g_got_symbol
== NULL
)
973 g_got_symbol
= gen_rtx_SYMBOL_REF (Pmode
, "_GLOBAL_OFFSET_TABLE_");
979 /* Return a reference to the got to be used by tls references. */
981 tilegx_tls_got (void)
986 crtl
->uses_pic_offset_table
= 1;
987 return tilegx_got_rtx ();
990 temp
= gen_reg_rtx (Pmode
);
991 emit_move_insn (temp
, tilegx_got_symbol ());
997 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
998 this (thread-local) address. */
1000 tilegx_legitimize_tls_address (rtx addr
)
1004 gcc_assert (can_create_pseudo_p ());
1006 if (GET_CODE (addr
) == SYMBOL_REF
)
1007 switch (SYMBOL_REF_TLS_MODEL (addr
))
1009 case TLS_MODEL_GLOBAL_DYNAMIC
:
1010 case TLS_MODEL_LOCAL_DYNAMIC
:
1012 rtx r0
, temp
, temp2
, temp3
, got
, last
;
1014 ret
= gen_reg_rtx (Pmode
);
1015 r0
= gen_rtx_REG (Pmode
, 0);
1016 temp
= gen_reg_rtx (Pmode
);
1017 temp2
= gen_reg_rtx (Pmode
);
1018 temp3
= gen_reg_rtx (Pmode
);
1020 got
= tilegx_tls_got ();
1023 emit_insn (gen_mov_tls_gd_step1_32bit (temp
, addr
));
1024 emit_insn (gen_mov_tls_gd_step2_32bit (temp2
, temp
, addr
));
1025 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
1029 emit_insn (gen_mov_tls_gd_step1 (temp
, addr
));
1030 emit_insn (gen_mov_tls_gd_step2 (temp2
, temp
, addr
));
1031 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
1034 emit_move_insn (r0
, temp2
);
1038 emit_insn (gen_tls_gd_call_32bit (addr
));
1042 emit_insn (gen_tls_gd_call (addr
));
1045 emit_move_insn (temp3
, r0
);
1048 last
= emit_insn (gen_tls_gd_add_32bit (ret
, temp3
, addr
));
1050 last
= emit_insn (gen_tls_gd_add (ret
, temp3
, addr
));
1052 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1055 case TLS_MODEL_INITIAL_EXEC
:
1057 rtx temp
, temp2
, temp3
, got
;
1060 ret
= gen_reg_rtx (Pmode
);
1061 temp
= gen_reg_rtx (Pmode
);
1062 temp2
= gen_reg_rtx (Pmode
);
1063 temp3
= gen_reg_rtx (Pmode
);
1065 got
= tilegx_tls_got ();
1068 emit_insn (gen_mov_tls_ie_step1_32bit (temp
, addr
));
1069 emit_insn (gen_mov_tls_ie_step2_32bit (temp2
, temp
, addr
));
1070 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
1071 emit_insn (gen_tls_ie_load_32bit (temp3
, temp2
, addr
));
1075 emit_insn (gen_mov_tls_ie_step1 (temp
, addr
));
1076 emit_insn (gen_mov_tls_ie_step2 (temp2
, temp
, addr
));
1077 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
1078 emit_insn (gen_tls_ie_load (temp3
, temp2
, addr
));
1083 gen_rtx_PLUS (Pmode
,
1085 THREAD_POINTER_REGNUM
),
1087 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1090 case TLS_MODEL_LOCAL_EXEC
:
1095 ret
= gen_reg_rtx (Pmode
);
1096 temp
= gen_reg_rtx (Pmode
);
1097 temp2
= gen_reg_rtx (Pmode
);
1101 emit_insn (gen_mov_tls_le_step1_32bit (temp
, addr
));
1102 emit_insn (gen_mov_tls_le_step2_32bit (temp2
, temp
, addr
));
1106 emit_insn (gen_mov_tls_le_step1 (temp
, addr
));
1107 emit_insn (gen_mov_tls_le_step2 (temp2
, temp
, addr
));
1111 emit_move_insn (ret
,
1112 gen_rtx_PLUS (Pmode
,
1114 THREAD_POINTER_REGNUM
),
1116 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1122 else if (GET_CODE (addr
) == CONST
)
1126 gcc_assert (GET_CODE (XEXP (addr
, 0)) == PLUS
);
1128 base
= tilegx_legitimize_tls_address (XEXP (XEXP (addr
, 0), 0));
1129 offset
= XEXP (XEXP (addr
, 0), 1);
1131 base
= force_operand (base
, NULL_RTX
);
1132 ret
= force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1141 /* Returns a register that points to ADDR, a symbolic address, by
1142 computing its address relative to tilegx_text_label_symbol. */
1144 tilegx_compute_pcrel_address (rtx result
, rtx addr
)
1146 rtx text_label_symbol
= tilegx_text_label_symbol ();
1147 rtx text_label_rtx
= tilegx_text_label_rtx ();
1148 rtx temp
, temp2
, temp3
;
1150 temp
= create_temp_reg_if_possible (Pmode
, result
);
1151 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1155 emit_insn (gen_mov_pcrel_step1_32bit (temp
, addr
, text_label_symbol
));
1156 emit_insn (gen_mov_pcrel_step2_32bit (temp2
, temp
, addr
,
1157 text_label_symbol
));
1158 emit_insn (gen_mov_pcrel_step3_32bit (result
, temp2
,
1160 addr
, text_label_symbol
));
1162 else if (tilegx_cmodel
== CM_LARGE_PIC
)
1164 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1165 emit_insn (gen_mov_large_pcrel_step1 (temp
, addr
, text_label_symbol
));
1166 emit_insn (gen_mov_large_pcrel_step2 (temp2
, temp
, addr
,
1167 text_label_symbol
));
1168 emit_insn (gen_mov_large_pcrel_step3 (temp3
, temp2
, addr
,
1169 text_label_symbol
));
1170 emit_insn (gen_mov_large_pcrel_step4 (result
, temp3
,
1172 addr
, text_label_symbol
));
1176 emit_insn (gen_mov_pcrel_step1 (temp
, addr
, text_label_symbol
));
1177 emit_insn (gen_mov_pcrel_step2 (temp2
, temp
, addr
, text_label_symbol
));
1178 emit_insn (gen_mov_pcrel_step3 (result
, temp2
,
1180 addr
, text_label_symbol
));
1185 /* Returns a register that points to the plt entry of ADDR, a symbolic
1186 address, by computing its address relative to
1187 tilegx_text_label_symbol. */
1189 tilegx_compute_pcrel_plt_address (rtx result
, rtx addr
)
1191 rtx text_label_symbol
= tilegx_text_label_symbol ();
1192 rtx text_label_rtx
= tilegx_text_label_rtx ();
1193 rtx temp
, temp2
, temp3
;
1195 temp
= create_temp_reg_if_possible (Pmode
, result
);
1196 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1200 emit_insn (gen_mov_plt_pcrel_step1_32bit (temp
, addr
,
1201 text_label_symbol
));
1202 emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2
, temp
, addr
,
1203 text_label_symbol
));
1204 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp2
, text_label_rtx
));
1208 temp3
= create_temp_reg_if_possible (Pmode
, result
);
1210 emit_insn (gen_mov_plt_pcrel_step1 (temp
, addr
, text_label_symbol
));
1211 emit_insn (gen_mov_plt_pcrel_step2 (temp2
, temp
, addr
,
1212 text_label_symbol
));
1213 emit_insn (gen_mov_plt_pcrel_step3 (temp3
, temp2
, addr
,
1214 text_label_symbol
));
1215 emit_move_insn (result
, gen_rtx_PLUS (Pmode
, temp3
, text_label_rtx
));
1220 /* Legitimize PIC addresses. If the address is already
1221 position-independent, we return ORIG. Newly generated
1222 position-independent addresses go into a reg. This is REG if
1223 nonzero, otherwise we allocate register(s) as necessary. */
1225 tilegx_legitimize_pic_address (rtx orig
,
1226 machine_mode mode ATTRIBUTE_UNUSED
,
1229 if (GET_CODE (orig
) == SYMBOL_REF
)
1231 rtx address
, pic_ref
;
1235 gcc_assert (can_create_pseudo_p ());
1236 reg
= gen_reg_rtx (Pmode
);
1239 if (SYMBOL_REF_LOCAL_P (orig
))
1241 /* If not during reload, allocate another temp reg here for
1242 loading in the address, so that these instructions can be
1243 optimized properly. */
1244 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1245 tilegx_compute_pcrel_address (temp_reg
, orig
);
1247 /* Note: this is conservative. We use the text_label but we
1248 don't use the pic_offset_table. However, in some cases
1249 we may need the pic_offset_table (see
1250 tilegx_fixup_pcrel_references). */
1251 crtl
->uses_pic_offset_table
= 1;
1255 emit_move_insn (reg
, address
);
1260 /* If not during reload, allocate another temp reg here for
1261 loading in the address, so that these instructions can be
1262 optimized properly. */
1263 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1265 gcc_assert (flag_pic
);
1270 emit_insn (gen_add_got16_32bit (temp_reg
,
1276 emit_insn (gen_add_got16 (temp_reg
,
1277 tilegx_got_rtx (), orig
));
1282 rtx temp_reg2
= create_temp_reg_if_possible (Pmode
, reg
);
1283 rtx temp_reg3
= create_temp_reg_if_possible (Pmode
, reg
);
1286 emit_insn (gen_mov_got32_step1_32bit (temp_reg3
, orig
));
1287 emit_insn (gen_mov_got32_step2_32bit
1288 (temp_reg2
, temp_reg3
, orig
));
1292 emit_insn (gen_mov_got32_step1 (temp_reg3
, orig
));
1293 emit_insn (gen_mov_got32_step2 (temp_reg2
, temp_reg3
,
1296 emit_move_insn (temp_reg
,
1297 gen_rtx_PLUS (Pmode
,
1298 tilegx_got_rtx (), temp_reg2
));
1303 pic_ref
= gen_const_mem (Pmode
, address
);
1304 crtl
->uses_pic_offset_table
= 1;
1305 emit_move_insn (reg
, pic_ref
);
1306 /* The following put a REG_EQUAL note on this insn, so that
1307 it can be optimized by loop. But it causes the label to
1308 be optimized away. */
1309 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1313 else if (GET_CODE (orig
) == CONST
)
1317 if (GET_CODE (XEXP (orig
, 0)) == PLUS
1318 && XEXP (XEXP (orig
, 0), 0) == tilegx_got_rtx ())
1323 gcc_assert (can_create_pseudo_p ());
1324 reg
= gen_reg_rtx (Pmode
);
1327 gcc_assert (GET_CODE (XEXP (orig
, 0)) == PLUS
);
1328 base
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 0),
1330 offset
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 1), Pmode
,
1331 base
== reg
? 0 : reg
);
1333 if (CONST_INT_P (offset
))
1335 if (can_create_pseudo_p ())
1336 offset
= force_reg (Pmode
, offset
);
1338 /* If we reach here, then something is seriously wrong. */
1342 if (can_create_pseudo_p ())
1343 return force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1347 else if (GET_CODE (orig
) == LABEL_REF
)
1354 gcc_assert (can_create_pseudo_p ());
1355 reg
= gen_reg_rtx (Pmode
);
1358 /* If not during reload, allocate another temp reg here for
1359 loading in the address, so that these instructions can be
1360 optimized properly. */
1361 temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1362 tilegx_compute_pcrel_address (temp_reg
, orig
);
1364 /* Note: this is conservative. We use the text_label but we
1365 don't use the pic_offset_table. */
1366 crtl
->uses_pic_offset_table
= 1;
1370 emit_move_insn (reg
, address
);
1379 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1381 tilegx_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
1384 if (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
1385 && symbolic_operand (x
, Pmode
) && tilegx_tls_referenced_p (x
))
1387 return tilegx_legitimize_tls_address (x
);
1391 return tilegx_legitimize_pic_address (x
, mode
, 0);
1398 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1400 tilegx_delegitimize_address (rtx x
)
1402 x
= delegitimize_mem_from_attrs (x
);
1404 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == UNSPEC
)
1406 switch (XINT (XEXP (x
, 0), 1))
1412 case UNSPEC_HW0_LAST
:
1413 case UNSPEC_HW1_LAST
:
1414 case UNSPEC_HW2_LAST
:
1415 case UNSPEC_HW0_PCREL
:
1416 case UNSPEC_HW1_PCREL
:
1417 case UNSPEC_HW1_LAST_PCREL
:
1418 case UNSPEC_HW2_LAST_PCREL
:
1419 case UNSPEC_HW0_PLT_PCREL
:
1420 case UNSPEC_HW1_PLT_PCREL
:
1421 case UNSPEC_HW1_LAST_PLT_PCREL
:
1422 case UNSPEC_HW2_LAST_PLT_PCREL
:
1423 case UNSPEC_HW0_GOT
:
1424 case UNSPEC_HW0_LAST_GOT
:
1425 case UNSPEC_HW1_LAST_GOT
:
1426 case UNSPEC_HW0_TLS_GD
:
1427 case UNSPEC_HW1_LAST_TLS_GD
:
1428 case UNSPEC_HW0_TLS_IE
:
1429 case UNSPEC_HW1_LAST_TLS_IE
:
1430 case UNSPEC_HW0_TLS_LE
:
1431 case UNSPEC_HW1_LAST_TLS_LE
:
1432 x
= XVECEXP (XEXP (x
, 0), 0, 0);
1441 /* Emit code to load the PIC register. */
1443 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED
)
1445 int orig_flag_pic
= flag_pic
;
1447 rtx got_symbol
= tilegx_got_symbol ();
1448 rtx text_label_symbol
= tilegx_text_label_symbol ();
1449 rtx text_label_rtx
= tilegx_text_label_rtx ();
1454 emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx
,
1455 text_label_symbol
));
1459 emit_insn (gen_insn_lnk_and_label (text_label_rtx
, text_label_symbol
));
1462 tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol
);
1464 flag_pic
= orig_flag_pic
;
1466 /* Need to emit this whether or not we obey regdecls, since
1467 setjmp/longjmp can cause life info to screw up. ??? In the case
1468 where we don't obey regdecls, this is not sufficient since we may
1469 not fall out the bottom. */
1470 emit_use (tilegx_got_rtx ());
1474 /* Return the simd variant of the constant NUM of mode MODE, by
1475 replicating it to fill an interger of mode DImode. NUM is first
1476 truncated to fit in MODE. */
1478 tilegx_simd_int (rtx num
, machine_mode mode
)
1480 HOST_WIDE_INT n
= 0;
1482 gcc_assert (CONST_INT_P (num
));
1489 n
= 0x0101010101010101LL
* (n
& 0x000000FF);
1492 n
= 0x0001000100010001LL
* (n
& 0x0000FFFF);
1495 n
= 0x0000000100000001LL
* (n
& 0xFFFFFFFF);
1507 /* Returns true iff VAL can be moved into a register in one
1508 instruction. And if it can, it emits the code to move the constant
1511 If THREE_WIDE_ONLY is true, this insists on an instruction that
1512 works in a bundle containing three instructions. */
1514 expand_set_cint64_one_inst (rtx dest_reg
,
1515 HOST_WIDE_INT val
, bool three_wide_only
)
1517 if (val
== trunc_int_for_mode (val
, QImode
))
1520 emit_move_insn (dest_reg
, GEN_INT (val
));
1523 else if (!three_wide_only
)
1525 /* Test for the following constraints: J, K, N, P. We avoid
1526 generating an rtx and using existing predicates because we
1527 can be testing and rejecting a lot of constants, and GEN_INT
1529 if ((val
>= -32768 && val
<= 65535)
1530 || ((val
== (val
& 0xFF) * 0x0101010101010101LL
))
1531 || (val
== ((trunc_int_for_mode (val
, QImode
) & 0xFFFF)
1532 * 0x0001000100010001LL
)))
1534 emit_move_insn (dest_reg
, GEN_INT (val
));
1543 /* Implement DImode rotatert. */
1544 static HOST_WIDE_INT
1545 rotate_right (HOST_WIDE_INT n
, int count
)
1547 unsigned HOST_WIDE_INT x
= n
& 0xFFFFFFFFFFFFFFFFULL
;
1550 return ((x
>> count
) | (x
<< (64 - count
))) & 0xFFFFFFFFFFFFFFFFULL
;
1554 /* Return true iff n contains exactly one contiguous sequence of 1
1555 bits, possibly wrapping around from high bits to low bits. */
1557 tilegx_bitfield_operand_p (HOST_WIDE_INT n
, int *first_bit
, int *last_bit
)
1564 for (i
= 0; i
< 64; i
++)
1566 unsigned HOST_WIDE_INT x
= rotate_right (n
, i
);
1570 /* See if x is a power of two minus one, i.e. only consecutive 1
1571 bits starting from bit 0. */
1572 if ((x
& (x
+ 1)) == 0)
1574 if (first_bit
!= NULL
)
1576 if (last_bit
!= NULL
)
1577 *last_bit
= (i
+ exact_log2 (x
^ (x
>> 1))) & 63;
1587 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1589 expand_set_cint64 (rtx dest_reg
, rtx src_val
)
1592 int leading_zeroes
, trailing_zeroes
;
1593 int three_wide_only
;
1594 int shift
, ins_shift
, zero_cluster_shift
;
1597 gcc_assert (CONST_INT_P (src_val
));
1598 val
= trunc_int_for_mode (INTVAL (src_val
), GET_MODE (dest_reg
));
1600 /* See if we can generate the constant in one instruction. */
1601 if (expand_set_cint64_one_inst (dest_reg
, val
, false))
1604 /* Force the destination to DImode so we can use DImode instructions
1605 to create it. This both allows instructions like rotl, and
1606 certain efficient 3-wide instructions. */
1607 subreg
= simplify_gen_subreg (DImode
, dest_reg
, GET_MODE (dest_reg
), 0);
1608 gcc_assert (subreg
!= NULL
);
1611 temp
= create_temp_reg_if_possible (DImode
, dest_reg
);
1613 leading_zeroes
= 63 - floor_log2 (val
& 0xFFFFFFFFFFFFFFFFULL
);
1614 trailing_zeroes
= exact_log2 (val
& -val
);
1616 /* First try all three-wide instructions that generate a constant
1617 (i.e. movei) followed by various shifts and rotates. If none of
1618 those work, try various two-wide ways of generating a constant
1619 followed by various shifts and rotates. */
1620 for (three_wide_only
= 1; three_wide_only
>= 0; three_wide_only
--)
1624 if (expand_set_cint64_one_inst (temp
, val
>> trailing_zeroes
,
1627 /* 0xFFFFFFFFFFFFA500 becomes:
1628 movei temp, 0xFFFFFFFFFFFFFFA5
1629 shli dest, temp, 8 */
1630 emit_move_insn (dest_reg
,
1631 gen_rtx_ASHIFT (DImode
, temp
,
1632 GEN_INT (trailing_zeroes
)));
1636 if (expand_set_cint64_one_inst (temp
, val
<< leading_zeroes
,
1639 /* 0x7FFFFFFFFFFFFFFF becomes:
1641 shrui dest, temp, 1 */
1642 emit_move_insn (dest_reg
,
1643 gen_rtx_LSHIFTRT (DImode
, temp
,
1644 GEN_INT (leading_zeroes
)));
1648 /* Try rotating a one-instruction immediate. */
1649 for (count
= 1; count
< 64; count
++)
1651 HOST_WIDE_INT r
= rotate_right (val
, count
);
1652 if (expand_set_cint64_one_inst (temp
, r
, three_wide_only
))
1654 /* 0xFFFFFFFFFFA5FFFF becomes:
1655 movei temp, 0xFFFFFFFFFFFFFFA5
1656 rotli dest, temp, 16 */
1657 emit_move_insn (dest_reg
,
1658 gen_rtx_ROTATE (DImode
, temp
, GEN_INT (count
)));
1664 /* There are two cases here to produce a large constant.
1665 In the most general case, we do this:
1668 shl16insli x, x, hw2(NUM)
1669 shl16insli x, x, hw1(NUM)
1670 shl16insli x, x, hw0(NUM)
1672 However, we can sometimes do better. shl16insli is a poor way to
1673 insert 16 zero bits, because simply shifting left by 16 has more
1674 bundling freedom. So if we see any contiguous aligned sequence
1675 of 16 or more zero bits (below the highest set bit), it is always
1676 more efficient to materialize the bits above the zero bits, then
1677 left shift to put in the zeroes, then insert whatever bits
1678 remain. For example, we might end up with:
1680 movei x, NUM >> (37 + 16)
1682 shl16insli x, x, hw0(NUM) */
1684 zero_cluster_shift
= -1;
1686 for (shift
= 0; shift
< 48 - leading_zeroes
; shift
+= 16)
1688 HOST_WIDE_INT x
= val
>> shift
;
1690 /* Find the least significant group of 16 aligned zero bits. */
1691 if ((x
& 0xFFFF) == 0x0000)
1693 /* Grab any following zero bits as well. */
1694 zero_cluster_shift
= exact_log2 (x
& -x
);
1695 shift
+= zero_cluster_shift
;
1700 if (zero_cluster_shift
>= 0)
1702 unsigned HOST_WIDE_INT leftover
;
1704 /* Recursively create the constant above the lowest 16 zero
1706 expand_set_cint64 (temp
, GEN_INT (val
>> shift
));
1708 /* See if we can easily insert the remaining bits, or if we need
1709 to fall through to the more general case. */
1710 leftover
= val
- ((val
>> shift
) << shift
);
1713 /* A simple left shift is enough. */
1714 emit_move_insn (dest_reg
,
1715 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1718 else if (leftover
<= 32767)
1720 /* Left shift into position then add in the leftover. */
1721 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1722 emit_move_insn (temp2
,
1723 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1724 emit_move_insn (dest_reg
,
1725 gen_rtx_PLUS (DImode
, temp2
, GEN_INT (leftover
)));
1730 /* Shift in the batch of >= 16 zeroes we detected earlier.
1731 After this, shift will be aligned mod 16 so the final
1732 loop can use shl16insli. */
1733 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1734 rtx shift_count_rtx
= GEN_INT (zero_cluster_shift
);
1736 emit_move_insn (temp2
,
1737 gen_rtx_ASHIFT (DImode
, temp
, shift_count_rtx
));
1739 shift
-= zero_cluster_shift
;
1745 /* Set as many high 16-bit blocks as we can with a single
1746 instruction. We'll insert the remaining 16-bit blocks
1748 for (shift
= 16;; shift
+= 16)
1750 gcc_assert (shift
< 64);
1751 if (expand_set_cint64_one_inst (temp
, val
>> shift
, false))
1756 /* At this point, temp == val >> shift, shift % 16 == 0, and we
1757 still need to insert any bits of 'val' below 'shift'. Those bits
1758 are guaranteed to not have 16 contiguous zeroes. */
1760 gcc_assert ((shift
& 15) == 0);
1762 for (ins_shift
= shift
- 16; ins_shift
>= 0; ins_shift
-= 16)
1765 HOST_WIDE_INT bits
= (val
>> ins_shift
) & 0xFFFF;
1766 gcc_assert (bits
!= 0);
1768 /* On the last iteration we need to store into dest_reg. */
1772 result
= create_temp_reg_if_possible (DImode
, dest_reg
);
1774 emit_insn (gen_insn_shl16insli (result
, temp
, GEN_INT (bits
)));
1781 /* Load OP1, a 64-bit constant, into OP0, a register. We know it
1782 can't be done in one insn when we get here, the move expander
1785 tilegx_expand_set_const64 (rtx op0
, rtx op1
)
1787 if (CONST_INT_P (op1
))
1789 /* TODO: I don't know if we want to split large constants
1790 now, or wait until later (with a define_split).
1792 Does splitting early help CSE? Does it harm other
1793 optimizations that might fold loads? */
1794 expand_set_cint64 (op0
, op1
);
1798 rtx temp
= create_temp_reg_if_possible (Pmode
, op0
);
1802 /* Generate the 2-insn sequence to materialize a symbolic
1804 emit_insn (gen_mov_address_32bit_step1 (temp
, op1
));
1805 emit_insn (gen_mov_address_32bit_step2 (op0
, temp
, op1
));
1809 /* Generate the 3-insn sequence to materialize a symbolic
1810 address. Note that this assumes that virtual addresses
1811 fit in 48 signed bits, which is currently true. */
1812 rtx temp2
= create_temp_reg_if_possible (Pmode
, op0
);
1813 emit_insn (gen_mov_address_step1 (temp
, op1
));
1814 emit_insn (gen_mov_address_step2 (temp2
, temp
, op1
));
1815 emit_insn (gen_mov_address_step3 (op0
, temp2
, op1
));
1821 /* Expand a move instruction. Return true if all work is done. */
1823 tilegx_expand_mov (machine_mode mode
, rtx
*operands
)
1825 /* Handle sets of MEM first. */
1826 if (MEM_P (operands
[0]))
1828 if (can_create_pseudo_p ())
1829 operands
[0] = validize_mem (operands
[0]);
1831 if (reg_or_0_operand (operands
[1], mode
))
1834 if (!reload_in_progress
)
1835 operands
[1] = force_reg (mode
, operands
[1]);
1838 /* Fixup TLS cases. */
1839 if (CONSTANT_P (operands
[1]) && tilegx_tls_referenced_p (operands
[1]))
1841 operands
[1] = tilegx_legitimize_tls_address (operands
[1]);
1845 /* Fixup PIC cases. */
1846 if (flag_pic
&& CONSTANT_P (operands
[1]))
1848 if (tilegx_pic_address_needs_scratch (operands
[1]))
1849 operands
[1] = tilegx_legitimize_pic_address (operands
[1], mode
, 0);
1851 if (symbolic_operand (operands
[1], mode
))
1853 operands
[1] = tilegx_legitimize_pic_address (operands
[1],
1855 (reload_in_progress
?
1862 /* Accept non-constants and valid constants unmodified. */
1863 if (!CONSTANT_P (operands
[1]) || move_operand (operands
[1], mode
))
1866 /* Split large integers. */
1867 tilegx_expand_set_const64 (operands
[0], operands
[1]);
1872 /* Expand unaligned loads. */
1874 tilegx_expand_unaligned_load (rtx dest_reg
, rtx mem
, HOST_WIDE_INT bitsize
,
1875 HOST_WIDE_INT bit_offset
, bool sign
)
1878 rtx addr_lo
, addr_hi
;
1879 rtx mem_lo
, mem_hi
, hi
;
1880 rtx mema
, wide_result
;
1881 int last_byte_offset
;
1882 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1884 mode
= GET_MODE (dest_reg
);
1886 if (bitsize
== 2 * BITS_PER_UNIT
&& (bit_offset
% BITS_PER_UNIT
) == 0)
1888 rtx mem_left
, mem_right
;
1889 rtx left
= gen_reg_rtx (mode
);
1891 /* When just loading a two byte value, we can load the two bytes
1892 individually and combine them efficiently. */
1894 mem_lo
= adjust_address (mem
, QImode
, byte_offset
);
1895 mem_hi
= adjust_address (mem
, QImode
, byte_offset
+ 1);
1897 if (BYTES_BIG_ENDIAN
)
1910 /* Do a signed load of the second byte and use bfins to set
1911 the high bits of the result. */
1912 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, dest_reg
),
1914 emit_insn (gen_extendqidi2 (gen_lowpart (DImode
, left
), mem_left
));
1915 emit_insn (gen_insv (gen_lowpart (DImode
, dest_reg
),
1916 GEN_INT (64 - 8), GEN_INT (8),
1917 gen_lowpart (DImode
, left
)));
1921 /* Do two unsigned loads and use v1int_l to interleave
1923 rtx right
= gen_reg_rtx (mode
);
1924 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, right
),
1926 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, left
),
1928 emit_insn (gen_insn_v1int_l (gen_lowpart (DImode
, dest_reg
),
1929 gen_lowpart (DImode
, left
),
1930 gen_lowpart (DImode
, right
)));
1936 mema
= XEXP (mem
, 0);
1938 /* AND addresses cannot be in any alias set, since they may
1939 implicitly alias surrounding code. Ideally we'd have some alias
1940 set that covered all types except those with alignment 8 or
1942 addr_lo
= force_reg (Pmode
, plus_constant (Pmode
, mema
, byte_offset
));
1943 mem_lo
= change_address (mem
, mode
,
1944 gen_rtx_AND (GET_MODE (mema
), addr_lo
,
1946 set_mem_alias_set (mem_lo
, 0);
1948 /* Load the high word at an address that will not fault if the low
1949 address is aligned and at the very end of a page. */
1950 last_byte_offset
= (bit_offset
+ bitsize
- 1) / BITS_PER_UNIT
;
1951 addr_hi
= force_reg (Pmode
, plus_constant (Pmode
, mema
, last_byte_offset
));
1952 mem_hi
= change_address (mem
, mode
,
1953 gen_rtx_AND (GET_MODE (mema
), addr_hi
,
1955 set_mem_alias_set (mem_hi
, 0);
1959 addr_lo
= make_safe_from (addr_lo
, dest_reg
);
1960 wide_result
= dest_reg
;
1964 wide_result
= gen_reg_rtx (mode
);
1967 /* Load hi first in case dest_reg is used in mema. */
1968 hi
= gen_reg_rtx (mode
);
1969 emit_move_insn (hi
, mem_hi
);
1970 emit_move_insn (wide_result
, mem_lo
);
1972 emit_insn (gen_insn_dblalign (gen_lowpart (DImode
, wide_result
),
1973 gen_lowpart (DImode
, wide_result
),
1974 gen_lowpart (DImode
, hi
), addr_lo
));
1979 extract_bit_field (gen_lowpart (DImode
, wide_result
),
1980 bitsize
, bit_offset
% BITS_PER_UNIT
,
1981 !sign
, gen_lowpart (DImode
, dest_reg
),
1984 if (extracted
!= dest_reg
)
1985 emit_move_insn (dest_reg
, gen_lowpart (DImode
, extracted
));
1990 /* Expand unaligned stores. */
1992 tilegx_expand_unaligned_store (rtx mem
, rtx src
, HOST_WIDE_INT bitsize
,
1993 HOST_WIDE_INT bit_offset
)
1995 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1996 HOST_WIDE_INT bytesize
= bitsize
/ BITS_PER_UNIT
;
1997 HOST_WIDE_INT shift_init
, shift_increment
, shift_amt
;
2002 shift_init
= BYTES_BIG_ENDIAN
? (bitsize
- BITS_PER_UNIT
) : 0;
2003 shift_increment
= BYTES_BIG_ENDIAN
? -BITS_PER_UNIT
: BITS_PER_UNIT
;
2005 for (i
= 0, shift_amt
= shift_init
;
2007 i
++, shift_amt
+= shift_increment
)
2009 mem_addr
= adjust_address (mem
, QImode
, byte_offset
+ i
);
2013 store_val
= expand_simple_binop (DImode
, LSHIFTRT
,
2014 gen_lowpart (DImode
, src
),
2015 GEN_INT (shift_amt
), NULL
, 1,
2017 store_val
= gen_lowpart (QImode
, store_val
);
2021 store_val
= gen_lowpart (QImode
, src
);
2024 emit_move_insn (mem_addr
, store_val
);
2029 /* Implement the movmisalign patterns. One of the operands is a
2030 memory that is not naturally aligned. Emit instructions to load
2033 tilegx_expand_movmisalign (machine_mode mode
, rtx
*operands
)
2035 if (MEM_P (operands
[1]))
2039 if (register_operand (operands
[0], mode
))
2042 tmp
= gen_reg_rtx (mode
);
2044 tilegx_expand_unaligned_load (tmp
, operands
[1], GET_MODE_BITSIZE (mode
),
2047 if (tmp
!= operands
[0])
2048 emit_move_insn (operands
[0], tmp
);
2050 else if (MEM_P (operands
[0]))
2052 if (!reg_or_0_operand (operands
[1], mode
))
2053 operands
[1] = force_reg (mode
, operands
[1]);
2055 tilegx_expand_unaligned_store (operands
[0], operands
[1],
2056 GET_MODE_BITSIZE (mode
), 0);
2064 /* Implement the allocate_stack pattern (alloca). */
2066 tilegx_allocate_stack (rtx op0
, rtx op1
)
2068 /* Technically the correct way to initialize chain_loc is with
2069 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
2070 * sets the alias_set to that of a frame reference. Some of our
2071 * tests rely on some unsafe assumption about when the chaining
2072 * update is done, we need to be conservative about reordering the
2073 * chaining instructions.
2075 rtx fp_addr
= gen_reg_rtx (Pmode
);
2076 rtx fp_value
= gen_reg_rtx (Pmode
);
2079 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2080 GEN_INT (UNITS_PER_WORD
)));
2082 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
2084 emit_move_insn (fp_value
, fp_loc
);
2086 op1
= force_reg (Pmode
, op1
);
2088 emit_move_insn (stack_pointer_rtx
,
2089 gen_rtx_MINUS (Pmode
, stack_pointer_rtx
, op1
));
2091 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2092 GEN_INT (UNITS_PER_WORD
)));
2094 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
2096 emit_move_insn (fp_loc
, fp_value
);
2098 emit_move_insn (op0
, virtual_stack_dynamic_rtx
);
2106 /* Returns the insn_code in ENTRY. */
2107 static enum insn_code
2108 tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry
2111 return tilegx_multiply_insn_seq_decode_opcode
[entry
->compressed_opcode
];
2115 /* Returns the length of the 'op' array. */
2117 tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq
*seq
)
2119 /* The array either uses all of its allocated slots or is terminated
2120 by a bogus opcode. Either way, the array size is the index of the
2121 last valid opcode plus one. */
2123 for (i
= tilegx_multiply_insn_seq_MAX_OPERATIONS
- 1; i
>= 0; i
--)
2124 if (tilegx_multiply_get_opcode (&seq
->op
[i
]) != CODE_FOR_nothing
)
2127 /* An empty array is not allowed. */
2132 /* We precompute a number of expression trees for multiplying by
2133 constants. This generates code for such an expression tree by
2134 walking through the nodes in the tree (which are conveniently
2135 pre-linearized) and emitting an instruction for each one. */
2137 tilegx_expand_constant_multiply_given_sequence (rtx result
, rtx src
,
2139 tilegx_multiply_insn_seq
*seq
)
2144 /* Keep track of the subexpressions computed so far, so later
2145 instructions can refer to them. We seed the array with zero and
2146 the value being multiplied. */
2147 int num_subexprs
= 2;
2148 rtx subexprs
[tilegx_multiply_insn_seq_MAX_OPERATIONS
+ 2];
2149 subexprs
[0] = const0_rtx
;
2152 /* Determine how many instructions we are going to generate. */
2153 num_ops
= tilegx_multiply_get_num_ops (seq
);
2154 gcc_assert (num_ops
> 0
2155 && num_ops
<= tilegx_multiply_insn_seq_MAX_OPERATIONS
);
2157 for (i
= 0; i
< num_ops
; i
++)
2159 const struct tilegx_multiply_insn_seq_entry
*entry
= &seq
->op
[i
];
2161 /* Figure out where to store the output of this instruction. */
2162 const bool is_last_op
= (i
+ 1 == num_ops
);
2163 rtx out
= is_last_op
? result
: gen_reg_rtx (DImode
);
2165 enum insn_code opcode
= tilegx_multiply_get_opcode (entry
);
2166 if (opcode
== CODE_FOR_ashldi3
)
2168 /* Handle shift by immediate. This is a special case because
2169 the meaning of the second operand is a constant shift
2170 count rather than an operand index. */
2172 /* Make sure the shift count is in range. Zero should not
2174 const int shift_count
= entry
->rhs
;
2175 gcc_assert (shift_count
> 0 && shift_count
< 64);
2177 /* Emit the actual instruction. */
2178 emit_insn (GEN_FCN (opcode
)
2179 (out
, subexprs
[entry
->lhs
],
2180 gen_rtx_CONST_INT (DImode
, shift_count
)));
2184 /* Handle a normal two-operand instruction, such as add or
2187 /* Make sure we are referring to a previously computed
2189 gcc_assert (entry
->rhs
< num_subexprs
);
2191 /* Emit the actual instruction. */
2192 emit_insn (GEN_FCN (opcode
)
2193 (out
, subexprs
[entry
->lhs
], subexprs
[entry
->rhs
]));
2196 /* Record this subexpression for use by later expressions. */
2197 subexprs
[num_subexprs
++] = out
;
2202 /* bsearch helper function. */
2204 tilegx_compare_multipliers (const void *key
, const void *t
)
2207 (*(const long long *) key
2208 - ((const struct tilegx_multiply_insn_seq
*) t
)->multiplier
);
2209 return (delta
< 0) ? -1 : (delta
> 0);
2213 /* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none
2215 static const struct tilegx_multiply_insn_seq
*
2216 tilegx_find_multiply_insn_seq_for_constant (long long multiplier
)
2218 return ((const struct tilegx_multiply_insn_seq
*)
2219 bsearch (&multiplier
, tilegx_multiply_insn_seq_table
,
2220 tilegx_multiply_insn_seq_table_size
,
2221 sizeof tilegx_multiply_insn_seq_table
[0],
2222 tilegx_compare_multipliers
));
2226 /* Try to a expand constant multiply in DImode by looking it up in a
2227 precompiled table. OP0 is the result operand, OP1 is the source
2228 operand, and MULTIPLIER is the value of the constant. Return true
2231 tilegx_expand_const_muldi (rtx op0
, rtx op1
, long long multiplier
)
2233 /* See if we have precomputed an efficient way to multiply by this
2235 const struct tilegx_multiply_insn_seq
*seq
=
2236 tilegx_find_multiply_insn_seq_for_constant (multiplier
);
2239 tilegx_expand_constant_multiply_given_sequence (op0
, op1
, seq
);
2247 /* Expand the muldi pattern. */
2249 tilegx_expand_muldi (rtx op0
, rtx op1
, rtx op2
)
2251 if (CONST_INT_P (op2
))
2253 HOST_WIDE_INT n
= trunc_int_for_mode (INTVAL (op2
), DImode
);
2254 return tilegx_expand_const_muldi (op0
, op1
, n
);
2260 /* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the
2261 operands, and SIGN is true if it's a signed multiply, and false if
2262 it's an unsigned multiply. */
2264 tilegx_expand_high_multiply (rtx result
, rtx op1
, rtx op2
, bool sign
)
2266 rtx tmp0
= gen_reg_rtx (DImode
);
2267 rtx tmp1
= gen_reg_rtx (DImode
);
2268 rtx tmp2
= gen_reg_rtx (DImode
);
2269 rtx tmp3
= gen_reg_rtx (DImode
);
2270 rtx tmp4
= gen_reg_rtx (DImode
);
2271 rtx tmp5
= gen_reg_rtx (DImode
);
2272 rtx tmp6
= gen_reg_rtx (DImode
);
2273 rtx tmp7
= gen_reg_rtx (DImode
);
2274 rtx tmp8
= gen_reg_rtx (DImode
);
2275 rtx tmp9
= gen_reg_rtx (DImode
);
2276 rtx tmp10
= gen_reg_rtx (DImode
);
2277 rtx tmp11
= gen_reg_rtx (DImode
);
2278 rtx tmp12
= gen_reg_rtx (DImode
);
2279 rtx tmp13
= gen_reg_rtx (DImode
);
2280 rtx result_lo
= gen_reg_rtx (DImode
);
2284 emit_insn (gen_insn_mul_hs_lu (tmp0
, op1
, op2
));
2285 emit_insn (gen_insn_mul_hs_lu (tmp1
, op2
, op1
));
2286 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2287 emit_insn (gen_insn_mul_hs_hs (tmp3
, op1
, op2
));
2291 emit_insn (gen_insn_mul_hu_lu (tmp0
, op1
, op2
));
2292 emit_insn (gen_insn_mul_hu_lu (tmp1
, op2
, op1
));
2293 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2294 emit_insn (gen_insn_mul_hu_hu (tmp3
, op1
, op2
));
2297 emit_move_insn (tmp4
, (gen_rtx_ASHIFT (DImode
, tmp0
, GEN_INT (32))));
2299 emit_move_insn (tmp5
, (gen_rtx_ASHIFT (DImode
, tmp1
, GEN_INT (32))));
2301 emit_move_insn (tmp6
, (gen_rtx_PLUS (DImode
, tmp4
, tmp5
)));
2302 emit_move_insn (result_lo
, (gen_rtx_PLUS (DImode
, tmp2
, tmp6
)));
2304 emit_move_insn (tmp7
, gen_rtx_LTU (DImode
, tmp6
, tmp4
));
2305 emit_move_insn (tmp8
, gen_rtx_LTU (DImode
, result_lo
, tmp2
));
2309 emit_move_insn (tmp9
, (gen_rtx_ASHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2310 emit_move_insn (tmp10
, (gen_rtx_ASHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2314 emit_move_insn (tmp9
, (gen_rtx_LSHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2315 emit_move_insn (tmp10
, (gen_rtx_LSHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2318 emit_move_insn (tmp11
, (gen_rtx_PLUS (DImode
, tmp3
, tmp7
)));
2319 emit_move_insn (tmp12
, (gen_rtx_PLUS (DImode
, tmp8
, tmp9
)));
2320 emit_move_insn (tmp13
, (gen_rtx_PLUS (DImode
, tmp11
, tmp12
)));
2321 emit_move_insn (result
, (gen_rtx_PLUS (DImode
, tmp13
, tmp10
)));
2325 /* Implement smuldi3_highpart. */
2327 tilegx_expand_smuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2329 tilegx_expand_high_multiply (op0
, op1
, op2
, true);
2333 /* Implement umuldi3_highpart. */
2335 tilegx_expand_umuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2337 tilegx_expand_high_multiply (op0
, op1
, op2
, false);
2342 /* Compare and branches */
2344 /* Produce the rtx yielding a bool for a floating point
2347 tilegx_emit_fp_setcc (rtx res
, enum rtx_code code
, machine_mode mode
,
2350 /* TODO: Certain compares again constants can be done using entirely
2351 integer operations. But you have to get the special cases right
2352 e.g. NaN, +0 == -0, etc. */
2356 rtx a
= force_reg (DImode
, gen_lowpart (DImode
, op0
));
2357 rtx b
= force_reg (DImode
, gen_lowpart (DImode
, op1
));
2359 flags
= gen_reg_rtx (DImode
);
2363 emit_insn (gen_insn_fsingle_add1 (flags
, a
, b
));
2367 gcc_assert (mode
== DFmode
);
2368 emit_insn (gen_insn_fdouble_add_flags (flags
, a
, b
));
2373 case EQ
: flag_index
= 30; break;
2374 case NE
: flag_index
= 31; break;
2375 case LE
: flag_index
= 27; break;
2376 case LT
: flag_index
= 26; break;
2377 case GE
: flag_index
= 29; break;
2378 case GT
: flag_index
= 28; break;
2379 default: gcc_unreachable ();
2382 gcc_assert (GET_MODE (res
) == DImode
);
2383 emit_move_insn (res
, gen_rtx_ZERO_EXTRACT (DImode
, flags
, GEN_INT (1),
2384 GEN_INT (flag_index
)));
2389 /* Certain simplifications can be done to make invalid setcc
2390 operations valid. Return the final comparison, or NULL if we can't
2393 tilegx_emit_setcc_internal (rtx res
, enum rtx_code code
, rtx op0
, rtx op1
,
2394 machine_mode cmp_mode
)
2399 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2400 return tilegx_emit_fp_setcc (res
, code
, cmp_mode
, op0
, op1
);
2402 /* The general case: fold the comparison code to the types of
2403 compares that we have, choosing the branch as necessary. */
2413 /* We have these compares. */
2420 /* We do not have these compares, so we reverse the
2426 /* We should not have called this with any other code. */
2432 code
= swap_condition (code
);
2433 tmp
= op0
, op0
= op1
, op1
= tmp
;
2436 if (!reg_or_0_operand (op0
, cmp_mode
))
2437 op0
= force_reg (cmp_mode
, op0
);
2439 if (!CONST_INT_P (op1
) && !register_operand (op1
, cmp_mode
))
2440 op1
= force_reg (cmp_mode
, op1
);
2442 /* Return the setcc comparison. */
2443 emit_insn (gen_rtx_SET (VOIDmode
, res
,
2444 gen_rtx_fmt_ee (code
, DImode
, op0
, op1
)));
2450 /* Implement cstore patterns. */
2452 tilegx_emit_setcc (rtx operands
[], machine_mode cmp_mode
)
2455 tilegx_emit_setcc_internal (operands
[0], GET_CODE (operands
[1]),
2456 operands
[2], operands
[3], cmp_mode
);
2460 /* Return whether CODE is a signed comparison. */
2462 signed_compare_p (enum rtx_code code
)
2464 return (code
== EQ
|| code
== NE
|| code
== LT
|| code
== LE
2465 || code
== GT
|| code
== GE
);
2469 /* Generate the comparison for a DImode conditional branch. */
2471 tilegx_emit_cc_test (enum rtx_code code
, rtx op0
, rtx op1
,
2472 machine_mode cmp_mode
, bool eq_ne_only
)
2474 enum rtx_code branch_code
;
2477 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2479 /* Compute a boolean saying whether the comparison is true. */
2480 temp
= gen_reg_rtx (DImode
);
2481 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2483 /* Test that flag. */
2484 return gen_rtx_fmt_ee (NE
, VOIDmode
, temp
, const0_rtx
);
2487 /* Check for a compare against zero using a comparison we can do
2489 if (op1
== const0_rtx
2490 && (code
== EQ
|| code
== NE
2491 || (!eq_ne_only
&& signed_compare_p (code
))))
2493 op0
= force_reg (cmp_mode
, op0
);
2494 return gen_rtx_fmt_ee (code
, VOIDmode
, op0
, const0_rtx
);
2497 /* The general case: fold the comparison code to the types of
2498 compares that we have, choosing the branch as necessary. */
2506 /* We have these compares. */
2515 /* These must be reversed (except NE, but let's
2517 code
= reverse_condition (code
);
2525 if (CONST_INT_P (op1
) && (!satisfies_constraint_I (op1
) || code
== LEU
))
2527 HOST_WIDE_INT n
= INTVAL (op1
);
2532 /* Subtract off the value we want to compare against and see
2533 if we get zero. This is cheaper than creating a constant
2534 in a register. Except that subtracting -128 is more
2535 expensive than seqi to -128, so we leave that alone. */
2536 /* ??? Don't do this when comparing against symbols,
2537 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2538 0), which will be declared false out of hand (at least
2541 && add_operand (GEN_INT (-n
), DImode
)
2542 && !(symbolic_operand (op0
, VOIDmode
)
2543 || (REG_P (op0
) && REG_POINTER (op0
))))
2545 /* TODO: Use a SIMD add immediate to hit zero for tiled
2546 constants in a single instruction. */
2547 if (GET_MODE (op0
) != DImode
)
2549 /* Convert to DImode so we can use addli. Note that
2550 this will not actually generate any code because
2551 sign extension from SI -> DI is a no-op. I don't
2552 know if it's safe just to make a paradoxical
2553 subreg here though. */
2554 rtx temp2
= gen_reg_rtx (DImode
);
2555 emit_insn (gen_extendsidi2 (temp2
, op0
));
2560 op0
= force_reg (DImode
, op0
);
2562 temp
= gen_reg_rtx (DImode
);
2563 emit_move_insn (temp
, gen_rtx_PLUS (DImode
, op0
, GEN_INT (-n
)));
2564 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2565 VOIDmode
, temp
, const0_rtx
);
2575 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2576 We use arithmetic shift right because it's a 3-wide op,
2577 while logical shift right is not. */
2579 int first
= exact_log2 (code
== LTU
? n
: n
+ 1);
2582 op0
= force_reg (cmp_mode
, op0
);
2583 temp
= gen_reg_rtx (cmp_mode
);
2584 emit_move_insn (temp
,
2585 gen_rtx_ASHIFTRT (cmp_mode
, op0
,
2587 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2588 VOIDmode
, temp
, const0_rtx
);
2598 /* Compute a flag saying whether we should branch. */
2599 temp
= gen_reg_rtx (DImode
);
2600 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2602 /* Return the branch comparison. */
2603 return gen_rtx_fmt_ee (branch_code
, VOIDmode
, temp
, const0_rtx
);
2607 /* Generate the comparison for a conditional branch. */
2609 tilegx_emit_conditional_branch (rtx operands
[], machine_mode cmp_mode
)
2612 tilegx_emit_cc_test (GET_CODE (operands
[0]), operands
[1], operands
[2],
2614 rtx branch_rtx
= gen_rtx_SET (VOIDmode
, pc_rtx
,
2615 gen_rtx_IF_THEN_ELSE (VOIDmode
, cmp_rtx
,
2620 emit_jump_insn (branch_rtx
);
2624 /* Implement the mov<mode>cc pattern. */
2626 tilegx_emit_conditional_move (rtx cmp
)
2629 tilegx_emit_cc_test (GET_CODE (cmp
), XEXP (cmp
, 0), XEXP (cmp
, 1),
2630 GET_MODE (XEXP (cmp
, 0)), true);
2634 /* Return true if INSN is annotated with a REG_BR_PROB note that
2635 indicates it's a branch that's predicted taken. */
2637 cbranch_predicted_p (rtx_insn
*insn
)
2639 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2643 int pred_val
= XINT (x
, 0);
2645 return pred_val
>= REG_BR_PROB_BASE
/ 2;
2652 /* Output assembly code for a specific branch instruction, appending
2653 the branch prediction flag to the opcode if appropriate. */
2655 tilegx_output_simple_cbranch_with_opcode (rtx_insn
*insn
, const char *opcode
,
2656 int regop
, bool reverse_predicted
)
2658 static char buf
[64];
2659 sprintf (buf
, "%s%s\t%%r%d, %%l0", opcode
,
2660 (cbranch_predicted_p (insn
) ^ reverse_predicted
) ? "t" : "",
2666 /* Output assembly code for a specific branch instruction, appending
2667 the branch prediction flag to the opcode if appropriate. */
2669 tilegx_output_cbranch_with_opcode (rtx_insn
*insn
, rtx
*operands
,
2671 const char *rev_opcode
, int regop
)
2673 const char *branch_if_false
;
2674 rtx taken
, not_taken
;
2675 bool is_simple_branch
;
2677 gcc_assert (LABEL_P (operands
[0]));
2679 is_simple_branch
= true;
2680 if (INSN_ADDRESSES_SET_P ())
2682 int from_addr
= INSN_ADDRESSES (INSN_UID (insn
));
2683 int to_addr
= INSN_ADDRESSES (INSN_UID (operands
[0]));
2684 int delta
= to_addr
- from_addr
;
2685 is_simple_branch
= IN_RANGE (delta
, -524288, 524280);
2688 if (is_simple_branch
)
2690 /* Just a simple conditional branch. */
2692 tilegx_output_simple_cbranch_with_opcode (insn
, opcode
, regop
, false);
2695 /* Generate a reversed branch around a direct jump. This fallback
2696 does not use branch-likely instructions. */
2697 not_taken
= gen_label_rtx ();
2698 taken
= operands
[0];
2700 /* Generate the reversed branch to NOT_TAKEN. */
2701 operands
[0] = not_taken
;
2703 tilegx_output_simple_cbranch_with_opcode (insn
, rev_opcode
, regop
, true);
2704 output_asm_insn (branch_if_false
, operands
);
2706 output_asm_insn ("j\t%l0", &taken
);
2708 /* Output NOT_TAKEN. */
2709 targetm
.asm_out
.internal_label (asm_out_file
, "L",
2710 CODE_LABEL_NUMBER (not_taken
));
2715 /* Output assembly code for a conditional branch instruction. */
2717 tilegx_output_cbranch (rtx_insn
*insn
, rtx
*operands
, bool reversed
)
2719 enum rtx_code code
= GET_CODE (operands
[1]);
2721 const char *rev_opcode
;
2724 code
= reverse_condition (code
);
2730 rev_opcode
= "beqz";
2734 rev_opcode
= "bnez";
2738 rev_opcode
= "bltz";
2742 rev_opcode
= "blez";
2746 rev_opcode
= "bgtz";
2750 rev_opcode
= "bgez";
2756 return tilegx_output_cbranch_with_opcode (insn
, operands
, opcode
,
2761 /* Implement the tablejump pattern. */
2763 tilegx_expand_tablejump (rtx op0
, rtx op1
)
2767 rtx temp
= gen_reg_rtx (Pmode
);
2768 rtx temp2
= gen_reg_rtx (Pmode
);
2770 tilegx_compute_pcrel_address (temp
, gen_rtx_LABEL_REF (Pmode
, op1
));
2771 emit_move_insn (temp2
,
2772 gen_rtx_PLUS (Pmode
,
2773 convert_to_mode (Pmode
, op0
, false),
2778 emit_jump_insn (gen_tablejump_aux (op0
, op1
));
2782 /* Emit barrier before an atomic, as needed for the memory MODEL. */
2784 tilegx_pre_atomic_barrier (enum memmodel model
)
2786 if (need_atomic_barrier_p (model
, true))
2787 emit_insn (gen_memory_barrier ());
2791 /* Emit barrier after an atomic, as needed for the memory MODEL. */
2793 tilegx_post_atomic_barrier (enum memmodel model
)
2795 if (need_atomic_barrier_p (model
, false))
2796 emit_insn (gen_memory_barrier ());
2801 /* Expand a builtin vector binary op, by calling gen function GEN with
2802 operands in the proper modes. DEST is converted to DEST_MODE, and
2803 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2805 tilegx_expand_builtin_vector_binop (rtx (*gen
) (rtx
, rtx
, rtx
),
2806 machine_mode dest_mode
,
2808 machine_mode src_mode
,
2809 rtx src0
, rtx src1
, bool do_src1
)
2811 dest
= gen_lowpart (dest_mode
, dest
);
2813 if (src0
== const0_rtx
)
2814 src0
= CONST0_RTX (src_mode
);
2816 src0
= gen_lowpart (src_mode
, src0
);
2820 if (src1
== const0_rtx
)
2821 src1
= CONST0_RTX (src_mode
);
2823 src1
= gen_lowpart (src_mode
, src1
);
2826 emit_insn ((*gen
) (dest
, src0
, src1
));
2834 struct tile_builtin_info
2836 enum insn_code icode
;
2840 static struct tile_builtin_info tilegx_builtin_info
[TILEGX_BUILTIN_max
] = {
2841 { CODE_FOR_adddi3
, NULL
}, /* add */
2842 { CODE_FOR_addsi3
, NULL
}, /* addx */
2843 { CODE_FOR_ssaddsi3
, NULL
}, /* addxsc */
2844 { CODE_FOR_anddi3
, NULL
}, /* and */
2845 { CODE_FOR_insn_bfexts
, NULL
}, /* bfexts */
2846 { CODE_FOR_insn_bfextu
, NULL
}, /* bfextu */
2847 { CODE_FOR_insn_bfins
, NULL
}, /* bfins */
2848 { CODE_FOR_clzdi2
, NULL
}, /* clz */
2849 { CODE_FOR_insn_cmoveqz
, NULL
}, /* cmoveqz */
2850 { CODE_FOR_insn_cmovnez
, NULL
}, /* cmovnez */
2851 { CODE_FOR_insn_cmpeq_didi
, NULL
}, /* cmpeq */
2852 { CODE_FOR_insn_cmpexch
, NULL
}, /* cmpexch */
2853 { CODE_FOR_insn_cmpexch4
, NULL
}, /* cmpexch4 */
2854 { CODE_FOR_insn_cmples_didi
, NULL
}, /* cmples */
2855 { CODE_FOR_insn_cmpleu_didi
, NULL
}, /* cmpleu */
2856 { CODE_FOR_insn_cmplts_didi
, NULL
}, /* cmplts */
2857 { CODE_FOR_insn_cmpltu_didi
, NULL
}, /* cmpltu */
2858 { CODE_FOR_insn_cmpne_didi
, NULL
}, /* cmpne */
2859 { CODE_FOR_insn_cmul
, NULL
}, /* cmul */
2860 { CODE_FOR_insn_cmula
, NULL
}, /* cmula */
2861 { CODE_FOR_insn_cmulaf
, NULL
}, /* cmulaf */
2862 { CODE_FOR_insn_cmulf
, NULL
}, /* cmulf */
2863 { CODE_FOR_insn_cmulfr
, NULL
}, /* cmulfr */
2864 { CODE_FOR_insn_cmulh
, NULL
}, /* cmulh */
2865 { CODE_FOR_insn_cmulhr
, NULL
}, /* cmulhr */
2866 { CODE_FOR_insn_crc32_32
, NULL
}, /* crc32_32 */
2867 { CODE_FOR_insn_crc32_8
, NULL
}, /* crc32_8 */
2868 { CODE_FOR_ctzdi2
, NULL
}, /* ctz */
2869 { CODE_FOR_insn_dblalign
, NULL
}, /* dblalign */
2870 { CODE_FOR_insn_dblalign2
, NULL
}, /* dblalign2 */
2871 { CODE_FOR_insn_dblalign4
, NULL
}, /* dblalign4 */
2872 { CODE_FOR_insn_dblalign6
, NULL
}, /* dblalign6 */
2873 { CODE_FOR_insn_drain
, NULL
}, /* drain */
2874 { CODE_FOR_insn_dtlbpr
, NULL
}, /* dtlbpr */
2875 { CODE_FOR_insn_exch
, NULL
}, /* exch */
2876 { CODE_FOR_insn_exch4
, NULL
}, /* exch4 */
2877 { CODE_FOR_insn_fdouble_add_flags
, NULL
}, /* fdouble_add_flags */
2878 { CODE_FOR_insn_fdouble_addsub
, NULL
}, /* fdouble_addsub */
2879 { CODE_FOR_insn_fdouble_mul_flags
, NULL
}, /* fdouble_mul_flags */
2880 { CODE_FOR_insn_fdouble_pack1
, NULL
}, /* fdouble_pack1 */
2881 { CODE_FOR_insn_fdouble_pack2
, NULL
}, /* fdouble_pack2 */
2882 { CODE_FOR_insn_fdouble_sub_flags
, NULL
}, /* fdouble_sub_flags */
2883 { CODE_FOR_insn_fdouble_unpack_max
, NULL
}, /* fdouble_unpack_max */
2884 { CODE_FOR_insn_fdouble_unpack_min
, NULL
}, /* fdouble_unpack_min */
2885 { CODE_FOR_insn_fetchadd
, NULL
}, /* fetchadd */
2886 { CODE_FOR_insn_fetchadd4
, NULL
}, /* fetchadd4 */
2887 { CODE_FOR_insn_fetchaddgez
, NULL
}, /* fetchaddgez */
2888 { CODE_FOR_insn_fetchaddgez4
, NULL
}, /* fetchaddgez4 */
2889 { CODE_FOR_insn_fetchand
, NULL
}, /* fetchand */
2890 { CODE_FOR_insn_fetchand4
, NULL
}, /* fetchand4 */
2891 { CODE_FOR_insn_fetchor
, NULL
}, /* fetchor */
2892 { CODE_FOR_insn_fetchor4
, NULL
}, /* fetchor4 */
2893 { CODE_FOR_insn_finv
, NULL
}, /* finv */
2894 { CODE_FOR_insn_flush
, NULL
}, /* flush */
2895 { CODE_FOR_insn_flushwb
, NULL
}, /* flushwb */
2896 { CODE_FOR_insn_fnop
, NULL
}, /* fnop */
2897 { CODE_FOR_insn_fsingle_add1
, NULL
}, /* fsingle_add1 */
2898 { CODE_FOR_insn_fsingle_addsub2
, NULL
}, /* fsingle_addsub2 */
2899 { CODE_FOR_insn_fsingle_mul1
, NULL
}, /* fsingle_mul1 */
2900 { CODE_FOR_insn_fsingle_mul2
, NULL
}, /* fsingle_mul2 */
2901 { CODE_FOR_insn_fsingle_pack1
, NULL
}, /* fsingle_pack1 */
2902 { CODE_FOR_insn_fsingle_pack2
, NULL
}, /* fsingle_pack2 */
2903 { CODE_FOR_insn_fsingle_sub1
, NULL
}, /* fsingle_sub1 */
2904 { CODE_FOR_insn_icoh
, NULL
}, /* icoh */
2905 { CODE_FOR_insn_ill
, NULL
}, /* ill */
2906 { CODE_FOR_insn_info
, NULL
}, /* info */
2907 { CODE_FOR_insn_infol
, NULL
}, /* infol */
2908 { CODE_FOR_insn_inv
, NULL
}, /* inv */
2909 { CODE_FOR_insn_ld
, NULL
}, /* ld */
2910 { CODE_FOR_insn_ld1s
, NULL
}, /* ld1s */
2911 { CODE_FOR_insn_ld1u
, NULL
}, /* ld1u */
2912 { CODE_FOR_insn_ld2s
, NULL
}, /* ld2s */
2913 { CODE_FOR_insn_ld2u
, NULL
}, /* ld2u */
2914 { CODE_FOR_insn_ld4s
, NULL
}, /* ld4s */
2915 { CODE_FOR_insn_ld4u
, NULL
}, /* ld4u */
2916 { CODE_FOR_insn_ldna
, NULL
}, /* ldna */
2917 { CODE_FOR_insn_ldnt
, NULL
}, /* ldnt */
2918 { CODE_FOR_insn_ldnt1s
, NULL
}, /* ldnt1s */
2919 { CODE_FOR_insn_ldnt1u
, NULL
}, /* ldnt1u */
2920 { CODE_FOR_insn_ldnt2s
, NULL
}, /* ldnt2s */
2921 { CODE_FOR_insn_ldnt2u
, NULL
}, /* ldnt2u */
2922 { CODE_FOR_insn_ldnt4s
, NULL
}, /* ldnt4s */
2923 { CODE_FOR_insn_ldnt4u
, NULL
}, /* ldnt4u */
2924 { CODE_FOR_insn_ld_L2
, NULL
}, /* ld_L2 */
2925 { CODE_FOR_insn_ld1s_L2
, NULL
}, /* ld1s_L2 */
2926 { CODE_FOR_insn_ld1u_L2
, NULL
}, /* ld1u_L2 */
2927 { CODE_FOR_insn_ld2s_L2
, NULL
}, /* ld2s_L2 */
2928 { CODE_FOR_insn_ld2u_L2
, NULL
}, /* ld2u_L2 */
2929 { CODE_FOR_insn_ld4s_L2
, NULL
}, /* ld4s_L2 */
2930 { CODE_FOR_insn_ld4u_L2
, NULL
}, /* ld4u_L2 */
2931 { CODE_FOR_insn_ldna_L2
, NULL
}, /* ldna_L2 */
2932 { CODE_FOR_insn_ldnt_L2
, NULL
}, /* ldnt_L2 */
2933 { CODE_FOR_insn_ldnt1s_L2
, NULL
}, /* ldnt1s_L2 */
2934 { CODE_FOR_insn_ldnt1u_L2
, NULL
}, /* ldnt1u_L2 */
2935 { CODE_FOR_insn_ldnt2s_L2
, NULL
}, /* ldnt2s_L2 */
2936 { CODE_FOR_insn_ldnt2u_L2
, NULL
}, /* ldnt2u_L2 */
2937 { CODE_FOR_insn_ldnt4s_L2
, NULL
}, /* ldnt4s_L2 */
2938 { CODE_FOR_insn_ldnt4u_L2
, NULL
}, /* ldnt4u_L2 */
2939 { CODE_FOR_insn_ld_miss
, NULL
}, /* ld_miss */
2940 { CODE_FOR_insn_ld1s_miss
, NULL
}, /* ld1s_miss */
2941 { CODE_FOR_insn_ld1u_miss
, NULL
}, /* ld1u_miss */
2942 { CODE_FOR_insn_ld2s_miss
, NULL
}, /* ld2s_miss */
2943 { CODE_FOR_insn_ld2u_miss
, NULL
}, /* ld2u_miss */
2944 { CODE_FOR_insn_ld4s_miss
, NULL
}, /* ld4s_miss */
2945 { CODE_FOR_insn_ld4u_miss
, NULL
}, /* ld4u_miss */
2946 { CODE_FOR_insn_ldna_miss
, NULL
}, /* ldna_miss */
2947 { CODE_FOR_insn_ldnt_miss
, NULL
}, /* ldnt_miss */
2948 { CODE_FOR_insn_ldnt1s_miss
, NULL
}, /* ldnt1s_miss */
2949 { CODE_FOR_insn_ldnt1u_miss
, NULL
}, /* ldnt1u_miss */
2950 { CODE_FOR_insn_ldnt2s_miss
, NULL
}, /* ldnt2s_miss */
2951 { CODE_FOR_insn_ldnt2u_miss
, NULL
}, /* ldnt2u_miss */
2952 { CODE_FOR_insn_ldnt4s_miss
, NULL
}, /* ldnt4s_miss */
2953 { CODE_FOR_insn_ldnt4u_miss
, NULL
}, /* ldnt4u_miss */
2954 { CODE_FOR_insn_lnk
, NULL
}, /* lnk */
2955 { CODE_FOR_memory_barrier
, NULL
}, /* mf */
2956 { CODE_FOR_insn_mfspr
, NULL
}, /* mfspr */
2957 { CODE_FOR_insn_mm
, NULL
}, /* mm */
2958 { CODE_FOR_insn_mnz
, NULL
}, /* mnz */
2959 { CODE_FOR_movdi
, NULL
}, /* move */
2960 { CODE_FOR_insn_mtspr
, NULL
}, /* mtspr */
2961 { CODE_FOR_insn_mul_hs_hs
, NULL
}, /* mul_hs_hs */
2962 { CODE_FOR_insn_mul_hs_hu
, NULL
}, /* mul_hs_hu */
2963 { CODE_FOR_insn_mul_hs_ls
, NULL
}, /* mul_hs_ls */
2964 { CODE_FOR_insn_mul_hs_lu
, NULL
}, /* mul_hs_lu */
2965 { CODE_FOR_insn_mul_hu_hu
, NULL
}, /* mul_hu_hu */
2966 { CODE_FOR_insn_mul_hu_ls
, NULL
}, /* mul_hu_ls */
2967 { CODE_FOR_insn_mul_hu_lu
, NULL
}, /* mul_hu_lu */
2968 { CODE_FOR_insn_mul_ls_ls
, NULL
}, /* mul_ls_ls */
2969 { CODE_FOR_insn_mul_ls_lu
, NULL
}, /* mul_ls_lu */
2970 { CODE_FOR_insn_mul_lu_lu
, NULL
}, /* mul_lu_lu */
2971 { CODE_FOR_insn_mula_hs_hs
, NULL
}, /* mula_hs_hs */
2972 { CODE_FOR_insn_mula_hs_hu
, NULL
}, /* mula_hs_hu */
2973 { CODE_FOR_insn_mula_hs_ls
, NULL
}, /* mula_hs_ls */
2974 { CODE_FOR_insn_mula_hs_lu
, NULL
}, /* mula_hs_lu */
2975 { CODE_FOR_insn_mula_hu_hu
, NULL
}, /* mula_hu_hu */
2976 { CODE_FOR_insn_mula_hu_ls
, NULL
}, /* mula_hu_ls */
2977 { CODE_FOR_insn_mula_hu_lu
, NULL
}, /* mula_hu_lu */
2978 { CODE_FOR_insn_mula_ls_ls
, NULL
}, /* mula_ls_ls */
2979 { CODE_FOR_insn_mula_ls_lu
, NULL
}, /* mula_ls_lu */
2980 { CODE_FOR_insn_mula_lu_lu
, NULL
}, /* mula_lu_lu */
2981 { CODE_FOR_insn_mulax
, NULL
}, /* mulax */
2982 { CODE_FOR_mulsi3
, NULL
}, /* mulx */
2983 { CODE_FOR_insn_mz
, NULL
}, /* mz */
2984 { CODE_FOR_insn_nap
, NULL
}, /* nap */
2985 { CODE_FOR_nop
, NULL
}, /* nop */
2986 { CODE_FOR_insn_nor_di
, NULL
}, /* nor */
2987 { CODE_FOR_iordi3
, NULL
}, /* or */
2988 { CODE_FOR_popcountdi2
, NULL
}, /* pcnt */
2989 { CODE_FOR_insn_prefetch_l1
, NULL
}, /* prefetch_l1 */
2990 { CODE_FOR_insn_prefetch_l1_fault
, NULL
}, /* prefetch_l1_fault */
2991 { CODE_FOR_insn_prefetch_l2
, NULL
}, /* prefetch_l2 */
2992 { CODE_FOR_insn_prefetch_l2_fault
, NULL
}, /* prefetch_l2_fault */
2993 { CODE_FOR_insn_prefetch_l3
, NULL
}, /* prefetch_l3 */
2994 { CODE_FOR_insn_prefetch_l3_fault
, NULL
}, /* prefetch_l3_fault */
2995 { CODE_FOR_insn_revbits
, NULL
}, /* revbits */
2996 { CODE_FOR_bswapdi2
, NULL
}, /* revbytes */
2997 { CODE_FOR_rotldi3
, NULL
}, /* rotl */
2998 { CODE_FOR_ashldi3
, NULL
}, /* shl */
2999 { CODE_FOR_insn_shl16insli
, NULL
}, /* shl16insli */
3000 { CODE_FOR_insn_shl1add
, NULL
}, /* shl1add */
3001 { CODE_FOR_insn_shl1addx
, NULL
}, /* shl1addx */
3002 { CODE_FOR_insn_shl2add
, NULL
}, /* shl2add */
3003 { CODE_FOR_insn_shl2addx
, NULL
}, /* shl2addx */
3004 { CODE_FOR_insn_shl3add
, NULL
}, /* shl3add */
3005 { CODE_FOR_insn_shl3addx
, NULL
}, /* shl3addx */
3006 { CODE_FOR_ashlsi3
, NULL
}, /* shlx */
3007 { CODE_FOR_ashrdi3
, NULL
}, /* shrs */
3008 { CODE_FOR_lshrdi3
, NULL
}, /* shru */
3009 { CODE_FOR_lshrsi3
, NULL
}, /* shrux */
3010 { CODE_FOR_insn_shufflebytes
, NULL
}, /* shufflebytes */
3011 { CODE_FOR_insn_shufflebytes1
, NULL
}, /* shufflebytes1 */
3012 { CODE_FOR_insn_st
, NULL
}, /* st */
3013 { CODE_FOR_insn_st1
, NULL
}, /* st1 */
3014 { CODE_FOR_insn_st2
, NULL
}, /* st2 */
3015 { CODE_FOR_insn_st4
, NULL
}, /* st4 */
3016 { CODE_FOR_insn_stnt
, NULL
}, /* stnt */
3017 { CODE_FOR_insn_stnt1
, NULL
}, /* stnt1 */
3018 { CODE_FOR_insn_stnt2
, NULL
}, /* stnt2 */
3019 { CODE_FOR_insn_stnt4
, NULL
}, /* stnt4 */
3020 { CODE_FOR_subdi3
, NULL
}, /* sub */
3021 { CODE_FOR_subsi3
, NULL
}, /* subx */
3022 { CODE_FOR_sssubsi3
, NULL
}, /* subxsc */
3023 { CODE_FOR_insn_tblidxb0
, NULL
}, /* tblidxb0 */
3024 { CODE_FOR_insn_tblidxb1
, NULL
}, /* tblidxb1 */
3025 { CODE_FOR_insn_tblidxb2
, NULL
}, /* tblidxb2 */
3026 { CODE_FOR_insn_tblidxb3
, NULL
}, /* tblidxb3 */
3027 { CODE_FOR_insn_v1add
, NULL
}, /* v1add */
3028 { CODE_FOR_insn_v1addi
, NULL
}, /* v1addi */
3029 { CODE_FOR_insn_v1adduc
, NULL
}, /* v1adduc */
3030 { CODE_FOR_insn_v1adiffu
, NULL
}, /* v1adiffu */
3031 { CODE_FOR_insn_v1avgu
, NULL
}, /* v1avgu */
3032 { CODE_FOR_insn_v1cmpeq
, NULL
}, /* v1cmpeq */
3033 { CODE_FOR_insn_v1cmpeqi
, NULL
}, /* v1cmpeqi */
3034 { CODE_FOR_insn_v1cmples
, NULL
}, /* v1cmples */
3035 { CODE_FOR_insn_v1cmpleu
, NULL
}, /* v1cmpleu */
3036 { CODE_FOR_insn_v1cmplts
, NULL
}, /* v1cmplts */
3037 { CODE_FOR_insn_v1cmpltsi
, NULL
}, /* v1cmpltsi */
3038 { CODE_FOR_insn_v1cmpltu
, NULL
}, /* v1cmpltu */
3039 { CODE_FOR_insn_v1cmpltui
, NULL
}, /* v1cmpltui */
3040 { CODE_FOR_insn_v1cmpne
, NULL
}, /* v1cmpne */
3041 { CODE_FOR_insn_v1ddotpu
, NULL
}, /* v1ddotpu */
3042 { CODE_FOR_insn_v1ddotpua
, NULL
}, /* v1ddotpua */
3043 { CODE_FOR_insn_v1ddotpus
, NULL
}, /* v1ddotpus */
3044 { CODE_FOR_insn_v1ddotpusa
, NULL
}, /* v1ddotpusa */
3045 { CODE_FOR_insn_v1dotp
, NULL
}, /* v1dotp */
3046 { CODE_FOR_insn_v1dotpa
, NULL
}, /* v1dotpa */
3047 { CODE_FOR_insn_v1dotpu
, NULL
}, /* v1dotpu */
3048 { CODE_FOR_insn_v1dotpua
, NULL
}, /* v1dotpua */
3049 { CODE_FOR_insn_v1dotpus
, NULL
}, /* v1dotpus */
3050 { CODE_FOR_insn_v1dotpusa
, NULL
}, /* v1dotpusa */
3051 { CODE_FOR_insn_v1int_h
, NULL
}, /* v1int_h */
3052 { CODE_FOR_insn_v1int_l
, NULL
}, /* v1int_l */
3053 { CODE_FOR_insn_v1maxu
, NULL
}, /* v1maxu */
3054 { CODE_FOR_insn_v1maxui
, NULL
}, /* v1maxui */
3055 { CODE_FOR_insn_v1minu
, NULL
}, /* v1minu */
3056 { CODE_FOR_insn_v1minui
, NULL
}, /* v1minui */
3057 { CODE_FOR_insn_v1mnz
, NULL
}, /* v1mnz */
3058 { CODE_FOR_insn_v1multu
, NULL
}, /* v1multu */
3059 { CODE_FOR_insn_v1mulu
, NULL
}, /* v1mulu */
3060 { CODE_FOR_insn_v1mulus
, NULL
}, /* v1mulus */
3061 { CODE_FOR_insn_v1mz
, NULL
}, /* v1mz */
3062 { CODE_FOR_insn_v1sadau
, NULL
}, /* v1sadau */
3063 { CODE_FOR_insn_v1sadu
, NULL
}, /* v1sadu */
3064 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shl */
3065 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shli */
3066 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrs */
3067 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrsi */
3068 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shru */
3069 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shrui */
3070 { CODE_FOR_insn_v1sub
, NULL
}, /* v1sub */
3071 { CODE_FOR_insn_v1subuc
, NULL
}, /* v1subuc */
3072 { CODE_FOR_insn_v2add
, NULL
}, /* v2add */
3073 { CODE_FOR_insn_v2addi
, NULL
}, /* v2addi */
3074 { CODE_FOR_insn_v2addsc
, NULL
}, /* v2addsc */
3075 { CODE_FOR_insn_v2adiffs
, NULL
}, /* v2adiffs */
3076 { CODE_FOR_insn_v2avgs
, NULL
}, /* v2avgs */
3077 { CODE_FOR_insn_v2cmpeq
, NULL
}, /* v2cmpeq */
3078 { CODE_FOR_insn_v2cmpeqi
, NULL
}, /* v2cmpeqi */
3079 { CODE_FOR_insn_v2cmples
, NULL
}, /* v2cmples */
3080 { CODE_FOR_insn_v2cmpleu
, NULL
}, /* v2cmpleu */
3081 { CODE_FOR_insn_v2cmplts
, NULL
}, /* v2cmplts */
3082 { CODE_FOR_insn_v2cmpltsi
, NULL
}, /* v2cmpltsi */
3083 { CODE_FOR_insn_v2cmpltu
, NULL
}, /* v2cmpltu */
3084 { CODE_FOR_insn_v2cmpltui
, NULL
}, /* v2cmpltui */
3085 { CODE_FOR_insn_v2cmpne
, NULL
}, /* v2cmpne */
3086 { CODE_FOR_insn_v2dotp
, NULL
}, /* v2dotp */
3087 { CODE_FOR_insn_v2dotpa
, NULL
}, /* v2dotpa */
3088 { CODE_FOR_insn_v2int_h
, NULL
}, /* v2int_h */
3089 { CODE_FOR_insn_v2int_l
, NULL
}, /* v2int_l */
3090 { CODE_FOR_insn_v2maxs
, NULL
}, /* v2maxs */
3091 { CODE_FOR_insn_v2maxsi
, NULL
}, /* v2maxsi */
3092 { CODE_FOR_insn_v2mins
, NULL
}, /* v2mins */
3093 { CODE_FOR_insn_v2minsi
, NULL
}, /* v2minsi */
3094 { CODE_FOR_insn_v2mnz
, NULL
}, /* v2mnz */
3095 { CODE_FOR_insn_v2mulfsc
, NULL
}, /* v2mulfsc */
3096 { CODE_FOR_insn_v2muls
, NULL
}, /* v2muls */
3097 { CODE_FOR_insn_v2mults
, NULL
}, /* v2mults */
3098 { CODE_FOR_insn_v2mz
, NULL
}, /* v2mz */
3099 { CODE_FOR_insn_v2packh
, NULL
}, /* v2packh */
3100 { CODE_FOR_insn_v2packl
, NULL
}, /* v2packl */
3101 { CODE_FOR_insn_v2packuc
, NULL
}, /* v2packuc */
3102 { CODE_FOR_insn_v2sadas
, NULL
}, /* v2sadas */
3103 { CODE_FOR_insn_v2sadau
, NULL
}, /* v2sadau */
3104 { CODE_FOR_insn_v2sads
, NULL
}, /* v2sads */
3105 { CODE_FOR_insn_v2sadu
, NULL
}, /* v2sadu */
3106 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shl */
3107 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shli */
3108 { CODE_FOR_insn_v2shlsc
, NULL
}, /* v2shlsc */
3109 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrs */
3110 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrsi */
3111 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shru */
3112 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shrui */
3113 { CODE_FOR_insn_v2sub
, NULL
}, /* v2sub */
3114 { CODE_FOR_insn_v2subsc
, NULL
}, /* v2subsc */
3115 { CODE_FOR_insn_v4add
, NULL
}, /* v4add */
3116 { CODE_FOR_insn_v4addsc
, NULL
}, /* v4addsc */
3117 { CODE_FOR_insn_v4int_h
, NULL
}, /* v4int_h */
3118 { CODE_FOR_insn_v4int_l
, NULL
}, /* v4int_l */
3119 { CODE_FOR_insn_v4packsc
, NULL
}, /* v4packsc */
3120 { CODE_FOR_insn_v4shl
, NULL
}, /* v4shl */
3121 { CODE_FOR_insn_v4shlsc
, NULL
}, /* v4shlsc */
3122 { CODE_FOR_insn_v4shrs
, NULL
}, /* v4shrs */
3123 { CODE_FOR_insn_v4shru
, NULL
}, /* v4shru */
3124 { CODE_FOR_insn_v4sub
, NULL
}, /* v4sub */
3125 { CODE_FOR_insn_v4subsc
, NULL
}, /* v4subsc */
3126 { CODE_FOR_insn_wh64
, NULL
}, /* wh64 */
3127 { CODE_FOR_xordi3
, NULL
}, /* xor */
3128 { CODE_FOR_tilegx_network_barrier
, NULL
}, /* network_barrier */
3129 { CODE_FOR_tilegx_idn0_receive
, NULL
}, /* idn0_receive */
3130 { CODE_FOR_tilegx_idn1_receive
, NULL
}, /* idn1_receive */
3131 { CODE_FOR_tilegx_idn_send
, NULL
}, /* idn_send */
3132 { CODE_FOR_tilegx_udn0_receive
, NULL
}, /* udn0_receive */
3133 { CODE_FOR_tilegx_udn1_receive
, NULL
}, /* udn1_receive */
3134 { CODE_FOR_tilegx_udn2_receive
, NULL
}, /* udn2_receive */
3135 { CODE_FOR_tilegx_udn3_receive
, NULL
}, /* udn3_receive */
3136 { CODE_FOR_tilegx_udn_send
, NULL
}, /* udn_send */
3140 struct tilegx_builtin_def
3143 enum tilegx_builtin code
;
3145 /* The first character is the return type. Subsequent characters
3146 are the argument types. See char_to_type. */
3151 static const struct tilegx_builtin_def tilegx_builtins
[] = {
3152 { "__insn_add", TILEGX_INSN_ADD
, true, "lll" },
3153 { "__insn_addi", TILEGX_INSN_ADD
, true, "lll" },
3154 { "__insn_addli", TILEGX_INSN_ADD
, true, "lll" },
3155 { "__insn_addx", TILEGX_INSN_ADDX
, true, "iii" },
3156 { "__insn_addxi", TILEGX_INSN_ADDX
, true, "iii" },
3157 { "__insn_addxli", TILEGX_INSN_ADDX
, true, "iii" },
3158 { "__insn_addxsc", TILEGX_INSN_ADDXSC
, true, "iii" },
3159 { "__insn_and", TILEGX_INSN_AND
, true, "lll" },
3160 { "__insn_andi", TILEGX_INSN_AND
, true, "lll" },
3161 { "__insn_bfexts", TILEGX_INSN_BFEXTS
, true, "llll" },
3162 { "__insn_bfextu", TILEGX_INSN_BFEXTU
, true, "llll" },
3163 { "__insn_bfins", TILEGX_INSN_BFINS
, true, "lllll"},
3164 { "__insn_clz", TILEGX_INSN_CLZ
, true, "ll" },
3165 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ
, true, "llll" },
3166 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ
, true, "llll" },
3167 { "__insn_cmpeq", TILEGX_INSN_CMPEQ
, true, "lll" },
3168 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ
, true, "lll" },
3169 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH
, false, "lpl" },
3170 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4
, false, "ipi" },
3171 { "__insn_cmples", TILEGX_INSN_CMPLES
, true, "lll" },
3172 { "__insn_cmpleu", TILEGX_INSN_CMPLEU
, true, "lll" },
3173 { "__insn_cmplts", TILEGX_INSN_CMPLTS
, true, "lll" },
3174 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS
, true, "lll" },
3175 { "__insn_cmpltu", TILEGX_INSN_CMPLTU
, true, "lll" },
3176 { "__insn_cmpltui", TILEGX_INSN_CMPLTU
, true, "lll" },
3177 { "__insn_cmpne", TILEGX_INSN_CMPNE
, true, "lll" },
3178 { "__insn_cmul", TILEGX_INSN_CMUL
, true, "lll" },
3179 { "__insn_cmula", TILEGX_INSN_CMULA
, true, "llll" },
3180 { "__insn_cmulaf", TILEGX_INSN_CMULAF
, true, "llll" },
3181 { "__insn_cmulf", TILEGX_INSN_CMULF
, true, "lll" },
3182 { "__insn_cmulfr", TILEGX_INSN_CMULFR
, true, "lll" },
3183 { "__insn_cmulh", TILEGX_INSN_CMULH
, true, "lll" },
3184 { "__insn_cmulhr", TILEGX_INSN_CMULHR
, true, "lll" },
3185 { "__insn_crc32_32", TILEGX_INSN_CRC32_32
, true, "lll" },
3186 { "__insn_crc32_8", TILEGX_INSN_CRC32_8
, true, "lll" },
3187 { "__insn_ctz", TILEGX_INSN_CTZ
, true, "ll" },
3188 { "__insn_dblalign", TILEGX_INSN_DBLALIGN
, true, "lllk" },
3189 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2
, true, "lll" },
3190 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4
, true, "lll" },
3191 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6
, true, "lll" },
3192 { "__insn_drain", TILEGX_INSN_DRAIN
, false, "v" },
3193 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR
, false, "vl" },
3194 { "__insn_exch", TILEGX_INSN_EXCH
, false, "lpl" },
3195 { "__insn_exch4", TILEGX_INSN_EXCH4
, false, "ipi" },
3196 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS
, true, "lll" },
3197 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB
, true, "llll" },
3198 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS
, true, "lll" },
3199 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1
, true, "lll" },
3200 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2
, true, "llll" },
3201 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS
, true, "lll" },
3202 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX
, true, "lll" },
3203 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN
, true, "lll" },
3204 { "__insn_fetchadd", TILEGX_INSN_FETCHADD
, false, "lpl" },
3205 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4
, false, "ipi" },
3206 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ
, false, "lpl" },
3207 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4
, false, "ipi" },
3208 { "__insn_fetchand", TILEGX_INSN_FETCHAND
, false, "lpl" },
3209 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4
, false, "ipi" },
3210 { "__insn_fetchor", TILEGX_INSN_FETCHOR
, false, "lpl" },
3211 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4
, false, "ipi" },
3212 { "__insn_finv", TILEGX_INSN_FINV
, false, "vk" },
3213 { "__insn_flush", TILEGX_INSN_FLUSH
, false, "vk" },
3214 { "__insn_flushwb", TILEGX_INSN_FLUSHWB
, false, "v" },
3215 { "__insn_fnop", TILEGX_INSN_FNOP
, false, "v" },
3216 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1
, true, "lll" },
3217 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2
, true, "llll" },
3218 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1
, true, "lll" },
3219 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2
, true, "lll" },
3220 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1
, true, "ll" },
3221 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2
, true, "lll" },
3222 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1
, true, "lll" },
3223 { "__insn_icoh", TILEGX_INSN_ICOH
, false, "vk" },
3224 { "__insn_ill", TILEGX_INSN_ILL
, false, "v" },
3225 { "__insn_info", TILEGX_INSN_INFO
, false, "vl" },
3226 { "__insn_infol", TILEGX_INSN_INFOL
, false, "vl" },
3227 { "__insn_inv", TILEGX_INSN_INV
, false, "vp" },
3228 { "__insn_ld", TILEGX_INSN_LD
, false, "lk" },
3229 { "__insn_ld1s", TILEGX_INSN_LD1S
, false, "lk" },
3230 { "__insn_ld1u", TILEGX_INSN_LD1U
, false, "lk" },
3231 { "__insn_ld2s", TILEGX_INSN_LD2S
, false, "lk" },
3232 { "__insn_ld2u", TILEGX_INSN_LD2U
, false, "lk" },
3233 { "__insn_ld4s", TILEGX_INSN_LD4S
, false, "lk" },
3234 { "__insn_ld4u", TILEGX_INSN_LD4U
, false, "lk" },
3235 { "__insn_ldna", TILEGX_INSN_LDNA
, false, "lk" },
3236 { "__insn_ldnt", TILEGX_INSN_LDNT
, false, "lk" },
3237 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S
, false, "lk" },
3238 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U
, false, "lk" },
3239 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S
, false, "lk" },
3240 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U
, false, "lk" },
3241 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S
, false, "lk" },
3242 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U
, false, "lk" },
3243 { "__insn_ld_L2", TILEGX_INSN_LD_L2
, false, "lk" },
3244 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2
, false, "lk" },
3245 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2
, false, "lk" },
3246 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2
, false, "lk" },
3247 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2
, false, "lk" },
3248 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2
, false, "lk" },
3249 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2
, false, "lk" },
3250 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2
, false, "lk" },
3251 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2
, false, "lk" },
3252 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2
, false, "lk" },
3253 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2
, false, "lk" },
3254 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2
, false, "lk" },
3255 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2
, false, "lk" },
3256 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2
, false, "lk" },
3257 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2
, false, "lk" },
3258 { "__insn_ld_miss", TILEGX_INSN_LD_MISS
, false, "lk" },
3259 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS
, false, "lk" },
3260 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS
, false, "lk" },
3261 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS
, false, "lk" },
3262 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS
, false, "lk" },
3263 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS
, false, "lk" },
3264 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS
, false, "lk" },
3265 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS
, false, "lk" },
3266 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS
, false, "lk" },
3267 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS
, false, "lk" },
3268 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS
, false, "lk" },
3269 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS
, false, "lk" },
3270 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS
, false, "lk" },
3271 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS
, false, "lk" },
3272 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS
, false, "lk" },
3273 { "__insn_lnk", TILEGX_INSN_LNK
, true, "l" },
3274 { "__insn_mf", TILEGX_INSN_MF
, false, "v" },
3275 { "__insn_mfspr", TILEGX_INSN_MFSPR
, false, "ll" },
3276 { "__insn_mm", TILEGX_INSN_MM
, true, "lllll"},
3277 { "__insn_mnz", TILEGX_INSN_MNZ
, true, "lll" },
3278 { "__insn_move", TILEGX_INSN_MOVE
, true, "ll" },
3279 { "__insn_movei", TILEGX_INSN_MOVE
, true, "ll" },
3280 { "__insn_moveli", TILEGX_INSN_MOVE
, true, "ll" },
3281 { "__insn_mtspr", TILEGX_INSN_MTSPR
, false, "vll" },
3282 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS
, true, "lll" },
3283 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU
, true, "lll" },
3284 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS
, true, "lll" },
3285 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU
, true, "lll" },
3286 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU
, true, "lll" },
3287 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS
, true, "lll" },
3288 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU
, true, "lll" },
3289 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS
, true, "lll" },
3290 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU
, true, "lll" },
3291 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU
, true, "lll" },
3292 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS
, true, "llll" },
3293 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU
, true, "llll" },
3294 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS
, true, "llll" },
3295 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU
, true, "llll" },
3296 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU
, true, "llll" },
3297 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS
, true, "llll" },
3298 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU
, true, "llll" },
3299 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS
, true, "llll" },
3300 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU
, true, "llll" },
3301 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU
, true, "llll" },
3302 { "__insn_mulax", TILEGX_INSN_MULAX
, true, "iiii" },
3303 { "__insn_mulx", TILEGX_INSN_MULX
, true, "iii" },
3304 { "__insn_mz", TILEGX_INSN_MZ
, true, "lll" },
3305 { "__insn_nap", TILEGX_INSN_NAP
, false, "v" },
3306 { "__insn_nop", TILEGX_INSN_NOP
, true, "v" },
3307 { "__insn_nor", TILEGX_INSN_NOR
, true, "lll" },
3308 { "__insn_or", TILEGX_INSN_OR
, true, "lll" },
3309 { "__insn_ori", TILEGX_INSN_OR
, true, "lll" },
3310 { "__insn_pcnt", TILEGX_INSN_PCNT
, true, "ll" },
3311 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3312 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3313 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT
, false, "vk" },
3314 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2
, false, "vk" },
3315 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT
, false, "vk" },
3316 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3
, false, "vk" },
3317 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT
, false, "vk" },
3318 { "__insn_revbits", TILEGX_INSN_REVBITS
, true, "ll" },
3319 { "__insn_revbytes", TILEGX_INSN_REVBYTES
, true, "ll" },
3320 { "__insn_rotl", TILEGX_INSN_ROTL
, true, "lli" },
3321 { "__insn_rotli", TILEGX_INSN_ROTL
, true, "lli" },
3322 { "__insn_shl", TILEGX_INSN_SHL
, true, "lli" },
3323 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI
, true, "lll" },
3324 { "__insn_shl1add", TILEGX_INSN_SHL1ADD
, true, "lll" },
3325 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX
, true, "iii" },
3326 { "__insn_shl2add", TILEGX_INSN_SHL2ADD
, true, "lll" },
3327 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX
, true, "iii" },
3328 { "__insn_shl3add", TILEGX_INSN_SHL3ADD
, true, "lll" },
3329 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX
, true, "iii" },
3330 { "__insn_shli", TILEGX_INSN_SHL
, true, "lli" },
3331 { "__insn_shlx", TILEGX_INSN_SHLX
, true, "iii" },
3332 { "__insn_shlxi", TILEGX_INSN_SHLX
, true, "iii" },
3333 { "__insn_shrs", TILEGX_INSN_SHRS
, true, "lli" },
3334 { "__insn_shrsi", TILEGX_INSN_SHRS
, true, "lli" },
3335 { "__insn_shru", TILEGX_INSN_SHRU
, true, "lli" },
3336 { "__insn_shrui", TILEGX_INSN_SHRU
, true, "lli" },
3337 { "__insn_shrux", TILEGX_INSN_SHRUX
, true, "iii" },
3338 { "__insn_shruxi", TILEGX_INSN_SHRUX
, true, "iii" },
3339 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES
, true, "llll" },
3340 { "__insn_shufflebytes1", TILEGX_INSN_SHUFFLEBYTES1
, true, "lll" },
3341 { "__insn_st", TILEGX_INSN_ST
, false, "vpl" },
3342 { "__insn_st1", TILEGX_INSN_ST1
, false, "vpl" },
3343 { "__insn_st2", TILEGX_INSN_ST2
, false, "vpl" },
3344 { "__insn_st4", TILEGX_INSN_ST4
, false, "vpl" },
3345 { "__insn_stnt", TILEGX_INSN_STNT
, false, "vpl" },
3346 { "__insn_stnt1", TILEGX_INSN_STNT1
, false, "vpl" },
3347 { "__insn_stnt2", TILEGX_INSN_STNT2
, false, "vpl" },
3348 { "__insn_stnt4", TILEGX_INSN_STNT4
, false, "vpl" },
3349 { "__insn_sub", TILEGX_INSN_SUB
, true, "lll" },
3350 { "__insn_subx", TILEGX_INSN_SUBX
, true, "iii" },
3351 { "__insn_subxsc", TILEGX_INSN_SUBXSC
, true, "iii" },
3352 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0
, true, "lll" },
3353 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1
, true, "lll" },
3354 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2
, true, "lll" },
3355 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3
, true, "lll" },
3356 { "__insn_v1add", TILEGX_INSN_V1ADD
, true, "lll" },
3357 { "__insn_v1addi", TILEGX_INSN_V1ADDI
, true, "lll" },
3358 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC
, true, "lll" },
3359 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU
, true, "lll" },
3360 { "__insn_v1avgu", TILEGX_INSN_V1AVGU
, true, "lll" },
3361 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ
, true, "lll" },
3362 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI
, true, "lll" },
3363 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES
, true, "lll" },
3364 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU
, true, "lll" },
3365 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS
, true, "lll" },
3366 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI
, true, "lll" },
3367 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU
, true, "lll" },
3368 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI
, true, "lll" },
3369 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE
, true, "lll" },
3370 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU
, true, "lll" },
3371 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA
, true, "llll" },
3372 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS
, true, "lll" },
3373 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA
, true, "llll" },
3374 { "__insn_v1dotp", TILEGX_INSN_V1DOTP
, true, "lll" },
3375 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA
, true, "llll" },
3376 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU
, true, "lll" },
3377 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA
, true, "llll" },
3378 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS
, true, "lll" },
3379 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA
, true, "llll" },
3380 { "__insn_v1int_h", TILEGX_INSN_V1INT_H
, true, "lll" },
3381 { "__insn_v1int_l", TILEGX_INSN_V1INT_L
, true, "lll" },
3382 { "__insn_v1maxu", TILEGX_INSN_V1MAXU
, true, "lll" },
3383 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI
, true, "lll" },
3384 { "__insn_v1minu", TILEGX_INSN_V1MINU
, true, "lll" },
3385 { "__insn_v1minui", TILEGX_INSN_V1MINUI
, true, "lll" },
3386 { "__insn_v1mnz", TILEGX_INSN_V1MNZ
, true, "lll" },
3387 { "__insn_v1multu", TILEGX_INSN_V1MULTU
, true, "lll" },
3388 { "__insn_v1mulu", TILEGX_INSN_V1MULU
, true, "lll" },
3389 { "__insn_v1mulus", TILEGX_INSN_V1MULUS
, true, "lll" },
3390 { "__insn_v1mz", TILEGX_INSN_V1MZ
, true, "lll" },
3391 { "__insn_v1sadau", TILEGX_INSN_V1SADAU
, true, "llll" },
3392 { "__insn_v1sadu", TILEGX_INSN_V1SADU
, true, "lll" },
3393 { "__insn_v1shl", TILEGX_INSN_V1SHL
, true, "lll" },
3394 { "__insn_v1shli", TILEGX_INSN_V1SHLI
, true, "lll" },
3395 { "__insn_v1shrs", TILEGX_INSN_V1SHRS
, true, "lll" },
3396 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI
, true, "lll" },
3397 { "__insn_v1shru", TILEGX_INSN_V1SHRU
, true, "lll" },
3398 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI
, true, "lll" },
3399 { "__insn_v1sub", TILEGX_INSN_V1SUB
, true, "lll" },
3400 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC
, true, "lll" },
3401 { "__insn_v2add", TILEGX_INSN_V2ADD
, true, "lll" },
3402 { "__insn_v2addi", TILEGX_INSN_V2ADDI
, true, "lll" },
3403 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC
, true, "lll" },
3404 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS
, true, "lll" },
3405 { "__insn_v2avgs", TILEGX_INSN_V2AVGS
, true, "lll" },
3406 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ
, true, "lll" },
3407 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI
, true, "lll" },
3408 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES
, true, "lll" },
3409 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU
, true, "lll" },
3410 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS
, true, "lll" },
3411 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI
, true, "lll" },
3412 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU
, true, "lll" },
3413 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI
, true, "lll" },
3414 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE
, true, "lll" },
3415 { "__insn_v2dotp", TILEGX_INSN_V2DOTP
, true, "lll" },
3416 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA
, true, "llll" },
3417 { "__insn_v2int_h", TILEGX_INSN_V2INT_H
, true, "lll" },
3418 { "__insn_v2int_l", TILEGX_INSN_V2INT_L
, true, "lll" },
3419 { "__insn_v2maxs", TILEGX_INSN_V2MAXS
, true, "lll" },
3420 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI
, true, "lll" },
3421 { "__insn_v2mins", TILEGX_INSN_V2MINS
, true, "lll" },
3422 { "__insn_v2minsi", TILEGX_INSN_V2MINSI
, true, "lll" },
3423 { "__insn_v2mnz", TILEGX_INSN_V2MNZ
, true, "lll" },
3424 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC
, true, "lll" },
3425 { "__insn_v2muls", TILEGX_INSN_V2MULS
, true, "lll" },
3426 { "__insn_v2mults", TILEGX_INSN_V2MULTS
, true, "lll" },
3427 { "__insn_v2mz", TILEGX_INSN_V2MZ
, true, "lll" },
3428 { "__insn_v2packh", TILEGX_INSN_V2PACKH
, true, "lll" },
3429 { "__insn_v2packl", TILEGX_INSN_V2PACKL
, true, "lll" },
3430 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC
, true, "lll" },
3431 { "__insn_v2sadas", TILEGX_INSN_V2SADAS
, true, "llll" },
3432 { "__insn_v2sadau", TILEGX_INSN_V2SADAU
, true, "llll" },
3433 { "__insn_v2sads", TILEGX_INSN_V2SADS
, true, "lll" },
3434 { "__insn_v2sadu", TILEGX_INSN_V2SADU
, true, "lll" },
3435 { "__insn_v2shl", TILEGX_INSN_V2SHL
, true, "lll" },
3436 { "__insn_v2shli", TILEGX_INSN_V2SHLI
, true, "lll" },
3437 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC
, true, "lll" },
3438 { "__insn_v2shrs", TILEGX_INSN_V2SHRS
, true, "lll" },
3439 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI
, true, "lll" },
3440 { "__insn_v2shru", TILEGX_INSN_V2SHRU
, true, "lll" },
3441 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI
, true, "lll" },
3442 { "__insn_v2sub", TILEGX_INSN_V2SUB
, true, "lll" },
3443 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC
, true, "lll" },
3444 { "__insn_v4add", TILEGX_INSN_V4ADD
, true, "lll" },
3445 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC
, true, "lll" },
3446 { "__insn_v4int_h", TILEGX_INSN_V4INT_H
, true, "lll" },
3447 { "__insn_v4int_l", TILEGX_INSN_V4INT_L
, true, "lll" },
3448 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC
, true, "lll" },
3449 { "__insn_v4shl", TILEGX_INSN_V4SHL
, true, "lll" },
3450 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC
, true, "lll" },
3451 { "__insn_v4shrs", TILEGX_INSN_V4SHRS
, true, "lll" },
3452 { "__insn_v4shru", TILEGX_INSN_V4SHRU
, true, "lll" },
3453 { "__insn_v4sub", TILEGX_INSN_V4SUB
, true, "lll" },
3454 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC
, true, "lll" },
3455 { "__insn_wh64", TILEGX_INSN_WH64
, false, "vp" },
3456 { "__insn_xor", TILEGX_INSN_XOR
, true, "lll" },
3457 { "__insn_xori", TILEGX_INSN_XOR
, true, "lll" },
3458 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER
, false, "v" },
3459 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE
, false, "l" },
3460 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE
, false, "l" },
3461 { "__tile_idn_send", TILEGX_IDN_SEND
, false, "vl" },
3462 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE
, false, "l" },
3463 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE
, false, "l" },
3464 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE
, false, "l" },
3465 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE
, false, "l" },
3466 { "__tile_udn_send", TILEGX_UDN_SEND
, false, "vl" },
3470 /* Convert a character in a builtin type string to a tree type. */
3472 char_to_type (char c
)
3474 static tree volatile_ptr_type_node
= NULL
;
3475 static tree volatile_const_ptr_type_node
= NULL
;
3477 if (volatile_ptr_type_node
== NULL
)
3479 volatile_ptr_type_node
=
3480 build_pointer_type (build_qualified_type (void_type_node
,
3481 TYPE_QUAL_VOLATILE
));
3482 volatile_const_ptr_type_node
=
3483 build_pointer_type (build_qualified_type (void_type_node
,
3485 | TYPE_QUAL_VOLATILE
));
3491 return void_type_node
;
3493 return unsigned_type_node
;
3495 return long_long_unsigned_type_node
;
3497 return volatile_ptr_type_node
;
3499 return volatile_const_ptr_type_node
;
3506 /* Implement TARGET_INIT_BUILTINS. */
3508 tilegx_init_builtins (void)
3512 for (i
= 0; i
< ARRAY_SIZE (tilegx_builtins
); i
++)
3514 const struct tilegx_builtin_def
*p
= &tilegx_builtins
[i
];
3515 tree ftype
, ret_type
, arg_type_list
= void_list_node
;
3519 for (j
= strlen (p
->type
) - 1; j
> 0; j
--)
3522 tree_cons (NULL_TREE
, char_to_type (p
->type
[j
]), arg_type_list
);
3525 ret_type
= char_to_type (p
->type
[0]);
3527 ftype
= build_function_type (ret_type
, arg_type_list
);
3529 decl
= add_builtin_function (p
->name
, ftype
, p
->code
, BUILT_IN_MD
,
3533 TREE_READONLY (decl
) = 1;
3534 TREE_NOTHROW (decl
) = 1;
3536 if (tilegx_builtin_info
[p
->code
].fndecl
== NULL
)
3537 tilegx_builtin_info
[p
->code
].fndecl
= decl
;
3542 /* Implement TARGET_EXPAND_BUILTIN. */
3544 tilegx_expand_builtin (tree exp
,
3546 rtx subtarget ATTRIBUTE_UNUSED
,
3547 machine_mode mode ATTRIBUTE_UNUSED
,
3548 int ignore ATTRIBUTE_UNUSED
)
3550 #define MAX_BUILTIN_ARGS 4
3552 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
3553 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
3555 call_expr_arg_iterator iter
;
3556 enum insn_code icode
;
3557 rtx op
[MAX_BUILTIN_ARGS
+ 1], pat
;
3562 if (fcode
>= TILEGX_BUILTIN_max
)
3563 internal_error ("bad builtin fcode");
3564 icode
= tilegx_builtin_info
[fcode
].icode
;
3566 internal_error ("bad builtin icode");
3568 nonvoid
= TREE_TYPE (TREE_TYPE (fndecl
)) != void_type_node
;
3571 FOR_EACH_CALL_EXPR_ARG (arg
, iter
, exp
)
3573 const struct insn_operand_data
*insn_op
;
3575 if (arg
== error_mark_node
)
3577 if (opnum
> MAX_BUILTIN_ARGS
)
3580 insn_op
= &insn_data
[icode
].operand
[opnum
];
3582 op
[opnum
] = expand_expr (arg
, NULL_RTX
, insn_op
->mode
, EXPAND_NORMAL
);
3584 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3586 machine_mode opmode
= insn_op
->mode
;
3588 /* pointer_operand and pmode_register_operand operands do
3589 not specify a mode, so use the operand's mode instead
3590 (which should always be right by the time we get here,
3591 except for constants, which are VOIDmode). */
3592 if (opmode
== VOIDmode
)
3594 machine_mode m
= GET_MODE (op
[opnum
]);
3595 gcc_assert (m
== Pmode
|| m
== VOIDmode
);
3599 op
[opnum
] = copy_to_mode_reg (opmode
, op
[opnum
]);
3602 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3604 /* We still failed to meet the predicate even after moving
3605 into a register. Assume we needed an immediate. */
3606 error_at (EXPR_LOCATION (exp
),
3607 "operand must be an immediate of the right size");
3616 machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
3618 || GET_MODE (target
) != tmode
3619 || !(*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
3621 if (tmode
== VOIDmode
)
3623 /* get the mode from the return type. */
3624 tmode
= TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl
)));
3626 target
= gen_reg_rtx (tmode
);
3631 fn
= GEN_FCN (icode
);
3635 pat
= fn (NULL_RTX
);
3641 pat
= fn (op
[0], op
[1]);
3644 pat
= fn (op
[0], op
[1], op
[2]);
3647 pat
= fn (op
[0], op
[1], op
[2], op
[3]);
3650 pat
= fn (op
[0], op
[1], op
[2], op
[3], op
[4]);
3658 /* If we are generating a prefetch, tell the scheduler not to move
3660 if (GET_CODE (pat
) == PREFETCH
)
3661 PREFETCH_SCHEDULE_BARRIER_P (pat
) = true;
3672 /* Implement TARGET_BUILTIN_DECL. */
3674 tilegx_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
3676 if (code
>= TILEGX_BUILTIN_max
)
3677 return error_mark_node
;
3679 return tilegx_builtin_info
[code
].fndecl
;
3686 /* Return whether REGNO needs to be saved in the stack frame. */
3688 need_to_save_reg (unsigned int regno
)
3690 if (!fixed_regs
[regno
] && !call_used_regs
[regno
]
3691 && df_regs_ever_live_p (regno
))
3695 && (regno
== PIC_OFFSET_TABLE_REGNUM
3696 || regno
== TILEGX_PIC_TEXT_LABEL_REGNUM
)
3697 && (crtl
->uses_pic_offset_table
|| crtl
->saves_all_registers
))
3700 if (crtl
->calls_eh_return
)
3703 for (i
= 0; EH_RETURN_DATA_REGNO (i
) != INVALID_REGNUM
; i
++)
3705 if (regno
== EH_RETURN_DATA_REGNO (i
))
3714 /* Return the size of the register savev area. This function is only
3715 correct starting with local register allocation */
3717 tilegx_saved_regs_size (void)
3719 int reg_save_size
= 0;
3721 int offset_to_frame
;
3724 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
3725 if (need_to_save_reg (regno
))
3726 reg_save_size
+= UNITS_PER_WORD
;
3728 /* Pad out the register save area if necessary to make
3729 frame_pointer_rtx be as aligned as the stack pointer. */
3730 offset_to_frame
= crtl
->args
.pretend_args_size
+ reg_save_size
;
3731 align_mask
= (STACK_BOUNDARY
/ BITS_PER_UNIT
) - 1;
3732 reg_save_size
+= (-offset_to_frame
) & align_mask
;
3734 return reg_save_size
;
3738 /* Round up frame size SIZE. */
3740 round_frame_size (int size
)
3742 return ((size
+ STACK_BOUNDARY
/ BITS_PER_UNIT
- 1)
3743 & -STACK_BOUNDARY
/ BITS_PER_UNIT
);
3747 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3748 emit the corresponding REG_CFA_OFFSET note described by CFA and
3749 CFA_OFFSET. Return the emitted insn. */
3751 frame_emit_store (int regno
, int regno_note
, rtx addr
, rtx cfa
,
3754 rtx reg
= gen_rtx_REG (DImode
, regno
);
3755 rtx mem
= gen_frame_mem (DImode
, addr
);
3756 rtx mov
= gen_movdi (mem
, reg
);
3758 /* Describe what just happened in a way that dwarf understands. We
3759 use temporary registers to hold the address to make scheduling
3760 easier, and use the REG_CFA_OFFSET to describe the address as an
3761 offset from the CFA. */
3762 rtx reg_note
= gen_rtx_REG (DImode
, regno_note
);
3763 rtx cfa_relative_addr
= gen_rtx_PLUS (Pmode
, cfa
, GEN_INT (cfa_offset
));
3764 rtx cfa_relative_mem
= gen_frame_mem (DImode
, cfa_relative_addr
);
3765 rtx real
= gen_rtx_SET (VOIDmode
, cfa_relative_mem
, reg_note
);
3766 add_reg_note (mov
, REG_CFA_OFFSET
, real
);
3768 return emit_insn (mov
);
3772 /* Emit a load in the stack frame to load REGNO from address ADDR.
3773 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3774 non-null. Return the emitted insn. */
3776 frame_emit_load (int regno
, rtx addr
, rtx
*cfa_restores
)
3778 rtx reg
= gen_rtx_REG (DImode
, regno
);
3779 rtx mem
= gen_frame_mem (DImode
, addr
);
3781 *cfa_restores
= alloc_reg_note (REG_CFA_RESTORE
, reg
, *cfa_restores
);
3782 return emit_insn (gen_movdi (reg
, mem
));
3786 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3787 including sequences. */
3789 set_frame_related_p (void)
3791 rtx_insn
*seq
= get_insns ();
3802 while (insn
!= NULL_RTX
)
3804 RTX_FRAME_RELATED_P (insn
) = 1;
3805 insn
= NEXT_INSN (insn
);
3807 seq
= emit_insn (seq
);
3811 seq
= emit_insn (seq
);
3812 RTX_FRAME_RELATED_P (seq
) = 1;
3818 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3820 /* This emits code for 'sp += offset'.
3822 The ABI only allows us to modify 'sp' in a single 'addi' or
3823 'addli', so the backtracer understands it. Larger amounts cannot
3824 use those instructions, so are added by placing the offset into a
3825 large register and using 'add'.
3827 This happens after reload, so we need to expand it ourselves. */
3829 emit_sp_adjust (int offset
, int *next_scratch_regno
, bool frame_related
,
3833 rtx imm_rtx
= GEN_INT (offset
);
3837 if (satisfies_constraint_J (imm_rtx
))
3839 /* We can add this using a single immediate add. */
3844 rtx tmp
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3845 tilegx_expand_set_const64 (tmp
, imm_rtx
);
3849 /* Actually adjust the stack pointer. */
3851 pat
= gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3853 pat
= gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3855 insn
= emit_insn (pat
);
3856 REG_NOTES (insn
) = reg_notes
;
3858 /* Describe what just happened in a way that dwarf understands. */
3861 rtx real
= gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
3862 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3864 RTX_FRAME_RELATED_P (insn
) = 1;
3865 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, real
);
3872 /* Return whether the current function is leaf. This takes into
3873 account whether the function calls tls_get_addr. */
3875 tilegx_current_function_is_leaf (void)
3877 return crtl
->is_leaf
&& !cfun
->machine
->calls_tls_get_addr
;
3881 /* Return the frame size. */
3883 compute_total_frame_size (void)
3885 int total_size
= (get_frame_size () + tilegx_saved_regs_size ()
3886 + crtl
->outgoing_args_size
3887 + crtl
->args
.pretend_args_size
);
3889 if (!tilegx_current_function_is_leaf () || cfun
->calls_alloca
)
3891 /* Make room for save area in callee. */
3892 total_size
+= STACK_POINTER_OFFSET
;
3895 return round_frame_size (total_size
);
3899 /* Return nonzero if this function is known to have a null epilogue.
3900 This allows the optimizer to omit jumps to jumps if no stack was
3903 tilegx_can_use_return_insn_p (void)
3905 return (reload_completed
3906 && cfun
->static_chain_decl
== 0
3907 && compute_total_frame_size () == 0
3908 && tilegx_current_function_is_leaf ()
3909 && !crtl
->profile
&& !df_regs_ever_live_p (TILEGX_LINK_REGNUM
));
3913 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3914 is a frame pointer, it computes the value relative to
3915 that. Otherwise it uses the stack pointer. */
3917 compute_frame_addr (int offset_from_fp
, int *next_scratch_regno
)
3919 rtx base_reg_rtx
, tmp_reg_rtx
, offset_rtx
;
3920 int offset_from_base
;
3922 if (frame_pointer_needed
)
3924 base_reg_rtx
= hard_frame_pointer_rtx
;
3925 offset_from_base
= offset_from_fp
;
3929 int offset_from_sp
= compute_total_frame_size () + offset_from_fp
;
3930 offset_from_base
= offset_from_sp
;
3931 base_reg_rtx
= stack_pointer_rtx
;
3934 if (offset_from_base
== 0)
3935 return base_reg_rtx
;
3937 /* Compute the new value of the stack pointer. */
3938 tmp_reg_rtx
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3939 offset_rtx
= GEN_INT (offset_from_base
);
3941 if (!add_operand (offset_rtx
, Pmode
))
3943 expand_set_cint64 (tmp_reg_rtx
, offset_rtx
);
3944 offset_rtx
= tmp_reg_rtx
;
3947 emit_insn (gen_rtx_SET (VOIDmode
, tmp_reg_rtx
,
3948 gen_rtx_PLUS (Pmode
, base_reg_rtx
, offset_rtx
)));
3954 /* The stack frame looks like this:
3959 AP -> +-------------+
3963 HFP -> +-------------+
3965 | reg save | crtl->args.pretend_args_size bytes
3968 | saved regs | tilegx_saved_regs_size() bytes
3969 FP -> +-------------+
3971 | vars | get_frame_size() bytes
3975 | stack args | crtl->outgoing_args_size bytes
3977 | HFP | ptr_size bytes (only here if nonleaf / alloca)
3979 | callee lr | ptr_size bytes (only here if nonleaf / alloca)
3981 SP -> +-------------+
3985 For functions with a frame larger than 32767 bytes, or which use
3986 alloca (), r52 is used as a frame pointer. Otherwise there is no
3989 FP is saved at SP+ptr_size before calling a subroutine so the callee
3992 tilegx_expand_prologue (void)
3994 #define ROUND_ROBIN_SIZE 4
3995 /* We round-robin through four scratch registers to hold temporary
3996 addresses for saving registers, to make instruction scheduling
3998 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
3999 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
4002 unsigned int which_scratch
;
4003 int offset
, start_offset
, regno
;
4005 /* A register that holds a copy of the incoming fp. */
4006 int fp_copy_regno
= -1;
4008 /* A register that holds a copy of the incoming sp. */
4009 int sp_copy_regno
= -1;
4011 /* Next scratch register number to hand out (postdecrementing). */
4012 int next_scratch_regno
= 29;
4014 int total_size
= compute_total_frame_size ();
4016 if (flag_stack_usage_info
)
4017 current_function_static_stack_size
= total_size
;
4019 /* Save lr first in its special location because code after this
4020 might use the link register as a scratch register. */
4021 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
) || crtl
->calls_eh_return
)
4022 FRP (frame_emit_store (TILEGX_LINK_REGNUM
, TILEGX_LINK_REGNUM
,
4023 stack_pointer_rtx
, stack_pointer_rtx
, 0));
4025 if (total_size
== 0)
4027 /* Load the PIC register if needed. */
4028 if (flag_pic
&& crtl
->uses_pic_offset_table
)
4029 load_pic_register (false);
4034 cfa
= stack_pointer_rtx
;
4036 if (frame_pointer_needed
)
4038 fp_copy_regno
= next_scratch_regno
--;
4040 /* Copy the old frame pointer aside so we can save it later. */
4042 FRP (emit_move_insn (gen_rtx_REG (word_mode
, fp_copy_regno
),
4043 gen_lowpart (word_mode
, hard_frame_pointer_rtx
)));
4044 add_reg_note (insn
, REG_CFA_REGISTER
, NULL_RTX
);
4046 /* Set up the frame pointer. */
4047 insn
= FRP (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
4048 add_reg_note (insn
, REG_CFA_DEF_CFA
, hard_frame_pointer_rtx
);
4049 cfa
= hard_frame_pointer_rtx
;
4050 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM
) = STACK_BOUNDARY
;
4052 /* fp holds a copy of the incoming sp, in case we need to store
4054 sp_copy_regno
= HARD_FRAME_POINTER_REGNUM
;
4056 else if (!tilegx_current_function_is_leaf ())
4058 /* Copy the old stack pointer aside so we can save it later. */
4059 sp_copy_regno
= next_scratch_regno
--;
4060 emit_move_insn (gen_rtx_REG (Pmode
, sp_copy_regno
),
4064 if (tilegx_current_function_is_leaf ())
4066 /* No need to store chain pointer to caller's frame. */
4067 emit_sp_adjust (-total_size
, &next_scratch_regno
,
4068 !frame_pointer_needed
, NULL_RTX
);
4072 /* Save the frame pointer (incoming sp value) to support
4073 backtracing. First we need to create an rtx with the store
4075 rtx chain_addr
= gen_rtx_REG (Pmode
, next_scratch_regno
--);
4076 rtx size_rtx
= GEN_INT (-(total_size
- UNITS_PER_WORD
));
4078 if (add_operand (size_rtx
, Pmode
))
4080 /* Expose more parallelism by computing this value from the
4081 original stack pointer, not the one after we have pushed
4083 rtx p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, size_rtx
);
4084 emit_insn (gen_rtx_SET (VOIDmode
, chain_addr
, p
));
4085 emit_sp_adjust (-total_size
, &next_scratch_regno
,
4086 !frame_pointer_needed
, NULL_RTX
);
4090 /* The stack frame is large, so just store the incoming sp
4091 value at *(new_sp + UNITS_PER_WORD). */
4093 emit_sp_adjust (-total_size
, &next_scratch_regno
,
4094 !frame_pointer_needed
, NULL_RTX
);
4095 p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
4096 GEN_INT (UNITS_PER_WORD
));
4097 emit_insn (gen_rtx_SET (VOIDmode
, chain_addr
, p
));
4100 /* Save our frame pointer for backtrace chaining. */
4101 emit_insn (gen_movdi (gen_frame_mem (DImode
, chain_addr
),
4102 gen_rtx_REG (DImode
, sp_copy_regno
)));
4105 /* Compute where to start storing registers we need to save. */
4106 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
4107 offset
= start_offset
;
4109 /* Store all registers that need saving. */
4111 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
4112 if (need_to_save_reg (regno
))
4114 rtx r
= reg_save_addr
[which_scratch
];
4116 int cfa_offset
= frame_pointer_needed
? offset
: total_size
+ offset
;
4120 int prev_scratch_regno
= next_scratch_regno
;
4121 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4122 if (prev_scratch_regno
!= next_scratch_regno
)
4123 reg_save_addr
[which_scratch
] = r
;
4127 /* Advance to the next stack slot to store this
4129 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4130 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4131 emit_insn (gen_rtx_SET (VOIDmode
, r
, p
));
4134 /* Save this register to the stack (but use the old fp value
4135 we copied aside if appropriate). */
4137 (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4138 ? fp_copy_regno
: regno
;
4139 FRP (frame_emit_store (from_regno
, regno
, r
, cfa
, cfa_offset
));
4141 offset
-= UNITS_PER_WORD
;
4142 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4145 /* If profiling, force that to happen after the frame is set up. */
4147 emit_insn (gen_blockage ());
4149 /* Load the PIC register if needed. */
4150 if (flag_pic
&& crtl
->uses_pic_offset_table
)
4151 load_pic_register (false);
4155 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
4156 true for a sibcall_epilogue pattern, and false for an epilogue
4159 tilegx_expand_epilogue (bool sibcall_p
)
4161 /* We round-robin through four scratch registers to hold temporary
4162 addresses for saving registers, to make instruction scheduling
4164 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
4165 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
4167 rtx_insn
*last_insn
, *insn
;
4168 unsigned int which_scratch
;
4169 int offset
, start_offset
, regno
;
4170 rtx cfa_restores
= NULL_RTX
;
4172 /* A register that holds a copy of the incoming fp. */
4173 int fp_copy_regno
= -1;
4175 /* Next scratch register number to hand out (postdecrementing). */
4176 int next_scratch_regno
= 29;
4178 int total_size
= compute_total_frame_size ();
4180 last_insn
= get_last_insn ();
4182 /* Load lr first since we are going to need it first. */
4184 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
))
4186 insn
= frame_emit_load (TILEGX_LINK_REGNUM
,
4187 compute_frame_addr (0, &next_scratch_regno
),
4191 if (total_size
== 0)
4195 RTX_FRAME_RELATED_P (insn
) = 1;
4196 REG_NOTES (insn
) = cfa_restores
;
4201 /* Compute where to start restoring registers. */
4202 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
4203 offset
= start_offset
;
4205 if (frame_pointer_needed
)
4206 fp_copy_regno
= next_scratch_regno
--;
4208 /* Restore all callee-saved registers. */
4210 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
4211 if (need_to_save_reg (regno
))
4213 rtx r
= reg_save_addr
[which_scratch
];
4216 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4217 reg_save_addr
[which_scratch
] = r
;
4221 /* Advance to the next stack slot to store this register. */
4222 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4223 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4224 emit_insn (gen_rtx_SET (VOIDmode
, r
, p
));
4227 if (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4228 frame_emit_load (fp_copy_regno
, r
, NULL
);
4230 frame_emit_load (regno
, r
, &cfa_restores
);
4232 offset
-= UNITS_PER_WORD
;
4233 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4236 if (!tilegx_current_function_is_leaf ())
4238 alloc_reg_note (REG_CFA_RESTORE
, stack_pointer_rtx
, cfa_restores
);
4240 emit_insn (gen_blockage ());
4242 if (frame_pointer_needed
)
4244 /* Restore the old stack pointer by copying from the frame
4248 insn
= emit_insn (gen_sp_restore_32bit (stack_pointer_rtx
,
4249 hard_frame_pointer_rtx
));
4253 insn
= emit_insn (gen_sp_restore (stack_pointer_rtx
,
4254 hard_frame_pointer_rtx
));
4256 RTX_FRAME_RELATED_P (insn
) = 1;
4257 REG_NOTES (insn
) = cfa_restores
;
4258 add_reg_note (insn
, REG_CFA_DEF_CFA
, stack_pointer_rtx
);
4262 insn
= emit_sp_adjust (total_size
, &next_scratch_regno
, true,
4266 if (crtl
->calls_eh_return
)
4269 emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
,
4270 EH_RETURN_STACKADJ_RTX
));
4272 emit_insn (gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
,
4273 EH_RETURN_STACKADJ_RTX
));
4276 /* Restore the old frame pointer. */
4277 if (frame_pointer_needed
)
4279 insn
= emit_move_insn (gen_lowpart (DImode
, hard_frame_pointer_rtx
),
4280 gen_rtx_REG (DImode
, fp_copy_regno
));
4281 add_reg_note (insn
, REG_CFA_RESTORE
, hard_frame_pointer_rtx
);
4284 /* Mark the pic registers as live outside of the function. */
4287 emit_use (cfun
->machine
->text_label_rtx
);
4288 emit_use (cfun
->machine
->got_rtx
);
4294 emit_jump_insn (gen__return ());
4298 emit_use (gen_rtx_REG (Pmode
, TILEGX_LINK_REGNUM
));
4301 /* Mark all insns we just emitted as frame-related. */
4302 for (; last_insn
!= NULL_RTX
; last_insn
= next_insn (last_insn
))
4303 RTX_FRAME_RELATED_P (last_insn
) = 1;
4306 #undef ROUND_ROBIN_SIZE
4309 /* Implement INITIAL_ELIMINATION_OFFSET. */
4311 tilegx_initial_elimination_offset (int from
, int to
)
4313 int total_size
= compute_total_frame_size ();
4315 if (from
== FRAME_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4317 return (total_size
- crtl
->args
.pretend_args_size
4318 - tilegx_saved_regs_size ());
4320 else if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4322 return -(crtl
->args
.pretend_args_size
+ tilegx_saved_regs_size ());
4324 else if (from
== ARG_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4326 return STACK_POINTER_OFFSET
+ total_size
;
4328 else if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4330 return STACK_POINTER_OFFSET
;
4337 /* Return an RTX indicating where the return address to the calling
4338 function can be found. */
4340 tilegx_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
4345 return get_hard_reg_initial_val (Pmode
, TILEGX_LINK_REGNUM
);
4349 /* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to
4350 prevent it from being deleted. */
4352 tilegx_eh_return_handler_rtx (void)
4354 rtx tmp
= gen_frame_mem (Pmode
, hard_frame_pointer_rtx
);
4355 MEM_VOLATILE_P (tmp
) = true;
4363 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
4365 tilegx_conditional_register_usage (void)
4367 global_regs
[TILEGX_NETORDER_REGNUM
] = 1;
4368 /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
4369 member of fixed_regs, and therefore must be member of
4370 call_used_regs, but it is not a member of call_really_used_regs[]
4371 because it is not clobbered by a call. */
4372 if (TILEGX_PIC_TEXT_LABEL_REGNUM
!= INVALID_REGNUM
)
4374 fixed_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4375 call_used_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4377 if (PIC_OFFSET_TABLE_REGNUM
!= INVALID_REGNUM
)
4379 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4380 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4385 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
4387 tilegx_frame_pointer_required (void)
4389 return crtl
->calls_eh_return
|| cfun
->calls_alloca
;
4394 /* Scheduling and reorg */
4396 /* Return the length of INSN. LENGTH is the initial length computed
4397 by attributes in the machine-description file. This is where we
4398 account for bundles. */
4400 tilegx_adjust_insn_length (rtx_insn
*insn
, int length
)
4402 machine_mode mode
= GET_MODE (insn
);
4404 /* A non-termininating instruction in a bundle has length 0. */
4408 /* By default, there is not length adjustment. */
4413 /* Implement TARGET_SCHED_ISSUE_RATE. */
4415 tilegx_issue_rate (void)
4421 /* Return the rtx for the jump target. */
4423 get_jump_target (rtx branch
)
4425 if (CALL_P (branch
))
4428 call
= PATTERN (branch
);
4430 if (GET_CODE (call
) == PARALLEL
)
4431 call
= XVECEXP (call
, 0, 0);
4433 if (GET_CODE (call
) == SET
)
4434 call
= SET_SRC (call
);
4436 if (GET_CODE (call
) == CALL
)
4437 return XEXP (XEXP (call
, 0), 0);
4443 /* Implement TARGET_SCHED_ADJUST_COST. */
4445 tilegx_sched_adjust_cost (rtx_insn
*insn
, rtx link
, rtx_insn
*dep_insn
,
4448 /* If we have a true dependence, INSN is a call, and DEP_INSN
4449 defines a register that is needed by the call (argument or stack
4450 pointer) , set its latency to 0 so that it can be bundled with
4451 the call. Explicitly check for and exclude the case when
4452 DEP_INSN defines the target of the jump. */
4453 if (CALL_P (insn
) && REG_NOTE_KIND (link
) == REG_DEP_TRUE
)
4455 rtx target
= get_jump_target (insn
);
4456 if (!REG_P (target
) || !set_of (target
, dep_insn
))
4464 /* Skip over irrelevant NOTEs and such and look for the next insn we
4465 would consider bundling. */
4467 next_insn_to_bundle (rtx_insn
*r
, rtx_insn
*end
)
4469 for (; r
!= end
; r
= NEXT_INSN (r
))
4471 if (NONDEBUG_INSN_P (r
)
4472 && GET_CODE (PATTERN (r
)) != USE
4473 && GET_CODE (PATTERN (r
)) != CLOBBER
)
4481 /* Go through all insns, and use the information generated during
4482 scheduling to generate SEQUENCEs to represent bundles of
4483 instructions issued simultaneously. */
4485 tilegx_gen_bundles (void)
4488 FOR_EACH_BB_FN (bb
, cfun
)
4490 rtx_insn
*insn
, *next
, *prev
;
4491 rtx_insn
*end
= NEXT_INSN (BB_END (bb
));
4494 for (insn
= next_insn_to_bundle (BB_HEAD (bb
), end
); insn
;
4495 prev
= insn
, insn
= next
)
4497 next
= next_insn_to_bundle (NEXT_INSN (insn
), end
);
4499 /* Never wrap {} around inline asm. */
4500 if (GET_CODE (PATTERN (insn
)) != ASM_INPUT
)
4502 if (next
== NULL_RTX
|| GET_MODE (next
) == TImode
4503 /* NOTE: The scheduler incorrectly believes a call
4504 insn can execute in the same cycle as the insn
4505 after the call. This is of course impossible.
4506 Really we need to fix the scheduler somehow, so
4507 the code after the call gets scheduled
4511 /* Mark current insn as the end of a bundle. */
4512 PUT_MODE (insn
, QImode
);
4516 /* Mark it as part of a bundle. */
4517 PUT_MODE (insn
, SImode
);
4521 /* Delete barrier insns, because they can mess up the
4522 emitting of bundle braces. If it is end-of-bundle, then
4523 the previous insn must be marked end-of-bundle. */
4524 if (get_attr_type (insn
) == TYPE_NOTHING
) {
4525 if (GET_MODE (insn
) == QImode
&& prev
!= NULL
4526 && GET_MODE (prev
) == SImode
)
4528 PUT_MODE (prev
, QImode
);
4537 /* Replace OLD_INSN with NEW_INSN. */
4539 replace_insns (rtx_insn
*old_insn
, rtx_insn
*new_insns
)
4542 emit_insn_before (new_insns
, old_insn
);
4544 delete_insn (old_insn
);
4548 /* Returns true if INSN is the first instruction of a pc-relative
4549 address compuatation. */
4551 match_pcrel_step1 (rtx insn
)
4553 rtx pattern
= PATTERN (insn
);
4556 if (GET_CODE (pattern
) != SET
)
4559 src
= SET_SRC (pattern
);
4561 return (GET_CODE (src
) == CONST
4562 && GET_CODE (XEXP (src
, 0)) == UNSPEC
4563 && XINT (XEXP (src
, 0), 1) == UNSPEC_HW1_LAST_PCREL
);
4567 /* Do the first replacement step in tilegx_fixup_pcrel_references. */
4569 replace_mov_pcrel_step1 (rtx_insn
*insn
)
4571 rtx pattern
= PATTERN (insn
);
4574 rtx_insn
*new_insns
;
4576 gcc_assert (GET_CODE (pattern
) == SET
);
4577 opnds
[0] = SET_DEST (pattern
);
4579 gcc_assert (GET_CODE (SET_SRC (pattern
)) == CONST
);
4581 unspec
= XEXP (SET_SRC (pattern
), 0);
4582 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4583 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW1_LAST_PCREL
);
4584 opnds
[1] = XVECEXP (unspec
, 0, 0);
4586 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4587 if (GET_CODE (opnds
[1]) != SYMBOL_REF
)
4595 emit_insn (gen_mov_got32_step1_32bit (opnds
[0], opnds
[1]));
4597 emit_insn (gen_mov_got32_step1 (opnds
[0], opnds
[1]));
4600 new_insns
= get_insns ();
4603 replace_insns (insn
, new_insns
);
4607 /* Returns true if INSN is the second instruction of a pc-relative
4608 address compuatation. */
4610 match_pcrel_step2 (rtx_insn
*insn
)
4617 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli_32bit
)
4622 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli
)
4626 unspec
= SET_SRC (PATTERN (insn
));
4627 addr
= XVECEXP (unspec
, 0, 1);
4629 return (GET_CODE (addr
) == CONST
4630 && GET_CODE (XEXP (addr
, 0)) == UNSPEC
4631 && XINT (XEXP (addr
, 0), 1) == UNSPEC_HW0_PCREL
);
4635 /* Do the second replacement step in tilegx_fixup_pcrel_references. */
4637 replace_mov_pcrel_step2 (rtx_insn
*insn
)
4639 rtx pattern
= PATTERN (insn
);
4643 rtx_insn
*new_insns
;
4644 rtx got_rtx
= tilegx_got_rtx ();
4646 gcc_assert (GET_CODE (pattern
) == SET
);
4647 opnds
[0] = SET_DEST (pattern
);
4649 unspec
= SET_SRC (pattern
);
4650 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4651 gcc_assert (XINT (unspec
, 1) == UNSPEC_INSN_ADDR_SHL16INSLI
);
4653 opnds
[1] = XVECEXP (unspec
, 0, 0);
4655 addr
= XVECEXP (unspec
, 0, 1);
4656 gcc_assert (GET_CODE (addr
) == CONST
);
4658 unspec
= XEXP (addr
, 0);
4659 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4660 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW0_PCREL
);
4661 opnds
[2] = XVECEXP (unspec
, 0, 0);
4663 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4664 if (GET_CODE (opnds
[2]) != SYMBOL_REF
)
4672 emit_insn (gen_add_got16_32bit (opnds
[0], got_rtx
, opnds
[2]));
4674 emit_insn (gen_add_got16 (opnds
[0], got_rtx
, opnds
[2]));
4679 emit_insn (gen_mov_got32_step2_32bit
4680 (opnds
[0], opnds
[1], opnds
[2]));
4682 emit_insn (gen_mov_got32_step2 (opnds
[0], opnds
[1], opnds
[2]));
4685 new_insns
= get_insns ();
4688 replace_insns (insn
, new_insns
);
4692 /* Do the third replacement step in tilegx_fixup_pcrel_references. */
4694 replace_mov_pcrel_step3 (rtx_insn
*insn
)
4696 rtx pattern
= PATTERN (insn
);
4699 rtx_insn
*new_insns
;
4700 rtx got_rtx
= tilegx_got_rtx ();
4701 rtx text_label_rtx
= tilegx_text_label_rtx ();
4703 gcc_assert (GET_CODE (pattern
) == SET
);
4704 opnds
[0] = SET_DEST (pattern
);
4706 unspec
= SET_SRC (pattern
);
4707 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4708 gcc_assert (XINT (unspec
, 1) == UNSPEC_MOV_PCREL_STEP3
);
4712 if (XVECEXP (unspec
, 0, 0) == text_label_rtx
)
4713 opnds
[2] = XVECEXP (unspec
, 0, 1);
4716 gcc_assert (XVECEXP (unspec
, 0, 1) == text_label_rtx
);
4717 opnds
[2] = XVECEXP (unspec
, 0, 0);
4720 opnds
[3] = XVECEXP (unspec
, 0, 2);
4722 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4723 if (GET_CODE (opnds
[3]) != SYMBOL_REF
)
4730 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[2]));
4734 emit_move_insn (opnds
[0], gen_rtx_PLUS (Pmode
, opnds
[1], opnds
[2]));
4735 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[0]));
4738 new_insns
= get_insns ();
4741 replace_insns (insn
, new_insns
);
4745 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4746 going through the GOT when the symbol is local to the compilation
4747 unit. But such a symbol requires that the common text_label that
4748 we generate at the beginning of the function be in the same section
4749 as the reference to the SYMBOL_REF. This may not be true if we
4750 generate hot/cold sections. This function looks for such cases and
4751 replaces such references with the longer sequence going through the
4754 We expect following instruction sequence:
4755 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4756 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4757 add<x> tmp3, txt_label_reg, tmp2 [3]
4759 If we're compiling -fpic, we replace with the following sequence
4760 (the numbers in brackets match the instructions they're replacing
4763 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4764 ld<4> tmp3, tmp2 [3]
4766 If we're compiling -fPIC, we replace the first instruction with:
4768 moveli tmp1, hw1_last_got(x) [1]
4769 shl16insli tmp2, tmp1, hw0_got(x) [2]
4770 add<x> tmp3, got_reg, tmp2 [3]
4771 ld<4> tmp3, tmp3 [3]
4773 Note that we're careful to disturb the instruction sequence as
4774 little as possible, since it's very late in the compilation
4777 tilegx_fixup_pcrel_references (void)
4779 rtx_insn
*insn
, *next_insn
;
4780 bool same_section_as_entry
= true;
4782 for (insn
= get_insns (); insn
; insn
= next_insn
)
4784 next_insn
= NEXT_INSN (insn
);
4786 if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_SWITCH_TEXT_SECTIONS
)
4788 same_section_as_entry
= !same_section_as_entry
;
4792 if (same_section_as_entry
)
4796 && GET_CODE (PATTERN (insn
)) != USE
4797 && GET_CODE (PATTERN (insn
)) != CLOBBER
))
4802 if (match_pcrel_step1 (insn
))
4803 replace_mov_pcrel_step1 (insn
);
4804 else if (match_pcrel_step2 (insn
))
4805 replace_mov_pcrel_step2 (insn
);
4806 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3_32bit
)
4807 replace_mov_pcrel_step3 (insn
);
4811 if (match_pcrel_step1 (insn
))
4812 replace_mov_pcrel_step1 (insn
);
4813 else if (match_pcrel_step2 (insn
))
4814 replace_mov_pcrel_step2 (insn
);
4815 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3
)
4816 replace_mov_pcrel_step3 (insn
);
4822 /* Ensure that no var tracking notes are emitted in the middle of a
4823 three-instruction bundle. */
4825 reorder_var_tracking_notes (void)
4828 FOR_EACH_BB_FN (bb
, cfun
)
4830 rtx_insn
*insn
, *next
;
4831 rtx_insn
*queue
= NULL
;
4832 bool in_bundle
= false;
4834 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4836 next
= NEXT_INSN (insn
);
4840 /* Emit queued up notes at the last instruction of a
4842 if (GET_MODE (insn
) == QImode
)
4846 rtx_insn
*next_queue
= PREV_INSN (queue
);
4847 SET_PREV_INSN (NEXT_INSN (insn
)) = queue
;
4848 SET_NEXT_INSN (queue
) = NEXT_INSN (insn
);
4849 SET_NEXT_INSN (insn
) = queue
;
4850 SET_PREV_INSN (queue
) = insn
;
4855 else if (GET_MODE (insn
) == SImode
)
4858 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4862 rtx_insn
*prev
= PREV_INSN (insn
);
4863 SET_PREV_INSN (next
) = prev
;
4864 SET_NEXT_INSN (prev
) = next
;
4866 SET_PREV_INSN (insn
) = queue
;
4875 /* Perform machine dependent operations on the rtl chain INSNS. */
4879 /* We are freeing block_for_insn in the toplev to keep compatibility
4880 with old MDEP_REORGS that are not CFG based. Recompute it
4882 compute_bb_for_insn ();
4884 if (flag_reorder_blocks_and_partition
)
4886 tilegx_fixup_pcrel_references ();
4889 if (flag_schedule_insns_after_reload
)
4893 timevar_push (TV_SCHED2
);
4895 timevar_pop (TV_SCHED2
);
4897 /* Examine the schedule to group into bundles. */
4898 tilegx_gen_bundles ();
4903 if (flag_var_tracking
)
4905 timevar_push (TV_VAR_TRACKING
);
4906 variable_tracking_main ();
4907 reorder_var_tracking_notes ();
4908 timevar_pop (TV_VAR_TRACKING
);
4911 df_finish_pass (false);
4918 /* Select a format to encode pointers in exception handling data.
4919 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4920 GLOBAL is true if the symbol may be affected by dynamic
4923 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED
, int global
)
4925 int type
= TARGET_32BIT
? DW_EH_PE_sdata4
: DW_EH_PE_sdata8
;
4926 return (global
? DW_EH_PE_indirect
: 0) | DW_EH_PE_pcrel
| type
;
4930 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4932 tilegx_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
4933 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
4936 rtx this_rtx
, funexp
, addend
;
4939 /* Pretend to be a post-reload pass while generating rtl. */
4940 reload_completed
= 1;
4942 /* Mark the end of the (empty) prologue. */
4943 emit_note (NOTE_INSN_PROLOGUE_END
);
4945 /* Find the "this" pointer. If the function returns a structure,
4946 the structure return pointer is in $1. */
4947 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
4948 this_rtx
= gen_rtx_REG (Pmode
, 1);
4950 this_rtx
= gen_rtx_REG (Pmode
, 0);
4952 /* Add DELTA to THIS_RTX. */
4953 if (!(delta
>= -32868 && delta
<= 32767))
4955 addend
= gen_rtx_REG (Pmode
, 29);
4956 emit_move_insn (addend
, GEN_INT (delta
));
4959 addend
= GEN_INT (delta
);
4962 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, addend
));
4964 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, addend
));
4966 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4971 tmp
= gen_rtx_REG (Pmode
, 29);
4972 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, this_rtx
));
4974 if (!(vcall_offset
>= -32868 && vcall_offset
<= 32767))
4976 addend
= gen_rtx_REG (Pmode
, 28);
4977 emit_move_insn (addend
, GEN_INT (vcall_offset
));
4980 addend
= GEN_INT (vcall_offset
);
4983 emit_insn (gen_addsi3 (tmp
, tmp
, addend
));
4985 emit_insn (gen_adddi3 (tmp
, tmp
, addend
));
4987 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, tmp
));
4990 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, tmp
));
4992 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, tmp
));
4995 /* Generate a tail call to the target function. */
4996 if (!TREE_USED (function
))
4998 assemble_external (function
);
4999 TREE_USED (function
) = 1;
5001 funexp
= XEXP (DECL_RTL (function
), 0);
5002 funexp
= gen_rtx_MEM (FUNCTION_MODE
, funexp
);
5003 insn
= emit_call_insn (gen_sibcall (funexp
, const0_rtx
));
5004 SIBLING_CALL_P (insn
) = 1;
5006 /* Run just enough of rest_of_compilation to get the insns emitted.
5007 There's not really enough bulk here to make other passes such as
5008 instruction scheduling worth while. Note that use_thunk calls
5009 assemble_start_function and assemble_end_function.
5011 We don't currently bundle, but the instruciton sequence is all
5012 serial except for the tail call, so we're only wasting one cycle.
5014 insn
= get_insns ();
5015 shorten_branches (insn
);
5016 final_start_function (insn
, file
, 1);
5017 final (insn
, file
, 1);
5018 final_end_function ();
5020 /* Stop pretending to be a post-reload pass. */
5021 reload_completed
= 0;
5025 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
5027 tilegx_asm_trampoline_template (FILE *file
)
5029 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
5032 fprintf (file
, "\tlnk r10\n");
5033 fprintf (file
, "\taddxi r10, r10, 32\n");
5034 fprintf (file
, "\tld4s_add r11, r10, %d\n", ptr_mode_size
);
5035 fprintf (file
, "\tld4s r10, r10\n");
5036 fprintf (file
, "\tjr r11\n");
5037 fprintf (file
, "\t.word 0 # <function address>\n");
5038 fprintf (file
, "\t.word 0 # <static chain value>\n");
5042 fprintf (file
, "\tlnk r10\n");
5043 fprintf (file
, "\taddi r10, r10, 32\n");
5044 fprintf (file
, "\tld_add r11, r10, %d\n", ptr_mode_size
);
5045 fprintf (file
, "\tld r10, r10\n");
5046 fprintf (file
, "\tjr r11\n");
5047 fprintf (file
, "\t.quad 0 # <function address>\n");
5048 fprintf (file
, "\t.quad 0 # <static chain value>\n");
5053 /* Implement TARGET_TRAMPOLINE_INIT. */
5055 tilegx_trampoline_init (rtx m_tramp
, tree fndecl
, rtx static_chain
)
5059 rtx begin_addr
, end_addr
;
5060 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
5062 fnaddr
= copy_to_reg (XEXP (DECL_RTL (fndecl
), 0));
5063 chaddr
= copy_to_reg (static_chain
);
5065 emit_block_move (m_tramp
, assemble_trampoline_template (),
5066 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
5068 mem
= adjust_address (m_tramp
, ptr_mode
,
5069 TRAMPOLINE_SIZE
- 2 * ptr_mode_size
);
5070 emit_move_insn (mem
, fnaddr
);
5071 mem
= adjust_address (m_tramp
, ptr_mode
,
5072 TRAMPOLINE_SIZE
- ptr_mode_size
);
5073 emit_move_insn (mem
, chaddr
);
5075 /* Get pointers to the beginning and end of the code block. */
5076 begin_addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
5077 end_addr
= force_reg (Pmode
, plus_constant (Pmode
, XEXP (m_tramp
, 0),
5080 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__clear_cache"),
5081 LCT_NORMAL
, VOIDmode
, 2, begin_addr
, Pmode
,
5086 /* Implement TARGET_PRINT_OPERAND. */
5088 tilegx_print_operand (FILE *file
, rtx x
, int code
)
5093 /* Print the compare operator opcode for conditional moves. */
5094 switch (GET_CODE (x
))
5103 output_operand_lossage ("invalid %%c operand");
5108 /* Print the compare operator opcode for conditional moves. */
5109 switch (GET_CODE (x
))
5118 output_operand_lossage ("invalid %%C operand");
5124 /* Print the compare operator opcode for conditional moves. */
5125 switch (GET_CODE (x
))
5134 output_operand_lossage ("invalid %%d operand");
5141 /* Print the compare operator opcode for conditional moves. */
5142 switch (GET_CODE (x
))
5151 output_operand_lossage ("invalid %%D operand");
5158 if (GET_CODE (x
) == CONST
5159 && GET_CODE (XEXP (x
, 0)) == UNSPEC
)
5161 rtx addr
= XVECEXP (XEXP (x
, 0), 0, 0);
5162 int unspec
= XINT (XEXP (x
, 0), 1);
5163 const char *opstr
= NULL
;
5167 case UNSPEC_HW0_PCREL
:
5171 case UNSPEC_HW1_PCREL
:
5180 case UNSPEC_HW0_LAST
:
5183 case UNSPEC_HW1_LAST
:
5184 case UNSPEC_HW1_LAST_PCREL
:
5187 case UNSPEC_HW2_LAST
:
5188 case UNSPEC_HW2_LAST_PCREL
:
5191 case UNSPEC_HW0_GOT
:
5194 case UNSPEC_HW0_LAST_GOT
:
5195 opstr
= "hw0_last_got";
5197 case UNSPEC_HW1_LAST_GOT
:
5198 opstr
= "hw1_last_got";
5200 case UNSPEC_HW0_TLS_GD
:
5201 opstr
= "hw0_tls_gd";
5203 case UNSPEC_HW1_LAST_TLS_GD
:
5204 opstr
= "hw1_last_tls_gd";
5206 case UNSPEC_HW0_TLS_IE
:
5207 opstr
= "hw0_tls_ie";
5209 case UNSPEC_HW1_LAST_TLS_IE
:
5210 opstr
= "hw1_last_tls_ie";
5212 case UNSPEC_HW0_TLS_LE
:
5213 opstr
= "hw0_tls_le";
5215 case UNSPEC_HW1_LAST_TLS_LE
:
5216 opstr
= "hw1_last_tls_le";
5218 case UNSPEC_HW0_PLT_PCREL
:
5221 case UNSPEC_HW1_PLT_PCREL
:
5224 case UNSPEC_HW1_LAST_PLT_PCREL
:
5225 opstr
= "hw1_last_plt";
5227 case UNSPEC_HW2_LAST_PLT_PCREL
:
5228 opstr
= "hw2_last_plt";
5231 output_operand_lossage ("invalid %%H specifier");
5234 fputs (opstr
, file
);
5236 output_addr_const (file
, addr
);
5238 if (unspec
== UNSPEC_HW0_PCREL
5239 || unspec
== UNSPEC_HW1_PCREL
5240 || unspec
== UNSPEC_HW1_LAST_PCREL
5241 || unspec
== UNSPEC_HW2_LAST_PCREL
5242 || unspec
== UNSPEC_HW0_PLT_PCREL
5243 || unspec
== UNSPEC_HW1_PLT_PCREL
5244 || unspec
== UNSPEC_HW1_LAST_PLT_PCREL
5245 || unspec
== UNSPEC_HW2_LAST_PLT_PCREL
)
5247 rtx addr2
= XVECEXP (XEXP (x
, 0), 0, 1);
5248 fputs (" - " , file
);
5249 output_addr_const (file
, addr2
);
5255 else if (symbolic_operand (x
, VOIDmode
))
5257 output_addr_const (file
, x
);
5265 /* Print the low 16 bits of a constant. */
5267 if (CONST_INT_P (x
))
5269 else if (GET_CODE (x
) == CONST_DOUBLE
)
5270 i
= CONST_DOUBLE_LOW (x
);
5273 output_operand_lossage ("invalid %%h operand");
5276 i
= trunc_int_for_mode (i
, HImode
);
5277 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5282 /* Print an auto-inc memory operand. */
5285 output_operand_lossage ("invalid %%I operand");
5289 output_memory_reference_mode
= GET_MODE (x
);
5290 output_memory_autoinc_first
= true;
5291 output_address (XEXP (x
, 0));
5292 output_memory_reference_mode
= VOIDmode
;
5296 /* Print an auto-inc memory operand. */
5299 output_operand_lossage ("invalid %%i operand");
5303 output_memory_reference_mode
= GET_MODE (x
);
5304 output_memory_autoinc_first
= false;
5305 output_address (XEXP (x
, 0));
5306 output_memory_reference_mode
= VOIDmode
;
5311 /* Print the low 8 bits of a constant. */
5313 if (CONST_INT_P (x
))
5315 else if (GET_CODE (x
) == CONST_DOUBLE
)
5316 i
= CONST_DOUBLE_LOW (x
);
5317 else if (GET_CODE (x
) == CONST_VECTOR
5318 && CONST_INT_P (CONST_VECTOR_ELT (x
, 0)))
5319 i
= INTVAL (CONST_VECTOR_ELT (x
, 0));
5322 output_operand_lossage ("invalid %%j operand");
5325 i
= trunc_int_for_mode (i
, QImode
);
5326 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5332 /* Print a constant plus one. */
5333 if (!CONST_INT_P (x
))
5335 output_operand_lossage ("invalid %%P operand");
5338 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (x
) + 1);
5345 /* Print a bfextu-style bit range. */
5346 int first_bit
, last_bit
;
5347 HOST_WIDE_INT flip
= (code
== 'm') ? ~0 : 0;
5349 if (!CONST_INT_P (x
)
5350 || !tilegx_bitfield_operand_p (INTVAL (x
) ^ flip
,
5351 &first_bit
, &last_bit
))
5353 output_operand_lossage ("invalid %%%c operand", code
);
5357 fprintf (file
, "%d, %d", first_bit
, last_bit
);
5363 const char *reg
= NULL
;
5365 /* Print a network register. */
5366 if (!CONST_INT_P (x
))
5368 output_operand_lossage ("invalid %%N operand");
5374 case TILEGX_NETREG_IDN0
: reg
= "idn0"; break;
5375 case TILEGX_NETREG_IDN1
: reg
= "idn1"; break;
5376 case TILEGX_NETREG_UDN0
: reg
= "udn0"; break;
5377 case TILEGX_NETREG_UDN1
: reg
= "udn1"; break;
5378 case TILEGX_NETREG_UDN2
: reg
= "udn2"; break;
5379 case TILEGX_NETREG_UDN3
: reg
= "udn3"; break;
5384 fprintf (file
, reg
);
5389 if (GET_CODE (x
) == SYMBOL_REF
)
5391 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5392 fprintf (file
, "plt(");
5393 output_addr_const (file
, x
);
5394 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5395 fprintf (file
, ")");
5398 output_addr_const (file
, x
);
5402 /* In this case we need a register. Use 'zero' if the operand
5405 || (GET_MODE (x
) != VOIDmode
&& x
== CONST0_RTX (GET_MODE (x
))))
5407 fputs ("zero", file
);
5410 else if (!REG_P (x
))
5412 output_operand_lossage ("invalid operand for 'r' specifier");
5420 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
5425 output_memory_reference_mode
= VOIDmode
;
5426 output_address (XEXP (x
, 0));
5431 output_addr_const (file
, x
);
5437 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5442 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5444 tilegx_print_operand_address (FILE *file
, rtx addr
)
5446 if (GET_CODE (addr
) == POST_DEC
5447 || GET_CODE (addr
) == POST_INC
)
5449 int offset
= GET_MODE_SIZE (output_memory_reference_mode
);
5451 gcc_assert (output_memory_reference_mode
!= VOIDmode
);
5453 if (output_memory_autoinc_first
)
5454 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5456 fprintf (file
, "%d",
5457 GET_CODE (addr
) == POST_DEC
? -offset
: offset
);
5459 else if (GET_CODE (addr
) == POST_MODIFY
)
5461 gcc_assert (output_memory_reference_mode
!= VOIDmode
);
5463 gcc_assert (GET_CODE (XEXP (addr
, 1)) == PLUS
);
5465 if (output_memory_autoinc_first
)
5466 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5468 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
,
5469 INTVAL (XEXP (XEXP (addr
, 1), 1)));
5472 tilegx_print_operand (file
, addr
, 'r');
5476 /* Machine mode of current insn, for determining curly brace
5478 static machine_mode insn_mode
;
5481 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5483 tilegx_final_prescan_insn (rtx_insn
*insn
)
5485 /* Record this for tilegx_asm_output_opcode to examine. */
5486 insn_mode
= GET_MODE (insn
);
5490 /* While emitting asm, are we currently inside '{' for a bundle? */
5491 static bool tilegx_in_bundle
= false;
5493 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5494 appropriate given the bundling information recorded by
5495 tilegx_gen_bundles. */
5497 tilegx_asm_output_opcode (FILE *stream
, const char *code
)
5499 bool pseudo
= !strcmp (code
, "pseudo");
5501 if (!tilegx_in_bundle
&& insn_mode
== SImode
)
5503 /* Start a new bundle. */
5504 fprintf (stream
, "{\n\t");
5505 tilegx_in_bundle
= true;
5508 if (tilegx_in_bundle
&& insn_mode
== QImode
)
5510 /* Close an existing bundle. */
5511 static char buf
[100];
5513 gcc_assert (strlen (code
) + 3 + 1 < sizeof (buf
));
5515 strcpy (buf
, pseudo
? "" : code
);
5516 strcat (buf
, "\n\t}");
5517 tilegx_in_bundle
= false;
5523 return pseudo
? "" : code
;
5528 /* Output assembler code to FILE to increment profiler label # LABELNO
5529 for profiling a function entry. */
5531 tilegx_function_profiler (FILE *file
, int labelno ATTRIBUTE_UNUSED
)
5533 if (tilegx_in_bundle
)
5535 fprintf (file
, "\t}\n");
5544 "\t}\n", MCOUNT_NAME
);
5552 "\t}\n", MCOUNT_NAME
);
5555 tilegx_in_bundle
= false;
5559 /* Implement TARGET_ASM_FILE_END. */
5561 tilegx_file_end (void)
5563 if (NEED_INDICATE_EXEC_STACK
)
5564 file_end_indicate_exec_stack ();
5569 #undef TARGET_HAVE_TLS
5570 #define TARGET_HAVE_TLS HAVE_AS_TLS
5572 #undef TARGET_OPTION_OVERRIDE
5573 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5575 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5576 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5578 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5579 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5581 #undef TARGET_CANNOT_FORCE_CONST_MEM
5582 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5584 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5585 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5587 #undef TARGET_PASS_BY_REFERENCE
5588 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5590 #undef TARGET_RETURN_IN_MSB
5591 #define TARGET_RETURN_IN_MSB tilegx_return_in_msb
5593 #undef TARGET_RETURN_IN_MEMORY
5594 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5596 #undef TARGET_MODE_REP_EXTENDED
5597 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5599 #undef TARGET_FUNCTION_ARG_BOUNDARY
5600 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5602 #undef TARGET_FUNCTION_ARG
5603 #define TARGET_FUNCTION_ARG tilegx_function_arg
5605 #undef TARGET_FUNCTION_ARG_ADVANCE
5606 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5608 #undef TARGET_FUNCTION_VALUE
5609 #define TARGET_FUNCTION_VALUE tilegx_function_value
5611 #undef TARGET_LIBCALL_VALUE
5612 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5614 #undef TARGET_FUNCTION_VALUE_REGNO_P
5615 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5617 #undef TARGET_PROMOTE_FUNCTION_MODE
5618 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5620 #undef TARGET_PROMOTE_PROTOTYPES
5621 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5623 #undef TARGET_BUILD_BUILTIN_VA_LIST
5624 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5626 #undef TARGET_EXPAND_BUILTIN_VA_START
5627 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5629 #undef TARGET_SETUP_INCOMING_VARARGS
5630 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5632 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5633 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5635 #undef TARGET_RTX_COSTS
5636 #define TARGET_RTX_COSTS tilegx_rtx_costs
5638 #undef TARGET_EXPAND_TO_RTL_HOOK
5639 #define TARGET_EXPAND_TO_RTL_HOOK tilegx_expand_to_rtl_hook
5641 #undef TARGET_SHIFT_TRUNCATION_MASK
5642 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5644 #undef TARGET_INIT_LIBFUNCS
5645 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5647 /* Limit to what we can reach in one addli. */
5648 #undef TARGET_MIN_ANCHOR_OFFSET
5649 #define TARGET_MIN_ANCHOR_OFFSET -32768
5650 #undef TARGET_MAX_ANCHOR_OFFSET
5651 #define TARGET_MAX_ANCHOR_OFFSET 32767
5653 #undef TARGET_LEGITIMATE_CONSTANT_P
5654 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5656 #undef TARGET_LEGITIMATE_ADDRESS_P
5657 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5659 #undef TARGET_LEGITIMIZE_ADDRESS
5660 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5662 #undef TARGET_DELEGITIMIZE_ADDRESS
5663 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5665 #undef TARGET_INIT_BUILTINS
5666 #define TARGET_INIT_BUILTINS tilegx_init_builtins
5668 #undef TARGET_BUILTIN_DECL
5669 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5671 #undef TARGET_EXPAND_BUILTIN
5672 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5674 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5675 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5677 #undef TARGET_FRAME_POINTER_REQUIRED
5678 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5680 #undef TARGET_DELAY_SCHED2
5681 #define TARGET_DELAY_SCHED2 true
5683 #undef TARGET_DELAY_VARTRACK
5684 #define TARGET_DELAY_VARTRACK true
5686 #undef TARGET_SCHED_ISSUE_RATE
5687 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5689 #undef TARGET_SCHED_ADJUST_COST
5690 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5692 #undef TARGET_MACHINE_DEPENDENT_REORG
5693 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5695 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5696 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5697 hook_bool_const_tree_hwi_hwi_const_tree_true
5699 #undef TARGET_ASM_OUTPUT_MI_THUNK
5700 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5702 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5703 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5705 #undef TARGET_TRAMPOLINE_INIT
5706 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5708 #undef TARGET_PRINT_OPERAND
5709 #define TARGET_PRINT_OPERAND tilegx_print_operand
5711 #undef TARGET_PRINT_OPERAND_ADDRESS
5712 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5714 #undef TARGET_ASM_FILE_END
5715 #define TARGET_ASM_FILE_END tilegx_file_end
5717 #undef TARGET_ASM_ALIGNED_DI_OP
5718 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5720 #undef TARGET_CAN_USE_DOLOOP_P
5721 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
5723 struct gcc_target targetm
= TARGET_INITIALIZER
;
5725 #include "gt-tilegx.h"