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