PR target/81369
[official-gcc.git] / gcc / config / tilepro / tilepro.c
blob80475b959eee5de1970d17c100030de674c36a3c
1 /* Subroutines used for code generation on the Tilera TILEPro.
2 Copyright (C) 2011-2017 Free Software Foundation, Inc.
3 Contributed by Walter Lee (walt@tilera.com)
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "target.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "gimple.h"
29 #include "df.h"
30 #include "memmodel.h"
31 #include "tm_p.h"
32 #include "stringpool.h"
33 #include "expmed.h"
34 #include "optabs.h"
35 #include "regs.h"
36 #include "emit-rtl.h"
37 #include "recog.h"
38 #include "diagnostic.h"
39 #include "output.h"
40 #include "insn-attr.h"
41 #include "alias.h"
42 #include "explow.h"
43 #include "calls.h"
44 #include "varasm.h"
45 #include "expr.h"
46 #include "langhooks.h"
47 #include "cfgrtl.h"
48 #include "tm-constrs.h"
49 #include "dwarf2.h"
50 #include "fold-const.h"
51 #include "stor-layout.h"
52 #include "gimplify.h"
53 #include "tilepro-builtins.h"
54 #include "tilepro-multiply.h"
55 #include "builtins.h"
57 /* This file should be included last. */
58 #include "target-def.h"
60 /* SYMBOL_REF for GOT */
61 static GTY(()) rtx g_got_symbol = NULL;
63 /* Report whether we're printing out the first address fragment of a
64 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
65 TARGET_PRINT_OPERAND_ADDRESS. */
66 static bool output_memory_autoinc_first;
70 /* Option handling */
72 /* Implement TARGET_OPTION_OVERRIDE. */
73 static void
74 tilepro_option_override (void)
76 /* When modulo scheduling is enabled, we still rely on regular
77 scheduler for bundling. */
78 if (flag_modulo_sched)
79 flag_resched_modulo_sched = 1;
84 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
85 static bool
86 tilepro_scalar_mode_supported_p (machine_mode mode)
88 switch (mode)
90 case QImode:
91 case HImode:
92 case SImode:
93 case DImode:
94 return true;
96 case SFmode:
97 case DFmode:
98 return true;
100 default:
101 return false;
106 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
107 static bool
108 tile_vector_mode_supported_p (machine_mode mode)
110 return mode == V4QImode || mode == V2HImode;
114 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
115 static bool
116 tilepro_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED,
117 rtx x ATTRIBUTE_UNUSED)
119 return true;
123 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
124 static bool
125 tilepro_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
127 return decl != NULL;
131 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
132 passed by reference. */
133 static bool
134 tilepro_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
135 machine_mode mode ATTRIBUTE_UNUSED,
136 const_tree type, bool named ATTRIBUTE_UNUSED)
138 return (type && TYPE_SIZE (type)
139 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST);
143 /* Implement TARGET_RETURN_IN_MEMORY. */
144 static bool
145 tilepro_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
147 return !IN_RANGE (int_size_in_bytes (type),
148 0, TILEPRO_NUM_RETURN_REGS * UNITS_PER_WORD);
152 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
153 static unsigned int
154 tilepro_function_arg_boundary (machine_mode mode, const_tree type)
156 unsigned int alignment;
158 alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode);
159 if (alignment < PARM_BOUNDARY)
160 alignment = PARM_BOUNDARY;
161 if (alignment > STACK_BOUNDARY)
162 alignment = STACK_BOUNDARY;
163 return alignment;
167 /* Implement TARGET_FUNCTION_ARG. */
168 static rtx
169 tilepro_function_arg (cumulative_args_t cum_v,
170 machine_mode mode,
171 const_tree type, bool named ATTRIBUTE_UNUSED)
173 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
174 int byte_size = ((mode == BLKmode)
175 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
176 bool doubleword_aligned_p;
178 if (cum >= TILEPRO_NUM_ARG_REGS)
179 return NULL_RTX;
181 /* See whether the argument has doubleword alignment. */
182 doubleword_aligned_p =
183 tilepro_function_arg_boundary (mode, type) > BITS_PER_WORD;
185 if (doubleword_aligned_p)
186 cum += cum & 1;
188 /* The ABI does not allow parameters to be passed partially in reg
189 and partially in stack. */
190 if ((cum + (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
191 > TILEPRO_NUM_ARG_REGS)
192 return NULL_RTX;
194 return gen_rtx_REG (mode, cum);
198 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
199 static void
200 tilepro_function_arg_advance (cumulative_args_t cum_v,
201 machine_mode mode,
202 const_tree type, bool named ATTRIBUTE_UNUSED)
204 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
206 int byte_size = ((mode == BLKmode)
207 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
208 int word_size = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
209 bool doubleword_aligned_p;
211 /* See whether the argument has doubleword alignment. */
212 doubleword_aligned_p =
213 tilepro_function_arg_boundary (mode, type) > BITS_PER_WORD;
215 if (doubleword_aligned_p)
216 *cum += *cum & 1;
218 /* If the current argument does not fit in the pretend_args space,
219 skip over it. */
220 if (*cum < TILEPRO_NUM_ARG_REGS
221 && *cum + word_size > TILEPRO_NUM_ARG_REGS)
222 *cum = TILEPRO_NUM_ARG_REGS;
224 *cum += word_size;
228 /* Implement TARGET_FUNCTION_VALUE. */
229 static rtx
230 tilepro_function_value (const_tree valtype, const_tree fn_decl_or_type,
231 bool outgoing ATTRIBUTE_UNUSED)
233 machine_mode mode;
234 int unsigned_p;
236 mode = TYPE_MODE (valtype);
237 unsigned_p = TYPE_UNSIGNED (valtype);
239 mode = promote_function_mode (valtype, mode, &unsigned_p,
240 fn_decl_or_type, 1);
242 return gen_rtx_REG (mode, 0);
246 /* Implement TARGET_LIBCALL_VALUE. */
247 static rtx
248 tilepro_libcall_value (machine_mode mode,
249 const_rtx fun ATTRIBUTE_UNUSED)
251 return gen_rtx_REG (mode, 0);
255 /* Implement FUNCTION_VALUE_REGNO_P. */
256 static bool
257 tilepro_function_value_regno_p (const unsigned int regno)
259 return regno < TILEPRO_NUM_RETURN_REGS;
263 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
264 static tree
265 tilepro_build_builtin_va_list (void)
267 tree f_args, f_skip, record, type_decl;
268 bool owp;
270 record = lang_hooks.types.make_type (RECORD_TYPE);
272 type_decl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
273 get_identifier ("__va_list_tag"), record);
275 f_args = build_decl (BUILTINS_LOCATION, FIELD_DECL,
276 get_identifier ("__args"), ptr_type_node);
277 f_skip = build_decl (BUILTINS_LOCATION, FIELD_DECL,
278 get_identifier ("__skip"), ptr_type_node);
280 DECL_FIELD_CONTEXT (f_args) = record;
282 DECL_FIELD_CONTEXT (f_skip) = record;
284 TREE_CHAIN (record) = type_decl;
285 TYPE_NAME (record) = type_decl;
286 TYPE_FIELDS (record) = f_args;
287 TREE_CHAIN (f_args) = f_skip;
289 /* We know this is being padded and we want it too. It is an
290 internal type so hide the warnings from the user. */
291 owp = warn_padded;
292 warn_padded = false;
294 layout_type (record);
296 warn_padded = owp;
298 /* The correct type is an array type of one element. */
299 return record;
303 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
304 static void
305 tilepro_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
307 tree f_args, f_skip;
308 tree args, skip, t;
310 f_args = TYPE_FIELDS (TREE_TYPE (valist));
311 f_skip = TREE_CHAIN (f_args);
313 args =
314 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
315 skip =
316 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
318 /* Find the __args area. */
319 t = make_tree (TREE_TYPE (args), virtual_incoming_args_rtx);
320 t = fold_build_pointer_plus_hwi (t,
321 UNITS_PER_WORD *
322 (crtl->args.info - TILEPRO_NUM_ARG_REGS));
324 if (crtl->args.pretend_args_size > 0)
325 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
327 t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t);
328 TREE_SIDE_EFFECTS (t) = 1;
329 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
331 /* Find the __skip area. */
332 t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx);
333 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
334 t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t);
335 TREE_SIDE_EFFECTS (t) = 1;
336 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
340 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
341 static void
342 tilepro_setup_incoming_varargs (cumulative_args_t cum,
343 machine_mode mode,
344 tree type, int *pretend_args, int no_rtl)
346 CUMULATIVE_ARGS local_cum = *get_cumulative_args (cum);
347 int first_reg;
349 /* The caller has advanced CUM up to, but not beyond, the last named
350 argument. Advance a local copy of CUM past the last "real" named
351 argument, to find out how many registers are left over. */
352 targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum),
353 mode, type, true);
354 first_reg = local_cum;
356 if (local_cum < TILEPRO_NUM_ARG_REGS)
358 *pretend_args = UNITS_PER_WORD * (TILEPRO_NUM_ARG_REGS - first_reg);
360 if (!no_rtl)
362 alias_set_type set = get_varargs_alias_set ();
363 rtx tmp =
364 gen_rtx_MEM (BLKmode, plus_constant (Pmode, \
365 virtual_incoming_args_rtx,
366 -STACK_POINTER_OFFSET -
367 UNITS_PER_WORD *
368 (TILEPRO_NUM_ARG_REGS -
369 first_reg)));
370 MEM_NOTRAP_P (tmp) = 1;
371 set_mem_alias_set (tmp, set);
372 move_block_from_reg (first_reg, tmp,
373 TILEPRO_NUM_ARG_REGS - first_reg);
376 else
377 *pretend_args = 0;
381 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
382 the va_list structure VALIST as required to retrieve an argument of
383 type TYPE, and returning that argument.
385 ret = va_arg(VALIST, TYPE);
387 generates code equivalent to:
389 paddedsize = (sizeof(TYPE) + 3) & -4;
390 if ((VALIST.__args + paddedsize > VALIST.__skip)
391 & (VALIST.__args <= VALIST.__skip))
392 addr = VALIST.__skip + STACK_POINTER_OFFSET;
393 else
394 addr = VALIST.__args;
395 VALIST.__args = addr + paddedsize;
396 ret = *(TYPE *)addr; */
397 static tree
398 tilepro_gimplify_va_arg_expr (tree valist, tree type, gimple_seq * pre_p,
399 gimple_seq * post_p ATTRIBUTE_UNUSED)
401 tree f_args, f_skip;
402 tree args, skip;
403 HOST_WIDE_INT size, rsize;
404 tree addr, tmp;
405 bool pass_by_reference_p;
407 f_args = TYPE_FIELDS (va_list_type_node);
408 f_skip = TREE_CHAIN (f_args);
410 args =
411 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
412 skip =
413 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
415 addr = create_tmp_var (ptr_type_node, "va_arg");
417 /* if an object is dynamically sized, a pointer to it is passed
418 instead of the object itself. */
419 pass_by_reference_p = pass_by_reference (NULL, TYPE_MODE (type), type,
420 false);
422 if (pass_by_reference_p)
423 type = build_pointer_type (type);
425 size = int_size_in_bytes (type);
426 rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD;
428 /* If the alignment of the type is greater than the default for a
429 parameter, align to STACK_BOUNDARY. */
430 if (TYPE_ALIGN (type) > PARM_BOUNDARY)
432 /* Assert the only case we generate code for: when
433 stack boundary = 2 * parm boundary. */
434 gcc_assert (STACK_BOUNDARY == PARM_BOUNDARY * 2);
436 tmp = build2 (BIT_AND_EXPR, sizetype,
437 fold_convert (sizetype, unshare_expr (args)),
438 size_int (PARM_BOUNDARY / 8));
439 tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node,
440 unshare_expr (args), tmp);
442 gimplify_assign (unshare_expr (args), tmp, pre_p);
445 /* Build conditional expression to calculate addr. The expression
446 will be gimplified later. */
447 tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize);
448 tmp = build2 (TRUTH_AND_EXPR, boolean_type_node,
449 build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)),
450 build2 (LE_EXPR, boolean_type_node, unshare_expr (args),
451 unshare_expr (skip)));
453 tmp = build3 (COND_EXPR, ptr_type_node, tmp,
454 build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip),
455 size_int (STACK_POINTER_OFFSET)),
456 unshare_expr (args));
458 gimplify_assign (addr, tmp, pre_p);
460 /* Update VALIST.__args. */
461 tmp = fold_build_pointer_plus_hwi (addr, rsize);
462 gimplify_assign (unshare_expr (args), tmp, pre_p);
464 addr = fold_convert (build_pointer_type (type), addr);
466 if (pass_by_reference_p)
467 addr = build_va_arg_indirect_ref (addr);
469 return build_va_arg_indirect_ref (addr);
474 /* Implement TARGET_RTX_COSTS. */
475 static bool
476 tilepro_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno,
477 int *total, bool speed)
479 int code = GET_CODE (x);
481 switch (code)
483 case CONST_INT:
484 /* If this is an 8-bit constant, return zero since it can be
485 used nearly anywhere with no cost. If it is a valid operand
486 for an ADD or AND, likewise return 0 if we know it will be
487 used in that context. Otherwise, return 2 since it might be
488 used there later. All other constants take at least two
489 insns. */
490 if (satisfies_constraint_I (x))
492 *total = 0;
493 return true;
495 else if (outer_code == PLUS && add_operand (x, VOIDmode))
497 /* Slightly penalize large constants even though we can add
498 them in one instruction, because it forces the use of
499 2-wide bundling mode. */
500 *total = 1;
501 return true;
503 else if (move_operand (x, SImode))
505 /* We can materialize in one move. */
506 *total = COSTS_N_INSNS (1);
507 return true;
509 else
511 /* We can materialize in two moves. */
512 *total = COSTS_N_INSNS (2);
513 return true;
516 return false;
518 case CONST:
519 case LABEL_REF:
520 case SYMBOL_REF:
521 *total = COSTS_N_INSNS (2);
522 return true;
524 case CONST_DOUBLE:
525 *total = COSTS_N_INSNS (4);
526 return true;
528 case HIGH:
529 *total = 0;
530 return true;
532 case MEM:
533 /* If outer-code was a sign or zero extension, a cost of
534 COSTS_N_INSNS (1) was already added in, so account for
535 that. */
536 if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND)
537 *total = COSTS_N_INSNS (1);
538 else
539 *total = COSTS_N_INSNS (2);
540 return true;
542 case PLUS:
543 /* Convey that s[123]a are efficient. */
544 if (GET_CODE (XEXP (x, 0)) == MULT
545 && cint_248_operand (XEXP (XEXP (x, 0), 1), VOIDmode))
547 *total = (rtx_cost (XEXP (XEXP (x, 0), 0), mode,
548 (enum rtx_code) outer_code, opno, speed)
549 + rtx_cost (XEXP (x, 1), mode,
550 (enum rtx_code) outer_code, opno, speed)
551 + COSTS_N_INSNS (1));
552 return true;
554 return false;
556 case MULT:
557 *total = COSTS_N_INSNS (2);
558 return false;
560 case SIGN_EXTEND:
561 case ZERO_EXTEND:
562 if (outer_code == MULT)
563 *total = 0;
564 else
565 *total = COSTS_N_INSNS (1);
566 return false;
568 case DIV:
569 case UDIV:
570 case MOD:
571 case UMOD:
572 /* These are handled by software and are very expensive. */
573 *total = COSTS_N_INSNS (100);
574 return false;
576 case UNSPEC:
577 case UNSPEC_VOLATILE:
579 int num = XINT (x, 1);
581 if (num <= TILEPRO_LAST_LATENCY_1_INSN)
582 *total = COSTS_N_INSNS (1);
583 else if (num <= TILEPRO_LAST_LATENCY_2_INSN)
584 *total = COSTS_N_INSNS (2);
585 else if (num > TILEPRO_LAST_LATENCY_INSN)
587 if (outer_code == PLUS)
588 *total = 0;
589 else
590 *total = COSTS_N_INSNS (1);
592 else
594 switch (num)
596 case UNSPEC_BLOCKAGE:
597 case UNSPEC_NETWORK_BARRIER:
598 *total = 0;
599 break;
601 case UNSPEC_LNK_AND_LABEL:
602 case UNSPEC_MF:
603 case UNSPEC_NETWORK_RECEIVE:
604 case UNSPEC_NETWORK_SEND:
605 case UNSPEC_TLS_GD_ADD:
606 *total = COSTS_N_INSNS (1);
607 break;
609 case UNSPEC_TLS_IE_LOAD:
610 *total = COSTS_N_INSNS (2);
611 break;
613 case UNSPEC_SP_SET:
614 *total = COSTS_N_INSNS (3);
615 break;
617 case UNSPEC_SP_TEST:
618 *total = COSTS_N_INSNS (4);
619 break;
621 case UNSPEC_LATENCY_L2:
622 *total = COSTS_N_INSNS (8);
623 break;
625 case UNSPEC_TLS_GD_CALL:
626 *total = COSTS_N_INSNS (30);
627 break;
629 case UNSPEC_LATENCY_MISS:
630 *total = COSTS_N_INSNS (80);
631 break;
633 default:
634 *total = COSTS_N_INSNS (1);
637 return true;
640 default:
641 return false;
647 /* Returns an SImode integer rtx with value VAL. */
648 static rtx
649 gen_int_si (HOST_WIDE_INT val)
651 return gen_int_mode (val, SImode);
655 /* Create a temporary variable to hold a partial result, to enable
656 CSE. */
657 static rtx
658 create_temp_reg_if_possible (machine_mode mode, rtx default_reg)
660 return can_create_pseudo_p ()? gen_reg_rtx (mode) : default_reg;
664 /* Functions to save and restore machine-specific function data. */
665 static struct machine_function *
666 tilepro_init_machine_status (void)
668 return ggc_cleared_alloc<machine_function> ();
672 /* Do anything needed before RTL is emitted for each function. */
673 void
674 tilepro_init_expanders (void)
676 /* Arrange to initialize and mark the machine per-function
677 status. */
678 init_machine_status = tilepro_init_machine_status;
680 if (cfun && cfun->machine && flag_pic)
682 static int label_num = 0;
684 char text_label_name[32];
686 struct machine_function *machine = cfun->machine;
688 ASM_GENERATE_INTERNAL_LABEL (text_label_name, "L_PICLNK", label_num++);
690 machine->text_label_symbol =
691 gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (text_label_name));
693 machine->text_label_rtx =
694 gen_rtx_REG (Pmode, TILEPRO_PIC_TEXT_LABEL_REGNUM);
696 machine->got_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
698 machine->calls_tls_get_addr = false;
703 /* Return true if X contains a thread-local symbol. */
704 static bool
705 tilepro_tls_referenced_p (rtx x)
707 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
708 x = XEXP (XEXP (x, 0), 0);
710 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
711 return true;
713 /* That's all we handle in tilepro_legitimize_tls_address for
714 now. */
715 return false;
719 /* Return true if X requires a scratch register. It is given that
720 flag_pic is on and that X satisfies CONSTANT_P. */
721 static int
722 tilepro_pic_address_needs_scratch (rtx x)
724 if (GET_CODE (x) == CONST
725 && GET_CODE (XEXP (x, 0)) == PLUS
726 && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
727 || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
728 && CONST_INT_P (XEXP (XEXP (x, 0), 1)))
729 return true;
731 return false;
735 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
736 which we are willing to load the value into a register via a move
737 pattern. TLS cannot be treated as a constant because it can
738 include a function call. */
739 static bool
740 tilepro_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
742 switch (GET_CODE (x))
744 case CONST:
745 case SYMBOL_REF:
746 return !tilepro_tls_referenced_p (x);
748 default:
749 return true;
754 /* Return true if the constant value X is a legitimate general operand
755 when generating PIC code. It is given that flag_pic is on and that
756 X satisfies CONSTANT_P. */
757 bool
758 tilepro_legitimate_pic_operand_p (rtx x)
760 if (tilepro_pic_address_needs_scratch (x))
761 return false;
763 if (tilepro_tls_referenced_p (x))
764 return false;
766 return true;
770 /* Return true if the rtx X can be used as an address operand. */
771 static bool
772 tilepro_legitimate_address_p (machine_mode ARG_UNUSED (mode), rtx x,
773 bool strict)
775 if (GET_CODE (x) == SUBREG)
776 x = SUBREG_REG (x);
778 switch (GET_CODE (x))
780 case POST_INC:
781 case POST_DEC:
782 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
783 return false;
785 x = XEXP (x, 0);
786 break;
788 case POST_MODIFY:
789 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
790 return false;
792 if (GET_CODE (XEXP (x, 1)) != PLUS)
793 return false;
795 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
796 return false;
798 if (!satisfies_constraint_I (XEXP (XEXP (x, 1), 1)))
799 return false;
801 x = XEXP (x, 0);
802 break;
804 case REG:
805 break;
807 default:
808 return false;
811 /* Check if x is a valid reg. */
812 if (!REG_P (x))
813 return false;
815 if (strict)
816 return REGNO_OK_FOR_BASE_P (REGNO (x));
817 else
818 return true;
822 /* Return the rtx containing SYMBOL_REF to the text label. */
823 static rtx
824 tilepro_text_label_symbol (void)
826 return cfun->machine->text_label_symbol;
830 /* Return the register storing the value of the text label. */
831 static rtx
832 tilepro_text_label_rtx (void)
834 return cfun->machine->text_label_rtx;
838 /* Return the register storing the value of the global offset
839 table. */
840 static rtx
841 tilepro_got_rtx (void)
843 return cfun->machine->got_rtx;
847 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
848 static rtx
849 tilepro_got_symbol (void)
851 if (g_got_symbol == NULL)
852 g_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
854 return g_got_symbol;
858 /* Return a reference to the got to be used by tls references. */
859 static rtx
860 tilepro_tls_got (void)
862 rtx temp;
863 if (flag_pic)
865 crtl->uses_pic_offset_table = 1;
866 return tilepro_got_rtx ();
869 temp = gen_reg_rtx (Pmode);
870 emit_move_insn (temp, tilepro_got_symbol ());
872 return temp;
876 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
877 this (thread-local) address. */
878 static rtx
879 tilepro_legitimize_tls_address (rtx addr)
881 rtx ret;
883 gcc_assert (can_create_pseudo_p ());
885 if (GET_CODE (addr) == SYMBOL_REF)
886 switch (SYMBOL_REF_TLS_MODEL (addr))
888 case TLS_MODEL_GLOBAL_DYNAMIC:
889 case TLS_MODEL_LOCAL_DYNAMIC:
891 rtx r0, temp1, temp2, temp3, got;
892 rtx_insn *last;
894 ret = gen_reg_rtx (Pmode);
895 r0 = gen_rtx_REG (Pmode, 0);
896 temp1 = gen_reg_rtx (Pmode);
897 temp2 = gen_reg_rtx (Pmode);
898 temp3 = gen_reg_rtx (Pmode);
900 got = tilepro_tls_got ();
901 emit_insn (gen_tls_gd_addhi (temp1, got, addr));
902 emit_insn (gen_tls_gd_addlo (temp2, temp1, addr));
903 emit_move_insn (r0, temp2);
904 emit_insn (gen_tls_gd_call (addr));
905 emit_move_insn (temp3, r0);
906 last = emit_insn (gen_tls_gd_add (ret, temp3, addr));
907 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
908 break;
910 case TLS_MODEL_INITIAL_EXEC:
912 rtx temp1, temp2, temp3, got;
913 rtx_insn *last;
915 ret = gen_reg_rtx (Pmode);
916 temp1 = gen_reg_rtx (Pmode);
917 temp2 = gen_reg_rtx (Pmode);
918 temp3 = gen_reg_rtx (Pmode);
920 got = tilepro_tls_got ();
921 emit_insn (gen_tls_ie_addhi (temp1, got, addr));
922 emit_insn (gen_tls_ie_addlo (temp2, temp1, addr));
923 emit_insn (gen_tls_ie_load (temp3, temp2, addr));
924 last =
925 emit_move_insn(ret,
926 gen_rtx_PLUS (Pmode,
927 gen_rtx_REG (Pmode,
928 THREAD_POINTER_REGNUM),
929 temp3));
930 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
931 break;
933 case TLS_MODEL_LOCAL_EXEC:
935 rtx temp1;
936 rtx_insn *last;
938 ret = gen_reg_rtx (Pmode);
939 temp1 = gen_reg_rtx (Pmode);
941 emit_insn (gen_tls_le_addhi (temp1,
942 gen_rtx_REG (Pmode,
943 THREAD_POINTER_REGNUM),
944 addr));
945 last = emit_insn (gen_tls_le_addlo (ret, temp1, addr));
946 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
947 break;
949 default:
950 gcc_unreachable ();
952 else if (GET_CODE (addr) == CONST)
954 rtx base, offset;
956 gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
958 base = tilepro_legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
959 offset = XEXP (XEXP (addr, 0), 1);
961 base = force_operand (base, NULL_RTX);
962 ret = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
964 else
965 gcc_unreachable ();
967 return ret;
971 /* Legitimize PIC addresses. If the address is already
972 position-independent, we return ORIG. Newly generated
973 position-independent addresses go into a reg. This is REG if
974 nonzero, otherwise we allocate register(s) as necessary. */
975 static rtx
976 tilepro_legitimize_pic_address (rtx orig,
977 machine_mode mode ATTRIBUTE_UNUSED,
978 rtx reg)
980 if (GET_CODE (orig) == SYMBOL_REF)
982 rtx address, pic_ref;
984 if (reg == 0)
986 gcc_assert (can_create_pseudo_p ());
987 reg = gen_reg_rtx (Pmode);
990 if (SYMBOL_REF_LOCAL_P (orig))
992 /* If not during reload, allocate another temp reg here for
993 loading in the address, so that these instructions can be
994 optimized properly. */
995 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
996 rtx text_label_symbol = tilepro_text_label_symbol ();
997 rtx text_label_rtx = tilepro_text_label_rtx ();
999 emit_insn (gen_addli_pcrel (temp_reg, text_label_rtx, orig,
1000 text_label_symbol));
1001 emit_insn (gen_auli_pcrel (temp_reg, temp_reg, orig,
1002 text_label_symbol));
1004 /* Note: this is conservative. We use the text_label but we
1005 don't use the pic_offset_table. However, in some cases
1006 we may need the pic_offset_table (see
1007 tilepro_fixup_pcrel_references). */
1008 crtl->uses_pic_offset_table = 1;
1010 address = temp_reg;
1012 emit_move_insn (reg, address);
1013 return reg;
1015 else
1017 /* If not during reload, allocate another temp reg here for
1018 loading in the address, so that these instructions can be
1019 optimized properly. */
1020 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
1022 gcc_assert (flag_pic);
1023 if (flag_pic == 1)
1025 emit_insn (gen_add_got16 (temp_reg,
1026 tilepro_got_rtx (), orig));
1028 else
1030 rtx temp_reg2 = create_temp_reg_if_possible (Pmode, reg);
1031 emit_insn (gen_addhi_got32 (temp_reg2,
1032 tilepro_got_rtx (), orig));
1033 emit_insn (gen_addlo_got32 (temp_reg, temp_reg2, orig));
1036 address = temp_reg;
1038 pic_ref = gen_const_mem (Pmode, address);
1039 crtl->uses_pic_offset_table = 1;
1040 emit_move_insn (reg, pic_ref);
1041 /* The following put a REG_EQUAL note on this insn, so that
1042 it can be optimized by loop. But it causes the label to
1043 be optimized away. */
1044 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1045 return reg;
1048 else if (GET_CODE (orig) == CONST)
1050 rtx base, offset;
1052 if (GET_CODE (XEXP (orig, 0)) == PLUS
1053 && XEXP (XEXP (orig, 0), 0) == tilepro_got_rtx ())
1054 return orig;
1056 if (reg == 0)
1058 gcc_assert (can_create_pseudo_p ());
1059 reg = gen_reg_rtx (Pmode);
1062 gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
1063 base = tilepro_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode,
1064 reg);
1065 offset =
1066 tilepro_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
1067 base == reg ? 0 : reg);
1069 if (CONST_INT_P (offset))
1071 if (can_create_pseudo_p ())
1072 offset = force_reg (Pmode, offset);
1073 else
1074 /* If we reach here, then something is seriously
1075 wrong. */
1076 gcc_unreachable ();
1079 if (can_create_pseudo_p ())
1080 return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
1081 else
1082 gcc_unreachable ();
1084 else if (GET_CODE (orig) == LABEL_REF)
1086 rtx address, temp_reg;
1087 rtx text_label_symbol;
1088 rtx text_label_rtx;
1090 if (reg == 0)
1092 gcc_assert (can_create_pseudo_p ());
1093 reg = gen_reg_rtx (Pmode);
1096 /* If not during reload, allocate another temp reg here for
1097 loading in the address, so that these instructions can be
1098 optimized properly. */
1099 temp_reg = create_temp_reg_if_possible (Pmode, reg);
1100 text_label_symbol = tilepro_text_label_symbol ();
1101 text_label_rtx = tilepro_text_label_rtx ();
1103 emit_insn (gen_addli_pcrel (temp_reg, text_label_rtx, orig,
1104 text_label_symbol));
1105 emit_insn (gen_auli_pcrel (temp_reg, temp_reg, orig,
1106 text_label_symbol));
1108 /* Note: this is conservative. We use the text_label but we
1109 don't use the pic_offset_table. */
1110 crtl->uses_pic_offset_table = 1;
1112 address = temp_reg;
1114 emit_move_insn (reg, address);
1116 return reg;
1119 return orig;
1123 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1124 static rtx
1125 tilepro_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1126 machine_mode mode)
1128 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
1129 && symbolic_operand (x, Pmode) && tilepro_tls_referenced_p (x))
1131 return tilepro_legitimize_tls_address (x);
1133 else if (flag_pic)
1135 return tilepro_legitimize_pic_address (x, mode, 0);
1137 else
1138 return x;
1142 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1143 static rtx
1144 tilepro_delegitimize_address (rtx x)
1146 x = delegitimize_mem_from_attrs (x);
1148 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC)
1150 switch (XINT (XEXP (x, 0), 1))
1152 case UNSPEC_PCREL_SYM:
1153 case UNSPEC_GOT16_SYM:
1154 case UNSPEC_GOT32_SYM:
1155 case UNSPEC_TLS_GD:
1156 case UNSPEC_TLS_IE:
1157 x = XVECEXP (XEXP (x, 0), 0, 0);
1158 break;
1162 return x;
1166 /* Emit code to load the PIC register. */
1167 static void
1168 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED)
1170 int orig_flag_pic = flag_pic;
1172 rtx got_symbol = tilepro_got_symbol ();
1173 rtx text_label_symbol = tilepro_text_label_symbol ();
1174 rtx text_label_rtx = tilepro_text_label_rtx ();
1175 flag_pic = 0;
1177 emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol));
1179 emit_insn (gen_addli_pcrel (tilepro_got_rtx (),
1180 text_label_rtx, got_symbol, text_label_symbol));
1182 emit_insn (gen_auli_pcrel (tilepro_got_rtx (),
1183 tilepro_got_rtx (),
1184 got_symbol, text_label_symbol));
1186 flag_pic = orig_flag_pic;
1188 /* Need to emit this whether or not we obey regdecls, since
1189 setjmp/longjmp can cause life info to screw up. ??? In the case
1190 where we don't obey regdecls, this is not sufficient since we may
1191 not fall out the bottom. */
1192 emit_use (tilepro_got_rtx ());
1196 /* Return the simd variant of the constant NUM of mode MODE, by
1197 replicating it to fill an interger of mode SImode. NUM is first
1198 truncated to fit in MODE. */
1200 tilepro_simd_int (rtx num, machine_mode mode)
1202 HOST_WIDE_INT n = 0;
1204 gcc_assert (CONST_INT_P (num));
1206 n = INTVAL (num);
1208 switch (mode)
1210 case QImode:
1211 n = 0x01010101 * (n & 0x000000FF);
1212 break;
1213 case HImode:
1214 n = 0x00010001 * (n & 0x0000FFFF);
1215 break;
1216 case SImode:
1217 break;
1218 case DImode:
1219 break;
1220 default:
1221 gcc_unreachable ();
1224 return gen_int_si (n);
1228 /* Split one or more DImode RTL references into pairs of SImode
1229 references. The RTL can be REG, offsettable MEM, integer constant,
1230 or CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL
1231 to split and "num" is its length. lo_half and hi_half are output
1232 arrays that parallel "operands". */
1233 void
1234 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1236 while (num--)
1238 rtx op = operands[num];
1240 /* simplify_subreg refuse to split volatile memory addresses,
1241 but we still have to handle it. */
1242 if (MEM_P (op))
1244 lo_half[num] = adjust_address (op, SImode, 0);
1245 hi_half[num] = adjust_address (op, SImode, 4);
1247 else
1249 lo_half[num] = simplify_gen_subreg (SImode, op,
1250 GET_MODE (op) == VOIDmode
1251 ? DImode : GET_MODE (op), 0);
1252 hi_half[num] = simplify_gen_subreg (SImode, op,
1253 GET_MODE (op) == VOIDmode
1254 ? DImode : GET_MODE (op), 4);
1260 /* Returns true iff val can be moved into a register in one
1261 instruction. And if it can, it emits the code to move the
1262 constant.
1264 If three_wide_only is true, this insists on an instruction that
1265 works in a bundle containing three instructions. */
1266 static bool
1267 expand_set_cint32_one_inst (rtx dest_reg,
1268 HOST_WIDE_INT val, bool three_wide_only)
1270 val = trunc_int_for_mode (val, SImode);
1272 if (val == trunc_int_for_mode (val, QImode))
1274 /* Success! */
1275 emit_move_insn (dest_reg, GEN_INT (val));
1276 return true;
1278 else if (!three_wide_only)
1280 rtx imm_op = GEN_INT (val);
1282 if (satisfies_constraint_J (imm_op)
1283 || satisfies_constraint_K (imm_op)
1284 || satisfies_constraint_N (imm_op)
1285 || satisfies_constraint_P (imm_op))
1287 emit_move_insn (dest_reg, imm_op);
1288 return true;
1292 return false;
1296 /* Implement SImode rotatert. */
1297 static HOST_WIDE_INT
1298 rotate_right (HOST_WIDE_INT n, int count)
1300 unsigned HOST_WIDE_INT x = n & 0xFFFFFFFF;
1301 if (count == 0)
1302 return x;
1303 return ((x >> count) | (x << (32 - count))) & 0xFFFFFFFF;
1307 /* Return true iff n contains exactly one contiguous sequence of 1
1308 bits, possibly wrapping around from high bits to low bits. */
1309 bool
1310 tilepro_bitfield_operand_p (HOST_WIDE_INT n, int *first_bit, int *last_bit)
1312 int i;
1314 if (n == 0)
1315 return false;
1317 for (i = 0; i < 32; i++)
1319 unsigned HOST_WIDE_INT x = rotate_right (n, i);
1320 if (!(x & 1))
1321 continue;
1323 /* See if x is a power of two minus one, i.e. only consecutive 1
1324 bits starting from bit 0. */
1325 if ((x & (x + 1)) == 0)
1327 if (first_bit != NULL)
1328 *first_bit = i;
1329 if (last_bit != NULL)
1330 *last_bit = (i + exact_log2 (x ^ (x >> 1))) & 31;
1332 return true;
1336 return false;
1340 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1341 static void
1342 expand_set_cint32 (rtx dest_reg, rtx src_val)
1344 HOST_WIDE_INT val;
1345 int leading_zeroes, trailing_zeroes;
1346 int lower, upper;
1347 int three_wide_only;
1348 rtx temp;
1350 gcc_assert (CONST_INT_P (src_val));
1351 val = trunc_int_for_mode (INTVAL (src_val), SImode);
1353 /* See if we can generate the constant in one instruction. */
1354 if (expand_set_cint32_one_inst (dest_reg, val, false))
1355 return;
1357 /* Create a temporary variable to hold a partial result, to enable
1358 CSE. */
1359 temp = create_temp_reg_if_possible (SImode, dest_reg);
1361 leading_zeroes = 31 - floor_log2 (val & 0xFFFFFFFF);
1362 trailing_zeroes = exact_log2 (val & -val);
1364 lower = trunc_int_for_mode (val, HImode);
1365 upper = trunc_int_for_mode ((val - lower) >> 16, HImode);
1367 /* First try all three-wide instructions that generate a constant
1368 (i.e. movei) followed by various shifts and rotates. If none of
1369 those work, try various two-wide ways of generating a constant
1370 followed by various shifts and rotates. */
1371 for (three_wide_only = 1; three_wide_only >= 0; three_wide_only--)
1373 int count;
1375 if (expand_set_cint32_one_inst (temp, val >> trailing_zeroes,
1376 three_wide_only))
1378 /* 0xFFFFA500 becomes:
1379 movei temp, 0xFFFFFFA5
1380 shli dest, temp, 8 */
1381 emit_move_insn (dest_reg,
1382 gen_rtx_ASHIFT (SImode, temp,
1383 GEN_INT (trailing_zeroes)));
1384 return;
1387 if (expand_set_cint32_one_inst (temp, val << leading_zeroes,
1388 three_wide_only))
1390 /* 0x7FFFFFFF becomes:
1391 movei temp, -2
1392 shri dest, temp, 1 */
1393 emit_move_insn (dest_reg,
1394 gen_rtx_LSHIFTRT (SImode, temp,
1395 GEN_INT (leading_zeroes)));
1396 return;
1399 /* Try rotating a one-instruction immediate, since rotate is
1400 3-wide. */
1401 for (count = 1; count < 32; count++)
1403 HOST_WIDE_INT r = rotate_right (val, count);
1404 if (expand_set_cint32_one_inst (temp, r, three_wide_only))
1406 /* 0xFFA5FFFF becomes:
1407 movei temp, 0xFFFFFFA5
1408 rli dest, temp, 16 */
1409 emit_move_insn (dest_reg,
1410 gen_rtx_ROTATE (SImode, temp, GEN_INT (count)));
1411 return;
1415 if (lower == trunc_int_for_mode (lower, QImode))
1417 /* We failed to use two 3-wide instructions, but the low 16
1418 bits are a small number so just use a 2-wide + 3-wide
1419 auli + addi pair rather than anything more exotic.
1421 0x12340056 becomes:
1422 auli temp, zero, 0x1234
1423 addi dest, temp, 0x56 */
1424 break;
1428 /* Fallback case: use a auli + addli/addi pair. */
1429 emit_move_insn (temp, GEN_INT (upper << 16));
1430 emit_move_insn (dest_reg, (gen_rtx_PLUS (SImode, temp, GEN_INT (lower))));
1434 /* Load OP1, a 32-bit constant, into OP0, a register. We know it
1435 can't be done in one insn when we get here, the move expander
1436 guarantees this. */
1437 void
1438 tilepro_expand_set_const32 (rtx op0, rtx op1)
1440 machine_mode mode = GET_MODE (op0);
1441 rtx temp;
1443 if (CONST_INT_P (op1))
1445 /* TODO: I don't know if we want to split large constants now,
1446 or wait until later (with a define_split).
1448 Does splitting early help CSE? Does it harm other
1449 optimizations that might fold loads? */
1450 expand_set_cint32 (op0, op1);
1452 else
1454 temp = create_temp_reg_if_possible (mode, op0);
1456 /* A symbol, emit in the traditional way. */
1457 emit_move_insn (temp, gen_rtx_HIGH (mode, op1));
1458 emit_move_insn (op0, gen_rtx_LO_SUM (mode, temp, op1));
1463 /* Expand a move instruction. Return true if all work is done. */
1464 bool
1465 tilepro_expand_mov (machine_mode mode, rtx *operands)
1467 /* Handle sets of MEM first. */
1468 if (MEM_P (operands[0]))
1470 if (can_create_pseudo_p ())
1471 operands[0] = validize_mem (operands[0]);
1473 if (reg_or_0_operand (operands[1], mode))
1474 return false;
1476 if (!reload_in_progress)
1477 operands[1] = force_reg (mode, operands[1]);
1480 /* Fixup TLS cases. */
1481 if (CONSTANT_P (operands[1]) && tilepro_tls_referenced_p (operands[1]))
1483 operands[1] = tilepro_legitimize_tls_address (operands[1]);
1484 return false;
1487 /* Fixup PIC cases. */
1488 if (flag_pic && CONSTANT_P (operands[1]))
1490 if (tilepro_pic_address_needs_scratch (operands[1]))
1491 operands[1] = tilepro_legitimize_pic_address (operands[1], mode, 0);
1493 if (symbolic_operand (operands[1], mode))
1495 operands[1] = tilepro_legitimize_pic_address (operands[1],
1496 mode,
1497 (reload_in_progress ?
1498 operands[0] :
1499 NULL_RTX));
1500 return false;
1504 /* Fixup for UNSPEC addresses. */
1505 if (flag_pic
1506 && GET_CODE (operands[1]) == HIGH
1507 && GET_CODE (XEXP (operands[1], 0)) == CONST
1508 && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == UNSPEC)
1510 rtx unspec = XEXP (XEXP (operands[1], 0), 0);
1511 int unspec_num = XINT (unspec, 1);
1512 if (unspec_num == UNSPEC_PCREL_SYM)
1514 emit_insn (gen_auli_pcrel (operands[0], const0_rtx,
1515 XVECEXP (unspec, 0, 0),
1516 XVECEXP (unspec, 0, 1)));
1517 return true;
1519 else if (flag_pic == 2 && unspec_num == UNSPEC_GOT32_SYM)
1521 emit_insn (gen_addhi_got32 (operands[0], const0_rtx,
1522 XVECEXP (unspec, 0, 0)));
1523 return true;
1525 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_GD)
1527 emit_insn (gen_tls_gd_addhi (operands[0], const0_rtx,
1528 XVECEXP (unspec, 0, 0)));
1529 return true;
1531 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_IE)
1533 emit_insn (gen_tls_ie_addhi (operands[0], const0_rtx,
1534 XVECEXP (unspec, 0, 0)));
1535 return true;
1537 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_LE)
1539 emit_insn (gen_tls_le_addhi (operands[0], const0_rtx,
1540 XVECEXP (unspec, 0, 0)));
1541 return true;
1545 /* Accept non-constants and valid constants unmodified. */
1546 if (!CONSTANT_P (operands[1])
1547 || GET_CODE (operands[1]) == HIGH || move_operand (operands[1], mode))
1548 return false;
1550 /* Split large integers. */
1551 if (GET_MODE_SIZE (mode) <= 4)
1553 tilepro_expand_set_const32 (operands[0], operands[1]);
1554 return true;
1557 return false;
1561 /* Expand the "insv" pattern. */
1562 void
1563 tilepro_expand_insv (rtx operands[4])
1565 rtx first_rtx = operands[2];
1566 HOST_WIDE_INT first = INTVAL (first_rtx);
1567 HOST_WIDE_INT width = INTVAL (operands[1]);
1568 rtx v = operands[3];
1570 /* Shift the inserted bits into position. */
1571 if (first != 0)
1573 if (CONST_INT_P (v))
1575 /* Shift the constant into mm position. */
1576 v = gen_int_si (INTVAL (v) << first);
1578 else
1580 /* Shift over the value to be inserted. */
1581 rtx tmp = gen_reg_rtx (SImode);
1582 emit_insn (gen_ashlsi3 (tmp, v, first_rtx));
1583 v = tmp;
1587 /* Insert the shifted bits using an 'mm' insn. */
1588 emit_insn (gen_insn_mm (operands[0], v, operands[0], first_rtx,
1589 GEN_INT (first + width - 1)));
1593 /* Expand unaligned loads. */
1594 void
1595 tilepro_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize,
1596 HOST_WIDE_INT bit_offset, bool sign)
1598 machine_mode mode;
1599 rtx addr_lo, addr_hi;
1600 rtx mem_lo, mem_hi, hi;
1601 rtx mema, wide_result;
1602 int last_byte_offset;
1603 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1605 mode = GET_MODE (dest_reg);
1607 hi = gen_reg_rtx (mode);
1609 if (bitsize == 2 * BITS_PER_UNIT && (bit_offset % BITS_PER_UNIT) == 0)
1611 rtx lo;
1613 /* When just loading a two byte value, we can load the two bytes
1614 individually and combine them efficiently. */
1616 mem_lo = adjust_address (mem, QImode, byte_offset);
1617 mem_hi = adjust_address (mem, QImode, byte_offset + 1);
1619 lo = gen_reg_rtx (mode);
1620 emit_insn (gen_zero_extendqisi2 (lo, mem_lo));
1622 if (sign)
1624 rtx tmp = gen_reg_rtx (mode);
1626 /* Do a signed load of the second byte then shift and OR it
1627 in. */
1628 emit_insn (gen_extendqisi2 (gen_lowpart (SImode, hi), mem_hi));
1629 emit_insn (gen_ashlsi3 (gen_lowpart (SImode, tmp),
1630 gen_lowpart (SImode, hi), GEN_INT (8)));
1631 emit_insn (gen_iorsi3 (gen_lowpart (SImode, dest_reg),
1632 gen_lowpart (SImode, lo),
1633 gen_lowpart (SImode, tmp)));
1635 else
1637 /* Do two unsigned loads and use intlb to interleave
1638 them. */
1639 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, hi), mem_hi));
1640 emit_insn (gen_insn_intlb (gen_lowpart (SImode, dest_reg),
1641 gen_lowpart (SImode, hi),
1642 gen_lowpart (SImode, lo)));
1645 return;
1648 mema = XEXP (mem, 0);
1650 /* AND addresses cannot be in any alias set, since they may
1651 implicitly alias surrounding code. Ideally we'd have some alias
1652 set that covered all types except those with alignment 8 or
1653 higher. */
1654 addr_lo = force_reg (Pmode, plus_constant (Pmode, mema, byte_offset));
1655 mem_lo = change_address (mem, mode,
1656 gen_rtx_AND (Pmode, addr_lo, GEN_INT (-4)));
1657 set_mem_alias_set (mem_lo, 0);
1659 /* Load the high word at an address that will not fault if the low
1660 address is aligned and at the very end of a page. */
1661 last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT;
1662 addr_hi = force_reg (Pmode, plus_constant (Pmode, mema, last_byte_offset));
1663 mem_hi = change_address (mem, mode,
1664 gen_rtx_AND (Pmode, addr_hi, GEN_INT (-4)));
1665 set_mem_alias_set (mem_hi, 0);
1667 if (bitsize == 32)
1669 addr_lo = make_safe_from (addr_lo, dest_reg);
1670 wide_result = dest_reg;
1672 else
1674 wide_result = gen_reg_rtx (mode);
1677 /* Load hi first in case dest_reg is used in mema. */
1678 emit_move_insn (hi, mem_hi);
1679 emit_move_insn (wide_result, mem_lo);
1681 emit_insn (gen_insn_dword_align (gen_lowpart (SImode, wide_result),
1682 gen_lowpart (SImode, wide_result),
1683 gen_lowpart (SImode, hi), addr_lo));
1685 if (bitsize != 32)
1687 rtx extracted =
1688 extract_bit_field (gen_lowpart (SImode, wide_result),
1689 bitsize, bit_offset % BITS_PER_UNIT,
1690 !sign, gen_lowpart (SImode, dest_reg),
1691 SImode, SImode, false, NULL);
1693 if (extracted != dest_reg)
1694 emit_move_insn (dest_reg, gen_lowpart (SImode, extracted));
1699 /* Expand unaligned stores. */
1700 static void
1701 tilepro_expand_unaligned_store (rtx mem, rtx src, HOST_WIDE_INT bitsize,
1702 HOST_WIDE_INT bit_offset)
1704 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1705 HOST_WIDE_INT bytesize = bitsize / BITS_PER_UNIT;
1706 HOST_WIDE_INT shift_amt;
1707 HOST_WIDE_INT i;
1708 rtx mem_addr;
1709 rtx store_val;
1711 for (i = 0, shift_amt = 0; i < bytesize; i++, shift_amt += BITS_PER_UNIT)
1713 mem_addr = adjust_address (mem, QImode, byte_offset + i);
1715 if (shift_amt)
1717 store_val = expand_simple_binop (SImode, LSHIFTRT,
1718 gen_lowpart (SImode, src),
1719 GEN_INT (shift_amt), NULL, 1,
1720 OPTAB_LIB_WIDEN);
1721 store_val = gen_lowpart (QImode, store_val);
1723 else
1725 store_val = gen_lowpart (QImode, src);
1728 emit_move_insn (mem_addr, store_val);
1733 /* Implement the movmisalign patterns. One of the operands is a
1734 memory that is not naturally aligned. Emit instructions to load
1735 it. */
1736 void
1737 tilepro_expand_movmisalign (machine_mode mode, rtx *operands)
1739 if (MEM_P (operands[1]))
1741 rtx tmp;
1743 if (register_operand (operands[0], mode))
1744 tmp = operands[0];
1745 else
1746 tmp = gen_reg_rtx (mode);
1748 tilepro_expand_unaligned_load (tmp, operands[1],
1749 GET_MODE_BITSIZE (mode), 0, true);
1751 if (tmp != operands[0])
1752 emit_move_insn (operands[0], tmp);
1754 else if (MEM_P (operands[0]))
1756 if (!reg_or_0_operand (operands[1], mode))
1757 operands[1] = force_reg (mode, operands[1]);
1759 tilepro_expand_unaligned_store (operands[0], operands[1],
1760 GET_MODE_BITSIZE (mode), 0);
1762 else
1763 gcc_unreachable ();
1767 /* Implement the addsi3 pattern. */
1768 bool
1769 tilepro_expand_addsi (rtx op0, rtx op1, rtx op2)
1771 rtx temp;
1772 HOST_WIDE_INT n;
1773 HOST_WIDE_INT high;
1775 /* Skip anything that only takes one instruction. */
1776 if (add_operand (op2, SImode))
1777 return false;
1779 /* We can only optimize ints here (it should be impossible to get
1780 here with any other type, but it is harmless to check. */
1781 if (!CONST_INT_P (op2))
1782 return false;
1784 temp = create_temp_reg_if_possible (SImode, op0);
1785 n = INTVAL (op2);
1786 high = (n + (n & 0x8000)) & ~0xffff;
1788 emit_move_insn (temp, gen_rtx_PLUS (SImode, op1, gen_int_si (high)));
1789 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, gen_int_si (n - high)));
1791 return true;
1795 /* Implement the allocate_stack pattern (alloca). */
1796 void
1797 tilepro_allocate_stack (rtx op0, rtx op1)
1799 /* Technically the correct way to initialize chain_loc is with
1800 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
1801 * sets the alias_set to that of a frame reference. Some of our
1802 * tests rely on some unsafe assumption about when the chaining
1803 * update is done, we need to be conservative about reordering the
1804 * chaining instructions.
1806 rtx fp_addr = gen_reg_rtx (Pmode);
1807 rtx fp_value = gen_reg_rtx (Pmode);
1808 rtx fp_loc;
1810 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1811 GEN_INT (UNITS_PER_WORD)));
1813 fp_loc = gen_frame_mem (Pmode, fp_addr);
1815 emit_move_insn (fp_value, fp_loc);
1817 op1 = force_reg (Pmode, op1);
1819 emit_move_insn (stack_pointer_rtx,
1820 gen_rtx_MINUS (Pmode, stack_pointer_rtx, op1));
1822 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1823 GEN_INT (UNITS_PER_WORD)));
1825 fp_loc = gen_frame_mem (Pmode, fp_addr);
1827 emit_move_insn (fp_loc, fp_value);
1829 emit_move_insn (op0, virtual_stack_dynamic_rtx);
1834 /* Multiplies */
1836 /* Returns the insn_code in ENTRY. */
1837 static enum insn_code
1838 tilepro_multiply_get_opcode (const struct tilepro_multiply_insn_seq_entry
1839 *entry)
1841 return tilepro_multiply_insn_seq_decode_opcode[entry->compressed_opcode];
1845 /* Returns the length of the 'op' array. */
1846 static int
1847 tilepro_multiply_get_num_ops (const struct tilepro_multiply_insn_seq *seq)
1849 /* The array either uses all of its allocated slots or is terminated
1850 by a bogus opcode. Either way, the array size is the index of the
1851 last valid opcode plus one. */
1852 int i;
1853 for (i = tilepro_multiply_insn_seq_MAX_OPERATIONS - 1; i >= 0; i--)
1854 if (tilepro_multiply_get_opcode (&seq->op[i]) != CODE_FOR_nothing)
1855 return i + 1;
1857 /* An empty array is not allowed. */
1858 gcc_unreachable ();
1862 /* We precompute a number of expression trees for multiplying by
1863 constants. This generates code for such an expression tree by
1864 walking through the nodes in the tree (which are conveniently
1865 pre-linearized) and emitting an instruction for each one. */
1866 static void
1867 tilepro_expand_constant_multiply_given_sequence (rtx result, rtx src,
1868 const struct
1869 tilepro_multiply_insn_seq
1870 *seq)
1872 int i;
1873 int num_ops;
1875 /* Keep track of the subexpressions computed so far, so later
1876 instructions can refer to them. We seed the array with zero and
1877 the value being multiplied. */
1878 int num_subexprs = 2;
1879 rtx subexprs[tilepro_multiply_insn_seq_MAX_OPERATIONS + 2];
1880 subexprs[0] = const0_rtx;
1881 subexprs[1] = src;
1883 /* Determine how many instructions we are going to generate. */
1884 num_ops = tilepro_multiply_get_num_ops (seq);
1885 gcc_assert (num_ops > 0
1886 && num_ops <= tilepro_multiply_insn_seq_MAX_OPERATIONS);
1888 for (i = 0; i < num_ops; i++)
1890 const struct tilepro_multiply_insn_seq_entry *entry = &seq->op[i];
1892 /* Figure out where to store the output of this instruction. */
1893 const bool is_last_op = (i + 1 == num_ops);
1894 rtx out = is_last_op ? result : gen_reg_rtx (SImode);
1896 enum insn_code opcode = tilepro_multiply_get_opcode (entry);
1897 if (opcode == CODE_FOR_ashlsi3)
1899 /* Handle shift by immediate. This is a special case because
1900 the meaning of the second operand is a constant shift
1901 count rather than an operand index. */
1903 /* Make sure the shift count is in range. Zero should not
1904 happen. */
1905 const int shift_count = entry->rhs;
1906 gcc_assert (shift_count > 0 && shift_count < 32);
1908 /* Emit the actual instruction. */
1909 emit_insn (GEN_FCN (opcode)
1910 (out, subexprs[entry->lhs],
1911 gen_rtx_CONST_INT (SImode, shift_count)));
1913 else
1915 /* Handle a normal two-operand instruction, such as add or
1916 s1a. */
1918 /* Make sure we are referring to a previously computed
1919 subexpression. */
1920 gcc_assert (entry->rhs < num_subexprs);
1922 /* Emit the actual instruction. */
1923 emit_insn (GEN_FCN (opcode)
1924 (out, subexprs[entry->lhs], subexprs[entry->rhs]));
1927 /* Record this subexpression for use by later expressions. */
1928 subexprs[num_subexprs++] = out;
1933 /* bsearch helper function. */
1934 static int
1935 tilepro_compare_multipliers (const void *key, const void *t)
1937 return *(const int *) key -
1938 ((const struct tilepro_multiply_insn_seq *) t)->multiplier;
1942 /* Returns the tilepro_multiply_insn_seq for multiplier, or NULL if
1943 none exists. */
1944 static const struct tilepro_multiply_insn_seq *
1945 tilepro_find_multiply_insn_seq_for_constant (int multiplier)
1947 return ((const struct tilepro_multiply_insn_seq *)
1948 bsearch (&multiplier, tilepro_multiply_insn_seq_table,
1949 tilepro_multiply_insn_seq_table_size,
1950 sizeof tilepro_multiply_insn_seq_table[0],
1951 tilepro_compare_multipliers));
1955 /* Try to a expand constant multiply in SImode by looking it up in a
1956 precompiled table. OP0 is the result operand, OP1 is the source
1957 operand, and MULTIPLIER is the value of the constant. Return true
1958 if it succeeds. */
1959 static bool
1960 tilepro_expand_const_mulsi (rtx op0, rtx op1, int multiplier)
1962 /* See if we have precomputed an efficient way to multiply by this
1963 constant. */
1964 const struct tilepro_multiply_insn_seq *seq =
1965 tilepro_find_multiply_insn_seq_for_constant (multiplier);
1966 if (seq != NULL)
1968 tilepro_expand_constant_multiply_given_sequence (op0, op1, seq);
1969 return true;
1971 else
1972 return false;
1976 /* Expand the mulsi pattern. */
1977 bool
1978 tilepro_expand_mulsi (rtx op0, rtx op1, rtx op2)
1980 if (CONST_INT_P (op2))
1982 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), SImode);
1983 return tilepro_expand_const_mulsi (op0, op1, n);
1985 return false;
1989 /* Expand a high multiply pattern in SImode. RESULT, OP1, OP2 are the
1990 operands, and SIGN is true if it's a signed multiply, and false if
1991 it's an unsigned multiply. */
1992 static void
1993 tilepro_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign)
1995 rtx tmp0 = gen_reg_rtx (SImode);
1996 rtx tmp1 = gen_reg_rtx (SImode);
1997 rtx tmp2 = gen_reg_rtx (SImode);
1998 rtx tmp3 = gen_reg_rtx (SImode);
1999 rtx tmp4 = gen_reg_rtx (SImode);
2000 rtx tmp5 = gen_reg_rtx (SImode);
2001 rtx tmp6 = gen_reg_rtx (SImode);
2002 rtx tmp7 = gen_reg_rtx (SImode);
2003 rtx tmp8 = gen_reg_rtx (SImode);
2004 rtx tmp9 = gen_reg_rtx (SImode);
2005 rtx tmp10 = gen_reg_rtx (SImode);
2006 rtx tmp11 = gen_reg_rtx (SImode);
2007 rtx tmp12 = gen_reg_rtx (SImode);
2008 rtx tmp13 = gen_reg_rtx (SImode);
2009 rtx result_lo = gen_reg_rtx (SImode);
2011 if (sign)
2013 emit_insn (gen_insn_mulhl_su (tmp0, op1, op2));
2014 emit_insn (gen_insn_mulhl_su (tmp1, op2, op1));
2015 emit_insn (gen_insn_mulll_uu (tmp2, op1, op2));
2016 emit_insn (gen_insn_mulhh_ss (tmp3, op1, op2));
2018 else
2020 emit_insn (gen_insn_mulhl_uu (tmp0, op1, op2));
2021 emit_insn (gen_insn_mulhl_uu (tmp1, op2, op1));
2022 emit_insn (gen_insn_mulll_uu (tmp2, op1, op2));
2023 emit_insn (gen_insn_mulhh_uu (tmp3, op1, op2));
2026 emit_move_insn (tmp4, (gen_rtx_ASHIFT (SImode, tmp0, GEN_INT (16))));
2028 emit_move_insn (tmp5, (gen_rtx_ASHIFT (SImode, tmp1, GEN_INT (16))));
2030 emit_move_insn (tmp6, (gen_rtx_PLUS (SImode, tmp4, tmp5)));
2031 emit_move_insn (result_lo, (gen_rtx_PLUS (SImode, tmp2, tmp6)));
2033 emit_move_insn (tmp7, gen_rtx_LTU (SImode, tmp6, tmp4));
2034 emit_move_insn (tmp8, gen_rtx_LTU (SImode, result_lo, tmp2));
2036 if (sign)
2038 emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (SImode, tmp0, GEN_INT (16))));
2039 emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (SImode, tmp1, GEN_INT (16))));
2041 else
2043 emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (SImode, tmp0, GEN_INT (16))));
2044 emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (SImode, tmp1, GEN_INT (16))));
2047 emit_move_insn (tmp11, (gen_rtx_PLUS (SImode, tmp3, tmp7)));
2048 emit_move_insn (tmp12, (gen_rtx_PLUS (SImode, tmp8, tmp9)));
2049 emit_move_insn (tmp13, (gen_rtx_PLUS (SImode, tmp11, tmp12)));
2050 emit_move_insn (result, (gen_rtx_PLUS (SImode, tmp13, tmp10)));
2054 /* Implement smulsi3_highpart. */
2055 void
2056 tilepro_expand_smulsi3_highpart (rtx op0, rtx op1, rtx op2)
2058 tilepro_expand_high_multiply (op0, op1, op2, true);
2062 /* Implement umulsi3_highpart. */
2063 void
2064 tilepro_expand_umulsi3_highpart (rtx op0, rtx op1, rtx op2)
2066 tilepro_expand_high_multiply (op0, op1, op2, false);
2071 /* Compare and branches */
2073 /* Helper function to handle DImode for tilepro_emit_setcc_internal. */
2074 static bool
2075 tilepro_emit_setcc_internal_di (rtx res, enum rtx_code code, rtx op0, rtx op1)
2077 rtx operands[2], lo_half[2], hi_half[2];
2078 rtx tmp, tmp0, tmp1, tmp2;
2079 bool swap = false;
2081 /* Reduce the number of cases we need to handle by reversing the
2082 operands. */
2083 switch (code)
2085 case EQ:
2086 case NE:
2087 case LE:
2088 case LT:
2089 case LEU:
2090 case LTU:
2091 /* We handle these compares directly. */
2092 break;
2094 case GE:
2095 case GT:
2096 case GEU:
2097 case GTU:
2098 /* Reverse the operands. */
2099 swap = true;
2100 break;
2102 default:
2103 /* We should not have called this with any other code. */
2104 gcc_unreachable ();
2107 if (swap)
2109 code = swap_condition (code);
2110 tmp = op0, op0 = op1, op1 = tmp;
2113 operands[0] = op0;
2114 operands[1] = op1;
2116 split_di (operands, 2, lo_half, hi_half);
2118 if (!reg_or_0_operand (lo_half[0], SImode))
2119 lo_half[0] = force_reg (SImode, lo_half[0]);
2121 if (!reg_or_0_operand (hi_half[0], SImode))
2122 hi_half[0] = force_reg (SImode, hi_half[0]);
2124 if (!CONST_INT_P (lo_half[1]) && !register_operand (lo_half[1], SImode))
2125 lo_half[1] = force_reg (SImode, lo_half[1]);
2127 if (!CONST_INT_P (hi_half[1]) && !register_operand (hi_half[1], SImode))
2128 hi_half[1] = force_reg (SImode, hi_half[1]);
2130 tmp0 = gen_reg_rtx (SImode);
2131 tmp1 = gen_reg_rtx (SImode);
2132 tmp2 = gen_reg_rtx (SImode);
2134 switch (code)
2136 case EQ:
2137 emit_insn (gen_insn_seq (tmp0, lo_half[0], lo_half[1]));
2138 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2139 emit_insn (gen_andsi3 (res, tmp0, tmp1));
2140 return true;
2141 case NE:
2142 emit_insn (gen_insn_sne (tmp0, lo_half[0], lo_half[1]));
2143 emit_insn (gen_insn_sne (tmp1, hi_half[0], hi_half[1]));
2144 emit_insn (gen_iorsi3 (res, tmp0, tmp1));
2145 return true;
2146 case LE:
2147 emit_insn (gen_insn_slte (tmp0, hi_half[0], hi_half[1]));
2148 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2149 emit_insn (gen_insn_slte_u (tmp2, lo_half[0], lo_half[1]));
2150 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2151 return true;
2152 case LT:
2153 if (operands[1] == const0_rtx)
2155 emit_insn (gen_lshrsi3 (res, hi_half[0], GEN_INT (31)));
2156 return true;
2158 else
2160 emit_insn (gen_insn_slt (tmp0, hi_half[0], hi_half[1]));
2161 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2162 emit_insn (gen_insn_slt_u (tmp2, lo_half[0], lo_half[1]));
2163 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2165 return true;
2166 case LEU:
2167 emit_insn (gen_insn_slte_u (tmp0, hi_half[0], hi_half[1]));
2168 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2169 emit_insn (gen_insn_slte_u (tmp2, lo_half[0], lo_half[1]));
2170 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2171 return true;
2172 case LTU:
2173 emit_insn (gen_insn_slt_u (tmp0, hi_half[0], hi_half[1]));
2174 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2175 emit_insn (gen_insn_slt_u (tmp2, lo_half[0], lo_half[1]));
2176 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2177 return true;
2178 default:
2179 gcc_unreachable ();
2182 return false;
2186 /* Certain simplifications can be done to make invalid setcc
2187 operations valid. Return the final comparison, or NULL if we can't
2188 work. */
2189 static bool
2190 tilepro_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1,
2191 machine_mode cmp_mode)
2193 rtx tmp;
2194 bool swap = false;
2196 if (cmp_mode == DImode)
2198 return tilepro_emit_setcc_internal_di (res, code, op0, op1);
2201 /* The general case: fold the comparison code to the types of
2202 compares that we have, choosing the branch as necessary. */
2204 switch (code)
2206 case EQ:
2207 case NE:
2208 case LE:
2209 case LT:
2210 case LEU:
2211 case LTU:
2212 /* We have these compares. */
2213 break;
2215 case GE:
2216 case GT:
2217 case GEU:
2218 case GTU:
2219 /* We do not have these compares, so we reverse the
2220 operands. */
2221 swap = true;
2222 break;
2224 default:
2225 /* We should not have called this with any other code. */
2226 gcc_unreachable ();
2229 if (swap)
2231 code = swap_condition (code);
2232 tmp = op0, op0 = op1, op1 = tmp;
2235 if (!reg_or_0_operand (op0, SImode))
2236 op0 = force_reg (SImode, op0);
2238 if (!CONST_INT_P (op1) && !register_operand (op1, SImode))
2239 op1 = force_reg (SImode, op1);
2241 /* Return the setcc comparison. */
2242 emit_insn (gen_rtx_SET (res, gen_rtx_fmt_ee (code, SImode, op0, op1)));
2244 return true;
2248 /* Implement cstore patterns. */
2249 bool
2250 tilepro_emit_setcc (rtx operands[], machine_mode cmp_mode)
2252 return
2253 tilepro_emit_setcc_internal (operands[0], GET_CODE (operands[1]),
2254 operands[2], operands[3], cmp_mode);
2258 /* Return whether CODE is a signed comparison. */
2259 static bool
2260 signed_compare_p (enum rtx_code code)
2262 return (code == EQ || code == NE || code == LT || code == LE
2263 || code == GT || code == GE);
2267 /* Generate the comparison for an SImode conditional branch. */
2268 static rtx
2269 tilepro_emit_cc_test (enum rtx_code code, rtx op0, rtx op1,
2270 machine_mode cmp_mode, bool eq_ne_only)
2272 enum rtx_code branch_code;
2273 rtx temp;
2275 /* Check for a compare against zero using a comparison we can do
2276 directly. */
2277 if (cmp_mode != DImode
2278 && op1 == const0_rtx
2279 && (code == EQ || code == NE
2280 || (!eq_ne_only && signed_compare_p (code))))
2282 op0 = force_reg (SImode, op0);
2283 return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx);
2286 /* The general case: fold the comparison code to the types of
2287 compares that we have, choosing the branch as necessary. */
2288 switch (code)
2290 case EQ:
2291 case LE:
2292 case LT:
2293 case LEU:
2294 case LTU:
2295 /* We have these compares. */
2296 branch_code = NE;
2297 break;
2299 case NE:
2300 case GE:
2301 case GT:
2302 case GEU:
2303 case GTU:
2304 /* These must be reversed (except NE, but let's
2305 canonicalize). */
2306 code = reverse_condition (code);
2307 branch_code = EQ;
2308 break;
2310 default:
2311 gcc_unreachable ();
2314 if (cmp_mode != DImode
2315 && CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU))
2317 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op1), SImode);
2319 switch (code)
2321 case EQ:
2322 /* Subtract off the value we want to compare against and see
2323 if we get zero. This is cheaper than creating a constant
2324 in a register. Except that subtracting -128 is more
2325 expensive than seqi to -128, so we leave that alone. */
2326 /* ??? Don't do this when comparing against symbols,
2327 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2328 0), which will be declared false out of hand (at least
2329 for non-weak). */
2330 if (!(symbolic_operand (op0, VOIDmode)
2331 || (REG_P (op0) && REG_POINTER (op0))))
2333 /* To compare against MIN_INT, we add MIN_INT and check
2334 for 0. */
2335 HOST_WIDE_INT add;
2336 if (n != -2147483647 - 1)
2337 add = -n;
2338 else
2339 add = n;
2341 op0 = force_reg (SImode, op0);
2342 temp = gen_reg_rtx (SImode);
2343 emit_insn (gen_addsi3 (temp, op0, gen_int_si (add)));
2344 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2345 VOIDmode, temp, const0_rtx);
2347 break;
2349 case LEU:
2350 if (n == -1)
2351 break;
2352 /* FALLTHRU */
2354 case LTU:
2355 /* Change ((unsigned)x < 0x1000) into !((unsigned)x >> 12),
2356 etc. */
2358 int first = exact_log2 (code == LTU ? n : n + 1);
2359 if (first != -1)
2361 op0 = force_reg (SImode, op0);
2362 temp = gen_reg_rtx (SImode);
2363 emit_move_insn (temp,
2364 gen_rtx_LSHIFTRT (SImode, op0,
2365 gen_int_si (first)));
2366 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2367 VOIDmode, temp, const0_rtx);
2370 break;
2372 default:
2373 break;
2377 /* Compute a flag saying whether we should branch. */
2378 temp = gen_reg_rtx (SImode);
2379 tilepro_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2381 /* Return the branch comparison. */
2382 return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx);
2386 /* Generate the comparison for a conditional branch. */
2387 void
2388 tilepro_emit_conditional_branch (rtx operands[], machine_mode cmp_mode)
2390 rtx cmp_rtx =
2391 tilepro_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2],
2392 cmp_mode, false);
2393 rtx branch_rtx = gen_rtx_SET (pc_rtx,
2394 gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx,
2395 gen_rtx_LABEL_REF
2396 (VOIDmode,
2397 operands[3]),
2398 pc_rtx));
2399 emit_jump_insn (branch_rtx);
2403 /* Implement the movsicc pattern. */
2405 tilepro_emit_conditional_move (rtx cmp)
2407 return
2408 tilepro_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1),
2409 GET_MODE (XEXP (cmp, 0)), true);
2413 /* Return true if INSN is annotated with a REG_BR_PROB note that
2414 indicates it's a branch that's predicted taken. */
2415 static bool
2416 cbranch_predicted_p (rtx_insn *insn)
2418 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2420 if (x)
2422 return profile_probability::from_reg_br_prob_note (XINT (x, 0))
2423 >= profile_probability::even ();
2426 return false;
2430 /* Output assembly code for a specific branch instruction, appending
2431 the branch prediction flag to the opcode if appropriate. */
2432 static const char *
2433 tilepro_output_simple_cbranch_with_opcode (rtx_insn *insn, const char *opcode,
2434 int regop, bool netreg_p,
2435 bool reverse_predicted)
2437 static char buf[64];
2438 sprintf (buf, "%s%s\t%%%c%d, %%l0", opcode,
2439 (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "",
2440 netreg_p ? 'N' : 'r', regop);
2441 return buf;
2445 /* Output assembly code for a specific branch instruction, appending
2446 the branch prediction flag to the opcode if appropriate. */
2447 const char *
2448 tilepro_output_cbranch_with_opcode (rtx_insn *insn, rtx *operands,
2449 const char *opcode,
2450 const char *rev_opcode,
2451 int regop, bool netreg_p)
2453 const char *branch_if_false;
2454 rtx taken, not_taken;
2455 bool is_simple_branch;
2457 gcc_assert (LABEL_P (operands[0]));
2459 is_simple_branch = true;
2460 if (INSN_ADDRESSES_SET_P ())
2462 int from_addr = INSN_ADDRESSES (INSN_UID (insn));
2463 int to_addr = INSN_ADDRESSES (INSN_UID (operands[0]));
2464 int delta = to_addr - from_addr;
2465 is_simple_branch = IN_RANGE (delta, -524288, 524280);
2468 if (is_simple_branch)
2470 /* Just a simple conditional branch. */
2471 return
2472 tilepro_output_simple_cbranch_with_opcode (insn, opcode, regop,
2473 netreg_p, false);
2476 /* Generate a reversed branch around a direct jump. This fallback
2477 does not use branch-likely instructions. */
2478 not_taken = gen_label_rtx ();
2479 taken = operands[0];
2481 /* Generate the reversed branch to NOT_TAKEN. */
2482 operands[0] = not_taken;
2483 branch_if_false =
2484 tilepro_output_simple_cbranch_with_opcode (insn, rev_opcode, regop,
2485 netreg_p, true);
2486 output_asm_insn (branch_if_false, operands);
2488 output_asm_insn ("j\t%l0", &taken);
2490 /* Output NOT_TAKEN. */
2491 targetm.asm_out.internal_label (asm_out_file, "L",
2492 CODE_LABEL_NUMBER (not_taken));
2493 return "";
2497 /* Output assembly code for a conditional branch instruction. */
2498 const char *
2499 tilepro_output_cbranch (rtx_insn *insn, rtx *operands, bool reversed)
2501 enum rtx_code code = GET_CODE (operands[1]);
2502 const char *opcode;
2503 const char *rev_opcode;
2505 if (reversed)
2506 code = reverse_condition (code);
2508 switch (code)
2510 case NE:
2511 opcode = "bnz";
2512 rev_opcode = "bz";
2513 break;
2514 case EQ:
2515 opcode = "bz";
2516 rev_opcode = "bnz";
2517 break;
2518 case GE:
2519 opcode = "bgez";
2520 rev_opcode = "blz";
2521 break;
2522 case GT:
2523 opcode = "bgz";
2524 rev_opcode = "blez";
2525 break;
2526 case LE:
2527 opcode = "blez";
2528 rev_opcode = "bgz";
2529 break;
2530 case LT:
2531 opcode = "blz";
2532 rev_opcode = "bgez";
2533 break;
2534 default:
2535 gcc_unreachable ();
2538 return
2539 tilepro_output_cbranch_with_opcode (insn, operands, opcode, rev_opcode,
2540 2, false);
2544 /* Implement the tablejump pattern. */
2545 void
2546 tilepro_expand_tablejump (rtx op0, rtx op1)
2548 if (flag_pic)
2550 rtx table = gen_rtx_LABEL_REF (Pmode, op1);
2551 rtx temp = gen_reg_rtx (Pmode);
2552 rtx text_label_symbol = tilepro_text_label_symbol ();
2553 rtx text_label_rtx = tilepro_text_label_rtx ();
2555 emit_insn (gen_addli_pcrel (temp, text_label_rtx,
2556 table, text_label_symbol));
2557 emit_insn (gen_auli_pcrel (temp, temp, table, text_label_symbol));
2558 emit_move_insn (temp,
2559 gen_rtx_PLUS (Pmode,
2560 convert_to_mode (Pmode, op0, false),
2561 temp));
2562 op0 = temp;
2565 emit_jump_insn (gen_tablejump_aux (op0, op1));
2569 /* Expand a builtin vector binary op, by calling gen function GEN with
2570 operands in the proper modes. DEST is converted to DEST_MODE, and
2571 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2572 void
2573 tilepro_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx),
2574 machine_mode dest_mode,
2575 rtx dest,
2576 machine_mode src_mode,
2577 rtx src0, rtx src1, bool do_src1)
2579 dest = gen_lowpart (dest_mode, dest);
2581 if (src0 == const0_rtx)
2582 src0 = CONST0_RTX (src_mode);
2583 else
2584 src0 = gen_lowpart (src_mode, src0);
2586 if (do_src1)
2588 if (src1 == const0_rtx)
2589 src1 = CONST0_RTX (src_mode);
2590 else
2591 src1 = gen_lowpart (src_mode, src1);
2594 emit_insn ((*gen) (dest, src0, src1));
2599 /* Intrinsics */
2601 struct tile_builtin_info
2603 enum insn_code icode;
2604 tree fndecl;
2607 static struct tile_builtin_info tilepro_builtin_info[TILEPRO_BUILTIN_max] = {
2608 { CODE_FOR_addsi3, NULL }, /* add */
2609 { CODE_FOR_insn_addb, NULL }, /* addb */
2610 { CODE_FOR_insn_addbs_u, NULL }, /* addbs_u */
2611 { CODE_FOR_insn_addh, NULL }, /* addh */
2612 { CODE_FOR_insn_addhs, NULL }, /* addhs */
2613 { CODE_FOR_insn_addib, NULL }, /* addib */
2614 { CODE_FOR_insn_addih, NULL }, /* addih */
2615 { CODE_FOR_insn_addlis, NULL }, /* addlis */
2616 { CODE_FOR_ssaddsi3, NULL }, /* adds */
2617 { CODE_FOR_insn_adiffb_u, NULL }, /* adiffb_u */
2618 { CODE_FOR_insn_adiffh, NULL }, /* adiffh */
2619 { CODE_FOR_andsi3, NULL }, /* and */
2620 { CODE_FOR_insn_auli, NULL }, /* auli */
2621 { CODE_FOR_insn_avgb_u, NULL }, /* avgb_u */
2622 { CODE_FOR_insn_avgh, NULL }, /* avgh */
2623 { CODE_FOR_insn_bitx, NULL }, /* bitx */
2624 { CODE_FOR_bswapsi2, NULL }, /* bytex */
2625 { CODE_FOR_clzsi2, NULL }, /* clz */
2626 { CODE_FOR_insn_crc32_32, NULL }, /* crc32_32 */
2627 { CODE_FOR_insn_crc32_8, NULL }, /* crc32_8 */
2628 { CODE_FOR_ctzsi2, NULL }, /* ctz */
2629 { CODE_FOR_insn_drain, NULL }, /* drain */
2630 { CODE_FOR_insn_dtlbpr, NULL }, /* dtlbpr */
2631 { CODE_FOR_insn_dword_align, NULL }, /* dword_align */
2632 { CODE_FOR_insn_finv, NULL }, /* finv */
2633 { CODE_FOR_insn_flush, NULL }, /* flush */
2634 { CODE_FOR_insn_fnop, NULL }, /* fnop */
2635 { CODE_FOR_insn_icoh, NULL }, /* icoh */
2636 { CODE_FOR_insn_ill, NULL }, /* ill */
2637 { CODE_FOR_insn_info, NULL }, /* info */
2638 { CODE_FOR_insn_infol, NULL }, /* infol */
2639 { CODE_FOR_insn_inthb, NULL }, /* inthb */
2640 { CODE_FOR_insn_inthh, NULL }, /* inthh */
2641 { CODE_FOR_insn_intlb, NULL }, /* intlb */
2642 { CODE_FOR_insn_intlh, NULL }, /* intlh */
2643 { CODE_FOR_insn_inv, NULL }, /* inv */
2644 { CODE_FOR_insn_lb, NULL }, /* lb */
2645 { CODE_FOR_insn_lb_u, NULL }, /* lb_u */
2646 { CODE_FOR_insn_lh, NULL }, /* lh */
2647 { CODE_FOR_insn_lh_u, NULL }, /* lh_u */
2648 { CODE_FOR_insn_lnk, NULL }, /* lnk */
2649 { CODE_FOR_insn_lw, NULL }, /* lw */
2650 { CODE_FOR_insn_lw_na, NULL }, /* lw_na */
2651 { CODE_FOR_insn_lb_L2, NULL }, /* lb_L2 */
2652 { CODE_FOR_insn_lb_u_L2, NULL }, /* lb_u_L2 */
2653 { CODE_FOR_insn_lh_L2, NULL }, /* lh_L2 */
2654 { CODE_FOR_insn_lh_u_L2, NULL }, /* lh_u_L2 */
2655 { CODE_FOR_insn_lw_L2, NULL }, /* lw_L2 */
2656 { CODE_FOR_insn_lw_na_L2, NULL }, /* lw_na_L2 */
2657 { CODE_FOR_insn_lb_miss, NULL }, /* lb_miss */
2658 { CODE_FOR_insn_lb_u_miss, NULL }, /* lb_u_miss */
2659 { CODE_FOR_insn_lh_miss, NULL }, /* lh_miss */
2660 { CODE_FOR_insn_lh_u_miss, NULL }, /* lh_u_miss */
2661 { CODE_FOR_insn_lw_miss, NULL }, /* lw_miss */
2662 { CODE_FOR_insn_lw_na_miss, NULL }, /* lw_na_miss */
2663 { CODE_FOR_insn_maxb_u, NULL }, /* maxb_u */
2664 { CODE_FOR_insn_maxh, NULL }, /* maxh */
2665 { CODE_FOR_insn_maxib_u, NULL }, /* maxib_u */
2666 { CODE_FOR_insn_maxih, NULL }, /* maxih */
2667 { CODE_FOR_memory_barrier, NULL }, /* mf */
2668 { CODE_FOR_insn_mfspr, NULL }, /* mfspr */
2669 { CODE_FOR_insn_minb_u, NULL }, /* minb_u */
2670 { CODE_FOR_insn_minh, NULL }, /* minh */
2671 { CODE_FOR_insn_minib_u, NULL }, /* minib_u */
2672 { CODE_FOR_insn_minih, NULL }, /* minih */
2673 { CODE_FOR_insn_mm, NULL }, /* mm */
2674 { CODE_FOR_insn_mnz, NULL }, /* mnz */
2675 { CODE_FOR_insn_mnzb, NULL }, /* mnzb */
2676 { CODE_FOR_insn_mnzh, NULL }, /* mnzh */
2677 { CODE_FOR_movsi, NULL }, /* move */
2678 { CODE_FOR_insn_movelis, NULL }, /* movelis */
2679 { CODE_FOR_insn_mtspr, NULL }, /* mtspr */
2680 { CODE_FOR_insn_mulhh_ss, NULL }, /* mulhh_ss */
2681 { CODE_FOR_insn_mulhh_su, NULL }, /* mulhh_su */
2682 { CODE_FOR_insn_mulhh_uu, NULL }, /* mulhh_uu */
2683 { CODE_FOR_insn_mulhha_ss, NULL }, /* mulhha_ss */
2684 { CODE_FOR_insn_mulhha_su, NULL }, /* mulhha_su */
2685 { CODE_FOR_insn_mulhha_uu, NULL }, /* mulhha_uu */
2686 { CODE_FOR_insn_mulhhsa_uu, NULL }, /* mulhhsa_uu */
2687 { CODE_FOR_insn_mulhl_ss, NULL }, /* mulhl_ss */
2688 { CODE_FOR_insn_mulhl_su, NULL }, /* mulhl_su */
2689 { CODE_FOR_insn_mulhl_us, NULL }, /* mulhl_us */
2690 { CODE_FOR_insn_mulhl_uu, NULL }, /* mulhl_uu */
2691 { CODE_FOR_insn_mulhla_ss, NULL }, /* mulhla_ss */
2692 { CODE_FOR_insn_mulhla_su, NULL }, /* mulhla_su */
2693 { CODE_FOR_insn_mulhla_us, NULL }, /* mulhla_us */
2694 { CODE_FOR_insn_mulhla_uu, NULL }, /* mulhla_uu */
2695 { CODE_FOR_insn_mulhlsa_uu, NULL }, /* mulhlsa_uu */
2696 { CODE_FOR_insn_mulll_ss, NULL }, /* mulll_ss */
2697 { CODE_FOR_insn_mulll_su, NULL }, /* mulll_su */
2698 { CODE_FOR_insn_mulll_uu, NULL }, /* mulll_uu */
2699 { CODE_FOR_insn_mullla_ss, NULL }, /* mullla_ss */
2700 { CODE_FOR_insn_mullla_su, NULL }, /* mullla_su */
2701 { CODE_FOR_insn_mullla_uu, NULL }, /* mullla_uu */
2702 { CODE_FOR_insn_mulllsa_uu, NULL }, /* mulllsa_uu */
2703 { CODE_FOR_insn_mvnz, NULL }, /* mvnz */
2704 { CODE_FOR_insn_mvz, NULL }, /* mvz */
2705 { CODE_FOR_insn_mz, NULL }, /* mz */
2706 { CODE_FOR_insn_mzb, NULL }, /* mzb */
2707 { CODE_FOR_insn_mzh, NULL }, /* mzh */
2708 { CODE_FOR_insn_nap, NULL }, /* nap */
2709 { CODE_FOR_nop, NULL }, /* nop */
2710 { CODE_FOR_insn_nor, NULL }, /* nor */
2711 { CODE_FOR_iorsi3, NULL }, /* or */
2712 { CODE_FOR_insn_packbs_u, NULL }, /* packbs_u */
2713 { CODE_FOR_insn_packhb, NULL }, /* packhb */
2714 { CODE_FOR_insn_packhs, NULL }, /* packhs */
2715 { CODE_FOR_insn_packlb, NULL }, /* packlb */
2716 { CODE_FOR_popcountsi2, NULL }, /* pcnt */
2717 { CODE_FOR_insn_prefetch, NULL }, /* prefetch */
2718 { CODE_FOR_insn_prefetch_L1, NULL }, /* prefetch_L1 */
2719 { CODE_FOR_rotlsi3, NULL }, /* rl */
2720 { CODE_FOR_insn_s1a, NULL }, /* s1a */
2721 { CODE_FOR_insn_s2a, NULL }, /* s2a */
2722 { CODE_FOR_insn_s3a, NULL }, /* s3a */
2723 { CODE_FOR_insn_sadab_u, NULL }, /* sadab_u */
2724 { CODE_FOR_insn_sadah, NULL }, /* sadah */
2725 { CODE_FOR_insn_sadah_u, NULL }, /* sadah_u */
2726 { CODE_FOR_insn_sadb_u, NULL }, /* sadb_u */
2727 { CODE_FOR_insn_sadh, NULL }, /* sadh */
2728 { CODE_FOR_insn_sadh_u, NULL }, /* sadh_u */
2729 { CODE_FOR_insn_sb, NULL }, /* sb */
2730 { CODE_FOR_insn_seq, NULL }, /* seq */
2731 { CODE_FOR_insn_seqb, NULL }, /* seqb */
2732 { CODE_FOR_insn_seqh, NULL }, /* seqh */
2733 { CODE_FOR_insn_seqib, NULL }, /* seqib */
2734 { CODE_FOR_insn_seqih, NULL }, /* seqih */
2735 { CODE_FOR_insn_sh, NULL }, /* sh */
2736 { CODE_FOR_ashlsi3, NULL }, /* shl */
2737 { CODE_FOR_insn_shlb, NULL }, /* shlb */
2738 { CODE_FOR_insn_shlh, NULL }, /* shlh */
2739 { CODE_FOR_insn_shlb, NULL }, /* shlib */
2740 { CODE_FOR_insn_shlh, NULL }, /* shlih */
2741 { CODE_FOR_lshrsi3, NULL }, /* shr */
2742 { CODE_FOR_insn_shrb, NULL }, /* shrb */
2743 { CODE_FOR_insn_shrh, NULL }, /* shrh */
2744 { CODE_FOR_insn_shrb, NULL }, /* shrib */
2745 { CODE_FOR_insn_shrh, NULL }, /* shrih */
2746 { CODE_FOR_insn_slt, NULL }, /* slt */
2747 { CODE_FOR_insn_slt_u, NULL }, /* slt_u */
2748 { CODE_FOR_insn_sltb, NULL }, /* sltb */
2749 { CODE_FOR_insn_sltb_u, NULL }, /* sltb_u */
2750 { CODE_FOR_insn_slte, NULL }, /* slte */
2751 { CODE_FOR_insn_slte_u, NULL }, /* slte_u */
2752 { CODE_FOR_insn_slteb, NULL }, /* slteb */
2753 { CODE_FOR_insn_slteb_u, NULL }, /* slteb_u */
2754 { CODE_FOR_insn_slteh, NULL }, /* slteh */
2755 { CODE_FOR_insn_slteh_u, NULL }, /* slteh_u */
2756 { CODE_FOR_insn_slth, NULL }, /* slth */
2757 { CODE_FOR_insn_slth_u, NULL }, /* slth_u */
2758 { CODE_FOR_insn_sltib, NULL }, /* sltib */
2759 { CODE_FOR_insn_sltib_u, NULL }, /* sltib_u */
2760 { CODE_FOR_insn_sltih, NULL }, /* sltih */
2761 { CODE_FOR_insn_sltih_u, NULL }, /* sltih_u */
2762 { CODE_FOR_insn_sne, NULL }, /* sne */
2763 { CODE_FOR_insn_sneb, NULL }, /* sneb */
2764 { CODE_FOR_insn_sneh, NULL }, /* sneh */
2765 { CODE_FOR_ashrsi3, NULL }, /* sra */
2766 { CODE_FOR_insn_srab, NULL }, /* srab */
2767 { CODE_FOR_insn_srah, NULL }, /* srah */
2768 { CODE_FOR_insn_srab, NULL }, /* sraib */
2769 { CODE_FOR_insn_srah, NULL }, /* sraih */
2770 { CODE_FOR_subsi3, NULL }, /* sub */
2771 { CODE_FOR_insn_subb, NULL }, /* subb */
2772 { CODE_FOR_insn_subbs_u, NULL }, /* subbs_u */
2773 { CODE_FOR_insn_subh, NULL }, /* subh */
2774 { CODE_FOR_insn_subhs, NULL }, /* subhs */
2775 { CODE_FOR_sssubsi3, NULL }, /* subs */
2776 { CODE_FOR_insn_sw, NULL }, /* sw */
2777 { CODE_FOR_insn_tblidxb0, NULL }, /* tblidxb0 */
2778 { CODE_FOR_insn_tblidxb1, NULL }, /* tblidxb1 */
2779 { CODE_FOR_insn_tblidxb2, NULL }, /* tblidxb2 */
2780 { CODE_FOR_insn_tblidxb3, NULL }, /* tblidxb3 */
2781 { CODE_FOR_insn_tns, NULL }, /* tns */
2782 { CODE_FOR_insn_wh64, NULL }, /* wh64 */
2783 { CODE_FOR_xorsi3, NULL }, /* xor */
2784 { CODE_FOR_tilepro_network_barrier, NULL }, /* network_barrier */
2785 { CODE_FOR_tilepro_idn0_receive, NULL }, /* idn0_receive */
2786 { CODE_FOR_tilepro_idn1_receive, NULL }, /* idn1_receive */
2787 { CODE_FOR_tilepro_idn_send, NULL }, /* idn_send */
2788 { CODE_FOR_tilepro_sn_receive, NULL }, /* sn_receive */
2789 { CODE_FOR_tilepro_sn_send, NULL }, /* sn_send */
2790 { CODE_FOR_tilepro_udn0_receive, NULL }, /* udn0_receive */
2791 { CODE_FOR_tilepro_udn1_receive, NULL }, /* udn1_receive */
2792 { CODE_FOR_tilepro_udn2_receive, NULL }, /* udn2_receive */
2793 { CODE_FOR_tilepro_udn3_receive, NULL }, /* udn3_receive */
2794 { CODE_FOR_tilepro_udn_send, NULL }, /* udn_send */
2798 struct tilepro_builtin_def
2800 const char *name;
2801 enum tilepro_builtin code;
2802 bool is_const;
2803 /* The first character is the return type. Subsequent characters
2804 are the argument types. See char_to_type. */
2805 const char *type;
2809 static const struct tilepro_builtin_def tilepro_builtins[] = {
2810 { "__insn_add", TILEPRO_INSN_ADD, true, "lll" },
2811 { "__insn_addb", TILEPRO_INSN_ADDB, true, "lll" },
2812 { "__insn_addbs_u", TILEPRO_INSN_ADDBS_U, false, "lll" },
2813 { "__insn_addh", TILEPRO_INSN_ADDH, true, "lll" },
2814 { "__insn_addhs", TILEPRO_INSN_ADDHS, false, "lll" },
2815 { "__insn_addi", TILEPRO_INSN_ADD, true, "lll" },
2816 { "__insn_addib", TILEPRO_INSN_ADDIB, true, "lll" },
2817 { "__insn_addih", TILEPRO_INSN_ADDIH, true, "lll" },
2818 { "__insn_addli", TILEPRO_INSN_ADD, true, "lll" },
2819 { "__insn_addlis", TILEPRO_INSN_ADDLIS, false, "lll" },
2820 { "__insn_adds", TILEPRO_INSN_ADDS, false, "lll" },
2821 { "__insn_adiffb_u", TILEPRO_INSN_ADIFFB_U, true, "lll" },
2822 { "__insn_adiffh", TILEPRO_INSN_ADIFFH, true, "lll" },
2823 { "__insn_and", TILEPRO_INSN_AND, true, "lll" },
2824 { "__insn_andi", TILEPRO_INSN_AND, true, "lll" },
2825 { "__insn_auli", TILEPRO_INSN_AULI, true, "lll" },
2826 { "__insn_avgb_u", TILEPRO_INSN_AVGB_U, true, "lll" },
2827 { "__insn_avgh", TILEPRO_INSN_AVGH, true, "lll" },
2828 { "__insn_bitx", TILEPRO_INSN_BITX, true, "ll" },
2829 { "__insn_bytex", TILEPRO_INSN_BYTEX, true, "ll" },
2830 { "__insn_clz", TILEPRO_INSN_CLZ, true, "ll" },
2831 { "__insn_crc32_32", TILEPRO_INSN_CRC32_32, true, "lll" },
2832 { "__insn_crc32_8", TILEPRO_INSN_CRC32_8, true, "lll" },
2833 { "__insn_ctz", TILEPRO_INSN_CTZ, true, "ll" },
2834 { "__insn_drain", TILEPRO_INSN_DRAIN, false, "v" },
2835 { "__insn_dtlbpr", TILEPRO_INSN_DTLBPR, false, "vl" },
2836 { "__insn_dword_align", TILEPRO_INSN_DWORD_ALIGN, true, "lllk" },
2837 { "__insn_finv", TILEPRO_INSN_FINV, false, "vk" },
2838 { "__insn_flush", TILEPRO_INSN_FLUSH, false, "vk" },
2839 { "__insn_fnop", TILEPRO_INSN_FNOP, false, "v" },
2840 { "__insn_icoh", TILEPRO_INSN_ICOH, false, "vk" },
2841 { "__insn_ill", TILEPRO_INSN_ILL, false, "v" },
2842 { "__insn_info", TILEPRO_INSN_INFO, false, "vl" },
2843 { "__insn_infol", TILEPRO_INSN_INFOL, false, "vl" },
2844 { "__insn_inthb", TILEPRO_INSN_INTHB, true, "lll" },
2845 { "__insn_inthh", TILEPRO_INSN_INTHH, true, "lll" },
2846 { "__insn_intlb", TILEPRO_INSN_INTLB, true, "lll" },
2847 { "__insn_intlh", TILEPRO_INSN_INTLH, true, "lll" },
2848 { "__insn_inv", TILEPRO_INSN_INV, false, "vp" },
2849 { "__insn_lb", TILEPRO_INSN_LB, false, "lk" },
2850 { "__insn_lb_u", TILEPRO_INSN_LB_U, false, "lk" },
2851 { "__insn_lh", TILEPRO_INSN_LH, false, "lk" },
2852 { "__insn_lh_u", TILEPRO_INSN_LH_U, false, "lk" },
2853 { "__insn_lnk", TILEPRO_INSN_LNK, true, "l" },
2854 { "__insn_lw", TILEPRO_INSN_LW, false, "lk" },
2855 { "__insn_lw_na", TILEPRO_INSN_LW_NA, false, "lk" },
2856 { "__insn_lb_L2", TILEPRO_INSN_LB_L2, false, "lk" },
2857 { "__insn_lb_u_L2", TILEPRO_INSN_LB_U_L2, false, "lk" },
2858 { "__insn_lh_L2", TILEPRO_INSN_LH_L2, false, "lk" },
2859 { "__insn_lh_u_L2", TILEPRO_INSN_LH_U_L2, false, "lk" },
2860 { "__insn_lw_L2", TILEPRO_INSN_LW_L2, false, "lk" },
2861 { "__insn_lw_na_L2", TILEPRO_INSN_LW_NA_L2, false, "lk" },
2862 { "__insn_lb_miss", TILEPRO_INSN_LB_MISS, false, "lk" },
2863 { "__insn_lb_u_miss", TILEPRO_INSN_LB_U_MISS, false, "lk" },
2864 { "__insn_lh_miss", TILEPRO_INSN_LH_MISS, false, "lk" },
2865 { "__insn_lh_u_miss", TILEPRO_INSN_LH_U_MISS, false, "lk" },
2866 { "__insn_lw_miss", TILEPRO_INSN_LW_MISS, false, "lk" },
2867 { "__insn_lw_na_miss", TILEPRO_INSN_LW_NA_MISS, false, "lk" },
2868 { "__insn_maxb_u", TILEPRO_INSN_MAXB_U, true, "lll" },
2869 { "__insn_maxh", TILEPRO_INSN_MAXH, true, "lll" },
2870 { "__insn_maxib_u", TILEPRO_INSN_MAXIB_U, true, "lll" },
2871 { "__insn_maxih", TILEPRO_INSN_MAXIH, true, "lll" },
2872 { "__insn_mf", TILEPRO_INSN_MF, false, "v" },
2873 { "__insn_mfspr", TILEPRO_INSN_MFSPR, false, "ll" },
2874 { "__insn_minb_u", TILEPRO_INSN_MINB_U, true, "lll" },
2875 { "__insn_minh", TILEPRO_INSN_MINH, true, "lll" },
2876 { "__insn_minib_u", TILEPRO_INSN_MINIB_U, true, "lll" },
2877 { "__insn_minih", TILEPRO_INSN_MINIH, true, "lll" },
2878 { "__insn_mm", TILEPRO_INSN_MM, true, "lllll" },
2879 { "__insn_mnz", TILEPRO_INSN_MNZ, true, "lll" },
2880 { "__insn_mnzb", TILEPRO_INSN_MNZB, true, "lll" },
2881 { "__insn_mnzh", TILEPRO_INSN_MNZH, true, "lll" },
2882 { "__insn_move", TILEPRO_INSN_MOVE, true, "ll" },
2883 { "__insn_movei", TILEPRO_INSN_MOVE, true, "ll" },
2884 { "__insn_moveli", TILEPRO_INSN_MOVE, true, "ll" },
2885 { "__insn_movelis", TILEPRO_INSN_MOVELIS, false, "ll" },
2886 { "__insn_mtspr", TILEPRO_INSN_MTSPR, false, "vll" },
2887 { "__insn_mulhh_ss", TILEPRO_INSN_MULHH_SS, true, "lll" },
2888 { "__insn_mulhh_su", TILEPRO_INSN_MULHH_SU, true, "lll" },
2889 { "__insn_mulhh_uu", TILEPRO_INSN_MULHH_UU, true, "lll" },
2890 { "__insn_mulhha_ss", TILEPRO_INSN_MULHHA_SS, true, "llll" },
2891 { "__insn_mulhha_su", TILEPRO_INSN_MULHHA_SU, true, "llll" },
2892 { "__insn_mulhha_uu", TILEPRO_INSN_MULHHA_UU, true, "llll" },
2893 { "__insn_mulhhsa_uu", TILEPRO_INSN_MULHHSA_UU, true, "llll" },
2894 { "__insn_mulhl_ss", TILEPRO_INSN_MULHL_SS, true, "lll" },
2895 { "__insn_mulhl_su", TILEPRO_INSN_MULHL_SU, true, "lll" },
2896 { "__insn_mulhl_us", TILEPRO_INSN_MULHL_US, true, "lll" },
2897 { "__insn_mulhl_uu", TILEPRO_INSN_MULHL_UU, true, "lll" },
2898 { "__insn_mulhla_ss", TILEPRO_INSN_MULHLA_SS, true, "llll" },
2899 { "__insn_mulhla_su", TILEPRO_INSN_MULHLA_SU, true, "llll" },
2900 { "__insn_mulhla_us", TILEPRO_INSN_MULHLA_US, true, "llll" },
2901 { "__insn_mulhla_uu", TILEPRO_INSN_MULHLA_UU, true, "llll" },
2902 { "__insn_mulhlsa_uu", TILEPRO_INSN_MULHLSA_UU, true, "llll" },
2903 { "__insn_mulll_ss", TILEPRO_INSN_MULLL_SS, true, "lll" },
2904 { "__insn_mulll_su", TILEPRO_INSN_MULLL_SU, true, "lll" },
2905 { "__insn_mulll_uu", TILEPRO_INSN_MULLL_UU, true, "lll" },
2906 { "__insn_mullla_ss", TILEPRO_INSN_MULLLA_SS, true, "llll" },
2907 { "__insn_mullla_su", TILEPRO_INSN_MULLLA_SU, true, "llll" },
2908 { "__insn_mullla_uu", TILEPRO_INSN_MULLLA_UU, true, "llll" },
2909 { "__insn_mulllsa_uu", TILEPRO_INSN_MULLLSA_UU, true, "llll" },
2910 { "__insn_mvnz", TILEPRO_INSN_MVNZ, true, "llll" },
2911 { "__insn_mvz", TILEPRO_INSN_MVZ, true, "llll" },
2912 { "__insn_mz", TILEPRO_INSN_MZ, true, "lll" },
2913 { "__insn_mzb", TILEPRO_INSN_MZB, true, "lll" },
2914 { "__insn_mzh", TILEPRO_INSN_MZH, true, "lll" },
2915 { "__insn_nap", TILEPRO_INSN_NAP, false, "v" },
2916 { "__insn_nop", TILEPRO_INSN_NOP, true, "v" },
2917 { "__insn_nor", TILEPRO_INSN_NOR, true, "lll" },
2918 { "__insn_or", TILEPRO_INSN_OR, true, "lll" },
2919 { "__insn_ori", TILEPRO_INSN_OR, true, "lll" },
2920 { "__insn_packbs_u", TILEPRO_INSN_PACKBS_U, false, "lll" },
2921 { "__insn_packhb", TILEPRO_INSN_PACKHB, true, "lll" },
2922 { "__insn_packhs", TILEPRO_INSN_PACKHS, false, "lll" },
2923 { "__insn_packlb", TILEPRO_INSN_PACKLB, true, "lll" },
2924 { "__insn_pcnt", TILEPRO_INSN_PCNT, true, "ll" },
2925 { "__insn_prefetch", TILEPRO_INSN_PREFETCH, false, "vk" },
2926 { "__insn_prefetch_L1", TILEPRO_INSN_PREFETCH_L1, false, "vk" },
2927 { "__insn_rl", TILEPRO_INSN_RL, true, "lll" },
2928 { "__insn_rli", TILEPRO_INSN_RL, true, "lll" },
2929 { "__insn_s1a", TILEPRO_INSN_S1A, true, "lll" },
2930 { "__insn_s2a", TILEPRO_INSN_S2A, true, "lll" },
2931 { "__insn_s3a", TILEPRO_INSN_S3A, true, "lll" },
2932 { "__insn_sadab_u", TILEPRO_INSN_SADAB_U, true, "llll" },
2933 { "__insn_sadah", TILEPRO_INSN_SADAH, true, "llll" },
2934 { "__insn_sadah_u", TILEPRO_INSN_SADAH_U, true, "llll" },
2935 { "__insn_sadb_u", TILEPRO_INSN_SADB_U, true, "lll" },
2936 { "__insn_sadh", TILEPRO_INSN_SADH, true, "lll" },
2937 { "__insn_sadh_u", TILEPRO_INSN_SADH_U, true, "lll" },
2938 { "__insn_sb", TILEPRO_INSN_SB, false, "vpl" },
2939 { "__insn_seq", TILEPRO_INSN_SEQ, true, "lll" },
2940 { "__insn_seqb", TILEPRO_INSN_SEQB, true, "lll" },
2941 { "__insn_seqh", TILEPRO_INSN_SEQH, true, "lll" },
2942 { "__insn_seqi", TILEPRO_INSN_SEQ, true, "lll" },
2943 { "__insn_seqib", TILEPRO_INSN_SEQIB, true, "lll" },
2944 { "__insn_seqih", TILEPRO_INSN_SEQIH, true, "lll" },
2945 { "__insn_sh", TILEPRO_INSN_SH, false, "vpl" },
2946 { "__insn_shl", TILEPRO_INSN_SHL, true, "lll" },
2947 { "__insn_shlb", TILEPRO_INSN_SHLB, true, "lll" },
2948 { "__insn_shlh", TILEPRO_INSN_SHLH, true, "lll" },
2949 { "__insn_shli", TILEPRO_INSN_SHL, true, "lll" },
2950 { "__insn_shlib", TILEPRO_INSN_SHLIB, true, "lll" },
2951 { "__insn_shlih", TILEPRO_INSN_SHLIH, true, "lll" },
2952 { "__insn_shr", TILEPRO_INSN_SHR, true, "lll" },
2953 { "__insn_shrb", TILEPRO_INSN_SHRB, true, "lll" },
2954 { "__insn_shrh", TILEPRO_INSN_SHRH, true, "lll" },
2955 { "__insn_shri", TILEPRO_INSN_SHR, true, "lll" },
2956 { "__insn_shrib", TILEPRO_INSN_SHRIB, true, "lll" },
2957 { "__insn_shrih", TILEPRO_INSN_SHRIH, true, "lll" },
2958 { "__insn_slt", TILEPRO_INSN_SLT, true, "lll" },
2959 { "__insn_slt_u", TILEPRO_INSN_SLT_U, true, "lll" },
2960 { "__insn_sltb", TILEPRO_INSN_SLTB, true, "lll" },
2961 { "__insn_sltb_u", TILEPRO_INSN_SLTB_U, true, "lll" },
2962 { "__insn_slte", TILEPRO_INSN_SLTE, true, "lll" },
2963 { "__insn_slte_u", TILEPRO_INSN_SLTE_U, true, "lll" },
2964 { "__insn_slteb", TILEPRO_INSN_SLTEB, true, "lll" },
2965 { "__insn_slteb_u", TILEPRO_INSN_SLTEB_U, true, "lll" },
2966 { "__insn_slteh", TILEPRO_INSN_SLTEH, true, "lll" },
2967 { "__insn_slteh_u", TILEPRO_INSN_SLTEH_U, true, "lll" },
2968 { "__insn_slth", TILEPRO_INSN_SLTH, true, "lll" },
2969 { "__insn_slth_u", TILEPRO_INSN_SLTH_U, true, "lll" },
2970 { "__insn_slti", TILEPRO_INSN_SLT, true, "lll" },
2971 { "__insn_slti_u", TILEPRO_INSN_SLT_U, true, "lll" },
2972 { "__insn_sltib", TILEPRO_INSN_SLTIB, true, "lll" },
2973 { "__insn_sltib_u", TILEPRO_INSN_SLTIB_U, true, "lll" },
2974 { "__insn_sltih", TILEPRO_INSN_SLTIH, true, "lll" },
2975 { "__insn_sltih_u", TILEPRO_INSN_SLTIH_U, true, "lll" },
2976 { "__insn_sne", TILEPRO_INSN_SNE, true, "lll" },
2977 { "__insn_sneb", TILEPRO_INSN_SNEB, true, "lll" },
2978 { "__insn_sneh", TILEPRO_INSN_SNEH, true, "lll" },
2979 { "__insn_sra", TILEPRO_INSN_SRA, true, "lll" },
2980 { "__insn_srab", TILEPRO_INSN_SRAB, true, "lll" },
2981 { "__insn_srah", TILEPRO_INSN_SRAH, true, "lll" },
2982 { "__insn_srai", TILEPRO_INSN_SRA, true, "lll" },
2983 { "__insn_sraib", TILEPRO_INSN_SRAIB, true, "lll" },
2984 { "__insn_sraih", TILEPRO_INSN_SRAIH, true, "lll" },
2985 { "__insn_sub", TILEPRO_INSN_SUB, true, "lll" },
2986 { "__insn_subb", TILEPRO_INSN_SUBB, true, "lll" },
2987 { "__insn_subbs_u", TILEPRO_INSN_SUBBS_U, false, "lll" },
2988 { "__insn_subh", TILEPRO_INSN_SUBH, true, "lll" },
2989 { "__insn_subhs", TILEPRO_INSN_SUBHS, false, "lll" },
2990 { "__insn_subs", TILEPRO_INSN_SUBS, false, "lll" },
2991 { "__insn_sw", TILEPRO_INSN_SW, false, "vpl" },
2992 { "__insn_tblidxb0", TILEPRO_INSN_TBLIDXB0, true, "lll" },
2993 { "__insn_tblidxb1", TILEPRO_INSN_TBLIDXB1, true, "lll" },
2994 { "__insn_tblidxb2", TILEPRO_INSN_TBLIDXB2, true, "lll" },
2995 { "__insn_tblidxb3", TILEPRO_INSN_TBLIDXB3, true, "lll" },
2996 { "__insn_tns", TILEPRO_INSN_TNS, false, "lp" },
2997 { "__insn_wh64", TILEPRO_INSN_WH64, false, "vp" },
2998 { "__insn_xor", TILEPRO_INSN_XOR, true, "lll" },
2999 { "__insn_xori", TILEPRO_INSN_XOR, true, "lll" },
3000 { "__tile_network_barrier", TILEPRO_NETWORK_BARRIER, false, "v" },
3001 { "__tile_idn0_receive", TILEPRO_IDN0_RECEIVE, false, "l" },
3002 { "__tile_idn1_receive", TILEPRO_IDN1_RECEIVE, false, "l" },
3003 { "__tile_idn_send", TILEPRO_IDN_SEND, false, "vl" },
3004 { "__tile_sn_receive", TILEPRO_SN_RECEIVE, false, "l" },
3005 { "__tile_sn_send", TILEPRO_SN_SEND, false, "vl" },
3006 { "__tile_udn0_receive", TILEPRO_UDN0_RECEIVE, false, "l" },
3007 { "__tile_udn1_receive", TILEPRO_UDN1_RECEIVE, false, "l" },
3008 { "__tile_udn2_receive", TILEPRO_UDN2_RECEIVE, false, "l" },
3009 { "__tile_udn3_receive", TILEPRO_UDN3_RECEIVE, false, "l" },
3010 { "__tile_udn_send", TILEPRO_UDN_SEND, false, "vl" },
3014 /* Convert a character in a builtin type string to a tree type. */
3015 static tree
3016 char_to_type (char c)
3018 static tree volatile_ptr_type_node = NULL;
3019 static tree volatile_const_ptr_type_node = NULL;
3021 if (volatile_ptr_type_node == NULL)
3023 volatile_ptr_type_node =
3024 build_pointer_type (build_qualified_type (void_type_node,
3025 TYPE_QUAL_VOLATILE));
3026 volatile_const_ptr_type_node =
3027 build_pointer_type (build_qualified_type (void_type_node,
3028 TYPE_QUAL_CONST
3029 | TYPE_QUAL_VOLATILE));
3032 switch (c)
3034 case 'v':
3035 return void_type_node;
3036 case 'l':
3037 return long_unsigned_type_node;
3038 case 'p':
3039 return volatile_ptr_type_node;
3040 case 'k':
3041 return volatile_const_ptr_type_node;
3042 default:
3043 gcc_unreachable ();
3048 /* Implement TARGET_INIT_BUILTINS. */
3049 static void
3050 tilepro_init_builtins (void)
3052 size_t i;
3054 for (i = 0; i < ARRAY_SIZE (tilepro_builtins); i++)
3056 const struct tilepro_builtin_def *p = &tilepro_builtins[i];
3057 tree ftype, ret_type, arg_type_list = void_list_node;
3058 tree decl;
3059 int j;
3061 for (j = strlen (p->type) - 1; j > 0; j--)
3063 arg_type_list =
3064 tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list);
3067 ret_type = char_to_type (p->type[0]);
3069 ftype = build_function_type (ret_type, arg_type_list);
3071 decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
3072 NULL, NULL);
3074 if (p->is_const)
3075 TREE_READONLY (decl) = 1;
3076 TREE_NOTHROW (decl) = 1;
3078 if (tilepro_builtin_info[p->code].fndecl == NULL)
3079 tilepro_builtin_info[p->code].fndecl = decl;
3084 /* Implement TARGET_EXPAND_BUILTIN. */
3085 static rtx
3086 tilepro_expand_builtin (tree exp,
3087 rtx target,
3088 rtx subtarget ATTRIBUTE_UNUSED,
3089 machine_mode mode ATTRIBUTE_UNUSED,
3090 int ignore ATTRIBUTE_UNUSED)
3092 #define MAX_BUILTIN_ARGS 4
3094 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
3095 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
3096 tree arg;
3097 call_expr_arg_iterator iter;
3098 enum insn_code icode;
3099 rtx op[MAX_BUILTIN_ARGS + 1], pat;
3100 int opnum;
3101 bool nonvoid;
3102 insn_gen_fn fn;
3104 if (fcode >= TILEPRO_BUILTIN_max)
3105 internal_error ("bad builtin fcode");
3106 icode = tilepro_builtin_info[fcode].icode;
3107 if (icode == 0)
3108 internal_error ("bad builtin icode");
3110 nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
3112 opnum = nonvoid;
3113 FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
3115 const struct insn_operand_data *insn_op;
3117 if (arg == error_mark_node)
3118 return NULL_RTX;
3119 if (opnum > MAX_BUILTIN_ARGS)
3120 return NULL_RTX;
3122 insn_op = &insn_data[icode].operand[opnum];
3124 op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL);
3126 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3127 op[opnum] = copy_to_mode_reg (insn_op->mode, op[opnum]);
3129 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3131 /* We still failed to meet the predicate even after moving
3132 into a register. Assume we needed an immediate. */
3133 error_at (EXPR_LOCATION (exp),
3134 "operand must be an immediate of the right size");
3135 return const0_rtx;
3138 opnum++;
3141 if (nonvoid)
3143 machine_mode tmode = insn_data[icode].operand[0].mode;
3144 if (!target
3145 || GET_MODE (target) != tmode
3146 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
3147 target = gen_reg_rtx (tmode);
3148 op[0] = target;
3151 fn = GEN_FCN (icode);
3152 switch (opnum)
3154 case 0:
3155 pat = fn (NULL_RTX);
3156 break;
3157 case 1:
3158 pat = fn (op[0]);
3159 break;
3160 case 2:
3161 pat = fn (op[0], op[1]);
3162 break;
3163 case 3:
3164 pat = fn (op[0], op[1], op[2]);
3165 break;
3166 case 4:
3167 pat = fn (op[0], op[1], op[2], op[3]);
3168 break;
3169 case 5:
3170 pat = fn (op[0], op[1], op[2], op[3], op[4]);
3171 break;
3172 default:
3173 gcc_unreachable ();
3175 if (!pat)
3176 return NULL_RTX;
3178 /* If we are generating a prefetch, tell the scheduler not to move
3179 it around. */
3180 if (GET_CODE (pat) == PREFETCH)
3181 PREFETCH_SCHEDULE_BARRIER_P (pat) = true;
3183 emit_insn (pat);
3185 if (nonvoid)
3186 return target;
3187 else
3188 return const0_rtx;
3192 /* Implement TARGET_BUILTIN_DECL. */
3193 static tree
3194 tilepro_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
3196 if (code >= TILEPRO_BUILTIN_max)
3197 return error_mark_node;
3199 return tilepro_builtin_info[code].fndecl;
3204 /* Stack frames */
3206 /* Return whether REGNO needs to be saved in the stack frame. */
3207 static bool
3208 need_to_save_reg (unsigned int regno)
3210 if (!fixed_regs[regno] && !call_used_regs[regno]
3211 && df_regs_ever_live_p (regno))
3212 return true;
3214 if (flag_pic
3215 && (regno == PIC_OFFSET_TABLE_REGNUM
3216 || regno == TILEPRO_PIC_TEXT_LABEL_REGNUM)
3217 && (crtl->uses_pic_offset_table || crtl->saves_all_registers))
3218 return true;
3220 if (crtl->calls_eh_return)
3222 unsigned i;
3223 for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++)
3225 if (regno == EH_RETURN_DATA_REGNO (i))
3226 return true;
3230 return false;
3234 /* Return the size of the register savev area. This function is only
3235 correct starting with local register allocation */
3236 static int
3237 tilepro_saved_regs_size (void)
3239 int reg_save_size = 0;
3240 int regno;
3241 int offset_to_frame;
3242 int align_mask;
3244 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3245 if (need_to_save_reg (regno))
3246 reg_save_size += UNITS_PER_WORD;
3248 /* Pad out the register save area if necessary to make
3249 frame_pointer_rtx be as aligned as the stack pointer. */
3250 offset_to_frame = crtl->args.pretend_args_size + reg_save_size;
3251 align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1;
3252 reg_save_size += (-offset_to_frame) & align_mask;
3254 return reg_save_size;
3258 /* Round up frame size SIZE. */
3259 static int
3260 round_frame_size (int size)
3262 return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1)
3263 & -STACK_BOUNDARY / BITS_PER_UNIT);
3267 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3268 emit the corresponding REG_CFA_OFFSET note described by CFA and
3269 CFA_OFFSET. Return the emitted insn. */
3270 static rtx
3271 frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa,
3272 int cfa_offset)
3274 rtx reg = gen_rtx_REG (Pmode, regno);
3275 rtx mem = gen_frame_mem (Pmode, addr);
3276 rtx mov = gen_movsi (mem, reg);
3278 /* Describe what just happened in a way that dwarf understands. We
3279 use temporary registers to hold the address to make scheduling
3280 easier, and use the REG_CFA_OFFSET to describe the address as an
3281 offset from the CFA. */
3282 rtx reg_note = gen_rtx_REG (Pmode, regno_note);
3283 rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, gen_int_si (cfa_offset));
3284 rtx cfa_relative_mem = gen_frame_mem (Pmode, cfa_relative_addr);
3285 rtx real = gen_rtx_SET (cfa_relative_mem, reg_note);
3286 add_reg_note (mov, REG_CFA_OFFSET, real);
3288 return emit_insn (mov);
3292 /* Emit a load in the stack frame to load REGNO from address ADDR.
3293 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3294 non-null. Return the emitted insn. */
3295 static rtx_insn *
3296 frame_emit_load (int regno, rtx addr, rtx *cfa_restores)
3298 rtx reg = gen_rtx_REG (Pmode, regno);
3299 rtx mem = gen_frame_mem (Pmode, addr);
3300 if (cfa_restores)
3301 *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores);
3302 return emit_insn (gen_movsi (reg, mem));
3306 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3307 including sequences. */
3308 static rtx_insn *
3309 set_frame_related_p (void)
3311 rtx_insn *seq = get_insns ();
3312 rtx_insn *insn;
3314 end_sequence ();
3316 if (!seq)
3317 return NULL;
3319 if (INSN_P (seq))
3321 insn = seq;
3322 while (insn != NULL_RTX)
3324 RTX_FRAME_RELATED_P (insn) = 1;
3325 insn = NEXT_INSN (insn);
3327 seq = emit_insn (seq);
3329 else
3331 seq = emit_insn (seq);
3332 RTX_FRAME_RELATED_P (seq) = 1;
3334 return seq;
3338 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3340 /* This emits code for 'sp += offset'.
3342 The ABI only allows us to modify 'sp' in a single 'addi' or
3343 'addli', so the backtracer understands it. Larger amounts cannot
3344 use those instructions, so are added by placing the offset into a
3345 large register and using 'add'.
3347 This happens after reload, so we need to expand it ourselves. */
3348 static rtx_insn *
3349 emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related,
3350 rtx reg_notes)
3352 rtx to_add;
3353 rtx imm_rtx = gen_int_si (offset);
3355 rtx_insn *insn;
3356 if (satisfies_constraint_J (imm_rtx))
3358 /* We can add this using a single addi or addli. */
3359 to_add = imm_rtx;
3361 else
3363 rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3364 tilepro_expand_set_const32 (tmp, imm_rtx);
3365 to_add = tmp;
3368 /* Actually adjust the stack pointer. */
3369 insn = emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
3370 to_add));
3371 REG_NOTES (insn) = reg_notes;
3373 /* Describe what just happened in a way that dwarf understands. */
3374 if (frame_related)
3376 rtx real = gen_rtx_SET (stack_pointer_rtx,
3377 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3378 imm_rtx));
3379 RTX_FRAME_RELATED_P (insn) = 1;
3380 add_reg_note (insn, REG_CFA_ADJUST_CFA, real);
3383 return insn;
3387 /* Return whether the current function is leaf. This takes into
3388 account whether the function calls tls_get_addr. */
3389 static bool
3390 tilepro_current_function_is_leaf (void)
3392 return crtl->is_leaf && !cfun->machine->calls_tls_get_addr;
3396 /* Return the frame size. */
3397 static int
3398 compute_total_frame_size (void)
3400 int total_size = (get_frame_size () + tilepro_saved_regs_size ()
3401 + crtl->outgoing_args_size
3402 + crtl->args.pretend_args_size);
3404 if (!tilepro_current_function_is_leaf () || cfun->calls_alloca)
3406 /* Make room for save area in callee. */
3407 total_size += STACK_POINTER_OFFSET;
3410 return round_frame_size (total_size);
3414 /* Return nonzero if this function is known to have a null epilogue.
3415 This allows the optimizer to omit jumps to jumps if no stack was
3416 created. */
3417 bool
3418 tilepro_can_use_return_insn_p (void)
3420 return (reload_completed
3421 && cfun->static_chain_decl == 0
3422 && compute_total_frame_size () == 0
3423 && tilepro_current_function_is_leaf ()
3424 && !crtl->profile && !df_regs_ever_live_p (TILEPRO_LINK_REGNUM));
3428 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3429 is a frame pointer, it computes the value relative to
3430 that. Otherwise it uses the stack pointer. */
3431 static rtx
3432 compute_frame_addr (int offset_from_fp, int *next_scratch_regno)
3434 rtx base_reg_rtx, tmp_reg_rtx, offset_rtx;
3435 int offset_from_base;
3437 if (frame_pointer_needed)
3439 base_reg_rtx = hard_frame_pointer_rtx;
3440 offset_from_base = offset_from_fp;
3442 else
3444 int offset_from_sp = compute_total_frame_size () + offset_from_fp;
3445 base_reg_rtx = stack_pointer_rtx;
3446 offset_from_base = offset_from_sp;
3449 if (offset_from_base == 0)
3450 return base_reg_rtx;
3452 /* Compute the new value of the stack pointer. */
3453 tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3454 offset_rtx = gen_int_si (offset_from_base);
3456 if (!tilepro_expand_addsi (tmp_reg_rtx, base_reg_rtx, offset_rtx))
3458 emit_insn (gen_rtx_SET (tmp_reg_rtx,
3459 gen_rtx_PLUS (Pmode, base_reg_rtx,
3460 offset_rtx)));
3463 return tmp_reg_rtx;
3467 /* The stack frame looks like this:
3468 +-------------+
3469 | ... |
3470 | incoming |
3471 | stack args |
3472 AP -> +-------------+
3473 | caller's HFP|
3474 +-------------+
3475 | lr save |
3476 HFP -> +-------------+
3477 | var args |
3478 | reg save | crtl->args.pretend_args_size bytes
3479 +-------------+
3480 | ... |
3481 | saved regs | tilepro_saved_regs_size() bytes
3482 FP -> +-------------+
3483 | ... |
3484 | vars | get_frame_size() bytes
3485 +-------------+
3486 | ... |
3487 | outgoing |
3488 | stack args | crtl->outgoing_args_size bytes
3489 +-------------+
3490 | HFP | 4 bytes (only here if nonleaf / alloca)
3491 +-------------+
3492 | callee lr | 4 bytes (only here if nonleaf / alloca)
3493 | save |
3494 SP -> +-------------+
3496 HFP == incoming SP.
3498 For functions with a frame larger than 32767 bytes, or which use
3499 alloca (), r52 is used as a frame pointer. Otherwise there is no
3500 frame pointer.
3502 FP is saved at SP+4 before calling a subroutine so the
3503 callee can chain. */
3504 void
3505 tilepro_expand_prologue (void)
3507 #define ROUND_ROBIN_SIZE 4
3508 /* We round-robin through four scratch registers to hold temporary
3509 addresses for saving registers, to make instruction scheduling
3510 easier. */
3511 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3512 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3514 rtx insn, cfa;
3515 unsigned int which_scratch;
3516 int offset, start_offset, regno;
3518 /* A register that holds a copy of the incoming fp. */
3519 int fp_copy_regno = -1;
3521 /* A register that holds a copy of the incoming sp. */
3522 int sp_copy_regno = -1;
3524 /* Next scratch register number to hand out (postdecrementing). */
3525 int next_scratch_regno = 29;
3527 int total_size = compute_total_frame_size ();
3529 if (flag_stack_usage_info)
3530 current_function_static_stack_size = total_size;
3532 /* Save lr first in its special location because code after this
3533 might use the link register as a scratch register. */
3534 if (df_regs_ever_live_p (TILEPRO_LINK_REGNUM) || crtl->calls_eh_return)
3536 FRP (frame_emit_store (TILEPRO_LINK_REGNUM, TILEPRO_LINK_REGNUM,
3537 stack_pointer_rtx, stack_pointer_rtx, 0));
3538 emit_insn (gen_blockage ());
3541 if (total_size == 0)
3543 /* Load the PIC register if needed. */
3544 if (flag_pic && crtl->uses_pic_offset_table)
3545 load_pic_register (false);
3547 return;
3550 cfa = stack_pointer_rtx;
3552 if (frame_pointer_needed)
3554 fp_copy_regno = next_scratch_regno--;
3556 /* Copy the old frame pointer aside so we can save it later. */
3557 insn = FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno),
3558 hard_frame_pointer_rtx));
3559 add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
3561 /* Set up the frame pointer. */
3562 insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
3563 add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx);
3564 cfa = hard_frame_pointer_rtx;
3565 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
3567 /* fp holds a copy of the incoming sp, in case we need to store
3568 it. */
3569 sp_copy_regno = HARD_FRAME_POINTER_REGNUM;
3571 else if (!tilepro_current_function_is_leaf ())
3573 /* Copy the old stack pointer aside so we can save it later. */
3574 sp_copy_regno = next_scratch_regno--;
3575 emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno),
3576 stack_pointer_rtx);
3579 if (tilepro_current_function_is_leaf ())
3581 /* No need to store chain pointer to caller's frame. */
3582 emit_sp_adjust (-total_size, &next_scratch_regno,
3583 !frame_pointer_needed, NULL_RTX);
3585 else
3587 /* Save the frame pointer (incoming sp value) to support
3588 backtracing. First we need to create an rtx with the store
3589 address. */
3590 rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--);
3591 rtx size_rtx = gen_int_si (-(total_size - UNITS_PER_WORD));
3593 if (add_operand (size_rtx, Pmode))
3595 /* Expose more parallelism by computing this value from the
3596 original stack pointer, not the one after we have pushed
3597 the frame. */
3598 rtx p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, size_rtx);
3599 emit_insn (gen_rtx_SET (chain_addr, p));
3600 emit_sp_adjust (-total_size, &next_scratch_regno,
3601 !frame_pointer_needed, NULL_RTX);
3603 else
3605 /* The stack frame is large, so just store the incoming sp
3606 value at *(new_sp + UNITS_PER_WORD). */
3607 rtx p;
3608 emit_sp_adjust (-total_size, &next_scratch_regno,
3609 !frame_pointer_needed, NULL_RTX);
3610 p = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3611 GEN_INT (UNITS_PER_WORD));
3612 emit_insn (gen_rtx_SET (chain_addr, p));
3615 /* Save our frame pointer for backtrace chaining. */
3616 emit_insn (gen_movsi (gen_frame_mem (SImode, chain_addr),
3617 gen_rtx_REG (SImode, sp_copy_regno)));
3620 /* Compute where to start storing registers we need to save. */
3621 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
3622 offset = start_offset;
3624 /* Store all registers that need saving. */
3625 which_scratch = 0;
3626 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
3627 if (need_to_save_reg (regno))
3629 rtx r = reg_save_addr[which_scratch];
3630 int from_regno;
3631 int cfa_offset = frame_pointer_needed ? offset : total_size + offset;
3633 if (r == NULL_RTX)
3635 rtx p = compute_frame_addr (offset, &next_scratch_regno);
3636 r = gen_rtx_REG (word_mode, next_scratch_regno--);
3637 reg_save_addr[which_scratch] = r;
3639 emit_insn (gen_rtx_SET (r, p));
3641 else
3643 /* Advance to the next stack slot to store this register. */
3644 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
3645 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
3646 emit_insn (gen_rtx_SET (r, p));
3649 /* Save this register to the stack (but use the old fp value
3650 we copied aside if appropriate). */
3651 from_regno = (fp_copy_regno >= 0
3652 && regno ==
3653 HARD_FRAME_POINTER_REGNUM) ? fp_copy_regno : regno;
3654 FRP (frame_emit_store (from_regno, regno, r, cfa, cfa_offset));
3656 offset -= UNITS_PER_WORD;
3657 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
3660 /* If profiling, force that to happen after the frame is set up. */
3661 if (crtl->profile)
3662 emit_insn (gen_blockage ());
3664 /* Load the PIC register if needed. */
3665 if (flag_pic && crtl->uses_pic_offset_table)
3666 load_pic_register (false);
3670 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
3671 true for a sibcall_epilogue pattern, and false for an epilogue
3672 pattern. */
3673 void
3674 tilepro_expand_epilogue (bool sibcall_p)
3676 /* We round-robin through four scratch registers to hold temporary
3677 addresses for saving registers, to make instruction scheduling
3678 easier. */
3679 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3680 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3682 rtx_insn *last_insn, *insn;
3683 unsigned int which_scratch;
3684 int offset, start_offset, regno;
3685 rtx cfa_restores = NULL_RTX;
3687 /* A register that holds a copy of the incoming fp. */
3688 int fp_copy_regno = -1;
3690 /* Next scratch register number to hand out (postdecrementing). */
3691 int next_scratch_regno = 29;
3693 int total_size = compute_total_frame_size ();
3695 last_insn = get_last_insn ();
3697 /* Load lr first since we are going to need it first. */
3698 insn = NULL;
3699 if (df_regs_ever_live_p (TILEPRO_LINK_REGNUM))
3701 insn = frame_emit_load (TILEPRO_LINK_REGNUM,
3702 compute_frame_addr (0, &next_scratch_regno),
3703 &cfa_restores);
3706 if (total_size == 0)
3708 if (insn)
3710 RTX_FRAME_RELATED_P (insn) = 1;
3711 REG_NOTES (insn) = cfa_restores;
3713 goto done;
3716 /* Compute where to start restoring registers. */
3717 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
3718 offset = start_offset;
3720 if (frame_pointer_needed)
3721 fp_copy_regno = next_scratch_regno--;
3723 /* Restore all callee-saved registers. */
3724 which_scratch = 0;
3725 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
3726 if (need_to_save_reg (regno))
3728 rtx r = reg_save_addr[which_scratch];
3729 if (r == NULL_RTX)
3731 r = compute_frame_addr (offset, &next_scratch_regno);
3732 reg_save_addr[which_scratch] = r;
3734 else
3736 /* Advance to the next stack slot to store this
3737 register. */
3738 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
3739 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
3740 emit_insn (gen_rtx_SET (r, p));
3743 if (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM)
3744 frame_emit_load (fp_copy_regno, r, NULL);
3745 else
3746 frame_emit_load (regno, r, &cfa_restores);
3748 offset -= UNITS_PER_WORD;
3749 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
3752 if (!tilepro_current_function_is_leaf ())
3753 cfa_restores =
3754 alloc_reg_note (REG_CFA_RESTORE, stack_pointer_rtx, cfa_restores);
3756 emit_insn (gen_blockage ());
3758 if (frame_pointer_needed)
3760 /* Restore the old stack pointer by copying from the frame
3761 pointer. */
3762 insn = emit_insn (gen_sp_restore (stack_pointer_rtx,
3763 hard_frame_pointer_rtx));
3764 RTX_FRAME_RELATED_P (insn) = 1;
3765 REG_NOTES (insn) = cfa_restores;
3766 add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx);
3768 else
3770 insn = emit_sp_adjust (total_size, &next_scratch_regno, true,
3771 cfa_restores);
3774 if (crtl->calls_eh_return)
3775 emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
3776 EH_RETURN_STACKADJ_RTX));
3778 /* Restore the old frame pointer. */
3779 if (frame_pointer_needed)
3781 insn = emit_move_insn (hard_frame_pointer_rtx,
3782 gen_rtx_REG (Pmode, fp_copy_regno));
3783 add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);
3786 /* Mark the pic registers as live outside of the function. */
3787 if (flag_pic)
3789 emit_use (cfun->machine->text_label_rtx);
3790 emit_use (cfun->machine->got_rtx);
3793 done:
3794 if (!sibcall_p)
3796 /* Emit the actual 'return' instruction. */
3797 emit_jump_insn (gen__return ());
3799 else
3801 emit_use (gen_rtx_REG (Pmode, TILEPRO_LINK_REGNUM));
3804 /* Mark all insns we just emitted as frame-related. */
3805 for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn))
3806 RTX_FRAME_RELATED_P (last_insn) = 1;
3809 #undef ROUND_ROBIN_SIZE
3812 /* Implement INITIAL_ELIMINATION_OFFSET. */
3814 tilepro_initial_elimination_offset (int from, int to)
3816 int total_size = compute_total_frame_size ();
3818 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
3820 return (total_size - crtl->args.pretend_args_size
3821 - tilepro_saved_regs_size ());
3823 else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
3825 return -(crtl->args.pretend_args_size + tilepro_saved_regs_size ());
3827 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
3829 return STACK_POINTER_OFFSET + total_size;
3831 else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
3833 return STACK_POINTER_OFFSET;
3835 else
3836 gcc_unreachable ();
3840 /* Return an RTX indicating where the return address to the
3841 calling function can be found. */
3843 tilepro_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3845 if (count != 0)
3846 return const0_rtx;
3848 return get_hard_reg_initial_val (Pmode, TILEPRO_LINK_REGNUM);
3852 /* Implement EH_RETURN_HANDLER_RTX. */
3854 tilepro_eh_return_handler_rtx (void)
3856 /* The MEM needs to be volatile to prevent it from being
3857 deleted. */
3858 rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
3859 MEM_VOLATILE_P (tmp) = true;
3860 return tmp;
3865 /* Registers */
3867 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
3868 static void
3869 tilepro_conditional_register_usage (void)
3871 global_regs[TILEPRO_NETORDER_REGNUM] = 1;
3872 /* TILEPRO_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
3873 member of fixed_regs, and therefore must be member of
3874 call_used_regs, but it is not a member of call_really_used_regs[]
3875 because it is not clobbered by a call. */
3876 if (TILEPRO_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM)
3878 fixed_regs[TILEPRO_PIC_TEXT_LABEL_REGNUM] = 1;
3879 call_used_regs[TILEPRO_PIC_TEXT_LABEL_REGNUM] = 1;
3881 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
3883 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
3884 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
3889 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3890 static bool
3891 tilepro_frame_pointer_required (void)
3893 return crtl->calls_eh_return || cfun->calls_alloca;
3898 /* Scheduling and reorg */
3900 /* Return the length of INSN. LENGTH is the initial length computed
3901 by attributes in the machine-description file. This is where we
3902 account for bundles. */
3904 tilepro_adjust_insn_length (rtx_insn *insn, int length)
3906 machine_mode mode = GET_MODE (insn);
3908 /* A non-termininating instruction in a bundle has length 0. */
3909 if (mode == SImode)
3910 return 0;
3912 /* By default, there is not length adjustment. */
3913 return length;
3917 /* Implement TARGET_SCHED_ISSUE_RATE. */
3918 static int
3919 tilepro_issue_rate (void)
3921 return 3;
3925 /* Return the rtx for the jump target. */
3926 static rtx
3927 get_jump_target (rtx branch)
3929 if (CALL_P (branch))
3931 rtx call;
3932 call = PATTERN (branch);
3934 if (GET_CODE (call) == PARALLEL)
3935 call = XVECEXP (call, 0, 0);
3937 if (GET_CODE (call) == SET)
3938 call = SET_SRC (call);
3940 if (GET_CODE (call) == CALL)
3941 return XEXP (XEXP (call, 0), 0);
3943 return 0;
3946 /* Implement TARGET_SCHED_ADJUST_COST. */
3947 static int
3948 tilepro_sched_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn,
3949 int cost, unsigned int)
3951 /* If we have a true dependence, INSN is a call, and DEP_INSN
3952 defines a register that is needed by the call (argument or stack
3953 pointer), set its latency to 0 so that it can be bundled with
3954 the call. Explicitly check for and exclude the case when
3955 DEP_INSN defines the target of the jump. */
3956 if (CALL_P (insn) && dep_type == REG_DEP_TRUE)
3958 rtx target = get_jump_target (insn);
3959 if (!REG_P (target) || !set_of (target, dep_insn))
3960 return 0;
3963 return cost;
3967 /* Skip over irrelevant NOTEs and such and look for the next insn we
3968 would consider bundling. */
3969 static rtx_insn *
3970 next_insn_to_bundle (rtx_insn *r, rtx_insn *end)
3972 for (; r != end; r = NEXT_INSN (r))
3974 if (NONDEBUG_INSN_P (r)
3975 && GET_CODE (PATTERN (r)) != USE
3976 && GET_CODE (PATTERN (r)) != CLOBBER)
3977 return r;
3980 return NULL;
3984 /* Go through all insns, and use the information generated during
3985 scheduling to generate SEQUENCEs to represent bundles of
3986 instructions issued simultaneously. */
3987 static void
3988 tilepro_gen_bundles (void)
3990 basic_block bb;
3991 FOR_EACH_BB_FN (bb, cfun)
3993 rtx_insn *insn, *next;
3994 rtx_insn *end = NEXT_INSN (BB_END (bb));
3996 for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn; insn = next)
3998 next = next_insn_to_bundle (NEXT_INSN (insn), end);
4000 /* Never wrap {} around inline asm. */
4001 if (GET_CODE (PATTERN (insn)) != ASM_INPUT)
4003 if (next == NULL_RTX || GET_MODE (next) == TImode
4004 /* NOTE: The scheduler incorrectly believes a call
4005 insn can execute in the same cycle as the insn
4006 after the call. This is of course impossible.
4007 Really we need to fix the scheduler somehow, so
4008 the code after the call gets scheduled
4009 optimally. */
4010 || CALL_P (insn))
4012 /* Mark current insn as the end of a bundle. */
4013 PUT_MODE (insn, QImode);
4015 else
4017 /* Mark it as part of a bundle. */
4018 PUT_MODE (insn, SImode);
4026 /* Helper function for tilepro_fixup_pcrel_references. */
4027 static void
4028 replace_pc_relative_symbol_ref (rtx_insn *insn, rtx opnds[4], bool first_insn_p)
4030 rtx_insn *new_insns;
4032 start_sequence ();
4034 if (flag_pic == 1)
4036 if (!first_insn_p)
4038 emit_insn (gen_add_got16 (opnds[0], tilepro_got_rtx (),
4039 opnds[2]));
4040 emit_insn (gen_insn_lw (opnds[0], opnds[0]));
4043 else
4045 if (first_insn_p)
4047 emit_insn (gen_addhi_got32 (opnds[0], tilepro_got_rtx (),
4048 opnds[2]));
4050 else
4052 emit_insn (gen_addlo_got32 (opnds[0], opnds[1], opnds[2]));
4053 emit_insn (gen_insn_lw (opnds[0], opnds[0]));
4057 new_insns = get_insns ();
4058 end_sequence ();
4060 if (new_insns)
4061 emit_insn_before (new_insns, insn);
4063 delete_insn (insn);
4067 /* Returns whether INSN is a pc-relative addli insn. */
4068 static bool
4069 match_addli_pcrel (rtx_insn *insn)
4071 rtx pattern = PATTERN (insn);
4072 rtx unspec;
4074 if (GET_CODE (pattern) != SET)
4075 return false;
4077 if (GET_CODE (SET_SRC (pattern)) != LO_SUM)
4078 return false;
4080 if (GET_CODE (XEXP (SET_SRC (pattern), 1)) != CONST)
4081 return false;
4083 unspec = XEXP (XEXP (SET_SRC (pattern), 1), 0);
4085 return (GET_CODE (unspec) == UNSPEC
4086 && XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4090 /* Helper function for tilepro_fixup_pcrel_references. */
4091 static void
4092 replace_addli_pcrel (rtx_insn *insn)
4094 rtx pattern = PATTERN (insn);
4095 rtx set_src;
4096 rtx unspec;
4097 rtx opnds[4];
4098 bool first_insn_p;
4100 gcc_assert (GET_CODE (pattern) == SET);
4101 opnds[0] = SET_DEST (pattern);
4103 set_src = SET_SRC (pattern);
4104 gcc_assert (GET_CODE (set_src) == LO_SUM);
4105 gcc_assert (GET_CODE (XEXP (set_src, 1)) == CONST);
4106 opnds[1] = XEXP (set_src, 0);
4108 unspec = XEXP (XEXP (set_src, 1), 0);
4109 gcc_assert (GET_CODE (unspec) == UNSPEC);
4110 gcc_assert (XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4111 opnds[2] = XVECEXP (unspec, 0, 0);
4112 opnds[3] = XVECEXP (unspec, 0, 1);
4114 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4115 if (GET_CODE (opnds[2]) != SYMBOL_REF)
4116 return;
4118 first_insn_p = (opnds[1] == tilepro_text_label_rtx ());
4120 replace_pc_relative_symbol_ref (insn, opnds, first_insn_p);
4124 /* Returns whether INSN is a pc-relative auli insn. */
4125 static bool
4126 match_auli_pcrel (rtx_insn *insn)
4128 rtx pattern = PATTERN (insn);
4129 rtx high;
4130 rtx unspec;
4132 if (GET_CODE (pattern) != SET)
4133 return false;
4135 if (GET_CODE (SET_SRC (pattern)) != PLUS)
4136 return false;
4138 high = XEXP (SET_SRC (pattern), 1);
4140 if (GET_CODE (high) != HIGH
4141 || GET_CODE (XEXP (high, 0)) != CONST)
4142 return false;
4144 unspec = XEXP (XEXP (high, 0), 0);
4146 return (GET_CODE (unspec) == UNSPEC
4147 && XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4151 /* Helper function for tilepro_fixup_pcrel_references. */
4152 static void
4153 replace_auli_pcrel (rtx_insn *insn)
4155 rtx pattern = PATTERN (insn);
4156 rtx set_src;
4157 rtx high;
4158 rtx unspec;
4159 rtx opnds[4];
4160 bool first_insn_p;
4162 gcc_assert (GET_CODE (pattern) == SET);
4163 opnds[0] = SET_DEST (pattern);
4165 set_src = SET_SRC (pattern);
4166 gcc_assert (GET_CODE (set_src) == PLUS);
4167 opnds[1] = XEXP (set_src, 0);
4169 high = XEXP (set_src, 1);
4170 gcc_assert (GET_CODE (high) == HIGH);
4171 gcc_assert (GET_CODE (XEXP (high, 0)) == CONST);
4173 unspec = XEXP (XEXP (high, 0), 0);
4174 gcc_assert (GET_CODE (unspec) == UNSPEC);
4175 gcc_assert (XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4176 opnds[2] = XVECEXP (unspec, 0, 0);
4177 opnds[3] = XVECEXP (unspec, 0, 1);
4179 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4180 if (GET_CODE (opnds[2]) != SYMBOL_REF)
4181 return;
4183 first_insn_p = (opnds[1] == tilepro_text_label_rtx ());
4185 replace_pc_relative_symbol_ref (insn, opnds, first_insn_p);
4189 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4190 going through the GOT when the symbol is local to the compilation
4191 unit. But such a symbol requires that the common text_label that
4192 we generate at the beginning of the function be in the same section
4193 as the reference to the SYMBOL_REF. This may not be true if we
4194 generate hot/cold sections. This function looks for such cases and
4195 replaces such references with the longer sequence going through the
4196 GOT.
4198 We expect one of the following two instruction sequences:
4199 addli tmp1, txt_label_reg, lo16(sym - txt_label)
4200 auli tmp2, tmp1, ha16(sym - txt_label)
4202 auli tmp1, txt_label_reg, ha16(sym - txt_label)
4203 addli tmp2, tmp1, lo16(sym - txt_label)
4205 If we're compiling -fpic, we replace the first instruction with
4206 nothing, and the second instruction with:
4208 addli tmp2, got_rtx, got(sym)
4209 lw tmp2, tmp2
4211 If we're compiling -fPIC, we replace the first instruction with:
4213 auli tmp1, got_rtx, got_ha16(sym)
4215 and the second instruction with:
4217 addli tmp2, tmp1, got_lo16(sym)
4218 lw tmp2, tmp2
4220 Note that we're careful to disturb the instruction sequence as
4221 little as possible, since it's very late in the compilation
4222 process.
4224 static void
4225 tilepro_fixup_pcrel_references (void)
4227 rtx_insn *insn, *next_insn;
4228 bool same_section_as_entry = true;
4230 for (insn = get_insns (); insn; insn = next_insn)
4232 next_insn = NEXT_INSN (insn);
4234 if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
4236 same_section_as_entry = !same_section_as_entry;
4237 continue;
4240 if (same_section_as_entry)
4241 continue;
4243 if (!(INSN_P (insn)
4244 && GET_CODE (PATTERN (insn)) != USE
4245 && GET_CODE (PATTERN (insn)) != CLOBBER))
4246 continue;
4248 if (match_addli_pcrel (insn))
4249 replace_addli_pcrel (insn);
4250 else if (match_auli_pcrel (insn))
4251 replace_auli_pcrel (insn);
4256 /* Ensure that no var tracking notes are emitted in the middle of a
4257 three-instruction bundle. */
4258 static void
4259 reorder_var_tracking_notes (void)
4261 basic_block bb;
4262 FOR_EACH_BB_FN (bb, cfun)
4264 rtx_insn *insn, *next;
4265 rtx_insn *queue = NULL;
4266 bool in_bundle = false;
4268 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4270 next = NEXT_INSN (insn);
4272 if (INSN_P (insn))
4274 /* Emit queued up notes at the last instruction of a bundle. */
4275 if (GET_MODE (insn) == QImode)
4277 while (queue)
4279 rtx_insn *next_queue = PREV_INSN (queue);
4280 SET_PREV_INSN (NEXT_INSN (insn)) = queue;
4281 SET_NEXT_INSN (queue) = NEXT_INSN (insn);
4282 SET_NEXT_INSN (insn) = queue;
4283 SET_PREV_INSN (queue) = insn;
4284 queue = next_queue;
4286 in_bundle = false;
4288 else if (GET_MODE (insn) == SImode)
4289 in_bundle = true;
4291 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4293 if (in_bundle)
4295 rtx_insn *prev = PREV_INSN (insn);
4296 SET_PREV_INSN (next) = prev;
4297 SET_NEXT_INSN (prev) = next;
4299 SET_PREV_INSN (insn) = queue;
4300 queue = insn;
4308 /* Perform machine dependent operations on the rtl chain INSNS. */
4309 static void
4310 tilepro_reorg (void)
4312 /* We are freeing block_for_insn in the toplev to keep compatibility
4313 with old MDEP_REORGS that are not CFG based. Recompute it
4314 now. */
4315 compute_bb_for_insn ();
4317 if (flag_reorder_blocks_and_partition)
4319 tilepro_fixup_pcrel_references ();
4322 if (flag_schedule_insns_after_reload)
4324 split_all_insns ();
4326 timevar_push (TV_SCHED2);
4327 schedule_insns ();
4328 timevar_pop (TV_SCHED2);
4330 /* Examine the schedule to group into bundles. */
4331 tilepro_gen_bundles ();
4334 df_analyze ();
4336 if (flag_var_tracking)
4338 timevar_push (TV_VAR_TRACKING);
4339 variable_tracking_main ();
4340 reorder_var_tracking_notes ();
4341 timevar_pop (TV_VAR_TRACKING);
4344 df_finish_pass (false);
4349 /* Assembly */
4351 /* Select a format to encode pointers in exception handling data.
4352 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4353 GLOBAL is true if the symbol may be affected by dynamic
4354 relocations. */
4356 tilepro_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
4358 return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4;
4362 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4363 static void
4364 tilepro_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
4365 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
4366 tree function)
4368 rtx this_rtx, funexp;
4369 rtx_insn *insn;
4371 /* Pretend to be a post-reload pass while generating rtl. */
4372 reload_completed = 1;
4374 /* Mark the end of the (empty) prologue. */
4375 emit_note (NOTE_INSN_PROLOGUE_END);
4377 /* Find the "this" pointer. If the function returns a structure,
4378 the structure return pointer is in $1. */
4379 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
4380 this_rtx = gen_rtx_REG (Pmode, 1);
4381 else
4382 this_rtx = gen_rtx_REG (Pmode, 0);
4384 /* Add DELTA to THIS_RTX. */
4385 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
4387 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4388 if (vcall_offset)
4390 rtx tmp;
4392 tmp = gen_rtx_REG (Pmode, 29);
4393 emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx));
4395 emit_insn (gen_addsi3 (tmp, tmp, GEN_INT (vcall_offset)));
4397 emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
4399 emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp));
4402 /* Generate a tail call to the target function. */
4403 if (!TREE_USED (function))
4405 assemble_external (function);
4406 TREE_USED (function) = 1;
4408 funexp = XEXP (DECL_RTL (function), 0);
4409 funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
4410 insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
4411 SIBLING_CALL_P (insn) = 1;
4413 /* Run just enough of rest_of_compilation to get the insns emitted.
4414 There's not really enough bulk here to make other passes such as
4415 instruction scheduling worth while. Note that use_thunk calls
4416 assemble_start_function and assemble_end_function.
4418 We don't currently bundle, but the instruciton sequence is all
4419 serial except for the tail call, so we're only wasting one cycle.
4421 insn = get_insns ();
4422 shorten_branches (insn);
4423 final_start_function (insn, file, 1);
4424 final (insn, file, 1);
4425 final_end_function ();
4427 /* Stop pretending to be a post-reload pass. */
4428 reload_completed = 0;
4432 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
4433 static void
4434 tilepro_asm_trampoline_template (FILE *file)
4436 fprintf (file, "\tlnk r10\n");
4437 fprintf (file, "\taddi r10, r10, 32\n");
4438 fprintf (file, "\tlwadd r11, r10, %d\n", GET_MODE_SIZE (ptr_mode));
4439 fprintf (file, "\tlw r10, r10\n");
4440 fprintf (file, "\tjr r11\n");
4441 fprintf (file, "\t.word 0 # <function address>\n");
4442 fprintf (file, "\t.word 0 # <static chain value>\n");
4446 /* Implement TARGET_TRAMPOLINE_INIT. */
4447 static void
4448 tilepro_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
4450 rtx fnaddr, chaddr;
4451 rtx mem;
4452 rtx begin_addr, end_addr;
4453 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4455 fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
4456 chaddr = copy_to_reg (static_chain);
4458 emit_block_move (m_tramp, assemble_trampoline_template (),
4459 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
4461 mem = adjust_address (m_tramp, ptr_mode,
4462 TRAMPOLINE_SIZE - 2 * ptr_mode_size);
4463 emit_move_insn (mem, fnaddr);
4464 mem = adjust_address (m_tramp, ptr_mode,
4465 TRAMPOLINE_SIZE - ptr_mode_size);
4466 emit_move_insn (mem, chaddr);
4468 /* Get pointers to the beginning and end of the code block. */
4469 begin_addr = force_reg (Pmode, XEXP (m_tramp, 0));
4470 end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0),
4471 TRAMPOLINE_SIZE));
4473 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
4474 LCT_NORMAL, VOIDmode, 2, begin_addr, Pmode,
4475 end_addr, Pmode);
4479 /* Implement TARGET_PRINT_OPERAND. */
4480 static void
4481 tilepro_print_operand (FILE *file, rtx x, int code)
4483 switch (code)
4485 case 'c':
4486 /* Print the compare operator opcode for conditional moves. */
4487 switch (GET_CODE (x))
4489 case EQ:
4490 fputs ("z", file);
4491 break;
4492 case NE:
4493 fputs ("nz", file);
4494 break;
4495 default:
4496 output_operand_lossage ("invalid %%c operand");
4498 return;
4500 case 'C':
4501 /* Print the compare operator opcode for conditional moves. */
4502 switch (GET_CODE (x))
4504 case EQ:
4505 fputs ("nz", file);
4506 break;
4507 case NE:
4508 fputs ("z", file);
4509 break;
4510 default:
4511 output_operand_lossage ("invalid %%C operand");
4513 return;
4515 case 'h':
4517 /* Print the high 16 bits of a 32-bit constant. */
4518 HOST_WIDE_INT i;
4519 if (CONST_INT_P (x))
4520 i = INTVAL (x);
4521 else if (GET_CODE (x) == CONST_DOUBLE)
4522 i = CONST_DOUBLE_LOW (x);
4523 else
4525 output_operand_lossage ("invalid %%h operand");
4526 return;
4528 i = trunc_int_for_mode (i >> 16, HImode);
4529 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4530 return;
4533 case 'H':
4535 rtx addr = NULL;
4536 const char *opstr = NULL;
4537 bool pcrel = false;
4538 if (GET_CODE (x) == CONST
4539 && GET_CODE (XEXP (x, 0)) == UNSPEC)
4541 addr = XVECEXP (XEXP (x, 0), 0, 0);
4542 switch (XINT (XEXP (x, 0), 1))
4544 case UNSPEC_GOT32_SYM:
4545 opstr = "got_ha16";
4546 break;
4547 case UNSPEC_PCREL_SYM:
4548 opstr = "ha16";
4549 pcrel = true;
4550 break;
4551 case UNSPEC_TLS_GD:
4552 opstr = "tls_gd_ha16";
4553 break;
4554 case UNSPEC_TLS_IE:
4555 opstr = "tls_ie_ha16";
4556 break;
4557 case UNSPEC_TLS_LE:
4558 opstr = "tls_le_ha16";
4559 break;
4560 default:
4561 output_operand_lossage ("invalid %%H operand");
4564 else
4566 addr = x;
4567 opstr = "ha16";
4570 fputs (opstr, file);
4571 fputc ('(', file);
4572 output_addr_const (file, addr);
4574 if (pcrel)
4576 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
4577 fputs (" - " , file);
4578 output_addr_const (file, addr2);
4581 fputc (')', file);
4582 return;
4585 case 'I':
4586 /* Print an auto-inc memory operand. */
4587 if (!MEM_P (x))
4589 output_operand_lossage ("invalid %%I operand");
4590 return;
4593 output_memory_autoinc_first = true;
4594 output_address (GET_MODE (x), XEXP (x, 0));
4595 return;
4597 case 'i':
4598 /* Print an auto-inc memory operand. */
4599 if (!MEM_P (x))
4601 output_operand_lossage ("invalid %%i operand");
4602 return;
4605 output_memory_autoinc_first = false;
4606 output_address (GET_MODE (x), XEXP (x, 0));
4607 return;
4609 case 'j':
4611 /* Print the low 8 bits of a constant. */
4612 HOST_WIDE_INT i;
4613 if (CONST_INT_P (x))
4614 i = INTVAL (x);
4615 else if (GET_CODE (x) == CONST_DOUBLE)
4616 i = CONST_DOUBLE_LOW (x);
4617 else if (GET_CODE (x) == CONST_VECTOR
4618 && CONST_INT_P (CONST_VECTOR_ELT (x, 0)))
4619 i = INTVAL (CONST_VECTOR_ELT (x, 0));
4620 else
4622 output_operand_lossage ("invalid %%j operand");
4623 return;
4625 i = trunc_int_for_mode (i, QImode);
4626 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4627 return;
4630 case 'L':
4632 rtx addr = NULL;
4633 const char *opstr = NULL;
4634 bool pcrel = false;
4635 if (GET_CODE (x) == CONST
4636 && GET_CODE (XEXP (x, 0)) == UNSPEC)
4638 addr = XVECEXP (XEXP (x, 0), 0, 0);
4639 switch (XINT (XEXP (x, 0), 1))
4641 case UNSPEC_GOT16_SYM:
4642 opstr = "got";
4643 break;
4644 case UNSPEC_GOT32_SYM:
4645 opstr = "got_lo16";
4646 break;
4647 case UNSPEC_PCREL_SYM:
4648 opstr = "lo16";
4649 pcrel = true;
4650 break;
4651 case UNSPEC_TLS_GD:
4652 opstr = "tls_gd_lo16";
4653 break;
4654 case UNSPEC_TLS_IE:
4655 opstr = "tls_ie_lo16";
4656 break;
4657 case UNSPEC_TLS_LE:
4658 opstr = "tls_le_lo16";
4659 break;
4660 default:
4661 output_operand_lossage ("invalid %%L operand");
4664 else
4666 addr = x;
4667 opstr = "lo16";
4670 fputs (opstr, file);
4671 fputc ('(', file);
4672 output_addr_const (file, addr);
4674 if (pcrel)
4676 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
4677 fputs (" - " , file);
4678 output_addr_const (file, addr2);
4681 fputc (')', file);
4682 return;
4685 case 'p':
4686 if (GET_CODE (x) == SYMBOL_REF)
4688 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
4689 fprintf (file, "plt(");
4690 output_addr_const (file, x);
4691 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
4692 fprintf (file, ")");
4694 else
4695 output_addr_const (file, x);
4696 return;
4698 case 'P':
4700 /* Print a 32-bit constant plus one. */
4701 HOST_WIDE_INT i;
4702 if (!CONST_INT_P (x))
4704 output_operand_lossage ("invalid %%P operand");
4705 return;
4707 i = trunc_int_for_mode (INTVAL (x) + 1, SImode);
4708 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4709 return;
4712 case 'M':
4714 /* Print an mm-style bit range. */
4715 int first_bit, last_bit;
4717 if (!CONST_INT_P (x)
4718 || !tilepro_bitfield_operand_p (INTVAL (x), &first_bit,
4719 &last_bit))
4721 output_operand_lossage ("invalid %%M operand");
4722 return;
4725 fprintf (file, "%d, %d", first_bit, last_bit);
4726 return;
4729 case 'N':
4731 const char *reg = NULL;
4733 /* Print a network register. */
4734 if (!CONST_INT_P (x))
4736 output_operand_lossage ("invalid %%N operand");
4737 return;
4740 switch (INTVAL (x))
4742 case TILEPRO_NETREG_IDN0: reg = "idn0"; break;
4743 case TILEPRO_NETREG_IDN1: reg = "idn1"; break;
4744 case TILEPRO_NETREG_SN: reg = "sn"; break;
4745 case TILEPRO_NETREG_UDN0: reg = "udn0"; break;
4746 case TILEPRO_NETREG_UDN1: reg = "udn1"; break;
4747 case TILEPRO_NETREG_UDN2: reg = "udn2"; break;
4748 case TILEPRO_NETREG_UDN3: reg = "udn3"; break;
4749 default: gcc_unreachable ();
4752 fprintf (file, reg);
4753 return;
4756 case 't':
4758 /* Log base 2 of a power of two. */
4759 HOST_WIDE_INT i;
4760 HOST_WIDE_INT n;
4762 if (!CONST_INT_P (x))
4764 output_operand_lossage ("invalid %%t operand");
4765 return;
4767 n = trunc_int_for_mode (INTVAL (x), SImode);
4768 i = exact_log2 (n);
4769 if (i < 0)
4771 output_operand_lossage ("invalid %%t operand '"
4772 HOST_WIDE_INT_PRINT_DEC "'", n);
4773 return;
4776 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4777 return;
4779 break;
4781 case 'r':
4782 /* In this case we need a register. Use 'zero' if the
4783 operand is const0_rtx. */
4784 if (x == const0_rtx
4785 || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
4787 fputs ("zero", file);
4788 return;
4790 else if (!REG_P (x))
4792 output_operand_lossage ("invalid %%r operand");
4793 return;
4795 /* FALLTHRU */
4797 case 0:
4798 if (REG_P (x))
4800 fprintf (file, "%s", reg_names[REGNO (x)]);
4801 return;
4803 else if (MEM_P (x))
4805 output_address (VOIDmode, XEXP (x, 0));
4806 return;
4808 else
4810 output_addr_const (file, x);
4811 return;
4813 break;
4816 debug_rtx (x);
4817 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
4818 code, code);
4822 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
4823 static void
4824 tilepro_print_operand_address (FILE *file, machine_mode mode, rtx addr)
4826 if (GET_CODE (addr) == POST_DEC
4827 || GET_CODE (addr) == POST_INC)
4829 int offset = GET_MODE_SIZE (mode);
4831 gcc_assert (mode != VOIDmode);
4833 if (output_memory_autoinc_first)
4834 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
4835 else
4836 fprintf (file, "%d",
4837 GET_CODE (addr) == POST_DEC ? -offset : offset);
4839 else if (GET_CODE (addr) == POST_MODIFY)
4841 gcc_assert (mode != VOIDmode);
4843 gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
4845 if (output_memory_autoinc_first)
4846 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
4847 else
4848 fprintf (file, HOST_WIDE_INT_PRINT_DEC,
4849 INTVAL (XEXP (XEXP (addr, 1), 1)));
4851 else
4852 tilepro_print_operand (file, addr, 'r');
4856 /* Machine mode of current insn, for determining curly brace
4857 placement. */
4858 static machine_mode insn_mode;
4861 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
4862 void
4863 tilepro_final_prescan_insn (rtx_insn *insn)
4865 /* Record this for tilepro_asm_output_opcode to examine. */
4866 insn_mode = GET_MODE (insn);
4870 /* While emitting asm, are we currently inside '{' for a bundle? */
4871 static bool tilepro_in_bundle = false;
4873 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
4874 appropriate given the bundling information recorded by
4875 tilepro_gen_bundles. */
4876 const char *
4877 tilepro_asm_output_opcode (FILE *stream, const char *code)
4879 bool pseudo = !strcmp (code, "pseudo");
4881 if (!tilepro_in_bundle && insn_mode == SImode)
4883 /* Start a new bundle. */
4884 fprintf (stream, "{\n\t");
4885 tilepro_in_bundle = true;
4888 if (tilepro_in_bundle && insn_mode == QImode)
4890 /* Close an existing bundle. */
4891 static char buf[100];
4893 gcc_assert (strlen (code) + 3 + 1 < sizeof (buf));
4895 strcpy (buf, pseudo ? "" : code);
4896 strcat (buf, "\n\t}");
4897 tilepro_in_bundle = false;
4899 return buf;
4901 else
4903 return pseudo ? "" : code;
4908 /* Output assembler code to FILE to increment profiler label # LABELNO
4909 for profiling a function entry. */
4910 void
4911 tilepro_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
4913 if (tilepro_in_bundle)
4915 fprintf (file, "\t}\n");
4918 if (flag_pic)
4920 fprintf (file,
4921 "\t{\n"
4922 "\tmove\tr10, lr\n"
4923 "\tjal\tplt(%s)\n"
4924 "\t}\n", MCOUNT_NAME);
4926 else
4928 fprintf (file,
4929 "\t{\n"
4930 "\tmove\tr10, lr\n"
4931 "\tjal\t%s\n"
4932 "\t}\n", MCOUNT_NAME);
4935 tilepro_in_bundle = false;
4939 /* Implement TARGET_ASM_FILE_END. */
4940 static void
4941 tilepro_file_end (void)
4943 if (NEED_INDICATE_EXEC_STACK)
4944 file_end_indicate_exec_stack ();
4948 #undef TARGET_HAVE_TLS
4949 #define TARGET_HAVE_TLS HAVE_AS_TLS
4951 #undef TARGET_OPTION_OVERRIDE
4952 #define TARGET_OPTION_OVERRIDE tilepro_option_override
4954 #ifdef TARGET_THREAD_SSP_OFFSET
4955 #undef TARGET_STACK_PROTECT_GUARD
4956 #define TARGET_STACK_PROTECT_GUARD hook_tree_void_null
4957 #endif
4959 #undef TARGET_SCALAR_MODE_SUPPORTED_P
4960 #define TARGET_SCALAR_MODE_SUPPORTED_P tilepro_scalar_mode_supported_p
4962 #undef TARGET_VECTOR_MODE_SUPPORTED_P
4963 #define TARGET_VECTOR_MODE_SUPPORTED_P tile_vector_mode_supported_p
4965 #undef TARGET_CANNOT_FORCE_CONST_MEM
4966 #define TARGET_CANNOT_FORCE_CONST_MEM tilepro_cannot_force_const_mem
4968 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
4969 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilepro_function_ok_for_sibcall
4971 #undef TARGET_PASS_BY_REFERENCE
4972 #define TARGET_PASS_BY_REFERENCE tilepro_pass_by_reference
4974 #undef TARGET_RETURN_IN_MEMORY
4975 #define TARGET_RETURN_IN_MEMORY tilepro_return_in_memory
4977 #undef TARGET_FUNCTION_ARG_BOUNDARY
4978 #define TARGET_FUNCTION_ARG_BOUNDARY tilepro_function_arg_boundary
4980 #undef TARGET_FUNCTION_ARG
4981 #define TARGET_FUNCTION_ARG tilepro_function_arg
4983 #undef TARGET_FUNCTION_ARG_ADVANCE
4984 #define TARGET_FUNCTION_ARG_ADVANCE tilepro_function_arg_advance
4986 #undef TARGET_FUNCTION_VALUE
4987 #define TARGET_FUNCTION_VALUE tilepro_function_value
4989 #undef TARGET_LIBCALL_VALUE
4990 #define TARGET_LIBCALL_VALUE tilepro_libcall_value
4992 #undef TARGET_FUNCTION_VALUE_REGNO_P
4993 #define TARGET_FUNCTION_VALUE_REGNO_P tilepro_function_value_regno_p
4995 #undef TARGET_PROMOTE_FUNCTION_MODE
4996 #define TARGET_PROMOTE_FUNCTION_MODE \
4997 default_promote_function_mode_always_promote
4999 #undef TARGET_PROMOTE_PROTOTYPES
5000 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5002 #undef TARGET_BUILD_BUILTIN_VA_LIST
5003 #define TARGET_BUILD_BUILTIN_VA_LIST tilepro_build_builtin_va_list
5005 #undef TARGET_EXPAND_BUILTIN_VA_START
5006 #define TARGET_EXPAND_BUILTIN_VA_START tilepro_va_start
5008 #undef TARGET_SETUP_INCOMING_VARARGS
5009 #define TARGET_SETUP_INCOMING_VARARGS tilepro_setup_incoming_varargs
5011 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5012 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilepro_gimplify_va_arg_expr
5014 #undef TARGET_RTX_COSTS
5015 #define TARGET_RTX_COSTS tilepro_rtx_costs
5017 /* Limit to what we can reach in one addli. */
5018 #undef TARGET_MIN_ANCHOR_OFFSET
5019 #define TARGET_MIN_ANCHOR_OFFSET -32768
5020 #undef TARGET_MAX_ANCHOR_OFFSET
5021 #define TARGET_MAX_ANCHOR_OFFSET 32767
5023 #undef TARGET_LEGITIMATE_CONSTANT_P
5024 #define TARGET_LEGITIMATE_CONSTANT_P tilepro_legitimate_constant_p
5026 #undef TARGET_LRA_P
5027 #define TARGET_LRA_P hook_bool_void_false
5029 #undef TARGET_LEGITIMATE_ADDRESS_P
5030 #define TARGET_LEGITIMATE_ADDRESS_P tilepro_legitimate_address_p
5032 #undef TARGET_LEGITIMIZE_ADDRESS
5033 #define TARGET_LEGITIMIZE_ADDRESS tilepro_legitimize_address
5035 #undef TARGET_DELEGITIMIZE_ADDRESS
5036 #define TARGET_DELEGITIMIZE_ADDRESS tilepro_delegitimize_address
5038 #undef TARGET_INIT_BUILTINS
5039 #define TARGET_INIT_BUILTINS tilepro_init_builtins
5041 #undef TARGET_BUILTIN_DECL
5042 #define TARGET_BUILTIN_DECL tilepro_builtin_decl
5044 #undef TARGET_EXPAND_BUILTIN
5045 #define TARGET_EXPAND_BUILTIN tilepro_expand_builtin
5047 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5048 #define TARGET_CONDITIONAL_REGISTER_USAGE tilepro_conditional_register_usage
5050 #undef TARGET_FRAME_POINTER_REQUIRED
5051 #define TARGET_FRAME_POINTER_REQUIRED tilepro_frame_pointer_required
5053 #undef TARGET_DELAY_SCHED2
5054 #define TARGET_DELAY_SCHED2 true
5056 #undef TARGET_DELAY_VARTRACK
5057 #define TARGET_DELAY_VARTRACK true
5059 #undef TARGET_SCHED_ISSUE_RATE
5060 #define TARGET_SCHED_ISSUE_RATE tilepro_issue_rate
5062 #undef TARGET_SCHED_ADJUST_COST
5063 #define TARGET_SCHED_ADJUST_COST tilepro_sched_adjust_cost
5065 #undef TARGET_MACHINE_DEPENDENT_REORG
5066 #define TARGET_MACHINE_DEPENDENT_REORG tilepro_reorg
5068 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5069 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5070 hook_bool_const_tree_hwi_hwi_const_tree_true
5072 #undef TARGET_ASM_OUTPUT_MI_THUNK
5073 #define TARGET_ASM_OUTPUT_MI_THUNK tilepro_asm_output_mi_thunk
5075 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5076 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilepro_asm_trampoline_template
5078 #undef TARGET_TRAMPOLINE_INIT
5079 #define TARGET_TRAMPOLINE_INIT tilepro_trampoline_init
5081 #undef TARGET_PRINT_OPERAND
5082 #define TARGET_PRINT_OPERAND tilepro_print_operand
5084 #undef TARGET_PRINT_OPERAND_ADDRESS
5085 #define TARGET_PRINT_OPERAND_ADDRESS tilepro_print_operand_address
5087 #undef TARGET_ASM_FILE_END
5088 #define TARGET_ASM_FILE_END tilepro_file_end
5090 #undef TARGET_CAN_USE_DOLOOP_P
5091 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
5093 struct gcc_target targetm = TARGET_INITIALIZER;
5095 #include "gt-tilepro.h"