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