2013-10-22 Jan-Benedict Glaw <jbglaw@lug-owl.de>
[official-gcc.git] / gcc / config / tilepro / tilepro.c
blob12adda30e573b529461362a9e5271f6ba8e3eb7d
1 /* Subroutines used for code generation on the Tilera TILEPro.
2 Copyright (C) 2011-2013 Free Software Foundation, Inc.
3 Contributed by Walter Lee (walt@tilera.com)
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
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 "expr.h"
32 #include "langhooks.h"
33 #include "optabs.h"
34 #include "sched-int.h"
35 #include "sel-sched.h"
36 #include "tm_p.h"
37 #include "tm-constrs.h"
38 #include "target.h"
39 #include "target-def.h"
40 #include "function.h"
41 #include "dwarf2.h"
42 #include "timevar.h"
43 #include "tree.h"
44 #include "gimple.h"
45 #include "cfgloop.h"
46 #include "tilepro-builtins.h"
47 #include "tilepro-multiply.h"
48 #include "diagnostic.h"
50 /* SYMBOL_REF for GOT */
51 static GTY(()) rtx g_got_symbol = NULL;
53 /* In case of a POST_INC or POST_DEC memory reference, we must report
54 the mode of the memory reference from TARGET_PRINT_OPERAND to
55 TARGET_PRINT_OPERAND_ADDRESS. */
56 static enum machine_mode output_memory_reference_mode;
58 /* Report whether we're printing out the first address fragment of a
59 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
60 TARGET_PRINT_OPERAND_ADDRESS. */
61 static bool output_memory_autoinc_first;
65 /* Option handling */
67 /* Implement TARGET_OPTION_OVERRIDE. */
68 static void
69 tilepro_option_override (void)
71 /* When modulo scheduling is enabled, we still rely on regular
72 scheduler for bundling. */
73 if (flag_modulo_sched)
74 flag_resched_modulo_sched = 1;
79 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
80 static bool
81 tilepro_scalar_mode_supported_p (enum machine_mode mode)
83 switch (mode)
85 case QImode:
86 case HImode:
87 case SImode:
88 case DImode:
89 return true;
91 case SFmode:
92 case DFmode:
93 return true;
95 default:
96 return false;
101 /* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
102 static bool
103 tile_vector_mode_supported_p (enum machine_mode mode)
105 return mode == V4QImode || mode == V2HImode;
109 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
110 static bool
111 tilepro_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED,
112 rtx x ATTRIBUTE_UNUSED)
114 return true;
118 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
119 static bool
120 tilepro_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
122 return decl != NULL;
126 /* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
127 passed by reference. */
128 static bool
129 tilepro_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
130 enum machine_mode mode ATTRIBUTE_UNUSED,
131 const_tree type, bool named ATTRIBUTE_UNUSED)
133 return (type && TYPE_SIZE (type)
134 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST);
138 /* Implement TARGET_RETURN_IN_MEMORY. */
139 static bool
140 tilepro_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
142 return !IN_RANGE (int_size_in_bytes (type),
143 0, TILEPRO_NUM_RETURN_REGS * UNITS_PER_WORD);
147 /* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
148 static unsigned int
149 tilepro_function_arg_boundary (enum machine_mode mode, const_tree type)
151 unsigned int alignment;
153 alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode);
154 if (alignment < PARM_BOUNDARY)
155 alignment = PARM_BOUNDARY;
156 if (alignment > STACK_BOUNDARY)
157 alignment = STACK_BOUNDARY;
158 return alignment;
162 /* Implement TARGET_FUNCTION_ARG. */
163 static rtx
164 tilepro_function_arg (cumulative_args_t cum_v,
165 enum machine_mode mode,
166 const_tree type, bool named ATTRIBUTE_UNUSED)
168 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
169 int byte_size = ((mode == BLKmode)
170 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
171 bool doubleword_aligned_p;
173 if (cum >= TILEPRO_NUM_ARG_REGS)
174 return NULL_RTX;
176 /* See whether the argument has doubleword alignment. */
177 doubleword_aligned_p =
178 tilepro_function_arg_boundary (mode, type) > BITS_PER_WORD;
180 if (doubleword_aligned_p)
181 cum += cum & 1;
183 /* The ABI does not allow parameters to be passed partially in reg
184 and partially in stack. */
185 if ((cum + (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
186 > TILEPRO_NUM_ARG_REGS)
187 return NULL_RTX;
189 return gen_rtx_REG (mode, cum);
193 /* Implement TARGET_FUNCTION_ARG_ADVANCE. */
194 static void
195 tilepro_function_arg_advance (cumulative_args_t cum_v,
196 enum machine_mode mode,
197 const_tree type, bool named ATTRIBUTE_UNUSED)
199 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 int word_size = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
204 bool doubleword_aligned_p;
206 /* See whether the argument has doubleword alignment. */
207 doubleword_aligned_p =
208 tilepro_function_arg_boundary (mode, type) > BITS_PER_WORD;
210 if (doubleword_aligned_p)
211 *cum += *cum & 1;
213 /* If the current argument does not fit in the pretend_args space,
214 skip over it. */
215 if (*cum < TILEPRO_NUM_ARG_REGS
216 && *cum + word_size > TILEPRO_NUM_ARG_REGS)
217 *cum = TILEPRO_NUM_ARG_REGS;
219 *cum += word_size;
223 /* Implement TARGET_FUNCTION_VALUE. */
224 static rtx
225 tilepro_function_value (const_tree valtype, const_tree fn_decl_or_type,
226 bool outgoing ATTRIBUTE_UNUSED)
228 enum machine_mode mode;
229 int unsigned_p;
231 mode = TYPE_MODE (valtype);
232 unsigned_p = TYPE_UNSIGNED (valtype);
234 mode = promote_function_mode (valtype, mode, &unsigned_p,
235 fn_decl_or_type, 1);
237 return gen_rtx_REG (mode, 0);
241 /* Implement TARGET_LIBCALL_VALUE. */
242 static rtx
243 tilepro_libcall_value (enum machine_mode mode,
244 const_rtx fun ATTRIBUTE_UNUSED)
246 return gen_rtx_REG (mode, 0);
250 /* Implement FUNCTION_VALUE_REGNO_P. */
251 static bool
252 tilepro_function_value_regno_p (const unsigned int regno)
254 return regno < TILEPRO_NUM_RETURN_REGS;
258 /* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
259 static tree
260 tilepro_build_builtin_va_list (void)
262 tree f_args, f_skip, record, type_decl;
263 bool owp;
265 record = lang_hooks.types.make_type (RECORD_TYPE);
267 type_decl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
268 get_identifier ("__va_list_tag"), record);
270 f_args = build_decl (BUILTINS_LOCATION, FIELD_DECL,
271 get_identifier ("__args"), ptr_type_node);
272 f_skip = build_decl (BUILTINS_LOCATION, FIELD_DECL,
273 get_identifier ("__skip"), ptr_type_node);
275 DECL_FIELD_CONTEXT (f_args) = record;
277 DECL_FIELD_CONTEXT (f_skip) = record;
279 TREE_CHAIN (record) = type_decl;
280 TYPE_NAME (record) = type_decl;
281 TYPE_FIELDS (record) = f_args;
282 TREE_CHAIN (f_args) = f_skip;
284 /* We know this is being padded and we want it too. It is an
285 internal type so hide the warnings from the user. */
286 owp = warn_padded;
287 warn_padded = false;
289 layout_type (record);
291 warn_padded = owp;
293 /* The correct type is an array type of one element. */
294 return record;
298 /* Implement TARGET_EXPAND_BUILTIN_VA_START. */
299 static void
300 tilepro_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
302 tree f_args, f_skip;
303 tree args, skip, t;
305 f_args = TYPE_FIELDS (TREE_TYPE (valist));
306 f_skip = TREE_CHAIN (f_args);
308 args =
309 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
310 skip =
311 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
313 /* Find the __args area. */
314 t = make_tree (TREE_TYPE (args), virtual_incoming_args_rtx);
315 t = fold_build_pointer_plus_hwi (t,
316 UNITS_PER_WORD *
317 (crtl->args.info - TILEPRO_NUM_ARG_REGS));
319 if (crtl->args.pretend_args_size > 0)
320 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
322 t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t);
323 TREE_SIDE_EFFECTS (t) = 1;
324 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
326 /* Find the __skip area. */
327 t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx);
328 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
329 t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t);
330 TREE_SIDE_EFFECTS (t) = 1;
331 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
335 /* Implement TARGET_SETUP_INCOMING_VARARGS. */
336 static void
337 tilepro_setup_incoming_varargs (cumulative_args_t cum,
338 enum machine_mode mode,
339 tree type, int *pretend_args, int no_rtl)
341 CUMULATIVE_ARGS local_cum = *get_cumulative_args (cum);
342 int first_reg;
344 /* The caller has advanced CUM up to, but not beyond, the last named
345 argument. Advance a local copy of CUM past the last "real" named
346 argument, to find out how many registers are left over. */
347 targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum),
348 mode, type, true);
349 first_reg = local_cum;
351 if (local_cum < TILEPRO_NUM_ARG_REGS)
353 *pretend_args = UNITS_PER_WORD * (TILEPRO_NUM_ARG_REGS - first_reg);
355 if (!no_rtl)
357 alias_set_type set = get_varargs_alias_set ();
358 rtx tmp =
359 gen_rtx_MEM (BLKmode, plus_constant (Pmode, \
360 virtual_incoming_args_rtx,
361 -STACK_POINTER_OFFSET -
362 UNITS_PER_WORD *
363 (TILEPRO_NUM_ARG_REGS -
364 first_reg)));
365 MEM_NOTRAP_P (tmp) = 1;
366 set_mem_alias_set (tmp, set);
367 move_block_from_reg (first_reg, tmp,
368 TILEPRO_NUM_ARG_REGS - first_reg);
371 else
372 *pretend_args = 0;
376 /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
377 the va_list structure VALIST as required to retrieve an argument of
378 type TYPE, and returning that argument.
380 ret = va_arg(VALIST, TYPE);
382 generates code equivalent to:
384 paddedsize = (sizeof(TYPE) + 3) & -4;
385 if ((VALIST.__args + paddedsize > VALIST.__skip)
386 & (VALIST.__args <= VALIST.__skip))
387 addr = VALIST.__skip + STACK_POINTER_OFFSET;
388 else
389 addr = VALIST.__args;
390 VALIST.__args = addr + paddedsize;
391 ret = *(TYPE *)addr; */
392 static tree
393 tilepro_gimplify_va_arg_expr (tree valist, tree type, gimple_seq * pre_p,
394 gimple_seq * post_p ATTRIBUTE_UNUSED)
396 tree f_args, f_skip;
397 tree args, skip;
398 HOST_WIDE_INT size, rsize;
399 tree addr, tmp;
400 bool pass_by_reference_p;
402 f_args = TYPE_FIELDS (va_list_type_node);
403 f_skip = TREE_CHAIN (f_args);
405 args =
406 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
407 skip =
408 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
410 addr = create_tmp_var (ptr_type_node, "va_arg");
412 /* if an object is dynamically sized, a pointer to it is passed
413 instead of the object itself. */
414 pass_by_reference_p = pass_by_reference (NULL, TYPE_MODE (type), type,
415 false);
417 if (pass_by_reference_p)
418 type = build_pointer_type (type);
420 size = int_size_in_bytes (type);
421 rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD;
423 /* If the alignment of the type is greater than the default for a
424 parameter, align to STACK_BOUNDARY. */
425 if (TYPE_ALIGN (type) > PARM_BOUNDARY)
427 /* Assert the only case we generate code for: when
428 stack boundary = 2 * parm boundary. */
429 gcc_assert (STACK_BOUNDARY == PARM_BOUNDARY * 2);
431 tmp = build2 (BIT_AND_EXPR, sizetype,
432 fold_convert (sizetype, unshare_expr (args)),
433 size_int (PARM_BOUNDARY / 8));
434 tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node,
435 unshare_expr (args), tmp);
437 gimplify_assign (unshare_expr (args), tmp, pre_p);
440 /* Build conditional expression to calculate addr. The expression
441 will be gimplified later. */
442 tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize);
443 tmp = build2 (TRUTH_AND_EXPR, boolean_type_node,
444 build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)),
445 build2 (LE_EXPR, boolean_type_node, unshare_expr (args),
446 unshare_expr (skip)));
448 tmp = build3 (COND_EXPR, ptr_type_node, tmp,
449 build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip),
450 size_int (STACK_POINTER_OFFSET)),
451 unshare_expr (args));
453 gimplify_assign (addr, tmp, pre_p);
455 /* Update VALIST.__args. */
456 tmp = fold_build_pointer_plus_hwi (addr, rsize);
457 gimplify_assign (unshare_expr (args), tmp, pre_p);
459 addr = fold_convert (build_pointer_type (type), addr);
461 if (pass_by_reference_p)
462 addr = build_va_arg_indirect_ref (addr);
464 return build_va_arg_indirect_ref (addr);
469 /* Implement TARGET_RTX_COSTS. */
470 static bool
471 tilepro_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
472 bool speed)
474 switch (code)
476 case CONST_INT:
477 /* If this is an 8-bit constant, return zero since it can be
478 used nearly anywhere with no cost. If it is a valid operand
479 for an ADD or AND, likewise return 0 if we know it will be
480 used in that context. Otherwise, return 2 since it might be
481 used there later. All other constants take at least two
482 insns. */
483 if (satisfies_constraint_I (x))
485 *total = 0;
486 return true;
488 else if (outer_code == PLUS && add_operand (x, VOIDmode))
490 /* Slightly penalize large constants even though we can add
491 them in one instruction, because it forces the use of
492 2-wide bundling mode. */
493 *total = 1;
494 return true;
496 else if (move_operand (x, SImode))
498 /* We can materialize in one move. */
499 *total = COSTS_N_INSNS (1);
500 return true;
502 else
504 /* We can materialize in two moves. */
505 *total = COSTS_N_INSNS (2);
506 return true;
509 return false;
511 case CONST:
512 case LABEL_REF:
513 case SYMBOL_REF:
514 *total = COSTS_N_INSNS (2);
515 return true;
517 case CONST_DOUBLE:
518 *total = COSTS_N_INSNS (4);
519 return true;
521 case HIGH:
522 *total = 0;
523 return true;
525 case MEM:
526 /* If outer-code was a sign or zero extension, a cost of
527 COSTS_N_INSNS (1) was already added in, so account for
528 that. */
529 if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND)
530 *total = COSTS_N_INSNS (1);
531 else
532 *total = COSTS_N_INSNS (2);
533 return true;
535 case PLUS:
536 /* Convey that s[123]a are efficient. */
537 if (GET_CODE (XEXP (x, 0)) == MULT
538 && cint_248_operand (XEXP (XEXP (x, 0), 1), VOIDmode))
540 *total = (rtx_cost (XEXP (XEXP (x, 0), 0),
541 (enum rtx_code) outer_code, opno, speed)
542 + rtx_cost (XEXP (x, 1),
543 (enum rtx_code) outer_code, opno, speed)
544 + COSTS_N_INSNS (1));
545 return true;
547 return false;
549 case MULT:
550 *total = COSTS_N_INSNS (2);
551 return false;
553 case SIGN_EXTEND:
554 case ZERO_EXTEND:
555 if (outer_code == MULT)
556 *total = 0;
557 else
558 *total = COSTS_N_INSNS (1);
559 return false;
561 case DIV:
562 case UDIV:
563 case MOD:
564 case UMOD:
565 /* These are handled by software and are very expensive. */
566 *total = COSTS_N_INSNS (100);
567 return false;
569 case UNSPEC:
570 case UNSPEC_VOLATILE:
572 int num = XINT (x, 1);
574 if (num <= TILEPRO_LAST_LATENCY_1_INSN)
575 *total = COSTS_N_INSNS (1);
576 else if (num <= TILEPRO_LAST_LATENCY_2_INSN)
577 *total = COSTS_N_INSNS (2);
578 else if (num > TILEPRO_LAST_LATENCY_INSN)
580 if (outer_code == PLUS)
581 *total = 0;
582 else
583 *total = COSTS_N_INSNS (1);
585 else
587 switch (num)
589 case UNSPEC_BLOCKAGE:
590 case UNSPEC_NETWORK_BARRIER:
591 *total = 0;
592 break;
594 case UNSPEC_LNK_AND_LABEL:
595 case UNSPEC_MF:
596 case UNSPEC_NETWORK_RECEIVE:
597 case UNSPEC_NETWORK_SEND:
598 case UNSPEC_TLS_GD_ADD:
599 *total = COSTS_N_INSNS (1);
600 break;
602 case UNSPEC_TLS_IE_LOAD:
603 *total = COSTS_N_INSNS (2);
604 break;
606 case UNSPEC_SP_SET:
607 *total = COSTS_N_INSNS (3);
608 break;
610 case UNSPEC_SP_TEST:
611 *total = COSTS_N_INSNS (4);
612 break;
614 case UNSPEC_LATENCY_L2:
615 *total = COSTS_N_INSNS (8);
616 break;
618 case UNSPEC_TLS_GD_CALL:
619 *total = COSTS_N_INSNS (30);
620 break;
622 case UNSPEC_LATENCY_MISS:
623 *total = COSTS_N_INSNS (80);
624 break;
626 default:
627 *total = COSTS_N_INSNS (1);
630 return true;
633 default:
634 return false;
640 /* Returns an SImode integer rtx with value VAL. */
641 static rtx
642 gen_int_si (HOST_WIDE_INT val)
644 return gen_int_mode (val, SImode);
648 /* Create a temporary variable to hold a partial result, to enable
649 CSE. */
650 static rtx
651 create_temp_reg_if_possible (enum machine_mode mode, rtx default_reg)
653 return can_create_pseudo_p ()? gen_reg_rtx (mode) : default_reg;
657 /* Functions to save and restore machine-specific function data. */
658 static struct machine_function *
659 tilepro_init_machine_status (void)
661 return ggc_alloc_cleared_machine_function ();
665 /* Do anything needed before RTL is emitted for each function. */
666 void
667 tilepro_init_expanders (void)
669 /* Arrange to initialize and mark the machine per-function
670 status. */
671 init_machine_status = tilepro_init_machine_status;
673 if (cfun && cfun->machine && flag_pic)
675 static int label_num = 0;
677 char text_label_name[32];
679 struct machine_function *machine = cfun->machine;
681 ASM_GENERATE_INTERNAL_LABEL (text_label_name, "L_PICLNK", label_num++);
683 machine->text_label_symbol =
684 gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (text_label_name));
686 machine->text_label_rtx =
687 gen_rtx_REG (Pmode, TILEPRO_PIC_TEXT_LABEL_REGNUM);
689 machine->got_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
691 machine->calls_tls_get_addr = false;
696 /* Return true if X contains a thread-local symbol. */
697 static bool
698 tilepro_tls_referenced_p (rtx x)
700 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
701 x = XEXP (XEXP (x, 0), 0);
703 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
704 return true;
706 /* That's all we handle in tilepro_legitimize_tls_address for
707 now. */
708 return false;
712 /* Return true if X requires a scratch register. It is given that
713 flag_pic is on and that X satisfies CONSTANT_P. */
714 static int
715 tilepro_pic_address_needs_scratch (rtx x)
717 if (GET_CODE (x) == CONST
718 && GET_CODE (XEXP (x, 0)) == PLUS
719 && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
720 || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
721 && CONST_INT_P (XEXP (XEXP (x, 0), 1)))
722 return true;
724 return false;
728 /* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
729 which we are willing to load the value into a register via a move
730 pattern. TLS cannot be treated as a constant because it can
731 include a function call. */
732 static bool
733 tilepro_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
735 switch (GET_CODE (x))
737 case CONST:
738 case SYMBOL_REF:
739 return !tilepro_tls_referenced_p (x);
741 default:
742 return true;
747 /* Return true if the constant value X is a legitimate general operand
748 when generating PIC code. It is given that flag_pic is on and that
749 X satisfies CONSTANT_P. */
750 bool
751 tilepro_legitimate_pic_operand_p (rtx x)
753 if (tilepro_pic_address_needs_scratch (x))
754 return false;
756 if (tilepro_tls_referenced_p (x))
757 return false;
759 return true;
763 /* Return true if the rtx X can be used as an address operand. */
764 static bool
765 tilepro_legitimate_address_p (enum machine_mode ARG_UNUSED (mode), rtx x,
766 bool strict)
768 if (GET_CODE (x) == SUBREG)
769 x = SUBREG_REG (x);
771 switch (GET_CODE (x))
773 case POST_INC:
774 case POST_DEC:
775 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
776 return false;
778 x = XEXP (x, 0);
779 break;
781 case POST_MODIFY:
782 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
783 return false;
785 if (GET_CODE (XEXP (x, 1)) != PLUS)
786 return false;
788 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
789 return false;
791 if (!satisfies_constraint_I (XEXP (XEXP (x, 1), 1)))
792 return false;
794 x = XEXP (x, 0);
795 break;
797 case REG:
798 break;
800 default:
801 return false;
804 /* Check if x is a valid reg. */
805 if (!REG_P (x))
806 return false;
808 if (strict)
809 return REGNO_OK_FOR_BASE_P (REGNO (x));
810 else
811 return true;
815 /* Return the rtx containing SYMBOL_REF to the text label. */
816 static rtx
817 tilepro_text_label_symbol (void)
819 return cfun->machine->text_label_symbol;
823 /* Return the register storing the value of the text label. */
824 static rtx
825 tilepro_text_label_rtx (void)
827 return cfun->machine->text_label_rtx;
831 /* Return the register storing the value of the global offset
832 table. */
833 static rtx
834 tilepro_got_rtx (void)
836 return cfun->machine->got_rtx;
840 /* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
841 static rtx
842 tilepro_got_symbol (void)
844 if (g_got_symbol == NULL)
845 g_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
847 return g_got_symbol;
851 /* Return a reference to the got to be used by tls references. */
852 static rtx
853 tilepro_tls_got (void)
855 rtx temp;
856 if (flag_pic)
858 crtl->uses_pic_offset_table = 1;
859 return tilepro_got_rtx ();
862 temp = gen_reg_rtx (Pmode);
863 emit_move_insn (temp, tilepro_got_symbol ());
865 return temp;
869 /* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
870 this (thread-local) address. */
871 static rtx
872 tilepro_legitimize_tls_address (rtx addr)
874 rtx ret;
876 gcc_assert (can_create_pseudo_p ());
878 if (GET_CODE (addr) == SYMBOL_REF)
879 switch (SYMBOL_REF_TLS_MODEL (addr))
881 case TLS_MODEL_GLOBAL_DYNAMIC:
882 case TLS_MODEL_LOCAL_DYNAMIC:
884 rtx r0, temp1, temp2, temp3, got, last;
886 ret = gen_reg_rtx (Pmode);
887 r0 = gen_rtx_REG (Pmode, 0);
888 temp1 = gen_reg_rtx (Pmode);
889 temp2 = gen_reg_rtx (Pmode);
890 temp3 = gen_reg_rtx (Pmode);
892 got = tilepro_tls_got ();
893 emit_insn (gen_tls_gd_addhi (temp1, got, addr));
894 emit_insn (gen_tls_gd_addlo (temp2, temp1, addr));
895 emit_move_insn (r0, temp2);
896 emit_insn (gen_tls_gd_call (addr));
897 emit_move_insn (temp3, r0);
898 last = emit_insn (gen_tls_gd_add (ret, temp3, addr));
899 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
900 break;
902 case TLS_MODEL_INITIAL_EXEC:
904 rtx temp1, temp2, temp3, got, last;
906 ret = gen_reg_rtx (Pmode);
907 temp1 = gen_reg_rtx (Pmode);
908 temp2 = gen_reg_rtx (Pmode);
909 temp3 = gen_reg_rtx (Pmode);
911 got = tilepro_tls_got ();
912 emit_insn (gen_tls_ie_addhi (temp1, got, addr));
913 emit_insn (gen_tls_ie_addlo (temp2, temp1, addr));
914 emit_insn (gen_tls_ie_load (temp3, temp2, addr));
915 last =
916 emit_move_insn(ret,
917 gen_rtx_PLUS (Pmode,
918 gen_rtx_REG (Pmode,
919 THREAD_POINTER_REGNUM),
920 temp3));
921 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
922 break;
924 case TLS_MODEL_LOCAL_EXEC:
926 rtx temp1, last;
928 ret = gen_reg_rtx (Pmode);
929 temp1 = gen_reg_rtx (Pmode);
931 emit_insn (gen_tls_le_addhi (temp1,
932 gen_rtx_REG (Pmode,
933 THREAD_POINTER_REGNUM),
934 addr));
935 last = emit_insn (gen_tls_le_addlo (ret, temp1, addr));
936 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
937 break;
939 default:
940 gcc_unreachable ();
942 else if (GET_CODE (addr) == CONST)
944 rtx base, offset;
946 gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
948 base = tilepro_legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
949 offset = XEXP (XEXP (addr, 0), 1);
951 base = force_operand (base, NULL_RTX);
952 ret = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
954 else
955 gcc_unreachable ();
957 return ret;
961 /* Legitimize PIC addresses. If the address is already
962 position-independent, we return ORIG. Newly generated
963 position-independent addresses go into a reg. This is REG if
964 nonzero, otherwise we allocate register(s) as necessary. */
965 static rtx
966 tilepro_legitimize_pic_address (rtx orig,
967 enum machine_mode mode ATTRIBUTE_UNUSED,
968 rtx reg)
970 if (GET_CODE (orig) == SYMBOL_REF)
972 rtx address, pic_ref;
974 if (reg == 0)
976 gcc_assert (can_create_pseudo_p ());
977 reg = gen_reg_rtx (Pmode);
980 if (SYMBOL_REF_LOCAL_P (orig))
982 /* If not during reload, allocate another temp reg here for
983 loading in the address, so that these instructions can be
984 optimized properly. */
985 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
986 rtx text_label_symbol = tilepro_text_label_symbol ();
987 rtx text_label_rtx = tilepro_text_label_rtx ();
989 emit_insn (gen_addli_pcrel (temp_reg, text_label_rtx, orig,
990 text_label_symbol));
991 emit_insn (gen_auli_pcrel (temp_reg, temp_reg, orig,
992 text_label_symbol));
994 /* Note: this is conservative. We use the text_label but we
995 don't use the pic_offset_table. However, in some cases
996 we may need the pic_offset_table (see
997 tilepro_fixup_pcrel_references). */
998 crtl->uses_pic_offset_table = 1;
1000 address = temp_reg;
1002 emit_move_insn (reg, address);
1003 return reg;
1005 else
1007 /* If not during reload, allocate another temp reg here for
1008 loading in the address, so that these instructions can be
1009 optimized properly. */
1010 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
1012 gcc_assert (flag_pic);
1013 if (flag_pic == 1)
1015 emit_insn (gen_add_got16 (temp_reg,
1016 tilepro_got_rtx (), orig));
1018 else
1020 rtx temp_reg2 = create_temp_reg_if_possible (Pmode, reg);
1021 emit_insn (gen_addhi_got32 (temp_reg2,
1022 tilepro_got_rtx (), orig));
1023 emit_insn (gen_addlo_got32 (temp_reg, temp_reg2, orig));
1026 address = temp_reg;
1028 pic_ref = gen_const_mem (Pmode, address);
1029 crtl->uses_pic_offset_table = 1;
1030 emit_move_insn (reg, pic_ref);
1031 /* The following put a REG_EQUAL note on this insn, so that
1032 it can be optimized by loop. But it causes the label to
1033 be optimized away. */
1034 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1035 return reg;
1038 else if (GET_CODE (orig) == CONST)
1040 rtx base, offset;
1042 if (GET_CODE (XEXP (orig, 0)) == PLUS
1043 && XEXP (XEXP (orig, 0), 0) == tilepro_got_rtx ())
1044 return orig;
1046 if (reg == 0)
1048 gcc_assert (can_create_pseudo_p ());
1049 reg = gen_reg_rtx (Pmode);
1052 gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
1053 base = tilepro_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode,
1054 reg);
1055 offset =
1056 tilepro_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
1057 base == reg ? 0 : reg);
1059 if (CONST_INT_P (offset))
1061 if (can_create_pseudo_p ())
1062 offset = force_reg (Pmode, offset);
1063 else
1064 /* If we reach here, then something is seriously
1065 wrong. */
1066 gcc_unreachable ();
1069 if (can_create_pseudo_p ())
1070 return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
1071 else
1072 gcc_unreachable ();
1074 else if (GET_CODE (orig) == LABEL_REF)
1076 rtx address, temp_reg;
1077 rtx text_label_symbol;
1078 rtx text_label_rtx;
1080 if (reg == 0)
1082 gcc_assert (can_create_pseudo_p ());
1083 reg = gen_reg_rtx (Pmode);
1086 /* If not during reload, allocate another temp reg here for
1087 loading in the address, so that these instructions can be
1088 optimized properly. */
1089 temp_reg = create_temp_reg_if_possible (Pmode, reg);
1090 text_label_symbol = tilepro_text_label_symbol ();
1091 text_label_rtx = tilepro_text_label_rtx ();
1093 emit_insn (gen_addli_pcrel (temp_reg, text_label_rtx, orig,
1094 text_label_symbol));
1095 emit_insn (gen_auli_pcrel (temp_reg, temp_reg, orig,
1096 text_label_symbol));
1098 /* Note: this is conservative. We use the text_label but we
1099 don't use the pic_offset_table. */
1100 crtl->uses_pic_offset_table = 1;
1102 address = temp_reg;
1104 emit_move_insn (reg, address);
1106 return reg;
1109 return orig;
1113 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1114 static rtx
1115 tilepro_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1116 enum machine_mode mode)
1118 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
1119 && symbolic_operand (x, Pmode) && tilepro_tls_referenced_p (x))
1121 return tilepro_legitimize_tls_address (x);
1123 else if (flag_pic)
1125 return tilepro_legitimize_pic_address (x, mode, 0);
1127 else
1128 return x;
1132 /* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1133 static rtx
1134 tilepro_delegitimize_address (rtx x)
1136 x = delegitimize_mem_from_attrs (x);
1138 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC)
1140 switch (XINT (XEXP (x, 0), 1))
1142 case UNSPEC_PCREL_SYM:
1143 case UNSPEC_GOT16_SYM:
1144 case UNSPEC_GOT32_SYM:
1145 case UNSPEC_TLS_GD:
1146 case UNSPEC_TLS_IE:
1147 x = XVECEXP (XEXP (x, 0), 0, 0);
1148 break;
1152 return x;
1156 /* Emit code to load the PIC register. */
1157 static void
1158 load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED)
1160 int orig_flag_pic = flag_pic;
1162 rtx got_symbol = tilepro_got_symbol ();
1163 rtx text_label_symbol = tilepro_text_label_symbol ();
1164 rtx text_label_rtx = tilepro_text_label_rtx ();
1165 flag_pic = 0;
1167 emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol));
1169 emit_insn (gen_addli_pcrel (tilepro_got_rtx (),
1170 text_label_rtx, got_symbol, text_label_symbol));
1172 emit_insn (gen_auli_pcrel (tilepro_got_rtx (),
1173 tilepro_got_rtx (),
1174 got_symbol, text_label_symbol));
1176 flag_pic = orig_flag_pic;
1178 /* Need to emit this whether or not we obey regdecls, since
1179 setjmp/longjmp can cause life info to screw up. ??? In the case
1180 where we don't obey regdecls, this is not sufficient since we may
1181 not fall out the bottom. */
1182 emit_use (tilepro_got_rtx ());
1186 /* Return the simd variant of the constant NUM of mode MODE, by
1187 replicating it to fill an interger of mode SImode. NUM is first
1188 truncated to fit in MODE. */
1190 tilepro_simd_int (rtx num, enum machine_mode mode)
1192 HOST_WIDE_INT n = 0;
1194 gcc_assert (CONST_INT_P (num));
1196 n = INTVAL (num);
1198 switch (mode)
1200 case QImode:
1201 n = 0x01010101 * (n & 0x000000FF);
1202 break;
1203 case HImode:
1204 n = 0x00010001 * (n & 0x0000FFFF);
1205 break;
1206 case SImode:
1207 break;
1208 case DImode:
1209 break;
1210 default:
1211 gcc_unreachable ();
1214 return gen_int_si (n);
1218 /* Split one or more DImode RTL references into pairs of SImode
1219 references. The RTL can be REG, offsettable MEM, integer constant,
1220 or CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL
1221 to split and "num" is its length. lo_half and hi_half are output
1222 arrays that parallel "operands". */
1223 void
1224 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1226 while (num--)
1228 rtx op = operands[num];
1230 /* simplify_subreg refuse to split volatile memory addresses,
1231 but we still have to handle it. */
1232 if (MEM_P (op))
1234 lo_half[num] = adjust_address (op, SImode, 0);
1235 hi_half[num] = adjust_address (op, SImode, 4);
1237 else
1239 lo_half[num] = simplify_gen_subreg (SImode, op,
1240 GET_MODE (op) == VOIDmode
1241 ? DImode : GET_MODE (op), 0);
1242 hi_half[num] = simplify_gen_subreg (SImode, op,
1243 GET_MODE (op) == VOIDmode
1244 ? DImode : GET_MODE (op), 4);
1250 /* Returns true iff val can be moved into a register in one
1251 instruction. And if it can, it emits the code to move the
1252 constant.
1254 If three_wide_only is true, this insists on an instruction that
1255 works in a bundle containing three instructions. */
1256 static bool
1257 expand_set_cint32_one_inst (rtx dest_reg,
1258 HOST_WIDE_INT val, bool three_wide_only)
1260 val = trunc_int_for_mode (val, SImode);
1262 if (val == trunc_int_for_mode (val, QImode))
1264 /* Success! */
1265 emit_move_insn (dest_reg, GEN_INT (val));
1266 return true;
1268 else if (!three_wide_only)
1270 rtx imm_op = GEN_INT (val);
1272 if (satisfies_constraint_J (imm_op)
1273 || satisfies_constraint_K (imm_op)
1274 || satisfies_constraint_N (imm_op)
1275 || satisfies_constraint_P (imm_op))
1277 emit_move_insn (dest_reg, imm_op);
1278 return true;
1282 return false;
1286 /* Implement SImode rotatert. */
1287 static HOST_WIDE_INT
1288 rotate_right (HOST_WIDE_INT n, int count)
1290 unsigned HOST_WIDE_INT x = n & 0xFFFFFFFF;
1291 if (count == 0)
1292 return x;
1293 return ((x >> count) | (x << (32 - count))) & 0xFFFFFFFF;
1297 /* Return true iff n contains exactly one contiguous sequence of 1
1298 bits, possibly wrapping around from high bits to low bits. */
1299 bool
1300 tilepro_bitfield_operand_p (HOST_WIDE_INT n, int *first_bit, int *last_bit)
1302 int i;
1304 if (n == 0)
1305 return false;
1307 for (i = 0; i < 32; i++)
1309 unsigned HOST_WIDE_INT x = rotate_right (n, i);
1310 if (!(x & 1))
1311 continue;
1313 /* See if x is a power of two minus one, i.e. only consecutive 1
1314 bits starting from bit 0. */
1315 if ((x & (x + 1)) == 0)
1317 if (first_bit != NULL)
1318 *first_bit = i;
1319 if (last_bit != NULL)
1320 *last_bit = (i + exact_log2 (x ^ (x >> 1))) & 31;
1322 return true;
1326 return false;
1330 /* Create code to move the CONST_INT value in src_val to dest_reg. */
1331 static void
1332 expand_set_cint32 (rtx dest_reg, rtx src_val)
1334 HOST_WIDE_INT val;
1335 int leading_zeroes, trailing_zeroes;
1336 int lower, upper;
1337 int three_wide_only;
1338 rtx temp;
1340 gcc_assert (CONST_INT_P (src_val));
1341 val = trunc_int_for_mode (INTVAL (src_val), SImode);
1343 /* See if we can generate the constant in one instruction. */
1344 if (expand_set_cint32_one_inst (dest_reg, val, false))
1345 return;
1347 /* Create a temporary variable to hold a partial result, to enable
1348 CSE. */
1349 temp = create_temp_reg_if_possible (SImode, dest_reg);
1351 leading_zeroes = 31 - floor_log2 (val & 0xFFFFFFFF);
1352 trailing_zeroes = exact_log2 (val & -val);
1354 lower = trunc_int_for_mode (val, HImode);
1355 upper = trunc_int_for_mode ((val - lower) >> 16, HImode);
1357 /* First try all three-wide instructions that generate a constant
1358 (i.e. movei) followed by various shifts and rotates. If none of
1359 those work, try various two-wide ways of generating a constant
1360 followed by various shifts and rotates. */
1361 for (three_wide_only = 1; three_wide_only >= 0; three_wide_only--)
1363 int count;
1365 if (expand_set_cint32_one_inst (temp, val >> trailing_zeroes,
1366 three_wide_only))
1368 /* 0xFFFFA500 becomes:
1369 movei temp, 0xFFFFFFA5
1370 shli dest, temp, 8 */
1371 emit_move_insn (dest_reg,
1372 gen_rtx_ASHIFT (SImode, temp,
1373 GEN_INT (trailing_zeroes)));
1374 return;
1377 if (expand_set_cint32_one_inst (temp, val << leading_zeroes,
1378 three_wide_only))
1380 /* 0x7FFFFFFF becomes:
1381 movei temp, -2
1382 shri dest, temp, 1 */
1383 emit_move_insn (dest_reg,
1384 gen_rtx_LSHIFTRT (SImode, temp,
1385 GEN_INT (leading_zeroes)));
1386 return;
1389 /* Try rotating a one-instruction immediate, since rotate is
1390 3-wide. */
1391 for (count = 1; count < 32; count++)
1393 HOST_WIDE_INT r = rotate_right (val, count);
1394 if (expand_set_cint32_one_inst (temp, r, three_wide_only))
1396 /* 0xFFA5FFFF becomes:
1397 movei temp, 0xFFFFFFA5
1398 rli dest, temp, 16 */
1399 emit_move_insn (dest_reg,
1400 gen_rtx_ROTATE (SImode, temp, GEN_INT (count)));
1401 return;
1405 if (lower == trunc_int_for_mode (lower, QImode))
1407 /* We failed to use two 3-wide instructions, but the low 16
1408 bits are a small number so just use a 2-wide + 3-wide
1409 auli + addi pair rather than anything more exotic.
1411 0x12340056 becomes:
1412 auli temp, zero, 0x1234
1413 addi dest, temp, 0x56 */
1414 break;
1418 /* Fallback case: use a auli + addli/addi pair. */
1419 emit_move_insn (temp, GEN_INT (upper << 16));
1420 emit_move_insn (dest_reg, (gen_rtx_PLUS (SImode, temp, GEN_INT (lower))));
1424 /* Load OP1, a 32-bit constant, into OP0, a register. We know it
1425 can't be done in one insn when we get here, the move expander
1426 guarantees this. */
1427 void
1428 tilepro_expand_set_const32 (rtx op0, rtx op1)
1430 enum machine_mode mode = GET_MODE (op0);
1431 rtx temp;
1433 if (CONST_INT_P (op1))
1435 /* TODO: I don't know if we want to split large constants now,
1436 or wait until later (with a define_split).
1438 Does splitting early help CSE? Does it harm other
1439 optimizations that might fold loads? */
1440 expand_set_cint32 (op0, op1);
1442 else
1444 temp = create_temp_reg_if_possible (mode, op0);
1446 /* A symbol, emit in the traditional way. */
1447 emit_move_insn (temp, gen_rtx_HIGH (mode, op1));
1448 emit_move_insn (op0, gen_rtx_LO_SUM (mode, temp, op1));
1453 /* Expand a move instruction. Return true if all work is done. */
1454 bool
1455 tilepro_expand_mov (enum machine_mode mode, rtx *operands)
1457 /* Handle sets of MEM first. */
1458 if (MEM_P (operands[0]))
1460 if (can_create_pseudo_p ())
1461 operands[0] = validize_mem (operands[0]);
1463 if (reg_or_0_operand (operands[1], mode))
1464 return false;
1466 if (!reload_in_progress)
1467 operands[1] = force_reg (mode, operands[1]);
1470 /* Fixup TLS cases. */
1471 if (CONSTANT_P (operands[1]) && tilepro_tls_referenced_p (operands[1]))
1473 operands[1] = tilepro_legitimize_tls_address (operands[1]);
1474 return false;
1477 /* Fixup PIC cases. */
1478 if (flag_pic && CONSTANT_P (operands[1]))
1480 if (tilepro_pic_address_needs_scratch (operands[1]))
1481 operands[1] = tilepro_legitimize_pic_address (operands[1], mode, 0);
1483 if (symbolic_operand (operands[1], mode))
1485 operands[1] = tilepro_legitimize_pic_address (operands[1],
1486 mode,
1487 (reload_in_progress ?
1488 operands[0] :
1489 NULL_RTX));
1490 return false;
1494 /* Fixup for UNSPEC addresses. */
1495 if (flag_pic
1496 && GET_CODE (operands[1]) == HIGH
1497 && GET_CODE (XEXP (operands[1], 0)) == CONST
1498 && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == UNSPEC)
1500 rtx unspec = XEXP (XEXP (operands[1], 0), 0);
1501 int unspec_num = XINT (unspec, 1);
1502 if (unspec_num == UNSPEC_PCREL_SYM)
1504 emit_insn (gen_auli_pcrel (operands[0], const0_rtx,
1505 XVECEXP (unspec, 0, 0),
1506 XVECEXP (unspec, 0, 1)));
1507 return true;
1509 else if (flag_pic == 2 && unspec_num == UNSPEC_GOT32_SYM)
1511 emit_insn (gen_addhi_got32 (operands[0], const0_rtx,
1512 XVECEXP (unspec, 0, 0)));
1513 return true;
1515 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_GD)
1517 emit_insn (gen_tls_gd_addhi (operands[0], const0_rtx,
1518 XVECEXP (unspec, 0, 0)));
1519 return true;
1521 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_IE)
1523 emit_insn (gen_tls_ie_addhi (operands[0], const0_rtx,
1524 XVECEXP (unspec, 0, 0)));
1525 return true;
1527 else if (HAVE_AS_TLS && unspec_num == UNSPEC_TLS_LE)
1529 emit_insn (gen_tls_le_addhi (operands[0], const0_rtx,
1530 XVECEXP (unspec, 0, 0)));
1531 return true;
1535 /* Accept non-constants and valid constants unmodified. */
1536 if (!CONSTANT_P (operands[1])
1537 || GET_CODE (operands[1]) == HIGH || move_operand (operands[1], mode))
1538 return false;
1540 /* Split large integers. */
1541 if (GET_MODE_SIZE (mode) <= 4)
1543 tilepro_expand_set_const32 (operands[0], operands[1]);
1544 return true;
1547 return false;
1551 /* Expand the "insv" pattern. */
1552 void
1553 tilepro_expand_insv (rtx operands[4])
1555 rtx first_rtx = operands[2];
1556 HOST_WIDE_INT first = INTVAL (first_rtx);
1557 HOST_WIDE_INT width = INTVAL (operands[1]);
1558 rtx v = operands[3];
1560 /* Shift the inserted bits into position. */
1561 if (first != 0)
1563 if (CONST_INT_P (v))
1565 /* Shift the constant into mm position. */
1566 v = gen_int_si (INTVAL (v) << first);
1568 else
1570 /* Shift over the value to be inserted. */
1571 rtx tmp = gen_reg_rtx (SImode);
1572 emit_insn (gen_ashlsi3 (tmp, v, first_rtx));
1573 v = tmp;
1577 /* Insert the shifted bits using an 'mm' insn. */
1578 emit_insn (gen_insn_mm (operands[0], v, operands[0], first_rtx,
1579 GEN_INT (first + width - 1)));
1583 /* Expand unaligned loads. */
1584 void
1585 tilepro_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize,
1586 HOST_WIDE_INT bit_offset, bool sign)
1588 enum machine_mode mode;
1589 rtx addr_lo, addr_hi;
1590 rtx mem_lo, mem_hi, hi;
1591 rtx mema, wide_result;
1592 int last_byte_offset;
1593 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1595 mode = GET_MODE (dest_reg);
1597 hi = gen_reg_rtx (mode);
1599 if (bitsize == 2 * BITS_PER_UNIT && (bit_offset % BITS_PER_UNIT) == 0)
1601 rtx lo;
1603 /* When just loading a two byte value, we can load the two bytes
1604 individually and combine them efficiently. */
1606 mem_lo = adjust_address (mem, QImode, byte_offset);
1607 mem_hi = adjust_address (mem, QImode, byte_offset + 1);
1609 lo = gen_reg_rtx (mode);
1610 emit_insn (gen_zero_extendqisi2 (lo, mem_lo));
1612 if (sign)
1614 rtx tmp = gen_reg_rtx (mode);
1616 /* Do a signed load of the second byte then shift and OR it
1617 in. */
1618 emit_insn (gen_extendqisi2 (gen_lowpart (SImode, hi), mem_hi));
1619 emit_insn (gen_ashlsi3 (gen_lowpart (SImode, tmp),
1620 gen_lowpart (SImode, hi), GEN_INT (8)));
1621 emit_insn (gen_iorsi3 (gen_lowpart (SImode, dest_reg),
1622 gen_lowpart (SImode, lo),
1623 gen_lowpart (SImode, tmp)));
1625 else
1627 /* Do two unsigned loads and use intlb to interleave
1628 them. */
1629 emit_insn (gen_zero_extendqisi2 (gen_lowpart (SImode, hi), mem_hi));
1630 emit_insn (gen_insn_intlb (gen_lowpart (SImode, dest_reg),
1631 gen_lowpart (SImode, hi),
1632 gen_lowpart (SImode, lo)));
1635 return;
1638 mema = XEXP (mem, 0);
1640 /* AND addresses cannot be in any alias set, since they may
1641 implicitly alias surrounding code. Ideally we'd have some alias
1642 set that covered all types except those with alignment 8 or
1643 higher. */
1644 addr_lo = force_reg (Pmode, plus_constant (Pmode, mema, byte_offset));
1645 mem_lo = change_address (mem, mode,
1646 gen_rtx_AND (Pmode, addr_lo, GEN_INT (-4)));
1647 set_mem_alias_set (mem_lo, 0);
1649 /* Load the high word at an address that will not fault if the low
1650 address is aligned and at the very end of a page. */
1651 last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT;
1652 addr_hi = force_reg (Pmode, plus_constant (Pmode, mema, last_byte_offset));
1653 mem_hi = change_address (mem, mode,
1654 gen_rtx_AND (Pmode, addr_hi, GEN_INT (-4)));
1655 set_mem_alias_set (mem_hi, 0);
1657 if (bitsize == 32)
1659 addr_lo = make_safe_from (addr_lo, dest_reg);
1660 wide_result = dest_reg;
1662 else
1664 wide_result = gen_reg_rtx (mode);
1667 /* Load hi first in case dest_reg is used in mema. */
1668 emit_move_insn (hi, mem_hi);
1669 emit_move_insn (wide_result, mem_lo);
1671 emit_insn (gen_insn_dword_align (gen_lowpart (SImode, wide_result),
1672 gen_lowpart (SImode, wide_result),
1673 gen_lowpart (SImode, hi), addr_lo));
1675 if (bitsize != 32)
1677 rtx extracted =
1678 extract_bit_field (gen_lowpart (SImode, wide_result),
1679 bitsize, bit_offset % BITS_PER_UNIT,
1680 !sign, gen_lowpart (SImode, dest_reg),
1681 SImode, SImode);
1683 if (extracted != dest_reg)
1684 emit_move_insn (dest_reg, gen_lowpart (SImode, extracted));
1689 /* Expand unaligned stores. */
1690 static void
1691 tilepro_expand_unaligned_store (rtx mem, rtx src, HOST_WIDE_INT bitsize,
1692 HOST_WIDE_INT bit_offset)
1694 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1695 HOST_WIDE_INT bytesize = bitsize / BITS_PER_UNIT;
1696 HOST_WIDE_INT shift_amt;
1697 HOST_WIDE_INT i;
1698 rtx mem_addr;
1699 rtx store_val;
1701 for (i = 0, shift_amt = 0; i < bytesize; i++, shift_amt += BITS_PER_UNIT)
1703 mem_addr = adjust_address (mem, QImode, byte_offset + i);
1705 if (shift_amt)
1707 store_val = expand_simple_binop (SImode, LSHIFTRT,
1708 gen_lowpart (SImode, src),
1709 GEN_INT (shift_amt), NULL, 1,
1710 OPTAB_LIB_WIDEN);
1711 store_val = gen_lowpart (QImode, store_val);
1713 else
1715 store_val = gen_lowpart (QImode, src);
1718 emit_move_insn (mem_addr, store_val);
1723 /* Implement the movmisalign patterns. One of the operands is a
1724 memory that is not naturally aligned. Emit instructions to load
1725 it. */
1726 void
1727 tilepro_expand_movmisalign (enum machine_mode mode, rtx *operands)
1729 if (MEM_P (operands[1]))
1731 rtx tmp;
1733 if (register_operand (operands[0], mode))
1734 tmp = operands[0];
1735 else
1736 tmp = gen_reg_rtx (mode);
1738 tilepro_expand_unaligned_load (tmp, operands[1],
1739 GET_MODE_BITSIZE (mode), 0, true);
1741 if (tmp != operands[0])
1742 emit_move_insn (operands[0], tmp);
1744 else if (MEM_P (operands[0]))
1746 if (!reg_or_0_operand (operands[1], mode))
1747 operands[1] = force_reg (mode, operands[1]);
1749 tilepro_expand_unaligned_store (operands[0], operands[1],
1750 GET_MODE_BITSIZE (mode), 0);
1752 else
1753 gcc_unreachable ();
1757 /* Implement the addsi3 pattern. */
1758 bool
1759 tilepro_expand_addsi (rtx op0, rtx op1, rtx op2)
1761 rtx temp;
1762 HOST_WIDE_INT n;
1763 HOST_WIDE_INT high;
1765 /* Skip anything that only takes one instruction. */
1766 if (add_operand (op2, SImode))
1767 return false;
1769 /* We can only optimize ints here (it should be impossible to get
1770 here with any other type, but it is harmless to check. */
1771 if (!CONST_INT_P (op2))
1772 return false;
1774 temp = create_temp_reg_if_possible (SImode, op0);
1775 n = INTVAL (op2);
1776 high = (n + (n & 0x8000)) & ~0xffff;
1778 emit_move_insn (temp, gen_rtx_PLUS (SImode, op1, gen_int_si (high)));
1779 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, gen_int_si (n - high)));
1781 return true;
1785 /* Implement the allocate_stack pattern (alloca). */
1786 void
1787 tilepro_allocate_stack (rtx op0, rtx op1)
1789 /* Technically the correct way to initialize chain_loc is with
1790 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
1791 * sets the alias_set to that of a frame reference. Some of our
1792 * tests rely on some unsafe assumption about when the chaining
1793 * update is done, we need to be conservative about reordering the
1794 * chaining instructions.
1796 rtx fp_addr = gen_reg_rtx (Pmode);
1797 rtx fp_value = gen_reg_rtx (Pmode);
1798 rtx fp_loc;
1800 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1801 GEN_INT (UNITS_PER_WORD)));
1803 fp_loc = gen_frame_mem (Pmode, fp_addr);
1805 emit_move_insn (fp_value, fp_loc);
1807 op1 = force_reg (Pmode, op1);
1809 emit_move_insn (stack_pointer_rtx,
1810 gen_rtx_MINUS (Pmode, stack_pointer_rtx, op1));
1812 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1813 GEN_INT (UNITS_PER_WORD)));
1815 fp_loc = gen_frame_mem (Pmode, fp_addr);
1817 emit_move_insn (fp_loc, fp_value);
1819 emit_move_insn (op0, virtual_stack_dynamic_rtx);
1824 /* Multiplies */
1826 /* Returns the insn_code in ENTRY. */
1827 static enum insn_code
1828 tilepro_multiply_get_opcode (const struct tilepro_multiply_insn_seq_entry
1829 *entry)
1831 return tilepro_multiply_insn_seq_decode_opcode[entry->compressed_opcode];
1835 /* Returns the length of the 'op' array. */
1836 static int
1837 tilepro_multiply_get_num_ops (const struct tilepro_multiply_insn_seq *seq)
1839 /* The array either uses all of its allocated slots or is terminated
1840 by a bogus opcode. Either way, the array size is the index of the
1841 last valid opcode plus one. */
1842 int i;
1843 for (i = tilepro_multiply_insn_seq_MAX_OPERATIONS - 1; i >= 0; i--)
1844 if (tilepro_multiply_get_opcode (&seq->op[i]) != CODE_FOR_nothing)
1845 return i + 1;
1847 /* An empty array is not allowed. */
1848 gcc_unreachable ();
1852 /* We precompute a number of expression trees for multiplying by
1853 constants. This generates code for such an expression tree by
1854 walking through the nodes in the tree (which are conveniently
1855 pre-linearized) and emitting an instruction for each one. */
1856 static void
1857 tilepro_expand_constant_multiply_given_sequence (rtx result, rtx src,
1858 const struct
1859 tilepro_multiply_insn_seq
1860 *seq)
1862 int i;
1863 int num_ops;
1865 /* Keep track of the subexpressions computed so far, so later
1866 instructions can refer to them. We seed the array with zero and
1867 the value being multiplied. */
1868 int num_subexprs = 2;
1869 rtx subexprs[tilepro_multiply_insn_seq_MAX_OPERATIONS + 2];
1870 subexprs[0] = const0_rtx;
1871 subexprs[1] = src;
1873 /* Determine how many instructions we are going to generate. */
1874 num_ops = tilepro_multiply_get_num_ops (seq);
1875 gcc_assert (num_ops > 0
1876 && num_ops <= tilepro_multiply_insn_seq_MAX_OPERATIONS);
1878 for (i = 0; i < num_ops; i++)
1880 const struct tilepro_multiply_insn_seq_entry *entry = &seq->op[i];
1882 /* Figure out where to store the output of this instruction. */
1883 const bool is_last_op = (i + 1 == num_ops);
1884 rtx out = is_last_op ? result : gen_reg_rtx (SImode);
1886 enum insn_code opcode = tilepro_multiply_get_opcode (entry);
1887 if (opcode == CODE_FOR_ashlsi3)
1889 /* Handle shift by immediate. This is a special case because
1890 the meaning of the second operand is a constant shift
1891 count rather than an operand index. */
1893 /* Make sure the shift count is in range. Zero should not
1894 happen. */
1895 const int shift_count = entry->rhs;
1896 gcc_assert (shift_count > 0 && shift_count < 32);
1898 /* Emit the actual instruction. */
1899 emit_insn (GEN_FCN (opcode)
1900 (out, subexprs[entry->lhs],
1901 gen_rtx_CONST_INT (SImode, shift_count)));
1903 else
1905 /* Handle a normal two-operand instruction, such as add or
1906 s1a. */
1908 /* Make sure we are referring to a previously computed
1909 subexpression. */
1910 gcc_assert (entry->rhs < num_subexprs);
1912 /* Emit the actual instruction. */
1913 emit_insn (GEN_FCN (opcode)
1914 (out, subexprs[entry->lhs], subexprs[entry->rhs]));
1917 /* Record this subexpression for use by later expressions. */
1918 subexprs[num_subexprs++] = out;
1923 /* bsearch helper function. */
1924 static int
1925 tilepro_compare_multipliers (const void *key, const void *t)
1927 return *(const int *) key -
1928 ((const struct tilepro_multiply_insn_seq *) t)->multiplier;
1932 /* Returns the tilepro_multiply_insn_seq for multiplier, or NULL if
1933 none exists. */
1934 static const struct tilepro_multiply_insn_seq *
1935 tilepro_find_multiply_insn_seq_for_constant (int multiplier)
1937 return ((const struct tilepro_multiply_insn_seq *)
1938 bsearch (&multiplier, tilepro_multiply_insn_seq_table,
1939 tilepro_multiply_insn_seq_table_size,
1940 sizeof tilepro_multiply_insn_seq_table[0],
1941 tilepro_compare_multipliers));
1945 /* Try to a expand constant multiply in SImode by looking it up in a
1946 precompiled table. OP0 is the result operand, OP1 is the source
1947 operand, and MULTIPLIER is the value of the constant. Return true
1948 if it succeeds. */
1949 static bool
1950 tilepro_expand_const_mulsi (rtx op0, rtx op1, int multiplier)
1952 /* See if we have precomputed an efficient way to multiply by this
1953 constant. */
1954 const struct tilepro_multiply_insn_seq *seq =
1955 tilepro_find_multiply_insn_seq_for_constant (multiplier);
1956 if (seq != NULL)
1958 tilepro_expand_constant_multiply_given_sequence (op0, op1, seq);
1959 return true;
1961 else
1962 return false;
1966 /* Expand the mulsi pattern. */
1967 bool
1968 tilepro_expand_mulsi (rtx op0, rtx op1, rtx op2)
1970 if (CONST_INT_P (op2))
1972 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), SImode);
1973 return tilepro_expand_const_mulsi (op0, op1, n);
1975 return false;
1979 /* Expand a high multiply pattern in SImode. RESULT, OP1, OP2 are the
1980 operands, and SIGN is true if it's a signed multiply, and false if
1981 it's an unsigned multiply. */
1982 static void
1983 tilepro_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign)
1985 rtx tmp0 = gen_reg_rtx (SImode);
1986 rtx tmp1 = gen_reg_rtx (SImode);
1987 rtx tmp2 = gen_reg_rtx (SImode);
1988 rtx tmp3 = gen_reg_rtx (SImode);
1989 rtx tmp4 = gen_reg_rtx (SImode);
1990 rtx tmp5 = gen_reg_rtx (SImode);
1991 rtx tmp6 = gen_reg_rtx (SImode);
1992 rtx tmp7 = gen_reg_rtx (SImode);
1993 rtx tmp8 = gen_reg_rtx (SImode);
1994 rtx tmp9 = gen_reg_rtx (SImode);
1995 rtx tmp10 = gen_reg_rtx (SImode);
1996 rtx tmp11 = gen_reg_rtx (SImode);
1997 rtx tmp12 = gen_reg_rtx (SImode);
1998 rtx tmp13 = gen_reg_rtx (SImode);
1999 rtx result_lo = gen_reg_rtx (SImode);
2001 if (sign)
2003 emit_insn (gen_insn_mulhl_su (tmp0, op1, op2));
2004 emit_insn (gen_insn_mulhl_su (tmp1, op2, op1));
2005 emit_insn (gen_insn_mulll_uu (tmp2, op1, op2));
2006 emit_insn (gen_insn_mulhh_ss (tmp3, op1, op2));
2008 else
2010 emit_insn (gen_insn_mulhl_uu (tmp0, op1, op2));
2011 emit_insn (gen_insn_mulhl_uu (tmp1, op2, op1));
2012 emit_insn (gen_insn_mulll_uu (tmp2, op1, op2));
2013 emit_insn (gen_insn_mulhh_uu (tmp3, op1, op2));
2016 emit_move_insn (tmp4, (gen_rtx_ASHIFT (SImode, tmp0, GEN_INT (16))));
2018 emit_move_insn (tmp5, (gen_rtx_ASHIFT (SImode, tmp1, GEN_INT (16))));
2020 emit_move_insn (tmp6, (gen_rtx_PLUS (SImode, tmp4, tmp5)));
2021 emit_move_insn (result_lo, (gen_rtx_PLUS (SImode, tmp2, tmp6)));
2023 emit_move_insn (tmp7, gen_rtx_LTU (SImode, tmp6, tmp4));
2024 emit_move_insn (tmp8, gen_rtx_LTU (SImode, result_lo, tmp2));
2026 if (sign)
2028 emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (SImode, tmp0, GEN_INT (16))));
2029 emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (SImode, tmp1, GEN_INT (16))));
2031 else
2033 emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (SImode, tmp0, GEN_INT (16))));
2034 emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (SImode, tmp1, GEN_INT (16))));
2037 emit_move_insn (tmp11, (gen_rtx_PLUS (SImode, tmp3, tmp7)));
2038 emit_move_insn (tmp12, (gen_rtx_PLUS (SImode, tmp8, tmp9)));
2039 emit_move_insn (tmp13, (gen_rtx_PLUS (SImode, tmp11, tmp12)));
2040 emit_move_insn (result, (gen_rtx_PLUS (SImode, tmp13, tmp10)));
2044 /* Implement smulsi3_highpart. */
2045 void
2046 tilepro_expand_smulsi3_highpart (rtx op0, rtx op1, rtx op2)
2048 tilepro_expand_high_multiply (op0, op1, op2, true);
2052 /* Implement umulsi3_highpart. */
2053 void
2054 tilepro_expand_umulsi3_highpart (rtx op0, rtx op1, rtx op2)
2056 tilepro_expand_high_multiply (op0, op1, op2, false);
2061 /* Compare and branches */
2063 /* Helper function to handle DImode for tilepro_emit_setcc_internal. */
2064 static bool
2065 tilepro_emit_setcc_internal_di (rtx res, enum rtx_code code, rtx op0, rtx op1)
2067 rtx operands[2], lo_half[2], hi_half[2];
2068 rtx tmp, tmp0, tmp1, tmp2;
2069 bool swap = false;
2071 /* Reduce the number of cases we need to handle by reversing the
2072 operands. */
2073 switch (code)
2075 case EQ:
2076 case NE:
2077 case LE:
2078 case LT:
2079 case LEU:
2080 case LTU:
2081 /* We handle these compares directly. */
2082 break;
2084 case GE:
2085 case GT:
2086 case GEU:
2087 case GTU:
2088 /* Reverse the operands. */
2089 swap = true;
2090 break;
2092 default:
2093 /* We should not have called this with any other code. */
2094 gcc_unreachable ();
2097 if (swap)
2099 code = swap_condition (code);
2100 tmp = op0, op0 = op1, op1 = tmp;
2103 operands[0] = op0;
2104 operands[1] = op1;
2106 split_di (operands, 2, lo_half, hi_half);
2108 if (!reg_or_0_operand (lo_half[0], SImode))
2109 lo_half[0] = force_reg (SImode, lo_half[0]);
2111 if (!reg_or_0_operand (hi_half[0], SImode))
2112 hi_half[0] = force_reg (SImode, hi_half[0]);
2114 if (!CONST_INT_P (lo_half[1]) && !register_operand (lo_half[1], SImode))
2115 lo_half[1] = force_reg (SImode, lo_half[1]);
2117 if (!CONST_INT_P (hi_half[1]) && !register_operand (hi_half[1], SImode))
2118 hi_half[1] = force_reg (SImode, hi_half[1]);
2120 tmp0 = gen_reg_rtx (SImode);
2121 tmp1 = gen_reg_rtx (SImode);
2122 tmp2 = gen_reg_rtx (SImode);
2124 switch (code)
2126 case EQ:
2127 emit_insn (gen_insn_seq (tmp0, lo_half[0], lo_half[1]));
2128 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2129 emit_insn (gen_andsi3 (res, tmp0, tmp1));
2130 return true;
2131 break;
2132 case NE:
2133 emit_insn (gen_insn_sne (tmp0, lo_half[0], lo_half[1]));
2134 emit_insn (gen_insn_sne (tmp1, hi_half[0], hi_half[1]));
2135 emit_insn (gen_iorsi3 (res, tmp0, tmp1));
2136 return true;
2137 break;
2138 case LE:
2139 emit_insn (gen_insn_slte (tmp0, hi_half[0], hi_half[1]));
2140 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2141 emit_insn (gen_insn_slte_u (tmp2, lo_half[0], lo_half[1]));
2142 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2143 return true;
2144 case LT:
2145 if (operands[1] == const0_rtx)
2147 emit_insn (gen_lshrsi3 (res, hi_half[0], GEN_INT (31)));
2148 return true;
2150 else
2152 emit_insn (gen_insn_slt (tmp0, hi_half[0], hi_half[1]));
2153 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2154 emit_insn (gen_insn_slt_u (tmp2, lo_half[0], lo_half[1]));
2155 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2157 return true;
2158 case LEU:
2159 emit_insn (gen_insn_slte_u (tmp0, hi_half[0], hi_half[1]));
2160 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2161 emit_insn (gen_insn_slte_u (tmp2, lo_half[0], lo_half[1]));
2162 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2163 return true;
2164 case LTU:
2165 emit_insn (gen_insn_slt_u (tmp0, hi_half[0], hi_half[1]));
2166 emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
2167 emit_insn (gen_insn_slt_u (tmp2, lo_half[0], lo_half[1]));
2168 emit_insn (gen_insn_mvnz (res, tmp0, tmp1, tmp2));
2169 return true;
2170 default:
2171 gcc_unreachable ();
2174 return false;
2178 /* Certain simplifications can be done to make invalid setcc
2179 operations valid. Return the final comparison, or NULL if we can't
2180 work. */
2181 static bool
2182 tilepro_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1,
2183 enum machine_mode cmp_mode)
2185 rtx tmp;
2186 bool swap = false;
2188 if (cmp_mode == DImode)
2190 return tilepro_emit_setcc_internal_di (res, code, op0, op1);
2193 /* The general case: fold the comparison code to the types of
2194 compares that we have, choosing the branch as necessary. */
2196 switch (code)
2198 case EQ:
2199 case NE:
2200 case LE:
2201 case LT:
2202 case LEU:
2203 case LTU:
2204 /* We have these compares. */
2205 break;
2207 case GE:
2208 case GT:
2209 case GEU:
2210 case GTU:
2211 /* We do not have these compares, so we reverse the
2212 operands. */
2213 swap = true;
2214 break;
2216 default:
2217 /* We should not have called this with any other code. */
2218 gcc_unreachable ();
2221 if (swap)
2223 code = swap_condition (code);
2224 tmp = op0, op0 = op1, op1 = tmp;
2227 if (!reg_or_0_operand (op0, SImode))
2228 op0 = force_reg (SImode, op0);
2230 if (!CONST_INT_P (op1) && !register_operand (op1, SImode))
2231 op1 = force_reg (SImode, op1);
2233 /* Return the setcc comparison. */
2234 emit_insn (gen_rtx_SET (VOIDmode, res,
2235 gen_rtx_fmt_ee (code, SImode, op0, op1)));
2237 return true;
2241 /* Implement cstore patterns. */
2242 bool
2243 tilepro_emit_setcc (rtx operands[], enum machine_mode cmp_mode)
2245 return
2246 tilepro_emit_setcc_internal (operands[0], GET_CODE (operands[1]),
2247 operands[2], operands[3], cmp_mode);
2251 /* Return whether CODE is a signed comparison. */
2252 static bool
2253 signed_compare_p (enum rtx_code code)
2255 return (code == EQ || code == NE || code == LT || code == LE
2256 || code == GT || code == GE);
2260 /* Generate the comparison for an SImode conditional branch. */
2261 static rtx
2262 tilepro_emit_cc_test (enum rtx_code code, rtx op0, rtx op1,
2263 enum machine_mode cmp_mode, bool eq_ne_only)
2265 enum rtx_code branch_code;
2266 rtx temp;
2268 /* Check for a compare against zero using a comparison we can do
2269 directly. */
2270 if (cmp_mode != DImode
2271 && op1 == const0_rtx
2272 && (code == EQ || code == NE
2273 || (!eq_ne_only && signed_compare_p (code))))
2275 op0 = force_reg (SImode, op0);
2276 return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx);
2279 /* The general case: fold the comparison code to the types of
2280 compares that we have, choosing the branch as necessary. */
2281 switch (code)
2283 case EQ:
2284 case LE:
2285 case LT:
2286 case LEU:
2287 case LTU:
2288 /* We have these compares. */
2289 branch_code = NE;
2290 break;
2292 case NE:
2293 case GE:
2294 case GT:
2295 case GEU:
2296 case GTU:
2297 /* These must be reversed (except NE, but let's
2298 canonicalize). */
2299 code = reverse_condition (code);
2300 branch_code = EQ;
2301 break;
2303 default:
2304 gcc_unreachable ();
2307 if (cmp_mode != DImode
2308 && CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU))
2310 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op1), SImode);
2312 switch (code)
2314 case EQ:
2315 /* Subtract off the value we want to compare against and see
2316 if we get zero. This is cheaper than creating a constant
2317 in a register. Except that subtracting -128 is more
2318 expensive than seqi to -128, so we leave that alone. */
2319 /* ??? Don't do this when comparing against symbols,
2320 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2321 0), which will be declared false out of hand (at least
2322 for non-weak). */
2323 if (!(symbolic_operand (op0, VOIDmode)
2324 || (REG_P (op0) && REG_POINTER (op0))))
2326 /* To compare against MIN_INT, we add MIN_INT and check
2327 for 0. */
2328 HOST_WIDE_INT add;
2329 if (n != -2147483647 - 1)
2330 add = -n;
2331 else
2332 add = n;
2334 op0 = force_reg (SImode, op0);
2335 temp = gen_reg_rtx (SImode);
2336 emit_insn (gen_addsi3 (temp, op0, gen_int_si (add)));
2337 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2338 VOIDmode, temp, const0_rtx);
2340 break;
2342 case LEU:
2343 if (n == -1)
2344 break;
2345 /* FALLTHRU */
2347 case LTU:
2348 /* Change ((unsigned)x < 0x1000) into !((unsigned)x >> 12),
2349 etc. */
2351 int first = exact_log2 (code == LTU ? n : n + 1);
2352 if (first != -1)
2354 op0 = force_reg (SImode, op0);
2355 temp = gen_reg_rtx (SImode);
2356 emit_move_insn (temp,
2357 gen_rtx_LSHIFTRT (SImode, op0,
2358 gen_int_si (first)));
2359 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2360 VOIDmode, temp, const0_rtx);
2363 break;
2365 default:
2366 break;
2370 /* Compute a flag saying whether we should branch. */
2371 temp = gen_reg_rtx (SImode);
2372 tilepro_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2374 /* Return the branch comparison. */
2375 return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx);
2379 /* Generate the comparison for a conditional branch. */
2380 void
2381 tilepro_emit_conditional_branch (rtx operands[], enum machine_mode cmp_mode)
2383 rtx cmp_rtx =
2384 tilepro_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2],
2385 cmp_mode, false);
2386 rtx branch_rtx = gen_rtx_SET (VOIDmode, pc_rtx,
2387 gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx,
2388 gen_rtx_LABEL_REF
2389 (VOIDmode,
2390 operands[3]),
2391 pc_rtx));
2392 emit_jump_insn (branch_rtx);
2396 /* Implement the movsicc pattern. */
2398 tilepro_emit_conditional_move (rtx cmp)
2400 return
2401 tilepro_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1),
2402 GET_MODE (XEXP (cmp, 0)), true);
2406 /* Return true if INSN is annotated with a REG_BR_PROB note that
2407 indicates it's a branch that's predicted taken. */
2408 static bool
2409 cbranch_predicted_p (rtx insn)
2411 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2413 if (x)
2415 int pred_val = XINT (x, 0);
2417 return pred_val >= REG_BR_PROB_BASE / 2;
2420 return false;
2424 /* Output assembly code for a specific branch instruction, appending
2425 the branch prediction flag to the opcode if appropriate. */
2426 static const char *
2427 tilepro_output_simple_cbranch_with_opcode (rtx insn, const char *opcode,
2428 int regop, bool netreg_p,
2429 bool reverse_predicted)
2431 static char buf[64];
2432 sprintf (buf, "%s%s\t%%%c%d, %%l0", opcode,
2433 (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "",
2434 netreg_p ? 'N' : 'r', regop);
2435 return buf;
2439 /* Output assembly code for a specific branch instruction, appending
2440 the branch prediction flag to the opcode if appropriate. */
2441 const char *
2442 tilepro_output_cbranch_with_opcode (rtx insn, rtx *operands,
2443 const char *opcode,
2444 const char *rev_opcode,
2445 int regop, bool netreg_p)
2447 const char *branch_if_false;
2448 rtx taken, not_taken;
2449 bool is_simple_branch;
2451 gcc_assert (LABEL_P (operands[0]));
2453 is_simple_branch = true;
2454 if (INSN_ADDRESSES_SET_P ())
2456 int from_addr = INSN_ADDRESSES (INSN_UID (insn));
2457 int to_addr = INSN_ADDRESSES (INSN_UID (operands[0]));
2458 int delta = to_addr - from_addr;
2459 is_simple_branch = IN_RANGE (delta, -524288, 524280);
2462 if (is_simple_branch)
2464 /* Just a simple conditional branch. */
2465 return
2466 tilepro_output_simple_cbranch_with_opcode (insn, opcode, regop,
2467 netreg_p, false);
2470 /* Generate a reversed branch around a direct jump. This fallback
2471 does not use branch-likely instructions. */
2472 not_taken = gen_label_rtx ();
2473 taken = operands[0];
2475 /* Generate the reversed branch to NOT_TAKEN. */
2476 operands[0] = not_taken;
2477 branch_if_false =
2478 tilepro_output_simple_cbranch_with_opcode (insn, rev_opcode, regop,
2479 netreg_p, true);
2480 output_asm_insn (branch_if_false, operands);
2482 output_asm_insn ("j\t%l0", &taken);
2484 /* Output NOT_TAKEN. */
2485 targetm.asm_out.internal_label (asm_out_file, "L",
2486 CODE_LABEL_NUMBER (not_taken));
2487 return "";
2491 /* Output assembly code for a conditional branch instruction. */
2492 const char *
2493 tilepro_output_cbranch (rtx insn, rtx *operands, bool reversed)
2495 enum rtx_code code = GET_CODE (operands[1]);
2496 const char *opcode;
2497 const char *rev_opcode;
2499 if (reversed)
2500 code = reverse_condition (code);
2502 switch (code)
2504 case NE:
2505 opcode = "bnz";
2506 rev_opcode = "bz";
2507 break;
2508 case EQ:
2509 opcode = "bz";
2510 rev_opcode = "bnz";
2511 break;
2512 case GE:
2513 opcode = "bgez";
2514 rev_opcode = "blz";
2515 break;
2516 case GT:
2517 opcode = "bgz";
2518 rev_opcode = "blez";
2519 break;
2520 case LE:
2521 opcode = "blez";
2522 rev_opcode = "bgz";
2523 break;
2524 case LT:
2525 opcode = "blz";
2526 rev_opcode = "bgez";
2527 break;
2528 default:
2529 gcc_unreachable ();
2532 return
2533 tilepro_output_cbranch_with_opcode (insn, operands, opcode, rev_opcode,
2534 2, false);
2538 /* Implement the tablejump pattern. */
2539 void
2540 tilepro_expand_tablejump (rtx op0, rtx op1)
2542 if (flag_pic)
2544 rtx table = gen_rtx_LABEL_REF (Pmode, op1);
2545 rtx temp = gen_reg_rtx (Pmode);
2546 rtx text_label_symbol = tilepro_text_label_symbol ();
2547 rtx text_label_rtx = tilepro_text_label_rtx ();
2549 emit_insn (gen_addli_pcrel (temp, text_label_rtx,
2550 table, text_label_symbol));
2551 emit_insn (gen_auli_pcrel (temp, temp, table, text_label_symbol));
2552 emit_move_insn (temp,
2553 gen_rtx_PLUS (Pmode,
2554 convert_to_mode (Pmode, op0, false),
2555 temp));
2556 op0 = temp;
2559 emit_jump_insn (gen_tablejump_aux (op0, op1));
2563 /* Expand a builtin vector binary op, by calling gen function GEN with
2564 operands in the proper modes. DEST is converted to DEST_MODE, and
2565 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2566 void
2567 tilepro_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx),
2568 enum machine_mode dest_mode,
2569 rtx dest,
2570 enum machine_mode src_mode,
2571 rtx src0, rtx src1, bool do_src1)
2573 dest = gen_lowpart (dest_mode, dest);
2575 if (src0 == const0_rtx)
2576 src0 = CONST0_RTX (src_mode);
2577 else
2578 src0 = gen_lowpart (src_mode, src0);
2580 if (do_src1)
2582 if (src1 == const0_rtx)
2583 src1 = CONST0_RTX (src_mode);
2584 else
2585 src1 = gen_lowpart (src_mode, src1);
2588 emit_insn ((*gen) (dest, src0, src1));
2593 /* Intrinsics */
2595 struct tile_builtin_info
2597 enum insn_code icode;
2598 tree fndecl;
2601 static struct tile_builtin_info tilepro_builtin_info[TILEPRO_BUILTIN_max] = {
2602 { CODE_FOR_addsi3, NULL }, /* add */
2603 { CODE_FOR_insn_addb, NULL }, /* addb */
2604 { CODE_FOR_insn_addbs_u, NULL }, /* addbs_u */
2605 { CODE_FOR_insn_addh, NULL }, /* addh */
2606 { CODE_FOR_insn_addhs, NULL }, /* addhs */
2607 { CODE_FOR_insn_addib, NULL }, /* addib */
2608 { CODE_FOR_insn_addih, NULL }, /* addih */
2609 { CODE_FOR_insn_addlis, NULL }, /* addlis */
2610 { CODE_FOR_ssaddsi3, NULL }, /* adds */
2611 { CODE_FOR_insn_adiffb_u, NULL }, /* adiffb_u */
2612 { CODE_FOR_insn_adiffh, NULL }, /* adiffh */
2613 { CODE_FOR_andsi3, NULL }, /* and */
2614 { CODE_FOR_insn_auli, NULL }, /* auli */
2615 { CODE_FOR_insn_avgb_u, NULL }, /* avgb_u */
2616 { CODE_FOR_insn_avgh, NULL }, /* avgh */
2617 { CODE_FOR_insn_bitx, NULL }, /* bitx */
2618 { CODE_FOR_bswapsi2, NULL }, /* bytex */
2619 { CODE_FOR_clzsi2, NULL }, /* clz */
2620 { CODE_FOR_insn_crc32_32, NULL }, /* crc32_32 */
2621 { CODE_FOR_insn_crc32_8, NULL }, /* crc32_8 */
2622 { CODE_FOR_ctzsi2, NULL }, /* ctz */
2623 { CODE_FOR_insn_drain, NULL }, /* drain */
2624 { CODE_FOR_insn_dtlbpr, NULL }, /* dtlbpr */
2625 { CODE_FOR_insn_dword_align, NULL }, /* dword_align */
2626 { CODE_FOR_insn_finv, NULL }, /* finv */
2627 { CODE_FOR_insn_flush, NULL }, /* flush */
2628 { CODE_FOR_insn_fnop, NULL }, /* fnop */
2629 { CODE_FOR_insn_icoh, NULL }, /* icoh */
2630 { CODE_FOR_insn_ill, NULL }, /* ill */
2631 { CODE_FOR_insn_info, NULL }, /* info */
2632 { CODE_FOR_insn_infol, NULL }, /* infol */
2633 { CODE_FOR_insn_inthb, NULL }, /* inthb */
2634 { CODE_FOR_insn_inthh, NULL }, /* inthh */
2635 { CODE_FOR_insn_intlb, NULL }, /* intlb */
2636 { CODE_FOR_insn_intlh, NULL }, /* intlh */
2637 { CODE_FOR_insn_inv, NULL }, /* inv */
2638 { CODE_FOR_insn_lb, NULL }, /* lb */
2639 { CODE_FOR_insn_lb_u, NULL }, /* lb_u */
2640 { CODE_FOR_insn_lh, NULL }, /* lh */
2641 { CODE_FOR_insn_lh_u, NULL }, /* lh_u */
2642 { CODE_FOR_insn_lnk, NULL }, /* lnk */
2643 { CODE_FOR_insn_lw, NULL }, /* lw */
2644 { CODE_FOR_insn_lw_na, NULL }, /* lw_na */
2645 { CODE_FOR_insn_lb_L2, NULL }, /* lb_L2 */
2646 { CODE_FOR_insn_lb_u_L2, NULL }, /* lb_u_L2 */
2647 { CODE_FOR_insn_lh_L2, NULL }, /* lh_L2 */
2648 { CODE_FOR_insn_lh_u_L2, NULL }, /* lh_u_L2 */
2649 { CODE_FOR_insn_lw_L2, NULL }, /* lw_L2 */
2650 { CODE_FOR_insn_lw_na_L2, NULL }, /* lw_na_L2 */
2651 { CODE_FOR_insn_lb_miss, NULL }, /* lb_miss */
2652 { CODE_FOR_insn_lb_u_miss, NULL }, /* lb_u_miss */
2653 { CODE_FOR_insn_lh_miss, NULL }, /* lh_miss */
2654 { CODE_FOR_insn_lh_u_miss, NULL }, /* lh_u_miss */
2655 { CODE_FOR_insn_lw_miss, NULL }, /* lw_miss */
2656 { CODE_FOR_insn_lw_na_miss, NULL }, /* lw_na_miss */
2657 { CODE_FOR_insn_maxb_u, NULL }, /* maxb_u */
2658 { CODE_FOR_insn_maxh, NULL }, /* maxh */
2659 { CODE_FOR_insn_maxib_u, NULL }, /* maxib_u */
2660 { CODE_FOR_insn_maxih, NULL }, /* maxih */
2661 { CODE_FOR_memory_barrier, NULL }, /* mf */
2662 { CODE_FOR_insn_mfspr, NULL }, /* mfspr */
2663 { CODE_FOR_insn_minb_u, NULL }, /* minb_u */
2664 { CODE_FOR_insn_minh, NULL }, /* minh */
2665 { CODE_FOR_insn_minib_u, NULL }, /* minib_u */
2666 { CODE_FOR_insn_minih, NULL }, /* minih */
2667 { CODE_FOR_insn_mm, NULL }, /* mm */
2668 { CODE_FOR_insn_mnz, NULL }, /* mnz */
2669 { CODE_FOR_insn_mnzb, NULL }, /* mnzb */
2670 { CODE_FOR_insn_mnzh, NULL }, /* mnzh */
2671 { CODE_FOR_movsi, NULL }, /* move */
2672 { CODE_FOR_insn_movelis, NULL }, /* movelis */
2673 { CODE_FOR_insn_mtspr, NULL }, /* mtspr */
2674 { CODE_FOR_insn_mulhh_ss, NULL }, /* mulhh_ss */
2675 { CODE_FOR_insn_mulhh_su, NULL }, /* mulhh_su */
2676 { CODE_FOR_insn_mulhh_uu, NULL }, /* mulhh_uu */
2677 { CODE_FOR_insn_mulhha_ss, NULL }, /* mulhha_ss */
2678 { CODE_FOR_insn_mulhha_su, NULL }, /* mulhha_su */
2679 { CODE_FOR_insn_mulhha_uu, NULL }, /* mulhha_uu */
2680 { CODE_FOR_insn_mulhhsa_uu, NULL }, /* mulhhsa_uu */
2681 { CODE_FOR_insn_mulhl_ss, NULL }, /* mulhl_ss */
2682 { CODE_FOR_insn_mulhl_su, NULL }, /* mulhl_su */
2683 { CODE_FOR_insn_mulhl_us, NULL }, /* mulhl_us */
2684 { CODE_FOR_insn_mulhl_uu, NULL }, /* mulhl_uu */
2685 { CODE_FOR_insn_mulhla_ss, NULL }, /* mulhla_ss */
2686 { CODE_FOR_insn_mulhla_su, NULL }, /* mulhla_su */
2687 { CODE_FOR_insn_mulhla_us, NULL }, /* mulhla_us */
2688 { CODE_FOR_insn_mulhla_uu, NULL }, /* mulhla_uu */
2689 { CODE_FOR_insn_mulhlsa_uu, NULL }, /* mulhlsa_uu */
2690 { CODE_FOR_insn_mulll_ss, NULL }, /* mulll_ss */
2691 { CODE_FOR_insn_mulll_su, NULL }, /* mulll_su */
2692 { CODE_FOR_insn_mulll_uu, NULL }, /* mulll_uu */
2693 { CODE_FOR_insn_mullla_ss, NULL }, /* mullla_ss */
2694 { CODE_FOR_insn_mullla_su, NULL }, /* mullla_su */
2695 { CODE_FOR_insn_mullla_uu, NULL }, /* mullla_uu */
2696 { CODE_FOR_insn_mulllsa_uu, NULL }, /* mulllsa_uu */
2697 { CODE_FOR_insn_mvnz, NULL }, /* mvnz */
2698 { CODE_FOR_insn_mvz, NULL }, /* mvz */
2699 { CODE_FOR_insn_mz, NULL }, /* mz */
2700 { CODE_FOR_insn_mzb, NULL }, /* mzb */
2701 { CODE_FOR_insn_mzh, NULL }, /* mzh */
2702 { CODE_FOR_insn_nap, NULL }, /* nap */
2703 { CODE_FOR_nop, NULL }, /* nop */
2704 { CODE_FOR_insn_nor, NULL }, /* nor */
2705 { CODE_FOR_iorsi3, NULL }, /* or */
2706 { CODE_FOR_insn_packbs_u, NULL }, /* packbs_u */
2707 { CODE_FOR_insn_packhb, NULL }, /* packhb */
2708 { CODE_FOR_insn_packhs, NULL }, /* packhs */
2709 { CODE_FOR_insn_packlb, NULL }, /* packlb */
2710 { CODE_FOR_popcountsi2, NULL }, /* pcnt */
2711 { CODE_FOR_insn_prefetch, NULL }, /* prefetch */
2712 { CODE_FOR_insn_prefetch_L1, NULL }, /* prefetch_L1 */
2713 { CODE_FOR_rotlsi3, NULL }, /* rl */
2714 { CODE_FOR_insn_s1a, NULL }, /* s1a */
2715 { CODE_FOR_insn_s2a, NULL }, /* s2a */
2716 { CODE_FOR_insn_s3a, NULL }, /* s3a */
2717 { CODE_FOR_insn_sadab_u, NULL }, /* sadab_u */
2718 { CODE_FOR_insn_sadah, NULL }, /* sadah */
2719 { CODE_FOR_insn_sadah_u, NULL }, /* sadah_u */
2720 { CODE_FOR_insn_sadb_u, NULL }, /* sadb_u */
2721 { CODE_FOR_insn_sadh, NULL }, /* sadh */
2722 { CODE_FOR_insn_sadh_u, NULL }, /* sadh_u */
2723 { CODE_FOR_insn_sb, NULL }, /* sb */
2724 { CODE_FOR_insn_seq, NULL }, /* seq */
2725 { CODE_FOR_insn_seqb, NULL }, /* seqb */
2726 { CODE_FOR_insn_seqh, NULL }, /* seqh */
2727 { CODE_FOR_insn_seqib, NULL }, /* seqib */
2728 { CODE_FOR_insn_seqih, NULL }, /* seqih */
2729 { CODE_FOR_insn_sh, NULL }, /* sh */
2730 { CODE_FOR_ashlsi3, NULL }, /* shl */
2731 { CODE_FOR_insn_shlb, NULL }, /* shlb */
2732 { CODE_FOR_insn_shlh, NULL }, /* shlh */
2733 { CODE_FOR_insn_shlb, NULL }, /* shlib */
2734 { CODE_FOR_insn_shlh, NULL }, /* shlih */
2735 { CODE_FOR_lshrsi3, NULL }, /* shr */
2736 { CODE_FOR_insn_shrb, NULL }, /* shrb */
2737 { CODE_FOR_insn_shrh, NULL }, /* shrh */
2738 { CODE_FOR_insn_shrb, NULL }, /* shrib */
2739 { CODE_FOR_insn_shrh, NULL }, /* shrih */
2740 { CODE_FOR_insn_slt, NULL }, /* slt */
2741 { CODE_FOR_insn_slt_u, NULL }, /* slt_u */
2742 { CODE_FOR_insn_sltb, NULL }, /* sltb */
2743 { CODE_FOR_insn_sltb_u, NULL }, /* sltb_u */
2744 { CODE_FOR_insn_slte, NULL }, /* slte */
2745 { CODE_FOR_insn_slte_u, NULL }, /* slte_u */
2746 { CODE_FOR_insn_slteb, NULL }, /* slteb */
2747 { CODE_FOR_insn_slteb_u, NULL }, /* slteb_u */
2748 { CODE_FOR_insn_slteh, NULL }, /* slteh */
2749 { CODE_FOR_insn_slteh_u, NULL }, /* slteh_u */
2750 { CODE_FOR_insn_slth, NULL }, /* slth */
2751 { CODE_FOR_insn_slth_u, NULL }, /* slth_u */
2752 { CODE_FOR_insn_sltib, NULL }, /* sltib */
2753 { CODE_FOR_insn_sltib_u, NULL }, /* sltib_u */
2754 { CODE_FOR_insn_sltih, NULL }, /* sltih */
2755 { CODE_FOR_insn_sltih_u, NULL }, /* sltih_u */
2756 { CODE_FOR_insn_sne, NULL }, /* sne */
2757 { CODE_FOR_insn_sneb, NULL }, /* sneb */
2758 { CODE_FOR_insn_sneh, NULL }, /* sneh */
2759 { CODE_FOR_ashrsi3, NULL }, /* sra */
2760 { CODE_FOR_insn_srab, NULL }, /* srab */
2761 { CODE_FOR_insn_srah, NULL }, /* srah */
2762 { CODE_FOR_insn_srab, NULL }, /* sraib */
2763 { CODE_FOR_insn_srah, NULL }, /* sraih */
2764 { CODE_FOR_subsi3, NULL }, /* sub */
2765 { CODE_FOR_insn_subb, NULL }, /* subb */
2766 { CODE_FOR_insn_subbs_u, NULL }, /* subbs_u */
2767 { CODE_FOR_insn_subh, NULL }, /* subh */
2768 { CODE_FOR_insn_subhs, NULL }, /* subhs */
2769 { CODE_FOR_sssubsi3, NULL }, /* subs */
2770 { CODE_FOR_insn_sw, NULL }, /* sw */
2771 { CODE_FOR_insn_tblidxb0, NULL }, /* tblidxb0 */
2772 { CODE_FOR_insn_tblidxb1, NULL }, /* tblidxb1 */
2773 { CODE_FOR_insn_tblidxb2, NULL }, /* tblidxb2 */
2774 { CODE_FOR_insn_tblidxb3, NULL }, /* tblidxb3 */
2775 { CODE_FOR_insn_tns, NULL }, /* tns */
2776 { CODE_FOR_insn_wh64, NULL }, /* wh64 */
2777 { CODE_FOR_xorsi3, NULL }, /* xor */
2778 { CODE_FOR_tilepro_network_barrier, NULL }, /* network_barrier */
2779 { CODE_FOR_tilepro_idn0_receive, NULL }, /* idn0_receive */
2780 { CODE_FOR_tilepro_idn1_receive, NULL }, /* idn1_receive */
2781 { CODE_FOR_tilepro_idn_send, NULL }, /* idn_send */
2782 { CODE_FOR_tilepro_sn_receive, NULL }, /* sn_receive */
2783 { CODE_FOR_tilepro_sn_send, NULL }, /* sn_send */
2784 { CODE_FOR_tilepro_udn0_receive, NULL }, /* udn0_receive */
2785 { CODE_FOR_tilepro_udn1_receive, NULL }, /* udn1_receive */
2786 { CODE_FOR_tilepro_udn2_receive, NULL }, /* udn2_receive */
2787 { CODE_FOR_tilepro_udn3_receive, NULL }, /* udn3_receive */
2788 { CODE_FOR_tilepro_udn_send, NULL }, /* udn_send */
2792 struct tilepro_builtin_def
2794 const char *name;
2795 enum tilepro_builtin code;
2796 bool is_const;
2797 /* The first character is the return type. Subsequent characters
2798 are the argument types. See char_to_type. */
2799 const char *type;
2803 static const struct tilepro_builtin_def tilepro_builtins[] = {
2804 { "__insn_add", TILEPRO_INSN_ADD, true, "lll" },
2805 { "__insn_addb", TILEPRO_INSN_ADDB, true, "lll" },
2806 { "__insn_addbs_u", TILEPRO_INSN_ADDBS_U, false, "lll" },
2807 { "__insn_addh", TILEPRO_INSN_ADDH, true, "lll" },
2808 { "__insn_addhs", TILEPRO_INSN_ADDHS, false, "lll" },
2809 { "__insn_addi", TILEPRO_INSN_ADD, true, "lll" },
2810 { "__insn_addib", TILEPRO_INSN_ADDIB, true, "lll" },
2811 { "__insn_addih", TILEPRO_INSN_ADDIH, true, "lll" },
2812 { "__insn_addli", TILEPRO_INSN_ADD, true, "lll" },
2813 { "__insn_addlis", TILEPRO_INSN_ADDLIS, false, "lll" },
2814 { "__insn_adds", TILEPRO_INSN_ADDS, false, "lll" },
2815 { "__insn_adiffb_u", TILEPRO_INSN_ADIFFB_U, true, "lll" },
2816 { "__insn_adiffh", TILEPRO_INSN_ADIFFH, true, "lll" },
2817 { "__insn_and", TILEPRO_INSN_AND, true, "lll" },
2818 { "__insn_andi", TILEPRO_INSN_AND, true, "lll" },
2819 { "__insn_auli", TILEPRO_INSN_AULI, true, "lll" },
2820 { "__insn_avgb_u", TILEPRO_INSN_AVGB_U, true, "lll" },
2821 { "__insn_avgh", TILEPRO_INSN_AVGH, true, "lll" },
2822 { "__insn_bitx", TILEPRO_INSN_BITX, true, "ll" },
2823 { "__insn_bytex", TILEPRO_INSN_BYTEX, true, "ll" },
2824 { "__insn_clz", TILEPRO_INSN_CLZ, true, "ll" },
2825 { "__insn_crc32_32", TILEPRO_INSN_CRC32_32, true, "lll" },
2826 { "__insn_crc32_8", TILEPRO_INSN_CRC32_8, true, "lll" },
2827 { "__insn_ctz", TILEPRO_INSN_CTZ, true, "ll" },
2828 { "__insn_drain", TILEPRO_INSN_DRAIN, false, "v" },
2829 { "__insn_dtlbpr", TILEPRO_INSN_DTLBPR, false, "vl" },
2830 { "__insn_dword_align", TILEPRO_INSN_DWORD_ALIGN, true, "lllk" },
2831 { "__insn_finv", TILEPRO_INSN_FINV, false, "vk" },
2832 { "__insn_flush", TILEPRO_INSN_FLUSH, false, "vk" },
2833 { "__insn_fnop", TILEPRO_INSN_FNOP, false, "v" },
2834 { "__insn_icoh", TILEPRO_INSN_ICOH, false, "vk" },
2835 { "__insn_ill", TILEPRO_INSN_ILL, false, "v" },
2836 { "__insn_info", TILEPRO_INSN_INFO, false, "vl" },
2837 { "__insn_infol", TILEPRO_INSN_INFOL, false, "vl" },
2838 { "__insn_inthb", TILEPRO_INSN_INTHB, true, "lll" },
2839 { "__insn_inthh", TILEPRO_INSN_INTHH, true, "lll" },
2840 { "__insn_intlb", TILEPRO_INSN_INTLB, true, "lll" },
2841 { "__insn_intlh", TILEPRO_INSN_INTLH, true, "lll" },
2842 { "__insn_inv", TILEPRO_INSN_INV, false, "vp" },
2843 { "__insn_lb", TILEPRO_INSN_LB, false, "lk" },
2844 { "__insn_lb_u", TILEPRO_INSN_LB_U, false, "lk" },
2845 { "__insn_lh", TILEPRO_INSN_LH, false, "lk" },
2846 { "__insn_lh_u", TILEPRO_INSN_LH_U, false, "lk" },
2847 { "__insn_lnk", TILEPRO_INSN_LNK, true, "l" },
2848 { "__insn_lw", TILEPRO_INSN_LW, false, "lk" },
2849 { "__insn_lw_na", TILEPRO_INSN_LW_NA, false, "lk" },
2850 { "__insn_lb_L2", TILEPRO_INSN_LB_L2, false, "lk" },
2851 { "__insn_lb_u_L2", TILEPRO_INSN_LB_U_L2, false, "lk" },
2852 { "__insn_lh_L2", TILEPRO_INSN_LH_L2, false, "lk" },
2853 { "__insn_lh_u_L2", TILEPRO_INSN_LH_U_L2, false, "lk" },
2854 { "__insn_lw_L2", TILEPRO_INSN_LW_L2, false, "lk" },
2855 { "__insn_lw_na_L2", TILEPRO_INSN_LW_NA_L2, false, "lk" },
2856 { "__insn_lb_miss", TILEPRO_INSN_LB_MISS, false, "lk" },
2857 { "__insn_lb_u_miss", TILEPRO_INSN_LB_U_MISS, false, "lk" },
2858 { "__insn_lh_miss", TILEPRO_INSN_LH_MISS, false, "lk" },
2859 { "__insn_lh_u_miss", TILEPRO_INSN_LH_U_MISS, false, "lk" },
2860 { "__insn_lw_miss", TILEPRO_INSN_LW_MISS, false, "lk" },
2861 { "__insn_lw_na_miss", TILEPRO_INSN_LW_NA_MISS, false, "lk" },
2862 { "__insn_maxb_u", TILEPRO_INSN_MAXB_U, true, "lll" },
2863 { "__insn_maxh", TILEPRO_INSN_MAXH, true, "lll" },
2864 { "__insn_maxib_u", TILEPRO_INSN_MAXIB_U, true, "lll" },
2865 { "__insn_maxih", TILEPRO_INSN_MAXIH, true, "lll" },
2866 { "__insn_mf", TILEPRO_INSN_MF, false, "v" },
2867 { "__insn_mfspr", TILEPRO_INSN_MFSPR, false, "ll" },
2868 { "__insn_minb_u", TILEPRO_INSN_MINB_U, true, "lll" },
2869 { "__insn_minh", TILEPRO_INSN_MINH, true, "lll" },
2870 { "__insn_minib_u", TILEPRO_INSN_MINIB_U, true, "lll" },
2871 { "__insn_minih", TILEPRO_INSN_MINIH, true, "lll" },
2872 { "__insn_mm", TILEPRO_INSN_MM, true, "lllll" },
2873 { "__insn_mnz", TILEPRO_INSN_MNZ, true, "lll" },
2874 { "__insn_mnzb", TILEPRO_INSN_MNZB, true, "lll" },
2875 { "__insn_mnzh", TILEPRO_INSN_MNZH, true, "lll" },
2876 { "__insn_move", TILEPRO_INSN_MOVE, true, "ll" },
2877 { "__insn_movei", TILEPRO_INSN_MOVE, true, "ll" },
2878 { "__insn_moveli", TILEPRO_INSN_MOVE, true, "ll" },
2879 { "__insn_movelis", TILEPRO_INSN_MOVELIS, false, "ll" },
2880 { "__insn_mtspr", TILEPRO_INSN_MTSPR, false, "vll" },
2881 { "__insn_mulhh_ss", TILEPRO_INSN_MULHH_SS, true, "lll" },
2882 { "__insn_mulhh_su", TILEPRO_INSN_MULHH_SU, true, "lll" },
2883 { "__insn_mulhh_uu", TILEPRO_INSN_MULHH_UU, true, "lll" },
2884 { "__insn_mulhha_ss", TILEPRO_INSN_MULHHA_SS, true, "llll" },
2885 { "__insn_mulhha_su", TILEPRO_INSN_MULHHA_SU, true, "llll" },
2886 { "__insn_mulhha_uu", TILEPRO_INSN_MULHHA_UU, true, "llll" },
2887 { "__insn_mulhhsa_uu", TILEPRO_INSN_MULHHSA_UU, true, "llll" },
2888 { "__insn_mulhl_ss", TILEPRO_INSN_MULHL_SS, true, "lll" },
2889 { "__insn_mulhl_su", TILEPRO_INSN_MULHL_SU, true, "lll" },
2890 { "__insn_mulhl_us", TILEPRO_INSN_MULHL_US, true, "lll" },
2891 { "__insn_mulhl_uu", TILEPRO_INSN_MULHL_UU, true, "lll" },
2892 { "__insn_mulhla_ss", TILEPRO_INSN_MULHLA_SS, true, "llll" },
2893 { "__insn_mulhla_su", TILEPRO_INSN_MULHLA_SU, true, "llll" },
2894 { "__insn_mulhla_us", TILEPRO_INSN_MULHLA_US, true, "llll" },
2895 { "__insn_mulhla_uu", TILEPRO_INSN_MULHLA_UU, true, "llll" },
2896 { "__insn_mulhlsa_uu", TILEPRO_INSN_MULHLSA_UU, true, "llll" },
2897 { "__insn_mulll_ss", TILEPRO_INSN_MULLL_SS, true, "lll" },
2898 { "__insn_mulll_su", TILEPRO_INSN_MULLL_SU, true, "lll" },
2899 { "__insn_mulll_uu", TILEPRO_INSN_MULLL_UU, true, "lll" },
2900 { "__insn_mullla_ss", TILEPRO_INSN_MULLLA_SS, true, "llll" },
2901 { "__insn_mullla_su", TILEPRO_INSN_MULLLA_SU, true, "llll" },
2902 { "__insn_mullla_uu", TILEPRO_INSN_MULLLA_UU, true, "llll" },
2903 { "__insn_mulllsa_uu", TILEPRO_INSN_MULLLSA_UU, true, "llll" },
2904 { "__insn_mvnz", TILEPRO_INSN_MVNZ, true, "llll" },
2905 { "__insn_mvz", TILEPRO_INSN_MVZ, true, "llll" },
2906 { "__insn_mz", TILEPRO_INSN_MZ, true, "lll" },
2907 { "__insn_mzb", TILEPRO_INSN_MZB, true, "lll" },
2908 { "__insn_mzh", TILEPRO_INSN_MZH, true, "lll" },
2909 { "__insn_nap", TILEPRO_INSN_NAP, false, "v" },
2910 { "__insn_nop", TILEPRO_INSN_NOP, true, "v" },
2911 { "__insn_nor", TILEPRO_INSN_NOR, true, "lll" },
2912 { "__insn_or", TILEPRO_INSN_OR, true, "lll" },
2913 { "__insn_ori", TILEPRO_INSN_OR, true, "lll" },
2914 { "__insn_packbs_u", TILEPRO_INSN_PACKBS_U, false, "lll" },
2915 { "__insn_packhb", TILEPRO_INSN_PACKHB, true, "lll" },
2916 { "__insn_packhs", TILEPRO_INSN_PACKHS, false, "lll" },
2917 { "__insn_packlb", TILEPRO_INSN_PACKLB, true, "lll" },
2918 { "__insn_pcnt", TILEPRO_INSN_PCNT, true, "ll" },
2919 { "__insn_prefetch", TILEPRO_INSN_PREFETCH, false, "vk" },
2920 { "__insn_prefetch_L1", TILEPRO_INSN_PREFETCH_L1, false, "vk" },
2921 { "__insn_rl", TILEPRO_INSN_RL, true, "lll" },
2922 { "__insn_rli", TILEPRO_INSN_RL, true, "lll" },
2923 { "__insn_s1a", TILEPRO_INSN_S1A, true, "lll" },
2924 { "__insn_s2a", TILEPRO_INSN_S2A, true, "lll" },
2925 { "__insn_s3a", TILEPRO_INSN_S3A, true, "lll" },
2926 { "__insn_sadab_u", TILEPRO_INSN_SADAB_U, true, "llll" },
2927 { "__insn_sadah", TILEPRO_INSN_SADAH, true, "llll" },
2928 { "__insn_sadah_u", TILEPRO_INSN_SADAH_U, true, "llll" },
2929 { "__insn_sadb_u", TILEPRO_INSN_SADB_U, true, "lll" },
2930 { "__insn_sadh", TILEPRO_INSN_SADH, true, "lll" },
2931 { "__insn_sadh_u", TILEPRO_INSN_SADH_U, true, "lll" },
2932 { "__insn_sb", TILEPRO_INSN_SB, false, "vpl" },
2933 { "__insn_seq", TILEPRO_INSN_SEQ, true, "lll" },
2934 { "__insn_seqb", TILEPRO_INSN_SEQB, true, "lll" },
2935 { "__insn_seqh", TILEPRO_INSN_SEQH, true, "lll" },
2936 { "__insn_seqi", TILEPRO_INSN_SEQ, true, "lll" },
2937 { "__insn_seqib", TILEPRO_INSN_SEQIB, true, "lll" },
2938 { "__insn_seqih", TILEPRO_INSN_SEQIH, true, "lll" },
2939 { "__insn_sh", TILEPRO_INSN_SH, false, "vpl" },
2940 { "__insn_shl", TILEPRO_INSN_SHL, true, "lll" },
2941 { "__insn_shlb", TILEPRO_INSN_SHLB, true, "lll" },
2942 { "__insn_shlh", TILEPRO_INSN_SHLH, true, "lll" },
2943 { "__insn_shli", TILEPRO_INSN_SHL, true, "lll" },
2944 { "__insn_shlib", TILEPRO_INSN_SHLIB, true, "lll" },
2945 { "__insn_shlih", TILEPRO_INSN_SHLIH, true, "lll" },
2946 { "__insn_shr", TILEPRO_INSN_SHR, true, "lll" },
2947 { "__insn_shrb", TILEPRO_INSN_SHRB, true, "lll" },
2948 { "__insn_shrh", TILEPRO_INSN_SHRH, true, "lll" },
2949 { "__insn_shri", TILEPRO_INSN_SHR, true, "lll" },
2950 { "__insn_shrib", TILEPRO_INSN_SHRIB, true, "lll" },
2951 { "__insn_shrih", TILEPRO_INSN_SHRIH, true, "lll" },
2952 { "__insn_slt", TILEPRO_INSN_SLT, true, "lll" },
2953 { "__insn_slt_u", TILEPRO_INSN_SLT_U, true, "lll" },
2954 { "__insn_sltb", TILEPRO_INSN_SLTB, true, "lll" },
2955 { "__insn_sltb_u", TILEPRO_INSN_SLTB_U, true, "lll" },
2956 { "__insn_slte", TILEPRO_INSN_SLTE, true, "lll" },
2957 { "__insn_slte_u", TILEPRO_INSN_SLTE_U, true, "lll" },
2958 { "__insn_slteb", TILEPRO_INSN_SLTEB, true, "lll" },
2959 { "__insn_slteb_u", TILEPRO_INSN_SLTEB_U, true, "lll" },
2960 { "__insn_slteh", TILEPRO_INSN_SLTEH, true, "lll" },
2961 { "__insn_slteh_u", TILEPRO_INSN_SLTEH_U, true, "lll" },
2962 { "__insn_slth", TILEPRO_INSN_SLTH, true, "lll" },
2963 { "__insn_slth_u", TILEPRO_INSN_SLTH_U, true, "lll" },
2964 { "__insn_slti", TILEPRO_INSN_SLT, true, "lll" },
2965 { "__insn_slti_u", TILEPRO_INSN_SLT_U, true, "lll" },
2966 { "__insn_sltib", TILEPRO_INSN_SLTIB, true, "lll" },
2967 { "__insn_sltib_u", TILEPRO_INSN_SLTIB_U, true, "lll" },
2968 { "__insn_sltih", TILEPRO_INSN_SLTIH, true, "lll" },
2969 { "__insn_sltih_u", TILEPRO_INSN_SLTIH_U, true, "lll" },
2970 { "__insn_sne", TILEPRO_INSN_SNE, true, "lll" },
2971 { "__insn_sneb", TILEPRO_INSN_SNEB, true, "lll" },
2972 { "__insn_sneh", TILEPRO_INSN_SNEH, true, "lll" },
2973 { "__insn_sra", TILEPRO_INSN_SRA, true, "lll" },
2974 { "__insn_srab", TILEPRO_INSN_SRAB, true, "lll" },
2975 { "__insn_srah", TILEPRO_INSN_SRAH, true, "lll" },
2976 { "__insn_srai", TILEPRO_INSN_SRA, true, "lll" },
2977 { "__insn_sraib", TILEPRO_INSN_SRAIB, true, "lll" },
2978 { "__insn_sraih", TILEPRO_INSN_SRAIH, true, "lll" },
2979 { "__insn_sub", TILEPRO_INSN_SUB, true, "lll" },
2980 { "__insn_subb", TILEPRO_INSN_SUBB, true, "lll" },
2981 { "__insn_subbs_u", TILEPRO_INSN_SUBBS_U, false, "lll" },
2982 { "__insn_subh", TILEPRO_INSN_SUBH, true, "lll" },
2983 { "__insn_subhs", TILEPRO_INSN_SUBHS, false, "lll" },
2984 { "__insn_subs", TILEPRO_INSN_SUBS, false, "lll" },
2985 { "__insn_sw", TILEPRO_INSN_SW, false, "vpl" },
2986 { "__insn_tblidxb0", TILEPRO_INSN_TBLIDXB0, true, "lll" },
2987 { "__insn_tblidxb1", TILEPRO_INSN_TBLIDXB1, true, "lll" },
2988 { "__insn_tblidxb2", TILEPRO_INSN_TBLIDXB2, true, "lll" },
2989 { "__insn_tblidxb3", TILEPRO_INSN_TBLIDXB3, true, "lll" },
2990 { "__insn_tns", TILEPRO_INSN_TNS, false, "lp" },
2991 { "__insn_wh64", TILEPRO_INSN_WH64, false, "vp" },
2992 { "__insn_xor", TILEPRO_INSN_XOR, true, "lll" },
2993 { "__insn_xori", TILEPRO_INSN_XOR, true, "lll" },
2994 { "__tile_network_barrier", TILEPRO_NETWORK_BARRIER, false, "v" },
2995 { "__tile_idn0_receive", TILEPRO_IDN0_RECEIVE, false, "l" },
2996 { "__tile_idn1_receive", TILEPRO_IDN1_RECEIVE, false, "l" },
2997 { "__tile_idn_send", TILEPRO_IDN_SEND, false, "vl" },
2998 { "__tile_sn_receive", TILEPRO_SN_RECEIVE, false, "l" },
2999 { "__tile_sn_send", TILEPRO_SN_SEND, false, "vl" },
3000 { "__tile_udn0_receive", TILEPRO_UDN0_RECEIVE, false, "l" },
3001 { "__tile_udn1_receive", TILEPRO_UDN1_RECEIVE, false, "l" },
3002 { "__tile_udn2_receive", TILEPRO_UDN2_RECEIVE, false, "l" },
3003 { "__tile_udn3_receive", TILEPRO_UDN3_RECEIVE, false, "l" },
3004 { "__tile_udn_send", TILEPRO_UDN_SEND, false, "vl" },
3008 /* Convert a character in a builtin type string to a tree type. */
3009 static tree
3010 char_to_type (char c)
3012 static tree volatile_ptr_type_node = NULL;
3013 static tree volatile_const_ptr_type_node = NULL;
3015 if (volatile_ptr_type_node == NULL)
3017 volatile_ptr_type_node =
3018 build_pointer_type (build_qualified_type (void_type_node,
3019 TYPE_QUAL_VOLATILE));
3020 volatile_const_ptr_type_node =
3021 build_pointer_type (build_qualified_type (void_type_node,
3022 TYPE_QUAL_CONST
3023 | TYPE_QUAL_VOLATILE));
3026 switch (c)
3028 case 'v':
3029 return void_type_node;
3030 case 'l':
3031 return long_unsigned_type_node;
3032 case 'p':
3033 return volatile_ptr_type_node;
3034 case 'k':
3035 return volatile_const_ptr_type_node;
3036 default:
3037 gcc_unreachable ();
3042 /* Implement TARGET_INIT_BUILTINS. */
3043 static void
3044 tilepro_init_builtins (void)
3046 size_t i;
3048 for (i = 0; i < ARRAY_SIZE (tilepro_builtins); i++)
3050 const struct tilepro_builtin_def *p = &tilepro_builtins[i];
3051 tree ftype, ret_type, arg_type_list = void_list_node;
3052 tree decl;
3053 int j;
3055 for (j = strlen (p->type) - 1; j > 0; j--)
3057 arg_type_list =
3058 tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list);
3061 ret_type = char_to_type (p->type[0]);
3063 ftype = build_function_type (ret_type, arg_type_list);
3065 decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
3066 NULL, NULL);
3068 if (p->is_const)
3069 TREE_READONLY (decl) = 1;
3070 TREE_NOTHROW (decl) = 1;
3072 if (tilepro_builtin_info[p->code].fndecl == NULL)
3073 tilepro_builtin_info[p->code].fndecl = decl;
3078 /* Implement TARGET_EXPAND_BUILTIN. */
3079 static rtx
3080 tilepro_expand_builtin (tree exp,
3081 rtx target,
3082 rtx subtarget ATTRIBUTE_UNUSED,
3083 enum machine_mode mode ATTRIBUTE_UNUSED,
3084 int ignore ATTRIBUTE_UNUSED)
3086 #define MAX_BUILTIN_ARGS 4
3088 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
3089 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
3090 tree arg;
3091 call_expr_arg_iterator iter;
3092 enum insn_code icode;
3093 rtx op[MAX_BUILTIN_ARGS + 1], pat;
3094 int opnum;
3095 bool nonvoid;
3096 insn_gen_fn fn;
3098 if (fcode >= TILEPRO_BUILTIN_max)
3099 internal_error ("bad builtin fcode");
3100 icode = tilepro_builtin_info[fcode].icode;
3101 if (icode == 0)
3102 internal_error ("bad builtin icode");
3104 nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
3106 opnum = nonvoid;
3107 FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
3109 const struct insn_operand_data *insn_op;
3111 if (arg == error_mark_node)
3112 return NULL_RTX;
3113 if (opnum > MAX_BUILTIN_ARGS)
3114 return NULL_RTX;
3116 insn_op = &insn_data[icode].operand[opnum];
3118 op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL);
3120 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3121 op[opnum] = copy_to_mode_reg (insn_op->mode, op[opnum]);
3123 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3125 /* We still failed to meet the predicate even after moving
3126 into a register. Assume we needed an immediate. */
3127 error_at (EXPR_LOCATION (exp),
3128 "operand must be an immediate of the right size");
3129 return const0_rtx;
3132 opnum++;
3135 if (nonvoid)
3137 enum machine_mode tmode = insn_data[icode].operand[0].mode;
3138 if (!target
3139 || GET_MODE (target) != tmode
3140 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
3141 target = gen_reg_rtx (tmode);
3142 op[0] = target;
3145 fn = GEN_FCN (icode);
3146 switch (opnum)
3148 case 0:
3149 pat = fn (NULL_RTX);
3150 break;
3151 case 1:
3152 pat = fn (op[0]);
3153 break;
3154 case 2:
3155 pat = fn (op[0], op[1]);
3156 break;
3157 case 3:
3158 pat = fn (op[0], op[1], op[2]);
3159 break;
3160 case 4:
3161 pat = fn (op[0], op[1], op[2], op[3]);
3162 break;
3163 case 5:
3164 pat = fn (op[0], op[1], op[2], op[3], op[4]);
3165 break;
3166 default:
3167 gcc_unreachable ();
3169 if (!pat)
3170 return NULL_RTX;
3171 emit_insn (pat);
3173 if (nonvoid)
3174 return target;
3175 else
3176 return const0_rtx;
3180 /* Implement TARGET_BUILTIN_DECL. */
3181 static tree
3182 tilepro_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
3184 if (code >= TILEPRO_BUILTIN_max)
3185 return error_mark_node;
3187 return tilepro_builtin_info[code].fndecl;
3192 /* Stack frames */
3194 /* Return whether REGNO needs to be saved in the stack frame. */
3195 static bool
3196 need_to_save_reg (unsigned int regno)
3198 if (!fixed_regs[regno] && !call_used_regs[regno]
3199 && df_regs_ever_live_p (regno))
3200 return true;
3202 if (flag_pic
3203 && (regno == PIC_OFFSET_TABLE_REGNUM
3204 || regno == TILEPRO_PIC_TEXT_LABEL_REGNUM)
3205 && (crtl->uses_pic_offset_table || crtl->saves_all_registers))
3206 return true;
3208 if (crtl->calls_eh_return)
3210 unsigned i;
3211 for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++)
3213 if (regno == EH_RETURN_DATA_REGNO (i))
3214 return true;
3218 return false;
3222 /* Return the size of the register savev area. This function is only
3223 correct starting with local register allocation */
3224 static int
3225 tilepro_saved_regs_size (void)
3227 int reg_save_size = 0;
3228 int regno;
3229 int offset_to_frame;
3230 int align_mask;
3232 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3233 if (need_to_save_reg (regno))
3234 reg_save_size += UNITS_PER_WORD;
3236 /* Pad out the register save area if necessary to make
3237 frame_pointer_rtx be as aligned as the stack pointer. */
3238 offset_to_frame = crtl->args.pretend_args_size + reg_save_size;
3239 align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1;
3240 reg_save_size += (-offset_to_frame) & align_mask;
3242 return reg_save_size;
3246 /* Round up frame size SIZE. */
3247 static int
3248 round_frame_size (int size)
3250 return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1)
3251 & -STACK_BOUNDARY / BITS_PER_UNIT);
3255 /* Emit a store in the stack frame to save REGNO at address ADDR, and
3256 emit the corresponding REG_CFA_OFFSET note described by CFA and
3257 CFA_OFFSET. Return the emitted insn. */
3258 static rtx
3259 frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa,
3260 int cfa_offset)
3262 rtx reg = gen_rtx_REG (Pmode, regno);
3263 rtx mem = gen_frame_mem (Pmode, addr);
3264 rtx mov = gen_movsi (mem, reg);
3266 /* Describe what just happened in a way that dwarf understands. We
3267 use temporary registers to hold the address to make scheduling
3268 easier, and use the REG_CFA_OFFSET to describe the address as an
3269 offset from the CFA. */
3270 rtx reg_note = gen_rtx_REG (Pmode, regno_note);
3271 rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, gen_int_si (cfa_offset));
3272 rtx cfa_relative_mem = gen_frame_mem (Pmode, cfa_relative_addr);
3273 rtx real = gen_rtx_SET (VOIDmode, cfa_relative_mem, reg_note);
3274 add_reg_note (mov, REG_CFA_OFFSET, real);
3276 return emit_insn (mov);
3280 /* Emit a load in the stack frame to load REGNO from address ADDR.
3281 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3282 non-null. Return the emitted insn. */
3283 static rtx
3284 frame_emit_load (int regno, rtx addr, rtx *cfa_restores)
3286 rtx reg = gen_rtx_REG (Pmode, regno);
3287 rtx mem = gen_frame_mem (Pmode, addr);
3288 if (cfa_restores)
3289 *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores);
3290 return emit_insn (gen_movsi (reg, mem));
3294 /* Helper function to set RTX_FRAME_RELATED_P on instructions,
3295 including sequences. */
3296 static rtx
3297 set_frame_related_p (void)
3299 rtx seq = get_insns ();
3300 rtx insn;
3302 end_sequence ();
3304 if (!seq)
3305 return NULL_RTX;
3307 if (INSN_P (seq))
3309 insn = seq;
3310 while (insn != NULL_RTX)
3312 RTX_FRAME_RELATED_P (insn) = 1;
3313 insn = NEXT_INSN (insn);
3315 seq = emit_insn (seq);
3317 else
3319 seq = emit_insn (seq);
3320 RTX_FRAME_RELATED_P (seq) = 1;
3322 return seq;
3326 #define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3328 /* This emits code for 'sp += offset'.
3330 The ABI only allows us to modify 'sp' in a single 'addi' or
3331 'addli', so the backtracer understands it. Larger amounts cannot
3332 use those instructions, so are added by placing the offset into a
3333 large register and using 'add'.
3335 This happens after reload, so we need to expand it ourselves. */
3336 static rtx
3337 emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related,
3338 rtx reg_notes)
3340 rtx to_add;
3341 rtx imm_rtx = gen_int_si (offset);
3343 rtx insn;
3344 if (satisfies_constraint_J (imm_rtx))
3346 /* We can add this using a single addi or addli. */
3347 to_add = imm_rtx;
3349 else
3351 rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3352 tilepro_expand_set_const32 (tmp, imm_rtx);
3353 to_add = tmp;
3356 /* Actually adjust the stack pointer. */
3357 insn = emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
3358 to_add));
3359 REG_NOTES (insn) = reg_notes;
3361 /* Describe what just happened in a way that dwarf understands. */
3362 if (frame_related)
3364 rtx real = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
3365 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3366 imm_rtx));
3367 RTX_FRAME_RELATED_P (insn) = 1;
3368 add_reg_note (insn, REG_CFA_ADJUST_CFA, real);
3371 return insn;
3375 /* Return whether the current function is leaf. This takes into
3376 account whether the function calls tls_get_addr. */
3377 static bool
3378 tilepro_current_function_is_leaf (void)
3380 return crtl->is_leaf && !cfun->machine->calls_tls_get_addr;
3384 /* Return the frame size. */
3385 static int
3386 compute_total_frame_size (void)
3388 int total_size = (get_frame_size () + tilepro_saved_regs_size ()
3389 + crtl->outgoing_args_size
3390 + crtl->args.pretend_args_size);
3392 if (!tilepro_current_function_is_leaf () || cfun->calls_alloca)
3394 /* Make room for save area in callee. */
3395 total_size += STACK_POINTER_OFFSET;
3398 return round_frame_size (total_size);
3402 /* Return nonzero if this function is known to have a null epilogue.
3403 This allows the optimizer to omit jumps to jumps if no stack was
3404 created. */
3405 bool
3406 tilepro_can_use_return_insn_p (void)
3408 return (reload_completed
3409 && cfun->static_chain_decl == 0
3410 && compute_total_frame_size () == 0
3411 && tilepro_current_function_is_leaf ()
3412 && !crtl->profile && !df_regs_ever_live_p (TILEPRO_LINK_REGNUM));
3416 /* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3417 is a frame pointer, it computes the value relative to
3418 that. Otherwise it uses the stack pointer. */
3419 static rtx
3420 compute_frame_addr (int offset_from_fp, int *next_scratch_regno)
3422 rtx base_reg_rtx, tmp_reg_rtx, offset_rtx;
3423 int offset_from_base;
3425 if (frame_pointer_needed)
3427 base_reg_rtx = hard_frame_pointer_rtx;
3428 offset_from_base = offset_from_fp;
3430 else
3432 int offset_from_sp = compute_total_frame_size () + offset_from_fp;
3433 base_reg_rtx = stack_pointer_rtx;
3434 offset_from_base = offset_from_sp;
3437 if (offset_from_base == 0)
3438 return base_reg_rtx;
3440 /* Compute the new value of the stack pointer. */
3441 tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3442 offset_rtx = gen_int_si (offset_from_base);
3444 if (!tilepro_expand_addsi (tmp_reg_rtx, base_reg_rtx, offset_rtx))
3446 emit_insn (gen_rtx_SET (VOIDmode, tmp_reg_rtx,
3447 gen_rtx_PLUS (Pmode, base_reg_rtx,
3448 offset_rtx)));
3451 return tmp_reg_rtx;
3455 /* The stack frame looks like this:
3456 +-------------+
3457 | ... |
3458 | incoming |
3459 | stack args |
3460 AP -> +-------------+
3461 | caller's HFP|
3462 +-------------+
3463 | lr save |
3464 HFP -> +-------------+
3465 | var args |
3466 | reg save | crtl->args.pretend_args_size bytes
3467 +-------------+
3468 | ... |
3469 | saved regs | tilepro_saved_regs_size() bytes
3470 FP -> +-------------+
3471 | ... |
3472 | vars | get_frame_size() bytes
3473 +-------------+
3474 | ... |
3475 | outgoing |
3476 | stack args | crtl->outgoing_args_size bytes
3477 +-------------+
3478 | HFP | 4 bytes (only here if nonleaf / alloca)
3479 +-------------+
3480 | callee lr | 4 bytes (only here if nonleaf / alloca)
3481 | save |
3482 SP -> +-------------+
3484 HFP == incoming SP.
3486 For functions with a frame larger than 32767 bytes, or which use
3487 alloca (), r52 is used as a frame pointer. Otherwise there is no
3488 frame pointer.
3490 FP is saved at SP+4 before calling a subroutine so the
3491 callee can chain. */
3492 void
3493 tilepro_expand_prologue (void)
3495 #define ROUND_ROBIN_SIZE 4
3496 /* We round-robin through four scratch registers to hold temporary
3497 addresses for saving registers, to make instruction scheduling
3498 easier. */
3499 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3500 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3502 rtx insn, cfa;
3503 unsigned int which_scratch;
3504 int offset, start_offset, regno;
3506 /* A register that holds a copy of the incoming fp. */
3507 int fp_copy_regno = -1;
3509 /* A register that holds a copy of the incoming sp. */
3510 int sp_copy_regno = -1;
3512 /* Next scratch register number to hand out (postdecrementing). */
3513 int next_scratch_regno = 29;
3515 int total_size = compute_total_frame_size ();
3517 if (flag_stack_usage_info)
3518 current_function_static_stack_size = total_size;
3520 /* Save lr first in its special location because code after this
3521 might use the link register as a scratch register. */
3522 if (df_regs_ever_live_p (TILEPRO_LINK_REGNUM) || crtl->calls_eh_return)
3523 FRP (frame_emit_store (TILEPRO_LINK_REGNUM, TILEPRO_LINK_REGNUM,
3524 stack_pointer_rtx, stack_pointer_rtx, 0));
3526 if (total_size == 0)
3528 /* Load the PIC register if needed. */
3529 if (flag_pic && crtl->uses_pic_offset_table)
3530 load_pic_register (false);
3532 return;
3535 cfa = stack_pointer_rtx;
3537 if (frame_pointer_needed)
3539 fp_copy_regno = next_scratch_regno--;
3541 /* Copy the old frame pointer aside so we can save it later. */
3542 insn = FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno),
3543 hard_frame_pointer_rtx));
3544 add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
3546 /* Set up the frame pointer. */
3547 insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
3548 add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx);
3549 cfa = hard_frame_pointer_rtx;
3550 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
3552 /* fp holds a copy of the incoming sp, in case we need to store
3553 it. */
3554 sp_copy_regno = HARD_FRAME_POINTER_REGNUM;
3556 else if (!tilepro_current_function_is_leaf ())
3558 /* Copy the old stack pointer aside so we can save it later. */
3559 sp_copy_regno = next_scratch_regno--;
3560 emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno),
3561 stack_pointer_rtx);
3564 if (tilepro_current_function_is_leaf ())
3566 /* No need to store chain pointer to caller's frame. */
3567 emit_sp_adjust (-total_size, &next_scratch_regno,
3568 !frame_pointer_needed, NULL_RTX);
3570 else
3572 /* Save the frame pointer (incoming sp value) to support
3573 backtracing. First we need to create an rtx with the store
3574 address. */
3575 rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--);
3576 rtx size_rtx = gen_int_si (-(total_size - UNITS_PER_WORD));
3578 if (add_operand (size_rtx, Pmode))
3580 /* Expose more parallelism by computing this value from the
3581 original stack pointer, not the one after we have pushed
3582 the frame. */
3583 rtx p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, size_rtx);
3584 emit_insn (gen_rtx_SET (VOIDmode, chain_addr, p));
3585 emit_sp_adjust (-total_size, &next_scratch_regno,
3586 !frame_pointer_needed, NULL_RTX);
3588 else
3590 /* The stack frame is large, so just store the incoming sp
3591 value at *(new_sp + UNITS_PER_WORD). */
3592 rtx p;
3593 emit_sp_adjust (-total_size, &next_scratch_regno,
3594 !frame_pointer_needed, NULL_RTX);
3595 p = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3596 GEN_INT (UNITS_PER_WORD));
3597 emit_insn (gen_rtx_SET (VOIDmode, chain_addr, p));
3600 /* Save our frame pointer for backtrace chaining. */
3601 emit_insn (gen_movsi (gen_frame_mem (SImode, chain_addr),
3602 gen_rtx_REG (SImode, sp_copy_regno)));
3605 /* Compute where to start storing registers we need to save. */
3606 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
3607 offset = start_offset;
3609 /* Store all registers that need saving. */
3610 which_scratch = 0;
3611 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
3612 if (need_to_save_reg (regno))
3614 rtx r = reg_save_addr[which_scratch];
3615 int from_regno;
3616 int cfa_offset = frame_pointer_needed ? offset : total_size + offset;
3618 if (r == NULL_RTX)
3620 rtx p = compute_frame_addr (offset, &next_scratch_regno);
3621 r = gen_rtx_REG (word_mode, next_scratch_regno--);
3622 reg_save_addr[which_scratch] = r;
3624 emit_insn (gen_rtx_SET (VOIDmode, r, p));
3626 else
3628 /* Advance to the next stack slot to store this register. */
3629 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
3630 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
3631 emit_insn (gen_rtx_SET (VOIDmode, r, p));
3634 /* Save this register to the stack (but use the old fp value
3635 we copied aside if appropriate). */
3636 from_regno = (fp_copy_regno >= 0
3637 && regno ==
3638 HARD_FRAME_POINTER_REGNUM) ? fp_copy_regno : regno;
3639 FRP (frame_emit_store (from_regno, regno, r, cfa, cfa_offset));
3641 offset -= UNITS_PER_WORD;
3642 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
3645 /* If profiling, force that to happen after the frame is set up. */
3646 if (crtl->profile)
3647 emit_insn (gen_blockage ());
3649 /* Load the PIC register if needed. */
3650 if (flag_pic && crtl->uses_pic_offset_table)
3651 load_pic_register (false);
3655 /* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
3656 true for a sibcall_epilogue pattern, and false for an epilogue
3657 pattern. */
3658 void
3659 tilepro_expand_epilogue (bool sibcall_p)
3661 /* We round-robin through four scratch registers to hold temporary
3662 addresses for saving registers, to make instruction scheduling
3663 easier. */
3664 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3665 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3667 rtx last_insn, insn;
3668 unsigned int which_scratch;
3669 int offset, start_offset, regno;
3670 rtx cfa_restores = NULL_RTX;
3672 /* A register that holds a copy of the incoming fp. */
3673 int fp_copy_regno = -1;
3675 /* Next scratch register number to hand out (postdecrementing). */
3676 int next_scratch_regno = 29;
3678 int total_size = compute_total_frame_size ();
3680 last_insn = get_last_insn ();
3682 /* Load lr first since we are going to need it first. */
3683 insn = NULL;
3684 if (df_regs_ever_live_p (TILEPRO_LINK_REGNUM))
3686 insn = frame_emit_load (TILEPRO_LINK_REGNUM,
3687 compute_frame_addr (0, &next_scratch_regno),
3688 &cfa_restores);
3691 if (total_size == 0)
3693 if (insn)
3695 RTX_FRAME_RELATED_P (insn) = 1;
3696 REG_NOTES (insn) = cfa_restores;
3698 goto done;
3701 /* Compute where to start restoring registers. */
3702 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
3703 offset = start_offset;
3705 if (frame_pointer_needed)
3706 fp_copy_regno = next_scratch_regno--;
3708 /* Restore all callee-saved registers. */
3709 which_scratch = 0;
3710 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
3711 if (need_to_save_reg (regno))
3713 rtx r = reg_save_addr[which_scratch];
3714 if (r == NULL_RTX)
3716 r = compute_frame_addr (offset, &next_scratch_regno);
3717 reg_save_addr[which_scratch] = r;
3719 else
3721 /* Advance to the next stack slot to store this
3722 register. */
3723 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
3724 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
3725 emit_insn (gen_rtx_SET (VOIDmode, r, p));
3728 if (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM)
3729 frame_emit_load (fp_copy_regno, r, NULL);
3730 else
3731 frame_emit_load (regno, r, &cfa_restores);
3733 offset -= UNITS_PER_WORD;
3734 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
3737 if (!tilepro_current_function_is_leaf ())
3738 cfa_restores =
3739 alloc_reg_note (REG_CFA_RESTORE, stack_pointer_rtx, cfa_restores);
3741 emit_insn (gen_blockage ());
3743 if (frame_pointer_needed)
3745 /* Restore the old stack pointer by copying from the frame
3746 pointer. */
3747 insn = emit_insn (gen_sp_restore (stack_pointer_rtx,
3748 hard_frame_pointer_rtx));
3749 RTX_FRAME_RELATED_P (insn) = 1;
3750 REG_NOTES (insn) = cfa_restores;
3751 add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx);
3753 else
3755 insn = emit_sp_adjust (total_size, &next_scratch_regno, true,
3756 cfa_restores);
3759 if (crtl->calls_eh_return)
3760 emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
3761 EH_RETURN_STACKADJ_RTX));
3763 /* Restore the old frame pointer. */
3764 if (frame_pointer_needed)
3766 insn = emit_move_insn (hard_frame_pointer_rtx,
3767 gen_rtx_REG (Pmode, fp_copy_regno));
3768 add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);
3771 /* Mark the pic registers as live outside of the function. */
3772 if (flag_pic)
3774 emit_use (cfun->machine->text_label_rtx);
3775 emit_use (cfun->machine->got_rtx);
3778 done:
3779 if (!sibcall_p)
3781 /* Emit the actual 'return' instruction. */
3782 emit_jump_insn (gen__return ());
3784 else
3786 emit_use (gen_rtx_REG (Pmode, TILEPRO_LINK_REGNUM));
3789 /* Mark all insns we just emitted as frame-related. */
3790 for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn))
3791 RTX_FRAME_RELATED_P (last_insn) = 1;
3794 #undef ROUND_ROBIN_SIZE
3797 /* Implement INITIAL_ELIMINATION_OFFSET. */
3799 tilepro_initial_elimination_offset (int from, int to)
3801 int total_size = compute_total_frame_size ();
3803 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
3805 return (total_size - crtl->args.pretend_args_size
3806 - tilepro_saved_regs_size ());
3808 else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
3810 return -(crtl->args.pretend_args_size + tilepro_saved_regs_size ());
3812 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
3814 return STACK_POINTER_OFFSET + total_size;
3816 else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
3818 return STACK_POINTER_OFFSET;
3820 else
3821 gcc_unreachable ();
3825 /* Return an RTX indicating where the return address to the
3826 calling function can be found. */
3828 tilepro_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3830 if (count != 0)
3831 return const0_rtx;
3833 return get_hard_reg_initial_val (Pmode, TILEPRO_LINK_REGNUM);
3837 /* Implement EH_RETURN_HANDLER_RTX. */
3839 tilepro_eh_return_handler_rtx (void)
3841 /* The MEM needs to be volatile to prevent it from being
3842 deleted. */
3843 rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
3844 MEM_VOLATILE_P (tmp) = true;
3845 return tmp;
3850 /* Registers */
3852 /* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
3853 static void
3854 tilepro_conditional_register_usage (void)
3856 global_regs[TILEPRO_NETORDER_REGNUM] = 1;
3857 /* TILEPRO_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
3858 member of fixed_regs, and therefore must be member of
3859 call_used_regs, but it is not a member of call_really_used_regs[]
3860 because it is not clobbered by a call. */
3861 if (TILEPRO_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM)
3863 fixed_regs[TILEPRO_PIC_TEXT_LABEL_REGNUM] = 1;
3864 call_used_regs[TILEPRO_PIC_TEXT_LABEL_REGNUM] = 1;
3866 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
3868 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
3869 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
3874 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3875 static bool
3876 tilepro_frame_pointer_required (void)
3878 return crtl->calls_eh_return || cfun->calls_alloca;
3883 /* Scheduling and reorg */
3885 /* Return the length of INSN. LENGTH is the initial length computed
3886 by attributes in the machine-description file. This is where we
3887 account for bundles. */
3889 tilepro_adjust_insn_length (rtx insn, int length)
3891 enum machine_mode mode = GET_MODE (insn);
3893 /* A non-termininating instruction in a bundle has length 0. */
3894 if (mode == SImode)
3895 return 0;
3897 /* By default, there is not length adjustment. */
3898 return length;
3902 /* Implement TARGET_SCHED_ISSUE_RATE. */
3903 static int
3904 tilepro_issue_rate (void)
3906 return 3;
3910 /* Return the rtx for the jump target. */
3911 static rtx
3912 get_jump_target (rtx branch)
3914 if (CALL_P (branch))
3916 rtx call;
3917 call = PATTERN (branch);
3919 if (GET_CODE (call) == PARALLEL)
3920 call = XVECEXP (call, 0, 0);
3922 if (GET_CODE (call) == SET)
3923 call = SET_SRC (call);
3925 if (GET_CODE (call) == CALL)
3926 return XEXP (XEXP (call, 0), 0);
3928 return 0;
3931 /* Implement TARGET_SCHED_ADJUST_COST. */
3932 static int
3933 tilepro_sched_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
3935 /* If we have a true dependence, INSN is a call, and DEP_INSN
3936 defines a register that is needed by the call (argument or stack
3937 pointer), set its latency to 0 so that it can be bundled with
3938 the call. Explicitly check for and exclude the case when
3939 DEP_INSN defines the target of the jump. */
3940 if (CALL_P (insn) && REG_NOTE_KIND (link) == REG_DEP_TRUE)
3942 rtx target = get_jump_target (insn);
3943 if (!REG_P (target) || !set_of (target, dep_insn))
3944 return 0;
3947 return cost;
3951 /* Skip over irrelevant NOTEs and such and look for the next insn we
3952 would consider bundling. */
3953 static rtx
3954 next_insn_to_bundle (rtx r, rtx end)
3956 for (; r != end; r = NEXT_INSN (r))
3958 if (NONDEBUG_INSN_P (r)
3959 && GET_CODE (PATTERN (r)) != USE
3960 && GET_CODE (PATTERN (r)) != CLOBBER)
3961 return r;
3964 return NULL_RTX;
3968 /* Go through all insns, and use the information generated during
3969 scheduling to generate SEQUENCEs to represent bundles of
3970 instructions issued simultaneously. */
3971 static void
3972 tilepro_gen_bundles (void)
3974 basic_block bb;
3975 FOR_EACH_BB (bb)
3977 rtx insn, next;
3978 rtx end = NEXT_INSN (BB_END (bb));
3980 for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn; insn = next)
3982 next = next_insn_to_bundle (NEXT_INSN (insn), end);
3984 /* Never wrap {} around inline asm. */
3985 if (GET_CODE (PATTERN (insn)) != ASM_INPUT)
3987 if (next == NULL_RTX || GET_MODE (next) == TImode
3988 /* NOTE: The scheduler incorrectly believes a call
3989 insn can execute in the same cycle as the insn
3990 after the call. This is of course impossible.
3991 Really we need to fix the scheduler somehow, so
3992 the code after the call gets scheduled
3993 optimally. */
3994 || CALL_P (insn))
3996 /* Mark current insn as the end of a bundle. */
3997 PUT_MODE (insn, QImode);
3999 else
4001 /* Mark it as part of a bundle. */
4002 PUT_MODE (insn, SImode);
4010 /* Helper function for tilepro_fixup_pcrel_references. */
4011 static void
4012 replace_pc_relative_symbol_ref (rtx insn, rtx opnds[4], bool first_insn_p)
4014 rtx new_insns;
4016 start_sequence ();
4018 if (flag_pic == 1)
4020 if (!first_insn_p)
4022 emit_insn (gen_add_got16 (opnds[0], tilepro_got_rtx (),
4023 opnds[2]));
4024 emit_insn (gen_insn_lw (opnds[0], opnds[0]));
4027 else
4029 if (first_insn_p)
4031 emit_insn (gen_addhi_got32 (opnds[0], tilepro_got_rtx (),
4032 opnds[2]));
4034 else
4036 emit_insn (gen_addlo_got32 (opnds[0], opnds[1], opnds[2]));
4037 emit_insn (gen_insn_lw (opnds[0], opnds[0]));
4041 new_insns = get_insns ();
4042 end_sequence ();
4044 if (new_insns)
4045 emit_insn_before (new_insns, insn);
4047 delete_insn (insn);
4051 /* Returns whether INSN is a pc-relative addli insn. */
4052 static bool
4053 match_addli_pcrel (rtx insn)
4055 rtx pattern = PATTERN (insn);
4056 rtx unspec;
4058 if (GET_CODE (pattern) != SET)
4059 return false;
4061 if (GET_CODE (SET_SRC (pattern)) != LO_SUM)
4062 return false;
4064 if (GET_CODE (XEXP (SET_SRC (pattern), 1)) != CONST)
4065 return false;
4067 unspec = XEXP (XEXP (SET_SRC (pattern), 1), 0);
4069 return (GET_CODE (unspec) == UNSPEC
4070 && XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4074 /* Helper function for tilepro_fixup_pcrel_references. */
4075 static void
4076 replace_addli_pcrel (rtx insn)
4078 rtx pattern = PATTERN (insn);
4079 rtx set_src;
4080 rtx unspec;
4081 rtx opnds[4];
4082 bool first_insn_p;
4084 gcc_assert (GET_CODE (pattern) == SET);
4085 opnds[0] = SET_DEST (pattern);
4087 set_src = SET_SRC (pattern);
4088 gcc_assert (GET_CODE (set_src) == LO_SUM);
4089 gcc_assert (GET_CODE (XEXP (set_src, 1)) == CONST);
4090 opnds[1] = XEXP (set_src, 0);
4092 unspec = XEXP (XEXP (set_src, 1), 0);
4093 gcc_assert (GET_CODE (unspec) == UNSPEC);
4094 gcc_assert (XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4095 opnds[2] = XVECEXP (unspec, 0, 0);
4096 opnds[3] = XVECEXP (unspec, 0, 1);
4098 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4099 if (GET_CODE (opnds[2]) != SYMBOL_REF)
4100 return;
4102 first_insn_p = (opnds[1] == tilepro_text_label_rtx ());
4104 replace_pc_relative_symbol_ref (insn, opnds, first_insn_p);
4108 /* Returns whether INSN is a pc-relative auli insn. */
4109 static bool
4110 match_auli_pcrel (rtx insn)
4112 rtx pattern = PATTERN (insn);
4113 rtx high;
4114 rtx unspec;
4116 if (GET_CODE (pattern) != SET)
4117 return false;
4119 if (GET_CODE (SET_SRC (pattern)) != PLUS)
4120 return false;
4122 high = XEXP (SET_SRC (pattern), 1);
4124 if (GET_CODE (high) != HIGH
4125 || GET_CODE (XEXP (high, 0)) != CONST)
4126 return false;
4128 unspec = XEXP (XEXP (high, 0), 0);
4130 return (GET_CODE (unspec) == UNSPEC
4131 && XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4135 /* Helper function for tilepro_fixup_pcrel_references. */
4136 static void
4137 replace_auli_pcrel (rtx insn)
4139 rtx pattern = PATTERN (insn);
4140 rtx set_src;
4141 rtx high;
4142 rtx unspec;
4143 rtx opnds[4];
4144 bool first_insn_p;
4146 gcc_assert (GET_CODE (pattern) == SET);
4147 opnds[0] = SET_DEST (pattern);
4149 set_src = SET_SRC (pattern);
4150 gcc_assert (GET_CODE (set_src) == PLUS);
4151 opnds[1] = XEXP (set_src, 0);
4153 high = XEXP (set_src, 1);
4154 gcc_assert (GET_CODE (high) == HIGH);
4155 gcc_assert (GET_CODE (XEXP (high, 0)) == CONST);
4157 unspec = XEXP (XEXP (high, 0), 0);
4158 gcc_assert (GET_CODE (unspec) == UNSPEC);
4159 gcc_assert (XINT (unspec, 1) == UNSPEC_PCREL_SYM);
4160 opnds[2] = XVECEXP (unspec, 0, 0);
4161 opnds[3] = XVECEXP (unspec, 0, 1);
4163 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4164 if (GET_CODE (opnds[2]) != SYMBOL_REF)
4165 return;
4167 first_insn_p = (opnds[1] == tilepro_text_label_rtx ());
4169 replace_pc_relative_symbol_ref (insn, opnds, first_insn_p);
4173 /* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4174 going through the GOT when the symbol is local to the compilation
4175 unit. But such a symbol requires that the common text_label that
4176 we generate at the beginning of the function be in the same section
4177 as the reference to the SYMBOL_REF. This may not be true if we
4178 generate hot/cold sections. This function looks for such cases and
4179 replaces such references with the longer sequence going through the
4180 GOT.
4182 We expect one of the following two instruction sequences:
4183 addli tmp1, txt_label_reg, lo16(sym - txt_label)
4184 auli tmp2, tmp1, ha16(sym - txt_label)
4186 auli tmp1, txt_label_reg, ha16(sym - txt_label)
4187 addli tmp2, tmp1, lo16(sym - txt_label)
4189 If we're compiling -fpic, we replace the first instruction with
4190 nothing, and the second instruction with:
4192 addli tmp2, got_rtx, got(sym)
4193 lw tmp2, tmp2
4195 If we're compiling -fPIC, we replace the first instruction with:
4197 auli tmp1, got_rtx, got_ha16(sym)
4199 and the second instruction with:
4201 addli tmp2, tmp1, got_lo16(sym)
4202 lw tmp2, tmp2
4204 Note that we're careful to disturb the instruction sequence as
4205 little as possible, since it's very late in the compilation
4206 process.
4208 static void
4209 tilepro_fixup_pcrel_references (void)
4211 rtx insn, next_insn;
4212 bool same_section_as_entry = true;
4214 for (insn = get_insns (); insn; insn = next_insn)
4216 next_insn = NEXT_INSN (insn);
4218 if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
4220 same_section_as_entry = !same_section_as_entry;
4221 continue;
4224 if (same_section_as_entry)
4225 continue;
4227 if (!(INSN_P (insn)
4228 && GET_CODE (PATTERN (insn)) != USE
4229 && GET_CODE (PATTERN (insn)) != CLOBBER))
4230 continue;
4232 if (match_addli_pcrel (insn))
4233 replace_addli_pcrel (insn);
4234 else if (match_auli_pcrel (insn))
4235 replace_auli_pcrel (insn);
4240 /* Ensure that no var tracking notes are emitted in the middle of a
4241 three-instruction bundle. */
4242 static void
4243 reorder_var_tracking_notes (void)
4245 basic_block bb;
4246 FOR_EACH_BB (bb)
4248 rtx insn, next;
4249 rtx queue = NULL_RTX;
4250 bool in_bundle = false;
4252 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4254 next = NEXT_INSN (insn);
4256 if (INSN_P (insn))
4258 /* Emit queued up notes at the last instruction of a bundle. */
4259 if (GET_MODE (insn) == QImode)
4261 while (queue)
4263 rtx next_queue = PREV_INSN (queue);
4264 PREV_INSN (NEXT_INSN (insn)) = queue;
4265 NEXT_INSN (queue) = NEXT_INSN (insn);
4266 NEXT_INSN (insn) = queue;
4267 PREV_INSN (queue) = insn;
4268 queue = next_queue;
4270 in_bundle = false;
4272 else if (GET_MODE (insn) == SImode)
4273 in_bundle = true;
4275 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4277 if (in_bundle)
4279 rtx prev = PREV_INSN (insn);
4280 PREV_INSN (next) = prev;
4281 NEXT_INSN (prev) = next;
4283 PREV_INSN (insn) = queue;
4284 queue = insn;
4292 /* Perform machine dependent operations on the rtl chain INSNS. */
4293 static void
4294 tilepro_reorg (void)
4296 /* We are freeing block_for_insn in the toplev to keep compatibility
4297 with old MDEP_REORGS that are not CFG based. Recompute it
4298 now. */
4299 compute_bb_for_insn ();
4301 if (flag_reorder_blocks_and_partition)
4303 tilepro_fixup_pcrel_references ();
4306 if (flag_schedule_insns_after_reload)
4308 split_all_insns ();
4310 timevar_push (TV_SCHED2);
4311 schedule_insns ();
4312 timevar_pop (TV_SCHED2);
4314 /* Examine the schedule to group into bundles. */
4315 tilepro_gen_bundles ();
4318 df_analyze ();
4320 if (flag_var_tracking)
4322 timevar_push (TV_VAR_TRACKING);
4323 variable_tracking_main ();
4324 reorder_var_tracking_notes ();
4325 timevar_pop (TV_VAR_TRACKING);
4328 df_finish_pass (false);
4333 /* Assembly */
4335 /* Select a format to encode pointers in exception handling data.
4336 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4337 GLOBAL is true if the symbol may be affected by dynamic
4338 relocations. */
4340 tilepro_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
4342 return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4;
4346 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4347 static void
4348 tilepro_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
4349 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
4350 tree function)
4352 rtx this_rtx, insn, funexp;
4354 /* Pretend to be a post-reload pass while generating rtl. */
4355 reload_completed = 1;
4357 /* Mark the end of the (empty) prologue. */
4358 emit_note (NOTE_INSN_PROLOGUE_END);
4360 /* Find the "this" pointer. If the function returns a structure,
4361 the structure return pointer is in $1. */
4362 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
4363 this_rtx = gen_rtx_REG (Pmode, 1);
4364 else
4365 this_rtx = gen_rtx_REG (Pmode, 0);
4367 /* Add DELTA to THIS_RTX. */
4368 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
4370 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4371 if (vcall_offset)
4373 rtx tmp;
4375 tmp = gen_rtx_REG (Pmode, 29);
4376 emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx));
4378 emit_insn (gen_addsi3 (tmp, tmp, GEN_INT (vcall_offset)));
4380 emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
4382 emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp));
4385 /* Generate a tail call to the target function. */
4386 if (!TREE_USED (function))
4388 assemble_external (function);
4389 TREE_USED (function) = 1;
4391 funexp = XEXP (DECL_RTL (function), 0);
4392 funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
4393 insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
4394 SIBLING_CALL_P (insn) = 1;
4396 /* Run just enough of rest_of_compilation to get the insns emitted.
4397 There's not really enough bulk here to make other passes such as
4398 instruction scheduling worth while. Note that use_thunk calls
4399 assemble_start_function and assemble_end_function.
4401 We don't currently bundle, but the instruciton sequence is all
4402 serial except for the tail call, so we're only wasting one cycle.
4404 insn = get_insns ();
4405 shorten_branches (insn);
4406 final_start_function (insn, file, 1);
4407 final (insn, file, 1);
4408 final_end_function ();
4410 /* Stop pretending to be a post-reload pass. */
4411 reload_completed = 0;
4415 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
4416 static void
4417 tilepro_asm_trampoline_template (FILE *file)
4419 fprintf (file, "\tlnk r10\n");
4420 fprintf (file, "\taddi r10, r10, 32\n");
4421 fprintf (file, "\tlwadd r11, r10, %d\n", GET_MODE_SIZE (ptr_mode));
4422 fprintf (file, "\tlw r10, r10\n");
4423 fprintf (file, "\tjr r11\n");
4424 fprintf (file, "\t.word 0 # <function address>\n");
4425 fprintf (file, "\t.word 0 # <static chain value>\n");
4429 /* Implement TARGET_TRAMPOLINE_INIT. */
4430 static void
4431 tilepro_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
4433 rtx fnaddr, chaddr;
4434 rtx mem;
4435 rtx begin_addr, end_addr;
4436 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4438 fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
4439 chaddr = copy_to_reg (static_chain);
4441 emit_block_move (m_tramp, assemble_trampoline_template (),
4442 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
4444 mem = adjust_address (m_tramp, ptr_mode,
4445 TRAMPOLINE_SIZE - 2 * ptr_mode_size);
4446 emit_move_insn (mem, fnaddr);
4447 mem = adjust_address (m_tramp, ptr_mode,
4448 TRAMPOLINE_SIZE - ptr_mode_size);
4449 emit_move_insn (mem, chaddr);
4451 /* Get pointers to the beginning and end of the code block. */
4452 begin_addr = force_reg (Pmode, XEXP (m_tramp, 0));
4453 end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0),
4454 TRAMPOLINE_SIZE));
4456 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
4457 LCT_NORMAL, VOIDmode, 2, begin_addr, Pmode,
4458 end_addr, Pmode);
4462 /* Implement TARGET_PRINT_OPERAND. */
4463 static void
4464 tilepro_print_operand (FILE *file, rtx x, int code)
4466 switch (code)
4468 case 'c':
4469 /* Print the compare operator opcode for conditional moves. */
4470 switch (GET_CODE (x))
4472 case EQ:
4473 fputs ("z", file);
4474 break;
4475 case NE:
4476 fputs ("nz", file);
4477 break;
4478 default:
4479 output_operand_lossage ("invalid %%c operand");
4481 return;
4483 case 'C':
4484 /* Print the compare operator opcode for conditional moves. */
4485 switch (GET_CODE (x))
4487 case EQ:
4488 fputs ("nz", file);
4489 break;
4490 case NE:
4491 fputs ("z", file);
4492 break;
4493 default:
4494 output_operand_lossage ("invalid %%C operand");
4496 return;
4498 case 'h':
4500 /* Print the high 16 bits of a 32-bit constant. */
4501 HOST_WIDE_INT i;
4502 if (CONST_INT_P (x))
4503 i = INTVAL (x);
4504 else if (GET_CODE (x) == CONST_DOUBLE)
4505 i = CONST_DOUBLE_LOW (x);
4506 else
4508 output_operand_lossage ("invalid %%h operand");
4509 return;
4511 i = trunc_int_for_mode (i >> 16, HImode);
4512 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4513 return;
4516 case 'H':
4518 rtx addr = NULL;
4519 const char *opstr = NULL;
4520 bool pcrel = false;
4521 if (GET_CODE (x) == CONST
4522 && GET_CODE (XEXP (x, 0)) == UNSPEC)
4524 addr = XVECEXP (XEXP (x, 0), 0, 0);
4525 switch (XINT (XEXP (x, 0), 1))
4527 case UNSPEC_GOT32_SYM:
4528 opstr = "got_ha16";
4529 break;
4530 case UNSPEC_PCREL_SYM:
4531 opstr = "ha16";
4532 pcrel = true;
4533 break;
4534 case UNSPEC_TLS_GD:
4535 opstr = "tls_gd_ha16";
4536 break;
4537 case UNSPEC_TLS_IE:
4538 opstr = "tls_ie_ha16";
4539 break;
4540 case UNSPEC_TLS_LE:
4541 opstr = "tls_le_ha16";
4542 break;
4543 default:
4544 output_operand_lossage ("invalid %%H operand");
4547 else
4549 addr = x;
4550 opstr = "ha16";
4553 fputs (opstr, file);
4554 fputc ('(', file);
4555 output_addr_const (file, addr);
4557 if (pcrel)
4559 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
4560 fputs (" - " , file);
4561 output_addr_const (file, addr2);
4564 fputc (')', file);
4565 return;
4568 case 'I':
4569 /* Print an auto-inc memory operand. */
4570 if (!MEM_P (x))
4572 output_operand_lossage ("invalid %%I operand");
4573 return;
4576 output_memory_reference_mode = GET_MODE (x);
4577 output_memory_autoinc_first = true;
4578 output_address (XEXP (x, 0));
4579 output_memory_reference_mode = VOIDmode;
4580 return;
4582 case 'i':
4583 /* Print an auto-inc memory operand. */
4584 if (!MEM_P (x))
4586 output_operand_lossage ("invalid %%i operand");
4587 return;
4590 output_memory_reference_mode = GET_MODE (x);
4591 output_memory_autoinc_first = false;
4592 output_address (XEXP (x, 0));
4593 output_memory_reference_mode = VOIDmode;
4594 return;
4596 case 'j':
4598 /* Print the low 8 bits of a constant. */
4599 HOST_WIDE_INT i;
4600 if (CONST_INT_P (x))
4601 i = INTVAL (x);
4602 else if (GET_CODE (x) == CONST_DOUBLE)
4603 i = CONST_DOUBLE_LOW (x);
4604 else if (GET_CODE (x) == CONST_VECTOR
4605 && CONST_INT_P (CONST_VECTOR_ELT (x, 0)))
4606 i = INTVAL (CONST_VECTOR_ELT (x, 0));
4607 else
4609 output_operand_lossage ("invalid %%j operand");
4610 return;
4612 i = trunc_int_for_mode (i, QImode);
4613 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4614 return;
4617 case 'L':
4619 rtx addr = NULL;
4620 const char *opstr = NULL;
4621 bool pcrel = false;
4622 if (GET_CODE (x) == CONST
4623 && GET_CODE (XEXP (x, 0)) == UNSPEC)
4625 addr = XVECEXP (XEXP (x, 0), 0, 0);
4626 switch (XINT (XEXP (x, 0), 1))
4628 case UNSPEC_GOT16_SYM:
4629 opstr = "got";
4630 break;
4631 case UNSPEC_GOT32_SYM:
4632 opstr = "got_lo16";
4633 break;
4634 case UNSPEC_PCREL_SYM:
4635 opstr = "lo16";
4636 pcrel = true;
4637 break;
4638 case UNSPEC_TLS_GD:
4639 opstr = "tls_gd_lo16";
4640 break;
4641 case UNSPEC_TLS_IE:
4642 opstr = "tls_ie_lo16";
4643 break;
4644 case UNSPEC_TLS_LE:
4645 opstr = "tls_le_lo16";
4646 break;
4647 default:
4648 output_operand_lossage ("invalid %%L operand");
4651 else
4653 addr = x;
4654 opstr = "lo16";
4657 fputs (opstr, file);
4658 fputc ('(', file);
4659 output_addr_const (file, addr);
4661 if (pcrel)
4663 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
4664 fputs (" - " , file);
4665 output_addr_const (file, addr2);
4668 fputc (')', file);
4669 return;
4672 case 'p':
4673 if (GET_CODE (x) == SYMBOL_REF)
4675 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
4676 fprintf (file, "plt(");
4677 output_addr_const (file, x);
4678 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
4679 fprintf (file, ")");
4681 else
4682 output_addr_const (file, x);
4683 return;
4685 case 'P':
4687 /* Print a 32-bit constant plus one. */
4688 HOST_WIDE_INT i;
4689 if (!CONST_INT_P (x))
4691 output_operand_lossage ("invalid %%P operand");
4692 return;
4694 i = trunc_int_for_mode (INTVAL (x) + 1, SImode);
4695 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4696 return;
4699 case 'M':
4701 /* Print an mm-style bit range. */
4702 int first_bit, last_bit;
4704 if (!CONST_INT_P (x)
4705 || !tilepro_bitfield_operand_p (INTVAL (x), &first_bit,
4706 &last_bit))
4708 output_operand_lossage ("invalid %%M operand");
4709 return;
4712 fprintf (file, "%d, %d", first_bit, last_bit);
4713 return;
4716 case 'N':
4718 const char *reg = NULL;
4720 /* Print a network register. */
4721 if (!CONST_INT_P (x))
4723 output_operand_lossage ("invalid %%N operand");
4724 return;
4727 switch (INTVAL (x))
4729 case TILEPRO_NETREG_IDN0: reg = "idn0"; break;
4730 case TILEPRO_NETREG_IDN1: reg = "idn1"; break;
4731 case TILEPRO_NETREG_SN: reg = "sn"; break;
4732 case TILEPRO_NETREG_UDN0: reg = "udn0"; break;
4733 case TILEPRO_NETREG_UDN1: reg = "udn1"; break;
4734 case TILEPRO_NETREG_UDN2: reg = "udn2"; break;
4735 case TILEPRO_NETREG_UDN3: reg = "udn3"; break;
4736 default: gcc_unreachable ();
4739 fprintf (file, reg);
4740 return;
4743 case 't':
4745 /* Log base 2 of a power of two. */
4746 HOST_WIDE_INT i;
4747 HOST_WIDE_INT n;
4749 if (!CONST_INT_P (x))
4751 output_operand_lossage ("invalid %%t operand");
4752 return;
4754 n = trunc_int_for_mode (INTVAL (x), SImode);
4755 i = exact_log2 (n);
4756 if (i < 0)
4758 output_operand_lossage ("invalid %%t operand '"
4759 HOST_WIDE_INT_PRINT_DEC "'", n);
4760 return;
4763 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
4764 return;
4766 break;
4768 case 'r':
4769 /* In this case we need a register. Use 'zero' if the
4770 operand is const0_rtx. */
4771 if (x == const0_rtx
4772 || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
4774 fputs ("zero", file);
4775 return;
4777 else if (!REG_P (x))
4779 output_operand_lossage ("invalid %%r operand");
4780 return;
4782 /* FALLTHRU */
4784 case 0:
4785 if (REG_P (x))
4787 fprintf (file, "%s", reg_names[REGNO (x)]);
4788 return;
4790 else if (MEM_P (x))
4792 output_memory_reference_mode = VOIDmode;
4793 output_address (XEXP (x, 0));
4794 return;
4796 else
4798 output_addr_const (file, x);
4799 return;
4801 break;
4804 debug_rtx (x);
4805 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
4806 code, code);
4810 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
4811 static void
4812 tilepro_print_operand_address (FILE *file, rtx addr)
4814 if (GET_CODE (addr) == POST_DEC
4815 || GET_CODE (addr) == POST_INC)
4817 int offset = GET_MODE_SIZE (output_memory_reference_mode);
4819 gcc_assert (output_memory_reference_mode != VOIDmode);
4821 if (output_memory_autoinc_first)
4822 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
4823 else
4824 fprintf (file, "%d",
4825 GET_CODE (addr) == POST_DEC ? -offset : offset);
4827 else if (GET_CODE (addr) == POST_MODIFY)
4829 gcc_assert (output_memory_reference_mode != VOIDmode);
4831 gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
4833 if (output_memory_autoinc_first)
4834 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
4835 else
4836 fprintf (file, HOST_WIDE_INT_PRINT_DEC,
4837 INTVAL (XEXP (XEXP (addr, 1), 1)));
4839 else
4840 tilepro_print_operand (file, addr, 'r');
4844 /* Machine mode of current insn, for determining curly brace
4845 placement. */
4846 static enum machine_mode insn_mode;
4849 /* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
4850 void
4851 tilepro_final_prescan_insn (rtx insn)
4853 /* Record this for tilepro_asm_output_opcode to examine. */
4854 insn_mode = GET_MODE (insn);
4858 /* While emitting asm, are we currently inside '{' for a bundle? */
4859 static bool tilepro_in_bundle = false;
4861 /* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
4862 appropriate given the bundling information recorded by
4863 tilepro_gen_bundles. */
4864 const char *
4865 tilepro_asm_output_opcode (FILE *stream, const char *code)
4867 bool pseudo = !strcmp (code, "pseudo");
4869 if (!tilepro_in_bundle && insn_mode == SImode)
4871 /* Start a new bundle. */
4872 fprintf (stream, "{\n\t");
4873 tilepro_in_bundle = true;
4876 if (tilepro_in_bundle && insn_mode == QImode)
4878 /* Close an existing bundle. */
4879 static char buf[100];
4881 gcc_assert (strlen (code) + 3 + 1 < sizeof (buf));
4883 strcpy (buf, pseudo ? "" : code);
4884 strcat (buf, "\n\t}");
4885 tilepro_in_bundle = false;
4887 return buf;
4889 else
4891 return pseudo ? "" : code;
4896 /* Output assembler code to FILE to increment profiler label # LABELNO
4897 for profiling a function entry. */
4898 void
4899 tilepro_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
4901 if (tilepro_in_bundle)
4903 fprintf (file, "\t}\n");
4906 if (flag_pic)
4908 fprintf (file,
4909 "\t{\n"
4910 "\tmove\tr10, lr\n"
4911 "\tjal\tplt(%s)\n"
4912 "\t}\n", MCOUNT_NAME);
4914 else
4916 fprintf (file,
4917 "\t{\n"
4918 "\tmove\tr10, lr\n"
4919 "\tjal\t%s\n"
4920 "\t}\n", MCOUNT_NAME);
4923 tilepro_in_bundle = false;
4927 /* Implement TARGET_ASM_FILE_END. */
4928 static void
4929 tilepro_file_end (void)
4931 if (NEED_INDICATE_EXEC_STACK)
4932 file_end_indicate_exec_stack ();
4936 #undef TARGET_HAVE_TLS
4937 #define TARGET_HAVE_TLS HAVE_AS_TLS
4939 #undef TARGET_OPTION_OVERRIDE
4940 #define TARGET_OPTION_OVERRIDE tilepro_option_override
4942 #undef TARGET_SCALAR_MODE_SUPPORTED_P
4943 #define TARGET_SCALAR_MODE_SUPPORTED_P tilepro_scalar_mode_supported_p
4945 #undef TARGET_VECTOR_MODE_SUPPORTED_P
4946 #define TARGET_VECTOR_MODE_SUPPORTED_P tile_vector_mode_supported_p
4948 #undef TARGET_CANNOT_FORCE_CONST_MEM
4949 #define TARGET_CANNOT_FORCE_CONST_MEM tilepro_cannot_force_const_mem
4951 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
4952 #define TARGET_FUNCTION_OK_FOR_SIBCALL tilepro_function_ok_for_sibcall
4954 #undef TARGET_PASS_BY_REFERENCE
4955 #define TARGET_PASS_BY_REFERENCE tilepro_pass_by_reference
4957 #undef TARGET_RETURN_IN_MEMORY
4958 #define TARGET_RETURN_IN_MEMORY tilepro_return_in_memory
4960 #undef TARGET_FUNCTION_ARG_BOUNDARY
4961 #define TARGET_FUNCTION_ARG_BOUNDARY tilepro_function_arg_boundary
4963 #undef TARGET_FUNCTION_ARG
4964 #define TARGET_FUNCTION_ARG tilepro_function_arg
4966 #undef TARGET_FUNCTION_ARG_ADVANCE
4967 #define TARGET_FUNCTION_ARG_ADVANCE tilepro_function_arg_advance
4969 #undef TARGET_FUNCTION_VALUE
4970 #define TARGET_FUNCTION_VALUE tilepro_function_value
4972 #undef TARGET_LIBCALL_VALUE
4973 #define TARGET_LIBCALL_VALUE tilepro_libcall_value
4975 #undef TARGET_FUNCTION_VALUE_REGNO_P
4976 #define TARGET_FUNCTION_VALUE_REGNO_P tilepro_function_value_regno_p
4978 #undef TARGET_PROMOTE_FUNCTION_MODE
4979 #define TARGET_PROMOTE_FUNCTION_MODE \
4980 default_promote_function_mode_always_promote
4982 #undef TARGET_PROMOTE_PROTOTYPES
4983 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
4985 #undef TARGET_BUILD_BUILTIN_VA_LIST
4986 #define TARGET_BUILD_BUILTIN_VA_LIST tilepro_build_builtin_va_list
4988 #undef TARGET_EXPAND_BUILTIN_VA_START
4989 #define TARGET_EXPAND_BUILTIN_VA_START tilepro_va_start
4991 #undef TARGET_SETUP_INCOMING_VARARGS
4992 #define TARGET_SETUP_INCOMING_VARARGS tilepro_setup_incoming_varargs
4994 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
4995 #define TARGET_GIMPLIFY_VA_ARG_EXPR tilepro_gimplify_va_arg_expr
4997 #undef TARGET_RTX_COSTS
4998 #define TARGET_RTX_COSTS tilepro_rtx_costs
5000 /* Limit to what we can reach in one addli. */
5001 #undef TARGET_MIN_ANCHOR_OFFSET
5002 #define TARGET_MIN_ANCHOR_OFFSET -32768
5003 #undef TARGET_MAX_ANCHOR_OFFSET
5004 #define TARGET_MAX_ANCHOR_OFFSET 32767
5006 #undef TARGET_LEGITIMATE_CONSTANT_P
5007 #define TARGET_LEGITIMATE_CONSTANT_P tilepro_legitimate_constant_p
5009 #undef TARGET_LEGITIMATE_ADDRESS_P
5010 #define TARGET_LEGITIMATE_ADDRESS_P tilepro_legitimate_address_p
5012 #undef TARGET_LEGITIMIZE_ADDRESS
5013 #define TARGET_LEGITIMIZE_ADDRESS tilepro_legitimize_address
5015 #undef TARGET_DELEGITIMIZE_ADDRESS
5016 #define TARGET_DELEGITIMIZE_ADDRESS tilepro_delegitimize_address
5018 #undef TARGET_INIT_BUILTINS
5019 #define TARGET_INIT_BUILTINS tilepro_init_builtins
5021 #undef TARGET_BUILTIN_DECL
5022 #define TARGET_BUILTIN_DECL tilepro_builtin_decl
5024 #undef TARGET_EXPAND_BUILTIN
5025 #define TARGET_EXPAND_BUILTIN tilepro_expand_builtin
5027 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5028 #define TARGET_CONDITIONAL_REGISTER_USAGE tilepro_conditional_register_usage
5030 #undef TARGET_FRAME_POINTER_REQUIRED
5031 #define TARGET_FRAME_POINTER_REQUIRED tilepro_frame_pointer_required
5033 #undef TARGET_DELAY_SCHED2
5034 #define TARGET_DELAY_SCHED2 true
5036 #undef TARGET_DELAY_VARTRACK
5037 #define TARGET_DELAY_VARTRACK true
5039 #undef TARGET_SCHED_ISSUE_RATE
5040 #define TARGET_SCHED_ISSUE_RATE tilepro_issue_rate
5042 #undef TARGET_SCHED_ADJUST_COST
5043 #define TARGET_SCHED_ADJUST_COST tilepro_sched_adjust_cost
5045 #undef TARGET_MACHINE_DEPENDENT_REORG
5046 #define TARGET_MACHINE_DEPENDENT_REORG tilepro_reorg
5048 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5049 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5050 hook_bool_const_tree_hwi_hwi_const_tree_true
5052 #undef TARGET_ASM_OUTPUT_MI_THUNK
5053 #define TARGET_ASM_OUTPUT_MI_THUNK tilepro_asm_output_mi_thunk
5055 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5056 #define TARGET_ASM_TRAMPOLINE_TEMPLATE tilepro_asm_trampoline_template
5058 #undef TARGET_TRAMPOLINE_INIT
5059 #define TARGET_TRAMPOLINE_INIT tilepro_trampoline_init
5061 #undef TARGET_PRINT_OPERAND
5062 #define TARGET_PRINT_OPERAND tilepro_print_operand
5064 #undef TARGET_PRINT_OPERAND_ADDRESS
5065 #define TARGET_PRINT_OPERAND_ADDRESS tilepro_print_operand_address
5067 #undef TARGET_ASM_FILE_END
5068 #define TARGET_ASM_FILE_END tilepro_file_end
5071 struct gcc_target targetm = TARGET_INITIALIZER;
5073 #include "gt-tilepro.h"