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