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