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