gcc/
[official-gcc.git] / gcc / config / tilepro / tilepro.c
blob81c939552230a212832f2694c75c0f0c8967d44a
1 /* Subroutines used for code generation on the Tilera TILEPro.
2 Copyright (C) 2011-2015 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 "tm.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "insn-config.h"
28 #include "output.h"
29 #include "insn-attr.h"
30 #include "recog.h"
31 #include "hard-reg-set.h"
32 #include "function.h"
33 #include "flags.h"
34 #include "alias.h"
35 #include "symtab.h"
36 #include "tree.h"
37 #include "expmed.h"
38 #include "dojump.h"
39 #include "explow.h"
40 #include "calls.h"
41 #include "emit-rtl.h"
42 #include "varasm.h"
43 #include "stmt.h"
44 #include "expr.h"
45 #include "langhooks.h"
46 #include "insn-codes.h"
47 #include "optabs.h"
48 #include "dominance.h"
49 #include "cfg.h"
50 #include "cfgrtl.h"
51 #include "cfganal.h"
52 #include "lcm.h"
53 #include "cfgbuild.h"
54 #include "cfgcleanup.h"
55 #include "predict.h"
56 #include "basic-block.h"
57 #include "sched-int.h"
58 #include "sel-sched.h"
59 #include "tm_p.h"
60 #include "tm-constrs.h"
61 #include "target.h"
62 #include "dwarf2.h"
63 #include "timevar.h"
64 #include "fold-const.h"
65 #include "tree-ssa-alias.h"
66 #include "internal-fn.h"
67 #include "gimple-fold.h"
68 #include "tree-eh.h"
69 #include "gimple-expr.h"
70 #include "gimple.h"
71 #include "stringpool.h"
72 #include "stor-layout.h"
73 #include "gimplify.h"
74 #include "cfgloop.h"
75 #include "tilepro-builtins.h"
76 #include "tilepro-multiply.h"
77 #include "diagnostic.h"
78 #include "builtins.h"
80 #include "target-def.h"
82 /* SYMBOL_REF for GOT */
83 static GTY(()) rtx g_got_symbol = NULL;
85 /* In case of a POST_INC or POST_DEC memory reference, we must report
86 the mode of the memory reference from TARGET_PRINT_OPERAND to
87 TARGET_PRINT_OPERAND_ADDRESS. */
88 static machine_mode output_memory_reference_mode;
90 /* Report whether we're printing out the first address fragment of a
91 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
92 TARGET_PRINT_OPERAND_ADDRESS. */
93 static bool output_memory_autoinc_first;
97 /* Option handling */
99 /* Implement TARGET_OPTION_OVERRIDE. */
100 static void
101 tilepro_option_override (void)
103 /* When modulo scheduling is enabled, we still rely on regular
104 scheduler for bundling. */
105 if (flag_modulo_sched)
106 flag_resched_modulo_sched = 1;
111 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
112 static bool
113 tilepro_scalar_mode_supported_p (machine_mode mode)
115 switch (mode)
117 case QImode:
118 case HImode:
119 case SImode:
120 case DImode:
121 return true;
123 case SFmode:
124 case DFmode:
125 return true;
127 default:
128 return false;
133 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
134 static bool
135 tile_vector_mode_supported_p (machine_mode mode)
137 return mode == V4QImode || mode == V2HImode;
141 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
142 static bool
143 tilepro_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED,
144 rtx x ATTRIBUTE_UNUSED)
146 return true;
150 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
151 static bool
152 tilepro_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
154 return decl != NULL;
158 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
159 passed by reference. */
160 static bool
161 tilepro_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
162 machine_mode mode ATTRIBUTE_UNUSED,
163 const_tree type, bool named ATTRIBUTE_UNUSED)
165 return (type && TYPE_SIZE (type)
166 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST);
170 /* Implement TARGET_RETURN_IN_MEMORY. */
171 static bool
172 tilepro_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
174 return !IN_RANGE (int_size_in_bytes (type),
175 0, TILEPRO_NUM_RETURN_REGS * UNITS_PER_WORD);
179 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
180 static unsigned int
181 tilepro_function_arg_boundary (machine_mode mode, const_tree type)
183 unsigned int alignment;
185 alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode);
186 if (alignment < PARM_BOUNDARY)
187 alignment = PARM_BOUNDARY;
188 if (alignment > STACK_BOUNDARY)
189 alignment = STACK_BOUNDARY;
190 return alignment;
194 /* Implement TARGET_FUNCTION_ARG. */
195 static rtx
196 tilepro_function_arg (cumulative_args_t cum_v,
197 machine_mode mode,
198 const_tree type, bool named ATTRIBUTE_UNUSED)
200 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
201 int byte_size = ((mode == BLKmode)
202 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
203 bool doubleword_aligned_p;
205 if (cum >= TILEPRO_NUM_ARG_REGS)
206 return NULL_RTX;
208 /* See whether the argument has doubleword alignment. */
209 doubleword_aligned_p =
210 tilepro_function_arg_boundary (mode, type) > BITS_PER_WORD;
212 if (doubleword_aligned_p)
213 cum += cum & 1;
215 /* The ABI does not allow parameters to be passed partially in reg
216 and partially in stack. */
217 if ((cum + (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
218 > TILEPRO_NUM_ARG_REGS)
219 return NULL_RTX;
221 return gen_rtx_REG (mode, cum);
225 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
226 static void
227 tilepro_function_arg_advance (cumulative_args_t cum_v,
228 machine_mode mode,
229 const_tree type, bool named ATTRIBUTE_UNUSED)
231 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
233 int byte_size = ((mode == BLKmode)
234 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
235 int word_size = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
236 bool doubleword_aligned_p;
238 /* See whether the argument has doubleword alignment. */
239 doubleword_aligned_p =
240 tilepro_function_arg_boundary (mode, type) > BITS_PER_WORD;
242 if (doubleword_aligned_p)
243 *cum += *cum & 1;
245 /* If the current argument does not fit in the pretend_args space,
246 skip over it. */
247 if (*cum < TILEPRO_NUM_ARG_REGS
248 && *cum + word_size > TILEPRO_NUM_ARG_REGS)
249 *cum = TILEPRO_NUM_ARG_REGS;
251 *cum += word_size;
255 /* Implement TARGET_FUNCTION_VALUE. */
256 static rtx
257 tilepro_function_value (const_tree valtype, const_tree fn_decl_or_type,
258 bool outgoing ATTRIBUTE_UNUSED)
260 machine_mode mode;
261 int unsigned_p;
263 mode = TYPE_MODE (valtype);
264 unsigned_p = TYPE_UNSIGNED (valtype);
266 mode = promote_function_mode (valtype, mode, &unsigned_p,
267 fn_decl_or_type, 1);
269 return gen_rtx_REG (mode, 0);
273 /* Implement TARGET_LIBCALL_VALUE. */
274 static rtx
275 tilepro_libcall_value (machine_mode mode,
276 const_rtx fun ATTRIBUTE_UNUSED)
278 return gen_rtx_REG (mode, 0);
282 /* Implement FUNCTION_VALUE_REGNO_P. */
283 static bool
284 tilepro_function_value_regno_p (const unsigned int regno)
286 return regno < TILEPRO_NUM_RETURN_REGS;
290 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
291 static tree
292 tilepro_build_builtin_va_list (void)
294 tree f_args, f_skip, record, type_decl;
295 bool owp;
297 record = lang_hooks.types.make_type (RECORD_TYPE);
299 type_decl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
300 get_identifier ("__va_list_tag"), record);
302 f_args = build_decl (BUILTINS_LOCATION, FIELD_DECL,
303 get_identifier ("__args"), ptr_type_node);
304 f_skip = build_decl (BUILTINS_LOCATION, FIELD_DECL,
305 get_identifier ("__skip"), ptr_type_node);
307 DECL_FIELD_CONTEXT (f_args) = record;
309 DECL_FIELD_CONTEXT (f_skip) = record;
311 TREE_CHAIN (record) = type_decl;
312 TYPE_NAME (record) = type_decl;
313 TYPE_FIELDS (record) = f_args;
314 TREE_CHAIN (f_args) = f_skip;
316 /* We know this is being padded and we want it too. It is an
317 internal type so hide the warnings from the user. */
318 owp = warn_padded;
319 warn_padded = false;
321 layout_type (record);
323 warn_padded = owp;
325 /* The correct type is an array type of one element. */
326 return record;
330 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
331 static void
332 tilepro_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
334 tree f_args, f_skip;
335 tree args, skip, t;
337 f_args = TYPE_FIELDS (TREE_TYPE (valist));
338 f_skip = TREE_CHAIN (f_args);
340 args =
341 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
342 skip =
343 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
345 /* Find the __args area. */
346 t = make_tree (TREE_TYPE (args), virtual_incoming_args_rtx);
347 t = fold_build_pointer_plus_hwi (t,
348 UNITS_PER_WORD *
349 (crtl->args.info - TILEPRO_NUM_ARG_REGS));
351 if (crtl->args.pretend_args_size > 0)
352 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
354 t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t);
355 TREE_SIDE_EFFECTS (t) = 1;
356 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
358 /* Find the __skip area. */
359 t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx);
360 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
361 t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t);
362 TREE_SIDE_EFFECTS (t) = 1;
363 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
367 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
368 static void
369 tilepro_setup_incoming_varargs (cumulative_args_t cum,
370 machine_mode mode,
371 tree type, int *pretend_args, int no_rtl)
373 CUMULATIVE_ARGS local_cum = *get_cumulative_args (cum);
374 int first_reg;
376 /* The caller has advanced CUM up to, but not beyond, the last named
377 argument. Advance a local copy of CUM past the last "real" named
378 argument, to find out how many registers are left over. */
379 targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum),
380 mode, type, true);
381 first_reg = local_cum;
383 if (local_cum < TILEPRO_NUM_ARG_REGS)
385 *pretend_args = UNITS_PER_WORD * (TILEPRO_NUM_ARG_REGS - first_reg);
387 if (!no_rtl)
389 alias_set_type set = get_varargs_alias_set ();
390 rtx tmp =
391 gen_rtx_MEM (BLKmode, plus_constant (Pmode, \
392 virtual_incoming_args_rtx,
393 -STACK_POINTER_OFFSET -
394 UNITS_PER_WORD *
395 (TILEPRO_NUM_ARG_REGS -
396 first_reg)));
397 MEM_NOTRAP_P (tmp) = 1;
398 set_mem_alias_set (tmp, set);
399 move_block_from_reg (first_reg, tmp,
400 TILEPRO_NUM_ARG_REGS - first_reg);
403 else
404 *pretend_args = 0;
408 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
409 the va_list structure VALIST as required to retrieve an argument of
410 type TYPE, and returning that argument.
412 ret = va_arg(VALIST, TYPE);
414 generates code equivalent to:
416 paddedsize = (sizeof(TYPE) + 3) & -4;
417 if ((VALIST.__args + paddedsize > VALIST.__skip)
418 & (VALIST.__args <= VALIST.__skip))
419 addr = VALIST.__skip + STACK_POINTER_OFFSET;
420 else
421 addr = VALIST.__args;
422 VALIST.__args = addr + paddedsize;
423 ret = *(TYPE *)addr; */
424 static tree
425 tilepro_gimplify_va_arg_expr (tree valist, tree type, gimple_seq * pre_p,
426 gimple_seq * post_p ATTRIBUTE_UNUSED)
428 tree f_args, f_skip;
429 tree args, skip;
430 HOST_WIDE_INT size, rsize;
431 tree addr, tmp;
432 bool pass_by_reference_p;
434 f_args = TYPE_FIELDS (va_list_type_node);
435 f_skip = TREE_CHAIN (f_args);
437 args =
438 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
439 skip =
440 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
442 addr = create_tmp_var (ptr_type_node, "va_arg");
444 /* if an object is dynamically sized, a pointer to it is passed
445 instead of the object itself. */
446 pass_by_reference_p = pass_by_reference (NULL, TYPE_MODE (type), type,
447 false);
449 if (pass_by_reference_p)
450 type = build_pointer_type (type);
452 size = int_size_in_bytes (type);
453 rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD;
455 /* If the alignment of the type is greater than the default for a
456 parameter, align to STACK_BOUNDARY. */
457 if (TYPE_ALIGN (type) > PARM_BOUNDARY)
459 /* Assert the only case we generate code for: when
460 stack boundary = 2 * parm boundary. */
461 gcc_assert (STACK_BOUNDARY == PARM_BOUNDARY * 2);
463 tmp = build2 (BIT_AND_EXPR, sizetype,
464 fold_convert (sizetype, unshare_expr (args)),
465 size_int (PARM_BOUNDARY / 8));
466 tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node,
467 unshare_expr (args), tmp);
469 gimplify_assign (unshare_expr (args), tmp, pre_p);
472 /* Build conditional expression to calculate addr. The expression
473 will be gimplified later. */
474 tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize);
475 tmp = build2 (TRUTH_AND_EXPR, boolean_type_node,
476 build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)),
477 build2 (LE_EXPR, boolean_type_node, unshare_expr (args),
478 unshare_expr (skip)));
480 tmp = build3 (COND_EXPR, ptr_type_node, tmp,
481 build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip),
482 size_int (STACK_POINTER_OFFSET)),
483 unshare_expr (args));
485 gimplify_assign (addr, tmp, pre_p);
487 /* Update VALIST.__args. */
488 tmp = fold_build_pointer_plus_hwi (addr, rsize);
489 gimplify_assign (unshare_expr (args), tmp, pre_p);
491 addr = fold_convert (build_pointer_type (type), addr);
493 if (pass_by_reference_p)
494 addr = build_va_arg_indirect_ref (addr);
496 return build_va_arg_indirect_ref (addr);
501 /* Implement TARGET_RTX_COSTS. */
502 static bool
503 tilepro_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
504 bool speed)
506 switch (code)
508 case CONST_INT:
509 /* If this is an 8-bit constant, return zero since it can be
510 used nearly anywhere with no cost. If it is a valid operand
511 for an ADD or AND, likewise return 0 if we know it will be
512 used in that context. Otherwise, return 2 since it might be
513 used there later. All other constants take at least two
514 insns. */
515 if (satisfies_constraint_I (x))
517 *total = 0;
518 return true;
520 else if (outer_code == PLUS && add_operand (x, VOIDmode))
522 /* Slightly penalize large constants even though we can add
523 them in one instruction, because it forces the use of
524 2-wide bundling mode. */
525 *total = 1;
526 return true;
528 else if (move_operand (x, SImode))
530 /* We can materialize in one move. */
531 *total = COSTS_N_INSNS (1);
532 return true;
534 else
536 /* We can materialize in two moves. */
537 *total = COSTS_N_INSNS (2);
538 return true;
541 return false;
543 case CONST:
544 case LABEL_REF:
545 case SYMBOL_REF:
546 *total = COSTS_N_INSNS (2);
547 return true;
549 case CONST_DOUBLE:
550 *total = COSTS_N_INSNS (4);
551 return true;
553 case HIGH:
554 *total = 0;
555 return true;
557 case MEM:
558 /* If outer-code was a sign or zero extension, a cost of
559 COSTS_N_INSNS (1) was already added in, so account for
560 that. */
561 if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND)
562 *total = COSTS_N_INSNS (1);
563 else
564 *total = COSTS_N_INSNS (2);
565 return true;
567 case PLUS:
568 /* Convey that s[123]a are efficient. */
569 if (GET_CODE (XEXP (x, 0)) == MULT
570 && cint_248_operand (XEXP (XEXP (x, 0), 1), VOIDmode))
572 *total = (rtx_cost (XEXP (XEXP (x, 0), 0),
573 (enum rtx_code) outer_code, opno, speed)
574 + rtx_cost (XEXP (x, 1),
575 (enum rtx_code) outer_code, opno, speed)
576 + COSTS_N_INSNS (1));
577 return true;
579 return false;
581 case MULT:
582 *total = COSTS_N_INSNS (2);
583 return false;
585 case SIGN_EXTEND:
586 case ZERO_EXTEND:
587 if (outer_code == MULT)
588 *total = 0;
589 else
590 *total = COSTS_N_INSNS (1);
591 return false;
593 case DIV:
594 case UDIV:
595 case MOD:
596 case UMOD:
597 /* These are handled by software and are very expensive. */
598 *total = COSTS_N_INSNS (100);
599 return false;
601 case UNSPEC:
602 case UNSPEC_VOLATILE:
604 int num = XINT (x, 1);
606 if (num <= TILEPRO_LAST_LATENCY_1_INSN)
607 *total = COSTS_N_INSNS (1);
608 else if (num <= TILEPRO_LAST_LATENCY_2_INSN)
609 *total = COSTS_N_INSNS (2);
610 else if (num > TILEPRO_LAST_LATENCY_INSN)
612 if (outer_code == PLUS)
613 *total = 0;
614 else
615 *total = COSTS_N_INSNS (1);
617 else
619 switch (num)
621 case UNSPEC_BLOCKAGE:
622 case UNSPEC_NETWORK_BARRIER:
623 *total = 0;
624 break;
626 case UNSPEC_LNK_AND_LABEL:
627 case UNSPEC_MF:
628 case UNSPEC_NETWORK_RECEIVE:
629 case UNSPEC_NETWORK_SEND:
630 case UNSPEC_TLS_GD_ADD:
631 *total = COSTS_N_INSNS (1);
632 break;
634 case UNSPEC_TLS_IE_LOAD:
635 *total = COSTS_N_INSNS (2);
636 break;
638 case UNSPEC_SP_SET:
639 *total = COSTS_N_INSNS (3);
640 break;
642 case UNSPEC_SP_TEST:
643 *total = COSTS_N_INSNS (4);
644 break;
646 case UNSPEC_LATENCY_L2:
647 *total = COSTS_N_INSNS (8);
648 break;
650 case UNSPEC_TLS_GD_CALL:
651 *total = COSTS_N_INSNS (30);
652 break;
654 case UNSPEC_LATENCY_MISS:
655 *total = COSTS_N_INSNS (80);
656 break;
658 default:
659 *total = COSTS_N_INSNS (1);
662 return true;
665 default:
666 return false;
672 /* Returns an SImode integer rtx with value VAL. */
673 static rtx
674 gen_int_si (HOST_WIDE_INT val)
676 return gen_int_mode (val, SImode);
680 /* Create a temporary variable to hold a partial result, to enable
681 CSE. */
682 static rtx
683 create_temp_reg_if_possible (machine_mode mode, rtx default_reg)
685 return can_create_pseudo_p ()? gen_reg_rtx (mode) : default_reg;
689 /* Functions to save and restore machine-specific function data. */
690 static struct machine_function *
691 tilepro_init_machine_status (void)
693 return ggc_cleared_alloc<machine_function> ();
697 /* Do anything needed before RTL is emitted for each function. */
698 void
699 tilepro_init_expanders (void)
701 /* Arrange to initialize and mark the machine per-function
702 status. */
703 init_machine_status = tilepro_init_machine_status;
705 if (cfun && cfun->machine && flag_pic)
707 static int label_num = 0;
709 char text_label_name[32];
711 struct machine_function *machine = cfun->machine;
713 ASM_GENERATE_INTERNAL_LABEL (text_label_name, "L_PICLNK", label_num++);
715 machine->text_label_symbol =
716 gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (text_label_name));
718 machine->text_label_rtx =
719 gen_rtx_REG (Pmode, TILEPRO_PIC_TEXT_LABEL_REGNUM);
721 machine->got_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
723 machine->calls_tls_get_addr = false;
728 /* Return true if X contains a thread-local symbol. */
729 static bool
730 tilepro_tls_referenced_p (rtx x)
732 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
733 x = XEXP (XEXP (x, 0), 0);
735 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
736 return true;
738 /* That's all we handle in tilepro_legitimize_tls_address for
739 now. */
740 return false;
744 /* Return true if X requires a scratch register. It is given that
745 flag_pic is on and that X satisfies CONSTANT_P. */
746 static int
747 tilepro_pic_address_needs_scratch (rtx x)
749 if (GET_CODE (x) == CONST
750 && GET_CODE (XEXP (x, 0)) == PLUS
751 && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
752 || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
753 && CONST_INT_P (XEXP (XEXP (x, 0), 1)))
754 return true;
756 return false;
760 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
761 which we are willing to load the value into a register via a move
762 pattern. TLS cannot be treated as a constant because it can
763 include a function call. */
764 static bool
765 tilepro_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
767 switch (GET_CODE (x))
769 case CONST:
770 case SYMBOL_REF:
771 return !tilepro_tls_referenced_p (x);
773 default:
774 return true;
779 /* Return true if the constant value X is a legitimate general operand
780 when generating PIC code. It is given that flag_pic is on and that
781 X satisfies CONSTANT_P. */
782 bool
783 tilepro_legitimate_pic_operand_p (rtx x)
785 if (tilepro_pic_address_needs_scratch (x))
786 return false;
788 if (tilepro_tls_referenced_p (x))
789 return false;
791 return true;
795 /* Return true if the rtx X can be used as an address operand. */
796 static bool
797 tilepro_legitimate_address_p (machine_mode ARG_UNUSED (mode), rtx x,
798 bool strict)
800 if (GET_CODE (x) == SUBREG)
801 x = SUBREG_REG (x);
803 switch (GET_CODE (x))
805 case POST_INC:
806 case POST_DEC:
807 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
808 return false;
810 x = XEXP (x, 0);
811 break;
813 case POST_MODIFY:
814 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
815 return false;
817 if (GET_CODE (XEXP (x, 1)) != PLUS)
818 return false;
820 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
821 return false;
823 if (!satisfies_constraint_I (XEXP (XEXP (x, 1), 1)))
824 return false;
826 x = XEXP (x, 0);
827 break;
829 case REG:
830 break;
832 default:
833 return false;
836 /* Check if x is a valid reg. */
837 if (!REG_P (x))
838 return false;
840 if (strict)
841 return REGNO_OK_FOR_BASE_P (REGNO (x));
842 else
843 return true;
847 /* Return the rtx containing SYMBOL_REF to the text label. */
848 static rtx
849 tilepro_text_label_symbol (void)
851 return cfun->machine->text_label_symbol;
855 /* Return the register storing the value of the text label. */
856 static rtx
857 tilepro_text_label_rtx (void)
859 return cfun->machine->text_label_rtx;
863 /* Return the register storing the value of the global offset
864 table. */
865 static rtx
866 tilepro_got_rtx (void)
868 return cfun->machine->got_rtx;
872 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
873 static rtx
874 tilepro_got_symbol (void)
876 if (g_got_symbol == NULL)
877 g_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
879 return g_got_symbol;
883 /* Return a reference to the got to be used by tls references. */
884 static rtx
885 tilepro_tls_got (void)
887 rtx temp;
888 if (flag_pic)
890 crtl->uses_pic_offset_table = 1;
891 return tilepro_got_rtx ();
894 temp = gen_reg_rtx (Pmode);
895 emit_move_insn (temp, tilepro_got_symbol ());
897 return temp;
901 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
902 this (thread-local) address. */
903 static rtx
904 tilepro_legitimize_tls_address (rtx addr)
906 rtx ret;
908 gcc_assert (can_create_pseudo_p ());
910 if (GET_CODE (addr) == SYMBOL_REF)
911 switch (SYMBOL_REF_TLS_MODEL (addr))
913 case TLS_MODEL_GLOBAL_DYNAMIC:
914 case TLS_MODEL_LOCAL_DYNAMIC:
916 rtx r0, temp1, temp2, temp3, got;
917 rtx_insn *last;
919 ret = gen_reg_rtx (Pmode);
920 r0 = gen_rtx_REG (Pmode, 0);
921 temp1 = gen_reg_rtx (Pmode);
922 temp2 = gen_reg_rtx (Pmode);
923 temp3 = gen_reg_rtx (Pmode);
925 got = tilepro_tls_got ();
926 emit_insn (gen_tls_gd_addhi (temp1, got, addr));
927 emit_insn (gen_tls_gd_addlo (temp2, temp1, addr));
928 emit_move_insn (r0, temp2);
929 emit_insn (gen_tls_gd_call (addr));
930 emit_move_insn (temp3, r0);
931 last = emit_insn (gen_tls_gd_add (ret, temp3, addr));
932 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
933 break;
935 case TLS_MODEL_INITIAL_EXEC:
937 rtx temp1, temp2, temp3, got;
938 rtx_insn *last;
940 ret = gen_reg_rtx (Pmode);
941 temp1 = gen_reg_rtx (Pmode);
942 temp2 = gen_reg_rtx (Pmode);
943 temp3 = gen_reg_rtx (Pmode);
945 got = tilepro_tls_got ();
946 emit_insn (gen_tls_ie_addhi (temp1, got, addr));
947 emit_insn (gen_tls_ie_addlo (temp2, temp1, addr));
948 emit_insn (gen_tls_ie_load (temp3, temp2, addr));
949 last =
950 emit_move_insn(ret,
951 gen_rtx_PLUS (Pmode,
952 gen_rtx_REG (Pmode,
953 THREAD_POINTER_REGNUM),
954 temp3));
955 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
956 break;
958 case TLS_MODEL_LOCAL_EXEC:
960 rtx temp1;
961 rtx_insn *last;
963 ret = gen_reg_rtx (Pmode);
964 temp1 = gen_reg_rtx (Pmode);
966 emit_insn (gen_tls_le_addhi (temp1,
967 gen_rtx_REG (Pmode,
968 THREAD_POINTER_REGNUM),
969 addr));
970 last = emit_insn (gen_tls_le_addlo (ret, temp1, addr));
971 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
972 break;
974 default:
975 gcc_unreachable ();
977 else if (GET_CODE (addr) == CONST)
979 rtx base, offset;
981 gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
983 base = tilepro_legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
984 offset = XEXP (XEXP (addr, 0), 1);
986 base = force_operand (base, NULL_RTX);
987 ret = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
989 else
990 gcc_unreachable ();
992 return ret;
996 /* Legitimize PIC addresses. If the address is already
997 position-independent, we return ORIG. Newly generated
998 position-independent addresses go into a reg. This is REG if
999 nonzero, otherwise we allocate register(s) as necessary. */
1000 static rtx
1001 tilepro_legitimize_pic_address (rtx orig,
1002 machine_mode mode ATTRIBUTE_UNUSED,
1003 rtx reg)
1005 if (GET_CODE (orig) == SYMBOL_REF)
1007 rtx address, pic_ref;
1009 if (reg == 0)
1011 gcc_assert (can_create_pseudo_p ());
1012 reg = gen_reg_rtx (Pmode);
1015 if (SYMBOL_REF_LOCAL_P (orig))
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);
1021 rtx text_label_symbol = tilepro_text_label_symbol ();
1022 rtx text_label_rtx = tilepro_text_label_rtx ();
1024 emit_insn (gen_addli_pcrel (temp_reg, text_label_rtx, orig,
1025 text_label_symbol));
1026 emit_insn (gen_auli_pcrel (temp_reg, temp_reg, orig,
1027 text_label_symbol));
1029 /* Note: this is conservative. We use the text_label but we
1030 don't use the pic_offset_table. However, in some cases
1031 we may need the pic_offset_table (see
1032 tilepro_fixup_pcrel_references). */
1033 crtl->uses_pic_offset_table = 1;
1035 address = temp_reg;
1037 emit_move_insn (reg, address);
1038 return reg;
1040 else
1042 /* If not during reload, allocate another temp reg here for
1043 loading in the address, so that these instructions can be
1044 optimized properly. */
1045 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
1047 gcc_assert (flag_pic);
1048 if (flag_pic == 1)
1050 emit_insn (gen_add_got16 (temp_reg,
1051 tilepro_got_rtx (), orig));
1053 else
1055 rtx temp_reg2 = create_temp_reg_if_possible (Pmode, reg);
1056 emit_insn (gen_addhi_got32 (temp_reg2,
1057 tilepro_got_rtx (), orig));
1058 emit_insn (gen_addlo_got32 (temp_reg, temp_reg2, orig));
1061 address = temp_reg;
1063 pic_ref = gen_const_mem (Pmode, address);
1064 crtl->uses_pic_offset_table = 1;
1065 emit_move_insn (reg, pic_ref);
1066 /* The following put a REG_EQUAL note on this insn, so that
1067 it can be optimized by loop. But it causes the label to
1068 be optimized away. */
1069 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1070 return reg;
1073 else if (GET_CODE (orig) == CONST)
1075 rtx base, offset;
1077 if (GET_CODE (XEXP (orig, 0)) == PLUS
1078 && XEXP (XEXP (orig, 0), 0) == tilepro_got_rtx ())
1079 return orig;
1081 if (reg == 0)
1083 gcc_assert (can_create_pseudo_p ());
1084 reg = gen_reg_rtx (Pmode);
1087 gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
1088 base = tilepro_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode,
1089 reg);
1090 offset =
1091 tilepro_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
1092 base == reg ? 0 : reg);
1094 if (CONST_INT_P (offset))
1096 if (can_create_pseudo_p ())
1097 offset = force_reg (Pmode, offset);
1098 else
1099 /* If we reach here, then something is seriously
1100 wrong. */
1101 gcc_unreachable ();
1104 if (can_create_pseudo_p ())
1105 return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
1106 else
1107 gcc_unreachable ();
1109 else if (GET_CODE (orig) == LABEL_REF)
1111 rtx address, temp_reg;
1112 rtx text_label_symbol;
1113 rtx text_label_rtx;
1115 if (reg == 0)
1117 gcc_assert (can_create_pseudo_p ());
1118 reg = gen_reg_rtx (Pmode);
1121 /* If not during reload, allocate another temp reg here for
1122 loading in the address, so that these instructions can be
1123 optimized properly. */
1124 temp_reg = create_temp_reg_if_possible (Pmode, reg);
1125 text_label_symbol = tilepro_text_label_symbol ();
1126 text_label_rtx = tilepro_text_label_rtx ();
1128 emit_insn (gen_addli_pcrel (temp_reg, text_label_rtx, orig,
1129 text_label_symbol));
1130 emit_insn (gen_auli_pcrel (temp_reg, temp_reg, orig,
1131 text_label_symbol));
1133 /* Note: this is conservative. We use the text_label but we
1134 don't use the pic_offset_table. */
1135 crtl->uses_pic_offset_table = 1;
1137 address = temp_reg;
1139 emit_move_insn (reg, address);
1141 return reg;
1144 return orig;
1148 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1149 static rtx
1150 tilepro_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1151 machine_mode mode)
1153 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
1154 && symbolic_operand (x, Pmode) && tilepro_tls_referenced_p (x))
1156 return tilepro_legitimize_tls_address (x);
1158 else if (flag_pic)
1160 return tilepro_legitimize_pic_address (x, mode, 0);
1162 else
1163 return x;
1167 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1168 static rtx
1169 tilepro_delegitimize_address (rtx x)
1171 x = delegitimize_mem_from_attrs (x);
1173 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC)
1175 switch (XINT (XEXP (x, 0), 1))
1177 case UNSPEC_PCREL_SYM:
1178 case UNSPEC_GOT16_SYM:
1179 case UNSPEC_GOT32_SYM:
1180 case UNSPEC_TLS_GD:
1181 case UNSPEC_TLS_IE:
1182 x = XVECEXP (XEXP (x, 0), 0, 0);
1183 break;
1187 return x;
1191 /* Emit code to load the PIC register. */
1192 static void
1193 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED)
1195 int orig_flag_pic = flag_pic;
1197 rtx got_symbol = tilepro_got_symbol ();
1198 rtx text_label_symbol = tilepro_text_label_symbol ();
1199 rtx text_label_rtx = tilepro_text_label_rtx ();
1200 flag_pic = 0;
1202 emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol));
1204 emit_insn (gen_addli_pcrel (tilepro_got_rtx (),
1205 text_label_rtx, got_symbol, text_label_symbol));
1207 emit_insn (gen_auli_pcrel (tilepro_got_rtx (),
1208 tilepro_got_rtx (),
1209 got_symbol, text_label_symbol));
1211 flag_pic = orig_flag_pic;
1213 /* Need to emit this whether or not we obey regdecls, since
1214 setjmp/longjmp can cause life info to screw up. ??? In the case
1215 where we don't obey regdecls, this is not sufficient since we may
1216 not fall out the bottom. */
1217 emit_use (tilepro_got_rtx ());
1221 /* Return the simd variant of the constant NUM of mode MODE, by
1222 replicating it to fill an interger of mode SImode. NUM is first
1223 truncated to fit in MODE. */
1225 tilepro_simd_int (rtx num, machine_mode mode)
1227 HOST_WIDE_INT n = 0;
1229 gcc_assert (CONST_INT_P (num));
1231 n = INTVAL (num);
1233 switch (mode)
1235 case QImode:
1236 n = 0x01010101 * (n & 0x000000FF);
1237 break;
1238 case HImode:
1239 n = 0x00010001 * (n & 0x0000FFFF);
1240 break;
1241 case SImode:
1242 break;
1243 case DImode:
1244 break;
1245 default:
1246 gcc_unreachable ();
1249 return gen_int_si (n);
1253 /* Split one or more DImode RTL references into pairs of SImode
1254 references. The RTL can be REG, offsettable MEM, integer constant,
1255 or CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL
1256 to split and "num" is its length. lo_half and hi_half are output
1257 arrays that parallel "operands". */
1258 void
1259 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1261 while (num--)
1263 rtx op = operands[num];
1265 /* simplify_subreg refuse to split volatile memory addresses,
1266 but we still have to handle it. */
1267 if (MEM_P (op))
1269 lo_half[num] = adjust_address (op, SImode, 0);
1270 hi_half[num] = adjust_address (op, SImode, 4);
1272 else
1274 lo_half[num] = simplify_gen_subreg (SImode, op,
1275 GET_MODE (op) == VOIDmode
1276 ? DImode : GET_MODE (op), 0);
1277 hi_half[num] = simplify_gen_subreg (SImode, op,
1278 GET_MODE (op) == VOIDmode
1279 ? DImode : GET_MODE (op), 4);
1285 /* Returns true iff val can be moved into a register in one
1286 instruction. And if it can, it emits the code to move the
1287 constant.
1289 If three_wide_only is true, this insists on an instruction that
1290 works in a bundle containing three instructions. */
1291 static bool
1292 expand_set_cint32_one_inst (rtx dest_reg,
1293 HOST_WIDE_INT val, bool three_wide_only)
1295 val = trunc_int_for_mode (val, SImode);
1297 if (val == trunc_int_for_mode (val, QImode))
1299 /* Success! */
1300 emit_move_insn (dest_reg, GEN_INT (val));
1301 return true;
1303 else if (!three_wide_only)
1305 rtx imm_op = GEN_INT (val);
1307 if (satisfies_constraint_J (imm_op)
1308 || satisfies_constraint_K (imm_op)
1309 || satisfies_constraint_N (imm_op)
1310 || satisfies_constraint_P (imm_op))
1312 emit_move_insn (dest_reg, imm_op);
1313 return true;
1317 return false;
1321 /* Implement SImode rotatert. */
1322 static HOST_WIDE_INT
1323 rotate_right (HOST_WIDE_INT n, int count)
1325 unsigned HOST_WIDE_INT x = n & 0xFFFFFFFF;
1326 if (count == 0)
1327 return x;
1328 return ((x >> count) | (x << (32 - count))) & 0xFFFFFFFF;
1332 /* Return true iff n contains exactly one contiguous sequence of 1
1333 bits, possibly wrapping around from high bits to low bits. */
1334 bool
1335 tilepro_bitfield_operand_p (HOST_WIDE_INT n, int *first_bit, int *last_bit)
1337 int i;
1339 if (n == 0)
1340 return false;
1342 for (i = 0; i < 32; i++)
1344 unsigned HOST_WIDE_INT x = rotate_right (n, i);
1345 if (!(x & 1))
1346 continue;
1348 /* See if x is a power of two minus one, i.e. only consecutive 1
1349 bits starting from bit 0. */
1350 if ((x & (x + 1)) == 0)
1352 if (first_bit != NULL)
1353 *first_bit = i;
1354 if (last_bit != NULL)
1355 *last_bit = (i + exact_log2 (x ^ (x >> 1))) & 31;
1357 return true;
1361 return false;
1365 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1366 static void
1367 expand_set_cint32 (rtx dest_reg, rtx src_val)
1369 HOST_WIDE_INT val;
1370 int leading_zeroes, trailing_zeroes;
1371 int lower, upper;
1372 int three_wide_only;
1373 rtx temp;
1375 gcc_assert (CONST_INT_P (src_val));
1376 val = trunc_int_for_mode (INTVAL (src_val), SImode);
1378 /* See if we can generate the constant in one instruction. */
1379 if (expand_set_cint32_one_inst (dest_reg, val, false))
1380 return;
1382 /* Create a temporary variable to hold a partial result, to enable
1383 CSE. */
1384 temp = create_temp_reg_if_possible (SImode, dest_reg);
1386 leading_zeroes = 31 - floor_log2 (val & 0xFFFFFFFF);
1387 trailing_zeroes = exact_log2 (val & -val);
1389 lower = trunc_int_for_mode (val, HImode);
1390 upper = trunc_int_for_mode ((val - lower) >> 16, HImode);
1392 /* First try all three-wide instructions that generate a constant
1393 (i.e. movei) followed by various shifts and rotates. If none of
1394 those work, try various two-wide ways of generating a constant
1395 followed by various shifts and rotates. */
1396 for (three_wide_only = 1; three_wide_only >= 0; three_wide_only--)
1398 int count;
1400 if (expand_set_cint32_one_inst (temp, val >> trailing_zeroes,
1401 three_wide_only))
1403 /* 0xFFFFA500 becomes:
1404 movei temp, 0xFFFFFFA5
1405 shli dest, temp, 8 */
1406 emit_move_insn (dest_reg,
1407 gen_rtx_ASHIFT (SImode, temp,
1408 GEN_INT (trailing_zeroes)));
1409 return;
1412 if (expand_set_cint32_one_inst (temp, val << leading_zeroes,
1413 three_wide_only))
1415 /* 0x7FFFFFFF becomes:
1416 movei temp, -2
1417 shri dest, temp, 1 */
1418 emit_move_insn (dest_reg,
1419 gen_rtx_LSHIFTRT (SImode, temp,
1420 GEN_INT (leading_zeroes)));
1421 return;
1424 /* Try rotating a one-instruction immediate, since rotate is
1425 3-wide. */
1426 for (count = 1; count < 32; count++)
1428 HOST_WIDE_INT r = rotate_right (val, count);
1429 if (expand_set_cint32_one_inst (temp, r, three_wide_only))
1431 /* 0xFFA5FFFF becomes:
1432 movei temp, 0xFFFFFFA5
1433 rli dest, temp, 16 */
1434 emit_move_insn (dest_reg,
1435 gen_rtx_ROTATE (SImode, temp, GEN_INT (count)));
1436 return;
1440 if (lower == trunc_int_for_mode (lower, QImode))
1442 /* We failed to use two 3-wide instructions, but the low 16
1443 bits are a small number so just use a 2-wide + 3-wide
1444 auli + addi pair rather than anything more exotic.
1446 0x12340056 becomes:
1447 auli temp, zero, 0x1234
1448 addi dest, temp, 0x56 */
1449 break;
1453 /* Fallback case: use a auli + addli/addi pair. */
1454 emit_move_insn (temp, GEN_INT (upper << 16));
1455 emit_move_insn (dest_reg, (gen_rtx_PLUS (SImode, temp, GEN_INT (lower))));
1459 /* Load OP1, a 32-bit constant, into OP0, a register. We know it
1460 can't be done in one insn when we get here, the move expander
1461 guarantees this. */
1462 void
1463 tilepro_expand_set_const32 (rtx op0, rtx op1)
1465 machine_mode mode = GET_MODE (op0);
1466 rtx temp;
1468 if (CONST_INT_P (op1))
1470 /* TODO: I don't know if we want to split large constants now,
1471 or wait until later (with a define_split).
1473 Does splitting early help CSE? Does it harm other
1474 optimizations that might fold loads? */
1475 expand_set_cint32 (op0, op1);
1477 else
1479 temp = create_temp_reg_if_possible (mode, op0);
1481 /* A symbol, emit in the traditional way. */
1482 emit_move_insn (temp, gen_rtx_HIGH (mode, op1));
1483 emit_move_insn (op0, gen_rtx_LO_SUM (mode, temp, op1));
1488 /* Expand a move instruction. Return true if all work is done. */
1489 bool
1490 tilepro_expand_mov (machine_mode mode, rtx *operands)
1492 /* Handle sets of MEM first. */
1493 if (MEM_P (operands[0]))
1495 if (can_create_pseudo_p ())
1496 operands[0] = validize_mem (operands[0]);
1498 if (reg_or_0_operand (operands[1], mode))
1499 return false;
1501 if (!reload_in_progress)
1502 operands[1] = force_reg (mode, operands[1]);
1505 /* Fixup TLS cases. */
1506 if (CONSTANT_P (operands[1]) && tilepro_tls_referenced_p (operands[1]))
1508 operands[1] = tilepro_legitimize_tls_address (operands[1]);
1509 return false;
1512 /* Fixup PIC cases. */
1513 if (flag_pic && CONSTANT_P (operands[1]))
1515 if (tilepro_pic_address_needs_scratch (operands[1]))
1516 operands[1] = tilepro_legitimize_pic_address (operands[1], mode, 0);
1518 if (symbolic_operand (operands[1], mode))
1520 operands[1] = tilepro_legitimize_pic_address (operands[1],
1521 mode,
1522 (reload_in_progress ?
1523 operands[0] :
1524 NULL_RTX));
1525 return false;
1529 /* Fixup for UNSPEC addresses. */
1530 if (flag_pic
1531 && GET_CODE (operands[1]) == HIGH
1532 && GET_CODE (XEXP (operands[1], 0)) == CONST
1533 && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == UNSPEC)
1535 rtx unspec = XEXP (XEXP (operands[1], 0), 0);
1536 int unspec_num = XINT (unspec, 1);
1537 if (unspec_num == UNSPEC_PCREL_SYM)
1539 emit_insn (gen_auli_pcrel (operands[0], const0_rtx,
1540 XVECEXP (unspec, 0, 0),
1541 XVECEXP (unspec, 0, 1)));
1542 return true;
1544 else if (flag_pic == 2 && unspec_num == UNSPEC_GOT32_SYM)
1546 emit_insn (gen_addhi_got32 (operands[0], const0_rtx,
1547 XVECEXP (unspec, 0, 0)));
1548 return true;
1550 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_GD)
1552 emit_insn (gen_tls_gd_addhi (operands[0], const0_rtx,
1553 XVECEXP (unspec, 0, 0)));
1554 return true;
1556 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_IE)
1558 emit_insn (gen_tls_ie_addhi (operands[0], const0_rtx,
1559 XVECEXP (unspec, 0, 0)));
1560 return true;
1562 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_LE)
1564 emit_insn (gen_tls_le_addhi (operands[0], const0_rtx,
1565 XVECEXP (unspec, 0, 0)));
1566 return true;
1570 /* Accept non-constants and valid constants unmodified. */
1571 if (!CONSTANT_P (operands[1])
1572 || GET_CODE (operands[1]) == HIGH || move_operand (operands[1], mode))
1573 return false;
1575 /* Split large integers. */
1576 if (GET_MODE_SIZE (mode) <= 4)
1578 tilepro_expand_set_const32 (operands[0], operands[1]);
1579 return true;
1582 return false;
1586 /* Expand the "insv" pattern. */
1587 void
1588 tilepro_expand_insv (rtx operands[4])
1590 rtx first_rtx = operands[2];
1591 HOST_WIDE_INT first = INTVAL (first_rtx);
1592 HOST_WIDE_INT width = INTVAL (operands[1]);
1593 rtx v = operands[3];
1595 /* Shift the inserted bits into position. */
1596 if (first != 0)
1598 if (CONST_INT_P (v))
1600 /* Shift the constant into mm position. */
1601 v = gen_int_si (INTVAL (v) << first);
1603 else
1605 /* Shift over the value to be inserted. */
1606 rtx tmp = gen_reg_rtx (SImode);
1607 emit_insn (gen_ashlsi3 (tmp, v, first_rtx));
1608 v = tmp;
1612 /* Insert the shifted bits using an 'mm' insn. */
1613 emit_insn (gen_insn_mm (operands[0], v, operands[0], first_rtx,
1614 GEN_INT (first + width - 1)));
1618 /* Expand unaligned loads. */
1619 void
1620 tilepro_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize,
1621 HOST_WIDE_INT bit_offset, bool sign)
1623 machine_mode mode;
1624 rtx addr_lo, addr_hi;
1625 rtx mem_lo, mem_hi, hi;
1626 rtx mema, wide_result;
1627 int last_byte_offset;
1628 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1630 mode = GET_MODE (dest_reg);
1632 hi = gen_reg_rtx (mode);
1634 if (bitsize == 2 * BITS_PER_UNIT && (bit_offset % BITS_PER_UNIT) == 0)
1636 rtx lo;
1638 /* When just loading a two byte value, we can load the two bytes
1639 individually and combine them efficiently. */
1641 mem_lo = adjust_address (mem, QImode, byte_offset);
1642 mem_hi = adjust_address (mem, QImode, byte_offset + 1);
1644 lo = gen_reg_rtx (mode);
1645 emit_insn (gen_zero_extendqisi2 (lo, mem_lo));
1647 if (sign)
1649 rtx tmp = gen_reg_rtx (mode);
1651 /* Do a signed load of the second byte then shift and OR it
1652 in. */
1653 emit_insn (gen_extendqisi2 (gen_lowpart (SImode, hi), mem_hi));
1654 emit_insn (gen_ashlsi3 (gen_lowpart (SImode, tmp),
1655 gen_lowpart (SImode, hi), GEN_INT (8)));
1656 emit_insn (gen_iorsi3 (gen_lowpart (SImode, dest_reg),
1657 gen_lowpart (SImode, lo),
1658 gen_lowpart (SImode, tmp)));
1660 else
1662 /* Do two unsigned loads and use intlb to interleave
1663 them. */
1664 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, hi), mem_hi));
1665 emit_insn (gen_insn_intlb (gen_lowpart (SImode, dest_reg),
1666 gen_lowpart (SImode, hi),
1667 gen_lowpart (SImode, lo)));
1670 return;
1673 mema = XEXP (mem, 0);
1675 /* AND addresses cannot be in any alias set, since they may
1676 implicitly alias surrounding code. Ideally we'd have some alias
1677 set that covered all types except those with alignment 8 or
1678 higher. */
1679 addr_lo = force_reg (Pmode, plus_constant (Pmode, mema, byte_offset));
1680 mem_lo = change_address (mem, mode,
1681 gen_rtx_AND (Pmode, addr_lo, GEN_INT (-4)));
1682 set_mem_alias_set (mem_lo, 0);
1684 /* Load the high word at an address that will not fault if the low
1685 address is aligned and at the very end of a page. */
1686 last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT;
1687 addr_hi = force_reg (Pmode, plus_constant (Pmode, mema, last_byte_offset));
1688 mem_hi = change_address (mem, mode,
1689 gen_rtx_AND (Pmode, addr_hi, GEN_INT (-4)));
1690 set_mem_alias_set (mem_hi, 0);
1692 if (bitsize == 32)
1694 addr_lo = make_safe_from (addr_lo, dest_reg);
1695 wide_result = dest_reg;
1697 else
1699 wide_result = gen_reg_rtx (mode);
1702 /* Load hi first in case dest_reg is used in mema. */
1703 emit_move_insn (hi, mem_hi);
1704 emit_move_insn (wide_result, mem_lo);
1706 emit_insn (gen_insn_dword_align (gen_lowpart (SImode, wide_result),
1707 gen_lowpart (SImode, wide_result),
1708 gen_lowpart (SImode, hi), addr_lo));
1710 if (bitsize != 32)
1712 rtx extracted =
1713 extract_bit_field (gen_lowpart (SImode, wide_result),
1714 bitsize, bit_offset % BITS_PER_UNIT,
1715 !sign, gen_lowpart (SImode, dest_reg),
1716 SImode, SImode);
1718 if (extracted != dest_reg)
1719 emit_move_insn (dest_reg, gen_lowpart (SImode, extracted));
1724 /* Expand unaligned stores. */
1725 static void
1726 tilepro_expand_unaligned_store (rtx mem, rtx src, HOST_WIDE_INT bitsize,
1727 HOST_WIDE_INT bit_offset)
1729 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1730 HOST_WIDE_INT bytesize = bitsize / BITS_PER_UNIT;
1731 HOST_WIDE_INT shift_amt;
1732 HOST_WIDE_INT i;
1733 rtx mem_addr;
1734 rtx store_val;
1736 for (i = 0, shift_amt = 0; i < bytesize; i++, shift_amt += BITS_PER_UNIT)
1738 mem_addr = adjust_address (mem, QImode, byte_offset + i);
1740 if (shift_amt)
1742 store_val = expand_simple_binop (SImode, LSHIFTRT,
1743 gen_lowpart (SImode, src),
1744 GEN_INT (shift_amt), NULL, 1,
1745 OPTAB_LIB_WIDEN);
1746 store_val = gen_lowpart (QImode, store_val);
1748 else
1750 store_val = gen_lowpart (QImode, src);
1753 emit_move_insn (mem_addr, store_val);
1758 /* Implement the movmisalign patterns. One of the operands is a
1759 memory that is not naturally aligned. Emit instructions to load
1760 it. */
1761 void
1762 tilepro_expand_movmisalign (machine_mode mode, rtx *operands)
1764 if (MEM_P (operands[1]))
1766 rtx tmp;
1768 if (register_operand (operands[0], mode))
1769 tmp = operands[0];
1770 else
1771 tmp = gen_reg_rtx (mode);
1773 tilepro_expand_unaligned_load (tmp, operands[1],
1774 GET_MODE_BITSIZE (mode), 0, true);
1776 if (tmp != operands[0])
1777 emit_move_insn (operands[0], tmp);
1779 else if (MEM_P (operands[0]))
1781 if (!reg_or_0_operand (operands[1], mode))
1782 operands[1] = force_reg (mode, operands[1]);
1784 tilepro_expand_unaligned_store (operands[0], operands[1],
1785 GET_MODE_BITSIZE (mode), 0);
1787 else
1788 gcc_unreachable ();
1792 /* Implement the addsi3 pattern. */
1793 bool
1794 tilepro_expand_addsi (rtx op0, rtx op1, rtx op2)
1796 rtx temp;
1797 HOST_WIDE_INT n;
1798 HOST_WIDE_INT high;
1800 /* Skip anything that only takes one instruction. */
1801 if (add_operand (op2, SImode))
1802 return false;
1804 /* We can only optimize ints here (it should be impossible to get
1805 here with any other type, but it is harmless to check. */
1806 if (!CONST_INT_P (op2))
1807 return false;
1809 temp = create_temp_reg_if_possible (SImode, op0);
1810 n = INTVAL (op2);
1811 high = (n + (n & 0x8000)) & ~0xffff;
1813 emit_move_insn (temp, gen_rtx_PLUS (SImode, op1, gen_int_si (high)));
1814 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, gen_int_si (n - high)));
1816 return true;
1820 /* Implement the allocate_stack pattern (alloca). */
1821 void
1822 tilepro_allocate_stack (rtx op0, rtx op1)
1824 /* Technically the correct way to initialize chain_loc is with
1825 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
1826 * sets the alias_set to that of a frame reference. Some of our
1827 * tests rely on some unsafe assumption about when the chaining
1828 * update is done, we need to be conservative about reordering the
1829 * chaining instructions.
1831 rtx fp_addr = gen_reg_rtx (Pmode);
1832 rtx fp_value = gen_reg_rtx (Pmode);
1833 rtx fp_loc;
1835 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1836 GEN_INT (UNITS_PER_WORD)));
1838 fp_loc = gen_frame_mem (Pmode, fp_addr);
1840 emit_move_insn (fp_value, fp_loc);
1842 op1 = force_reg (Pmode, op1);
1844 emit_move_insn (stack_pointer_rtx,
1845 gen_rtx_MINUS (Pmode, stack_pointer_rtx, op1));
1847 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1848 GEN_INT (UNITS_PER_WORD)));
1850 fp_loc = gen_frame_mem (Pmode, fp_addr);
1852 emit_move_insn (fp_loc, fp_value);
1854 emit_move_insn (op0, virtual_stack_dynamic_rtx);
1859 /* Multiplies */
1861 /* Returns the insn_code in ENTRY. */
1862 static enum insn_code
1863 tilepro_multiply_get_opcode (const struct tilepro_multiply_insn_seq_entry
1864 *entry)
1866 return tilepro_multiply_insn_seq_decode_opcode[entry->compressed_opcode];
1870 /* Returns the length of the 'op' array. */
1871 static int
1872 tilepro_multiply_get_num_ops (const struct tilepro_multiply_insn_seq *seq)
1874 /* The array either uses all of its allocated slots or is terminated
1875 by a bogus opcode. Either way, the array size is the index of the
1876 last valid opcode plus one. */
1877 int i;
1878 for (i = tilepro_multiply_insn_seq_MAX_OPERATIONS - 1; i >= 0; i--)
1879 if (tilepro_multiply_get_opcode (&seq->op[i]) != CODE_FOR_nothing)
1880 return i + 1;
1882 /* An empty array is not allowed. */
1883 gcc_unreachable ();
1887 /* We precompute a number of expression trees for multiplying by
1888 constants. This generates code for such an expression tree by
1889 walking through the nodes in the tree (which are conveniently
1890 pre-linearized) and emitting an instruction for each one. */
1891 static void
1892 tilepro_expand_constant_multiply_given_sequence (rtx result, rtx src,
1893 const struct
1894 tilepro_multiply_insn_seq
1895 *seq)
1897 int i;
1898 int num_ops;
1900 /* Keep track of the subexpressions computed so far, so later
1901 instructions can refer to them. We seed the array with zero and
1902 the value being multiplied. */
1903 int num_subexprs = 2;
1904 rtx subexprs[tilepro_multiply_insn_seq_MAX_OPERATIONS + 2];
1905 subexprs[0] = const0_rtx;
1906 subexprs[1] = src;
1908 /* Determine how many instructions we are going to generate. */
1909 num_ops = tilepro_multiply_get_num_ops (seq);
1910 gcc_assert (num_ops > 0
1911 && num_ops <= tilepro_multiply_insn_seq_MAX_OPERATIONS);
1913 for (i = 0; i < num_ops; i++)
1915 const struct tilepro_multiply_insn_seq_entry *entry = &seq->op[i];
1917 /* Figure out where to store the output of this instruction. */
1918 const bool is_last_op = (i + 1 == num_ops);
1919 rtx out = is_last_op ? result : gen_reg_rtx (SImode);
1921 enum insn_code opcode = tilepro_multiply_get_opcode (entry);
1922 if (opcode == CODE_FOR_ashlsi3)
1924 /* Handle shift by immediate. This is a special case because
1925 the meaning of the second operand is a constant shift
1926 count rather than an operand index. */
1928 /* Make sure the shift count is in range. Zero should not
1929 happen. */
1930 const int shift_count = entry->rhs;
1931 gcc_assert (shift_count > 0 && shift_count < 32);
1933 /* Emit the actual instruction. */
1934 emit_insn (GEN_FCN (opcode)
1935 (out, subexprs[entry->lhs],
1936 gen_rtx_CONST_INT (SImode, shift_count)));
1938 else
1940 /* Handle a normal two-operand instruction, such as add or
1941 s1a. */
1943 /* Make sure we are referring to a previously computed
1944 subexpression. */
1945 gcc_assert (entry->rhs < num_subexprs);
1947 /* Emit the actual instruction. */
1948 emit_insn (GEN_FCN (opcode)
1949 (out, subexprs[entry->lhs], subexprs[entry->rhs]));
1952 /* Record this subexpression for use by later expressions. */
1953 subexprs[num_subexprs++] = out;
1958 /* bsearch helper function. */
1959 static int
1960 tilepro_compare_multipliers (const void *key, const void *t)
1962 return *(const int *) key -
1963 ((const struct tilepro_multiply_insn_seq *) t)->multiplier;
1967 /* Returns the tilepro_multiply_insn_seq for multiplier, or NULL if
1968 none exists. */
1969 static const struct tilepro_multiply_insn_seq *
1970 tilepro_find_multiply_insn_seq_for_constant (int multiplier)
1972 return ((const struct tilepro_multiply_insn_seq *)
1973 bsearch (&multiplier, tilepro_multiply_insn_seq_table,
1974 tilepro_multiply_insn_seq_table_size,
1975 sizeof tilepro_multiply_insn_seq_table[0],
1976 tilepro_compare_multipliers));
1980 /* Try to a expand constant multiply in SImode by looking it up in a
1981 precompiled table. OP0 is the result operand, OP1 is the source
1982 operand, and MULTIPLIER is the value of the constant. Return true
1983 if it succeeds. */
1984 static bool
1985 tilepro_expand_const_mulsi (rtx op0, rtx op1, int multiplier)
1987 /* See if we have precomputed an efficient way to multiply by this
1988 constant. */
1989 const struct tilepro_multiply_insn_seq *seq =
1990 tilepro_find_multiply_insn_seq_for_constant (multiplier);
1991 if (seq != NULL)
1993 tilepro_expand_constant_multiply_given_sequence (op0, op1, seq);
1994 return true;
1996 else
1997 return false;
2001 /* Expand the mulsi pattern. */
2002 bool
2003 tilepro_expand_mulsi (rtx op0, rtx op1, rtx op2)
2005 if (CONST_INT_P (op2))
2007 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), SImode);
2008 return tilepro_expand_const_mulsi (op0, op1, n);
2010 return false;
2014 /* Expand a high multiply pattern in SImode. RESULT, OP1, OP2 are the
2015 operands, and SIGN is true if it's a signed multiply, and false if
2016 it's an unsigned multiply. */
2017 static void
2018 tilepro_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign)
2020 rtx tmp0 = gen_reg_rtx (SImode);
2021 rtx tmp1 = gen_reg_rtx (SImode);
2022 rtx tmp2 = gen_reg_rtx (SImode);
2023 rtx tmp3 = gen_reg_rtx (SImode);
2024 rtx tmp4 = gen_reg_rtx (SImode);
2025 rtx tmp5 = gen_reg_rtx (SImode);
2026 rtx tmp6 = gen_reg_rtx (SImode);
2027 rtx tmp7 = gen_reg_rtx (SImode);
2028 rtx tmp8 = gen_reg_rtx (SImode);
2029 rtx tmp9 = gen_reg_rtx (SImode);
2030 rtx tmp10 = gen_reg_rtx (SImode);
2031 rtx tmp11 = gen_reg_rtx (SImode);
2032 rtx tmp12 = gen_reg_rtx (SImode);
2033 rtx tmp13 = gen_reg_rtx (SImode);
2034 rtx result_lo = gen_reg_rtx (SImode);
2036 if (sign)
2038 emit_insn (gen_insn_mulhl_su (tmp0, op1, op2));
2039 emit_insn (gen_insn_mulhl_su (tmp1, op2, op1));
2040 emit_insn (gen_insn_mulll_uu (tmp2, op1, op2));
2041 emit_insn (gen_insn_mulhh_ss (tmp3, op1, op2));
2043 else
2045 emit_insn (gen_insn_mulhl_uu (tmp0, op1, op2));
2046 emit_insn (gen_insn_mulhl_uu (tmp1, op2, op1));
2047 emit_insn (gen_insn_mulll_uu (tmp2, op1, op2));
2048 emit_insn (gen_insn_mulhh_uu (tmp3, op1, op2));
2051 emit_move_insn (tmp4, (gen_rtx_ASHIFT (SImode, tmp0, GEN_INT (16))));
2053 emit_move_insn (tmp5, (gen_rtx_ASHIFT (SImode, tmp1, GEN_INT (16))));
2055 emit_move_insn (tmp6, (gen_rtx_PLUS (SImode, tmp4, tmp5)));
2056 emit_move_insn (result_lo, (gen_rtx_PLUS (SImode, tmp2, tmp6)));
2058 emit_move_insn (tmp7, gen_rtx_LTU (SImode, tmp6, tmp4));
2059 emit_move_insn (tmp8, gen_rtx_LTU (SImode, result_lo, tmp2));
2061 if (sign)
2063 emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (SImode, tmp0, GEN_INT (16))));
2064 emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (SImode, tmp1, GEN_INT (16))));
2066 else
2068 emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (SImode, tmp0, GEN_INT (16))));
2069 emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (SImode, tmp1, GEN_INT (16))));
2072 emit_move_insn (tmp11, (gen_rtx_PLUS (SImode, tmp3, tmp7)));
2073 emit_move_insn (tmp12, (gen_rtx_PLUS (SImode, tmp8, tmp9)));
2074 emit_move_insn (tmp13, (gen_rtx_PLUS (SImode, tmp11, tmp12)));
2075 emit_move_insn (result, (gen_rtx_PLUS (SImode, tmp13, tmp10)));
2079 /* Implement smulsi3_highpart. */
2080 void
2081 tilepro_expand_smulsi3_highpart (rtx op0, rtx op1, rtx op2)
2083 tilepro_expand_high_multiply (op0, op1, op2, true);
2087 /* Implement umulsi3_highpart. */
2088 void
2089 tilepro_expand_umulsi3_highpart (rtx op0, rtx op1, rtx op2)
2091 tilepro_expand_high_multiply (op0, op1, op2, false);
2096 /* Compare and branches */
2098 /* Helper function to handle DImode for tilepro_emit_setcc_internal. */
2099 static bool
2100 tilepro_emit_setcc_internal_di (rtx res, enum rtx_code code, rtx op0, rtx op1)
2102 rtx operands[2], lo_half[2], hi_half[2];
2103 rtx tmp, tmp0, tmp1, tmp2;
2104 bool swap = false;
2106 /* Reduce the number of cases we need to handle by reversing the
2107 operands. */
2108 switch (code)
2110 case EQ:
2111 case NE:
2112 case LE:
2113 case LT:
2114 case LEU:
2115 case LTU:
2116 /* We handle these compares directly. */
2117 break;
2119 case GE:
2120 case GT:
2121 case GEU:
2122 case GTU:
2123 /* Reverse the operands. */
2124 swap = true;
2125 break;
2127 default:
2128 /* We should not have called this with any other code. */
2129 gcc_unreachable ();
2132 if (swap)
2134 code = swap_condition (code);
2135 tmp = op0, op0 = op1, op1 = tmp;
2138 operands[0] = op0;
2139 operands[1] = op1;
2141 split_di (operands, 2, lo_half, hi_half);
2143 if (!reg_or_0_operand (lo_half[0], SImode))
2144 lo_half[0] = force_reg (SImode, lo_half[0]);
2146 if (!reg_or_0_operand (hi_half[0], SImode))
2147 hi_half[0] = force_reg (SImode, hi_half[0]);
2149 if (!CONST_INT_P (lo_half[1]) && !register_operand (lo_half[1], SImode))
2150 lo_half[1] = force_reg (SImode, lo_half[1]);
2152 if (!CONST_INT_P (hi_half[1]) && !register_operand (hi_half[1], SImode))
2153 hi_half[1] = force_reg (SImode, hi_half[1]);
2155 tmp0 = gen_reg_rtx (SImode);
2156 tmp1 = gen_reg_rtx (SImode);
2157 tmp2 = gen_reg_rtx (SImode);
2159 switch (code)
2161 case EQ:
2162 emit_insn (gen_insn_seq (tmp0, lo_half[0], lo_half[1]));
2163 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2164 emit_insn (gen_andsi3 (res, tmp0, tmp1));
2165 return true;
2166 break;
2167 case NE:
2168 emit_insn (gen_insn_sne (tmp0, lo_half[0], lo_half[1]));
2169 emit_insn (gen_insn_sne (tmp1, hi_half[0], hi_half[1]));
2170 emit_insn (gen_iorsi3 (res, tmp0, tmp1));
2171 return true;
2172 break;
2173 case LE:
2174 emit_insn (gen_insn_slte (tmp0, hi_half[0], hi_half[1]));
2175 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2176 emit_insn (gen_insn_slte_u (tmp2, lo_half[0], lo_half[1]));
2177 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2178 return true;
2179 case LT:
2180 if (operands[1] == const0_rtx)
2182 emit_insn (gen_lshrsi3 (res, hi_half[0], GEN_INT (31)));
2183 return true;
2185 else
2187 emit_insn (gen_insn_slt (tmp0, hi_half[0], hi_half[1]));
2188 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2189 emit_insn (gen_insn_slt_u (tmp2, lo_half[0], lo_half[1]));
2190 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2192 return true;
2193 case LEU:
2194 emit_insn (gen_insn_slte_u (tmp0, hi_half[0], hi_half[1]));
2195 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2196 emit_insn (gen_insn_slte_u (tmp2, lo_half[0], lo_half[1]));
2197 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2198 return true;
2199 case LTU:
2200 emit_insn (gen_insn_slt_u (tmp0, hi_half[0], hi_half[1]));
2201 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2202 emit_insn (gen_insn_slt_u (tmp2, lo_half[0], lo_half[1]));
2203 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2204 return true;
2205 default:
2206 gcc_unreachable ();
2209 return false;
2213 /* Certain simplifications can be done to make invalid setcc
2214 operations valid. Return the final comparison, or NULL if we can't
2215 work. */
2216 static bool
2217 tilepro_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1,
2218 machine_mode cmp_mode)
2220 rtx tmp;
2221 bool swap = false;
2223 if (cmp_mode == DImode)
2225 return tilepro_emit_setcc_internal_di (res, code, op0, op1);
2228 /* The general case: fold the comparison code to the types of
2229 compares that we have, choosing the branch as necessary. */
2231 switch (code)
2233 case EQ:
2234 case NE:
2235 case LE:
2236 case LT:
2237 case LEU:
2238 case LTU:
2239 /* We have these compares. */
2240 break;
2242 case GE:
2243 case GT:
2244 case GEU:
2245 case GTU:
2246 /* We do not have these compares, so we reverse the
2247 operands. */
2248 swap = true;
2249 break;
2251 default:
2252 /* We should not have called this with any other code. */
2253 gcc_unreachable ();
2256 if (swap)
2258 code = swap_condition (code);
2259 tmp = op0, op0 = op1, op1 = tmp;
2262 if (!reg_or_0_operand (op0, SImode))
2263 op0 = force_reg (SImode, op0);
2265 if (!CONST_INT_P (op1) && !register_operand (op1, SImode))
2266 op1 = force_reg (SImode, op1);
2268 /* Return the setcc comparison. */
2269 emit_insn (gen_rtx_SET (res, gen_rtx_fmt_ee (code, SImode, op0, op1)));
2271 return true;
2275 /* Implement cstore patterns. */
2276 bool
2277 tilepro_emit_setcc (rtx operands[], machine_mode cmp_mode)
2279 return
2280 tilepro_emit_setcc_internal (operands[0], GET_CODE (operands[1]),
2281 operands[2], operands[3], cmp_mode);
2285 /* Return whether CODE is a signed comparison. */
2286 static bool
2287 signed_compare_p (enum rtx_code code)
2289 return (code == EQ || code == NE || code == LT || code == LE
2290 || code == GT || code == GE);
2294 /* Generate the comparison for an SImode conditional branch. */
2295 static rtx
2296 tilepro_emit_cc_test (enum rtx_code code, rtx op0, rtx op1,
2297 machine_mode cmp_mode, bool eq_ne_only)
2299 enum rtx_code branch_code;
2300 rtx temp;
2302 /* Check for a compare against zero using a comparison we can do
2303 directly. */
2304 if (cmp_mode != DImode
2305 && op1 == const0_rtx
2306 && (code == EQ || code == NE
2307 || (!eq_ne_only && signed_compare_p (code))))
2309 op0 = force_reg (SImode, op0);
2310 return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx);
2313 /* The general case: fold the comparison code to the types of
2314 compares that we have, choosing the branch as necessary. */
2315 switch (code)
2317 case EQ:
2318 case LE:
2319 case LT:
2320 case LEU:
2321 case LTU:
2322 /* We have these compares. */
2323 branch_code = NE;
2324 break;
2326 case NE:
2327 case GE:
2328 case GT:
2329 case GEU:
2330 case GTU:
2331 /* These must be reversed (except NE, but let's
2332 canonicalize). */
2333 code = reverse_condition (code);
2334 branch_code = EQ;
2335 break;
2337 default:
2338 gcc_unreachable ();
2341 if (cmp_mode != DImode
2342 && CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU))
2344 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op1), SImode);
2346 switch (code)
2348 case EQ:
2349 /* Subtract off the value we want to compare against and see
2350 if we get zero. This is cheaper than creating a constant
2351 in a register. Except that subtracting -128 is more
2352 expensive than seqi to -128, so we leave that alone. */
2353 /* ??? Don't do this when comparing against symbols,
2354 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2355 0), which will be declared false out of hand (at least
2356 for non-weak). */
2357 if (!(symbolic_operand (op0, VOIDmode)
2358 || (REG_P (op0) && REG_POINTER (op0))))
2360 /* To compare against MIN_INT, we add MIN_INT and check
2361 for 0. */
2362 HOST_WIDE_INT add;
2363 if (n != -2147483647 - 1)
2364 add = -n;
2365 else
2366 add = n;
2368 op0 = force_reg (SImode, op0);
2369 temp = gen_reg_rtx (SImode);
2370 emit_insn (gen_addsi3 (temp, op0, gen_int_si (add)));
2371 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2372 VOIDmode, temp, const0_rtx);
2374 break;
2376 case LEU:
2377 if (n == -1)
2378 break;
2379 /* FALLTHRU */
2381 case LTU:
2382 /* Change ((unsigned)x < 0x1000) into !((unsigned)x >> 12),
2383 etc. */
2385 int first = exact_log2 (code == LTU ? n : n + 1);
2386 if (first != -1)
2388 op0 = force_reg (SImode, op0);
2389 temp = gen_reg_rtx (SImode);
2390 emit_move_insn (temp,
2391 gen_rtx_LSHIFTRT (SImode, op0,
2392 gen_int_si (first)));
2393 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2394 VOIDmode, temp, const0_rtx);
2397 break;
2399 default:
2400 break;
2404 /* Compute a flag saying whether we should branch. */
2405 temp = gen_reg_rtx (SImode);
2406 tilepro_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2408 /* Return the branch comparison. */
2409 return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx);
2413 /* Generate the comparison for a conditional branch. */
2414 void
2415 tilepro_emit_conditional_branch (rtx operands[], machine_mode cmp_mode)
2417 rtx cmp_rtx =
2418 tilepro_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2],
2419 cmp_mode, false);
2420 rtx branch_rtx = gen_rtx_SET (pc_rtx,
2421 gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx,
2422 gen_rtx_LABEL_REF
2423 (VOIDmode,
2424 operands[3]),
2425 pc_rtx));
2426 emit_jump_insn (branch_rtx);
2430 /* Implement the movsicc pattern. */
2432 tilepro_emit_conditional_move (rtx cmp)
2434 return
2435 tilepro_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1),
2436 GET_MODE (XEXP (cmp, 0)), true);
2440 /* Return true if INSN is annotated with a REG_BR_PROB note that
2441 indicates it's a branch that's predicted taken. */
2442 static bool
2443 cbranch_predicted_p (rtx_insn *insn)
2445 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2447 if (x)
2449 int pred_val = XINT (x, 0);
2451 return pred_val >= REG_BR_PROB_BASE / 2;
2454 return false;
2458 /* Output assembly code for a specific branch instruction, appending
2459 the branch prediction flag to the opcode if appropriate. */
2460 static const char *
2461 tilepro_output_simple_cbranch_with_opcode (rtx_insn *insn, const char *opcode,
2462 int regop, bool netreg_p,
2463 bool reverse_predicted)
2465 static char buf[64];
2466 sprintf (buf, "%s%s\t%%%c%d, %%l0", opcode,
2467 (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "",
2468 netreg_p ? 'N' : 'r', regop);
2469 return buf;
2473 /* Output assembly code for a specific branch instruction, appending
2474 the branch prediction flag to the opcode if appropriate. */
2475 const char *
2476 tilepro_output_cbranch_with_opcode (rtx_insn *insn, rtx *operands,
2477 const char *opcode,
2478 const char *rev_opcode,
2479 int regop, bool netreg_p)
2481 const char *branch_if_false;
2482 rtx taken, not_taken;
2483 bool is_simple_branch;
2485 gcc_assert (LABEL_P (operands[0]));
2487 is_simple_branch = true;
2488 if (INSN_ADDRESSES_SET_P ())
2490 int from_addr = INSN_ADDRESSES (INSN_UID (insn));
2491 int to_addr = INSN_ADDRESSES (INSN_UID (operands[0]));
2492 int delta = to_addr - from_addr;
2493 is_simple_branch = IN_RANGE (delta, -524288, 524280);
2496 if (is_simple_branch)
2498 /* Just a simple conditional branch. */
2499 return
2500 tilepro_output_simple_cbranch_with_opcode (insn, opcode, regop,
2501 netreg_p, false);
2504 /* Generate a reversed branch around a direct jump. This fallback
2505 does not use branch-likely instructions. */
2506 not_taken = gen_label_rtx ();
2507 taken = operands[0];
2509 /* Generate the reversed branch to NOT_TAKEN. */
2510 operands[0] = not_taken;
2511 branch_if_false =
2512 tilepro_output_simple_cbranch_with_opcode (insn, rev_opcode, regop,
2513 netreg_p, true);
2514 output_asm_insn (branch_if_false, operands);
2516 output_asm_insn ("j\t%l0", &taken);
2518 /* Output NOT_TAKEN. */
2519 targetm.asm_out.internal_label (asm_out_file, "L",
2520 CODE_LABEL_NUMBER (not_taken));
2521 return "";
2525 /* Output assembly code for a conditional branch instruction. */
2526 const char *
2527 tilepro_output_cbranch (rtx_insn *insn, rtx *operands, bool reversed)
2529 enum rtx_code code = GET_CODE (operands[1]);
2530 const char *opcode;
2531 const char *rev_opcode;
2533 if (reversed)
2534 code = reverse_condition (code);
2536 switch (code)
2538 case NE:
2539 opcode = "bnz";
2540 rev_opcode = "bz";
2541 break;
2542 case EQ:
2543 opcode = "bz";
2544 rev_opcode = "bnz";
2545 break;
2546 case GE:
2547 opcode = "bgez";
2548 rev_opcode = "blz";
2549 break;
2550 case GT:
2551 opcode = "bgz";
2552 rev_opcode = "blez";
2553 break;
2554 case LE:
2555 opcode = "blez";
2556 rev_opcode = "bgz";
2557 break;
2558 case LT:
2559 opcode = "blz";
2560 rev_opcode = "bgez";
2561 break;
2562 default:
2563 gcc_unreachable ();
2566 return
2567 tilepro_output_cbranch_with_opcode (insn, operands, opcode, rev_opcode,
2568 2, false);
2572 /* Implement the tablejump pattern. */
2573 void
2574 tilepro_expand_tablejump (rtx op0, rtx op1)
2576 if (flag_pic)
2578 rtx table = gen_rtx_LABEL_REF (Pmode, op1);
2579 rtx temp = gen_reg_rtx (Pmode);
2580 rtx text_label_symbol = tilepro_text_label_symbol ();
2581 rtx text_label_rtx = tilepro_text_label_rtx ();
2583 emit_insn (gen_addli_pcrel (temp, text_label_rtx,
2584 table, text_label_symbol));
2585 emit_insn (gen_auli_pcrel (temp, temp, table, text_label_symbol));
2586 emit_move_insn (temp,
2587 gen_rtx_PLUS (Pmode,
2588 convert_to_mode (Pmode, op0, false),
2589 temp));
2590 op0 = temp;
2593 emit_jump_insn (gen_tablejump_aux (op0, op1));
2597 /* Expand a builtin vector binary op, by calling gen function GEN with
2598 operands in the proper modes. DEST is converted to DEST_MODE, and
2599 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2600 void
2601 tilepro_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx),
2602 machine_mode dest_mode,
2603 rtx dest,
2604 machine_mode src_mode,
2605 rtx src0, rtx src1, bool do_src1)
2607 dest = gen_lowpart (dest_mode, dest);
2609 if (src0 == const0_rtx)
2610 src0 = CONST0_RTX (src_mode);
2611 else
2612 src0 = gen_lowpart (src_mode, src0);
2614 if (do_src1)
2616 if (src1 == const0_rtx)
2617 src1 = CONST0_RTX (src_mode);
2618 else
2619 src1 = gen_lowpart (src_mode, src1);
2622 emit_insn ((*gen) (dest, src0, src1));
2627 /* Intrinsics */
2629 struct tile_builtin_info
2631 enum insn_code icode;
2632 tree fndecl;
2635 static struct tile_builtin_info tilepro_builtin_info[TILEPRO_BUILTIN_max] = {
2636 { CODE_FOR_addsi3, NULL }, /* add */
2637 { CODE_FOR_insn_addb, NULL }, /* addb */
2638 { CODE_FOR_insn_addbs_u, NULL }, /* addbs_u */
2639 { CODE_FOR_insn_addh, NULL }, /* addh */
2640 { CODE_FOR_insn_addhs, NULL }, /* addhs */
2641 { CODE_FOR_insn_addib, NULL }, /* addib */
2642 { CODE_FOR_insn_addih, NULL }, /* addih */
2643 { CODE_FOR_insn_addlis, NULL }, /* addlis */
2644 { CODE_FOR_ssaddsi3, NULL }, /* adds */
2645 { CODE_FOR_insn_adiffb_u, NULL }, /* adiffb_u */
2646 { CODE_FOR_insn_adiffh, NULL }, /* adiffh */
2647 { CODE_FOR_andsi3, NULL }, /* and */
2648 { CODE_FOR_insn_auli, NULL }, /* auli */
2649 { CODE_FOR_insn_avgb_u, NULL }, /* avgb_u */
2650 { CODE_FOR_insn_avgh, NULL }, /* avgh */
2651 { CODE_FOR_insn_bitx, NULL }, /* bitx */
2652 { CODE_FOR_bswapsi2, NULL }, /* bytex */
2653 { CODE_FOR_clzsi2, NULL }, /* clz */
2654 { CODE_FOR_insn_crc32_32, NULL }, /* crc32_32 */
2655 { CODE_FOR_insn_crc32_8, NULL }, /* crc32_8 */
2656 { CODE_FOR_ctzsi2, NULL }, /* ctz */
2657 { CODE_FOR_insn_drain, NULL }, /* drain */
2658 { CODE_FOR_insn_dtlbpr, NULL }, /* dtlbpr */
2659 { CODE_FOR_insn_dword_align, NULL }, /* dword_align */
2660 { CODE_FOR_insn_finv, NULL }, /* finv */
2661 { CODE_FOR_insn_flush, NULL }, /* flush */
2662 { CODE_FOR_insn_fnop, NULL }, /* fnop */
2663 { CODE_FOR_insn_icoh, NULL }, /* icoh */
2664 { CODE_FOR_insn_ill, NULL }, /* ill */
2665 { CODE_FOR_insn_info, NULL }, /* info */
2666 { CODE_FOR_insn_infol, NULL }, /* infol */
2667 { CODE_FOR_insn_inthb, NULL }, /* inthb */
2668 { CODE_FOR_insn_inthh, NULL }, /* inthh */
2669 { CODE_FOR_insn_intlb, NULL }, /* intlb */
2670 { CODE_FOR_insn_intlh, NULL }, /* intlh */
2671 { CODE_FOR_insn_inv, NULL }, /* inv */
2672 { CODE_FOR_insn_lb, NULL }, /* lb */
2673 { CODE_FOR_insn_lb_u, NULL }, /* lb_u */
2674 { CODE_FOR_insn_lh, NULL }, /* lh */
2675 { CODE_FOR_insn_lh_u, NULL }, /* lh_u */
2676 { CODE_FOR_insn_lnk, NULL }, /* lnk */
2677 { CODE_FOR_insn_lw, NULL }, /* lw */
2678 { CODE_FOR_insn_lw_na, NULL }, /* lw_na */
2679 { CODE_FOR_insn_lb_L2, NULL }, /* lb_L2 */
2680 { CODE_FOR_insn_lb_u_L2, NULL }, /* lb_u_L2 */
2681 { CODE_FOR_insn_lh_L2, NULL }, /* lh_L2 */
2682 { CODE_FOR_insn_lh_u_L2, NULL }, /* lh_u_L2 */
2683 { CODE_FOR_insn_lw_L2, NULL }, /* lw_L2 */
2684 { CODE_FOR_insn_lw_na_L2, NULL }, /* lw_na_L2 */
2685 { CODE_FOR_insn_lb_miss, NULL }, /* lb_miss */
2686 { CODE_FOR_insn_lb_u_miss, NULL }, /* lb_u_miss */
2687 { CODE_FOR_insn_lh_miss, NULL }, /* lh_miss */
2688 { CODE_FOR_insn_lh_u_miss, NULL }, /* lh_u_miss */
2689 { CODE_FOR_insn_lw_miss, NULL }, /* lw_miss */
2690 { CODE_FOR_insn_lw_na_miss, NULL }, /* lw_na_miss */
2691 { CODE_FOR_insn_maxb_u, NULL }, /* maxb_u */
2692 { CODE_FOR_insn_maxh, NULL }, /* maxh */
2693 { CODE_FOR_insn_maxib_u, NULL }, /* maxib_u */
2694 { CODE_FOR_insn_maxih, NULL }, /* maxih */
2695 { CODE_FOR_memory_barrier, NULL }, /* mf */
2696 { CODE_FOR_insn_mfspr, NULL }, /* mfspr */
2697 { CODE_FOR_insn_minb_u, NULL }, /* minb_u */
2698 { CODE_FOR_insn_minh, NULL }, /* minh */
2699 { CODE_FOR_insn_minib_u, NULL }, /* minib_u */
2700 { CODE_FOR_insn_minih, NULL }, /* minih */
2701 { CODE_FOR_insn_mm, NULL }, /* mm */
2702 { CODE_FOR_insn_mnz, NULL }, /* mnz */
2703 { CODE_FOR_insn_mnzb, NULL }, /* mnzb */
2704 { CODE_FOR_insn_mnzh, NULL }, /* mnzh */
2705 { CODE_FOR_movsi, NULL }, /* move */
2706 { CODE_FOR_insn_movelis, NULL }, /* movelis */
2707 { CODE_FOR_insn_mtspr, NULL }, /* mtspr */
2708 { CODE_FOR_insn_mulhh_ss, NULL }, /* mulhh_ss */
2709 { CODE_FOR_insn_mulhh_su, NULL }, /* mulhh_su */
2710 { CODE_FOR_insn_mulhh_uu, NULL }, /* mulhh_uu */
2711 { CODE_FOR_insn_mulhha_ss, NULL }, /* mulhha_ss */
2712 { CODE_FOR_insn_mulhha_su, NULL }, /* mulhha_su */
2713 { CODE_FOR_insn_mulhha_uu, NULL }, /* mulhha_uu */
2714 { CODE_FOR_insn_mulhhsa_uu, NULL }, /* mulhhsa_uu */
2715 { CODE_FOR_insn_mulhl_ss, NULL }, /* mulhl_ss */
2716 { CODE_FOR_insn_mulhl_su, NULL }, /* mulhl_su */
2717 { CODE_FOR_insn_mulhl_us, NULL }, /* mulhl_us */
2718 { CODE_FOR_insn_mulhl_uu, NULL }, /* mulhl_uu */
2719 { CODE_FOR_insn_mulhla_ss, NULL }, /* mulhla_ss */
2720 { CODE_FOR_insn_mulhla_su, NULL }, /* mulhla_su */
2721 { CODE_FOR_insn_mulhla_us, NULL }, /* mulhla_us */
2722 { CODE_FOR_insn_mulhla_uu, NULL }, /* mulhla_uu */
2723 { CODE_FOR_insn_mulhlsa_uu, NULL }, /* mulhlsa_uu */
2724 { CODE_FOR_insn_mulll_ss, NULL }, /* mulll_ss */
2725 { CODE_FOR_insn_mulll_su, NULL }, /* mulll_su */
2726 { CODE_FOR_insn_mulll_uu, NULL }, /* mulll_uu */
2727 { CODE_FOR_insn_mullla_ss, NULL }, /* mullla_ss */
2728 { CODE_FOR_insn_mullla_su, NULL }, /* mullla_su */
2729 { CODE_FOR_insn_mullla_uu, NULL }, /* mullla_uu */
2730 { CODE_FOR_insn_mulllsa_uu, NULL }, /* mulllsa_uu */
2731 { CODE_FOR_insn_mvnz, NULL }, /* mvnz */
2732 { CODE_FOR_insn_mvz, NULL }, /* mvz */
2733 { CODE_FOR_insn_mz, NULL }, /* mz */
2734 { CODE_FOR_insn_mzb, NULL }, /* mzb */
2735 { CODE_FOR_insn_mzh, NULL }, /* mzh */
2736 { CODE_FOR_insn_nap, NULL }, /* nap */
2737 { CODE_FOR_nop, NULL }, /* nop */
2738 { CODE_FOR_insn_nor, NULL }, /* nor */
2739 { CODE_FOR_iorsi3, NULL }, /* or */
2740 { CODE_FOR_insn_packbs_u, NULL }, /* packbs_u */
2741 { CODE_FOR_insn_packhb, NULL }, /* packhb */
2742 { CODE_FOR_insn_packhs, NULL }, /* packhs */
2743 { CODE_FOR_insn_packlb, NULL }, /* packlb */
2744 { CODE_FOR_popcountsi2, NULL }, /* pcnt */
2745 { CODE_FOR_insn_prefetch, NULL }, /* prefetch */
2746 { CODE_FOR_insn_prefetch_L1, NULL }, /* prefetch_L1 */
2747 { CODE_FOR_rotlsi3, NULL }, /* rl */
2748 { CODE_FOR_insn_s1a, NULL }, /* s1a */
2749 { CODE_FOR_insn_s2a, NULL }, /* s2a */
2750 { CODE_FOR_insn_s3a, NULL }, /* s3a */
2751 { CODE_FOR_insn_sadab_u, NULL }, /* sadab_u */
2752 { CODE_FOR_insn_sadah, NULL }, /* sadah */
2753 { CODE_FOR_insn_sadah_u, NULL }, /* sadah_u */
2754 { CODE_FOR_insn_sadb_u, NULL }, /* sadb_u */
2755 { CODE_FOR_insn_sadh, NULL }, /* sadh */
2756 { CODE_FOR_insn_sadh_u, NULL }, /* sadh_u */
2757 { CODE_FOR_insn_sb, NULL }, /* sb */
2758 { CODE_FOR_insn_seq, NULL }, /* seq */
2759 { CODE_FOR_insn_seqb, NULL }, /* seqb */
2760 { CODE_FOR_insn_seqh, NULL }, /* seqh */
2761 { CODE_FOR_insn_seqib, NULL }, /* seqib */
2762 { CODE_FOR_insn_seqih, NULL }, /* seqih */
2763 { CODE_FOR_insn_sh, NULL }, /* sh */
2764 { CODE_FOR_ashlsi3, NULL }, /* shl */
2765 { CODE_FOR_insn_shlb, NULL }, /* shlb */
2766 { CODE_FOR_insn_shlh, NULL }, /* shlh */
2767 { CODE_FOR_insn_shlb, NULL }, /* shlib */
2768 { CODE_FOR_insn_shlh, NULL }, /* shlih */
2769 { CODE_FOR_lshrsi3, NULL }, /* shr */
2770 { CODE_FOR_insn_shrb, NULL }, /* shrb */
2771 { CODE_FOR_insn_shrh, NULL }, /* shrh */
2772 { CODE_FOR_insn_shrb, NULL }, /* shrib */
2773 { CODE_FOR_insn_shrh, NULL }, /* shrih */
2774 { CODE_FOR_insn_slt, NULL }, /* slt */
2775 { CODE_FOR_insn_slt_u, NULL }, /* slt_u */
2776 { CODE_FOR_insn_sltb, NULL }, /* sltb */
2777 { CODE_FOR_insn_sltb_u, NULL }, /* sltb_u */
2778 { CODE_FOR_insn_slte, NULL }, /* slte */
2779 { CODE_FOR_insn_slte_u, NULL }, /* slte_u */
2780 { CODE_FOR_insn_slteb, NULL }, /* slteb */
2781 { CODE_FOR_insn_slteb_u, NULL }, /* slteb_u */
2782 { CODE_FOR_insn_slteh, NULL }, /* slteh */
2783 { CODE_FOR_insn_slteh_u, NULL }, /* slteh_u */
2784 { CODE_FOR_insn_slth, NULL }, /* slth */
2785 { CODE_FOR_insn_slth_u, NULL }, /* slth_u */
2786 { CODE_FOR_insn_sltib, NULL }, /* sltib */
2787 { CODE_FOR_insn_sltib_u, NULL }, /* sltib_u */
2788 { CODE_FOR_insn_sltih, NULL }, /* sltih */
2789 { CODE_FOR_insn_sltih_u, NULL }, /* sltih_u */
2790 { CODE_FOR_insn_sne, NULL }, /* sne */
2791 { CODE_FOR_insn_sneb, NULL }, /* sneb */
2792 { CODE_FOR_insn_sneh, NULL }, /* sneh */
2793 { CODE_FOR_ashrsi3, NULL }, /* sra */
2794 { CODE_FOR_insn_srab, NULL }, /* srab */
2795 { CODE_FOR_insn_srah, NULL }, /* srah */
2796 { CODE_FOR_insn_srab, NULL }, /* sraib */
2797 { CODE_FOR_insn_srah, NULL }, /* sraih */
2798 { CODE_FOR_subsi3, NULL }, /* sub */
2799 { CODE_FOR_insn_subb, NULL }, /* subb */
2800 { CODE_FOR_insn_subbs_u, NULL }, /* subbs_u */
2801 { CODE_FOR_insn_subh, NULL }, /* subh */
2802 { CODE_FOR_insn_subhs, NULL }, /* subhs */
2803 { CODE_FOR_sssubsi3, NULL }, /* subs */
2804 { CODE_FOR_insn_sw, NULL }, /* sw */
2805 { CODE_FOR_insn_tblidxb0, NULL }, /* tblidxb0 */
2806 { CODE_FOR_insn_tblidxb1, NULL }, /* tblidxb1 */
2807 { CODE_FOR_insn_tblidxb2, NULL }, /* tblidxb2 */
2808 { CODE_FOR_insn_tblidxb3, NULL }, /* tblidxb3 */
2809 { CODE_FOR_insn_tns, NULL }, /* tns */
2810 { CODE_FOR_insn_wh64, NULL }, /* wh64 */
2811 { CODE_FOR_xorsi3, NULL }, /* xor */
2812 { CODE_FOR_tilepro_network_barrier, NULL }, /* network_barrier */
2813 { CODE_FOR_tilepro_idn0_receive, NULL }, /* idn0_receive */
2814 { CODE_FOR_tilepro_idn1_receive, NULL }, /* idn1_receive */
2815 { CODE_FOR_tilepro_idn_send, NULL }, /* idn_send */
2816 { CODE_FOR_tilepro_sn_receive, NULL }, /* sn_receive */
2817 { CODE_FOR_tilepro_sn_send, NULL }, /* sn_send */
2818 { CODE_FOR_tilepro_udn0_receive, NULL }, /* udn0_receive */
2819 { CODE_FOR_tilepro_udn1_receive, NULL }, /* udn1_receive */
2820 { CODE_FOR_tilepro_udn2_receive, NULL }, /* udn2_receive */
2821 { CODE_FOR_tilepro_udn3_receive, NULL }, /* udn3_receive */
2822 { CODE_FOR_tilepro_udn_send, NULL }, /* udn_send */
2826 struct tilepro_builtin_def
2828 const char *name;
2829 enum tilepro_builtin code;
2830 bool is_const;
2831 /* The first character is the return type. Subsequent characters
2832 are the argument types. See char_to_type. */
2833 const char *type;
2837 static const struct tilepro_builtin_def tilepro_builtins[] = {
2838 { "__insn_add", TILEPRO_INSN_ADD, true, "lll" },
2839 { "__insn_addb", TILEPRO_INSN_ADDB, true, "lll" },
2840 { "__insn_addbs_u", TILEPRO_INSN_ADDBS_U, false, "lll" },
2841 { "__insn_addh", TILEPRO_INSN_ADDH, true, "lll" },
2842 { "__insn_addhs", TILEPRO_INSN_ADDHS, false, "lll" },
2843 { "__insn_addi", TILEPRO_INSN_ADD, true, "lll" },
2844 { "__insn_addib", TILEPRO_INSN_ADDIB, true, "lll" },
2845 { "__insn_addih", TILEPRO_INSN_ADDIH, true, "lll" },
2846 { "__insn_addli", TILEPRO_INSN_ADD, true, "lll" },
2847 { "__insn_addlis", TILEPRO_INSN_ADDLIS, false, "lll" },
2848 { "__insn_adds", TILEPRO_INSN_ADDS, false, "lll" },
2849 { "__insn_adiffb_u", TILEPRO_INSN_ADIFFB_U, true, "lll" },
2850 { "__insn_adiffh", TILEPRO_INSN_ADIFFH, true, "lll" },
2851 { "__insn_and", TILEPRO_INSN_AND, true, "lll" },
2852 { "__insn_andi", TILEPRO_INSN_AND, true, "lll" },
2853 { "__insn_auli", TILEPRO_INSN_AULI, true, "lll" },
2854 { "__insn_avgb_u", TILEPRO_INSN_AVGB_U, true, "lll" },
2855 { "__insn_avgh", TILEPRO_INSN_AVGH, true, "lll" },
2856 { "__insn_bitx", TILEPRO_INSN_BITX, true, "ll" },
2857 { "__insn_bytex", TILEPRO_INSN_BYTEX, true, "ll" },
2858 { "__insn_clz", TILEPRO_INSN_CLZ, true, "ll" },
2859 { "__insn_crc32_32", TILEPRO_INSN_CRC32_32, true, "lll" },
2860 { "__insn_crc32_8", TILEPRO_INSN_CRC32_8, true, "lll" },
2861 { "__insn_ctz", TILEPRO_INSN_CTZ, true, "ll" },
2862 { "__insn_drain", TILEPRO_INSN_DRAIN, false, "v" },
2863 { "__insn_dtlbpr", TILEPRO_INSN_DTLBPR, false, "vl" },
2864 { "__insn_dword_align", TILEPRO_INSN_DWORD_ALIGN, true, "lllk" },
2865 { "__insn_finv", TILEPRO_INSN_FINV, false, "vk" },
2866 { "__insn_flush", TILEPRO_INSN_FLUSH, false, "vk" },
2867 { "__insn_fnop", TILEPRO_INSN_FNOP, false, "v" },
2868 { "__insn_icoh", TILEPRO_INSN_ICOH, false, "vk" },
2869 { "__insn_ill", TILEPRO_INSN_ILL, false, "v" },
2870 { "__insn_info", TILEPRO_INSN_INFO, false, "vl" },
2871 { "__insn_infol", TILEPRO_INSN_INFOL, false, "vl" },
2872 { "__insn_inthb", TILEPRO_INSN_INTHB, true, "lll" },
2873 { "__insn_inthh", TILEPRO_INSN_INTHH, true, "lll" },
2874 { "__insn_intlb", TILEPRO_INSN_INTLB, true, "lll" },
2875 { "__insn_intlh", TILEPRO_INSN_INTLH, true, "lll" },
2876 { "__insn_inv", TILEPRO_INSN_INV, false, "vp" },
2877 { "__insn_lb", TILEPRO_INSN_LB, false, "lk" },
2878 { "__insn_lb_u", TILEPRO_INSN_LB_U, false, "lk" },
2879 { "__insn_lh", TILEPRO_INSN_LH, false, "lk" },
2880 { "__insn_lh_u", TILEPRO_INSN_LH_U, false, "lk" },
2881 { "__insn_lnk", TILEPRO_INSN_LNK, true, "l" },
2882 { "__insn_lw", TILEPRO_INSN_LW, false, "lk" },
2883 { "__insn_lw_na", TILEPRO_INSN_LW_NA, false, "lk" },
2884 { "__insn_lb_L2", TILEPRO_INSN_LB_L2, false, "lk" },
2885 { "__insn_lb_u_L2", TILEPRO_INSN_LB_U_L2, false, "lk" },
2886 { "__insn_lh_L2", TILEPRO_INSN_LH_L2, false, "lk" },
2887 { "__insn_lh_u_L2", TILEPRO_INSN_LH_U_L2, false, "lk" },
2888 { "__insn_lw_L2", TILEPRO_INSN_LW_L2, false, "lk" },
2889 { "__insn_lw_na_L2", TILEPRO_INSN_LW_NA_L2, false, "lk" },
2890 { "__insn_lb_miss", TILEPRO_INSN_LB_MISS, false, "lk" },
2891 { "__insn_lb_u_miss", TILEPRO_INSN_LB_U_MISS, false, "lk" },
2892 { "__insn_lh_miss", TILEPRO_INSN_LH_MISS, false, "lk" },
2893 { "__insn_lh_u_miss", TILEPRO_INSN_LH_U_MISS, false, "lk" },
2894 { "__insn_lw_miss", TILEPRO_INSN_LW_MISS, false, "lk" },
2895 { "__insn_lw_na_miss", TILEPRO_INSN_LW_NA_MISS, false, "lk" },
2896 { "__insn_maxb_u", TILEPRO_INSN_MAXB_U, true, "lll" },
2897 { "__insn_maxh", TILEPRO_INSN_MAXH, true, "lll" },
2898 { "__insn_maxib_u", TILEPRO_INSN_MAXIB_U, true, "lll" },
2899 { "__insn_maxih", TILEPRO_INSN_MAXIH, true, "lll" },
2900 { "__insn_mf", TILEPRO_INSN_MF, false, "v" },
2901 { "__insn_mfspr", TILEPRO_INSN_MFSPR, false, "ll" },
2902 { "__insn_minb_u", TILEPRO_INSN_MINB_U, true, "lll" },
2903 { "__insn_minh", TILEPRO_INSN_MINH, true, "lll" },
2904 { "__insn_minib_u", TILEPRO_INSN_MINIB_U, true, "lll" },
2905 { "__insn_minih", TILEPRO_INSN_MINIH, true, "lll" },
2906 { "__insn_mm", TILEPRO_INSN_MM, true, "lllll" },
2907 { "__insn_mnz", TILEPRO_INSN_MNZ, true, "lll" },
2908 { "__insn_mnzb", TILEPRO_INSN_MNZB, true, "lll" },
2909 { "__insn_mnzh", TILEPRO_INSN_MNZH, true, "lll" },
2910 { "__insn_move", TILEPRO_INSN_MOVE, true, "ll" },
2911 { "__insn_movei", TILEPRO_INSN_MOVE, true, "ll" },
2912 { "__insn_moveli", TILEPRO_INSN_MOVE, true, "ll" },
2913 { "__insn_movelis", TILEPRO_INSN_MOVELIS, false, "ll" },
2914 { "__insn_mtspr", TILEPRO_INSN_MTSPR, false, "vll" },
2915 { "__insn_mulhh_ss", TILEPRO_INSN_MULHH_SS, true, "lll" },
2916 { "__insn_mulhh_su", TILEPRO_INSN_MULHH_SU, true, "lll" },
2917 { "__insn_mulhh_uu", TILEPRO_INSN_MULHH_UU, true, "lll" },
2918 { "__insn_mulhha_ss", TILEPRO_INSN_MULHHA_SS, true, "llll" },
2919 { "__insn_mulhha_su", TILEPRO_INSN_MULHHA_SU, true, "llll" },
2920 { "__insn_mulhha_uu", TILEPRO_INSN_MULHHA_UU, true, "llll" },
2921 { "__insn_mulhhsa_uu", TILEPRO_INSN_MULHHSA_UU, true, "llll" },
2922 { "__insn_mulhl_ss", TILEPRO_INSN_MULHL_SS, true, "lll" },
2923 { "__insn_mulhl_su", TILEPRO_INSN_MULHL_SU, true, "lll" },
2924 { "__insn_mulhl_us", TILEPRO_INSN_MULHL_US, true, "lll" },
2925 { "__insn_mulhl_uu", TILEPRO_INSN_MULHL_UU, true, "lll" },
2926 { "__insn_mulhla_ss", TILEPRO_INSN_MULHLA_SS, true, "llll" },
2927 { "__insn_mulhla_su", TILEPRO_INSN_MULHLA_SU, true, "llll" },
2928 { "__insn_mulhla_us", TILEPRO_INSN_MULHLA_US, true, "llll" },
2929 { "__insn_mulhla_uu", TILEPRO_INSN_MULHLA_UU, true, "llll" },
2930 { "__insn_mulhlsa_uu", TILEPRO_INSN_MULHLSA_UU, true, "llll" },
2931 { "__insn_mulll_ss", TILEPRO_INSN_MULLL_SS, true, "lll" },
2932 { "__insn_mulll_su", TILEPRO_INSN_MULLL_SU, true, "lll" },
2933 { "__insn_mulll_uu", TILEPRO_INSN_MULLL_UU, true, "lll" },
2934 { "__insn_mullla_ss", TILEPRO_INSN_MULLLA_SS, true, "llll" },
2935 { "__insn_mullla_su", TILEPRO_INSN_MULLLA_SU, true, "llll" },
2936 { "__insn_mullla_uu", TILEPRO_INSN_MULLLA_UU, true, "llll" },
2937 { "__insn_mulllsa_uu", TILEPRO_INSN_MULLLSA_UU, true, "llll" },
2938 { "__insn_mvnz", TILEPRO_INSN_MVNZ, true, "llll" },
2939 { "__insn_mvz", TILEPRO_INSN_MVZ, true, "llll" },
2940 { "__insn_mz", TILEPRO_INSN_MZ, true, "lll" },
2941 { "__insn_mzb", TILEPRO_INSN_MZB, true, "lll" },
2942 { "__insn_mzh", TILEPRO_INSN_MZH, true, "lll" },
2943 { "__insn_nap", TILEPRO_INSN_NAP, false, "v" },
2944 { "__insn_nop", TILEPRO_INSN_NOP, true, "v" },
2945 { "__insn_nor", TILEPRO_INSN_NOR, true, "lll" },
2946 { "__insn_or", TILEPRO_INSN_OR, true, "lll" },
2947 { "__insn_ori", TILEPRO_INSN_OR, true, "lll" },
2948 { "__insn_packbs_u", TILEPRO_INSN_PACKBS_U, false, "lll" },
2949 { "__insn_packhb", TILEPRO_INSN_PACKHB, true, "lll" },
2950 { "__insn_packhs", TILEPRO_INSN_PACKHS, false, "lll" },
2951 { "__insn_packlb", TILEPRO_INSN_PACKLB, true, "lll" },
2952 { "__insn_pcnt", TILEPRO_INSN_PCNT, true, "ll" },
2953 { "__insn_prefetch", TILEPRO_INSN_PREFETCH, false, "vk" },
2954 { "__insn_prefetch_L1", TILEPRO_INSN_PREFETCH_L1, false, "vk" },
2955 { "__insn_rl", TILEPRO_INSN_RL, true, "lll" },
2956 { "__insn_rli", TILEPRO_INSN_RL, true, "lll" },
2957 { "__insn_s1a", TILEPRO_INSN_S1A, true, "lll" },
2958 { "__insn_s2a", TILEPRO_INSN_S2A, true, "lll" },
2959 { "__insn_s3a", TILEPRO_INSN_S3A, true, "lll" },
2960 { "__insn_sadab_u", TILEPRO_INSN_SADAB_U, true, "llll" },
2961 { "__insn_sadah", TILEPRO_INSN_SADAH, true, "llll" },
2962 { "__insn_sadah_u", TILEPRO_INSN_SADAH_U, true, "llll" },
2963 { "__insn_sadb_u", TILEPRO_INSN_SADB_U, true, "lll" },
2964 { "__insn_sadh", TILEPRO_INSN_SADH, true, "lll" },
2965 { "__insn_sadh_u", TILEPRO_INSN_SADH_U, true, "lll" },
2966 { "__insn_sb", TILEPRO_INSN_SB, false, "vpl" },
2967 { "__insn_seq", TILEPRO_INSN_SEQ, true, "lll" },
2968 { "__insn_seqb", TILEPRO_INSN_SEQB, true, "lll" },
2969 { "__insn_seqh", TILEPRO_INSN_SEQH, true, "lll" },
2970 { "__insn_seqi", TILEPRO_INSN_SEQ, true, "lll" },
2971 { "__insn_seqib", TILEPRO_INSN_SEQIB, true, "lll" },
2972 { "__insn_seqih", TILEPRO_INSN_SEQIH, true, "lll" },
2973 { "__insn_sh", TILEPRO_INSN_SH, false, "vpl" },
2974 { "__insn_shl", TILEPRO_INSN_SHL, true, "lll" },
2975 { "__insn_shlb", TILEPRO_INSN_SHLB, true, "lll" },
2976 { "__insn_shlh", TILEPRO_INSN_SHLH, true, "lll" },
2977 { "__insn_shli", TILEPRO_INSN_SHL, true, "lll" },
2978 { "__insn_shlib", TILEPRO_INSN_SHLIB, true, "lll" },
2979 { "__insn_shlih", TILEPRO_INSN_SHLIH, true, "lll" },
2980 { "__insn_shr", TILEPRO_INSN_SHR, true, "lll" },
2981 { "__insn_shrb", TILEPRO_INSN_SHRB, true, "lll" },
2982 { "__insn_shrh", TILEPRO_INSN_SHRH, true, "lll" },
2983 { "__insn_shri", TILEPRO_INSN_SHR, true, "lll" },
2984 { "__insn_shrib", TILEPRO_INSN_SHRIB, true, "lll" },
2985 { "__insn_shrih", TILEPRO_INSN_SHRIH, true, "lll" },
2986 { "__insn_slt", TILEPRO_INSN_SLT, true, "lll" },
2987 { "__insn_slt_u", TILEPRO_INSN_SLT_U, true, "lll" },
2988 { "__insn_sltb", TILEPRO_INSN_SLTB, true, "lll" },
2989 { "__insn_sltb_u", TILEPRO_INSN_SLTB_U, true, "lll" },
2990 { "__insn_slte", TILEPRO_INSN_SLTE, true, "lll" },
2991 { "__insn_slte_u", TILEPRO_INSN_SLTE_U, true, "lll" },
2992 { "__insn_slteb", TILEPRO_INSN_SLTEB, true, "lll" },
2993 { "__insn_slteb_u", TILEPRO_INSN_SLTEB_U, true, "lll" },
2994 { "__insn_slteh", TILEPRO_INSN_SLTEH, true, "lll" },
2995 { "__insn_slteh_u", TILEPRO_INSN_SLTEH_U, true, "lll" },
2996 { "__insn_slth", TILEPRO_INSN_SLTH, true, "lll" },
2997 { "__insn_slth_u", TILEPRO_INSN_SLTH_U, true, "lll" },
2998 { "__insn_slti", TILEPRO_INSN_SLT, true, "lll" },
2999 { "__insn_slti_u", TILEPRO_INSN_SLT_U, true, "lll" },
3000 { "__insn_sltib", TILEPRO_INSN_SLTIB, true, "lll" },
3001 { "__insn_sltib_u", TILEPRO_INSN_SLTIB_U, true, "lll" },
3002 { "__insn_sltih", TILEPRO_INSN_SLTIH, true, "lll" },
3003 { "__insn_sltih_u", TILEPRO_INSN_SLTIH_U, true, "lll" },
3004 { "__insn_sne", TILEPRO_INSN_SNE, true, "lll" },
3005 { "__insn_sneb", TILEPRO_INSN_SNEB, true, "lll" },
3006 { "__insn_sneh", TILEPRO_INSN_SNEH, true, "lll" },
3007 { "__insn_sra", TILEPRO_INSN_SRA, true, "lll" },
3008 { "__insn_srab", TILEPRO_INSN_SRAB, true, "lll" },
3009 { "__insn_srah", TILEPRO_INSN_SRAH, true, "lll" },
3010 { "__insn_srai", TILEPRO_INSN_SRA, true, "lll" },
3011 { "__insn_sraib", TILEPRO_INSN_SRAIB, true, "lll" },
3012 { "__insn_sraih", TILEPRO_INSN_SRAIH, true, "lll" },
3013 { "__insn_sub", TILEPRO_INSN_SUB, true, "lll" },
3014 { "__insn_subb", TILEPRO_INSN_SUBB, true, "lll" },
3015 { "__insn_subbs_u", TILEPRO_INSN_SUBBS_U, false, "lll" },
3016 { "__insn_subh", TILEPRO_INSN_SUBH, true, "lll" },
3017 { "__insn_subhs", TILEPRO_INSN_SUBHS, false, "lll" },
3018 { "__insn_subs", TILEPRO_INSN_SUBS, false, "lll" },
3019 { "__insn_sw", TILEPRO_INSN_SW, false, "vpl" },
3020 { "__insn_tblidxb0", TILEPRO_INSN_TBLIDXB0, true, "lll" },
3021 { "__insn_tblidxb1", TILEPRO_INSN_TBLIDXB1, true, "lll" },
3022 { "__insn_tblidxb2", TILEPRO_INSN_TBLIDXB2, true, "lll" },
3023 { "__insn_tblidxb3", TILEPRO_INSN_TBLIDXB3, true, "lll" },
3024 { "__insn_tns", TILEPRO_INSN_TNS, false, "lp" },
3025 { "__insn_wh64", TILEPRO_INSN_WH64, false, "vp" },
3026 { "__insn_xor", TILEPRO_INSN_XOR, true, "lll" },
3027 { "__insn_xori", TILEPRO_INSN_XOR, true, "lll" },
3028 { "__tile_network_barrier", TILEPRO_NETWORK_BARRIER, false, "v" },
3029 { "__tile_idn0_receive", TILEPRO_IDN0_RECEIVE, false, "l" },
3030 { "__tile_idn1_receive", TILEPRO_IDN1_RECEIVE, false, "l" },
3031 { "__tile_idn_send", TILEPRO_IDN_SEND, false, "vl" },
3032 { "__tile_sn_receive", TILEPRO_SN_RECEIVE, false, "l" },
3033 { "__tile_sn_send", TILEPRO_SN_SEND, false, "vl" },
3034 { "__tile_udn0_receive", TILEPRO_UDN0_RECEIVE, false, "l" },
3035 { "__tile_udn1_receive", TILEPRO_UDN1_RECEIVE, false, "l" },
3036 { "__tile_udn2_receive", TILEPRO_UDN2_RECEIVE, false, "l" },
3037 { "__tile_udn3_receive", TILEPRO_UDN3_RECEIVE, false, "l" },
3038 { "__tile_udn_send", TILEPRO_UDN_SEND, false, "vl" },
3042 /* Convert a character in a builtin type string to a tree type. */
3043 static tree
3044 char_to_type (char c)
3046 static tree volatile_ptr_type_node = NULL;
3047 static tree volatile_const_ptr_type_node = NULL;
3049 if (volatile_ptr_type_node == NULL)
3051 volatile_ptr_type_node =
3052 build_pointer_type (build_qualified_type (void_type_node,
3053 TYPE_QUAL_VOLATILE));
3054 volatile_const_ptr_type_node =
3055 build_pointer_type (build_qualified_type (void_type_node,
3056 TYPE_QUAL_CONST
3057 | TYPE_QUAL_VOLATILE));
3060 switch (c)
3062 case 'v':
3063 return void_type_node;
3064 case 'l':
3065 return long_unsigned_type_node;
3066 case 'p':
3067 return volatile_ptr_type_node;
3068 case 'k':
3069 return volatile_const_ptr_type_node;
3070 default:
3071 gcc_unreachable ();
3076 /* Implement TARGET_INIT_BUILTINS. */
3077 static void
3078 tilepro_init_builtins (void)
3080 size_t i;
3082 for (i = 0; i < ARRAY_SIZE (tilepro_builtins); i++)
3084 const struct tilepro_builtin_def *p = &tilepro_builtins[i];
3085 tree ftype, ret_type, arg_type_list = void_list_node;
3086 tree decl;
3087 int j;
3089 for (j = strlen (p->type) - 1; j > 0; j--)
3091 arg_type_list =
3092 tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list);
3095 ret_type = char_to_type (p->type[0]);
3097 ftype = build_function_type (ret_type, arg_type_list);
3099 decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
3100 NULL, NULL);
3102 if (p->is_const)
3103 TREE_READONLY (decl) = 1;
3104 TREE_NOTHROW (decl) = 1;
3106 if (tilepro_builtin_info[p->code].fndecl == NULL)
3107 tilepro_builtin_info[p->code].fndecl = decl;
3112 /* Implement TARGET_EXPAND_BUILTIN. */
3113 static rtx
3114 tilepro_expand_builtin (tree exp,
3115 rtx target,
3116 rtx subtarget ATTRIBUTE_UNUSED,
3117 machine_mode mode ATTRIBUTE_UNUSED,
3118 int ignore ATTRIBUTE_UNUSED)
3120 #define MAX_BUILTIN_ARGS 4
3122 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
3123 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
3124 tree arg;
3125 call_expr_arg_iterator iter;
3126 enum insn_code icode;
3127 rtx op[MAX_BUILTIN_ARGS + 1], pat;
3128 int opnum;
3129 bool nonvoid;
3130 insn_gen_fn fn;
3132 if (fcode >= TILEPRO_BUILTIN_max)
3133 internal_error ("bad builtin fcode");
3134 icode = tilepro_builtin_info[fcode].icode;
3135 if (icode == 0)
3136 internal_error ("bad builtin icode");
3138 nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
3140 opnum = nonvoid;
3141 FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
3143 const struct insn_operand_data *insn_op;
3145 if (arg == error_mark_node)
3146 return NULL_RTX;
3147 if (opnum > MAX_BUILTIN_ARGS)
3148 return NULL_RTX;
3150 insn_op = &insn_data[icode].operand[opnum];
3152 op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL);
3154 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3155 op[opnum] = copy_to_mode_reg (insn_op->mode, op[opnum]);
3157 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3159 /* We still failed to meet the predicate even after moving
3160 into a register. Assume we needed an immediate. */
3161 error_at (EXPR_LOCATION (exp),
3162 "operand must be an immediate of the right size");
3163 return const0_rtx;
3166 opnum++;
3169 if (nonvoid)
3171 machine_mode tmode = insn_data[icode].operand[0].mode;
3172 if (!target
3173 || GET_MODE (target) != tmode
3174 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
3175 target = gen_reg_rtx (tmode);
3176 op[0] = target;
3179 fn = GEN_FCN (icode);
3180 switch (opnum)
3182 case 0:
3183 pat = fn (NULL_RTX);
3184 break;
3185 case 1:
3186 pat = fn (op[0]);
3187 break;
3188 case 2:
3189 pat = fn (op[0], op[1]);
3190 break;
3191 case 3:
3192 pat = fn (op[0], op[1], op[2]);
3193 break;
3194 case 4:
3195 pat = fn (op[0], op[1], op[2], op[3]);
3196 break;
3197 case 5:
3198 pat = fn (op[0], op[1], op[2], op[3], op[4]);
3199 break;
3200 default:
3201 gcc_unreachable ();
3203 if (!pat)
3204 return NULL_RTX;
3206 /* If we are generating a prefetch, tell the scheduler not to move
3207 it around. */
3208 if (GET_CODE (pat) == PREFETCH)
3209 PREFETCH_SCHEDULE_BARRIER_P (pat) = true;
3211 emit_insn (pat);
3213 if (nonvoid)
3214 return target;
3215 else
3216 return const0_rtx;
3220 /* Implement TARGET_BUILTIN_DECL. */
3221 static tree
3222 tilepro_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
3224 if (code >= TILEPRO_BUILTIN_max)
3225 return error_mark_node;
3227 return tilepro_builtin_info[code].fndecl;
3232 /* Stack frames */
3234 /* Return whether REGNO needs to be saved in the stack frame. */
3235 static bool
3236 need_to_save_reg (unsigned int regno)
3238 if (!fixed_regs[regno] && !call_used_regs[regno]
3239 && df_regs_ever_live_p (regno))
3240 return true;
3242 if (flag_pic
3243 && (regno == PIC_OFFSET_TABLE_REGNUM
3244 || regno == TILEPRO_PIC_TEXT_LABEL_REGNUM)
3245 && (crtl->uses_pic_offset_table || crtl->saves_all_registers))
3246 return true;
3248 if (crtl->calls_eh_return)
3250 unsigned i;
3251 for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++)
3253 if (regno == EH_RETURN_DATA_REGNO (i))
3254 return true;
3258 return false;
3262 /* Return the size of the register savev area. This function is only
3263 correct starting with local register allocation */
3264 static int
3265 tilepro_saved_regs_size (void)
3267 int reg_save_size = 0;
3268 int regno;
3269 int offset_to_frame;
3270 int align_mask;
3272 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3273 if (need_to_save_reg (regno))
3274 reg_save_size += UNITS_PER_WORD;
3276 /* Pad out the register save area if necessary to make
3277 frame_pointer_rtx be as aligned as the stack pointer. */
3278 offset_to_frame = crtl->args.pretend_args_size + reg_save_size;
3279 align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1;
3280 reg_save_size += (-offset_to_frame) & align_mask;
3282 return reg_save_size;
3286 /* Round up frame size SIZE. */
3287 static int
3288 round_frame_size (int size)
3290 return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1)
3291 & -STACK_BOUNDARY / BITS_PER_UNIT);
3295 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3296 emit the corresponding REG_CFA_OFFSET note described by CFA and
3297 CFA_OFFSET. Return the emitted insn. */
3298 static rtx
3299 frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa,
3300 int cfa_offset)
3302 rtx reg = gen_rtx_REG (Pmode, regno);
3303 rtx mem = gen_frame_mem (Pmode, addr);
3304 rtx mov = gen_movsi (mem, reg);
3306 /* Describe what just happened in a way that dwarf understands. We
3307 use temporary registers to hold the address to make scheduling
3308 easier, and use the REG_CFA_OFFSET to describe the address as an
3309 offset from the CFA. */
3310 rtx reg_note = gen_rtx_REG (Pmode, regno_note);
3311 rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, gen_int_si (cfa_offset));
3312 rtx cfa_relative_mem = gen_frame_mem (Pmode, cfa_relative_addr);
3313 rtx real = gen_rtx_SET (cfa_relative_mem, reg_note);
3314 add_reg_note (mov, REG_CFA_OFFSET, real);
3316 return emit_insn (mov);
3320 /* Emit a load in the stack frame to load REGNO from address ADDR.
3321 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3322 non-null. Return the emitted insn. */
3323 static rtx_insn *
3324 frame_emit_load (int regno, rtx addr, rtx *cfa_restores)
3326 rtx reg = gen_rtx_REG (Pmode, regno);
3327 rtx mem = gen_frame_mem (Pmode, addr);
3328 if (cfa_restores)
3329 *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores);
3330 return emit_insn (gen_movsi (reg, mem));
3334 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3335 including sequences. */
3336 static rtx_insn *
3337 set_frame_related_p (void)
3339 rtx_insn *seq = get_insns ();
3340 rtx_insn *insn;
3342 end_sequence ();
3344 if (!seq)
3345 return NULL;
3347 if (INSN_P (seq))
3349 insn = seq;
3350 while (insn != NULL_RTX)
3352 RTX_FRAME_RELATED_P (insn) = 1;
3353 insn = NEXT_INSN (insn);
3355 seq = emit_insn (seq);
3357 else
3359 seq = emit_insn (seq);
3360 RTX_FRAME_RELATED_P (seq) = 1;
3362 return seq;
3366 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3368 /* This emits code for 'sp += offset'.
3370 The ABI only allows us to modify 'sp' in a single 'addi' or
3371 'addli', so the backtracer understands it. Larger amounts cannot
3372 use those instructions, so are added by placing the offset into a
3373 large register and using 'add'.
3375 This happens after reload, so we need to expand it ourselves. */
3376 static rtx_insn *
3377 emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related,
3378 rtx reg_notes)
3380 rtx to_add;
3381 rtx imm_rtx = gen_int_si (offset);
3383 rtx_insn *insn;
3384 if (satisfies_constraint_J (imm_rtx))
3386 /* We can add this using a single addi or addli. */
3387 to_add = imm_rtx;
3389 else
3391 rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3392 tilepro_expand_set_const32 (tmp, imm_rtx);
3393 to_add = tmp;
3396 /* Actually adjust the stack pointer. */
3397 insn = emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
3398 to_add));
3399 REG_NOTES (insn) = reg_notes;
3401 /* Describe what just happened in a way that dwarf understands. */
3402 if (frame_related)
3404 rtx real = gen_rtx_SET (stack_pointer_rtx,
3405 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3406 imm_rtx));
3407 RTX_FRAME_RELATED_P (insn) = 1;
3408 add_reg_note (insn, REG_CFA_ADJUST_CFA, real);
3411 return insn;
3415 /* Return whether the current function is leaf. This takes into
3416 account whether the function calls tls_get_addr. */
3417 static bool
3418 tilepro_current_function_is_leaf (void)
3420 return crtl->is_leaf && !cfun->machine->calls_tls_get_addr;
3424 /* Return the frame size. */
3425 static int
3426 compute_total_frame_size (void)
3428 int total_size = (get_frame_size () + tilepro_saved_regs_size ()
3429 + crtl->outgoing_args_size
3430 + crtl->args.pretend_args_size);
3432 if (!tilepro_current_function_is_leaf () || cfun->calls_alloca)
3434 /* Make room for save area in callee. */
3435 total_size += STACK_POINTER_OFFSET;
3438 return round_frame_size (total_size);
3442 /* Return nonzero if this function is known to have a null epilogue.
3443 This allows the optimizer to omit jumps to jumps if no stack was
3444 created. */
3445 bool
3446 tilepro_can_use_return_insn_p (void)
3448 return (reload_completed
3449 && cfun->static_chain_decl == 0
3450 && compute_total_frame_size () == 0
3451 && tilepro_current_function_is_leaf ()
3452 && !crtl->profile && !df_regs_ever_live_p (TILEPRO_LINK_REGNUM));
3456 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3457 is a frame pointer, it computes the value relative to
3458 that. Otherwise it uses the stack pointer. */
3459 static rtx
3460 compute_frame_addr (int offset_from_fp, int *next_scratch_regno)
3462 rtx base_reg_rtx, tmp_reg_rtx, offset_rtx;
3463 int offset_from_base;
3465 if (frame_pointer_needed)
3467 base_reg_rtx = hard_frame_pointer_rtx;
3468 offset_from_base = offset_from_fp;
3470 else
3472 int offset_from_sp = compute_total_frame_size () + offset_from_fp;
3473 base_reg_rtx = stack_pointer_rtx;
3474 offset_from_base = offset_from_sp;
3477 if (offset_from_base == 0)
3478 return base_reg_rtx;
3480 /* Compute the new value of the stack pointer. */
3481 tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3482 offset_rtx = gen_int_si (offset_from_base);
3484 if (!tilepro_expand_addsi (tmp_reg_rtx, base_reg_rtx, offset_rtx))
3486 emit_insn (gen_rtx_SET (tmp_reg_rtx,
3487 gen_rtx_PLUS (Pmode, base_reg_rtx,
3488 offset_rtx)));
3491 return tmp_reg_rtx;
3495 /* The stack frame looks like this:
3496 +-------------+
3497 | ... |
3498 | incoming |
3499 | stack args |
3500 AP -> +-------------+
3501 | caller's HFP|
3502 +-------------+
3503 | lr save |
3504 HFP -> +-------------+
3505 | var args |
3506 | reg save | crtl->args.pretend_args_size bytes
3507 +-------------+
3508 | ... |
3509 | saved regs | tilepro_saved_regs_size() bytes
3510 FP -> +-------------+
3511 | ... |
3512 | vars | get_frame_size() bytes
3513 +-------------+
3514 | ... |
3515 | outgoing |
3516 | stack args | crtl->outgoing_args_size bytes
3517 +-------------+
3518 | HFP | 4 bytes (only here if nonleaf / alloca)
3519 +-------------+
3520 | callee lr | 4 bytes (only here if nonleaf / alloca)
3521 | save |
3522 SP -> +-------------+
3524 HFP == incoming SP.
3526 For functions with a frame larger than 32767 bytes, or which use
3527 alloca (), r52 is used as a frame pointer. Otherwise there is no
3528 frame pointer.
3530 FP is saved at SP+4 before calling a subroutine so the
3531 callee can chain. */
3532 void
3533 tilepro_expand_prologue (void)
3535 #define ROUND_ROBIN_SIZE 4
3536 /* We round-robin through four scratch registers to hold temporary
3537 addresses for saving registers, to make instruction scheduling
3538 easier. */
3539 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3540 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3542 rtx insn, cfa;
3543 unsigned int which_scratch;
3544 int offset, start_offset, regno;
3546 /* A register that holds a copy of the incoming fp. */
3547 int fp_copy_regno = -1;
3549 /* A register that holds a copy of the incoming sp. */
3550 int sp_copy_regno = -1;
3552 /* Next scratch register number to hand out (postdecrementing). */
3553 int next_scratch_regno = 29;
3555 int total_size = compute_total_frame_size ();
3557 if (flag_stack_usage_info)
3558 current_function_static_stack_size = total_size;
3560 /* Save lr first in its special location because code after this
3561 might use the link register as a scratch register. */
3562 if (df_regs_ever_live_p (TILEPRO_LINK_REGNUM) || crtl->calls_eh_return)
3563 FRP (frame_emit_store (TILEPRO_LINK_REGNUM, TILEPRO_LINK_REGNUM,
3564 stack_pointer_rtx, stack_pointer_rtx, 0));
3566 if (total_size == 0)
3568 /* Load the PIC register if needed. */
3569 if (flag_pic && crtl->uses_pic_offset_table)
3570 load_pic_register (false);
3572 return;
3575 cfa = stack_pointer_rtx;
3577 if (frame_pointer_needed)
3579 fp_copy_regno = next_scratch_regno--;
3581 /* Copy the old frame pointer aside so we can save it later. */
3582 insn = FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno),
3583 hard_frame_pointer_rtx));
3584 add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
3586 /* Set up the frame pointer. */
3587 insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
3588 add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx);
3589 cfa = hard_frame_pointer_rtx;
3590 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
3592 /* fp holds a copy of the incoming sp, in case we need to store
3593 it. */
3594 sp_copy_regno = HARD_FRAME_POINTER_REGNUM;
3596 else if (!tilepro_current_function_is_leaf ())
3598 /* Copy the old stack pointer aside so we can save it later. */
3599 sp_copy_regno = next_scratch_regno--;
3600 emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno),
3601 stack_pointer_rtx);
3604 if (tilepro_current_function_is_leaf ())
3606 /* No need to store chain pointer to caller's frame. */
3607 emit_sp_adjust (-total_size, &next_scratch_regno,
3608 !frame_pointer_needed, NULL_RTX);
3610 else
3612 /* Save the frame pointer (incoming sp value) to support
3613 backtracing. First we need to create an rtx with the store
3614 address. */
3615 rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--);
3616 rtx size_rtx = gen_int_si (-(total_size - UNITS_PER_WORD));
3618 if (add_operand (size_rtx, Pmode))
3620 /* Expose more parallelism by computing this value from the
3621 original stack pointer, not the one after we have pushed
3622 the frame. */
3623 rtx p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, size_rtx);
3624 emit_insn (gen_rtx_SET (chain_addr, p));
3625 emit_sp_adjust (-total_size, &next_scratch_regno,
3626 !frame_pointer_needed, NULL_RTX);
3628 else
3630 /* The stack frame is large, so just store the incoming sp
3631 value at *(new_sp + UNITS_PER_WORD). */
3632 rtx p;
3633 emit_sp_adjust (-total_size, &next_scratch_regno,
3634 !frame_pointer_needed, NULL_RTX);
3635 p = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3636 GEN_INT (UNITS_PER_WORD));
3637 emit_insn (gen_rtx_SET (chain_addr, p));
3640 /* Save our frame pointer for backtrace chaining. */
3641 emit_insn (gen_movsi (gen_frame_mem (SImode, chain_addr),
3642 gen_rtx_REG (SImode, sp_copy_regno)));
3645 /* Compute where to start storing registers we need to save. */
3646 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
3647 offset = start_offset;
3649 /* Store all registers that need saving. */
3650 which_scratch = 0;
3651 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
3652 if (need_to_save_reg (regno))
3654 rtx r = reg_save_addr[which_scratch];
3655 int from_regno;
3656 int cfa_offset = frame_pointer_needed ? offset : total_size + offset;
3658 if (r == NULL_RTX)
3660 rtx p = compute_frame_addr (offset, &next_scratch_regno);
3661 r = gen_rtx_REG (word_mode, next_scratch_regno--);
3662 reg_save_addr[which_scratch] = r;
3664 emit_insn (gen_rtx_SET (r, p));
3666 else
3668 /* Advance to the next stack slot to store this register. */
3669 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
3670 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
3671 emit_insn (gen_rtx_SET (r, p));
3674 /* Save this register to the stack (but use the old fp value
3675 we copied aside if appropriate). */
3676 from_regno = (fp_copy_regno >= 0
3677 && regno ==
3678 HARD_FRAME_POINTER_REGNUM) ? fp_copy_regno : regno;
3679 FRP (frame_emit_store (from_regno, regno, r, cfa, cfa_offset));
3681 offset -= UNITS_PER_WORD;
3682 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
3685 /* If profiling, force that to happen after the frame is set up. */
3686 if (crtl->profile)
3687 emit_insn (gen_blockage ());
3689 /* Load the PIC register if needed. */
3690 if (flag_pic && crtl->uses_pic_offset_table)
3691 load_pic_register (false);
3695 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
3696 true for a sibcall_epilogue pattern, and false for an epilogue
3697 pattern. */
3698 void
3699 tilepro_expand_epilogue (bool sibcall_p)
3701 /* We round-robin through four scratch registers to hold temporary
3702 addresses for saving registers, to make instruction scheduling
3703 easier. */
3704 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3705 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3707 rtx_insn *last_insn, *insn;
3708 unsigned int which_scratch;
3709 int offset, start_offset, regno;
3710 rtx cfa_restores = NULL_RTX;
3712 /* A register that holds a copy of the incoming fp. */
3713 int fp_copy_regno = -1;
3715 /* Next scratch register number to hand out (postdecrementing). */
3716 int next_scratch_regno = 29;
3718 int total_size = compute_total_frame_size ();
3720 last_insn = get_last_insn ();
3722 /* Load lr first since we are going to need it first. */
3723 insn = NULL;
3724 if (df_regs_ever_live_p (TILEPRO_LINK_REGNUM))
3726 insn = frame_emit_load (TILEPRO_LINK_REGNUM,
3727 compute_frame_addr (0, &next_scratch_regno),
3728 &cfa_restores);
3731 if (total_size == 0)
3733 if (insn)
3735 RTX_FRAME_RELATED_P (insn) = 1;
3736 REG_NOTES (insn) = cfa_restores;
3738 goto done;
3741 /* Compute where to start restoring registers. */
3742 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
3743 offset = start_offset;
3745 if (frame_pointer_needed)
3746 fp_copy_regno = next_scratch_regno--;
3748 /* Restore all callee-saved registers. */
3749 which_scratch = 0;
3750 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
3751 if (need_to_save_reg (regno))
3753 rtx r = reg_save_addr[which_scratch];
3754 if (r == NULL_RTX)
3756 r = compute_frame_addr (offset, &next_scratch_regno);
3757 reg_save_addr[which_scratch] = r;
3759 else
3761 /* Advance to the next stack slot to store this
3762 register. */
3763 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
3764 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
3765 emit_insn (gen_rtx_SET (r, p));
3768 if (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM)
3769 frame_emit_load (fp_copy_regno, r, NULL);
3770 else
3771 frame_emit_load (regno, r, &cfa_restores);
3773 offset -= UNITS_PER_WORD;
3774 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
3777 if (!tilepro_current_function_is_leaf ())
3778 cfa_restores =
3779 alloc_reg_note (REG_CFA_RESTORE, stack_pointer_rtx, cfa_restores);
3781 emit_insn (gen_blockage ());
3783 if (frame_pointer_needed)
3785 /* Restore the old stack pointer by copying from the frame
3786 pointer. */
3787 insn = emit_insn (gen_sp_restore (stack_pointer_rtx,
3788 hard_frame_pointer_rtx));
3789 RTX_FRAME_RELATED_P (insn) = 1;
3790 REG_NOTES (insn) = cfa_restores;
3791 add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx);
3793 else
3795 insn = emit_sp_adjust (total_size, &next_scratch_regno, true,
3796 cfa_restores);
3799 if (crtl->calls_eh_return)
3800 emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
3801 EH_RETURN_STACKADJ_RTX));
3803 /* Restore the old frame pointer. */
3804 if (frame_pointer_needed)
3806 insn = emit_move_insn (hard_frame_pointer_rtx,
3807 gen_rtx_REG (Pmode, fp_copy_regno));
3808 add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);
3811 /* Mark the pic registers as live outside of the function. */
3812 if (flag_pic)
3814 emit_use (cfun->machine->text_label_rtx);
3815 emit_use (cfun->machine->got_rtx);
3818 done:
3819 if (!sibcall_p)
3821 /* Emit the actual 'return' instruction. */
3822 emit_jump_insn (gen__return ());
3824 else
3826 emit_use (gen_rtx_REG (Pmode, TILEPRO_LINK_REGNUM));
3829 /* Mark all insns we just emitted as frame-related. */
3830 for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn))
3831 RTX_FRAME_RELATED_P (last_insn) = 1;
3834 #undef ROUND_ROBIN_SIZE
3837 /* Implement INITIAL_ELIMINATION_OFFSET. */
3839 tilepro_initial_elimination_offset (int from, int to)
3841 int total_size = compute_total_frame_size ();
3843 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
3845 return (total_size - crtl->args.pretend_args_size
3846 - tilepro_saved_regs_size ());
3848 else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
3850 return -(crtl->args.pretend_args_size + tilepro_saved_regs_size ());
3852 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
3854 return STACK_POINTER_OFFSET + total_size;
3856 else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
3858 return STACK_POINTER_OFFSET;
3860 else
3861 gcc_unreachable ();
3865 /* Return an RTX indicating where the return address to the
3866 calling function can be found. */
3868 tilepro_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3870 if (count != 0)
3871 return const0_rtx;
3873 return get_hard_reg_initial_val (Pmode, TILEPRO_LINK_REGNUM);
3877 /* Implement EH_RETURN_HANDLER_RTX. */
3879 tilepro_eh_return_handler_rtx (void)
3881 /* The MEM needs to be volatile to prevent it from being
3882 deleted. */
3883 rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
3884 MEM_VOLATILE_P (tmp) = true;
3885 return tmp;
3890 /* Registers */
3892 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
3893 static void
3894 tilepro_conditional_register_usage (void)
3896 global_regs[TILEPRO_NETORDER_REGNUM] = 1;
3897 /* TILEPRO_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
3898 member of fixed_regs, and therefore must be member of
3899 call_used_regs, but it is not a member of call_really_used_regs[]
3900 because it is not clobbered by a call. */
3901 if (TILEPRO_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM)
3903 fixed_regs[TILEPRO_PIC_TEXT_LABEL_REGNUM] = 1;
3904 call_used_regs[TILEPRO_PIC_TEXT_LABEL_REGNUM] = 1;
3906 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
3908 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
3909 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
3914 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3915 static bool
3916 tilepro_frame_pointer_required (void)
3918 return crtl->calls_eh_return || cfun->calls_alloca;
3923 /* Scheduling and reorg */
3925 /* Return the length of INSN. LENGTH is the initial length computed
3926 by attributes in the machine-description file. This is where we
3927 account for bundles. */
3929 tilepro_adjust_insn_length (rtx_insn *insn, int length)
3931 machine_mode mode = GET_MODE (insn);
3933 /* A non-termininating instruction in a bundle has length 0. */
3934 if (mode == SImode)
3935 return 0;
3937 /* By default, there is not length adjustment. */
3938 return length;
3942 /* Implement TARGET_SCHED_ISSUE_RATE. */
3943 static int
3944 tilepro_issue_rate (void)
3946 return 3;
3950 /* Return the rtx for the jump target. */
3951 static rtx
3952 get_jump_target (rtx branch)
3954 if (CALL_P (branch))
3956 rtx call;
3957 call = PATTERN (branch);
3959 if (GET_CODE (call) == PARALLEL)
3960 call = XVECEXP (call, 0, 0);
3962 if (GET_CODE (call) == SET)
3963 call = SET_SRC (call);
3965 if (GET_CODE (call) == CALL)
3966 return XEXP (XEXP (call, 0), 0);
3968 return 0;
3971 /* Implement TARGET_SCHED_ADJUST_COST. */
3972 static int
3973 tilepro_sched_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn,
3974 int cost)
3976 /* If we have a true dependence, INSN is a call, and DEP_INSN
3977 defines a register that is needed by the call (argument or stack
3978 pointer), set its latency to 0 so that it can be bundled with
3979 the call. Explicitly check for and exclude the case when
3980 DEP_INSN defines the target of the jump. */
3981 if (CALL_P (insn) && REG_NOTE_KIND (link) == REG_DEP_TRUE)
3983 rtx target = get_jump_target (insn);
3984 if (!REG_P (target) || !set_of (target, dep_insn))
3985 return 0;
3988 return cost;
3992 /* Skip over irrelevant NOTEs and such and look for the next insn we
3993 would consider bundling. */
3994 static rtx_insn *
3995 next_insn_to_bundle (rtx_insn *r, rtx_insn *end)
3997 for (; r != end; r = NEXT_INSN (r))
3999 if (NONDEBUG_INSN_P (r)
4000 && GET_CODE (PATTERN (r)) != USE
4001 && GET_CODE (PATTERN (r)) != CLOBBER)
4002 return r;
4005 return NULL;
4009 /* Go through all insns, and use the information generated during
4010 scheduling to generate SEQUENCEs to represent bundles of
4011 instructions issued simultaneously. */
4012 static void
4013 tilepro_gen_bundles (void)
4015 basic_block bb;
4016 FOR_EACH_BB_FN (bb, cfun)
4018 rtx_insn *insn, *next;
4019 rtx_insn *end = NEXT_INSN (BB_END (bb));
4021 for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn; insn = next)
4023 next = next_insn_to_bundle (NEXT_INSN (insn), end);
4025 /* Never wrap {} around inline asm. */
4026 if (GET_CODE (PATTERN (insn)) != ASM_INPUT)
4028 if (next == NULL_RTX || GET_MODE (next) == TImode
4029 /* NOTE: The scheduler incorrectly believes a call
4030 insn can execute in the same cycle as the insn
4031 after the call. This is of course impossible.
4032 Really we need to fix the scheduler somehow, so
4033 the code after the call gets scheduled
4034 optimally. */
4035 || CALL_P (insn))
4037 /* Mark current insn as the end of a bundle. */
4038 PUT_MODE (insn, QImode);
4040 else
4042 /* Mark it as part of a bundle. */
4043 PUT_MODE (insn, SImode);
4051 /* Helper function for tilepro_fixup_pcrel_references. */
4052 static void
4053 replace_pc_relative_symbol_ref (rtx_insn *insn, rtx opnds[4], bool first_insn_p)
4055 rtx_insn *new_insns;
4057 start_sequence ();
4059 if (flag_pic == 1)
4061 if (!first_insn_p)
4063 emit_insn (gen_add_got16 (opnds[0], tilepro_got_rtx (),
4064 opnds[2]));
4065 emit_insn (gen_insn_lw (opnds[0], opnds[0]));
4068 else
4070 if (first_insn_p)
4072 emit_insn (gen_addhi_got32 (opnds[0], tilepro_got_rtx (),
4073 opnds[2]));
4075 else
4077 emit_insn (gen_addlo_got32 (opnds[0], opnds[1], opnds[2]));
4078 emit_insn (gen_insn_lw (opnds[0], opnds[0]));
4082 new_insns = get_insns ();
4083 end_sequence ();
4085 if (new_insns)
4086 emit_insn_before (new_insns, insn);
4088 delete_insn (insn);
4092 /* Returns whether INSN is a pc-relative addli insn. */
4093 static bool
4094 match_addli_pcrel (rtx_insn *insn)
4096 rtx pattern = PATTERN (insn);
4097 rtx unspec;
4099 if (GET_CODE (pattern) != SET)
4100 return false;
4102 if (GET_CODE (SET_SRC (pattern)) != LO_SUM)
4103 return false;
4105 if (GET_CODE (XEXP (SET_SRC (pattern), 1)) != CONST)
4106 return false;
4108 unspec = XEXP (XEXP (SET_SRC (pattern), 1), 0);
4110 return (GET_CODE (unspec) == UNSPEC
4111 && XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4115 /* Helper function for tilepro_fixup_pcrel_references. */
4116 static void
4117 replace_addli_pcrel (rtx_insn *insn)
4119 rtx pattern = PATTERN (insn);
4120 rtx set_src;
4121 rtx unspec;
4122 rtx opnds[4];
4123 bool first_insn_p;
4125 gcc_assert (GET_CODE (pattern) == SET);
4126 opnds[0] = SET_DEST (pattern);
4128 set_src = SET_SRC (pattern);
4129 gcc_assert (GET_CODE (set_src) == LO_SUM);
4130 gcc_assert (GET_CODE (XEXP (set_src, 1)) == CONST);
4131 opnds[1] = XEXP (set_src, 0);
4133 unspec = XEXP (XEXP (set_src, 1), 0);
4134 gcc_assert (GET_CODE (unspec) == UNSPEC);
4135 gcc_assert (XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4136 opnds[2] = XVECEXP (unspec, 0, 0);
4137 opnds[3] = XVECEXP (unspec, 0, 1);
4139 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4140 if (GET_CODE (opnds[2]) != SYMBOL_REF)
4141 return;
4143 first_insn_p = (opnds[1] == tilepro_text_label_rtx ());
4145 replace_pc_relative_symbol_ref (insn, opnds, first_insn_p);
4149 /* Returns whether INSN is a pc-relative auli insn. */
4150 static bool
4151 match_auli_pcrel (rtx_insn *insn)
4153 rtx pattern = PATTERN (insn);
4154 rtx high;
4155 rtx unspec;
4157 if (GET_CODE (pattern) != SET)
4158 return false;
4160 if (GET_CODE (SET_SRC (pattern)) != PLUS)
4161 return false;
4163 high = XEXP (SET_SRC (pattern), 1);
4165 if (GET_CODE (high) != HIGH
4166 || GET_CODE (XEXP (high, 0)) != CONST)
4167 return false;
4169 unspec = XEXP (XEXP (high, 0), 0);
4171 return (GET_CODE (unspec) == UNSPEC
4172 && XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4176 /* Helper function for tilepro_fixup_pcrel_references. */
4177 static void
4178 replace_auli_pcrel (rtx_insn *insn)
4180 rtx pattern = PATTERN (insn);
4181 rtx set_src;
4182 rtx high;
4183 rtx unspec;
4184 rtx opnds[4];
4185 bool first_insn_p;
4187 gcc_assert (GET_CODE (pattern) == SET);
4188 opnds[0] = SET_DEST (pattern);
4190 set_src = SET_SRC (pattern);
4191 gcc_assert (GET_CODE (set_src) == PLUS);
4192 opnds[1] = XEXP (set_src, 0);
4194 high = XEXP (set_src, 1);
4195 gcc_assert (GET_CODE (high) == HIGH);
4196 gcc_assert (GET_CODE (XEXP (high, 0)) == CONST);
4198 unspec = XEXP (XEXP (high, 0), 0);
4199 gcc_assert (GET_CODE (unspec) == UNSPEC);
4200 gcc_assert (XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4201 opnds[2] = XVECEXP (unspec, 0, 0);
4202 opnds[3] = XVECEXP (unspec, 0, 1);
4204 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4205 if (GET_CODE (opnds[2]) != SYMBOL_REF)
4206 return;
4208 first_insn_p = (opnds[1] == tilepro_text_label_rtx ());
4210 replace_pc_relative_symbol_ref (insn, opnds, first_insn_p);
4214 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4215 going through the GOT when the symbol is local to the compilation
4216 unit. But such a symbol requires that the common text_label that
4217 we generate at the beginning of the function be in the same section
4218 as the reference to the SYMBOL_REF. This may not be true if we
4219 generate hot/cold sections. This function looks for such cases and
4220 replaces such references with the longer sequence going through the
4221 GOT.
4223 We expect one of the following two instruction sequences:
4224 addli tmp1, txt_label_reg, lo16(sym - txt_label)
4225 auli tmp2, tmp1, ha16(sym - txt_label)
4227 auli tmp1, txt_label_reg, ha16(sym - txt_label)
4228 addli tmp2, tmp1, lo16(sym - txt_label)
4230 If we're compiling -fpic, we replace the first instruction with
4231 nothing, and the second instruction with:
4233 addli tmp2, got_rtx, got(sym)
4234 lw tmp2, tmp2
4236 If we're compiling -fPIC, we replace the first instruction with:
4238 auli tmp1, got_rtx, got_ha16(sym)
4240 and the second instruction with:
4242 addli tmp2, tmp1, got_lo16(sym)
4243 lw tmp2, tmp2
4245 Note that we're careful to disturb the instruction sequence as
4246 little as possible, since it's very late in the compilation
4247 process.
4249 static void
4250 tilepro_fixup_pcrel_references (void)
4252 rtx_insn *insn, *next_insn;
4253 bool same_section_as_entry = true;
4255 for (insn = get_insns (); insn; insn = next_insn)
4257 next_insn = NEXT_INSN (insn);
4259 if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
4261 same_section_as_entry = !same_section_as_entry;
4262 continue;
4265 if (same_section_as_entry)
4266 continue;
4268 if (!(INSN_P (insn)
4269 && GET_CODE (PATTERN (insn)) != USE
4270 && GET_CODE (PATTERN (insn)) != CLOBBER))
4271 continue;
4273 if (match_addli_pcrel (insn))
4274 replace_addli_pcrel (insn);
4275 else if (match_auli_pcrel (insn))
4276 replace_auli_pcrel (insn);
4281 /* Ensure that no var tracking notes are emitted in the middle of a
4282 three-instruction bundle. */
4283 static void
4284 reorder_var_tracking_notes (void)
4286 basic_block bb;
4287 FOR_EACH_BB_FN (bb, cfun)
4289 rtx_insn *insn, *next;
4290 rtx_insn *queue = NULL;
4291 bool in_bundle = false;
4293 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4295 next = NEXT_INSN (insn);
4297 if (INSN_P (insn))
4299 /* Emit queued up notes at the last instruction of a bundle. */
4300 if (GET_MODE (insn) == QImode)
4302 while (queue)
4304 rtx_insn *next_queue = PREV_INSN (queue);
4305 SET_PREV_INSN (NEXT_INSN (insn)) = queue;
4306 SET_NEXT_INSN (queue) = NEXT_INSN (insn);
4307 SET_NEXT_INSN (insn) = queue;
4308 SET_PREV_INSN (queue) = insn;
4309 queue = next_queue;
4311 in_bundle = false;
4313 else if (GET_MODE (insn) == SImode)
4314 in_bundle = true;
4316 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4318 if (in_bundle)
4320 rtx_insn *prev = PREV_INSN (insn);
4321 SET_PREV_INSN (next) = prev;
4322 SET_NEXT_INSN (prev) = next;
4324 SET_PREV_INSN (insn) = queue;
4325 queue = insn;
4333 /* Perform machine dependent operations on the rtl chain INSNS. */
4334 static void
4335 tilepro_reorg (void)
4337 /* We are freeing block_for_insn in the toplev to keep compatibility
4338 with old MDEP_REORGS that are not CFG based. Recompute it
4339 now. */
4340 compute_bb_for_insn ();
4342 if (flag_reorder_blocks_and_partition)
4344 tilepro_fixup_pcrel_references ();
4347 if (flag_schedule_insns_after_reload)
4349 split_all_insns ();
4351 timevar_push (TV_SCHED2);
4352 schedule_insns ();
4353 timevar_pop (TV_SCHED2);
4355 /* Examine the schedule to group into bundles. */
4356 tilepro_gen_bundles ();
4359 df_analyze ();
4361 if (flag_var_tracking)
4363 timevar_push (TV_VAR_TRACKING);
4364 variable_tracking_main ();
4365 reorder_var_tracking_notes ();
4366 timevar_pop (TV_VAR_TRACKING);
4369 df_finish_pass (false);
4374 /* Assembly */
4376 /* Select a format to encode pointers in exception handling data.
4377 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4378 GLOBAL is true if the symbol may be affected by dynamic
4379 relocations. */
4381 tilepro_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
4383 return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4;
4387 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4388 static void
4389 tilepro_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
4390 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
4391 tree function)
4393 rtx this_rtx, funexp;
4394 rtx_insn *insn;
4396 /* Pretend to be a post-reload pass while generating rtl. */
4397 reload_completed = 1;
4399 /* Mark the end of the (empty) prologue. */
4400 emit_note (NOTE_INSN_PROLOGUE_END);
4402 /* Find the "this" pointer. If the function returns a structure,
4403 the structure return pointer is in $1. */
4404 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
4405 this_rtx = gen_rtx_REG (Pmode, 1);
4406 else
4407 this_rtx = gen_rtx_REG (Pmode, 0);
4409 /* Add DELTA to THIS_RTX. */
4410 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
4412 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4413 if (vcall_offset)
4415 rtx tmp;
4417 tmp = gen_rtx_REG (Pmode, 29);
4418 emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx));
4420 emit_insn (gen_addsi3 (tmp, tmp, GEN_INT (vcall_offset)));
4422 emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
4424 emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp));
4427 /* Generate a tail call to the target function. */
4428 if (!TREE_USED (function))
4430 assemble_external (function);
4431 TREE_USED (function) = 1;
4433 funexp = XEXP (DECL_RTL (function), 0);
4434 funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
4435 insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
4436 SIBLING_CALL_P (insn) = 1;
4438 /* Run just enough of rest_of_compilation to get the insns emitted.
4439 There's not really enough bulk here to make other passes such as
4440 instruction scheduling worth while. Note that use_thunk calls
4441 assemble_start_function and assemble_end_function.
4443 We don't currently bundle, but the instruciton sequence is all
4444 serial except for the tail call, so we're only wasting one cycle.
4446 insn = get_insns ();
4447 shorten_branches (insn);
4448 final_start_function (insn, file, 1);
4449 final (insn, file, 1);
4450 final_end_function ();
4452 /* Stop pretending to be a post-reload pass. */
4453 reload_completed = 0;
4457 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
4458 static void
4459 tilepro_asm_trampoline_template (FILE *file)
4461 fprintf (file, "\tlnk r10\n");
4462 fprintf (file, "\taddi r10, r10, 32\n");
4463 fprintf (file, "\tlwadd r11, r10, %d\n", GET_MODE_SIZE (ptr_mode));
4464 fprintf (file, "\tlw r10, r10\n");
4465 fprintf (file, "\tjr r11\n");
4466 fprintf (file, "\t.word 0 # <function address>\n");
4467 fprintf (file, "\t.word 0 # <static chain value>\n");
4471 /* Implement TARGET_TRAMPOLINE_INIT. */
4472 static void
4473 tilepro_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
4475 rtx fnaddr, chaddr;
4476 rtx mem;
4477 rtx begin_addr, end_addr;
4478 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4480 fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
4481 chaddr = copy_to_reg (static_chain);
4483 emit_block_move (m_tramp, assemble_trampoline_template (),
4484 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
4486 mem = adjust_address (m_tramp, ptr_mode,
4487 TRAMPOLINE_SIZE - 2 * ptr_mode_size);
4488 emit_move_insn (mem, fnaddr);
4489 mem = adjust_address (m_tramp, ptr_mode,
4490 TRAMPOLINE_SIZE - ptr_mode_size);
4491 emit_move_insn (mem, chaddr);
4493 /* Get pointers to the beginning and end of the code block. */
4494 begin_addr = force_reg (Pmode, XEXP (m_tramp, 0));
4495 end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0),
4496 TRAMPOLINE_SIZE));
4498 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
4499 LCT_NORMAL, VOIDmode, 2, begin_addr, Pmode,
4500 end_addr, Pmode);
4504 /* Implement TARGET_PRINT_OPERAND. */
4505 static void
4506 tilepro_print_operand (FILE *file, rtx x, int code)
4508 switch (code)
4510 case 'c':
4511 /* Print the compare operator opcode for conditional moves. */
4512 switch (GET_CODE (x))
4514 case EQ:
4515 fputs ("z", file);
4516 break;
4517 case NE:
4518 fputs ("nz", file);
4519 break;
4520 default:
4521 output_operand_lossage ("invalid %%c operand");
4523 return;
4525 case 'C':
4526 /* Print the compare operator opcode for conditional moves. */
4527 switch (GET_CODE (x))
4529 case EQ:
4530 fputs ("nz", file);
4531 break;
4532 case NE:
4533 fputs ("z", file);
4534 break;
4535 default:
4536 output_operand_lossage ("invalid %%C operand");
4538 return;
4540 case 'h':
4542 /* Print the high 16 bits of a 32-bit constant. */
4543 HOST_WIDE_INT i;
4544 if (CONST_INT_P (x))
4545 i = INTVAL (x);
4546 else if (GET_CODE (x) == CONST_DOUBLE)
4547 i = CONST_DOUBLE_LOW (x);
4548 else
4550 output_operand_lossage ("invalid %%h operand");
4551 return;
4553 i = trunc_int_for_mode (i >> 16, HImode);
4554 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4555 return;
4558 case 'H':
4560 rtx addr = NULL;
4561 const char *opstr = NULL;
4562 bool pcrel = false;
4563 if (GET_CODE (x) == CONST
4564 && GET_CODE (XEXP (x, 0)) == UNSPEC)
4566 addr = XVECEXP (XEXP (x, 0), 0, 0);
4567 switch (XINT (XEXP (x, 0), 1))
4569 case UNSPEC_GOT32_SYM:
4570 opstr = "got_ha16";
4571 break;
4572 case UNSPEC_PCREL_SYM:
4573 opstr = "ha16";
4574 pcrel = true;
4575 break;
4576 case UNSPEC_TLS_GD:
4577 opstr = "tls_gd_ha16";
4578 break;
4579 case UNSPEC_TLS_IE:
4580 opstr = "tls_ie_ha16";
4581 break;
4582 case UNSPEC_TLS_LE:
4583 opstr = "tls_le_ha16";
4584 break;
4585 default:
4586 output_operand_lossage ("invalid %%H operand");
4589 else
4591 addr = x;
4592 opstr = "ha16";
4595 fputs (opstr, file);
4596 fputc ('(', file);
4597 output_addr_const (file, addr);
4599 if (pcrel)
4601 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
4602 fputs (" - " , file);
4603 output_addr_const (file, addr2);
4606 fputc (')', file);
4607 return;
4610 case 'I':
4611 /* Print an auto-inc memory operand. */
4612 if (!MEM_P (x))
4614 output_operand_lossage ("invalid %%I operand");
4615 return;
4618 output_memory_reference_mode = GET_MODE (x);
4619 output_memory_autoinc_first = true;
4620 output_address (XEXP (x, 0));
4621 output_memory_reference_mode = VOIDmode;
4622 return;
4624 case 'i':
4625 /* Print an auto-inc memory operand. */
4626 if (!MEM_P (x))
4628 output_operand_lossage ("invalid %%i operand");
4629 return;
4632 output_memory_reference_mode = GET_MODE (x);
4633 output_memory_autoinc_first = false;
4634 output_address (XEXP (x, 0));
4635 output_memory_reference_mode = VOIDmode;
4636 return;
4638 case 'j':
4640 /* Print the low 8 bits of a constant. */
4641 HOST_WIDE_INT i;
4642 if (CONST_INT_P (x))
4643 i = INTVAL (x);
4644 else if (GET_CODE (x) == CONST_DOUBLE)
4645 i = CONST_DOUBLE_LOW (x);
4646 else if (GET_CODE (x) == CONST_VECTOR
4647 && CONST_INT_P (CONST_VECTOR_ELT (x, 0)))
4648 i = INTVAL (CONST_VECTOR_ELT (x, 0));
4649 else
4651 output_operand_lossage ("invalid %%j operand");
4652 return;
4654 i = trunc_int_for_mode (i, QImode);
4655 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4656 return;
4659 case 'L':
4661 rtx addr = NULL;
4662 const char *opstr = NULL;
4663 bool pcrel = false;
4664 if (GET_CODE (x) == CONST
4665 && GET_CODE (XEXP (x, 0)) == UNSPEC)
4667 addr = XVECEXP (XEXP (x, 0), 0, 0);
4668 switch (XINT (XEXP (x, 0), 1))
4670 case UNSPEC_GOT16_SYM:
4671 opstr = "got";
4672 break;
4673 case UNSPEC_GOT32_SYM:
4674 opstr = "got_lo16";
4675 break;
4676 case UNSPEC_PCREL_SYM:
4677 opstr = "lo16";
4678 pcrel = true;
4679 break;
4680 case UNSPEC_TLS_GD:
4681 opstr = "tls_gd_lo16";
4682 break;
4683 case UNSPEC_TLS_IE:
4684 opstr = "tls_ie_lo16";
4685 break;
4686 case UNSPEC_TLS_LE:
4687 opstr = "tls_le_lo16";
4688 break;
4689 default:
4690 output_operand_lossage ("invalid %%L operand");
4693 else
4695 addr = x;
4696 opstr = "lo16";
4699 fputs (opstr, file);
4700 fputc ('(', file);
4701 output_addr_const (file, addr);
4703 if (pcrel)
4705 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
4706 fputs (" - " , file);
4707 output_addr_const (file, addr2);
4710 fputc (')', file);
4711 return;
4714 case 'p':
4715 if (GET_CODE (x) == SYMBOL_REF)
4717 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
4718 fprintf (file, "plt(");
4719 output_addr_const (file, x);
4720 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
4721 fprintf (file, ")");
4723 else
4724 output_addr_const (file, x);
4725 return;
4727 case 'P':
4729 /* Print a 32-bit constant plus one. */
4730 HOST_WIDE_INT i;
4731 if (!CONST_INT_P (x))
4733 output_operand_lossage ("invalid %%P operand");
4734 return;
4736 i = trunc_int_for_mode (INTVAL (x) + 1, SImode);
4737 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4738 return;
4741 case 'M':
4743 /* Print an mm-style bit range. */
4744 int first_bit, last_bit;
4746 if (!CONST_INT_P (x)
4747 || !tilepro_bitfield_operand_p (INTVAL (x), &first_bit,
4748 &last_bit))
4750 output_operand_lossage ("invalid %%M operand");
4751 return;
4754 fprintf (file, "%d, %d", first_bit, last_bit);
4755 return;
4758 case 'N':
4760 const char *reg = NULL;
4762 /* Print a network register. */
4763 if (!CONST_INT_P (x))
4765 output_operand_lossage ("invalid %%N operand");
4766 return;
4769 switch (INTVAL (x))
4771 case TILEPRO_NETREG_IDN0: reg = "idn0"; break;
4772 case TILEPRO_NETREG_IDN1: reg = "idn1"; break;
4773 case TILEPRO_NETREG_SN: reg = "sn"; break;
4774 case TILEPRO_NETREG_UDN0: reg = "udn0"; break;
4775 case TILEPRO_NETREG_UDN1: reg = "udn1"; break;
4776 case TILEPRO_NETREG_UDN2: reg = "udn2"; break;
4777 case TILEPRO_NETREG_UDN3: reg = "udn3"; break;
4778 default: gcc_unreachable ();
4781 fprintf (file, reg);
4782 return;
4785 case 't':
4787 /* Log base 2 of a power of two. */
4788 HOST_WIDE_INT i;
4789 HOST_WIDE_INT n;
4791 if (!CONST_INT_P (x))
4793 output_operand_lossage ("invalid %%t operand");
4794 return;
4796 n = trunc_int_for_mode (INTVAL (x), SImode);
4797 i = exact_log2 (n);
4798 if (i < 0)
4800 output_operand_lossage ("invalid %%t operand '"
4801 HOST_WIDE_INT_PRINT_DEC "'", n);
4802 return;
4805 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4806 return;
4808 break;
4810 case 'r':
4811 /* In this case we need a register. Use 'zero' if the
4812 operand is const0_rtx. */
4813 if (x == const0_rtx
4814 || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
4816 fputs ("zero", file);
4817 return;
4819 else if (!REG_P (x))
4821 output_operand_lossage ("invalid %%r operand");
4822 return;
4824 /* FALLTHRU */
4826 case 0:
4827 if (REG_P (x))
4829 fprintf (file, "%s", reg_names[REGNO (x)]);
4830 return;
4832 else if (MEM_P (x))
4834 output_memory_reference_mode = VOIDmode;
4835 output_address (XEXP (x, 0));
4836 return;
4838 else
4840 output_addr_const (file, x);
4841 return;
4843 break;
4846 debug_rtx (x);
4847 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
4848 code, code);
4852 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
4853 static void
4854 tilepro_print_operand_address (FILE *file, rtx addr)
4856 if (GET_CODE (addr) == POST_DEC
4857 || GET_CODE (addr) == POST_INC)
4859 int offset = GET_MODE_SIZE (output_memory_reference_mode);
4861 gcc_assert (output_memory_reference_mode != VOIDmode);
4863 if (output_memory_autoinc_first)
4864 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
4865 else
4866 fprintf (file, "%d",
4867 GET_CODE (addr) == POST_DEC ? -offset : offset);
4869 else if (GET_CODE (addr) == POST_MODIFY)
4871 gcc_assert (output_memory_reference_mode != VOIDmode);
4873 gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
4875 if (output_memory_autoinc_first)
4876 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
4877 else
4878 fprintf (file, HOST_WIDE_INT_PRINT_DEC,
4879 INTVAL (XEXP (XEXP (addr, 1), 1)));
4881 else
4882 tilepro_print_operand (file, addr, 'r');
4886 /* Machine mode of current insn, for determining curly brace
4887 placement. */
4888 static machine_mode insn_mode;
4891 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
4892 void
4893 tilepro_final_prescan_insn (rtx_insn *insn)
4895 /* Record this for tilepro_asm_output_opcode to examine. */
4896 insn_mode = GET_MODE (insn);
4900 /* While emitting asm, are we currently inside '{' for a bundle? */
4901 static bool tilepro_in_bundle = false;
4903 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
4904 appropriate given the bundling information recorded by
4905 tilepro_gen_bundles. */
4906 const char *
4907 tilepro_asm_output_opcode (FILE *stream, const char *code)
4909 bool pseudo = !strcmp (code, "pseudo");
4911 if (!tilepro_in_bundle && insn_mode == SImode)
4913 /* Start a new bundle. */
4914 fprintf (stream, "{\n\t");
4915 tilepro_in_bundle = true;
4918 if (tilepro_in_bundle && insn_mode == QImode)
4920 /* Close an existing bundle. */
4921 static char buf[100];
4923 gcc_assert (strlen (code) + 3 + 1 < sizeof (buf));
4925 strcpy (buf, pseudo ? "" : code);
4926 strcat (buf, "\n\t}");
4927 tilepro_in_bundle = false;
4929 return buf;
4931 else
4933 return pseudo ? "" : code;
4938 /* Output assembler code to FILE to increment profiler label # LABELNO
4939 for profiling a function entry. */
4940 void
4941 tilepro_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
4943 if (tilepro_in_bundle)
4945 fprintf (file, "\t}\n");
4948 if (flag_pic)
4950 fprintf (file,
4951 "\t{\n"
4952 "\tmove\tr10, lr\n"
4953 "\tjal\tplt(%s)\n"
4954 "\t}\n", MCOUNT_NAME);
4956 else
4958 fprintf (file,
4959 "\t{\n"
4960 "\tmove\tr10, lr\n"
4961 "\tjal\t%s\n"
4962 "\t}\n", MCOUNT_NAME);
4965 tilepro_in_bundle = false;
4969 /* Implement TARGET_ASM_FILE_END. */
4970 static void
4971 tilepro_file_end (void)
4973 if (NEED_INDICATE_EXEC_STACK)
4974 file_end_indicate_exec_stack ();
4978 #undef TARGET_HAVE_TLS
4979 #define TARGET_HAVE_TLS HAVE_AS_TLS
4981 #undef TARGET_OPTION_OVERRIDE
4982 #define TARGET_OPTION_OVERRIDE tilepro_option_override
4984 #undef TARGET_SCALAR_MODE_SUPPORTED_P
4985 #define TARGET_SCALAR_MODE_SUPPORTED_P tilepro_scalar_mode_supported_p
4987 #undef TARGET_VECTOR_MODE_SUPPORTED_P
4988 #define TARGET_VECTOR_MODE_SUPPORTED_P tile_vector_mode_supported_p
4990 #undef TARGET_CANNOT_FORCE_CONST_MEM
4991 #define TARGET_CANNOT_FORCE_CONST_MEM tilepro_cannot_force_const_mem
4993 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
4994 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilepro_function_ok_for_sibcall
4996 #undef TARGET_PASS_BY_REFERENCE
4997 #define TARGET_PASS_BY_REFERENCE tilepro_pass_by_reference
4999 #undef TARGET_RETURN_IN_MEMORY
5000 #define TARGET_RETURN_IN_MEMORY tilepro_return_in_memory
5002 #undef TARGET_FUNCTION_ARG_BOUNDARY
5003 #define TARGET_FUNCTION_ARG_BOUNDARY tilepro_function_arg_boundary
5005 #undef TARGET_FUNCTION_ARG
5006 #define TARGET_FUNCTION_ARG tilepro_function_arg
5008 #undef TARGET_FUNCTION_ARG_ADVANCE
5009 #define TARGET_FUNCTION_ARG_ADVANCE tilepro_function_arg_advance
5011 #undef TARGET_FUNCTION_VALUE
5012 #define TARGET_FUNCTION_VALUE tilepro_function_value
5014 #undef TARGET_LIBCALL_VALUE
5015 #define TARGET_LIBCALL_VALUE tilepro_libcall_value
5017 #undef TARGET_FUNCTION_VALUE_REGNO_P
5018 #define TARGET_FUNCTION_VALUE_REGNO_P tilepro_function_value_regno_p
5020 #undef TARGET_PROMOTE_FUNCTION_MODE
5021 #define TARGET_PROMOTE_FUNCTION_MODE \
5022 default_promote_function_mode_always_promote
5024 #undef TARGET_PROMOTE_PROTOTYPES
5025 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5027 #undef TARGET_BUILD_BUILTIN_VA_LIST
5028 #define TARGET_BUILD_BUILTIN_VA_LIST tilepro_build_builtin_va_list
5030 #undef TARGET_EXPAND_BUILTIN_VA_START
5031 #define TARGET_EXPAND_BUILTIN_VA_START tilepro_va_start
5033 #undef TARGET_SETUP_INCOMING_VARARGS
5034 #define TARGET_SETUP_INCOMING_VARARGS tilepro_setup_incoming_varargs
5036 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
5037 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilepro_gimplify_va_arg_expr
5039 #undef TARGET_RTX_COSTS
5040 #define TARGET_RTX_COSTS tilepro_rtx_costs
5042 /* Limit to what we can reach in one addli. */
5043 #undef TARGET_MIN_ANCHOR_OFFSET
5044 #define TARGET_MIN_ANCHOR_OFFSET -32768
5045 #undef TARGET_MAX_ANCHOR_OFFSET
5046 #define TARGET_MAX_ANCHOR_OFFSET 32767
5048 #undef TARGET_LEGITIMATE_CONSTANT_P
5049 #define TARGET_LEGITIMATE_CONSTANT_P tilepro_legitimate_constant_p
5051 #undef TARGET_LEGITIMATE_ADDRESS_P
5052 #define TARGET_LEGITIMATE_ADDRESS_P tilepro_legitimate_address_p
5054 #undef TARGET_LEGITIMIZE_ADDRESS
5055 #define TARGET_LEGITIMIZE_ADDRESS tilepro_legitimize_address
5057 #undef TARGET_DELEGITIMIZE_ADDRESS
5058 #define TARGET_DELEGITIMIZE_ADDRESS tilepro_delegitimize_address
5060 #undef TARGET_INIT_BUILTINS
5061 #define TARGET_INIT_BUILTINS tilepro_init_builtins
5063 #undef TARGET_BUILTIN_DECL
5064 #define TARGET_BUILTIN_DECL tilepro_builtin_decl
5066 #undef TARGET_EXPAND_BUILTIN
5067 #define TARGET_EXPAND_BUILTIN tilepro_expand_builtin
5069 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5070 #define TARGET_CONDITIONAL_REGISTER_USAGE tilepro_conditional_register_usage
5072 #undef TARGET_FRAME_POINTER_REQUIRED
5073 #define TARGET_FRAME_POINTER_REQUIRED tilepro_frame_pointer_required
5075 #undef TARGET_DELAY_SCHED2
5076 #define TARGET_DELAY_SCHED2 true
5078 #undef TARGET_DELAY_VARTRACK
5079 #define TARGET_DELAY_VARTRACK true
5081 #undef TARGET_SCHED_ISSUE_RATE
5082 #define TARGET_SCHED_ISSUE_RATE tilepro_issue_rate
5084 #undef TARGET_SCHED_ADJUST_COST
5085 #define TARGET_SCHED_ADJUST_COST tilepro_sched_adjust_cost
5087 #undef TARGET_MACHINE_DEPENDENT_REORG
5088 #define TARGET_MACHINE_DEPENDENT_REORG tilepro_reorg
5090 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5091 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5092 hook_bool_const_tree_hwi_hwi_const_tree_true
5094 #undef TARGET_ASM_OUTPUT_MI_THUNK
5095 #define TARGET_ASM_OUTPUT_MI_THUNK tilepro_asm_output_mi_thunk
5097 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5098 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilepro_asm_trampoline_template
5100 #undef TARGET_TRAMPOLINE_INIT
5101 #define TARGET_TRAMPOLINE_INIT tilepro_trampoline_init
5103 #undef TARGET_PRINT_OPERAND
5104 #define TARGET_PRINT_OPERAND tilepro_print_operand
5106 #undef TARGET_PRINT_OPERAND_ADDRESS
5107 #define TARGET_PRINT_OPERAND_ADDRESS tilepro_print_operand_address
5109 #undef TARGET_ASM_FILE_END
5110 #define TARGET_ASM_FILE_END tilepro_file_end
5112 #undef TARGET_CAN_USE_DOLOOP_P
5113 #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
5115 struct gcc_target targetm = TARGET_INITIALIZER;
5117 #include "gt-tilepro.h"