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