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