1 /* Subroutines used for code generation on the Tilera TILE-Gx.
2 Copyright (C) 2011, 2012
3 Free Software Foundation, Inc.
4 Contributed by Walter Lee (walt@tilera.com)
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
28 #include "insn-config.h"
30 #include "insn-attr.h"
33 #include "langhooks.h"
35 #include "sched-int.h"
37 #include "tm-constrs.h"
39 #include "target-def.h"
45 #include "tilegx-builtins.h"
46 #include "tilegx-multiply.h"
47 #include "diagnostic.h"
49 /* SYMBOL_REF for GOT */
50 static GTY(()) rtx g_got_symbol
= NULL
;
52 /* In case of a POST_INC or POST_DEC memory reference, we must report
53 the mode of the memory reference from TARGET_PRINT_OPERAND to
54 TARGET_PRINT_OPERAND_ADDRESS. */
55 static enum machine_mode output_memory_reference_mode
;
57 /* Report whether we're printing out the first address fragment of a
58 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
59 TARGET_PRINT_OPERAND_ADDRESS. */
60 static bool output_memory_autoinc_first
;
66 /* Implement TARGET_OPTION_OVERRIDE. */
68 tilegx_option_override (void)
70 /* When modulo scheduling is enabled, we still rely on regular
71 scheduler for bundling. */
72 if (flag_modulo_sched
)
73 flag_resched_modulo_sched
= 1;
78 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
80 tilegx_scalar_mode_supported_p (enum machine_mode mode
)
101 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
103 tilegx_vector_mode_supported_p (enum machine_mode mode
)
105 return mode
== V8QImode
|| mode
== V4HImode
|| mode
== V2SImode
;
109 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
111 tilegx_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED
,
112 rtx x ATTRIBUTE_UNUSED
)
118 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
120 tilegx_function_ok_for_sibcall (tree decl
, tree exp ATTRIBUTE_UNUSED
)
126 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
127 passed by reference. */
129 tilegx_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED
,
130 enum machine_mode mode ATTRIBUTE_UNUSED
,
131 const_tree type
, bool named ATTRIBUTE_UNUSED
)
133 return (type
&& TYPE_SIZE (type
)
134 && TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
);
138 /* Implement TARGET_RETURN_IN_MEMORY. */
140 tilegx_return_in_memory (const_tree type
, const_tree fndecl ATTRIBUTE_UNUSED
)
142 return !IN_RANGE (int_size_in_bytes (type
),
143 0, TILEGX_NUM_RETURN_REGS
* UNITS_PER_WORD
);
147 /* TARGET_MODE_REP_EXTENDED. */
149 tilegx_mode_rep_extended (enum machine_mode mode
, enum machine_mode mode_rep
)
151 /* SImode register values are sign-extended to DImode. */
152 if (mode
== SImode
&& mode_rep
== DImode
)
159 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
161 tilegx_function_arg_boundary (enum machine_mode mode
, const_tree type
)
163 unsigned int alignment
;
165 alignment
= type
? TYPE_ALIGN (type
) : GET_MODE_ALIGNMENT (mode
);
166 if (alignment
< PARM_BOUNDARY
)
167 alignment
= PARM_BOUNDARY
;
168 if (alignment
> STACK_BOUNDARY
)
169 alignment
= STACK_BOUNDARY
;
174 /* Implement TARGET_FUNCTION_ARG. */
176 tilegx_function_arg (cumulative_args_t cum_v
,
177 enum machine_mode mode
,
178 const_tree type
, bool named ATTRIBUTE_UNUSED
)
180 CUMULATIVE_ARGS cum
= *get_cumulative_args (cum_v
);
181 int byte_size
= ((mode
== BLKmode
)
182 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
184 if (cum
>= TILEGX_NUM_ARG_REGS
)
187 /* The ABI does not allow parameters to be passed partially in reg
188 and partially in stack. */
189 if ((cum
+ (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
)
190 > TILEGX_NUM_ARG_REGS
)
193 return gen_rtx_REG (mode
, cum
);
197 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
199 tilegx_function_arg_advance (cumulative_args_t cum_v
,
200 enum machine_mode mode
,
201 const_tree type
, bool named ATTRIBUTE_UNUSED
)
203 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
205 int byte_size
= ((mode
== BLKmode
)
206 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
207 int word_size
= (byte_size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
209 /* If the current argument does not fit in the pretend_args space,
211 if (*cum
< TILEGX_NUM_ARG_REGS
212 && *cum
+ word_size
> TILEGX_NUM_ARG_REGS
)
213 *cum
= TILEGX_NUM_ARG_REGS
;
219 /* Implement TARGET_FUNCTION_VALUE. */
221 tilegx_function_value (const_tree valtype
, const_tree fn_decl_or_type
,
222 bool outgoing ATTRIBUTE_UNUSED
)
224 enum machine_mode mode
;
227 mode
= TYPE_MODE (valtype
);
228 unsigned_p
= TYPE_UNSIGNED (valtype
);
230 mode
= promote_function_mode (valtype
, mode
, &unsigned_p
,
233 return gen_rtx_REG (mode
, 0);
237 /* Implement TARGET_LIBCALL_VALUE. */
239 tilegx_libcall_value (enum machine_mode mode
,
240 const_rtx fun ATTRIBUTE_UNUSED
)
242 return gen_rtx_REG (mode
, 0);
246 /* Implement FUNCTION_VALUE_REGNO_P. */
248 tilegx_function_value_regno_p (const unsigned int regno
)
250 return regno
< TILEGX_NUM_RETURN_REGS
;
254 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
256 tilegx_build_builtin_va_list (void)
258 tree f_args
, f_skip
, record
, type_decl
;
261 record
= lang_hooks
.types
.make_type (RECORD_TYPE
);
263 type_decl
= build_decl (BUILTINS_LOCATION
, TYPE_DECL
,
264 get_identifier ("__va_list_tag"), record
);
266 f_args
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
267 get_identifier ("__args"), ptr_type_node
);
268 f_skip
= build_decl (BUILTINS_LOCATION
, FIELD_DECL
,
269 get_identifier ("__skip"), ptr_type_node
);
271 DECL_FIELD_CONTEXT (f_args
) = record
;
273 DECL_FIELD_CONTEXT (f_skip
) = record
;
275 TREE_CHAIN (record
) = type_decl
;
276 TYPE_NAME (record
) = type_decl
;
277 TYPE_FIELDS (record
) = f_args
;
278 TREE_CHAIN (f_args
) = f_skip
;
280 /* We know this is being padded and we want it too. It is an
281 internal type so hide the warnings from the user. */
285 layout_type (record
);
289 /* The correct type is an array type of one element. */
294 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
296 tilegx_va_start (tree valist
, rtx nextarg ATTRIBUTE_UNUSED
)
301 f_args
= TYPE_FIELDS (TREE_TYPE (valist
));
302 f_skip
= TREE_CHAIN (f_args
);
305 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
307 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
309 /* Find the __args area. */
310 t
= make_tree (TREE_TYPE (args
), virtual_incoming_args_rtx
);
311 t
= fold_build_pointer_plus_hwi (t
,
313 (crtl
->args
.info
- TILEGX_NUM_ARG_REGS
));
315 if (crtl
->args
.pretend_args_size
> 0)
316 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
318 t
= build2 (MODIFY_EXPR
, TREE_TYPE (args
), args
, t
);
319 TREE_SIDE_EFFECTS (t
) = 1;
320 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
322 /* Find the __skip area. */
323 t
= make_tree (TREE_TYPE (skip
), virtual_incoming_args_rtx
);
324 t
= fold_build_pointer_plus_hwi (t
, -STACK_POINTER_OFFSET
);
325 t
= build2 (MODIFY_EXPR
, TREE_TYPE (skip
), skip
, t
);
326 TREE_SIDE_EFFECTS (t
) = 1;
327 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
331 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
333 tilegx_setup_incoming_varargs (cumulative_args_t cum
,
334 enum machine_mode mode
,
335 tree type
, int *pretend_args
, int no_rtl
)
337 CUMULATIVE_ARGS local_cum
= *get_cumulative_args (cum
);
340 /* The caller has advanced CUM up to, but not beyond, the last named
341 argument. Advance a local copy of CUM past the last "real" named
342 argument, to find out how many registers are left over. */
343 targetm
.calls
.function_arg_advance (pack_cumulative_args (&local_cum
),
345 first_reg
= local_cum
;
347 if (local_cum
< TILEGX_NUM_ARG_REGS
)
349 *pretend_args
= UNITS_PER_WORD
* (TILEGX_NUM_ARG_REGS
- first_reg
);
353 alias_set_type set
= get_varargs_alias_set ();
355 gen_rtx_MEM (BLKmode
, plus_constant (Pmode
,
356 virtual_incoming_args_rtx
,
357 -STACK_POINTER_OFFSET
-
359 (TILEGX_NUM_ARG_REGS
-
361 MEM_NOTRAP_P (tmp
) = 1;
362 set_mem_alias_set (tmp
, set
);
363 move_block_from_reg (first_reg
, tmp
,
364 TILEGX_NUM_ARG_REGS
- first_reg
);
372 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
373 the va_list structure VALIST as required to retrieve an argument of
374 type TYPE, and returning that argument.
376 ret = va_arg(VALIST, TYPE);
378 generates code equivalent to:
380 paddedsize = (sizeof(TYPE) + 3) & -4;
381 if ( (VALIST.__args + paddedsize > VALIST.__skip)
382 & (VALIST.__args <= VALIST.__skip))
383 addr = VALIST.__skip + STACK_POINTER_OFFSET;
385 addr = VALIST.__args;
386 VALIST.__args = addr + paddedsize;
390 tilegx_gimplify_va_arg_expr (tree valist
, tree type
, gimple_seq
*pre_p
,
391 gimple_seq
*post_p ATTRIBUTE_UNUSED
)
395 HOST_WIDE_INT size
, rsize
;
397 bool pass_by_reference_p
;
399 f_args
= TYPE_FIELDS (va_list_type_node
);
400 f_skip
= TREE_CHAIN (f_args
);
403 build3 (COMPONENT_REF
, TREE_TYPE (f_args
), valist
, f_args
, NULL_TREE
);
405 build3 (COMPONENT_REF
, TREE_TYPE (f_skip
), valist
, f_skip
, NULL_TREE
);
407 addr
= create_tmp_var (ptr_type_node
, "va_arg");
409 /* if an object is dynamically sized, a pointer to it is passed
410 instead of the object itself. */
411 pass_by_reference_p
= pass_by_reference (NULL
, TYPE_MODE (type
), type
,
414 if (pass_by_reference_p
)
415 type
= build_pointer_type (type
);
417 size
= int_size_in_bytes (type
);
418 rsize
= ((size
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
) * UNITS_PER_WORD
;
420 /* Assert alignment assumption. */
421 gcc_assert (STACK_BOUNDARY
== PARM_BOUNDARY
);
423 /* Build conditional expression to calculate addr. The expression
424 will be gimplified later. */
425 tmp
= fold_build_pointer_plus_hwi (unshare_expr (args
), rsize
);
426 tmp
= build2 (TRUTH_AND_EXPR
, boolean_type_node
,
427 build2 (GT_EXPR
, boolean_type_node
, tmp
, unshare_expr (skip
)),
428 build2 (LE_EXPR
, boolean_type_node
, unshare_expr (args
),
429 unshare_expr (skip
)));
431 tmp
= build3 (COND_EXPR
, ptr_type_node
, tmp
,
432 build2 (POINTER_PLUS_EXPR
, ptr_type_node
, unshare_expr (skip
),
433 size_int (STACK_POINTER_OFFSET
)),
434 unshare_expr (args
));
436 gimplify_assign (addr
, tmp
, pre_p
);
438 /* Update VALIST.__args. */
439 tmp
= fold_build_pointer_plus_hwi (addr
, rsize
);
440 gimplify_assign (unshare_expr (args
), tmp
, pre_p
);
442 addr
= fold_convert (build_pointer_type (type
), addr
);
444 if (pass_by_reference_p
)
445 addr
= build_va_arg_indirect_ref (addr
);
447 return build_va_arg_indirect_ref (addr
);
452 /* Implement TARGET_RTX_COSTS. */
454 tilegx_rtx_costs (rtx x
, int code
, int outer_code
, int opno
, int *total
,
460 /* If this is an 8-bit constant, return zero since it can be
461 used nearly anywhere with no cost. If it is a valid operand
462 for an ADD or AND, likewise return 0 if we know it will be
463 used in that context. Otherwise, return 2 since it might be
464 used there later. All other constants take at least two
466 if (satisfies_constraint_I (x
))
471 else if (outer_code
== PLUS
&& add_operand (x
, VOIDmode
))
473 /* Slightly penalize large constants even though we can add
474 them in one instruction, because it forces the use of
475 2-wide bundling mode. */
479 else if (move_operand (x
, SImode
))
481 /* We can materialize in one move. */
482 *total
= COSTS_N_INSNS (1);
487 /* We can materialize in two moves. */
488 *total
= COSTS_N_INSNS (2);
497 *total
= COSTS_N_INSNS (2);
501 *total
= COSTS_N_INSNS (4);
509 /* If outer-code was a sign or zero extension, a cost of
510 COSTS_N_INSNS (1) was already added in, so account for
512 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
513 *total
= COSTS_N_INSNS (1);
515 *total
= COSTS_N_INSNS (2);
519 /* Convey that shl[123]add are efficient. */
520 if (GET_CODE (XEXP (x
, 0)) == MULT
521 && cint_248_operand (XEXP (XEXP (x
, 0), 1), VOIDmode
))
523 *total
= (rtx_cost (XEXP (XEXP (x
, 0), 0),
524 (enum rtx_code
) outer_code
, opno
, speed
)
525 + rtx_cost (XEXP (x
, 1),
526 (enum rtx_code
) outer_code
, opno
, speed
)
527 + COSTS_N_INSNS (1));
533 *total
= COSTS_N_INSNS (2);
540 /* These are handled by software and are very expensive. */
541 *total
= COSTS_N_INSNS (100);
545 case UNSPEC_VOLATILE
:
547 int num
= XINT (x
, 1);
549 if (num
<= TILEGX_LAST_LATENCY_1_INSN
)
550 *total
= COSTS_N_INSNS (1);
551 else if (num
<= TILEGX_LAST_LATENCY_2_INSN
)
552 *total
= COSTS_N_INSNS (2);
553 else if (num
> TILEGX_LAST_LATENCY_INSN
)
555 if (num
== UNSPEC_NON_TEMPORAL
)
557 /* These are basically loads. */
558 if (outer_code
== ZERO_EXTEND
|| outer_code
== SIGN_EXTEND
)
559 *total
= COSTS_N_INSNS (1);
561 *total
= COSTS_N_INSNS (2);
565 if (outer_code
== PLUS
)
568 *total
= COSTS_N_INSNS (1);
575 case UNSPEC_BLOCKAGE
:
576 case UNSPEC_NETWORK_BARRIER
:
581 case UNSPEC_LNK_AND_LABEL
:
583 case UNSPEC_MOV_PCREL_STEP3
:
584 case UNSPEC_NETWORK_RECEIVE
:
585 case UNSPEC_NETWORK_SEND
:
586 case UNSPEC_SPR_MOVE
:
587 case UNSPEC_TLS_GD_ADD
:
588 *total
= COSTS_N_INSNS (1);
591 case UNSPEC_TLS_IE_LOAD
:
593 *total
= COSTS_N_INSNS (2);
597 *total
= COSTS_N_INSNS (3);
601 *total
= COSTS_N_INSNS (4);
605 case UNSPEC_INSN_CMPEXCH
:
606 case UNSPEC_LATENCY_L2
:
607 *total
= COSTS_N_INSNS (11);
610 case UNSPEC_TLS_GD_CALL
:
611 *total
= COSTS_N_INSNS (30);
614 case UNSPEC_LATENCY_MISS
:
615 *total
= COSTS_N_INSNS (80);
619 *total
= COSTS_N_INSNS (1);
634 /* Create a temporary variable to hold a partial result, to enable
637 create_temp_reg_if_possible (enum machine_mode mode
, rtx default_reg
)
639 return can_create_pseudo_p ()? gen_reg_rtx (mode
) : default_reg
;
643 /* Functions to save and restore machine-specific function data. */
644 static struct machine_function
*
645 tilegx_init_machine_status (void)
647 return ggc_alloc_cleared_machine_function ();
651 /* Do anything needed before RTL is emitted for each function. */
653 tilegx_init_expanders (void)
655 /* Arrange to initialize and mark the machine per-function
657 init_machine_status
= tilegx_init_machine_status
;
659 if (cfun
&& cfun
->machine
&& flag_pic
)
661 static int label_num
= 0;
663 char text_label_name
[32];
665 struct machine_function
*machine
= cfun
->machine
;
667 ASM_GENERATE_INTERNAL_LABEL (text_label_name
, "L_PICLNK", label_num
++);
669 machine
->text_label_symbol
=
670 gen_rtx_SYMBOL_REF (Pmode
, ggc_strdup (text_label_name
));
672 machine
->text_label_rtx
=
673 gen_rtx_REG (Pmode
, TILEGX_PIC_TEXT_LABEL_REGNUM
);
675 machine
->got_rtx
= gen_rtx_REG (Pmode
, PIC_OFFSET_TABLE_REGNUM
);
677 machine
->calls_tls_get_addr
= false;
682 /* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode
683 matching insns and therefore guarantee that the shift count is
684 modulo 64. SImode shifts sometimes use the 64 bit version so do
685 not hold such guarantee. */
686 static unsigned HOST_WIDE_INT
687 tilegx_shift_truncation_mask (enum machine_mode mode
)
689 return mode
== DImode
? 63 : 0;
693 /* Implement TARGET_INIT_LIBFUNCS. */
695 tilegx_init_libfuncs (void)
697 /* We need to explicitly generate these libfunc's to support
698 conversion of divide by constant to multiply (the divide stubs in
699 tilegx.md exist also for this reason). Normally we'd expect gcc
700 to lazily generate them when they are needed, but for some reason
701 it's set up to only generate them if the mode is the word
703 set_optab_libfunc (sdiv_optab
, SImode
, "__divsi3");
704 set_optab_libfunc (udiv_optab
, SImode
, "__udivsi3");
705 set_optab_libfunc (smod_optab
, SImode
, "__modsi3");
706 set_optab_libfunc (umod_optab
, SImode
, "__umodsi3");
710 /* Return true if X contains a thread-local symbol. */
712 tilegx_tls_referenced_p (rtx x
)
714 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == PLUS
)
715 x
= XEXP (XEXP (x
, 0), 0);
717 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
))
720 /* That's all we handle in tilegx_legitimize_tls_address for
726 /* Return true if X requires a scratch register. It is given that
727 flag_pic is on and that X satisfies CONSTANT_P. */
729 tilegx_pic_address_needs_scratch (rtx x
)
731 if (GET_CODE (x
) == CONST
732 && GET_CODE (XEXP (x
, 0)) == PLUS
733 && (GET_CODE (XEXP (XEXP (x
, 0), 0)) == SYMBOL_REF
734 || GET_CODE (XEXP (XEXP (x
, 0), 0)) == LABEL_REF
)
735 && (CONST_INT_P (XEXP (XEXP (x
, 0), 1))))
742 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
743 which we are willing to load the value into a register via a move
744 pattern. TLS cannot be treated as a constant because it can
745 include a function call. */
747 tilegx_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
749 switch (GET_CODE (x
))
753 return !tilegx_tls_referenced_p (x
);
761 /* Return true if the constant value X is a legitimate general operand
762 when generating PIC code. It is given that flag_pic is on and that
763 X satisfies CONSTANT_P. */
765 tilegx_legitimate_pic_operand_p (rtx x
)
767 if (tilegx_pic_address_needs_scratch (x
))
770 if (tilegx_tls_referenced_p (x
))
777 /* Return true if the rtx X can be used as an address operand. */
779 tilegx_legitimate_address_p (enum machine_mode
ARG_UNUSED (mode
), rtx x
,
782 if (GET_CODE (x
) == SUBREG
)
785 switch (GET_CODE (x
))
789 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
796 if (GET_MODE_SIZE (GET_MODE (x
)) > UNITS_PER_WORD
)
799 if (GET_CODE (XEXP (x
, 1)) != PLUS
)
802 if (!rtx_equal_p (XEXP (x
, 0), XEXP (XEXP (x
, 1), 0)))
805 if (!satisfies_constraint_I (XEXP (XEXP (x
, 1), 1)))
818 /* Check if x is a valid reg. */
823 return REGNO_OK_FOR_BASE_P (REGNO (x
));
829 /* Return the rtx containing SYMBOL_REF to the text label. */
831 tilegx_text_label_symbol (void)
833 return cfun
->machine
->text_label_symbol
;
837 /* Return the register storing the value of the text label. */
839 tilegx_text_label_rtx (void)
841 return cfun
->machine
->text_label_rtx
;
845 /* Return the register storing the value of the global offset
848 tilegx_got_rtx (void)
850 return cfun
->machine
->got_rtx
;
854 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
856 tilegx_got_symbol (void)
858 if (g_got_symbol
== NULL
)
859 g_got_symbol
= gen_rtx_SYMBOL_REF (Pmode
, "_GLOBAL_OFFSET_TABLE_");
865 /* Return a reference to the got to be used by tls references. */
867 tilegx_tls_got (void)
872 crtl
->uses_pic_offset_table
= 1;
873 return tilegx_got_rtx ();
876 temp
= gen_reg_rtx (Pmode
);
877 emit_move_insn (temp
, tilegx_got_symbol ());
883 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
884 this (thread-local) address. */
886 tilegx_legitimize_tls_address (rtx addr
)
890 gcc_assert (can_create_pseudo_p ());
892 if (GET_CODE (addr
) == SYMBOL_REF
)
893 switch (SYMBOL_REF_TLS_MODEL (addr
))
895 case TLS_MODEL_GLOBAL_DYNAMIC
:
896 case TLS_MODEL_LOCAL_DYNAMIC
:
898 rtx r0
, temp
, temp2
, temp3
, got
, last
;
900 ret
= gen_reg_rtx (Pmode
);
901 r0
= gen_rtx_REG (Pmode
, 0);
902 temp
= gen_reg_rtx (Pmode
);
903 temp2
= gen_reg_rtx (Pmode
);
904 temp3
= gen_reg_rtx (Pmode
);
906 got
= tilegx_tls_got ();
909 emit_insn (gen_mov_tls_gd_step1_32bit (temp
, addr
));
910 emit_insn (gen_mov_tls_gd_step2_32bit (temp2
, temp
, addr
));
911 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
915 emit_insn (gen_mov_tls_gd_step1 (temp
, addr
));
916 emit_insn (gen_mov_tls_gd_step2 (temp2
, temp
, addr
));
917 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
920 emit_move_insn (r0
, temp2
);
924 emit_insn (gen_tls_gd_call_32bit (addr
));
928 emit_insn (gen_tls_gd_call (addr
));
931 emit_move_insn (temp3
, r0
);
934 last
= emit_insn (gen_tls_gd_add_32bit (ret
, temp3
, addr
));
936 last
= emit_insn (gen_tls_gd_add (ret
, temp3
, addr
));
938 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
941 case TLS_MODEL_INITIAL_EXEC
:
943 rtx temp
, temp2
, temp3
, got
, last
;
945 ret
= gen_reg_rtx (Pmode
);
946 temp
= gen_reg_rtx (Pmode
);
947 temp2
= gen_reg_rtx (Pmode
);
948 temp3
= gen_reg_rtx (Pmode
);
950 got
= tilegx_tls_got ();
953 emit_insn (gen_mov_tls_ie_step1_32bit (temp
, addr
));
954 emit_insn (gen_mov_tls_ie_step2_32bit (temp2
, temp
, addr
));
955 emit_insn (gen_tls_add_32bit (temp2
, got
, temp2
, addr
));
956 emit_insn (gen_tls_ie_load_32bit (temp3
, temp2
, addr
));
960 emit_insn (gen_mov_tls_ie_step1 (temp
, addr
));
961 emit_insn (gen_mov_tls_ie_step2 (temp2
, temp
, addr
));
962 emit_insn (gen_tls_add (temp2
, got
, temp2
, addr
));
963 emit_insn (gen_tls_ie_load (temp3
, temp2
, addr
));
970 THREAD_POINTER_REGNUM
),
972 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
975 case TLS_MODEL_LOCAL_EXEC
:
977 rtx temp
, temp2
, last
;
979 ret
= gen_reg_rtx (Pmode
);
980 temp
= gen_reg_rtx (Pmode
);
981 temp2
= gen_reg_rtx (Pmode
);
985 emit_insn (gen_mov_tls_le_step1_32bit (temp
, addr
));
986 emit_insn (gen_mov_tls_le_step2_32bit (temp2
, temp
, addr
));
990 emit_insn (gen_mov_tls_le_step1 (temp
, addr
));
991 emit_insn (gen_mov_tls_le_step2 (temp2
, temp
, addr
));
998 THREAD_POINTER_REGNUM
),
1000 set_unique_reg_note (last
, REG_EQUAL
, copy_rtx (addr
));
1006 else if (GET_CODE (addr
) == CONST
)
1010 gcc_assert (GET_CODE (XEXP (addr
, 0)) == PLUS
);
1012 base
= tilegx_legitimize_tls_address (XEXP (XEXP (addr
, 0), 0));
1013 offset
= XEXP (XEXP (addr
, 0), 1);
1015 base
= force_operand (base
, NULL_RTX
);
1016 ret
= force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1025 /* Returns a register that points to ADDR, a symbolic address, by
1026 computing its address relative to tilegx_text_label_symbol. */
1028 compute_pcrel_address (rtx result
, rtx addr
)
1030 rtx text_label_symbol
= tilegx_text_label_symbol ();
1031 rtx text_label_rtx
= tilegx_text_label_rtx ();
1034 temp
= create_temp_reg_if_possible (Pmode
, result
);
1035 temp2
= create_temp_reg_if_possible (Pmode
, result
);
1039 emit_insn (gen_mov_pcrel_step1_32bit (temp
, addr
, text_label_symbol
));
1040 emit_insn (gen_mov_pcrel_step2_32bit (temp2
, temp
, addr
,
1041 text_label_symbol
));
1042 emit_insn (gen_mov_pcrel_step3_32bit (result
, temp2
,
1044 addr
, text_label_symbol
));
1048 emit_insn (gen_mov_pcrel_step1 (temp
, addr
, text_label_symbol
));
1049 emit_insn (gen_mov_pcrel_step2 (temp2
, temp
, addr
, text_label_symbol
));
1050 emit_insn (gen_mov_pcrel_step3 (result
, temp2
,
1052 addr
, text_label_symbol
));
1057 /* Legitimize PIC addresses. If the address is already
1058 position-independent, we return ORIG. Newly generated
1059 position-independent addresses go into a reg. This is REG if
1060 nonzero, otherwise we allocate register(s) as necessary. */
1062 tilegx_legitimize_pic_address (rtx orig
,
1063 enum machine_mode mode ATTRIBUTE_UNUSED
,
1066 if (GET_CODE (orig
) == SYMBOL_REF
)
1068 rtx address
, pic_ref
;
1072 gcc_assert (can_create_pseudo_p ());
1073 reg
= gen_reg_rtx (Pmode
);
1076 if (SYMBOL_REF_LOCAL_P (orig
))
1078 /* If not during reload, allocate another temp reg here for
1079 loading in the address, so that these instructions can be
1080 optimized properly. */
1081 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1082 compute_pcrel_address (temp_reg
, orig
);
1084 /* Note: this is conservative. We use the text_label but we
1085 don't use the pic_offset_table. However, in some cases
1086 we may need the pic_offset_table (see
1087 tilegx_fixup_pcrel_references). */
1088 crtl
->uses_pic_offset_table
= 1;
1092 emit_move_insn (reg
, address
);
1097 /* If not during reload, allocate another temp reg here for
1098 loading in the address, so that these instructions can be
1099 optimized properly. */
1100 rtx temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1102 gcc_assert (flag_pic
);
1107 emit_insn (gen_add_got16_32bit (temp_reg
,
1113 emit_insn (gen_add_got16 (temp_reg
,
1114 tilegx_got_rtx (), orig
));
1119 rtx temp_reg2
= create_temp_reg_if_possible (Pmode
, reg
);
1120 rtx temp_reg3
= create_temp_reg_if_possible (Pmode
, reg
);
1123 emit_insn (gen_mov_got32_step1_32bit (temp_reg3
, orig
));
1124 emit_insn (gen_mov_got32_step2_32bit
1125 (temp_reg2
, temp_reg3
, orig
));
1129 emit_insn (gen_mov_got32_step1 (temp_reg3
, orig
));
1130 emit_insn (gen_mov_got32_step2 (temp_reg2
, temp_reg3
,
1133 emit_move_insn (temp_reg
,
1134 gen_rtx_PLUS (Pmode
,
1135 tilegx_got_rtx (), temp_reg2
));
1140 pic_ref
= gen_const_mem (Pmode
, address
);
1141 crtl
->uses_pic_offset_table
= 1;
1142 emit_move_insn (reg
, pic_ref
);
1143 /* The following put a REG_EQUAL note on this insn, so that
1144 it can be optimized by loop. But it causes the label to
1145 be optimized away. */
1146 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1150 else if (GET_CODE (orig
) == CONST
)
1154 if (GET_CODE (XEXP (orig
, 0)) == PLUS
1155 && XEXP (XEXP (orig
, 0), 0) == tilegx_got_rtx ())
1160 gcc_assert (can_create_pseudo_p ());
1161 reg
= gen_reg_rtx (Pmode
);
1164 gcc_assert (GET_CODE (XEXP (orig
, 0)) == PLUS
);
1165 base
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 0),
1167 offset
= tilegx_legitimize_pic_address (XEXP (XEXP (orig
, 0), 1), Pmode
,
1168 base
== reg
? 0 : reg
);
1170 if (CONST_INT_P (offset
))
1172 if (can_create_pseudo_p ())
1173 offset
= force_reg (Pmode
, offset
);
1175 /* If we reach here, then something is seriously wrong. */
1179 if (can_create_pseudo_p ())
1180 return force_reg (Pmode
, gen_rtx_PLUS (Pmode
, base
, offset
));
1184 else if (GET_CODE (orig
) == LABEL_REF
)
1191 gcc_assert (can_create_pseudo_p ());
1192 reg
= gen_reg_rtx (Pmode
);
1195 /* If not during reload, allocate another temp reg here for
1196 loading in the address, so that these instructions can be
1197 optimized properly. */
1198 temp_reg
= create_temp_reg_if_possible (Pmode
, reg
);
1199 compute_pcrel_address (temp_reg
, orig
);
1201 /* Note: this is conservative. We use the text_label but we
1202 don't use the pic_offset_table. */
1203 crtl
->uses_pic_offset_table
= 1;
1207 emit_move_insn (reg
, address
);
1216 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1218 tilegx_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
1219 enum machine_mode mode
)
1221 if (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
1222 && symbolic_operand (x
, Pmode
) && tilegx_tls_referenced_p (x
))
1224 return tilegx_legitimize_tls_address (x
);
1228 return tilegx_legitimize_pic_address (x
, mode
, 0);
1235 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1237 tilegx_delegitimize_address (rtx x
)
1239 x
= delegitimize_mem_from_attrs (x
);
1241 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == UNSPEC
)
1243 switch (XINT (XEXP (x
, 0), 1))
1249 case UNSPEC_HW0_LAST
:
1250 case UNSPEC_HW1_LAST
:
1251 case UNSPEC_HW2_LAST
:
1252 case UNSPEC_HW0_PCREL
:
1253 case UNSPEC_HW1_LAST_PCREL
:
1254 case UNSPEC_HW0_GOT
:
1255 case UNSPEC_HW0_LAST_GOT
:
1256 case UNSPEC_HW1_LAST_GOT
:
1257 case UNSPEC_HW0_TLS_GD
:
1258 case UNSPEC_HW1_LAST_TLS_GD
:
1259 case UNSPEC_HW0_TLS_IE
:
1260 case UNSPEC_HW1_LAST_TLS_IE
:
1261 case UNSPEC_HW0_TLS_LE
:
1262 case UNSPEC_HW1_LAST_TLS_LE
:
1263 x
= XVECEXP (XEXP (x
, 0), 0, 0);
1272 /* Emit code to load the PIC register. */
1274 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED
)
1276 int orig_flag_pic
= flag_pic
;
1278 rtx got_symbol
= tilegx_got_symbol ();
1279 rtx text_label_symbol
= tilegx_text_label_symbol ();
1280 rtx text_label_rtx
= tilegx_text_label_rtx ();
1285 emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx
,
1286 text_label_symbol
));
1290 emit_insn (gen_insn_lnk_and_label (text_label_rtx
, text_label_symbol
));
1293 compute_pcrel_address (tilegx_got_rtx (), got_symbol
);
1295 flag_pic
= orig_flag_pic
;
1297 /* Need to emit this whether or not we obey regdecls, since
1298 setjmp/longjmp can cause life info to screw up. ??? In the case
1299 where we don't obey regdecls, this is not sufficient since we may
1300 not fall out the bottom. */
1301 emit_use (tilegx_got_rtx ());
1305 /* Return the simd variant of the constant NUM of mode MODE, by
1306 replicating it to fill an interger of mode DImode. NUM is first
1307 truncated to fit in MODE. */
1309 tilegx_simd_int (rtx num
, enum machine_mode mode
)
1311 HOST_WIDE_INT n
= 0;
1313 gcc_assert (CONST_INT_P (num
));
1320 n
= 0x0101010101010101LL
* (n
& 0x000000FF);
1323 n
= 0x0001000100010001LL
* (n
& 0x0000FFFF);
1326 n
= 0x0000000100000001LL
* (n
& 0xFFFFFFFF);
1338 /* Returns true iff VAL can be moved into a register in one
1339 instruction. And if it can, it emits the code to move the
1340 constant into DEST_REG.
1342 If THREE_WIDE_ONLY is true, this insists on an instruction that
1343 works in a bundle containing three instructions. */
1345 expand_set_cint64_one_inst (rtx dest_reg
,
1346 HOST_WIDE_INT val
, bool three_wide_only
)
1348 if (val
== trunc_int_for_mode (val
, QImode
))
1351 emit_move_insn (dest_reg
, GEN_INT (val
));
1354 else if (!three_wide_only
)
1356 rtx imm_op
= GEN_INT (val
);
1358 if (satisfies_constraint_J (imm_op
)
1359 || satisfies_constraint_K (imm_op
)
1360 || satisfies_constraint_N (imm_op
)
1361 || satisfies_constraint_P (imm_op
))
1363 emit_move_insn (dest_reg
, imm_op
);
1372 /* Implement DImode rotatert. */
1373 static HOST_WIDE_INT
1374 rotate_right (HOST_WIDE_INT n
, int count
)
1376 unsigned HOST_WIDE_INT x
= n
& 0xFFFFFFFFFFFFFFFFULL
;
1379 return ((x
>> count
) | (x
<< (64 - count
))) & 0xFFFFFFFFFFFFFFFFULL
;
1383 /* Return true iff n contains exactly one contiguous sequence of 1
1384 bits, possibly wrapping around from high bits to low bits. */
1386 tilegx_bitfield_operand_p (HOST_WIDE_INT n
, int *first_bit
, int *last_bit
)
1393 for (i
= 0; i
< 64; i
++)
1395 unsigned HOST_WIDE_INT x
= rotate_right (n
, i
);
1399 /* See if x is a power of two minus one, i.e. only consecutive 1
1400 bits starting from bit 0. */
1401 if ((x
& (x
+ 1)) == 0)
1403 if (first_bit
!= NULL
)
1405 if (last_bit
!= NULL
)
1406 *last_bit
= (i
+ exact_log2 (x
^ (x
>> 1))) & 63;
1416 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1418 expand_set_cint64 (rtx dest_reg
, rtx src_val
)
1421 int leading_zeroes
, trailing_zeroes
;
1422 int three_wide_only
;
1423 int shift
, ins_shift
, zero_cluster_shift
;
1426 gcc_assert (CONST_INT_P (src_val
));
1427 val
= trunc_int_for_mode (INTVAL (src_val
), GET_MODE (dest_reg
));
1429 /* See if we can generate the constant in one instruction. */
1430 if (expand_set_cint64_one_inst (dest_reg
, val
, false))
1433 /* Force the destination to DImode so we can use DImode instructions
1434 to create it. This both allows instructions like rotl, and
1435 certain efficient 3-wide instructions. */
1436 subreg
= simplify_gen_subreg (DImode
, dest_reg
, GET_MODE (dest_reg
), 0);
1437 gcc_assert (subreg
!= NULL
);
1440 temp
= create_temp_reg_if_possible (DImode
, dest_reg
);
1442 leading_zeroes
= 63 - floor_log2 (val
& 0xFFFFFFFFFFFFFFFFULL
);
1443 trailing_zeroes
= exact_log2 (val
& -val
);
1445 /* First try all three-wide instructions that generate a constant
1446 (i.e. movei) followed by various shifts and rotates. If none of
1447 those work, try various two-wide ways of generating a constant
1448 followed by various shifts and rotates. */
1449 for (three_wide_only
= 1; three_wide_only
>= 0; three_wide_only
--)
1453 if (expand_set_cint64_one_inst (temp
, val
>> trailing_zeroes
,
1456 /* 0xFFFFFFFFFFFFA500 becomes:
1457 movei temp, 0xFFFFFFFFFFFFFFA5
1458 shli dest, temp, 8 */
1459 emit_move_insn (dest_reg
,
1460 gen_rtx_ASHIFT (DImode
, temp
,
1461 GEN_INT (trailing_zeroes
)));
1465 if (expand_set_cint64_one_inst (temp
, val
<< leading_zeroes
,
1468 /* 0x7FFFFFFFFFFFFFFF becomes:
1470 shrui dest, temp, 1 */
1471 emit_move_insn (dest_reg
,
1472 gen_rtx_LSHIFTRT (DImode
, temp
,
1473 GEN_INT (leading_zeroes
)));
1477 /* Try rotating a one-instruction immediate. */
1478 for (count
= 1; count
< 64; count
++)
1480 HOST_WIDE_INT r
= rotate_right (val
, count
);
1481 if (expand_set_cint64_one_inst (temp
, r
, three_wide_only
))
1483 /* 0xFFFFFFFFFFA5FFFF becomes:
1484 movei temp, 0xFFFFFFFFFFFFFFA5
1485 rotli dest, temp, 16 */
1486 emit_move_insn (dest_reg
,
1487 gen_rtx_ROTATE (DImode
, temp
, GEN_INT (count
)));
1493 /* There are two cases here to produce a large constant.
1494 In the most general case, we do this:
1497 shl16insli x, x, hw2(NUM)
1498 shl16insli x, x, hw1(NUM)
1499 shl16insli x, x, hw0(NUM)
1501 However, we can sometimes do better. shl16insli is a poor way to
1502 insert 16 zero bits, because simply shifting left by 16 has more
1503 bundling freedom. So if we see any contiguous aligned sequence
1504 of 16 or more zero bits (below the highest set bit), it is always
1505 more efficient to materialize the bits above the zero bits, then
1506 left shift to put in the zeroes, then insert whatever bits
1507 remain. For example, we might end up with:
1509 movei x, NUM >> (37 + 16)
1511 shl16insli x, x, hw0(NUM) */
1513 zero_cluster_shift
= -1;
1515 for (shift
= 0; shift
< 48 - leading_zeroes
; shift
+= 16)
1517 HOST_WIDE_INT x
= val
>> shift
;
1519 /* Find the least significant group of 16 aligned zero bits. */
1520 if ((x
& 0xFFFF) == 0x0000)
1522 /* Grab any following zero bits as well. */
1523 zero_cluster_shift
= exact_log2 (x
& -x
);
1524 shift
+= zero_cluster_shift
;
1529 if (zero_cluster_shift
>= 0)
1531 unsigned HOST_WIDE_INT leftover
;
1533 /* Recursively create the constant above the lowest 16 zero
1535 expand_set_cint64 (temp
, GEN_INT (val
>> shift
));
1537 /* See if we can easily insert the remaining bits, or if we need
1538 to fall through to the more general case. */
1539 leftover
= val
- ((val
>> shift
) << shift
);
1542 /* A simple left shift is enough. */
1543 emit_move_insn (dest_reg
,
1544 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1547 else if (leftover
<= 32767)
1549 /* Left shift into position then add in the leftover. */
1550 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1551 emit_move_insn (temp2
,
1552 gen_rtx_ASHIFT (DImode
, temp
, GEN_INT (shift
)));
1553 emit_move_insn (dest_reg
,
1554 gen_rtx_PLUS (DImode
, temp2
, GEN_INT (leftover
)));
1559 /* Shift in the batch of >= 16 zeroes we detected earlier.
1560 After this, shift will be aligned mod 16 so the final
1561 loop can use shl16insli. */
1562 rtx temp2
= create_temp_reg_if_possible (DImode
, temp
);
1563 rtx shift_count_rtx
= GEN_INT (zero_cluster_shift
);
1565 emit_move_insn (temp2
,
1566 gen_rtx_ASHIFT (DImode
, temp
, shift_count_rtx
));
1568 shift
-= zero_cluster_shift
;
1574 /* Set as many high 16-bit blocks as we can with a single
1575 instruction. We'll insert the remaining 16-bit blocks
1577 for (shift
= 16;; shift
+= 16)
1579 gcc_assert (shift
< 64);
1580 if (expand_set_cint64_one_inst (temp
, val
>> shift
, false))
1585 /* At this point, temp == val >> shift, shift % 16 == 0, and we
1586 still need to insert any bits of 'val' below 'shift'. Those bits
1587 are guaranteed to not have 16 contiguous zeroes. */
1589 gcc_assert ((shift
& 15) == 0);
1591 for (ins_shift
= shift
- 16; ins_shift
>= 0; ins_shift
-= 16)
1594 HOST_WIDE_INT bits
= (val
>> ins_shift
) & 0xFFFF;
1595 gcc_assert (bits
!= 0);
1597 /* On the last iteration we need to store into dest_reg. */
1601 result
= create_temp_reg_if_possible (DImode
, dest_reg
);
1603 emit_insn (gen_insn_shl16insli (result
, temp
, GEN_INT (bits
)));
1610 /* Load OP1, a 64-bit constant, into OP0, a register. We know it
1611 can't be done in one insn when we get here, the move expander
1614 tilegx_expand_set_const64 (rtx op0
, rtx op1
)
1616 if (CONST_INT_P (op1
))
1618 /* TODO: I don't know if we want to split large constants
1619 now, or wait until later (with a define_split).
1621 Does splitting early help CSE? Does it harm other
1622 optimizations that might fold loads? */
1623 expand_set_cint64 (op0
, op1
);
1627 rtx temp
= create_temp_reg_if_possible (Pmode
, op0
);
1631 /* Generate the 2-insn sequence to materialize a symbolic
1633 emit_insn (gen_mov_address_32bit_step1 (temp
, op1
));
1634 emit_insn (gen_mov_address_32bit_step2 (op0
, temp
, op1
));
1638 /* Generate the 3-insn sequence to materialize a symbolic
1639 address. Note that this assumes that virtual addresses
1640 fit in 48 signed bits, which is currently true. */
1641 rtx temp2
= create_temp_reg_if_possible (Pmode
, op0
);
1642 emit_insn (gen_mov_address_step1 (temp
, op1
));
1643 emit_insn (gen_mov_address_step2 (temp2
, temp
, op1
));
1644 emit_insn (gen_mov_address_step3 (op0
, temp2
, op1
));
1650 /* Expand a move instruction. Return true if all work is done. */
1652 tilegx_expand_mov (enum machine_mode mode
, rtx
*operands
)
1654 /* Handle sets of MEM first. */
1655 if (MEM_P (operands
[0]))
1657 if (can_create_pseudo_p ())
1658 operands
[0] = validize_mem (operands
[0]);
1660 if (reg_or_0_operand (operands
[1], mode
))
1663 if (!reload_in_progress
)
1664 operands
[1] = force_reg (mode
, operands
[1]);
1667 /* Fixup TLS cases. */
1668 if (CONSTANT_P (operands
[1]) && tilegx_tls_referenced_p (operands
[1]))
1670 operands
[1] = tilegx_legitimize_tls_address (operands
[1]);
1674 /* Fixup PIC cases. */
1675 if (flag_pic
&& CONSTANT_P (operands
[1]))
1677 if (tilegx_pic_address_needs_scratch (operands
[1]))
1678 operands
[1] = tilegx_legitimize_pic_address (operands
[1], mode
, 0);
1680 if (symbolic_operand (operands
[1], mode
))
1682 operands
[1] = tilegx_legitimize_pic_address (operands
[1],
1684 (reload_in_progress
?
1691 /* Accept non-constants and valid constants unmodified. */
1692 if (!CONSTANT_P (operands
[1]) || move_operand (operands
[1], mode
))
1695 /* Split large integers. */
1696 tilegx_expand_set_const64 (operands
[0], operands
[1]);
1701 /* Expand unaligned loads. */
1703 tilegx_expand_unaligned_load (rtx dest_reg
, rtx mem
, HOST_WIDE_INT bitsize
,
1704 HOST_WIDE_INT bit_offset
, bool sign
)
1706 enum machine_mode mode
;
1707 rtx addr_lo
, addr_hi
;
1708 rtx mem_lo
, mem_hi
, hi
;
1709 rtx mema
, wide_result
;
1710 int last_byte_offset
;
1711 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1713 mode
= GET_MODE (dest_reg
);
1715 hi
= gen_reg_rtx (mode
);
1717 if (bitsize
== 2 * BITS_PER_UNIT
&& (bit_offset
% BITS_PER_UNIT
) == 0)
1719 /* When just loading a two byte value, we can load the two bytes
1720 individually and combine them efficiently. */
1722 mem_lo
= adjust_address (mem
, QImode
, byte_offset
);
1723 mem_hi
= adjust_address (mem
, QImode
, byte_offset
+ 1);
1727 /* Do a signed load of the second byte and use bfins to set
1728 the high bits of the result. */
1729 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, dest_reg
),
1731 emit_insn (gen_extendqidi2 (gen_lowpart (DImode
, hi
), mem_hi
));
1732 emit_insn (gen_insv (gen_lowpart (DImode
, dest_reg
),
1733 GEN_INT (64 - 8), GEN_INT (8),
1734 gen_lowpart (DImode
, hi
)));
1738 /* Do two unsigned loads and use v1int_l to interleave
1740 rtx lo
= gen_reg_rtx (mode
);
1741 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, lo
),
1743 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode
, hi
),
1745 emit_insn (gen_insn_v1int_l (gen_lowpart (DImode
, dest_reg
),
1746 gen_lowpart (DImode
, hi
),
1747 gen_lowpart (DImode
, lo
)));
1753 mema
= XEXP (mem
, 0);
1755 /* AND addresses cannot be in any alias set, since they may
1756 implicitly alias surrounding code. Ideally we'd have some alias
1757 set that covered all types except those with alignment 8 or
1759 addr_lo
= force_reg (Pmode
, plus_constant (Pmode
, mema
, byte_offset
));
1760 mem_lo
= change_address (mem
, mode
,
1761 gen_rtx_AND (GET_MODE (mema
), addr_lo
,
1763 set_mem_alias_set (mem_lo
, 0);
1765 /* Load the high word at an address that will not fault if the low
1766 address is aligned and at the very end of a page. */
1767 last_byte_offset
= (bit_offset
+ bitsize
- 1) / BITS_PER_UNIT
;
1768 addr_hi
= force_reg (Pmode
, plus_constant (Pmode
, mema
, last_byte_offset
));
1769 mem_hi
= change_address (mem
, mode
,
1770 gen_rtx_AND (GET_MODE (mema
), addr_hi
,
1772 set_mem_alias_set (mem_hi
, 0);
1776 addr_lo
= make_safe_from (addr_lo
, dest_reg
);
1777 wide_result
= dest_reg
;
1781 wide_result
= gen_reg_rtx (mode
);
1784 /* Load hi first in case dest_reg is used in mema. */
1785 emit_move_insn (hi
, mem_hi
);
1786 emit_move_insn (wide_result
, mem_lo
);
1788 emit_insn (gen_insn_dblalign (gen_lowpart (DImode
, wide_result
),
1789 gen_lowpart (DImode
, wide_result
),
1790 gen_lowpart (DImode
, hi
), addr_lo
));
1795 extract_bit_field (gen_lowpart (DImode
, wide_result
),
1796 bitsize
, bit_offset
% BITS_PER_UNIT
,
1797 !sign
, false, gen_lowpart (DImode
, dest_reg
),
1800 if (extracted
!= dest_reg
)
1801 emit_move_insn (dest_reg
, gen_lowpart (DImode
, extracted
));
1806 /* Expand unaligned stores. */
1808 tilegx_expand_unaligned_store (rtx mem
, rtx src
, HOST_WIDE_INT bitsize
,
1809 HOST_WIDE_INT bit_offset
)
1811 HOST_WIDE_INT byte_offset
= bit_offset
/ BITS_PER_UNIT
;
1812 HOST_WIDE_INT bytesize
= bitsize
/ BITS_PER_UNIT
;
1813 HOST_WIDE_INT shift_amt
;
1818 for (i
= 0, shift_amt
= 0; i
< bytesize
; i
++, shift_amt
+= BITS_PER_UNIT
)
1820 mem_addr
= adjust_address (mem
, QImode
, byte_offset
+ i
);
1824 store_val
= expand_simple_binop (DImode
, LSHIFTRT
,
1825 gen_lowpart (DImode
, src
),
1826 GEN_INT (shift_amt
), NULL
, 1,
1828 store_val
= gen_lowpart (QImode
, store_val
);
1832 store_val
= gen_lowpart (QImode
, src
);
1835 emit_move_insn (mem_addr
, store_val
);
1840 /* Implement the movmisalign patterns. One of the operands is a
1841 memory that is not naturally aligned. Emit instructions to load
1844 tilegx_expand_movmisalign (enum machine_mode mode
, rtx
*operands
)
1846 if (MEM_P (operands
[1]))
1850 if (register_operand (operands
[0], mode
))
1853 tmp
= gen_reg_rtx (mode
);
1855 tilegx_expand_unaligned_load (tmp
, operands
[1], GET_MODE_BITSIZE (mode
),
1858 if (tmp
!= operands
[0])
1859 emit_move_insn (operands
[0], tmp
);
1861 else if (MEM_P (operands
[0]))
1863 if (!reg_or_0_operand (operands
[1], mode
))
1864 operands
[1] = force_reg (mode
, operands
[1]);
1866 tilegx_expand_unaligned_store (operands
[0], operands
[1],
1867 GET_MODE_BITSIZE (mode
), 0);
1875 /* Implement the allocate_stack pattern (alloca). */
1877 tilegx_allocate_stack (rtx op0
, rtx op1
)
1879 /* Technically the correct way to initialize chain_loc is with
1880 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
1881 * sets the alias_set to that of a frame reference. Some of our
1882 * tests rely on some unsafe assumption about when the chaining
1883 * update is done, we need to be conservative about reordering the
1884 * chaining instructions.
1886 rtx fp_addr
= gen_reg_rtx (Pmode
);
1887 rtx fp_value
= gen_reg_rtx (Pmode
);
1890 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
1891 GEN_INT (UNITS_PER_WORD
)));
1893 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
1895 emit_move_insn (fp_value
, fp_loc
);
1897 op1
= force_reg (Pmode
, op1
);
1899 emit_move_insn (stack_pointer_rtx
,
1900 gen_rtx_MINUS (Pmode
, stack_pointer_rtx
, op1
));
1902 emit_move_insn (fp_addr
, gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
1903 GEN_INT (UNITS_PER_WORD
)));
1905 fp_loc
= gen_frame_mem (Pmode
, fp_addr
);
1907 emit_move_insn (fp_loc
, fp_value
);
1909 emit_move_insn (op0
, virtual_stack_dynamic_rtx
);
1917 /* Returns the insn_code in ENTRY. */
1918 static enum insn_code
1919 tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry
1922 return tilegx_multiply_insn_seq_decode_opcode
[entry
->compressed_opcode
];
1926 /* Returns the length of the 'op' array. */
1928 tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq
*seq
)
1930 /* The array either uses all of its allocated slots or is terminated
1931 by a bogus opcode. Either way, the array size is the index of the
1932 last valid opcode plus one. */
1934 for (i
= tilegx_multiply_insn_seq_MAX_OPERATIONS
- 1; i
>= 0; i
--)
1935 if (tilegx_multiply_get_opcode (&seq
->op
[i
]) != CODE_FOR_nothing
)
1938 /* An empty array is not allowed. */
1943 /* We precompute a number of expression trees for multiplying by
1944 constants. This generates code for such an expression tree by
1945 walking through the nodes in the tree (which are conveniently
1946 pre-linearized) and emitting an instruction for each one. */
1948 tilegx_expand_constant_multiply_given_sequence (rtx result
, rtx src
,
1950 tilegx_multiply_insn_seq
*seq
)
1955 /* Keep track of the subexpressions computed so far, so later
1956 instructions can refer to them. We seed the array with zero and
1957 the value being multiplied. */
1958 int num_subexprs
= 2;
1959 rtx subexprs
[tilegx_multiply_insn_seq_MAX_OPERATIONS
+ 2];
1960 subexprs
[0] = const0_rtx
;
1963 /* Determine how many instructions we are going to generate. */
1964 num_ops
= tilegx_multiply_get_num_ops (seq
);
1965 gcc_assert (num_ops
> 0
1966 && num_ops
<= tilegx_multiply_insn_seq_MAX_OPERATIONS
);
1968 for (i
= 0; i
< num_ops
; i
++)
1970 const struct tilegx_multiply_insn_seq_entry
*entry
= &seq
->op
[i
];
1972 /* Figure out where to store the output of this instruction. */
1973 const bool is_last_op
= (i
+ 1 == num_ops
);
1974 rtx out
= is_last_op
? result
: gen_reg_rtx (DImode
);
1976 enum insn_code opcode
= tilegx_multiply_get_opcode (entry
);
1977 if (opcode
== CODE_FOR_ashldi3
)
1979 /* Handle shift by immediate. This is a special case because
1980 the meaning of the second operand is a constant shift
1981 count rather than an operand index. */
1983 /* Make sure the shift count is in range. Zero should not
1985 const int shift_count
= entry
->rhs
;
1986 gcc_assert (shift_count
> 0 && shift_count
< 64);
1988 /* Emit the actual instruction. */
1989 emit_insn (GEN_FCN (opcode
)
1990 (out
, subexprs
[entry
->lhs
],
1991 gen_rtx_CONST_INT (DImode
, shift_count
)));
1995 /* Handle a normal two-operand instruction, such as add or
1998 /* Make sure we are referring to a previously computed
2000 gcc_assert (entry
->rhs
< num_subexprs
);
2002 /* Emit the actual instruction. */
2003 emit_insn (GEN_FCN (opcode
)
2004 (out
, subexprs
[entry
->lhs
], subexprs
[entry
->rhs
]));
2007 /* Record this subexpression for use by later expressions. */
2008 subexprs
[num_subexprs
++] = out
;
2013 /* bsearch helper function. */
2015 tilegx_compare_multipliers (const void *key
, const void *t
)
2018 (*(const long long *) key
2019 - ((const struct tilegx_multiply_insn_seq
*) t
)->multiplier
);
2020 return (delta
< 0) ? -1 : (delta
> 0);
2024 /* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none
2026 static const struct tilegx_multiply_insn_seq
*
2027 tilegx_find_multiply_insn_seq_for_constant (long long multiplier
)
2029 return ((const struct tilegx_multiply_insn_seq
*)
2030 bsearch (&multiplier
, tilegx_multiply_insn_seq_table
,
2031 tilegx_multiply_insn_seq_table_size
,
2032 sizeof tilegx_multiply_insn_seq_table
[0],
2033 tilegx_compare_multipliers
));
2037 /* Try to a expand constant multiply in DImode by looking it up in a
2038 precompiled table. OP0 is the result operand, OP1 is the source
2039 operand, and MULTIPLIER is the value of the constant. Return true
2042 tilegx_expand_const_muldi (rtx op0
, rtx op1
, long long multiplier
)
2044 /* See if we have precomputed an efficient way to multiply by this
2046 const struct tilegx_multiply_insn_seq
*seq
=
2047 tilegx_find_multiply_insn_seq_for_constant (multiplier
);
2050 tilegx_expand_constant_multiply_given_sequence (op0
, op1
, seq
);
2057 /* Expand the muldi pattern. */
2059 tilegx_expand_muldi (rtx op0
, rtx op1
, rtx op2
)
2061 if (CONST_INT_P (op2
))
2063 HOST_WIDE_INT n
= trunc_int_for_mode (INTVAL (op2
), DImode
);
2064 return tilegx_expand_const_muldi (op0
, op1
, n
);
2070 /* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the
2071 operands, and SIGN is true if it's a signed multiply, and false if
2072 it's an unsigned multiply. */
2074 tilegx_expand_high_multiply (rtx result
, rtx op1
, rtx op2
, bool sign
)
2076 rtx tmp0
= gen_reg_rtx (DImode
);
2077 rtx tmp1
= gen_reg_rtx (DImode
);
2078 rtx tmp2
= gen_reg_rtx (DImode
);
2079 rtx tmp3
= gen_reg_rtx (DImode
);
2080 rtx tmp4
= gen_reg_rtx (DImode
);
2081 rtx tmp5
= gen_reg_rtx (DImode
);
2082 rtx tmp6
= gen_reg_rtx (DImode
);
2083 rtx tmp7
= gen_reg_rtx (DImode
);
2084 rtx tmp8
= gen_reg_rtx (DImode
);
2085 rtx tmp9
= gen_reg_rtx (DImode
);
2086 rtx tmp10
= gen_reg_rtx (DImode
);
2087 rtx tmp11
= gen_reg_rtx (DImode
);
2088 rtx tmp12
= gen_reg_rtx (DImode
);
2089 rtx tmp13
= gen_reg_rtx (DImode
);
2090 rtx result_lo
= gen_reg_rtx (DImode
);
2094 emit_insn (gen_insn_mul_hs_lu (tmp0
, op1
, op2
));
2095 emit_insn (gen_insn_mul_hs_lu (tmp1
, op2
, op1
));
2096 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2097 emit_insn (gen_insn_mul_hs_hs (tmp3
, op1
, op2
));
2101 emit_insn (gen_insn_mul_hu_lu (tmp0
, op1
, op2
));
2102 emit_insn (gen_insn_mul_hu_lu (tmp1
, op2
, op1
));
2103 emit_insn (gen_insn_mul_lu_lu (tmp2
, op1
, op2
));
2104 emit_insn (gen_insn_mul_hu_hu (tmp3
, op1
, op2
));
2107 emit_move_insn (tmp4
, (gen_rtx_ASHIFT (DImode
, tmp0
, GEN_INT (32))));
2109 emit_move_insn (tmp5
, (gen_rtx_ASHIFT (DImode
, tmp1
, GEN_INT (32))));
2111 emit_move_insn (tmp6
, (gen_rtx_PLUS (DImode
, tmp4
, tmp5
)));
2112 emit_move_insn (result_lo
, (gen_rtx_PLUS (DImode
, tmp2
, tmp6
)));
2114 emit_move_insn (tmp7
, gen_rtx_LTU (DImode
, tmp6
, tmp4
));
2115 emit_move_insn (tmp8
, gen_rtx_LTU (DImode
, result_lo
, tmp2
));
2119 emit_move_insn (tmp9
, (gen_rtx_ASHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2120 emit_move_insn (tmp10
, (gen_rtx_ASHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2124 emit_move_insn (tmp9
, (gen_rtx_LSHIFTRT (DImode
, tmp0
, GEN_INT (32))));
2125 emit_move_insn (tmp10
, (gen_rtx_LSHIFTRT (DImode
, tmp1
, GEN_INT (32))));
2128 emit_move_insn (tmp11
, (gen_rtx_PLUS (DImode
, tmp3
, tmp7
)));
2129 emit_move_insn (tmp12
, (gen_rtx_PLUS (DImode
, tmp8
, tmp9
)));
2130 emit_move_insn (tmp13
, (gen_rtx_PLUS (DImode
, tmp11
, tmp12
)));
2131 emit_move_insn (result
, (gen_rtx_PLUS (DImode
, tmp13
, tmp10
)));
2135 /* Implement smuldi3_highpart. */
2137 tilegx_expand_smuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2139 tilegx_expand_high_multiply (op0
, op1
, op2
, true);
2143 /* Implement umuldi3_highpart. */
2145 tilegx_expand_umuldi3_highpart (rtx op0
, rtx op1
, rtx op2
)
2147 tilegx_expand_high_multiply (op0
, op1
, op2
, false);
2152 /* Compare and branches */
2154 /* Produce the rtx yielding a bool for a floating point
2157 tilegx_emit_fp_setcc (rtx res
, enum rtx_code code
, enum machine_mode mode
,
2160 /* TODO: Certain compares again constants can be done using entirely
2161 integer operations. But you have to get the special cases right
2162 e.g. NaN, +0 == -0, etc. */
2166 rtx a
= force_reg (DImode
, gen_lowpart (DImode
, op0
));
2167 rtx b
= force_reg (DImode
, gen_lowpart (DImode
, op1
));
2169 flags
= gen_reg_rtx (DImode
);
2173 emit_insn (gen_insn_fsingle_add1 (flags
, a
, b
));
2177 gcc_assert (mode
== DFmode
);
2178 emit_insn (gen_insn_fdouble_add_flags (flags
, a
, b
));
2183 case EQ
: flag_index
= 30; break;
2184 case NE
: flag_index
= 31; break;
2185 case LE
: flag_index
= 27; break;
2186 case LT
: flag_index
= 26; break;
2187 case GE
: flag_index
= 29; break;
2188 case GT
: flag_index
= 28; break;
2189 default: gcc_unreachable ();
2192 gcc_assert (GET_MODE (res
) == DImode
);
2193 emit_move_insn (res
, gen_rtx_ZERO_EXTRACT (DImode
, flags
, GEN_INT (1),
2194 GEN_INT (flag_index
)));
2199 /* Certain simplifications can be done to make invalid setcc
2200 operations valid. Return the final comparison, or NULL if we can't
2203 tilegx_emit_setcc_internal (rtx res
, enum rtx_code code
, rtx op0
, rtx op1
,
2204 enum machine_mode cmp_mode
)
2209 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2210 return tilegx_emit_fp_setcc (res
, code
, cmp_mode
, op0
, op1
);
2212 /* The general case: fold the comparison code to the types of
2213 compares that we have, choosing the branch as necessary. */
2223 /* We have these compares. */
2230 /* We do not have these compares, so we reverse the
2236 /* We should not have called this with any other code. */
2242 code
= swap_condition (code
);
2243 tmp
= op0
, op0
= op1
, op1
= tmp
;
2246 if (!reg_or_0_operand (op0
, cmp_mode
))
2247 op0
= force_reg (cmp_mode
, op0
);
2249 if (!CONST_INT_P (op1
) && !register_operand (op1
, cmp_mode
))
2250 op1
= force_reg (cmp_mode
, op1
);
2252 /* Return the setcc comparison. */
2253 emit_insn (gen_rtx_SET (VOIDmode
, res
,
2254 gen_rtx_fmt_ee (code
, DImode
, op0
, op1
)));
2260 /* Implement cstore patterns. */
2262 tilegx_emit_setcc (rtx operands
[], enum machine_mode cmp_mode
)
2265 tilegx_emit_setcc_internal (operands
[0], GET_CODE (operands
[1]),
2266 operands
[2], operands
[3], cmp_mode
);
2270 /* Return whether CODE is a signed comparison. */
2272 signed_compare_p (enum rtx_code code
)
2274 return (code
== EQ
|| code
== NE
|| code
== LT
|| code
== LE
2275 || code
== GT
|| code
== GE
);
2279 /* Generate the comparison for a DImode conditional branch. */
2281 tilegx_emit_cc_test (enum rtx_code code
, rtx op0
, rtx op1
,
2282 enum machine_mode cmp_mode
, bool eq_ne_only
)
2284 enum rtx_code branch_code
;
2287 if (cmp_mode
== SFmode
|| cmp_mode
== DFmode
)
2289 /* Compute a boolean saying whether the comparison is true. */
2290 temp
= gen_reg_rtx (DImode
);
2291 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2293 /* Test that flag. */
2294 return gen_rtx_fmt_ee (NE
, VOIDmode
, temp
, const0_rtx
);
2297 /* Check for a compare against zero using a comparison we can do
2299 if (op1
== const0_rtx
2300 && (code
== EQ
|| code
== NE
2301 || (!eq_ne_only
&& signed_compare_p (code
))))
2303 op0
= force_reg (cmp_mode
, op0
);
2304 return gen_rtx_fmt_ee (code
, VOIDmode
, op0
, const0_rtx
);
2307 /* The general case: fold the comparison code to the types of
2308 compares that we have, choosing the branch as necessary. */
2316 /* We have these compares. */
2325 /* These must be reversed (except NE, but let's
2327 code
= reverse_condition (code
);
2335 if (CONST_INT_P (op1
) && (!satisfies_constraint_I (op1
) || code
== LEU
))
2337 HOST_WIDE_INT n
= INTVAL (op1
);
2342 /* Subtract off the value we want to compare against and see
2343 if we get zero. This is cheaper than creating a constant
2344 in a register. Except that subtracting -128 is more
2345 expensive than seqi to -128, so we leave that alone. */
2346 /* ??? Don't do this when comparing against symbols,
2347 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2348 0), which will be declared false out of hand (at least
2351 && add_operand (GEN_INT (-n
), DImode
)
2352 && !(symbolic_operand (op0
, VOIDmode
)
2353 || (REG_P (op0
) && REG_POINTER (op0
))))
2355 /* TODO: Use a SIMD add immediate to hit zero for tiled
2356 constants in a single instruction. */
2357 if (GET_MODE (op0
) != DImode
)
2359 /* Convert to DImode so we can use addli. Note that
2360 this will not actually generate any code because
2361 sign extension from SI -> DI is a no-op. I don't
2362 know if it's safe just to make a paradoxical
2363 subreg here though. */
2364 rtx temp2
= gen_reg_rtx (DImode
);
2365 emit_insn (gen_extendsidi2 (temp2
, op0
));
2370 op0
= force_reg (DImode
, op0
);
2372 temp
= gen_reg_rtx (DImode
);
2373 emit_move_insn (temp
, gen_rtx_PLUS (DImode
, op0
, GEN_INT (-n
)));
2374 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2375 VOIDmode
, temp
, const0_rtx
);
2385 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2386 We use arithmetic shift right because it's a 3-wide op,
2387 while logical shift right is not. */
2389 int first
= exact_log2 (code
== LTU
? n
: n
+ 1);
2392 op0
= force_reg (cmp_mode
, op0
);
2393 temp
= gen_reg_rtx (cmp_mode
);
2394 emit_move_insn (temp
,
2395 gen_rtx_ASHIFTRT (cmp_mode
, op0
,
2397 return gen_rtx_fmt_ee (reverse_condition (branch_code
),
2398 VOIDmode
, temp
, const0_rtx
);
2408 /* Compute a flag saying whether we should branch. */
2409 temp
= gen_reg_rtx (DImode
);
2410 tilegx_emit_setcc_internal (temp
, code
, op0
, op1
, cmp_mode
);
2412 /* Return the branch comparison. */
2413 return gen_rtx_fmt_ee (branch_code
, VOIDmode
, temp
, const0_rtx
);
2417 /* Generate the comparison for a conditional branch. */
2419 tilegx_emit_conditional_branch (rtx operands
[], enum machine_mode cmp_mode
)
2422 tilegx_emit_cc_test (GET_CODE (operands
[0]), operands
[1], operands
[2],
2424 rtx branch_rtx
= gen_rtx_SET (VOIDmode
, pc_rtx
,
2425 gen_rtx_IF_THEN_ELSE (VOIDmode
, cmp_rtx
,
2430 emit_jump_insn (branch_rtx
);
2434 /* Implement the mov<mode>cc pattern. */
2436 tilegx_emit_conditional_move (rtx cmp
)
2439 tilegx_emit_cc_test (GET_CODE (cmp
), XEXP (cmp
, 0), XEXP (cmp
, 1),
2440 GET_MODE (XEXP (cmp
, 0)), true);
2444 /* Return true if INSN is annotated with a REG_BR_PROB note that
2445 indicates it's a branch that's predicted taken. */
2447 cbranch_predicted_p (rtx insn
)
2449 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2453 int pred_val
= INTVAL (XEXP (x
, 0));
2455 return pred_val
>= REG_BR_PROB_BASE
/ 2;
2462 /* Output assembly code for a specific branch instruction, appending
2463 the branch prediction flag to the opcode if appropriate. */
2465 tilegx_output_simple_cbranch_with_opcode (rtx insn
, const char *opcode
,
2466 int regop
, bool reverse_predicted
)
2468 static char buf
[64];
2469 sprintf (buf
, "%s%s\t%%r%d, %%l0", opcode
,
2470 (cbranch_predicted_p (insn
) ^ reverse_predicted
) ? "t" : "",
2476 /* Output assembly code for a specific branch instruction, appending
2477 the branch prediction flag to the opcode if appropriate. */
2479 tilegx_output_cbranch_with_opcode (rtx insn
, rtx
*operands
,
2481 const char *rev_opcode
, int regop
)
2483 const char *branch_if_false
;
2484 rtx taken
, not_taken
;
2485 bool is_simple_branch
;
2487 gcc_assert (LABEL_P (operands
[0]));
2489 is_simple_branch
= true;
2490 if (INSN_ADDRESSES_SET_P ())
2492 int from_addr
= INSN_ADDRESSES (INSN_UID (insn
));
2493 int to_addr
= INSN_ADDRESSES (INSN_UID (operands
[0]));
2494 int delta
= to_addr
- from_addr
;
2495 is_simple_branch
= IN_RANGE (delta
, -524288, 524280);
2498 if (is_simple_branch
)
2500 /* Just a simple conditional branch. */
2502 tilegx_output_simple_cbranch_with_opcode (insn
, opcode
, regop
, false);
2505 /* Generate a reversed branch around a direct jump. This fallback
2506 does not use branch-likely instructions. */
2507 not_taken
= gen_label_rtx ();
2508 taken
= operands
[0];
2510 /* Generate the reversed branch to NOT_TAKEN. */
2511 operands
[0] = not_taken
;
2513 tilegx_output_simple_cbranch_with_opcode (insn
, rev_opcode
, regop
, true);
2514 output_asm_insn (branch_if_false
, operands
);
2516 output_asm_insn ("j\t%l0", &taken
);
2518 /* Output NOT_TAKEN. */
2519 targetm
.asm_out
.internal_label (asm_out_file
, "L",
2520 CODE_LABEL_NUMBER (not_taken
));
2525 /* Output assembly code for a conditional branch instruction. */
2527 tilegx_output_cbranch (rtx insn
, rtx
*operands
, bool reversed
)
2529 enum rtx_code code
= GET_CODE (operands
[1]);
2531 const char *rev_opcode
;
2534 code
= reverse_condition (code
);
2540 rev_opcode
= "beqz";
2544 rev_opcode
= "bnez";
2548 rev_opcode
= "bltz";
2552 rev_opcode
= "blez";
2556 rev_opcode
= "bgtz";
2560 rev_opcode
= "bgez";
2566 return tilegx_output_cbranch_with_opcode (insn
, operands
, opcode
,
2571 /* Implement the tablejump pattern. */
2573 tilegx_expand_tablejump (rtx op0
, rtx op1
)
2577 rtx temp
= gen_reg_rtx (Pmode
);
2578 rtx temp2
= gen_reg_rtx (Pmode
);
2580 compute_pcrel_address (temp
, gen_rtx_LABEL_REF (Pmode
, op1
));
2581 emit_move_insn (temp2
,
2582 gen_rtx_PLUS (Pmode
,
2583 convert_to_mode (Pmode
, op0
, false),
2588 emit_jump_insn (gen_tablejump_aux (op0
, op1
));
2592 /* Emit barrier before an atomic, as needed for the memory MODEL. */
2594 tilegx_pre_atomic_barrier (enum memmodel model
)
2596 if (need_atomic_barrier_p (model
, true))
2597 emit_insn (gen_memory_barrier ());
2601 /* Emit barrier after an atomic, as needed for the memory MODEL. */
2603 tilegx_post_atomic_barrier (enum memmodel model
)
2605 if (need_atomic_barrier_p (model
, false))
2606 emit_insn (gen_memory_barrier ());
2611 /* Expand a builtin vector binary op, by calling gen function GEN with
2612 operands in the proper modes. DEST is converted to DEST_MODE, and
2613 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2615 tilegx_expand_builtin_vector_binop (rtx (*gen
) (rtx
, rtx
, rtx
),
2616 enum machine_mode dest_mode
,
2618 enum machine_mode src_mode
,
2619 rtx src0
, rtx src1
, bool do_src1
)
2621 dest
= gen_lowpart (dest_mode
, dest
);
2623 if (src0
== const0_rtx
)
2624 src0
= CONST0_RTX (src_mode
);
2626 src0
= gen_lowpart (src_mode
, src0
);
2630 if (src1
== const0_rtx
)
2631 src1
= CONST0_RTX (src_mode
);
2633 src1
= gen_lowpart (src_mode
, src1
);
2636 emit_insn ((*gen
) (dest
, src0
, src1
));
2644 struct tile_builtin_info
2646 enum insn_code icode
;
2650 static struct tile_builtin_info tilegx_builtin_info
[TILEGX_BUILTIN_max
] = {
2651 { CODE_FOR_adddi3
, NULL
}, /* add */
2652 { CODE_FOR_addsi3
, NULL
}, /* addx */
2653 { CODE_FOR_ssaddsi3
, NULL
}, /* addxsc */
2654 { CODE_FOR_anddi3
, NULL
}, /* and */
2655 { CODE_FOR_insn_bfexts
, NULL
}, /* bfexts */
2656 { CODE_FOR_insn_bfextu
, NULL
}, /* bfextu */
2657 { CODE_FOR_insn_bfins
, NULL
}, /* bfins */
2658 { CODE_FOR_clzdi2
, NULL
}, /* clz */
2659 { CODE_FOR_insn_cmoveqz
, NULL
}, /* cmoveqz */
2660 { CODE_FOR_insn_cmovnez
, NULL
}, /* cmovnez */
2661 { CODE_FOR_insn_cmpeq_didi
, NULL
}, /* cmpeq */
2662 { CODE_FOR_insn_cmpexch
, NULL
}, /* cmpexch */
2663 { CODE_FOR_insn_cmpexch4
, NULL
}, /* cmpexch4 */
2664 { CODE_FOR_insn_cmples_didi
, NULL
}, /* cmples */
2665 { CODE_FOR_insn_cmpleu_didi
, NULL
}, /* cmpleu */
2666 { CODE_FOR_insn_cmplts_didi
, NULL
}, /* cmplts */
2667 { CODE_FOR_insn_cmpltu_didi
, NULL
}, /* cmpltu */
2668 { CODE_FOR_insn_cmpne_didi
, NULL
}, /* cmpne */
2669 { CODE_FOR_insn_cmul
, NULL
}, /* cmul */
2670 { CODE_FOR_insn_cmula
, NULL
}, /* cmula */
2671 { CODE_FOR_insn_cmulaf
, NULL
}, /* cmulaf */
2672 { CODE_FOR_insn_cmulf
, NULL
}, /* cmulf */
2673 { CODE_FOR_insn_cmulfr
, NULL
}, /* cmulfr */
2674 { CODE_FOR_insn_cmulh
, NULL
}, /* cmulh */
2675 { CODE_FOR_insn_cmulhr
, NULL
}, /* cmulhr */
2676 { CODE_FOR_insn_crc32_32
, NULL
}, /* crc32_32 */
2677 { CODE_FOR_insn_crc32_8
, NULL
}, /* crc32_8 */
2678 { CODE_FOR_ctzdi2
, NULL
}, /* ctz */
2679 { CODE_FOR_insn_dblalign
, NULL
}, /* dblalign */
2680 { CODE_FOR_insn_dblalign2
, NULL
}, /* dblalign2 */
2681 { CODE_FOR_insn_dblalign4
, NULL
}, /* dblalign4 */
2682 { CODE_FOR_insn_dblalign6
, NULL
}, /* dblalign6 */
2683 { CODE_FOR_insn_drain
, NULL
}, /* drain */
2684 { CODE_FOR_insn_dtlbpr
, NULL
}, /* dtlbpr */
2685 { CODE_FOR_insn_exch
, NULL
}, /* exch */
2686 { CODE_FOR_insn_exch4
, NULL
}, /* exch4 */
2687 { CODE_FOR_insn_fdouble_add_flags
, NULL
}, /* fdouble_add_flags */
2688 { CODE_FOR_insn_fdouble_addsub
, NULL
}, /* fdouble_addsub */
2689 { CODE_FOR_insn_fdouble_mul_flags
, NULL
}, /* fdouble_mul_flags */
2690 { CODE_FOR_insn_fdouble_pack1
, NULL
}, /* fdouble_pack1 */
2691 { CODE_FOR_insn_fdouble_pack2
, NULL
}, /* fdouble_pack2 */
2692 { CODE_FOR_insn_fdouble_sub_flags
, NULL
}, /* fdouble_sub_flags */
2693 { CODE_FOR_insn_fdouble_unpack_max
, NULL
}, /* fdouble_unpack_max */
2694 { CODE_FOR_insn_fdouble_unpack_min
, NULL
}, /* fdouble_unpack_min */
2695 { CODE_FOR_insn_fetchadd
, NULL
}, /* fetchadd */
2696 { CODE_FOR_insn_fetchadd4
, NULL
}, /* fetchadd4 */
2697 { CODE_FOR_insn_fetchaddgez
, NULL
}, /* fetchaddgez */
2698 { CODE_FOR_insn_fetchaddgez4
, NULL
}, /* fetchaddgez4 */
2699 { CODE_FOR_insn_fetchand
, NULL
}, /* fetchand */
2700 { CODE_FOR_insn_fetchand4
, NULL
}, /* fetchand4 */
2701 { CODE_FOR_insn_fetchor
, NULL
}, /* fetchor */
2702 { CODE_FOR_insn_fetchor4
, NULL
}, /* fetchor4 */
2703 { CODE_FOR_insn_finv
, NULL
}, /* finv */
2704 { CODE_FOR_insn_flush
, NULL
}, /* flush */
2705 { CODE_FOR_insn_flushwb
, NULL
}, /* flushwb */
2706 { CODE_FOR_insn_fnop
, NULL
}, /* fnop */
2707 { CODE_FOR_insn_fsingle_add1
, NULL
}, /* fsingle_add1 */
2708 { CODE_FOR_insn_fsingle_addsub2
, NULL
}, /* fsingle_addsub2 */
2709 { CODE_FOR_insn_fsingle_mul1
, NULL
}, /* fsingle_mul1 */
2710 { CODE_FOR_insn_fsingle_mul2
, NULL
}, /* fsingle_mul2 */
2711 { CODE_FOR_insn_fsingle_pack1
, NULL
}, /* fsingle_pack1 */
2712 { CODE_FOR_insn_fsingle_pack2
, NULL
}, /* fsingle_pack2 */
2713 { CODE_FOR_insn_fsingle_sub1
, NULL
}, /* fsingle_sub1 */
2714 { CODE_FOR_insn_icoh
, NULL
}, /* icoh */
2715 { CODE_FOR_insn_ill
, NULL
}, /* ill */
2716 { CODE_FOR_insn_info
, NULL
}, /* info */
2717 { CODE_FOR_insn_infol
, NULL
}, /* infol */
2718 { CODE_FOR_insn_inv
, NULL
}, /* inv */
2719 { CODE_FOR_insn_ld
, NULL
}, /* ld */
2720 { CODE_FOR_insn_ld1s
, NULL
}, /* ld1s */
2721 { CODE_FOR_insn_ld1u
, NULL
}, /* ld1u */
2722 { CODE_FOR_insn_ld2s
, NULL
}, /* ld2s */
2723 { CODE_FOR_insn_ld2u
, NULL
}, /* ld2u */
2724 { CODE_FOR_insn_ld4s
, NULL
}, /* ld4s */
2725 { CODE_FOR_insn_ld4u
, NULL
}, /* ld4u */
2726 { CODE_FOR_insn_ldna
, NULL
}, /* ldna */
2727 { CODE_FOR_insn_ldnt
, NULL
}, /* ldnt */
2728 { CODE_FOR_insn_ldnt1s
, NULL
}, /* ldnt1s */
2729 { CODE_FOR_insn_ldnt1u
, NULL
}, /* ldnt1u */
2730 { CODE_FOR_insn_ldnt2s
, NULL
}, /* ldnt2s */
2731 { CODE_FOR_insn_ldnt2u
, NULL
}, /* ldnt2u */
2732 { CODE_FOR_insn_ldnt4s
, NULL
}, /* ldnt4s */
2733 { CODE_FOR_insn_ldnt4u
, NULL
}, /* ldnt4u */
2734 { CODE_FOR_insn_ld_L2
, NULL
}, /* ld_L2 */
2735 { CODE_FOR_insn_ld1s_L2
, NULL
}, /* ld1s_L2 */
2736 { CODE_FOR_insn_ld1u_L2
, NULL
}, /* ld1u_L2 */
2737 { CODE_FOR_insn_ld2s_L2
, NULL
}, /* ld2s_L2 */
2738 { CODE_FOR_insn_ld2u_L2
, NULL
}, /* ld2u_L2 */
2739 { CODE_FOR_insn_ld4s_L2
, NULL
}, /* ld4s_L2 */
2740 { CODE_FOR_insn_ld4u_L2
, NULL
}, /* ld4u_L2 */
2741 { CODE_FOR_insn_ldna_L2
, NULL
}, /* ldna_L2 */
2742 { CODE_FOR_insn_ldnt_L2
, NULL
}, /* ldnt_L2 */
2743 { CODE_FOR_insn_ldnt1s_L2
, NULL
}, /* ldnt1s_L2 */
2744 { CODE_FOR_insn_ldnt1u_L2
, NULL
}, /* ldnt1u_L2 */
2745 { CODE_FOR_insn_ldnt2s_L2
, NULL
}, /* ldnt2s_L2 */
2746 { CODE_FOR_insn_ldnt2u_L2
, NULL
}, /* ldnt2u_L2 */
2747 { CODE_FOR_insn_ldnt4s_L2
, NULL
}, /* ldnt4s_L2 */
2748 { CODE_FOR_insn_ldnt4u_L2
, NULL
}, /* ldnt4u_L2 */
2749 { CODE_FOR_insn_ld_miss
, NULL
}, /* ld_miss */
2750 { CODE_FOR_insn_ld1s_miss
, NULL
}, /* ld1s_miss */
2751 { CODE_FOR_insn_ld1u_miss
, NULL
}, /* ld1u_miss */
2752 { CODE_FOR_insn_ld2s_miss
, NULL
}, /* ld2s_miss */
2753 { CODE_FOR_insn_ld2u_miss
, NULL
}, /* ld2u_miss */
2754 { CODE_FOR_insn_ld4s_miss
, NULL
}, /* ld4s_miss */
2755 { CODE_FOR_insn_ld4u_miss
, NULL
}, /* ld4u_miss */
2756 { CODE_FOR_insn_ldna_miss
, NULL
}, /* ldna_miss */
2757 { CODE_FOR_insn_ldnt_miss
, NULL
}, /* ldnt_miss */
2758 { CODE_FOR_insn_ldnt1s_miss
, NULL
}, /* ldnt1s_miss */
2759 { CODE_FOR_insn_ldnt1u_miss
, NULL
}, /* ldnt1u_miss */
2760 { CODE_FOR_insn_ldnt2s_miss
, NULL
}, /* ldnt2s_miss */
2761 { CODE_FOR_insn_ldnt2u_miss
, NULL
}, /* ldnt2u_miss */
2762 { CODE_FOR_insn_ldnt4s_miss
, NULL
}, /* ldnt4s_miss */
2763 { CODE_FOR_insn_ldnt4u_miss
, NULL
}, /* ldnt4u_miss */
2764 { CODE_FOR_insn_lnk
, NULL
}, /* lnk */
2765 { CODE_FOR_memory_barrier
, NULL
}, /* mf */
2766 { CODE_FOR_insn_mfspr
, NULL
}, /* mfspr */
2767 { CODE_FOR_insn_mm
, NULL
}, /* mm */
2768 { CODE_FOR_insn_mnz
, NULL
}, /* mnz */
2769 { CODE_FOR_movdi
, NULL
}, /* move */
2770 { CODE_FOR_insn_mtspr
, NULL
}, /* mtspr */
2771 { CODE_FOR_insn_mul_hs_hs
, NULL
}, /* mul_hs_hs */
2772 { CODE_FOR_insn_mul_hs_hu
, NULL
}, /* mul_hs_hu */
2773 { CODE_FOR_insn_mul_hs_ls
, NULL
}, /* mul_hs_ls */
2774 { CODE_FOR_insn_mul_hs_lu
, NULL
}, /* mul_hs_lu */
2775 { CODE_FOR_insn_mul_hu_hu
, NULL
}, /* mul_hu_hu */
2776 { CODE_FOR_insn_mul_hu_ls
, NULL
}, /* mul_hu_ls */
2777 { CODE_FOR_insn_mul_hu_lu
, NULL
}, /* mul_hu_lu */
2778 { CODE_FOR_insn_mul_ls_ls
, NULL
}, /* mul_ls_ls */
2779 { CODE_FOR_insn_mul_ls_lu
, NULL
}, /* mul_ls_lu */
2780 { CODE_FOR_insn_mul_lu_lu
, NULL
}, /* mul_lu_lu */
2781 { CODE_FOR_insn_mula_hs_hs
, NULL
}, /* mula_hs_hs */
2782 { CODE_FOR_insn_mula_hs_hu
, NULL
}, /* mula_hs_hu */
2783 { CODE_FOR_insn_mula_hs_ls
, NULL
}, /* mula_hs_ls */
2784 { CODE_FOR_insn_mula_hs_lu
, NULL
}, /* mula_hs_lu */
2785 { CODE_FOR_insn_mula_hu_hu
, NULL
}, /* mula_hu_hu */
2786 { CODE_FOR_insn_mula_hu_ls
, NULL
}, /* mula_hu_ls */
2787 { CODE_FOR_insn_mula_hu_lu
, NULL
}, /* mula_hu_lu */
2788 { CODE_FOR_insn_mula_ls_ls
, NULL
}, /* mula_ls_ls */
2789 { CODE_FOR_insn_mula_ls_lu
, NULL
}, /* mula_ls_lu */
2790 { CODE_FOR_insn_mula_lu_lu
, NULL
}, /* mula_lu_lu */
2791 { CODE_FOR_insn_mulax
, NULL
}, /* mulax */
2792 { CODE_FOR_mulsi3
, NULL
}, /* mulx */
2793 { CODE_FOR_insn_mz
, NULL
}, /* mz */
2794 { CODE_FOR_insn_nap
, NULL
}, /* nap */
2795 { CODE_FOR_nop
, NULL
}, /* nop */
2796 { CODE_FOR_insn_nor_di
, NULL
}, /* nor */
2797 { CODE_FOR_iordi3
, NULL
}, /* or */
2798 { CODE_FOR_popcountdi2
, NULL
}, /* pcnt */
2799 { CODE_FOR_insn_prefetch_l1
, NULL
}, /* prefetch_l1 */
2800 { CODE_FOR_insn_prefetch_l1_fault
, NULL
}, /* prefetch_l1_fault */
2801 { CODE_FOR_insn_prefetch_l2
, NULL
}, /* prefetch_l2 */
2802 { CODE_FOR_insn_prefetch_l2_fault
, NULL
}, /* prefetch_l2_fault */
2803 { CODE_FOR_insn_prefetch_l3
, NULL
}, /* prefetch_l3 */
2804 { CODE_FOR_insn_prefetch_l3_fault
, NULL
}, /* prefetch_l3_fault */
2805 { CODE_FOR_insn_revbits
, NULL
}, /* revbits */
2806 { CODE_FOR_bswapdi2
, NULL
}, /* revbytes */
2807 { CODE_FOR_rotldi3
, NULL
}, /* rotl */
2808 { CODE_FOR_ashldi3
, NULL
}, /* shl */
2809 { CODE_FOR_insn_shl16insli
, NULL
}, /* shl16insli */
2810 { CODE_FOR_insn_shl1add
, NULL
}, /* shl1add */
2811 { CODE_FOR_insn_shl1addx
, NULL
}, /* shl1addx */
2812 { CODE_FOR_insn_shl2add
, NULL
}, /* shl2add */
2813 { CODE_FOR_insn_shl2addx
, NULL
}, /* shl2addx */
2814 { CODE_FOR_insn_shl3add
, NULL
}, /* shl3add */
2815 { CODE_FOR_insn_shl3addx
, NULL
}, /* shl3addx */
2816 { CODE_FOR_ashlsi3
, NULL
}, /* shlx */
2817 { CODE_FOR_ashrdi3
, NULL
}, /* shrs */
2818 { CODE_FOR_lshrdi3
, NULL
}, /* shru */
2819 { CODE_FOR_lshrsi3
, NULL
}, /* shrux */
2820 { CODE_FOR_insn_shufflebytes
, NULL
}, /* shufflebytes */
2821 { CODE_FOR_insn_st
, NULL
}, /* st */
2822 { CODE_FOR_insn_st1
, NULL
}, /* st1 */
2823 { CODE_FOR_insn_st2
, NULL
}, /* st2 */
2824 { CODE_FOR_insn_st4
, NULL
}, /* st4 */
2825 { CODE_FOR_insn_stnt
, NULL
}, /* stnt */
2826 { CODE_FOR_insn_stnt1
, NULL
}, /* stnt1 */
2827 { CODE_FOR_insn_stnt2
, NULL
}, /* stnt2 */
2828 { CODE_FOR_insn_stnt4
, NULL
}, /* stnt4 */
2829 { CODE_FOR_subdi3
, NULL
}, /* sub */
2830 { CODE_FOR_subsi3
, NULL
}, /* subx */
2831 { CODE_FOR_sssubsi3
, NULL
}, /* subxsc */
2832 { CODE_FOR_insn_tblidxb0
, NULL
}, /* tblidxb0 */
2833 { CODE_FOR_insn_tblidxb1
, NULL
}, /* tblidxb1 */
2834 { CODE_FOR_insn_tblidxb2
, NULL
}, /* tblidxb2 */
2835 { CODE_FOR_insn_tblidxb3
, NULL
}, /* tblidxb3 */
2836 { CODE_FOR_insn_v1add
, NULL
}, /* v1add */
2837 { CODE_FOR_insn_v1addi
, NULL
}, /* v1addi */
2838 { CODE_FOR_insn_v1adduc
, NULL
}, /* v1adduc */
2839 { CODE_FOR_insn_v1adiffu
, NULL
}, /* v1adiffu */
2840 { CODE_FOR_insn_v1avgu
, NULL
}, /* v1avgu */
2841 { CODE_FOR_insn_v1cmpeq
, NULL
}, /* v1cmpeq */
2842 { CODE_FOR_insn_v1cmpeqi
, NULL
}, /* v1cmpeqi */
2843 { CODE_FOR_insn_v1cmples
, NULL
}, /* v1cmples */
2844 { CODE_FOR_insn_v1cmpleu
, NULL
}, /* v1cmpleu */
2845 { CODE_FOR_insn_v1cmplts
, NULL
}, /* v1cmplts */
2846 { CODE_FOR_insn_v1cmpltsi
, NULL
}, /* v1cmpltsi */
2847 { CODE_FOR_insn_v1cmpltu
, NULL
}, /* v1cmpltu */
2848 { CODE_FOR_insn_v1cmpltui
, NULL
}, /* v1cmpltui */
2849 { CODE_FOR_insn_v1cmpne
, NULL
}, /* v1cmpne */
2850 { CODE_FOR_insn_v1ddotpu
, NULL
}, /* v1ddotpu */
2851 { CODE_FOR_insn_v1ddotpua
, NULL
}, /* v1ddotpua */
2852 { CODE_FOR_insn_v1ddotpus
, NULL
}, /* v1ddotpus */
2853 { CODE_FOR_insn_v1ddotpusa
, NULL
}, /* v1ddotpusa */
2854 { CODE_FOR_insn_v1dotp
, NULL
}, /* v1dotp */
2855 { CODE_FOR_insn_v1dotpa
, NULL
}, /* v1dotpa */
2856 { CODE_FOR_insn_v1dotpu
, NULL
}, /* v1dotpu */
2857 { CODE_FOR_insn_v1dotpua
, NULL
}, /* v1dotpua */
2858 { CODE_FOR_insn_v1dotpus
, NULL
}, /* v1dotpus */
2859 { CODE_FOR_insn_v1dotpusa
, NULL
}, /* v1dotpusa */
2860 { CODE_FOR_insn_v1int_h
, NULL
}, /* v1int_h */
2861 { CODE_FOR_insn_v1int_l
, NULL
}, /* v1int_l */
2862 { CODE_FOR_insn_v1maxu
, NULL
}, /* v1maxu */
2863 { CODE_FOR_insn_v1maxui
, NULL
}, /* v1maxui */
2864 { CODE_FOR_insn_v1minu
, NULL
}, /* v1minu */
2865 { CODE_FOR_insn_v1minui
, NULL
}, /* v1minui */
2866 { CODE_FOR_insn_v1mnz
, NULL
}, /* v1mnz */
2867 { CODE_FOR_insn_v1multu
, NULL
}, /* v1multu */
2868 { CODE_FOR_insn_v1mulu
, NULL
}, /* v1mulu */
2869 { CODE_FOR_insn_v1mulus
, NULL
}, /* v1mulus */
2870 { CODE_FOR_insn_v1mz
, NULL
}, /* v1mz */
2871 { CODE_FOR_insn_v1sadau
, NULL
}, /* v1sadau */
2872 { CODE_FOR_insn_v1sadu
, NULL
}, /* v1sadu */
2873 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shl */
2874 { CODE_FOR_insn_v1shl
, NULL
}, /* v1shli */
2875 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrs */
2876 { CODE_FOR_insn_v1shrs
, NULL
}, /* v1shrsi */
2877 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shru */
2878 { CODE_FOR_insn_v1shru
, NULL
}, /* v1shrui */
2879 { CODE_FOR_insn_v1sub
, NULL
}, /* v1sub */
2880 { CODE_FOR_insn_v1subuc
, NULL
}, /* v1subuc */
2881 { CODE_FOR_insn_v2add
, NULL
}, /* v2add */
2882 { CODE_FOR_insn_v2addi
, NULL
}, /* v2addi */
2883 { CODE_FOR_insn_v2addsc
, NULL
}, /* v2addsc */
2884 { CODE_FOR_insn_v2adiffs
, NULL
}, /* v2adiffs */
2885 { CODE_FOR_insn_v2avgs
, NULL
}, /* v2avgs */
2886 { CODE_FOR_insn_v2cmpeq
, NULL
}, /* v2cmpeq */
2887 { CODE_FOR_insn_v2cmpeqi
, NULL
}, /* v2cmpeqi */
2888 { CODE_FOR_insn_v2cmples
, NULL
}, /* v2cmples */
2889 { CODE_FOR_insn_v2cmpleu
, NULL
}, /* v2cmpleu */
2890 { CODE_FOR_insn_v2cmplts
, NULL
}, /* v2cmplts */
2891 { CODE_FOR_insn_v2cmpltsi
, NULL
}, /* v2cmpltsi */
2892 { CODE_FOR_insn_v2cmpltu
, NULL
}, /* v2cmpltu */
2893 { CODE_FOR_insn_v2cmpltui
, NULL
}, /* v2cmpltui */
2894 { CODE_FOR_insn_v2cmpne
, NULL
}, /* v2cmpne */
2895 { CODE_FOR_insn_v2dotp
, NULL
}, /* v2dotp */
2896 { CODE_FOR_insn_v2dotpa
, NULL
}, /* v2dotpa */
2897 { CODE_FOR_insn_v2int_h
, NULL
}, /* v2int_h */
2898 { CODE_FOR_insn_v2int_l
, NULL
}, /* v2int_l */
2899 { CODE_FOR_insn_v2maxs
, NULL
}, /* v2maxs */
2900 { CODE_FOR_insn_v2maxsi
, NULL
}, /* v2maxsi */
2901 { CODE_FOR_insn_v2mins
, NULL
}, /* v2mins */
2902 { CODE_FOR_insn_v2minsi
, NULL
}, /* v2minsi */
2903 { CODE_FOR_insn_v2mnz
, NULL
}, /* v2mnz */
2904 { CODE_FOR_insn_v2mulfsc
, NULL
}, /* v2mulfsc */
2905 { CODE_FOR_insn_v2muls
, NULL
}, /* v2muls */
2906 { CODE_FOR_insn_v2mults
, NULL
}, /* v2mults */
2907 { CODE_FOR_insn_v2mz
, NULL
}, /* v2mz */
2908 { CODE_FOR_insn_v2packh
, NULL
}, /* v2packh */
2909 { CODE_FOR_insn_v2packl
, NULL
}, /* v2packl */
2910 { CODE_FOR_insn_v2packuc
, NULL
}, /* v2packuc */
2911 { CODE_FOR_insn_v2sadas
, NULL
}, /* v2sadas */
2912 { CODE_FOR_insn_v2sadau
, NULL
}, /* v2sadau */
2913 { CODE_FOR_insn_v2sads
, NULL
}, /* v2sads */
2914 { CODE_FOR_insn_v2sadu
, NULL
}, /* v2sadu */
2915 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shl */
2916 { CODE_FOR_insn_v2shl
, NULL
}, /* v2shli */
2917 { CODE_FOR_insn_v2shlsc
, NULL
}, /* v2shlsc */
2918 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrs */
2919 { CODE_FOR_insn_v2shrs
, NULL
}, /* v2shrsi */
2920 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shru */
2921 { CODE_FOR_insn_v2shru
, NULL
}, /* v2shrui */
2922 { CODE_FOR_insn_v2sub
, NULL
}, /* v2sub */
2923 { CODE_FOR_insn_v2subsc
, NULL
}, /* v2subsc */
2924 { CODE_FOR_insn_v4add
, NULL
}, /* v4add */
2925 { CODE_FOR_insn_v4addsc
, NULL
}, /* v4addsc */
2926 { CODE_FOR_insn_v4int_h
, NULL
}, /* v4int_h */
2927 { CODE_FOR_insn_v4int_l
, NULL
}, /* v4int_l */
2928 { CODE_FOR_insn_v4packsc
, NULL
}, /* v4packsc */
2929 { CODE_FOR_insn_v4shl
, NULL
}, /* v4shl */
2930 { CODE_FOR_insn_v4shlsc
, NULL
}, /* v4shlsc */
2931 { CODE_FOR_insn_v4shrs
, NULL
}, /* v4shrs */
2932 { CODE_FOR_insn_v4shru
, NULL
}, /* v4shru */
2933 { CODE_FOR_insn_v4sub
, NULL
}, /* v4sub */
2934 { CODE_FOR_insn_v4subsc
, NULL
}, /* v4subsc */
2935 { CODE_FOR_insn_wh64
, NULL
}, /* wh64 */
2936 { CODE_FOR_xordi3
, NULL
}, /* xor */
2937 { CODE_FOR_tilegx_network_barrier
, NULL
}, /* network_barrier */
2938 { CODE_FOR_tilegx_idn0_receive
, NULL
}, /* idn0_receive */
2939 { CODE_FOR_tilegx_idn1_receive
, NULL
}, /* idn1_receive */
2940 { CODE_FOR_tilegx_idn_send
, NULL
}, /* idn_send */
2941 { CODE_FOR_tilegx_udn0_receive
, NULL
}, /* udn0_receive */
2942 { CODE_FOR_tilegx_udn1_receive
, NULL
}, /* udn1_receive */
2943 { CODE_FOR_tilegx_udn2_receive
, NULL
}, /* udn2_receive */
2944 { CODE_FOR_tilegx_udn3_receive
, NULL
}, /* udn3_receive */
2945 { CODE_FOR_tilegx_udn_send
, NULL
}, /* udn_send */
2949 struct tilegx_builtin_def
2952 enum tilegx_builtin code
;
2954 /* The first character is the return type. Subsequent characters
2955 are the argument types. See char_to_type. */
2960 static const struct tilegx_builtin_def tilegx_builtins
[] = {
2961 { "__insn_add", TILEGX_INSN_ADD
, true, "lll" },
2962 { "__insn_addi", TILEGX_INSN_ADD
, true, "lll" },
2963 { "__insn_addli", TILEGX_INSN_ADD
, true, "lll" },
2964 { "__insn_addx", TILEGX_INSN_ADDX
, true, "iii" },
2965 { "__insn_addxi", TILEGX_INSN_ADDX
, true, "iii" },
2966 { "__insn_addxli", TILEGX_INSN_ADDX
, true, "iii" },
2967 { "__insn_addxsc", TILEGX_INSN_ADDXSC
, true, "iii" },
2968 { "__insn_and", TILEGX_INSN_AND
, true, "lll" },
2969 { "__insn_andi", TILEGX_INSN_AND
, true, "lll" },
2970 { "__insn_bfexts", TILEGX_INSN_BFEXTS
, true, "llll" },
2971 { "__insn_bfextu", TILEGX_INSN_BFEXTU
, true, "llll" },
2972 { "__insn_bfins", TILEGX_INSN_BFINS
, true, "lllll"},
2973 { "__insn_clz", TILEGX_INSN_CLZ
, true, "ll" },
2974 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ
, true, "llll" },
2975 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ
, true, "llll" },
2976 { "__insn_cmpeq", TILEGX_INSN_CMPEQ
, true, "lll" },
2977 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ
, true, "lll" },
2978 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH
, false, "lpl" },
2979 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4
, false, "ipi" },
2980 { "__insn_cmples", TILEGX_INSN_CMPLES
, true, "lll" },
2981 { "__insn_cmpleu", TILEGX_INSN_CMPLEU
, true, "lll" },
2982 { "__insn_cmplts", TILEGX_INSN_CMPLTS
, true, "lll" },
2983 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS
, true, "lll" },
2984 { "__insn_cmpltu", TILEGX_INSN_CMPLTU
, true, "lll" },
2985 { "__insn_cmpltui", TILEGX_INSN_CMPLTU
, true, "lll" },
2986 { "__insn_cmpne", TILEGX_INSN_CMPNE
, true, "lll" },
2987 { "__insn_cmul", TILEGX_INSN_CMUL
, true, "lll" },
2988 { "__insn_cmula", TILEGX_INSN_CMULA
, true, "llll" },
2989 { "__insn_cmulaf", TILEGX_INSN_CMULAF
, true, "llll" },
2990 { "__insn_cmulf", TILEGX_INSN_CMULF
, true, "lll" },
2991 { "__insn_cmulfr", TILEGX_INSN_CMULFR
, true, "lll" },
2992 { "__insn_cmulh", TILEGX_INSN_CMULH
, true, "lll" },
2993 { "__insn_cmulhr", TILEGX_INSN_CMULHR
, true, "lll" },
2994 { "__insn_crc32_32", TILEGX_INSN_CRC32_32
, true, "lll" },
2995 { "__insn_crc32_8", TILEGX_INSN_CRC32_8
, true, "lll" },
2996 { "__insn_ctz", TILEGX_INSN_CTZ
, true, "ll" },
2997 { "__insn_dblalign", TILEGX_INSN_DBLALIGN
, true, "lllk" },
2998 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2
, true, "lll" },
2999 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4
, true, "lll" },
3000 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6
, true, "lll" },
3001 { "__insn_drain", TILEGX_INSN_DRAIN
, false, "v" },
3002 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR
, false, "vl" },
3003 { "__insn_exch", TILEGX_INSN_EXCH
, false, "lpl" },
3004 { "__insn_exch4", TILEGX_INSN_EXCH4
, false, "ipi" },
3005 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS
, true, "lll" },
3006 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB
, true, "llll" },
3007 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS
, true, "lll" },
3008 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1
, true, "lll" },
3009 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2
, true, "llll" },
3010 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS
, true, "lll" },
3011 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX
, true, "lll" },
3012 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN
, true, "lll" },
3013 { "__insn_fetchadd", TILEGX_INSN_FETCHADD
, false, "lpl" },
3014 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4
, false, "ipi" },
3015 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ
, false, "lpl" },
3016 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4
, false, "ipi" },
3017 { "__insn_fetchand", TILEGX_INSN_FETCHAND
, false, "lpl" },
3018 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4
, false, "ipi" },
3019 { "__insn_fetchor", TILEGX_INSN_FETCHOR
, false, "lpl" },
3020 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4
, false, "ipi" },
3021 { "__insn_finv", TILEGX_INSN_FINV
, false, "vk" },
3022 { "__insn_flush", TILEGX_INSN_FLUSH
, false, "vk" },
3023 { "__insn_flushwb", TILEGX_INSN_FLUSHWB
, false, "v" },
3024 { "__insn_fnop", TILEGX_INSN_FNOP
, false, "v" },
3025 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1
, true, "lll" },
3026 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2
, true, "llll" },
3027 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1
, true, "lll" },
3028 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2
, true, "lll" },
3029 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1
, true, "ll" },
3030 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2
, true, "lll" },
3031 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1
, true, "lll" },
3032 { "__insn_icoh", TILEGX_INSN_ICOH
, false, "vk" },
3033 { "__insn_ill", TILEGX_INSN_ILL
, false, "v" },
3034 { "__insn_info", TILEGX_INSN_INFO
, false, "vl" },
3035 { "__insn_infol", TILEGX_INSN_INFOL
, false, "vl" },
3036 { "__insn_inv", TILEGX_INSN_INV
, false, "vp" },
3037 { "__insn_ld", TILEGX_INSN_LD
, false, "lk" },
3038 { "__insn_ld1s", TILEGX_INSN_LD1S
, false, "lk" },
3039 { "__insn_ld1u", TILEGX_INSN_LD1U
, false, "lk" },
3040 { "__insn_ld2s", TILEGX_INSN_LD2S
, false, "lk" },
3041 { "__insn_ld2u", TILEGX_INSN_LD2U
, false, "lk" },
3042 { "__insn_ld4s", TILEGX_INSN_LD4S
, false, "lk" },
3043 { "__insn_ld4u", TILEGX_INSN_LD4U
, false, "lk" },
3044 { "__insn_ldna", TILEGX_INSN_LDNA
, false, "lk" },
3045 { "__insn_ldnt", TILEGX_INSN_LDNT
, false, "lk" },
3046 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S
, false, "lk" },
3047 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U
, false, "lk" },
3048 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S
, false, "lk" },
3049 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U
, false, "lk" },
3050 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S
, false, "lk" },
3051 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U
, false, "lk" },
3052 { "__insn_ld_L2", TILEGX_INSN_LD_L2
, false, "lk" },
3053 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2
, false, "lk" },
3054 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2
, false, "lk" },
3055 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2
, false, "lk" },
3056 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2
, false, "lk" },
3057 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2
, false, "lk" },
3058 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2
, false, "lk" },
3059 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2
, false, "lk" },
3060 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2
, false, "lk" },
3061 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2
, false, "lk" },
3062 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2
, false, "lk" },
3063 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2
, false, "lk" },
3064 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2
, false, "lk" },
3065 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2
, false, "lk" },
3066 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2
, false, "lk" },
3067 { "__insn_ld_miss", TILEGX_INSN_LD_MISS
, false, "lk" },
3068 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS
, false, "lk" },
3069 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS
, false, "lk" },
3070 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS
, false, "lk" },
3071 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS
, false, "lk" },
3072 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS
, false, "lk" },
3073 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS
, false, "lk" },
3074 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS
, false, "lk" },
3075 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS
, false, "lk" },
3076 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS
, false, "lk" },
3077 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS
, false, "lk" },
3078 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS
, false, "lk" },
3079 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS
, false, "lk" },
3080 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS
, false, "lk" },
3081 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS
, false, "lk" },
3082 { "__insn_lnk", TILEGX_INSN_LNK
, true, "l" },
3083 { "__insn_mf", TILEGX_INSN_MF
, false, "v" },
3084 { "__insn_mfspr", TILEGX_INSN_MFSPR
, false, "ll" },
3085 { "__insn_mm", TILEGX_INSN_MM
, true, "lllll"},
3086 { "__insn_mnz", TILEGX_INSN_MNZ
, true, "lll" },
3087 { "__insn_move", TILEGX_INSN_MOVE
, true, "ll" },
3088 { "__insn_movei", TILEGX_INSN_MOVE
, true, "ll" },
3089 { "__insn_moveli", TILEGX_INSN_MOVE
, true, "ll" },
3090 { "__insn_mtspr", TILEGX_INSN_MTSPR
, false, "vll" },
3091 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS
, true, "lll" },
3092 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU
, true, "lll" },
3093 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS
, true, "lll" },
3094 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU
, true, "lll" },
3095 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU
, true, "lll" },
3096 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS
, true, "lll" },
3097 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU
, true, "lll" },
3098 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS
, true, "lll" },
3099 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU
, true, "lll" },
3100 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU
, true, "lll" },
3101 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS
, true, "llll" },
3102 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU
, true, "llll" },
3103 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS
, true, "llll" },
3104 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU
, true, "llll" },
3105 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU
, true, "llll" },
3106 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS
, true, "llll" },
3107 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU
, true, "llll" },
3108 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS
, true, "llll" },
3109 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU
, true, "llll" },
3110 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU
, true, "llll" },
3111 { "__insn_mulax", TILEGX_INSN_MULAX
, true, "iiii" },
3112 { "__insn_mulx", TILEGX_INSN_MULX
, true, "iii" },
3113 { "__insn_mz", TILEGX_INSN_MZ
, true, "lll" },
3114 { "__insn_nap", TILEGX_INSN_NAP
, false, "v" },
3115 { "__insn_nop", TILEGX_INSN_NOP
, true, "v" },
3116 { "__insn_nor", TILEGX_INSN_NOR
, true, "lll" },
3117 { "__insn_or", TILEGX_INSN_OR
, true, "lll" },
3118 { "__insn_ori", TILEGX_INSN_OR
, true, "lll" },
3119 { "__insn_pcnt", TILEGX_INSN_PCNT
, true, "ll" },
3120 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3121 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1
, false, "vk" },
3122 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT
, false, "vk" },
3123 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2
, false, "vk" },
3124 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT
, false, "vk" },
3125 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3
, false, "vk" },
3126 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT
, false, "vk" },
3127 { "__insn_revbits", TILEGX_INSN_REVBITS
, true, "ll" },
3128 { "__insn_revbytes", TILEGX_INSN_REVBYTES
, true, "ll" },
3129 { "__insn_rotl", TILEGX_INSN_ROTL
, true, "lli" },
3130 { "__insn_rotli", TILEGX_INSN_ROTL
, true, "lli" },
3131 { "__insn_shl", TILEGX_INSN_SHL
, true, "lli" },
3132 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI
, true, "lll" },
3133 { "__insn_shl1add", TILEGX_INSN_SHL1ADD
, true, "lll" },
3134 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX
, true, "iii" },
3135 { "__insn_shl2add", TILEGX_INSN_SHL2ADD
, true, "lll" },
3136 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX
, true, "iii" },
3137 { "__insn_shl3add", TILEGX_INSN_SHL3ADD
, true, "lll" },
3138 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX
, true, "iii" },
3139 { "__insn_shli", TILEGX_INSN_SHL
, true, "lli" },
3140 { "__insn_shlx", TILEGX_INSN_SHLX
, true, "iii" },
3141 { "__insn_shlxi", TILEGX_INSN_SHLX
, true, "iii" },
3142 { "__insn_shrs", TILEGX_INSN_SHRS
, true, "lli" },
3143 { "__insn_shrsi", TILEGX_INSN_SHRS
, true, "lli" },
3144 { "__insn_shru", TILEGX_INSN_SHRU
, true, "lli" },
3145 { "__insn_shrui", TILEGX_INSN_SHRU
, true, "lli" },
3146 { "__insn_shrux", TILEGX_INSN_SHRUX
, true, "iii" },
3147 { "__insn_shruxi", TILEGX_INSN_SHRUX
, true, "iii" },
3148 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES
, true, "llll" },
3149 { "__insn_st", TILEGX_INSN_ST
, false, "vpl" },
3150 { "__insn_st1", TILEGX_INSN_ST1
, false, "vpl" },
3151 { "__insn_st2", TILEGX_INSN_ST2
, false, "vpl" },
3152 { "__insn_st4", TILEGX_INSN_ST4
, false, "vpl" },
3153 { "__insn_stnt", TILEGX_INSN_STNT
, false, "vpl" },
3154 { "__insn_stnt1", TILEGX_INSN_STNT1
, false, "vpl" },
3155 { "__insn_stnt2", TILEGX_INSN_STNT2
, false, "vpl" },
3156 { "__insn_stnt4", TILEGX_INSN_STNT4
, false, "vpl" },
3157 { "__insn_sub", TILEGX_INSN_SUB
, true, "lll" },
3158 { "__insn_subx", TILEGX_INSN_SUBX
, true, "iii" },
3159 { "__insn_subxsc", TILEGX_INSN_SUBXSC
, true, "iii" },
3160 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0
, true, "lll" },
3161 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1
, true, "lll" },
3162 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2
, true, "lll" },
3163 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3
, true, "lll" },
3164 { "__insn_v1add", TILEGX_INSN_V1ADD
, true, "lll" },
3165 { "__insn_v1addi", TILEGX_INSN_V1ADDI
, true, "lll" },
3166 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC
, true, "lll" },
3167 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU
, true, "lll" },
3168 { "__insn_v1avgu", TILEGX_INSN_V1AVGU
, true, "lll" },
3169 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ
, true, "lll" },
3170 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI
, true, "lll" },
3171 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES
, true, "lll" },
3172 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU
, true, "lll" },
3173 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS
, true, "lll" },
3174 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI
, true, "lll" },
3175 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU
, true, "lll" },
3176 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI
, true, "lll" },
3177 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE
, true, "lll" },
3178 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU
, true, "lll" },
3179 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA
, true, "llll" },
3180 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS
, true, "lll" },
3181 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA
, true, "llll" },
3182 { "__insn_v1dotp", TILEGX_INSN_V1DOTP
, true, "lll" },
3183 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA
, true, "llll" },
3184 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU
, true, "lll" },
3185 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA
, true, "llll" },
3186 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS
, true, "lll" },
3187 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA
, true, "llll" },
3188 { "__insn_v1int_h", TILEGX_INSN_V1INT_H
, true, "lll" },
3189 { "__insn_v1int_l", TILEGX_INSN_V1INT_L
, true, "lll" },
3190 { "__insn_v1maxu", TILEGX_INSN_V1MAXU
, true, "lll" },
3191 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI
, true, "lll" },
3192 { "__insn_v1minu", TILEGX_INSN_V1MINU
, true, "lll" },
3193 { "__insn_v1minui", TILEGX_INSN_V1MINUI
, true, "lll" },
3194 { "__insn_v1mnz", TILEGX_INSN_V1MNZ
, true, "lll" },
3195 { "__insn_v1multu", TILEGX_INSN_V1MULTU
, true, "lll" },
3196 { "__insn_v1mulu", TILEGX_INSN_V1MULU
, true, "lll" },
3197 { "__insn_v1mulus", TILEGX_INSN_V1MULUS
, true, "lll" },
3198 { "__insn_v1mz", TILEGX_INSN_V1MZ
, true, "lll" },
3199 { "__insn_v1sadau", TILEGX_INSN_V1SADAU
, true, "llll" },
3200 { "__insn_v1sadu", TILEGX_INSN_V1SADU
, true, "lll" },
3201 { "__insn_v1shl", TILEGX_INSN_V1SHL
, true, "lll" },
3202 { "__insn_v1shli", TILEGX_INSN_V1SHLI
, true, "lll" },
3203 { "__insn_v1shrs", TILEGX_INSN_V1SHRS
, true, "lll" },
3204 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI
, true, "lll" },
3205 { "__insn_v1shru", TILEGX_INSN_V1SHRU
, true, "lll" },
3206 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI
, true, "lll" },
3207 { "__insn_v1sub", TILEGX_INSN_V1SUB
, true, "lll" },
3208 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC
, true, "lll" },
3209 { "__insn_v2add", TILEGX_INSN_V2ADD
, true, "lll" },
3210 { "__insn_v2addi", TILEGX_INSN_V2ADDI
, true, "lll" },
3211 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC
, true, "lll" },
3212 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS
, true, "lll" },
3213 { "__insn_v2avgs", TILEGX_INSN_V2AVGS
, true, "lll" },
3214 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ
, true, "lll" },
3215 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI
, true, "lll" },
3216 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES
, true, "lll" },
3217 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU
, true, "lll" },
3218 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS
, true, "lll" },
3219 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI
, true, "lll" },
3220 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU
, true, "lll" },
3221 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI
, true, "lll" },
3222 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE
, true, "lll" },
3223 { "__insn_v2dotp", TILEGX_INSN_V2DOTP
, true, "lll" },
3224 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA
, true, "llll" },
3225 { "__insn_v2int_h", TILEGX_INSN_V2INT_H
, true, "lll" },
3226 { "__insn_v2int_l", TILEGX_INSN_V2INT_L
, true, "lll" },
3227 { "__insn_v2maxs", TILEGX_INSN_V2MAXS
, true, "lll" },
3228 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI
, true, "lll" },
3229 { "__insn_v2mins", TILEGX_INSN_V2MINS
, true, "lll" },
3230 { "__insn_v2minsi", TILEGX_INSN_V2MINSI
, true, "lll" },
3231 { "__insn_v2mnz", TILEGX_INSN_V2MNZ
, true, "lll" },
3232 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC
, true, "lll" },
3233 { "__insn_v2muls", TILEGX_INSN_V2MULS
, true, "lll" },
3234 { "__insn_v2mults", TILEGX_INSN_V2MULTS
, true, "lll" },
3235 { "__insn_v2mz", TILEGX_INSN_V2MZ
, true, "lll" },
3236 { "__insn_v2packh", TILEGX_INSN_V2PACKH
, true, "lll" },
3237 { "__insn_v2packl", TILEGX_INSN_V2PACKL
, true, "lll" },
3238 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC
, true, "lll" },
3239 { "__insn_v2sadas", TILEGX_INSN_V2SADAS
, true, "llll" },
3240 { "__insn_v2sadau", TILEGX_INSN_V2SADAU
, true, "llll" },
3241 { "__insn_v2sads", TILEGX_INSN_V2SADS
, true, "lll" },
3242 { "__insn_v2sadu", TILEGX_INSN_V2SADU
, true, "lll" },
3243 { "__insn_v2shl", TILEGX_INSN_V2SHL
, true, "lll" },
3244 { "__insn_v2shli", TILEGX_INSN_V2SHLI
, true, "lll" },
3245 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC
, true, "lll" },
3246 { "__insn_v2shrs", TILEGX_INSN_V2SHRS
, true, "lll" },
3247 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI
, true, "lll" },
3248 { "__insn_v2shru", TILEGX_INSN_V2SHRU
, true, "lll" },
3249 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI
, true, "lll" },
3250 { "__insn_v2sub", TILEGX_INSN_V2SUB
, true, "lll" },
3251 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC
, true, "lll" },
3252 { "__insn_v4add", TILEGX_INSN_V4ADD
, true, "lll" },
3253 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC
, true, "lll" },
3254 { "__insn_v4int_h", TILEGX_INSN_V4INT_H
, true, "lll" },
3255 { "__insn_v4int_l", TILEGX_INSN_V4INT_L
, true, "lll" },
3256 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC
, true, "lll" },
3257 { "__insn_v4shl", TILEGX_INSN_V4SHL
, true, "lll" },
3258 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC
, true, "lll" },
3259 { "__insn_v4shrs", TILEGX_INSN_V4SHRS
, true, "lll" },
3260 { "__insn_v4shru", TILEGX_INSN_V4SHRU
, true, "lll" },
3261 { "__insn_v4sub", TILEGX_INSN_V4SUB
, true, "lll" },
3262 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC
, true, "lll" },
3263 { "__insn_wh64", TILEGX_INSN_WH64
, false, "vp" },
3264 { "__insn_xor", TILEGX_INSN_XOR
, true, "lll" },
3265 { "__insn_xori", TILEGX_INSN_XOR
, true, "lll" },
3266 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER
, false, "v" },
3267 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE
, false, "l" },
3268 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE
, false, "l" },
3269 { "__tile_idn_send", TILEGX_IDN_SEND
, false, "vl" },
3270 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE
, false, "l" },
3271 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE
, false, "l" },
3272 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE
, false, "l" },
3273 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE
, false, "l" },
3274 { "__tile_udn_send", TILEGX_UDN_SEND
, false, "vl" },
3278 /* Convert a character in a builtin type string to a tree type. */
3280 char_to_type (char c
)
3282 static tree volatile_ptr_type_node
= NULL
;
3283 static tree volatile_const_ptr_type_node
= NULL
;
3285 if (volatile_ptr_type_node
== NULL
)
3287 volatile_ptr_type_node
=
3288 build_pointer_type (build_qualified_type (void_type_node
,
3289 TYPE_QUAL_VOLATILE
));
3290 volatile_const_ptr_type_node
=
3291 build_pointer_type (build_qualified_type (void_type_node
,
3293 | TYPE_QUAL_VOLATILE
));
3299 return void_type_node
;
3301 return unsigned_type_node
;
3303 return long_long_unsigned_type_node
;
3305 return volatile_ptr_type_node
;
3307 return volatile_const_ptr_type_node
;
3314 /* Implement TARGET_INIT_BUILTINS. */
3316 tilegx_init_builtins (void)
3320 for (i
= 0; i
< ARRAY_SIZE (tilegx_builtins
); i
++)
3322 const struct tilegx_builtin_def
*p
= &tilegx_builtins
[i
];
3323 tree ftype
, ret_type
, arg_type_list
= void_list_node
;
3327 for (j
= strlen (p
->type
) - 1; j
> 0; j
--)
3330 tree_cons (NULL_TREE
, char_to_type (p
->type
[j
]), arg_type_list
);
3333 ret_type
= char_to_type (p
->type
[0]);
3335 ftype
= build_function_type (ret_type
, arg_type_list
);
3337 decl
= add_builtin_function (p
->name
, ftype
, p
->code
, BUILT_IN_MD
,
3341 TREE_READONLY (decl
) = 1;
3342 TREE_NOTHROW (decl
) = 1;
3344 if (tilegx_builtin_info
[p
->code
].fndecl
== NULL
)
3345 tilegx_builtin_info
[p
->code
].fndecl
= decl
;
3350 /* Implement TARGET_EXPAND_BUILTIN. */
3352 tilegx_expand_builtin (tree exp
,
3354 rtx subtarget ATTRIBUTE_UNUSED
,
3355 enum machine_mode mode ATTRIBUTE_UNUSED
,
3356 int ignore ATTRIBUTE_UNUSED
)
3358 #define MAX_BUILTIN_ARGS 4
3360 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
3361 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
3363 call_expr_arg_iterator iter
;
3364 enum insn_code icode
;
3365 rtx op
[MAX_BUILTIN_ARGS
+ 1], pat
;
3370 if (fcode
>= TILEGX_BUILTIN_max
)
3371 internal_error ("bad builtin fcode");
3372 icode
= tilegx_builtin_info
[fcode
].icode
;
3374 internal_error ("bad builtin icode");
3376 nonvoid
= TREE_TYPE (TREE_TYPE (fndecl
)) != void_type_node
;
3379 FOR_EACH_CALL_EXPR_ARG (arg
, iter
, exp
)
3381 const struct insn_operand_data
*insn_op
;
3383 if (arg
== error_mark_node
)
3385 if (opnum
> MAX_BUILTIN_ARGS
)
3388 insn_op
= &insn_data
[icode
].operand
[opnum
];
3390 op
[opnum
] = expand_expr (arg
, NULL_RTX
, insn_op
->mode
, EXPAND_NORMAL
);
3392 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3394 enum machine_mode opmode
= insn_op
->mode
;
3396 /* pointer_operand and pmode_register_operand operands do
3397 not specify a mode, so use the operand's mode instead
3398 (which should always be right by the time we get here,
3399 except for constants, which are VOIDmode). */
3400 if (opmode
== VOIDmode
)
3402 enum machine_mode m
= GET_MODE (op
[opnum
]);
3403 gcc_assert (m
== Pmode
|| m
== VOIDmode
);
3407 op
[opnum
] = copy_to_mode_reg (opmode
, op
[opnum
]);
3410 if (!(*insn_op
->predicate
) (op
[opnum
], insn_op
->mode
))
3412 /* We still failed to meet the predicate even after moving
3413 into a register. Assume we needed an immediate. */
3414 error_at (EXPR_LOCATION (exp
),
3415 "operand must be an immediate of the right size");
3424 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
3426 || GET_MODE (target
) != tmode
3427 || !(*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
3429 if (tmode
== VOIDmode
)
3431 /* get the mode from the return type. */
3432 tmode
= TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl
)));
3434 target
= gen_reg_rtx (tmode
);
3439 fn
= GEN_FCN (icode
);
3443 pat
= fn (NULL_RTX
);
3449 pat
= fn (op
[0], op
[1]);
3452 pat
= fn (op
[0], op
[1], op
[2]);
3455 pat
= fn (op
[0], op
[1], op
[2], op
[3]);
3458 pat
= fn (op
[0], op
[1], op
[2], op
[3], op
[4]);
3474 /* Implement TARGET_BUILTIN_DECL. */
3476 tilegx_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
3478 if (code
>= TILEGX_BUILTIN_max
)
3479 return error_mark_node
;
3481 return tilegx_builtin_info
[code
].fndecl
;
3488 /* Return whether REGNO needs to be saved in the stack frame. */
3490 need_to_save_reg (unsigned int regno
)
3492 if (!fixed_regs
[regno
] && !call_used_regs
[regno
]
3493 && df_regs_ever_live_p (regno
))
3497 && (regno
== PIC_OFFSET_TABLE_REGNUM
3498 || regno
== TILEGX_PIC_TEXT_LABEL_REGNUM
)
3499 && (crtl
->uses_pic_offset_table
|| crtl
->saves_all_registers
))
3502 if (crtl
->calls_eh_return
)
3505 for (i
= 0; EH_RETURN_DATA_REGNO (i
) != INVALID_REGNUM
; i
++)
3507 if (regno
== EH_RETURN_DATA_REGNO (i
))
3516 /* Return the size of the register savev area. This function is only
3517 correct starting with local register allocation */
3519 tilegx_saved_regs_size (void)
3521 int reg_save_size
= 0;
3523 int offset_to_frame
;
3526 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
3527 if (need_to_save_reg (regno
))
3528 reg_save_size
+= UNITS_PER_WORD
;
3530 /* Pad out the register save area if necessary to make
3531 frame_pointer_rtx be as aligned as the stack pointer. */
3532 offset_to_frame
= crtl
->args
.pretend_args_size
+ reg_save_size
;
3533 align_mask
= (STACK_BOUNDARY
/ BITS_PER_UNIT
) - 1;
3534 reg_save_size
+= (-offset_to_frame
) & align_mask
;
3536 return reg_save_size
;
3540 /* Round up frame size SIZE. */
3542 round_frame_size (int size
)
3544 return ((size
+ STACK_BOUNDARY
/ BITS_PER_UNIT
- 1)
3545 & -STACK_BOUNDARY
/ BITS_PER_UNIT
);
3549 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3550 emit the corresponding REG_CFA_OFFSET note described by CFA and
3551 CFA_OFFSET. Return the emitted insn. */
3553 frame_emit_store (int regno
, int regno_note
, rtx addr
, rtx cfa
,
3556 rtx reg
= gen_rtx_REG (DImode
, regno
);
3557 rtx mem
= gen_frame_mem (DImode
, addr
);
3558 rtx mov
= gen_movdi (mem
, reg
);
3560 /* Describe what just happened in a way that dwarf understands. We
3561 use temporary registers to hold the address to make scheduling
3562 easier, and use the REG_CFA_OFFSET to describe the address as an
3563 offset from the CFA. */
3564 rtx reg_note
= gen_rtx_REG (DImode
, regno_note
);
3565 rtx cfa_relative_addr
= gen_rtx_PLUS (Pmode
, cfa
, GEN_INT (cfa_offset
));
3566 rtx cfa_relative_mem
= gen_frame_mem (DImode
, cfa_relative_addr
);
3567 rtx real
= gen_rtx_SET (VOIDmode
, cfa_relative_mem
, reg_note
);
3568 add_reg_note (mov
, REG_CFA_OFFSET
, real
);
3570 return emit_insn (mov
);
3574 /* Emit a load in the stack frame to load REGNO from address ADDR.
3575 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3576 non-null. Return the emitted insn. */
3578 frame_emit_load (int regno
, rtx addr
, rtx
*cfa_restores
)
3580 rtx reg
= gen_rtx_REG (DImode
, regno
);
3581 rtx mem
= gen_frame_mem (DImode
, addr
);
3583 *cfa_restores
= alloc_reg_note (REG_CFA_RESTORE
, reg
, *cfa_restores
);
3584 return emit_insn (gen_movdi (reg
, mem
));
3588 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3589 including sequences. */
3591 set_frame_related_p (void)
3593 rtx seq
= get_insns ();
3604 while (insn
!= NULL_RTX
)
3606 RTX_FRAME_RELATED_P (insn
) = 1;
3607 insn
= NEXT_INSN (insn
);
3609 seq
= emit_insn (seq
);
3613 seq
= emit_insn (seq
);
3614 RTX_FRAME_RELATED_P (seq
) = 1;
3620 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3622 /* This emits code for 'sp += offset'.
3624 The ABI only allows us to modify 'sp' in a single 'addi' or
3625 'addli', so the backtracer understands it. Larger amounts cannot
3626 use those instructions, so are added by placing the offset into a
3627 large register and using 'add'.
3629 This happens after reload, so we need to expand it ourselves. */
3631 emit_sp_adjust (int offset
, int *next_scratch_regno
, bool frame_related
,
3635 rtx imm_rtx
= GEN_INT (offset
);
3638 if (satisfies_constraint_J (imm_rtx
))
3640 /* We can add this using a single immediate add. */
3645 rtx tmp
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3646 tilegx_expand_set_const64 (tmp
, imm_rtx
);
3650 /* Actually adjust the stack pointer. */
3652 insn
= gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3654 insn
= gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
, to_add
);
3656 insn
= emit_insn (insn
);
3657 REG_NOTES (insn
) = reg_notes
;
3659 /* Describe what just happened in a way that dwarf understands. */
3662 rtx real
= gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
3663 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3665 RTX_FRAME_RELATED_P (insn
) = 1;
3666 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, real
);
3673 /* Return whether the current function is leaf. This takes into
3674 account whether the function calls tls_get_addr. */
3676 tilegx_current_function_is_leaf (void)
3678 return current_function_is_leaf
&& !cfun
->machine
->calls_tls_get_addr
;
3682 /* Return the frame size. */
3684 compute_total_frame_size (void)
3686 int total_size
= (get_frame_size () + tilegx_saved_regs_size ()
3687 + crtl
->outgoing_args_size
3688 + crtl
->args
.pretend_args_size
);
3690 if (!tilegx_current_function_is_leaf () || cfun
->calls_alloca
)
3692 /* Make room for save area in callee. */
3693 total_size
+= STACK_POINTER_OFFSET
;
3696 return round_frame_size (total_size
);
3700 /* Return nonzero if this function is known to have a null epilogue.
3701 This allows the optimizer to omit jumps to jumps if no stack was
3704 tilegx_can_use_return_insn_p (void)
3706 return (reload_completed
3707 && cfun
->static_chain_decl
== 0
3708 && compute_total_frame_size () == 0
3709 && tilegx_current_function_is_leaf ()
3710 && !crtl
->profile
&& !df_regs_ever_live_p (TILEGX_LINK_REGNUM
));
3714 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3715 is a frame pointer, it computes the value relative to
3716 that. Otherwise it uses the stack pointer. */
3718 compute_frame_addr (int offset_from_fp
, int *next_scratch_regno
)
3720 rtx base_reg_rtx
, tmp_reg_rtx
, offset_rtx
;
3721 int offset_from_base
;
3723 if (frame_pointer_needed
)
3725 base_reg_rtx
= hard_frame_pointer_rtx
;
3726 offset_from_base
= offset_from_fp
;
3730 int offset_from_sp
= compute_total_frame_size () + offset_from_fp
;
3731 offset_from_base
= offset_from_sp
;
3732 base_reg_rtx
= stack_pointer_rtx
;
3735 if (offset_from_base
== 0)
3736 return base_reg_rtx
;
3738 /* Compute the new value of the stack pointer. */
3739 tmp_reg_rtx
= gen_rtx_REG (Pmode
, (*next_scratch_regno
)--);
3740 offset_rtx
= GEN_INT (offset_from_base
);
3742 if (!add_operand (offset_rtx
, Pmode
))
3744 expand_set_cint64 (tmp_reg_rtx
, offset_rtx
);
3745 offset_rtx
= tmp_reg_rtx
;
3748 emit_insn (gen_rtx_SET (VOIDmode
, tmp_reg_rtx
,
3749 gen_rtx_PLUS (Pmode
, base_reg_rtx
, offset_rtx
)));
3755 /* The stack frame looks like this:
3760 AP -> +-------------+
3764 HFP -> +-------------+
3766 | reg save | crtl->args.pretend_args_size bytes
3769 | saved regs | tilegx_saved_regs_size() bytes
3770 FP -> +-------------+
3772 | vars | get_frame_size() bytes
3776 | stack args | crtl->outgoing_args_size bytes
3778 | HFP | ptr_size bytes (only here if nonleaf / alloca)
3780 | callee lr | ptr_size bytes (only here if nonleaf / alloca)
3782 SP -> +-------------+
3786 For functions with a frame larger than 32767 bytes, or which use
3787 alloca (), r52 is used as a frame pointer. Otherwise there is no
3790 FP is saved at SP+ptr_size before calling a subroutine so the callee
3793 tilegx_expand_prologue (void)
3795 #define ROUND_ROBIN_SIZE 4
3796 /* We round-robin through four scratch registers to hold temporary
3797 addresses for saving registers, to make instruction scheduling
3799 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
3800 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
3803 unsigned int which_scratch
;
3804 int offset
, start_offset
, regno
;
3806 /* A register that holds a copy of the incoming fp. */
3807 int fp_copy_regno
= -1;
3809 /* A register that holds a copy of the incoming sp. */
3810 int sp_copy_regno
= -1;
3812 /* Next scratch register number to hand out (postdecrementing). */
3813 int next_scratch_regno
= 29;
3815 int total_size
= compute_total_frame_size ();
3817 if (flag_stack_usage_info
)
3818 current_function_static_stack_size
= total_size
;
3820 /* Save lr first in its special location because code after this
3821 might use the link register as a scratch register. */
3822 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
) || crtl
->calls_eh_return
)
3823 FRP (frame_emit_store (TILEGX_LINK_REGNUM
, TILEGX_LINK_REGNUM
,
3824 stack_pointer_rtx
, stack_pointer_rtx
, 0));
3826 if (total_size
== 0)
3828 /* Load the PIC register if needed. */
3829 if (flag_pic
&& crtl
->uses_pic_offset_table
)
3830 load_pic_register (false);
3835 cfa
= stack_pointer_rtx
;
3837 if (frame_pointer_needed
)
3839 fp_copy_regno
= next_scratch_regno
--;
3841 /* Copy the old frame pointer aside so we can save it later. */
3843 FRP (emit_move_insn (gen_rtx_REG (word_mode
, fp_copy_regno
),
3844 gen_lowpart (word_mode
, hard_frame_pointer_rtx
)));
3845 add_reg_note (insn
, REG_CFA_REGISTER
, NULL_RTX
);
3847 /* Set up the frame pointer. */
3848 insn
= FRP (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
3849 add_reg_note (insn
, REG_CFA_DEF_CFA
, hard_frame_pointer_rtx
);
3850 cfa
= hard_frame_pointer_rtx
;
3851 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM
) = STACK_BOUNDARY
;
3853 /* fp holds a copy of the incoming sp, in case we need to store
3855 sp_copy_regno
= HARD_FRAME_POINTER_REGNUM
;
3857 else if (!tilegx_current_function_is_leaf ())
3859 /* Copy the old stack pointer aside so we can save it later. */
3860 sp_copy_regno
= next_scratch_regno
--;
3861 emit_move_insn (gen_rtx_REG (Pmode
, sp_copy_regno
),
3865 if (tilegx_current_function_is_leaf ())
3867 /* No need to store chain pointer to caller's frame. */
3868 emit_sp_adjust (-total_size
, &next_scratch_regno
,
3869 !frame_pointer_needed
, NULL_RTX
);
3873 /* Save the frame pointer (incoming sp value) to support
3874 backtracing. First we need to create an rtx with the store
3876 rtx chain_addr
= gen_rtx_REG (Pmode
, next_scratch_regno
--);
3877 rtx size_rtx
= GEN_INT (-(total_size
- UNITS_PER_WORD
));
3879 frame_pointer_needed
? UNITS_PER_WORD
- total_size
: UNITS_PER_WORD
;
3881 if (add_operand (size_rtx
, Pmode
))
3883 /* Expose more parallelism by computing this value from the
3884 original stack pointer, not the one after we have pushed
3886 rtx p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, size_rtx
);
3887 emit_insn (gen_rtx_SET (VOIDmode
, chain_addr
, p
));
3888 emit_sp_adjust (-total_size
, &next_scratch_regno
,
3889 !frame_pointer_needed
, NULL_RTX
);
3893 /* The stack frame is large, so just store the incoming sp
3894 value at *(new_sp + UNITS_PER_WORD). */
3896 emit_sp_adjust (-total_size
, &next_scratch_regno
,
3897 !frame_pointer_needed
, NULL_RTX
);
3898 p
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3899 GEN_INT (UNITS_PER_WORD
));
3900 emit_insn (gen_rtx_SET (VOIDmode
, chain_addr
, p
));
3903 /* Save our frame pointer for backtrace chaining. */
3904 emit_insn (gen_movdi (gen_frame_mem (DImode
, chain_addr
),
3905 gen_rtx_REG (DImode
, sp_copy_regno
)));
3908 /* Compute where to start storing registers we need to save. */
3909 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
3910 offset
= start_offset
;
3912 /* Store all registers that need saving. */
3914 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
3915 if (need_to_save_reg (regno
))
3917 rtx r
= reg_save_addr
[which_scratch
];
3919 int cfa_offset
= frame_pointer_needed
? offset
: total_size
+ offset
;
3923 rtx p
= compute_frame_addr (offset
, &next_scratch_regno
);
3924 r
= gen_rtx_REG (Pmode
, next_scratch_regno
--);
3925 reg_save_addr
[which_scratch
] = r
;
3927 emit_insn (gen_rtx_SET (VOIDmode
, r
, p
));
3931 /* Advance to the next stack slot to store this
3933 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
3934 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
3935 emit_insn (gen_rtx_SET (VOIDmode
, r
, p
));
3938 /* Save this register to the stack (but use the old fp value
3939 we copied aside if appropriate). */
3941 (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
3942 ? fp_copy_regno
: regno
;
3943 FRP (frame_emit_store (from_regno
, regno
, r
, cfa
, cfa_offset
));
3945 offset
-= UNITS_PER_WORD
;
3946 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
3949 /* If profiling, force that to happen after the frame is set up. */
3951 emit_insn (gen_blockage ());
3953 /* Load the PIC register if needed. */
3954 if (flag_pic
&& crtl
->uses_pic_offset_table
)
3955 load_pic_register (false);
3959 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
3960 true for a sibcall_epilogue pattern, and false for an epilogue
3963 tilegx_expand_epilogue (bool sibcall_p
)
3965 /* We round-robin through four scratch registers to hold temporary
3966 addresses for saving registers, to make instruction scheduling
3968 rtx reg_save_addr
[ROUND_ROBIN_SIZE
] = {
3969 NULL_RTX
, NULL_RTX
, NULL_RTX
, NULL_RTX
3971 rtx last_insn
, insn
;
3972 unsigned int which_scratch
;
3973 int offset
, start_offset
, regno
;
3974 rtx cfa_restores
= NULL_RTX
;
3976 /* A register that holds a copy of the incoming fp. */
3977 int fp_copy_regno
= -1;
3979 /* Next scratch register number to hand out (postdecrementing). */
3980 int next_scratch_regno
= 29;
3982 int total_size
= compute_total_frame_size ();
3984 last_insn
= get_last_insn ();
3986 /* Load lr first since we are going to need it first. */
3988 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM
))
3990 insn
= frame_emit_load (TILEGX_LINK_REGNUM
,
3991 compute_frame_addr (0, &next_scratch_regno
),
3995 if (total_size
== 0)
3999 RTX_FRAME_RELATED_P (insn
) = 1;
4000 REG_NOTES (insn
) = cfa_restores
;
4005 /* Compute where to start restoring registers. */
4006 start_offset
= -crtl
->args
.pretend_args_size
- UNITS_PER_WORD
;
4007 offset
= start_offset
;
4009 if (frame_pointer_needed
)
4010 fp_copy_regno
= next_scratch_regno
--;
4012 /* Restore all callee-saved registers. */
4014 for (regno
= FIRST_PSEUDO_REGISTER
- 1; regno
>= 0; regno
--)
4015 if (need_to_save_reg (regno
))
4017 rtx r
= reg_save_addr
[which_scratch
];
4020 r
= compute_frame_addr (offset
, &next_scratch_regno
);
4021 reg_save_addr
[which_scratch
] = r
;
4025 /* Advance to the next stack slot to store this register. */
4026 int stride
= ROUND_ROBIN_SIZE
* -UNITS_PER_WORD
;
4027 rtx p
= gen_rtx_PLUS (Pmode
, r
, GEN_INT (stride
));
4028 emit_insn (gen_rtx_SET (VOIDmode
, r
, p
));
4031 if (fp_copy_regno
>= 0 && regno
== HARD_FRAME_POINTER_REGNUM
)
4032 frame_emit_load (fp_copy_regno
, r
, NULL
);
4034 frame_emit_load (regno
, r
, &cfa_restores
);
4036 offset
-= UNITS_PER_WORD
;
4037 which_scratch
= (which_scratch
+ 1) % ROUND_ROBIN_SIZE
;
4040 if (!tilegx_current_function_is_leaf ())
4042 alloc_reg_note (REG_CFA_RESTORE
, stack_pointer_rtx
, cfa_restores
);
4044 emit_insn (gen_blockage ());
4046 if (frame_pointer_needed
)
4048 /* Restore the old stack pointer by copying from the frame
4052 insn
= emit_insn (gen_sp_restore_32bit (stack_pointer_rtx
,
4053 hard_frame_pointer_rtx
));
4057 insn
= emit_insn (gen_sp_restore (stack_pointer_rtx
,
4058 hard_frame_pointer_rtx
));
4060 RTX_FRAME_RELATED_P (insn
) = 1;
4061 REG_NOTES (insn
) = cfa_restores
;
4062 add_reg_note (insn
, REG_CFA_DEF_CFA
, stack_pointer_rtx
);
4066 insn
= emit_sp_adjust (total_size
, &next_scratch_regno
, true,
4070 if (crtl
->calls_eh_return
)
4073 emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx
, stack_pointer_rtx
,
4074 EH_RETURN_STACKADJ_RTX
));
4076 emit_insn (gen_sp_adjust (stack_pointer_rtx
, stack_pointer_rtx
,
4077 EH_RETURN_STACKADJ_RTX
));
4080 /* Restore the old frame pointer. */
4081 if (frame_pointer_needed
)
4083 insn
= emit_move_insn (gen_lowpart (DImode
, hard_frame_pointer_rtx
),
4084 gen_rtx_REG (DImode
, fp_copy_regno
));
4085 add_reg_note (insn
, REG_CFA_RESTORE
, hard_frame_pointer_rtx
);
4088 /* Mark the pic registers as live outside of the function. */
4091 emit_use (cfun
->machine
->text_label_rtx
);
4092 emit_use (cfun
->machine
->got_rtx
);
4098 emit_jump_insn (gen__return ());
4102 emit_use (gen_rtx_REG (Pmode
, TILEGX_LINK_REGNUM
));
4105 /* Mark all insns we just emitted as frame-related. */
4106 for (; last_insn
!= NULL_RTX
; last_insn
= next_insn (last_insn
))
4107 RTX_FRAME_RELATED_P (last_insn
) = 1;
4110 #undef ROUND_ROBIN_SIZE
4113 /* Implement INITIAL_ELIMINATION_OFFSET. */
4115 tilegx_initial_elimination_offset (int from
, int to
)
4117 int total_size
= compute_total_frame_size ();
4119 if (from
== FRAME_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4121 return (total_size
- crtl
->args
.pretend_args_size
4122 - tilegx_saved_regs_size ());
4124 else if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4126 return -(crtl
->args
.pretend_args_size
+ tilegx_saved_regs_size ());
4128 else if (from
== ARG_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
4130 return STACK_POINTER_OFFSET
+ total_size
;
4132 else if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
4134 return STACK_POINTER_OFFSET
;
4141 /* Return an RTX indicating where the return address to the calling
4142 function can be found. */
4144 tilegx_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
4149 return get_hard_reg_initial_val (Pmode
, TILEGX_LINK_REGNUM
);
4153 /* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to
4154 prevent it from being deleted. */
4156 tilegx_eh_return_handler_rtx (void)
4158 rtx tmp
= gen_frame_mem (Pmode
, hard_frame_pointer_rtx
);
4159 MEM_VOLATILE_P (tmp
) = true;
4167 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
4169 tilegx_conditional_register_usage (void)
4171 global_regs
[TILEGX_NETORDER_REGNUM
] = 1;
4172 /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
4173 member of fixed_regs, and therefore must be member of
4174 call_used_regs, but it is not a member of call_really_used_regs[]
4175 because it is not clobbered by a call. */
4176 if (TILEGX_PIC_TEXT_LABEL_REGNUM
!= INVALID_REGNUM
)
4178 fixed_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4179 call_used_regs
[TILEGX_PIC_TEXT_LABEL_REGNUM
] = 1;
4181 if (PIC_OFFSET_TABLE_REGNUM
!= INVALID_REGNUM
)
4183 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4184 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
4189 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
4191 tilegx_frame_pointer_required (void)
4193 return crtl
->calls_eh_return
|| cfun
->calls_alloca
;
4198 /* Scheduling and reorg */
4200 /* Return the length of INSN. LENGTH is the initial length computed
4201 by attributes in the machine-description file. This is where we
4202 account for bundles. */
4204 tilegx_adjust_insn_length (rtx insn
, int length
)
4206 enum machine_mode mode
= GET_MODE (insn
);
4208 /* A non-termininating instruction in a bundle has length 0. */
4212 /* By default, there is not length adjustment. */
4217 /* Implement TARGET_SCHED_ISSUE_RATE. */
4219 tilegx_issue_rate (void)
4225 /* Return the rtx for the jump target. */
4227 get_jump_target (rtx branch
)
4229 if (CALL_P (branch
))
4232 call
= PATTERN (branch
);
4234 if (GET_CODE (call
) == PARALLEL
)
4235 call
= XVECEXP (call
, 0, 0);
4237 if (GET_CODE (call
) == SET
)
4238 call
= SET_SRC (call
);
4240 if (GET_CODE (call
) == CALL
)
4241 return XEXP (XEXP (call
, 0), 0);
4246 /* Implement TARGET_SCHED_ADJUST_COST. */
4248 tilegx_sched_adjust_cost (rtx insn
, rtx link
, rtx dep_insn
, int cost
)
4250 /* If we have a true dependence, INSN is a call, and DEP_INSN
4251 defines a register that is needed by the call (argument or stack
4252 pointer) , set its latency to 0 so that it can be bundled with
4253 the call. Explicitly check for and exclude the case when
4254 DEP_INSN defines the target of the jump. */
4255 if (CALL_P (insn
) && REG_NOTE_KIND (link
) == REG_DEP_TRUE
)
4257 rtx target
= get_jump_target (insn
);
4258 if (!REG_P (target
) || !set_of (target
, dep_insn
))
4266 /* Skip over irrelevant NOTEs and such and look for the next insn we
4267 would consider bundling. */
4269 next_insn_to_bundle (rtx r
, rtx end
)
4271 for (; r
!= end
; r
= NEXT_INSN (r
))
4273 if (NONDEBUG_INSN_P (r
)
4274 && GET_CODE (PATTERN (r
)) != USE
4275 && GET_CODE (PATTERN (r
)) != CLOBBER
)
4283 /* Go through all insns, and use the information generated during
4284 scheduling to generate SEQUENCEs to represent bundles of
4285 instructions issued simultaneously. */
4287 tilegx_gen_bundles (void)
4293 rtx end
= NEXT_INSN (BB_END (bb
));
4295 for (insn
= next_insn_to_bundle (BB_HEAD (bb
), end
); insn
; insn
= next
)
4297 next
= next_insn_to_bundle (NEXT_INSN (insn
), end
);
4299 /* Never wrap {} around inline asm. */
4300 if (GET_CODE (PATTERN (insn
)) != ASM_INPUT
)
4302 if (next
== NULL_RTX
|| GET_MODE (next
) == TImode
4303 /* NOTE: The scheduler incorrectly believes a call
4304 insn can execute in the same cycle as the insn
4305 after the call. This is of course impossible.
4306 Really we need to fix the scheduler somehow, so
4307 the code after the call gets scheduled
4311 /* Mark current insn as the end of a bundle. */
4312 PUT_MODE (insn
, QImode
);
4316 /* Mark it as part of a bundle. */
4317 PUT_MODE (insn
, SImode
);
4325 /* Replace OLD_INSN with NEW_INSN. */
4327 replace_insns (rtx old_insn
, rtx new_insns
)
4330 emit_insn_before (new_insns
, old_insn
);
4332 delete_insn (old_insn
);
4336 /* Returns true if INSN is the first instruction of a pc-relative
4337 address compuatation. */
4339 match_pcrel_step1 (rtx insn
)
4341 rtx pattern
= PATTERN (insn
);
4344 if (GET_CODE (pattern
) != SET
)
4347 src
= SET_SRC (pattern
);
4349 return (GET_CODE (src
) == CONST
4350 && GET_CODE (XEXP (src
, 0)) == UNSPEC
4351 && XINT (XEXP (src
, 0), 1) == UNSPEC_HW1_LAST_PCREL
);
4355 /* Do the first replacement step in tilegx_fixup_pcrel_references. */
4357 replace_mov_pcrel_step1 (rtx insn
)
4359 rtx pattern
= PATTERN (insn
);
4364 gcc_assert (GET_CODE (pattern
) == SET
);
4365 opnds
[0] = SET_DEST (pattern
);
4367 gcc_assert (GET_CODE (SET_SRC (pattern
)) == CONST
);
4369 unspec
= XEXP (SET_SRC (pattern
), 0);
4370 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4371 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW1_LAST_PCREL
);
4372 opnds
[1] = XVECEXP (unspec
, 0, 0);
4374 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4375 if (GET_CODE (opnds
[1]) != SYMBOL_REF
)
4383 emit_insn (gen_mov_got32_step1_32bit (opnds
[0], opnds
[1]));
4385 emit_insn (gen_mov_got32_step1 (opnds
[0], opnds
[1]));
4388 new_insns
= get_insns ();
4391 replace_insns (insn
, new_insns
);
4395 /* Returns true if INSN is the second instruction of a pc-relative
4396 address compuatation. */
4398 match_pcrel_step2 (rtx insn
)
4405 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli_32bit
)
4410 if (recog_memoized (insn
) != CODE_FOR_insn_addr_shl16insli
)
4414 unspec
= SET_SRC (PATTERN (insn
));
4415 addr
= XVECEXP (unspec
, 0, 1);
4417 return (GET_CODE (addr
) == CONST
4418 && GET_CODE (XEXP (addr
, 0)) == UNSPEC
4419 && XINT (XEXP (addr
, 0), 1) == UNSPEC_HW0_PCREL
);
4423 /* Do the second replacement step in tilegx_fixup_pcrel_references. */
4425 replace_mov_pcrel_step2 (rtx insn
)
4427 rtx pattern
= PATTERN (insn
);
4432 rtx got_rtx
= tilegx_got_rtx ();
4434 gcc_assert (GET_CODE (pattern
) == SET
);
4435 opnds
[0] = SET_DEST (pattern
);
4437 unspec
= SET_SRC (pattern
);
4438 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4439 gcc_assert (XINT (unspec
, 1) == UNSPEC_INSN_ADDR_SHL16INSLI
);
4441 opnds
[1] = XVECEXP (unspec
, 0, 0);
4443 addr
= XVECEXP (unspec
, 0, 1);
4444 gcc_assert (GET_CODE (addr
) == CONST
);
4446 unspec
= XEXP (addr
, 0);
4447 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4448 gcc_assert (XINT (unspec
, 1) == UNSPEC_HW0_PCREL
);
4449 opnds
[2] = XVECEXP (unspec
, 0, 0);
4451 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4452 if (GET_CODE (opnds
[2]) != SYMBOL_REF
)
4460 emit_insn (gen_add_got16_32bit (opnds
[0], got_rtx
, opnds
[2]));
4462 emit_insn (gen_add_got16 (opnds
[0], got_rtx
, opnds
[2]));
4467 emit_insn (gen_mov_got32_step2_32bit
4468 (opnds
[0], opnds
[1], opnds
[2]));
4470 emit_insn (gen_mov_got32_step2 (opnds
[0], opnds
[1], opnds
[2]));
4473 new_insns
= get_insns ();
4476 replace_insns (insn
, new_insns
);
4480 /* Do the third replacement step in tilegx_fixup_pcrel_references. */
4482 replace_mov_pcrel_step3 (rtx insn
)
4484 rtx pattern
= PATTERN (insn
);
4488 rtx got_rtx
= tilegx_got_rtx ();
4489 rtx text_label_rtx
= tilegx_text_label_rtx ();
4491 gcc_assert (GET_CODE (pattern
) == SET
);
4492 opnds
[0] = SET_DEST (pattern
);
4494 unspec
= SET_SRC (pattern
);
4495 gcc_assert (GET_CODE (unspec
) == UNSPEC
);
4496 gcc_assert (XINT (unspec
, 1) == UNSPEC_MOV_PCREL_STEP3
);
4500 if (XVECEXP (unspec
, 0, 0) == text_label_rtx
)
4501 opnds
[2] = XVECEXP (unspec
, 0, 1);
4504 gcc_assert (XVECEXP (unspec
, 0, 1) == text_label_rtx
);
4505 opnds
[2] = XVECEXP (unspec
, 0, 0);
4508 opnds
[3] = XVECEXP (unspec
, 0, 2);
4510 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4511 if (GET_CODE (opnds
[3]) != SYMBOL_REF
)
4518 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[2]));
4522 emit_move_insn (opnds
[0], gen_rtx_PLUS (Pmode
, opnds
[1], opnds
[2]));
4523 emit_move_insn (opnds
[0], gen_const_mem (Pmode
, opnds
[0]));
4526 new_insns
= get_insns ();
4529 replace_insns (insn
, new_insns
);
4533 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4534 going through the GOT when the symbol is local to the compilation
4535 unit. But such a symbol requires that the common text_label that
4536 we generate at the beginning of the function be in the same section
4537 as the reference to the SYMBOL_REF. This may not be true if we
4538 generate hot/cold sections. This function looks for such cases and
4539 replaces such references with the longer sequence going through the
4542 We expect following instruction sequence:
4543 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4544 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4545 add<x> tmp3, txt_label_reg, tmp2 [3]
4547 If we're compiling -fpic, we replace with the following sequence
4548 (the numbers in brackets match the instructions they're replacing
4551 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4552 ld<4> tmp3, tmp2 [3]
4554 If we're compiling -fPIC, we replace the first instruction with:
4556 moveli tmp1, hw1_last_got(x) [1]
4557 shl16insli tmp2, tmp1, hw0_got(x) [2]
4558 add<x> tmp3, got_reg, tmp2 [3]
4559 ld<4> tmp3, tmp3 [3]
4561 Note that we're careful to disturb the instruction sequence as
4562 little as possible, since it's very late in the compilation
4565 tilegx_fixup_pcrel_references (void)
4567 rtx insn
, next_insn
;
4568 bool same_section_as_entry
= true;
4570 for (insn
= get_insns (); insn
; insn
= next_insn
)
4572 next_insn
= NEXT_INSN (insn
);
4574 if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_SWITCH_TEXT_SECTIONS
)
4576 same_section_as_entry
= !same_section_as_entry
;
4580 if (same_section_as_entry
)
4584 && GET_CODE (PATTERN (insn
)) != USE
4585 && GET_CODE (PATTERN (insn
)) != CLOBBER
))
4590 if (match_pcrel_step1 (insn
))
4591 replace_mov_pcrel_step1 (insn
);
4592 else if (match_pcrel_step2 (insn
))
4593 replace_mov_pcrel_step2 (insn
);
4594 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3_32bit
)
4595 replace_mov_pcrel_step3 (insn
);
4599 if (match_pcrel_step1 (insn
))
4600 replace_mov_pcrel_step1 (insn
);
4601 else if (match_pcrel_step2 (insn
))
4602 replace_mov_pcrel_step2 (insn
);
4603 else if (recog_memoized (insn
) == CODE_FOR_mov_pcrel_step3
)
4604 replace_mov_pcrel_step3 (insn
);
4610 /* Ensure that no var tracking notes are emitted in the middle of a
4611 three-instruction bundle. */
4613 reorder_var_tracking_notes (void)
4619 rtx queue
= NULL_RTX
;
4620 bool in_bundle
= false;
4622 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4624 next
= NEXT_INSN (insn
);
4628 /* Emit queued up notes at the last instruction of a
4630 if (GET_MODE (insn
) == QImode
)
4634 rtx next_queue
= PREV_INSN (queue
);
4635 PREV_INSN (NEXT_INSN (insn
)) = queue
;
4636 NEXT_INSN (queue
) = NEXT_INSN (insn
);
4637 NEXT_INSN (insn
) = queue
;
4638 PREV_INSN (queue
) = insn
;
4643 else if (GET_MODE (insn
) == SImode
)
4646 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4650 rtx prev
= PREV_INSN (insn
);
4651 PREV_INSN (next
) = prev
;
4652 NEXT_INSN (prev
) = next
;
4654 PREV_INSN (insn
) = queue
;
4663 /* Perform machine dependent operations on the rtl chain INSNS. */
4667 /* We are freeing block_for_insn in the toplev to keep compatibility
4668 with old MDEP_REORGS that are not CFG based. Recompute it
4670 compute_bb_for_insn ();
4672 if (flag_reorder_blocks_and_partition
)
4674 tilegx_fixup_pcrel_references ();
4677 if (flag_schedule_insns_after_reload
)
4681 timevar_push (TV_SCHED2
);
4683 timevar_pop (TV_SCHED2
);
4685 /* Examine the schedule to group into bundles. */
4686 tilegx_gen_bundles ();
4691 if (flag_var_tracking
)
4693 timevar_push (TV_VAR_TRACKING
);
4694 variable_tracking_main ();
4695 reorder_var_tracking_notes ();
4696 timevar_pop (TV_VAR_TRACKING
);
4699 df_finish_pass (false);
4706 /* Select a format to encode pointers in exception handling data.
4707 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4708 GLOBAL is true if the symbol may be affected by dynamic
4711 tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED
, int global
)
4715 int type
= TARGET_32BIT
? DW_EH_PE_sdata4
: DW_EH_PE_sdata8
;
4716 return (global
? DW_EH_PE_indirect
: 0) | DW_EH_PE_pcrel
| type
;
4719 return DW_EH_PE_absptr
;
4723 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4725 tilegx_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
4726 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
4729 rtx this_rtx
, insn
, funexp
, addend
;
4731 /* Pretend to be a post-reload pass while generating rtl. */
4732 reload_completed
= 1;
4734 /* Mark the end of the (empty) prologue. */
4735 emit_note (NOTE_INSN_PROLOGUE_END
);
4737 /* Find the "this" pointer. If the function returns a structure,
4738 the structure return pointer is in $1. */
4739 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
4740 this_rtx
= gen_rtx_REG (Pmode
, 1);
4742 this_rtx
= gen_rtx_REG (Pmode
, 0);
4744 /* Add DELTA to THIS_RTX. */
4745 if (!(delta
>= -32868 && delta
<= 32767))
4747 addend
= gen_rtx_REG (Pmode
, 29);
4748 emit_move_insn (addend
, GEN_INT (delta
));
4751 addend
= GEN_INT (delta
);
4754 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, addend
));
4756 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, addend
));
4758 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4763 tmp
= gen_rtx_REG (Pmode
, 29);
4764 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, this_rtx
));
4766 if (!(vcall_offset
>= -32868 && vcall_offset
<= 32767))
4768 addend
= gen_rtx_REG (Pmode
, 28);
4769 emit_move_insn (addend
, GEN_INT (vcall_offset
));
4772 addend
= GEN_INT (vcall_offset
);
4775 emit_insn (gen_addsi3 (tmp
, tmp
, addend
));
4777 emit_insn (gen_adddi3 (tmp
, tmp
, addend
));
4779 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, tmp
));
4782 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, tmp
));
4784 emit_insn (gen_adddi3 (this_rtx
, this_rtx
, tmp
));
4787 /* Generate a tail call to the target function. */
4788 if (!TREE_USED (function
))
4790 assemble_external (function
);
4791 TREE_USED (function
) = 1;
4793 funexp
= XEXP (DECL_RTL (function
), 0);
4794 funexp
= gen_rtx_MEM (FUNCTION_MODE
, funexp
);
4795 insn
= emit_call_insn (gen_sibcall (funexp
, const0_rtx
));
4796 SIBLING_CALL_P (insn
) = 1;
4798 /* Run just enough of rest_of_compilation to get the insns emitted.
4799 There's not really enough bulk here to make other passes such as
4800 instruction scheduling worth while. Note that use_thunk calls
4801 assemble_start_function and assemble_end_function.
4803 We don't currently bundle, but the instruciton sequence is all
4804 serial except for the tail call, so we're only wasting one cycle.
4806 insn
= get_insns ();
4807 insn_locators_alloc ();
4808 shorten_branches (insn
);
4809 final_start_function (insn
, file
, 1);
4810 final (insn
, file
, 1);
4811 final_end_function ();
4813 /* Stop pretending to be a post-reload pass. */
4814 reload_completed
= 0;
4818 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
4820 tilegx_asm_trampoline_template (FILE *file
)
4822 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
4825 fprintf (file
, "\tlnk r10\n");
4826 fprintf (file
, "\taddxi r10, r10, 32\n");
4827 fprintf (file
, "\tld4s_add r11, r10, %d\n", ptr_mode_size
);
4828 fprintf (file
, "\tld4s r10, r10\n");
4829 fprintf (file
, "\tjr r11\n");
4830 fprintf (file
, "\t.word 0 # <function address>\n");
4831 fprintf (file
, "\t.word 0 # <static chain value>\n");
4835 fprintf (file
, "\tlnk r10\n");
4836 fprintf (file
, "\taddi r10, r10, 32\n");
4837 fprintf (file
, "\tld_add r11, r10, %d\n", ptr_mode_size
);
4838 fprintf (file
, "\tld r10, r10\n");
4839 fprintf (file
, "\tjr r11\n");
4840 fprintf (file
, "\t.quad 0 # <function address>\n");
4841 fprintf (file
, "\t.quad 0 # <static chain value>\n");
4846 /* Implement TARGET_TRAMPOLINE_INIT. */
4848 tilegx_trampoline_init (rtx m_tramp
, tree fndecl
, rtx static_chain
)
4852 rtx begin_addr
, end_addr
;
4853 int ptr_mode_size
= GET_MODE_SIZE (ptr_mode
);
4855 fnaddr
= copy_to_reg (XEXP (DECL_RTL (fndecl
), 0));
4856 chaddr
= copy_to_reg (static_chain
);
4858 emit_block_move (m_tramp
, assemble_trampoline_template (),
4859 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
4861 mem
= adjust_address (m_tramp
, ptr_mode
,
4862 TRAMPOLINE_SIZE
- 2 * ptr_mode_size
);
4863 emit_move_insn (mem
, fnaddr
);
4864 mem
= adjust_address (m_tramp
, ptr_mode
,
4865 TRAMPOLINE_SIZE
- ptr_mode_size
);
4866 emit_move_insn (mem
, chaddr
);
4868 /* Get pointers to the beginning and end of the code block. */
4869 begin_addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
4870 end_addr
= force_reg (Pmode
, plus_constant (Pmode
, XEXP (m_tramp
, 0),
4873 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__clear_cache"),
4874 LCT_NORMAL
, VOIDmode
, 2, begin_addr
, Pmode
,
4879 /* Implement TARGET_PRINT_OPERAND. */
4881 tilegx_print_operand (FILE *file
, rtx x
, int code
)
4886 /* Print the compare operator opcode for conditional moves. */
4887 switch (GET_CODE (x
))
4896 output_operand_lossage ("invalid %%c operand");
4901 /* Print the compare operator opcode for conditional moves. */
4902 switch (GET_CODE (x
))
4911 output_operand_lossage ("invalid %%C operand");
4917 /* Print the compare operator opcode for conditional moves. */
4918 switch (GET_CODE (x
))
4927 output_operand_lossage ("invalid %%d operand");
4934 /* Print the compare operator opcode for conditional moves. */
4935 switch (GET_CODE (x
))
4944 output_operand_lossage ("invalid %%D operand");
4951 if (GET_CODE (x
) == CONST
4952 && GET_CODE (XEXP (x
, 0)) == UNSPEC
)
4954 rtx addr
= XVECEXP (XEXP (x
, 0), 0, 0);
4955 int unspec
= XINT (XEXP (x
, 0), 1);
4956 const char *opstr
= NULL
;
4960 case UNSPEC_HW0_PCREL
:
4972 case UNSPEC_HW0_LAST
:
4975 case UNSPEC_HW1_LAST
:
4976 case UNSPEC_HW1_LAST_PCREL
:
4979 case UNSPEC_HW2_LAST
:
4982 case UNSPEC_HW0_GOT
:
4985 case UNSPEC_HW0_LAST_GOT
:
4986 opstr
= "hw0_last_got";
4988 case UNSPEC_HW1_LAST_GOT
:
4989 opstr
= "hw1_last_got";
4991 case UNSPEC_HW0_TLS_GD
:
4992 opstr
= "hw0_tls_gd";
4994 case UNSPEC_HW1_LAST_TLS_GD
:
4995 opstr
= "hw1_last_tls_gd";
4997 case UNSPEC_HW0_TLS_IE
:
4998 opstr
= "hw0_tls_ie";
5000 case UNSPEC_HW1_LAST_TLS_IE
:
5001 opstr
= "hw1_last_tls_ie";
5003 case UNSPEC_HW0_TLS_LE
:
5004 opstr
= "hw0_tls_le";
5006 case UNSPEC_HW1_LAST_TLS_LE
:
5007 opstr
= "hw1_last_tls_le";
5010 output_operand_lossage ("invalid %%H specifier");
5013 fputs (opstr
, file
);
5015 output_addr_const (file
, addr
);
5017 if (unspec
== UNSPEC_HW0_PCREL
5018 || unspec
== UNSPEC_HW1_LAST_PCREL
)
5020 rtx addr2
= XVECEXP (XEXP (x
, 0), 0, 1);
5021 fputs (" - " , file
);
5022 output_addr_const (file
, addr2
);
5028 else if (symbolic_operand (x
, VOIDmode
))
5030 output_addr_const (file
, x
);
5038 /* Print the low 16 bits of a constant. */
5040 if (CONST_INT_P (x
))
5042 else if (GET_CODE (x
) == CONST_DOUBLE
)
5043 i
= CONST_DOUBLE_LOW (x
);
5046 output_operand_lossage ("invalid %%h operand");
5049 i
= trunc_int_for_mode (i
, HImode
);
5050 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5055 /* Print an auto-inc memory operand. */
5058 output_operand_lossage ("invalid %%I operand");
5062 output_memory_reference_mode
= GET_MODE (x
);
5063 output_memory_autoinc_first
= true;
5064 output_address (XEXP (x
, 0));
5065 output_memory_reference_mode
= VOIDmode
;
5069 /* Print an auto-inc memory operand. */
5072 output_operand_lossage ("invalid %%i operand");
5076 output_memory_reference_mode
= GET_MODE (x
);
5077 output_memory_autoinc_first
= false;
5078 output_address (XEXP (x
, 0));
5079 output_memory_reference_mode
= VOIDmode
;
5084 /* Print the low 8 bits of a constant. */
5086 if (CONST_INT_P (x
))
5088 else if (GET_CODE (x
) == CONST_DOUBLE
)
5089 i
= CONST_DOUBLE_LOW (x
);
5090 else if (GET_CODE (x
) == CONST_VECTOR
5091 && CONST_INT_P (CONST_VECTOR_ELT (x
, 0)))
5092 i
= INTVAL (CONST_VECTOR_ELT (x
, 0));
5095 output_operand_lossage ("invalid %%j operand");
5098 i
= trunc_int_for_mode (i
, QImode
);
5099 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, i
);
5105 /* Print a constant plus one. */
5106 if (!CONST_INT_P (x
))
5108 output_operand_lossage ("invalid %%P operand");
5111 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (x
) + 1);
5118 /* Print a bfextu-style bit range. */
5119 int first_bit
, last_bit
;
5120 HOST_WIDE_INT flip
= (code
== 'm') ? ~0 : 0;
5122 if (!CONST_INT_P (x
)
5123 || !tilegx_bitfield_operand_p (INTVAL (x
) ^ flip
,
5124 &first_bit
, &last_bit
))
5126 output_operand_lossage ("invalid %%%c operand", code
);
5130 fprintf (file
, "%d, %d", first_bit
, last_bit
);
5136 const char *reg
= NULL
;
5138 /* Print a network register. */
5139 if (!CONST_INT_P (x
))
5141 output_operand_lossage ("invalid %%N operand");
5147 case TILEGX_NETREG_IDN0
: reg
= "idn0"; break;
5148 case TILEGX_NETREG_IDN1
: reg
= "idn1"; break;
5149 case TILEGX_NETREG_UDN0
: reg
= "udn0"; break;
5150 case TILEGX_NETREG_UDN1
: reg
= "udn1"; break;
5151 case TILEGX_NETREG_UDN2
: reg
= "udn2"; break;
5152 case TILEGX_NETREG_UDN3
: reg
= "udn3"; break;
5157 fprintf (file
, reg
);
5162 if (GET_CODE (x
) == SYMBOL_REF
)
5164 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5165 fprintf (file
, "plt(");
5166 output_addr_const (file
, x
);
5167 if (flag_pic
&& !SYMBOL_REF_LOCAL_P (x
))
5168 fprintf (file
, ")");
5171 output_addr_const (file
, x
);
5175 /* In this case we need a register. Use 'zero' if the operand
5178 || (GET_MODE (x
) != VOIDmode
&& x
== CONST0_RTX (GET_MODE (x
))))
5180 fputs ("zero", file
);
5183 else if (!REG_P (x
))
5185 output_operand_lossage ("invalid operand for 'r' specifier");
5193 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
5198 output_memory_reference_mode
= VOIDmode
;
5199 output_address (XEXP (x
, 0));
5204 output_addr_const (file
, x
);
5210 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5215 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5217 tilegx_print_operand_address (FILE *file
, rtx addr
)
5219 if (GET_CODE (addr
) == POST_DEC
5220 || GET_CODE (addr
) == POST_INC
)
5222 int offset
= GET_MODE_SIZE (output_memory_reference_mode
);
5224 gcc_assert (output_memory_reference_mode
!= VOIDmode
);
5226 if (output_memory_autoinc_first
)
5227 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5229 fprintf (file
, "%d",
5230 GET_CODE (addr
) == POST_DEC
? -offset
: offset
);
5232 else if (GET_CODE (addr
) == POST_MODIFY
)
5234 gcc_assert (output_memory_reference_mode
!= VOIDmode
);
5236 gcc_assert (GET_CODE (XEXP (addr
, 1)) == PLUS
);
5238 if (output_memory_autoinc_first
)
5239 fprintf (file
, "%s", reg_names
[REGNO (XEXP (addr
, 0))]);
5241 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
,
5242 INTVAL (XEXP (XEXP (addr
, 1), 1)));
5245 tilegx_print_operand (file
, addr
, 'r');
5249 /* Machine mode of current insn, for determining curly brace
5251 static enum machine_mode insn_mode
;
5254 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5256 tilegx_final_prescan_insn (rtx insn
)
5258 /* Record this for tilegx_asm_output_opcode to examine. */
5259 insn_mode
= GET_MODE (insn
);
5263 /* While emitting asm, are we currently inside '{' for a bundle? */
5264 static bool tilegx_in_bundle
= false;
5266 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5267 appropriate given the bundling information recorded by
5268 tilegx_gen_bundles. */
5270 tilegx_asm_output_opcode (FILE *stream
, const char *code
)
5272 bool pseudo
= !strcmp (code
, "pseudo");
5274 if (!tilegx_in_bundle
&& insn_mode
== SImode
)
5276 /* Start a new bundle. */
5277 fprintf (stream
, "{\n\t");
5278 tilegx_in_bundle
= true;
5281 if (tilegx_in_bundle
&& insn_mode
== QImode
)
5283 /* Close an existing bundle. */
5284 static char buf
[100];
5286 gcc_assert (strlen (code
) + 3 + 1 < sizeof (buf
));
5288 strcpy (buf
, pseudo
? "" : code
);
5289 strcat (buf
, "\n\t}");
5290 tilegx_in_bundle
= false;
5296 return pseudo
? "" : code
;
5301 /* Output assembler code to FILE to increment profiler label # LABELNO
5302 for profiling a function entry. */
5304 tilegx_function_profiler (FILE *file
, int labelno ATTRIBUTE_UNUSED
)
5306 if (tilegx_in_bundle
)
5308 fprintf (file
, "\t}\n");
5317 "\t}\n", MCOUNT_NAME
);
5325 "\t}\t\n", MCOUNT_NAME
);
5328 tilegx_in_bundle
= false;
5332 /* Implement TARGET_ASM_FILE_END. */
5334 tilegx_file_end (void)
5336 if (NEED_INDICATE_EXEC_STACK
)
5337 file_end_indicate_exec_stack ();
5342 #undef TARGET_HAVE_TLS
5343 #define TARGET_HAVE_TLS HAVE_AS_TLS
5345 #undef TARGET_OPTION_OVERRIDE
5346 #define TARGET_OPTION_OVERRIDE tilegx_option_override
5348 #undef TARGET_SCALAR_MODE_SUPPORTED_P
5349 #define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5351 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5352 #define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5354 #undef TARGET_CANNOT_FORCE_CONST_MEM
5355 #define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5357 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5358 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5360 #undef TARGET_PASS_BY_REFERENCE
5361 #define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5363 #undef TARGET_RETURN_IN_MEMORY
5364 #define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5366 #undef TARGET_MODE_REP_EXTENDED
5367 #define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5369 #undef TARGET_FUNCTION_ARG_BOUNDARY
5370 #define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5372 #undef TARGET_FUNCTION_ARG
5373 #define TARGET_FUNCTION_ARG tilegx_function_arg
5375 #undef TARGET_FUNCTION_ARG_ADVANCE
5376 #define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5378 #undef TARGET_FUNCTION_VALUE
5379 #define TARGET_FUNCTION_VALUE tilegx_function_value
5381 #undef TARGET_LIBCALL_VALUE
5382 #define TARGET_LIBCALL_VALUE tilegx_libcall_value
5384 #undef TARGET_FUNCTION_VALUE_REGNO_P
5385 #define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5387 #undef TARGET_PROMOTE_FUNCTION_MODE
5388 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5390 #undef TARGET_PROMOTE_PROTOTYPES
5391 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5393 #undef TARGET_BUILD_BUILTIN_VA_LIST
5394 #define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5396 #undef TARGET_EXPAND_BUILTIN_VA_START
5397 #define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5399 #undef TARGET_SETUP_INCOMING_VARARGS
5400 #define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5402 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5403 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5405 #undef TARGET_RTX_COSTS
5406 #define TARGET_RTX_COSTS tilegx_rtx_costs
5408 #undef TARGET_SHIFT_TRUNCATION_MASK
5409 #define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5411 #undef TARGET_INIT_LIBFUNCS
5412 #define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5414 /* Limit to what we can reach in one addli. */
5415 #undef TARGET_MIN_ANCHOR_OFFSET
5416 #define TARGET_MIN_ANCHOR_OFFSET -32768
5417 #undef TARGET_MAX_ANCHOR_OFFSET
5418 #define TARGET_MAX_ANCHOR_OFFSET 32767
5420 #undef TARGET_LEGITIMATE_CONSTANT_P
5421 #define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5423 #undef TARGET_LEGITIMATE_ADDRESS_P
5424 #define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5426 #undef TARGET_LEGITIMIZE_ADDRESS
5427 #define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5429 #undef TARGET_DELEGITIMIZE_ADDRESS
5430 #define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5432 #undef TARGET_INIT_BUILTINS
5433 #define TARGET_INIT_BUILTINS tilegx_init_builtins
5435 #undef TARGET_BUILTIN_DECL
5436 #define TARGET_BUILTIN_DECL tilegx_builtin_decl
5438 #undef TARGET_EXPAND_BUILTIN
5439 #define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5441 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5442 #define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5444 #undef TARGET_FRAME_POINTER_REQUIRED
5445 #define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5447 #undef TARGET_DELAY_SCHED2
5448 #define TARGET_DELAY_SCHED2 true
5450 #undef TARGET_DELAY_VARTRACK
5451 #define TARGET_DELAY_VARTRACK true
5453 #undef TARGET_SCHED_ISSUE_RATE
5454 #define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5456 #undef TARGET_SCHED_ADJUST_COST
5457 #define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5459 #undef TARGET_MACHINE_DEPENDENT_REORG
5460 #define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5462 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5463 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5464 hook_bool_const_tree_hwi_hwi_const_tree_true
5466 #undef TARGET_ASM_OUTPUT_MI_THUNK
5467 #define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5469 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5470 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5472 #undef TARGET_TRAMPOLINE_INIT
5473 #define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5475 #undef TARGET_PRINT_OPERAND
5476 #define TARGET_PRINT_OPERAND tilegx_print_operand
5478 #undef TARGET_PRINT_OPERAND_ADDRESS
5479 #define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5481 #undef TARGET_ASM_FILE_END
5482 #define TARGET_ASM_FILE_END tilegx_file_end
5484 #undef TARGET_ASM_ALIGNED_DI_OP
5485 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5488 struct gcc_target targetm
= TARGET_INITIALIZER
;
5490 #include "gt-tilegx.h"