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