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