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