]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/tilegx/tilegx.c
Factor unrelated declarations out of tree.h.
[thirdparty/gcc.git] / gcc / config / tilegx / tilegx.c
CommitLineData
dd552284 1/* Subroutines used for code generation on the Tilera TILE-Gx.
d1e082c2 2 Copyright (C) 2011-2013 Free Software Foundation, Inc.
dd552284
WL
3 Contributed by Walter Lee (walt@tilera.com)
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "rtl.h"
26#include "regs.h"
27#include "insn-config.h"
28#include "output.h"
29#include "insn-attr.h"
30#include "recog.h"
31#include "expr.h"
32#include "langhooks.h"
33#include "optabs.h"
34#include "sched-int.h"
35#include "tm_p.h"
36#include "tm-constrs.h"
37#include "target.h"
38#include "target-def.h"
6399c0ab 39#include "function.h"
dd552284
WL
40#include "dwarf2.h"
41#include "timevar.h"
1099e569 42#include "tree.h"
18f429e2 43#include "gimple.h"
d8a2d370
DN
44#include "stringpool.h"
45#include "stor-layout.h"
46#include "varasm.h"
47#include "calls.h"
45b0be94 48#include "gimplify.h"
dd552284
WL
49#include "cfgloop.h"
50#include "tilegx-builtins.h"
51#include "tilegx-multiply.h"
52#include "diagnostic.h"
53
54/* SYMBOL_REF for GOT */
55static GTY(()) rtx g_got_symbol = NULL;
56
57/* In case of a POST_INC or POST_DEC memory reference, we must report
58 the mode of the memory reference from TARGET_PRINT_OPERAND to
59 TARGET_PRINT_OPERAND_ADDRESS. */
60static enum machine_mode output_memory_reference_mode;
61
62/* Report whether we're printing out the first address fragment of a
63 POST_INC or POST_DEC memory reference, from TARGET_PRINT_OPERAND to
64 TARGET_PRINT_OPERAND_ADDRESS. */
65static bool output_memory_autoinc_first;
66
67\f
68
69/* Option handling */
70
71/* Implement TARGET_OPTION_OVERRIDE. */
72static void
73tilegx_option_override (void)
74{
1773cd77
WL
75 if (global_options_set.x_tilegx_cmodel)
76 {
77 switch (tilegx_cmodel)
78 {
79 case CM_SMALL:
80 case CM_SMALL_PIC:
81 if (flag_pic)
82 tilegx_cmodel = CM_SMALL_PIC;
83 break;
84
85 case CM_LARGE:
86 case CM_LARGE_PIC:
87 if (flag_pic)
88 tilegx_cmodel = CM_LARGE_PIC;
89 break;
90
91 default:
92 gcc_unreachable ();
93 }
94 }
95 else
96 tilegx_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
97
dd552284
WL
98 /* When modulo scheduling is enabled, we still rely on regular
99 scheduler for bundling. */
100 if (flag_modulo_sched)
101 flag_resched_modulo_sched = 1;
102}
103\f
104
105
106/* Implement TARGET_SCALAR_MODE_SUPPORTED_P. */
107static bool
108tilegx_scalar_mode_supported_p (enum machine_mode mode)
109{
110 switch (mode)
111 {
112 case QImode:
113 case HImode:
114 case SImode:
115 case DImode:
116 case TImode:
117 return true;
118
119 case SFmode:
120 case DFmode:
121 return true;
122
123 default:
124 return false;
125 }
126}
127
128
129/* Implement TARGET_VECTOR_MODE_SUPPORTED_P. */
130static bool
131tilegx_vector_mode_supported_p (enum machine_mode mode)
132{
133 return mode == V8QImode || mode == V4HImode || mode == V2SImode;
134}
135
136
137/* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
138static bool
139tilegx_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED,
140 rtx x ATTRIBUTE_UNUSED)
141{
142 return true;
143}
144
145
146/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
147static bool
148tilegx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
149{
1773cd77
WL
150 return (tilegx_cmodel != CM_LARGE && tilegx_cmodel != CM_LARGE_PIC
151 && (decl != NULL));
dd552284
WL
152}
153
154
155/* Implement TARGET_PASS_BY_REFERENCE. Variable sized types are
156 passed by reference. */
157static bool
158tilegx_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
159 enum machine_mode mode ATTRIBUTE_UNUSED,
160 const_tree type, bool named ATTRIBUTE_UNUSED)
161{
162 return (type && TYPE_SIZE (type)
163 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST);
164}
165
166
167/* Implement TARGET_RETURN_IN_MEMORY. */
168static bool
169tilegx_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
170{
171 return !IN_RANGE (int_size_in_bytes (type),
172 0, TILEGX_NUM_RETURN_REGS * UNITS_PER_WORD);
173}
174
175
3aa775d6 176/* Implement TARGET_MODE_REP_EXTENDED. */
dd552284
WL
177static int
178tilegx_mode_rep_extended (enum machine_mode mode, enum machine_mode mode_rep)
179{
180 /* SImode register values are sign-extended to DImode. */
181 if (mode == SImode && mode_rep == DImode)
182 return SIGN_EXTEND;
183
184 return UNKNOWN;
185}
186
187
188/* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
189static unsigned int
190tilegx_function_arg_boundary (enum machine_mode mode, const_tree type)
191{
192 unsigned int alignment;
193
194 alignment = type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode);
195 if (alignment < PARM_BOUNDARY)
196 alignment = PARM_BOUNDARY;
197 if (alignment > STACK_BOUNDARY)
198 alignment = STACK_BOUNDARY;
199 return alignment;
200}
201
202
203/* Implement TARGET_FUNCTION_ARG. */
204static rtx
205tilegx_function_arg (cumulative_args_t cum_v,
206 enum machine_mode mode,
207 const_tree type, bool named ATTRIBUTE_UNUSED)
208{
209 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
210 int byte_size = ((mode == BLKmode)
211 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
212
213 if (cum >= TILEGX_NUM_ARG_REGS)
214 return NULL_RTX;
215
216 /* The ABI does not allow parameters to be passed partially in reg
217 and partially in stack. */
218 if ((cum + (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
219 > TILEGX_NUM_ARG_REGS)
220 return NULL_RTX;
221
222 return gen_rtx_REG (mode, cum);
223}
224
225
226/* Implement TARGET_FUNCTION_ARG_ADVANCE. */
227static void
228tilegx_function_arg_advance (cumulative_args_t cum_v,
229 enum machine_mode mode,
230 const_tree type, bool named ATTRIBUTE_UNUSED)
231{
232 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
233
234 int byte_size = ((mode == BLKmode)
235 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
236 int word_size = (byte_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
237
238 /* If the current argument does not fit in the pretend_args space,
239 skip over it. */
240 if (*cum < TILEGX_NUM_ARG_REGS
241 && *cum + word_size > TILEGX_NUM_ARG_REGS)
242 *cum = TILEGX_NUM_ARG_REGS;
243
244 *cum += word_size;
245}
246
247
248/* Implement TARGET_FUNCTION_VALUE. */
249static rtx
250tilegx_function_value (const_tree valtype, const_tree fn_decl_or_type,
251 bool outgoing ATTRIBUTE_UNUSED)
252{
253 enum machine_mode mode;
254 int unsigned_p;
255
256 mode = TYPE_MODE (valtype);
257 unsigned_p = TYPE_UNSIGNED (valtype);
258
259 mode = promote_function_mode (valtype, mode, &unsigned_p,
260 fn_decl_or_type, 1);
261
262 return gen_rtx_REG (mode, 0);
263}
264
265
266/* Implement TARGET_LIBCALL_VALUE. */
267static rtx
268tilegx_libcall_value (enum machine_mode mode,
269 const_rtx fun ATTRIBUTE_UNUSED)
270{
271 return gen_rtx_REG (mode, 0);
272}
273
274
275/* Implement FUNCTION_VALUE_REGNO_P. */
276static bool
277tilegx_function_value_regno_p (const unsigned int regno)
278{
279 return regno < TILEGX_NUM_RETURN_REGS;
280}
281
282
283/* Implement TARGET_BUILD_BUILTIN_VA_LIST. */
284static tree
285tilegx_build_builtin_va_list (void)
286{
287 tree f_args, f_skip, record, type_decl;
288 bool owp;
289
290 record = lang_hooks.types.make_type (RECORD_TYPE);
291
292 type_decl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
293 get_identifier ("__va_list_tag"), record);
294
295 f_args = build_decl (BUILTINS_LOCATION, FIELD_DECL,
296 get_identifier ("__args"), ptr_type_node);
297 f_skip = build_decl (BUILTINS_LOCATION, FIELD_DECL,
298 get_identifier ("__skip"), ptr_type_node);
299
300 DECL_FIELD_CONTEXT (f_args) = record;
301
302 DECL_FIELD_CONTEXT (f_skip) = record;
303
304 TREE_CHAIN (record) = type_decl;
305 TYPE_NAME (record) = type_decl;
306 TYPE_FIELDS (record) = f_args;
307 TREE_CHAIN (f_args) = f_skip;
308
309 /* We know this is being padded and we want it too. It is an
310 internal type so hide the warnings from the user. */
311 owp = warn_padded;
312 warn_padded = false;
313
314 layout_type (record);
315
316 warn_padded = owp;
317
318 /* The correct type is an array type of one element. */
319 return record;
320}
321
322
323/* Implement TARGET_EXPAND_BUILTIN_VA_START. */
324static void
325tilegx_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
326{
327 tree f_args, f_skip;
328 tree args, skip, t;
329
330 f_args = TYPE_FIELDS (TREE_TYPE (valist));
331 f_skip = TREE_CHAIN (f_args);
332
333 args =
334 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
335 skip =
336 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
337
338 /* Find the __args area. */
339 t = make_tree (TREE_TYPE (args), virtual_incoming_args_rtx);
340 t = fold_build_pointer_plus_hwi (t,
341 UNITS_PER_WORD *
342 (crtl->args.info - TILEGX_NUM_ARG_REGS));
343
344 if (crtl->args.pretend_args_size > 0)
345 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
346
347 t = build2 (MODIFY_EXPR, TREE_TYPE (args), args, t);
348 TREE_SIDE_EFFECTS (t) = 1;
349 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
350
351 /* Find the __skip area. */
352 t = make_tree (TREE_TYPE (skip), virtual_incoming_args_rtx);
353 t = fold_build_pointer_plus_hwi (t, -STACK_POINTER_OFFSET);
354 t = build2 (MODIFY_EXPR, TREE_TYPE (skip), skip, t);
355 TREE_SIDE_EFFECTS (t) = 1;
356 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
357}
358
359
360/* Implement TARGET_SETUP_INCOMING_VARARGS. */
361static void
362tilegx_setup_incoming_varargs (cumulative_args_t cum,
363 enum machine_mode mode,
364 tree type, int *pretend_args, int no_rtl)
365{
366 CUMULATIVE_ARGS local_cum = *get_cumulative_args (cum);
367 int first_reg;
368
369 /* The caller has advanced CUM up to, but not beyond, the last named
370 argument. Advance a local copy of CUM past the last "real" named
371 argument, to find out how many registers are left over. */
372 targetm.calls.function_arg_advance (pack_cumulative_args (&local_cum),
373 mode, type, true);
374 first_reg = local_cum;
375
376 if (local_cum < TILEGX_NUM_ARG_REGS)
377 {
378 *pretend_args = UNITS_PER_WORD * (TILEGX_NUM_ARG_REGS - first_reg);
379
380 if (!no_rtl)
381 {
382 alias_set_type set = get_varargs_alias_set ();
383 rtx tmp =
0a81f074
RS
384 gen_rtx_MEM (BLKmode, plus_constant (Pmode,
385 virtual_incoming_args_rtx,
dd552284
WL
386 -STACK_POINTER_OFFSET -
387 UNITS_PER_WORD *
388 (TILEGX_NUM_ARG_REGS -
389 first_reg)));
390 MEM_NOTRAP_P (tmp) = 1;
391 set_mem_alias_set (tmp, set);
392 move_block_from_reg (first_reg, tmp,
393 TILEGX_NUM_ARG_REGS - first_reg);
394 }
395 }
396 else
397 *pretend_args = 0;
398}
399
400
401/* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. Gimplify va_arg by updating
402 the va_list structure VALIST as required to retrieve an argument of
403 type TYPE, and returning that argument.
404
405 ret = va_arg(VALIST, TYPE);
406
407 generates code equivalent to:
408
409 paddedsize = (sizeof(TYPE) + 3) & -4;
410 if ( (VALIST.__args + paddedsize > VALIST.__skip)
411 & (VALIST.__args <= VALIST.__skip))
412 addr = VALIST.__skip + STACK_POINTER_OFFSET;
413 else
414 addr = VALIST.__args;
415 VALIST.__args = addr + paddedsize;
416 ret = *(TYPE *)addr;
417 */
418static tree
419tilegx_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
420 gimple_seq *post_p ATTRIBUTE_UNUSED)
421{
422 tree f_args, f_skip;
423 tree args, skip;
424 HOST_WIDE_INT size, rsize;
425 tree addr, tmp;
426 bool pass_by_reference_p;
427
428 f_args = TYPE_FIELDS (va_list_type_node);
429 f_skip = TREE_CHAIN (f_args);
430
431 args =
432 build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
433 skip =
434 build3 (COMPONENT_REF, TREE_TYPE (f_skip), valist, f_skip, NULL_TREE);
435
436 addr = create_tmp_var (ptr_type_node, "va_arg");
437
3aa775d6 438 /* If an object is dynamically sized, a pointer to it is passed
dd552284
WL
439 instead of the object itself. */
440 pass_by_reference_p = pass_by_reference (NULL, TYPE_MODE (type), type,
441 false);
442
443 if (pass_by_reference_p)
444 type = build_pointer_type (type);
445
446 size = int_size_in_bytes (type);
447 rsize = ((size + UNITS_PER_WORD - 1) / UNITS_PER_WORD) * UNITS_PER_WORD;
448
449 /* Assert alignment assumption. */
450 gcc_assert (STACK_BOUNDARY == PARM_BOUNDARY);
451
452 /* Build conditional expression to calculate addr. The expression
453 will be gimplified later. */
454 tmp = fold_build_pointer_plus_hwi (unshare_expr (args), rsize);
455 tmp = build2 (TRUTH_AND_EXPR, boolean_type_node,
456 build2 (GT_EXPR, boolean_type_node, tmp, unshare_expr (skip)),
457 build2 (LE_EXPR, boolean_type_node, unshare_expr (args),
458 unshare_expr (skip)));
459
460 tmp = build3 (COND_EXPR, ptr_type_node, tmp,
461 build2 (POINTER_PLUS_EXPR, ptr_type_node, unshare_expr (skip),
462 size_int (STACK_POINTER_OFFSET)),
463 unshare_expr (args));
464
465 gimplify_assign (addr, tmp, pre_p);
466
467 /* Update VALIST.__args. */
468 tmp = fold_build_pointer_plus_hwi (addr, rsize);
469 gimplify_assign (unshare_expr (args), tmp, pre_p);
470
471 addr = fold_convert (build_pointer_type (type), addr);
472
473 if (pass_by_reference_p)
474 addr = build_va_arg_indirect_ref (addr);
475
476 return build_va_arg_indirect_ref (addr);
477}
478\f
479
480
481/* Implement TARGET_RTX_COSTS. */
482static bool
483tilegx_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
484 bool speed)
485{
486 switch (code)
487 {
488 case CONST_INT:
489 /* If this is an 8-bit constant, return zero since it can be
3aa775d6
WL
490 used nearly anywhere with no cost. If it is a valid operand
491 for an ADD or AND, likewise return 0 if we know it will be
492 used in that context. Otherwise, return 2 since it might be
493 used there later. All other constants take at least two
494 insns. */
dd552284
WL
495 if (satisfies_constraint_I (x))
496 {
497 *total = 0;
498 return true;
499 }
500 else if (outer_code == PLUS && add_operand (x, VOIDmode))
501 {
502 /* Slightly penalize large constants even though we can add
503 them in one instruction, because it forces the use of
504 2-wide bundling mode. */
505 *total = 1;
506 return true;
507 }
508 else if (move_operand (x, SImode))
509 {
510 /* We can materialize in one move. */
511 *total = COSTS_N_INSNS (1);
512 return true;
513 }
514 else
515 {
516 /* We can materialize in two moves. */
517 *total = COSTS_N_INSNS (2);
518 return true;
519 }
520
521 return false;
522
523 case CONST:
524 case LABEL_REF:
525 case SYMBOL_REF:
526 *total = COSTS_N_INSNS (2);
527 return true;
528
529 case CONST_DOUBLE:
530 *total = COSTS_N_INSNS (4);
531 return true;
532
533 case HIGH:
534 *total = 0;
535 return true;
536
537 case MEM:
538 /* If outer-code was a sign or zero extension, a cost of
3aa775d6
WL
539 COSTS_N_INSNS (1) was already added in, so account for
540 that. */
dd552284
WL
541 if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND)
542 *total = COSTS_N_INSNS (1);
543 else
544 *total = COSTS_N_INSNS (2);
545 return true;
546
547 case PLUS:
548 /* Convey that shl[123]add are efficient. */
549 if (GET_CODE (XEXP (x, 0)) == MULT
550 && cint_248_operand (XEXP (XEXP (x, 0), 1), VOIDmode))
551 {
552 *total = (rtx_cost (XEXP (XEXP (x, 0), 0),
553 (enum rtx_code) outer_code, opno, speed)
554 + rtx_cost (XEXP (x, 1),
555 (enum rtx_code) outer_code, opno, speed)
556 + COSTS_N_INSNS (1));
557 return true;
558 }
559 return false;
560
561 case MULT:
562 *total = COSTS_N_INSNS (2);
563 return false;
564
565 case DIV:
566 case UDIV:
567 case MOD:
568 case UMOD:
569 /* These are handled by software and are very expensive. */
570 *total = COSTS_N_INSNS (100);
571 return false;
572
573 case UNSPEC:
574 case UNSPEC_VOLATILE:
575 {
576 int num = XINT (x, 1);
577
578 if (num <= TILEGX_LAST_LATENCY_1_INSN)
579 *total = COSTS_N_INSNS (1);
580 else if (num <= TILEGX_LAST_LATENCY_2_INSN)
581 *total = COSTS_N_INSNS (2);
582 else if (num > TILEGX_LAST_LATENCY_INSN)
583 {
584 if (num == UNSPEC_NON_TEMPORAL)
585 {
586 /* These are basically loads. */
587 if (outer_code == ZERO_EXTEND || outer_code == SIGN_EXTEND)
588 *total = COSTS_N_INSNS (1);
589 else
590 *total = COSTS_N_INSNS (2);
591 }
592 else
593 {
594 if (outer_code == PLUS)
595 *total = 0;
596 else
597 *total = COSTS_N_INSNS (1);
598 }
599 }
600 else
601 {
602 switch (num)
603 {
604 case UNSPEC_BLOCKAGE:
605 case UNSPEC_NETWORK_BARRIER:
606 case UNSPEC_ATOMIC:
607 *total = 0;
608 break;
609
610 case UNSPEC_LNK_AND_LABEL:
611 case UNSPEC_MF:
612 case UNSPEC_MOV_PCREL_STEP3:
613 case UNSPEC_NETWORK_RECEIVE:
614 case UNSPEC_NETWORK_SEND:
615 case UNSPEC_SPR_MOVE:
616 case UNSPEC_TLS_GD_ADD:
617 *total = COSTS_N_INSNS (1);
618 break;
619
620 case UNSPEC_TLS_IE_LOAD:
621 case UNSPEC_XCHG:
622 *total = COSTS_N_INSNS (2);
623 break;
624
625 case UNSPEC_SP_SET:
626 *total = COSTS_N_INSNS (3);
627 break;
628
629 case UNSPEC_SP_TEST:
630 *total = COSTS_N_INSNS (4);
631 break;
632
633 case UNSPEC_CMPXCHG:
634 case UNSPEC_INSN_CMPEXCH:
635 case UNSPEC_LATENCY_L2:
636 *total = COSTS_N_INSNS (11);
637 break;
638
639 case UNSPEC_TLS_GD_CALL:
640 *total = COSTS_N_INSNS (30);
641 break;
642
643 case UNSPEC_LATENCY_MISS:
644 *total = COSTS_N_INSNS (80);
645 break;
646
647 default:
648 *total = COSTS_N_INSNS (1);
649 }
650 }
651 return true;
652 }
653
654 default:
655 return false;
656 }
657}
658\f
659
660
661/* Rtl lowering. */
662
663/* Create a temporary variable to hold a partial result, to enable
664 CSE. */
665static rtx
666create_temp_reg_if_possible (enum machine_mode mode, rtx default_reg)
667{
3aa775d6 668 return can_create_pseudo_p () ? gen_reg_rtx (mode) : default_reg;
dd552284
WL
669}
670
671
672/* Functions to save and restore machine-specific function data. */
673static struct machine_function *
674tilegx_init_machine_status (void)
675{
676 return ggc_alloc_cleared_machine_function ();
677}
678
679
680/* Do anything needed before RTL is emitted for each function. */
681void
682tilegx_init_expanders (void)
683{
684 /* Arrange to initialize and mark the machine per-function
685 status. */
686 init_machine_status = tilegx_init_machine_status;
687
688 if (cfun && cfun->machine && flag_pic)
689 {
690 static int label_num = 0;
691
692 char text_label_name[32];
693
694 struct machine_function *machine = cfun->machine;
695
696 ASM_GENERATE_INTERNAL_LABEL (text_label_name, "L_PICLNK", label_num++);
697
698 machine->text_label_symbol =
699 gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (text_label_name));
700
701 machine->text_label_rtx =
702 gen_rtx_REG (Pmode, TILEGX_PIC_TEXT_LABEL_REGNUM);
703
704 machine->got_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
705
706 machine->calls_tls_get_addr = false;
707 }
708}
709
710
711/* Implement TARGET_SHIFT_TRUNCATION_MASK. DImode shifts use the mode
712 matching insns and therefore guarantee that the shift count is
713 modulo 64. SImode shifts sometimes use the 64 bit version so do
714 not hold such guarantee. */
715static unsigned HOST_WIDE_INT
716tilegx_shift_truncation_mask (enum machine_mode mode)
717{
718 return mode == DImode ? 63 : 0;
719}
720
721
722/* Implement TARGET_INIT_LIBFUNCS. */
723static void
724tilegx_init_libfuncs (void)
725{
726 /* We need to explicitly generate these libfunc's to support
727 conversion of divide by constant to multiply (the divide stubs in
728 tilegx.md exist also for this reason). Normally we'd expect gcc
729 to lazily generate them when they are needed, but for some reason
730 it's set up to only generate them if the mode is the word
731 mode. */
732 set_optab_libfunc (sdiv_optab, SImode, "__divsi3");
733 set_optab_libfunc (udiv_optab, SImode, "__udivsi3");
734 set_optab_libfunc (smod_optab, SImode, "__modsi3");
735 set_optab_libfunc (umod_optab, SImode, "__umodsi3");
736}
737
738
739/* Return true if X contains a thread-local symbol. */
740static bool
741tilegx_tls_referenced_p (rtx x)
742{
743 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
744 x = XEXP (XEXP (x, 0), 0);
745
746 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
747 return true;
748
749 /* That's all we handle in tilegx_legitimize_tls_address for
750 now. */
751 return false;
752}
753
754
755/* Return true if X requires a scratch register. It is given that
756 flag_pic is on and that X satisfies CONSTANT_P. */
757static int
758tilegx_pic_address_needs_scratch (rtx x)
759{
760 if (GET_CODE (x) == CONST
761 && GET_CODE (XEXP (x, 0)) == PLUS
762 && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
763 || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
764 && (CONST_INT_P (XEXP (XEXP (x, 0), 1))))
765 return true;
766
767 return false;
768}
769
770
771/* Implement TARGET_LEGITIMATE_CONSTANT_P. This is all constants for
772 which we are willing to load the value into a register via a move
773 pattern. TLS cannot be treated as a constant because it can
774 include a function call. */
775static bool
776tilegx_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
777{
778 switch (GET_CODE (x))
779 {
780 case CONST:
781 case SYMBOL_REF:
782 return !tilegx_tls_referenced_p (x);
783
784 default:
785 return true;
786 }
787}
788
789
790/* Return true if the constant value X is a legitimate general operand
791 when generating PIC code. It is given that flag_pic is on and that
792 X satisfies CONSTANT_P. */
793bool
794tilegx_legitimate_pic_operand_p (rtx x)
795{
796 if (tilegx_pic_address_needs_scratch (x))
797 return false;
798
799 if (tilegx_tls_referenced_p (x))
800 return false;
801
802 return true;
803}
804
805
806/* Return true if the rtx X can be used as an address operand. */
807static bool
808tilegx_legitimate_address_p (enum machine_mode ARG_UNUSED (mode), rtx x,
809 bool strict)
810{
811 if (GET_CODE (x) == SUBREG)
812 x = SUBREG_REG (x);
813
814 switch (GET_CODE (x))
815 {
816 case POST_INC:
817 case POST_DEC:
818 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
819 return false;
820
821 x = XEXP (x, 0);
822 break;
823
824 case POST_MODIFY:
825 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
826 return false;
827
828 if (GET_CODE (XEXP (x, 1)) != PLUS)
829 return false;
830
831 if (!rtx_equal_p (XEXP (x, 0), XEXP (XEXP (x, 1), 0)))
832 return false;
833
834 if (!satisfies_constraint_I (XEXP (XEXP (x, 1), 1)))
835 return false;
836
837 x = XEXP (x, 0);
838 break;
839
840 case REG:
841 break;
842
843 default:
844 return false;
845 }
846
847 /* Check if x is a valid reg. */
848 if (!REG_P (x))
849 return false;
850
851 if (strict)
852 return REGNO_OK_FOR_BASE_P (REGNO (x));
853 else
854 return true;
855}
856
857
858/* Return the rtx containing SYMBOL_REF to the text label. */
859static rtx
860tilegx_text_label_symbol (void)
861{
862 return cfun->machine->text_label_symbol;
863}
864
865
866/* Return the register storing the value of the text label. */
867static rtx
868tilegx_text_label_rtx (void)
869{
870 return cfun->machine->text_label_rtx;
871}
872
873
874/* Return the register storing the value of the global offset
875 table. */
876static rtx
877tilegx_got_rtx (void)
878{
879 return cfun->machine->got_rtx;
880}
881
882
883/* Return the SYMBOL_REF for _GLOBAL_OFFSET_TABLE_. */
884static rtx
885tilegx_got_symbol (void)
886{
887 if (g_got_symbol == NULL)
888 g_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
889
890 return g_got_symbol;
891}
892
893
894/* Return a reference to the got to be used by tls references. */
895static rtx
896tilegx_tls_got (void)
897{
898 rtx temp;
899 if (flag_pic)
900 {
901 crtl->uses_pic_offset_table = 1;
902 return tilegx_got_rtx ();
903 }
904
905 temp = gen_reg_rtx (Pmode);
906 emit_move_insn (temp, tilegx_got_symbol ());
907
908 return temp;
909}
910
911
912/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
913 this (thread-local) address. */
914static rtx
915tilegx_legitimize_tls_address (rtx addr)
916{
917 rtx ret;
918
919 gcc_assert (can_create_pseudo_p ());
920
921 if (GET_CODE (addr) == SYMBOL_REF)
922 switch (SYMBOL_REF_TLS_MODEL (addr))
923 {
924 case TLS_MODEL_GLOBAL_DYNAMIC:
925 case TLS_MODEL_LOCAL_DYNAMIC:
926 {
927 rtx r0, temp, temp2, temp3, got, last;
928
929 ret = gen_reg_rtx (Pmode);
930 r0 = gen_rtx_REG (Pmode, 0);
931 temp = gen_reg_rtx (Pmode);
932 temp2 = gen_reg_rtx (Pmode);
933 temp3 = gen_reg_rtx (Pmode);
934
935 got = tilegx_tls_got ();
936 if (TARGET_32BIT)
937 {
938 emit_insn (gen_mov_tls_gd_step1_32bit (temp, addr));
939 emit_insn (gen_mov_tls_gd_step2_32bit (temp2, temp, addr));
940 emit_insn (gen_tls_add_32bit (temp2, got, temp2, addr));
941 }
942 else
943 {
944 emit_insn (gen_mov_tls_gd_step1 (temp, addr));
945 emit_insn (gen_mov_tls_gd_step2 (temp2, temp, addr));
946 emit_insn (gen_tls_add (temp2, got, temp2, addr));
947 }
948
949 emit_move_insn (r0, temp2);
950
951 if (TARGET_32BIT)
952 {
953 emit_insn (gen_tls_gd_call_32bit (addr));
954 }
955 else
956 {
957 emit_insn (gen_tls_gd_call (addr));
958 }
959
960 emit_move_insn (temp3, r0);
961
962 if (TARGET_32BIT)
963 last = emit_insn (gen_tls_gd_add_32bit (ret, temp3, addr));
964 else
965 last = emit_insn (gen_tls_gd_add (ret, temp3, addr));
966
967 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
968 break;
969 }
970 case TLS_MODEL_INITIAL_EXEC:
971 {
972 rtx temp, temp2, temp3, got, last;
973
974 ret = gen_reg_rtx (Pmode);
975 temp = gen_reg_rtx (Pmode);
976 temp2 = gen_reg_rtx (Pmode);
977 temp3 = gen_reg_rtx (Pmode);
978
979 got = tilegx_tls_got ();
980 if (TARGET_32BIT)
981 {
982 emit_insn (gen_mov_tls_ie_step1_32bit (temp, addr));
983 emit_insn (gen_mov_tls_ie_step2_32bit (temp2, temp, addr));
984 emit_insn (gen_tls_add_32bit (temp2, got, temp2, addr));
985 emit_insn (gen_tls_ie_load_32bit (temp3, temp2, addr));
986 }
987 else
988 {
989 emit_insn (gen_mov_tls_ie_step1 (temp, addr));
990 emit_insn (gen_mov_tls_ie_step2 (temp2, temp, addr));
991 emit_insn (gen_tls_add (temp2, got, temp2, addr));
992 emit_insn (gen_tls_ie_load (temp3, temp2, addr));
993 }
994
995 last =
996 emit_move_insn(ret,
997 gen_rtx_PLUS (Pmode,
998 gen_rtx_REG (Pmode,
999 THREAD_POINTER_REGNUM),
1000 temp3));
1001 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
1002 break;
1003 }
1004 case TLS_MODEL_LOCAL_EXEC:
1005 {
1006 rtx temp, temp2, last;
1007
1008 ret = gen_reg_rtx (Pmode);
1009 temp = gen_reg_rtx (Pmode);
1010 temp2 = gen_reg_rtx (Pmode);
1011
1012 if (TARGET_32BIT)
1013 {
1014 emit_insn (gen_mov_tls_le_step1_32bit (temp, addr));
1015 emit_insn (gen_mov_tls_le_step2_32bit (temp2, temp, addr));
1016 }
1017 else
1018 {
1019 emit_insn (gen_mov_tls_le_step1 (temp, addr));
1020 emit_insn (gen_mov_tls_le_step2 (temp2, temp, addr));
1021 }
1022
1023 last =
1024 emit_move_insn (ret,
1025 gen_rtx_PLUS (Pmode,
1026 gen_rtx_REG (Pmode,
1027 THREAD_POINTER_REGNUM),
1028 temp2));
1029 set_unique_reg_note (last, REG_EQUAL, copy_rtx (addr));
1030 break;
1031 }
1032 default:
1033 gcc_unreachable ();
1034 }
1035 else if (GET_CODE (addr) == CONST)
1036 {
1037 rtx base, offset;
1038
1039 gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
1040
1041 base = tilegx_legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
1042 offset = XEXP (XEXP (addr, 0), 1);
1043
1044 base = force_operand (base, NULL_RTX);
1045 ret = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
1046 }
1047 else
1048 gcc_unreachable ();
1049
1050 return ret;
1051}
1052
1053
1054/* Returns a register that points to ADDR, a symbolic address, by
1055 computing its address relative to tilegx_text_label_symbol. */
1773cd77
WL
1056void
1057tilegx_compute_pcrel_address (rtx result, rtx addr)
dd552284
WL
1058{
1059 rtx text_label_symbol = tilegx_text_label_symbol ();
1060 rtx text_label_rtx = tilegx_text_label_rtx ();
1773cd77 1061 rtx temp, temp2, temp3;
dd552284
WL
1062
1063 temp = create_temp_reg_if_possible (Pmode, result);
1064 temp2 = create_temp_reg_if_possible (Pmode, result);
1065
1066 if (TARGET_32BIT)
1067 {
1068 emit_insn (gen_mov_pcrel_step1_32bit (temp, addr, text_label_symbol));
1069 emit_insn (gen_mov_pcrel_step2_32bit (temp2, temp, addr,
1070 text_label_symbol));
1071 emit_insn (gen_mov_pcrel_step3_32bit (result, temp2,
1072 text_label_rtx,
1073 addr, text_label_symbol));
1074 }
1773cd77
WL
1075 else if (tilegx_cmodel == CM_LARGE_PIC)
1076 {
1077 temp3 = create_temp_reg_if_possible (Pmode, result);
1078 emit_insn (gen_mov_large_pcrel_step1 (temp, addr, text_label_symbol));
1079 emit_insn (gen_mov_large_pcrel_step2 (temp2, temp, addr,
1080 text_label_symbol));
1081 emit_insn (gen_mov_large_pcrel_step3 (temp3, temp2, addr,
1082 text_label_symbol));
1083 emit_insn (gen_mov_large_pcrel_step4 (result, temp3,
1084 text_label_rtx,
1085 addr, text_label_symbol));
1086 }
dd552284
WL
1087 else
1088 {
1089 emit_insn (gen_mov_pcrel_step1 (temp, addr, text_label_symbol));
1090 emit_insn (gen_mov_pcrel_step2 (temp2, temp, addr, text_label_symbol));
1091 emit_insn (gen_mov_pcrel_step3 (result, temp2,
1092 text_label_rtx,
1093 addr, text_label_symbol));
1094 }
1095}
1096
1097
1773cd77
WL
1098/* Returns a register that points to the plt entry of ADDR, a symbolic
1099 address, by computing its address relative to
3aa775d6 1100 tilegx_text_label_symbol. */
1773cd77
WL
1101void
1102tilegx_compute_pcrel_plt_address (rtx result, rtx addr)
1103{
1104 rtx text_label_symbol = tilegx_text_label_symbol ();
1105 rtx text_label_rtx = tilegx_text_label_rtx ();
1106 rtx temp, temp2, temp3;
1107
1108 temp = create_temp_reg_if_possible (Pmode, result);
1109 temp2 = create_temp_reg_if_possible (Pmode, result);
1110
1111 if (TARGET_32BIT)
1112 {
1113 emit_insn (gen_mov_plt_pcrel_step1_32bit (temp, addr,
1114 text_label_symbol));
1115 emit_insn (gen_mov_plt_pcrel_step2_32bit (temp2, temp, addr,
1116 text_label_symbol));
1117 emit_move_insn (result, gen_rtx_PLUS (Pmode, temp2, text_label_rtx));
1118 }
1119 else
1120 {
1121 temp3 = create_temp_reg_if_possible (Pmode, result);
1122
1123 emit_insn (gen_mov_plt_pcrel_step1 (temp, addr, text_label_symbol));
1124 emit_insn (gen_mov_plt_pcrel_step2 (temp2, temp, addr,
1125 text_label_symbol));
1126 emit_insn (gen_mov_plt_pcrel_step3 (temp3, temp2, addr,
1127 text_label_symbol));
1128 emit_move_insn (result, gen_rtx_PLUS (Pmode, temp3, text_label_rtx));
1129 }
1130}
1131
1132
dd552284
WL
1133/* Legitimize PIC addresses. If the address is already
1134 position-independent, we return ORIG. Newly generated
1135 position-independent addresses go into a reg. This is REG if
1136 nonzero, otherwise we allocate register(s) as necessary. */
1137static rtx
1138tilegx_legitimize_pic_address (rtx orig,
1139 enum machine_mode mode ATTRIBUTE_UNUSED,
1140 rtx reg)
1141{
1142 if (GET_CODE (orig) == SYMBOL_REF)
1143 {
1144 rtx address, pic_ref;
1145
1146 if (reg == 0)
1147 {
1148 gcc_assert (can_create_pseudo_p ());
1149 reg = gen_reg_rtx (Pmode);
1150 }
1151
1152 if (SYMBOL_REF_LOCAL_P (orig))
1153 {
1154 /* If not during reload, allocate another temp reg here for
1155 loading in the address, so that these instructions can be
1156 optimized properly. */
1157 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
1773cd77 1158 tilegx_compute_pcrel_address (temp_reg, orig);
dd552284
WL
1159
1160 /* Note: this is conservative. We use the text_label but we
1161 don't use the pic_offset_table. However, in some cases
1162 we may need the pic_offset_table (see
1163 tilegx_fixup_pcrel_references). */
1164 crtl->uses_pic_offset_table = 1;
1165
1166 address = temp_reg;
1167
1168 emit_move_insn (reg, address);
1169 return reg;
1170 }
1171 else
1172 {
1173 /* If not during reload, allocate another temp reg here for
1174 loading in the address, so that these instructions can be
1175 optimized properly. */
1176 rtx temp_reg = create_temp_reg_if_possible (Pmode, reg);
1177
1178 gcc_assert (flag_pic);
1179 if (flag_pic == 1)
1180 {
1181 if (TARGET_32BIT)
1182 {
1183 emit_insn (gen_add_got16_32bit (temp_reg,
1184 tilegx_got_rtx (),
1185 orig));
1186 }
1187 else
1188 {
1189 emit_insn (gen_add_got16 (temp_reg,
1190 tilegx_got_rtx (), orig));
1191 }
1192 }
1193 else
1194 {
1195 rtx temp_reg2 = create_temp_reg_if_possible (Pmode, reg);
1196 rtx temp_reg3 = create_temp_reg_if_possible (Pmode, reg);
1197 if (TARGET_32BIT)
1198 {
1199 emit_insn (gen_mov_got32_step1_32bit (temp_reg3, orig));
1200 emit_insn (gen_mov_got32_step2_32bit
1201 (temp_reg2, temp_reg3, orig));
1202 }
1203 else
1204 {
1205 emit_insn (gen_mov_got32_step1 (temp_reg3, orig));
1206 emit_insn (gen_mov_got32_step2 (temp_reg2, temp_reg3,
1207 orig));
1208 }
1209 emit_move_insn (temp_reg,
1210 gen_rtx_PLUS (Pmode,
1211 tilegx_got_rtx (), temp_reg2));
1212 }
1213
1214 address = temp_reg;
1215
1216 pic_ref = gen_const_mem (Pmode, address);
1217 crtl->uses_pic_offset_table = 1;
1218 emit_move_insn (reg, pic_ref);
1219 /* The following put a REG_EQUAL note on this insn, so that
1220 it can be optimized by loop. But it causes the label to
1221 be optimized away. */
1222 /* set_unique_reg_note (insn, REG_EQUAL, orig); */
1223 return reg;
1224 }
1225 }
1226 else if (GET_CODE (orig) == CONST)
1227 {
1228 rtx base, offset;
1229
1230 if (GET_CODE (XEXP (orig, 0)) == PLUS
1231 && XEXP (XEXP (orig, 0), 0) == tilegx_got_rtx ())
1232 return orig;
1233
1234 if (reg == 0)
1235 {
1236 gcc_assert (can_create_pseudo_p ());
1237 reg = gen_reg_rtx (Pmode);
1238 }
1239
1240 gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
1241 base = tilegx_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
1242 Pmode, reg);
1243 offset = tilegx_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
1244 base == reg ? 0 : reg);
1245
1246 if (CONST_INT_P (offset))
1247 {
1248 if (can_create_pseudo_p ())
1249 offset = force_reg (Pmode, offset);
1250 else
1251 /* If we reach here, then something is seriously wrong. */
1252 gcc_unreachable ();
1253 }
1254
1255 if (can_create_pseudo_p ())
1256 return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, offset));
1257 else
1258 gcc_unreachable ();
1259 }
1260 else if (GET_CODE (orig) == LABEL_REF)
1261 {
1262 rtx address;
1263 rtx temp_reg;
1264
1265 if (reg == 0)
1266 {
1267 gcc_assert (can_create_pseudo_p ());
1268 reg = gen_reg_rtx (Pmode);
1269 }
1270
1271 /* If not during reload, allocate another temp reg here for
3aa775d6
WL
1272 loading in the address, so that these instructions can be
1273 optimized properly. */
dd552284 1274 temp_reg = create_temp_reg_if_possible (Pmode, reg);
1773cd77 1275 tilegx_compute_pcrel_address (temp_reg, orig);
dd552284
WL
1276
1277 /* Note: this is conservative. We use the text_label but we
3aa775d6 1278 don't use the pic_offset_table. */
dd552284
WL
1279 crtl->uses_pic_offset_table = 1;
1280
1281 address = temp_reg;
1282
1283 emit_move_insn (reg, address);
1284
1285 return reg;
1286 }
1287
1288 return orig;
1289}
1290
1291
1292/* Implement TARGET_LEGITIMIZE_ADDRESS. */
1293static rtx
1294tilegx_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
1295 enum machine_mode mode)
1296{
1297 if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
1298 && symbolic_operand (x, Pmode) && tilegx_tls_referenced_p (x))
1299 {
1300 return tilegx_legitimize_tls_address (x);
1301 }
1302 else if (flag_pic)
1303 {
1304 return tilegx_legitimize_pic_address (x, mode, 0);
1305 }
1306 else
1307 return x;
1308}
1309
1310
1311/* Implement TARGET_DELEGITIMIZE_ADDRESS. */
1312static rtx
1313tilegx_delegitimize_address (rtx x)
1314{
1315 x = delegitimize_mem_from_attrs (x);
1316
1317 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC)
1318 {
1319 switch (XINT (XEXP (x, 0), 1))
1320 {
1321 case UNSPEC_HW0:
1322 case UNSPEC_HW1:
1323 case UNSPEC_HW2:
1324 case UNSPEC_HW3:
1325 case UNSPEC_HW0_LAST:
1326 case UNSPEC_HW1_LAST:
1327 case UNSPEC_HW2_LAST:
1328 case UNSPEC_HW0_PCREL:
1773cd77 1329 case UNSPEC_HW1_PCREL:
dd552284 1330 case UNSPEC_HW1_LAST_PCREL:
1773cd77
WL
1331 case UNSPEC_HW2_LAST_PCREL:
1332 case UNSPEC_HW0_PLT_PCREL:
1333 case UNSPEC_HW1_PLT_PCREL:
1334 case UNSPEC_HW1_LAST_PLT_PCREL:
1335 case UNSPEC_HW2_LAST_PLT_PCREL:
dd552284
WL
1336 case UNSPEC_HW0_GOT:
1337 case UNSPEC_HW0_LAST_GOT:
1338 case UNSPEC_HW1_LAST_GOT:
1339 case UNSPEC_HW0_TLS_GD:
1340 case UNSPEC_HW1_LAST_TLS_GD:
1341 case UNSPEC_HW0_TLS_IE:
1342 case UNSPEC_HW1_LAST_TLS_IE:
1343 case UNSPEC_HW0_TLS_LE:
1344 case UNSPEC_HW1_LAST_TLS_LE:
1345 x = XVECEXP (XEXP (x, 0), 0, 0);
1346 break;
1347 }
1348 }
1349
1350 return x;
1351}
1352
1353
1354/* Emit code to load the PIC register. */
1355static void
1356load_pic_register (bool delay_pic_helper ATTRIBUTE_UNUSED)
1357{
1358 int orig_flag_pic = flag_pic;
1359
1360 rtx got_symbol = tilegx_got_symbol ();
1361 rtx text_label_symbol = tilegx_text_label_symbol ();
1362 rtx text_label_rtx = tilegx_text_label_rtx ();
1363 flag_pic = 0;
1364
1365 if (TARGET_32BIT)
1366 {
1367 emit_insn (gen_insn_lnk_and_label_32bit (text_label_rtx,
1368 text_label_symbol));
1369 }
1370 else
1371 {
1372 emit_insn (gen_insn_lnk_and_label (text_label_rtx, text_label_symbol));
1373 }
1374
1773cd77 1375 tilegx_compute_pcrel_address (tilegx_got_rtx (), got_symbol);
dd552284
WL
1376
1377 flag_pic = orig_flag_pic;
1378
1379 /* Need to emit this whether or not we obey regdecls, since
1380 setjmp/longjmp can cause life info to screw up. ??? In the case
1381 where we don't obey regdecls, this is not sufficient since we may
1382 not fall out the bottom. */
1383 emit_use (tilegx_got_rtx ());
1384}
1385
1386
1387/* Return the simd variant of the constant NUM of mode MODE, by
1388 replicating it to fill an interger of mode DImode. NUM is first
1389 truncated to fit in MODE. */
1390rtx
1391tilegx_simd_int (rtx num, enum machine_mode mode)
1392{
1393 HOST_WIDE_INT n = 0;
1394
1395 gcc_assert (CONST_INT_P (num));
1396
1397 n = INTVAL (num);
1398
1399 switch (mode)
1400 {
1401 case QImode:
1402 n = 0x0101010101010101LL * (n & 0x000000FF);
1403 break;
1404 case HImode:
1405 n = 0x0001000100010001LL * (n & 0x0000FFFF);
1406 break;
1407 case SImode:
1408 n = 0x0000000100000001LL * (n & 0xFFFFFFFF);
1409 break;
1410 case DImode:
1411 break;
1412 default:
1413 gcc_unreachable ();
1414 }
1415
1416 return GEN_INT (n);
1417}
1418
1419
1420/* Returns true iff VAL can be moved into a register in one
3aa775d6
WL
1421 instruction. And if it can, it emits the code to move the constant
1422 into DEST_REG.
dd552284
WL
1423
1424 If THREE_WIDE_ONLY is true, this insists on an instruction that
1425 works in a bundle containing three instructions. */
1426static bool
1427expand_set_cint64_one_inst (rtx dest_reg,
1428 HOST_WIDE_INT val, bool three_wide_only)
1429{
1430 if (val == trunc_int_for_mode (val, QImode))
1431 {
1432 /* Success! */
1433 emit_move_insn (dest_reg, GEN_INT (val));
1434 return true;
1435 }
1436 else if (!three_wide_only)
1437 {
5b2a3c82
WL
1438 /* Test for the following constraints: J, K, N, P. We avoid
1439 generating an rtx and using existing predicates because we
1440 can be testing and rejecting a lot of constants, and GEN_INT
1441 is O(N). */
1442 if ((val >= -32768 && val <= 65535)
1443 || ((val == (val & 0xFF) * 0x0101010101010101LL))
1444 || (val == ((trunc_int_for_mode (val, QImode) & 0xFFFF)
1445 * 0x0001000100010001LL)))
dd552284 1446 {
5b2a3c82 1447 emit_move_insn (dest_reg, GEN_INT (val));
dd552284
WL
1448 return true;
1449 }
1450 }
1451
1452 return false;
1453}
1454
1455
1456/* Implement DImode rotatert. */
1457static HOST_WIDE_INT
1458rotate_right (HOST_WIDE_INT n, int count)
1459{
1460 unsigned HOST_WIDE_INT x = n & 0xFFFFFFFFFFFFFFFFULL;
1461 if (count == 0)
1462 return x;
1463 return ((x >> count) | (x << (64 - count))) & 0xFFFFFFFFFFFFFFFFULL;
1464}
1465
1466
1467/* Return true iff n contains exactly one contiguous sequence of 1
1468 bits, possibly wrapping around from high bits to low bits. */
1469bool
1470tilegx_bitfield_operand_p (HOST_WIDE_INT n, int *first_bit, int *last_bit)
1471{
1472 int i;
1473
1474 if (n == 0)
1475 return false;
1476
1477 for (i = 0; i < 64; i++)
1478 {
1479 unsigned HOST_WIDE_INT x = rotate_right (n, i);
1480 if (!(x & 1))
1481 continue;
1482
1483 /* See if x is a power of two minus one, i.e. only consecutive 1
3aa775d6 1484 bits starting from bit 0. */
dd552284
WL
1485 if ((x & (x + 1)) == 0)
1486 {
1487 if (first_bit != NULL)
1488 *first_bit = i;
1489 if (last_bit != NULL)
1490 *last_bit = (i + exact_log2 (x ^ (x >> 1))) & 63;
1491
1492 return true;
1493 }
1494 }
1495
1496 return false;
1497}
1498
1499
1500/* Create code to move the CONST_INT value in src_val to dest_reg. */
1501static void
1502expand_set_cint64 (rtx dest_reg, rtx src_val)
1503{
1504 HOST_WIDE_INT val;
1505 int leading_zeroes, trailing_zeroes;
1506 int three_wide_only;
1507 int shift, ins_shift, zero_cluster_shift;
1508 rtx temp, subreg;
1509
1510 gcc_assert (CONST_INT_P (src_val));
1511 val = trunc_int_for_mode (INTVAL (src_val), GET_MODE (dest_reg));
1512
1513 /* See if we can generate the constant in one instruction. */
1514 if (expand_set_cint64_one_inst (dest_reg, val, false))
1515 return;
1516
1517 /* Force the destination to DImode so we can use DImode instructions
1518 to create it. This both allows instructions like rotl, and
1519 certain efficient 3-wide instructions. */
1520 subreg = simplify_gen_subreg (DImode, dest_reg, GET_MODE (dest_reg), 0);
1521 gcc_assert (subreg != NULL);
1522 dest_reg = subreg;
1523
1524 temp = create_temp_reg_if_possible (DImode, dest_reg);
1525
1526 leading_zeroes = 63 - floor_log2 (val & 0xFFFFFFFFFFFFFFFFULL);
1527 trailing_zeroes = exact_log2 (val & -val);
1528
1529 /* First try all three-wide instructions that generate a constant
1530 (i.e. movei) followed by various shifts and rotates. If none of
1531 those work, try various two-wide ways of generating a constant
1532 followed by various shifts and rotates. */
1533 for (three_wide_only = 1; three_wide_only >= 0; three_wide_only--)
1534 {
1535 int count;
1536
1537 if (expand_set_cint64_one_inst (temp, val >> trailing_zeroes,
1538 three_wide_only))
1539 {
1540 /* 0xFFFFFFFFFFFFA500 becomes:
1541 movei temp, 0xFFFFFFFFFFFFFFA5
1542 shli dest, temp, 8 */
1543 emit_move_insn (dest_reg,
1544 gen_rtx_ASHIFT (DImode, temp,
1545 GEN_INT (trailing_zeroes)));
1546 return;
1547 }
1548
1549 if (expand_set_cint64_one_inst (temp, val << leading_zeroes,
1550 three_wide_only))
1551 {
1552 /* 0x7FFFFFFFFFFFFFFF becomes:
1553 movei temp, -2
1554 shrui dest, temp, 1 */
1555 emit_move_insn (dest_reg,
1556 gen_rtx_LSHIFTRT (DImode, temp,
1557 GEN_INT (leading_zeroes)));
1558 return;
1559 }
1560
1561 /* Try rotating a one-instruction immediate. */
1562 for (count = 1; count < 64; count++)
1563 {
1564 HOST_WIDE_INT r = rotate_right (val, count);
1565 if (expand_set_cint64_one_inst (temp, r, three_wide_only))
1566 {
1567 /* 0xFFFFFFFFFFA5FFFF becomes:
3aa775d6
WL
1568 movei temp, 0xFFFFFFFFFFFFFFA5
1569 rotli dest, temp, 16 */
dd552284
WL
1570 emit_move_insn (dest_reg,
1571 gen_rtx_ROTATE (DImode, temp, GEN_INT (count)));
1572 return;
1573 }
1574 }
1575 }
1576
1577 /* There are two cases here to produce a large constant.
1578 In the most general case, we do this:
1579
1580 moveli x, hw3(NUM)
1581 shl16insli x, x, hw2(NUM)
1582 shl16insli x, x, hw1(NUM)
1583 shl16insli x, x, hw0(NUM)
1584
1585 However, we can sometimes do better. shl16insli is a poor way to
1586 insert 16 zero bits, because simply shifting left by 16 has more
1587 bundling freedom. So if we see any contiguous aligned sequence
1588 of 16 or more zero bits (below the highest set bit), it is always
1589 more efficient to materialize the bits above the zero bits, then
1590 left shift to put in the zeroes, then insert whatever bits
1591 remain. For example, we might end up with:
1592
1593 movei x, NUM >> (37 + 16)
1594 shli x, x, 37
1595 shl16insli x, x, hw0(NUM) */
1596
1597 zero_cluster_shift = -1;
1598
1599 for (shift = 0; shift < 48 - leading_zeroes; shift += 16)
1600 {
1601 HOST_WIDE_INT x = val >> shift;
1602
1603 /* Find the least significant group of 16 aligned zero bits. */
1604 if ((x & 0xFFFF) == 0x0000)
1605 {
1606 /* Grab any following zero bits as well. */
1607 zero_cluster_shift = exact_log2 (x & -x);
1608 shift += zero_cluster_shift;
1609 break;
1610 }
1611 }
1612
1613 if (zero_cluster_shift >= 0)
1614 {
1615 unsigned HOST_WIDE_INT leftover;
1616
1617 /* Recursively create the constant above the lowest 16 zero
3aa775d6 1618 bits. */
dd552284
WL
1619 expand_set_cint64 (temp, GEN_INT (val >> shift));
1620
1621 /* See if we can easily insert the remaining bits, or if we need
3aa775d6 1622 to fall through to the more general case. */
dd552284
WL
1623 leftover = val - ((val >> shift) << shift);
1624 if (leftover == 0)
1625 {
1626 /* A simple left shift is enough. */
1627 emit_move_insn (dest_reg,
1628 gen_rtx_ASHIFT (DImode, temp, GEN_INT (shift)));
1629 return;
1630 }
1631 else if (leftover <= 32767)
1632 {
1633 /* Left shift into position then add in the leftover. */
1634 rtx temp2 = create_temp_reg_if_possible (DImode, temp);
1635 emit_move_insn (temp2,
1636 gen_rtx_ASHIFT (DImode, temp, GEN_INT (shift)));
1637 emit_move_insn (dest_reg,
1638 gen_rtx_PLUS (DImode, temp2, GEN_INT (leftover)));
1639 return;
1640 }
1641 else
1642 {
1643 /* Shift in the batch of >= 16 zeroes we detected earlier.
1644 After this, shift will be aligned mod 16 so the final
1645 loop can use shl16insli. */
1646 rtx temp2 = create_temp_reg_if_possible (DImode, temp);
1647 rtx shift_count_rtx = GEN_INT (zero_cluster_shift);
1648
1649 emit_move_insn (temp2,
1650 gen_rtx_ASHIFT (DImode, temp, shift_count_rtx));
1651
1652 shift -= zero_cluster_shift;
1653 temp = temp2;
1654 }
1655 }
1656 else
1657 {
1658 /* Set as many high 16-bit blocks as we can with a single
3aa775d6
WL
1659 instruction. We'll insert the remaining 16-bit blocks
1660 below. */
dd552284
WL
1661 for (shift = 16;; shift += 16)
1662 {
1663 gcc_assert (shift < 64);
1664 if (expand_set_cint64_one_inst (temp, val >> shift, false))
1665 break;
1666 }
1667 }
1668
1669 /* At this point, temp == val >> shift, shift % 16 == 0, and we
1670 still need to insert any bits of 'val' below 'shift'. Those bits
1671 are guaranteed to not have 16 contiguous zeroes. */
1672
1673 gcc_assert ((shift & 15) == 0);
1674
1675 for (ins_shift = shift - 16; ins_shift >= 0; ins_shift -= 16)
1676 {
1677 rtx result;
1678 HOST_WIDE_INT bits = (val >> ins_shift) & 0xFFFF;
1679 gcc_assert (bits != 0);
1680
1681 /* On the last iteration we need to store into dest_reg. */
1682 if (ins_shift == 0)
1683 result = dest_reg;
1684 else
1685 result = create_temp_reg_if_possible (DImode, dest_reg);
1686
1687 emit_insn (gen_insn_shl16insli (result, temp, GEN_INT (bits)));
1688
1689 temp = result;
1690 }
1691}
1692
1693
1694/* Load OP1, a 64-bit constant, into OP0, a register. We know it
1695 can't be done in one insn when we get here, the move expander
1696 guarantees this. */
1697void
1698tilegx_expand_set_const64 (rtx op0, rtx op1)
1699{
1700 if (CONST_INT_P (op1))
1701 {
1702 /* TODO: I don't know if we want to split large constants
3aa775d6 1703 now, or wait until later (with a define_split).
dd552284 1704
3aa775d6
WL
1705 Does splitting early help CSE? Does it harm other
1706 optimizations that might fold loads? */
dd552284
WL
1707 expand_set_cint64 (op0, op1);
1708 }
1709 else
1710 {
1711 rtx temp = create_temp_reg_if_possible (Pmode, op0);
1712
1713 if (TARGET_32BIT)
1714 {
1715 /* Generate the 2-insn sequence to materialize a symbolic
1716 address. */
1717 emit_insn (gen_mov_address_32bit_step1 (temp, op1));
1718 emit_insn (gen_mov_address_32bit_step2 (op0, temp, op1));
1719 }
1720 else
1721 {
1722 /* Generate the 3-insn sequence to materialize a symbolic
1723 address. Note that this assumes that virtual addresses
1724 fit in 48 signed bits, which is currently true. */
1725 rtx temp2 = create_temp_reg_if_possible (Pmode, op0);
1726 emit_insn (gen_mov_address_step1 (temp, op1));
1727 emit_insn (gen_mov_address_step2 (temp2, temp, op1));
1728 emit_insn (gen_mov_address_step3 (op0, temp2, op1));
1729 }
1730 }
1731}
1732
1733
1734/* Expand a move instruction. Return true if all work is done. */
1735bool
1736tilegx_expand_mov (enum machine_mode mode, rtx *operands)
1737{
1738 /* Handle sets of MEM first. */
1739 if (MEM_P (operands[0]))
1740 {
1741 if (can_create_pseudo_p ())
1742 operands[0] = validize_mem (operands[0]);
1743
1744 if (reg_or_0_operand (operands[1], mode))
1745 return false;
1746
1747 if (!reload_in_progress)
1748 operands[1] = force_reg (mode, operands[1]);
1749 }
1750
1751 /* Fixup TLS cases. */
1752 if (CONSTANT_P (operands[1]) && tilegx_tls_referenced_p (operands[1]))
1753 {
1754 operands[1] = tilegx_legitimize_tls_address (operands[1]);
1755 return false;
1756 }
1757
1758 /* Fixup PIC cases. */
1759 if (flag_pic && CONSTANT_P (operands[1]))
1760 {
1761 if (tilegx_pic_address_needs_scratch (operands[1]))
1762 operands[1] = tilegx_legitimize_pic_address (operands[1], mode, 0);
1763
1764 if (symbolic_operand (operands[1], mode))
1765 {
1766 operands[1] = tilegx_legitimize_pic_address (operands[1],
1767 mode,
1768 (reload_in_progress ?
1769 operands[0] :
1770 NULL_RTX));
1771 return false;
1772 }
1773 }
1774
1775 /* Accept non-constants and valid constants unmodified. */
1776 if (!CONSTANT_P (operands[1]) || move_operand (operands[1], mode))
1777 return false;
1778
1779 /* Split large integers. */
1780 tilegx_expand_set_const64 (operands[0], operands[1]);
1781 return true;
1782}
1783
1784
1785/* Expand unaligned loads. */
1786void
1787tilegx_expand_unaligned_load (rtx dest_reg, rtx mem, HOST_WIDE_INT bitsize,
1788 HOST_WIDE_INT bit_offset, bool sign)
1789{
1790 enum machine_mode mode;
1791 rtx addr_lo, addr_hi;
1792 rtx mem_lo, mem_hi, hi;
1793 rtx mema, wide_result;
1794 int last_byte_offset;
1795 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1796
1797 mode = GET_MODE (dest_reg);
1798
1799 hi = gen_reg_rtx (mode);
1800
1801 if (bitsize == 2 * BITS_PER_UNIT && (bit_offset % BITS_PER_UNIT) == 0)
1802 {
1803 /* When just loading a two byte value, we can load the two bytes
3aa775d6 1804 individually and combine them efficiently. */
dd552284
WL
1805
1806 mem_lo = adjust_address (mem, QImode, byte_offset);
1807 mem_hi = adjust_address (mem, QImode, byte_offset + 1);
1808
1809 if (sign)
1810 {
1811 /* Do a signed load of the second byte and use bfins to set
1812 the high bits of the result. */
1813 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, dest_reg),
1814 mem_lo));
1815 emit_insn (gen_extendqidi2 (gen_lowpart (DImode, hi), mem_hi));
1816 emit_insn (gen_insv (gen_lowpart (DImode, dest_reg),
1817 GEN_INT (64 - 8), GEN_INT (8),
1818 gen_lowpart (DImode, hi)));
1819 }
1820 else
1821 {
1822 /* Do two unsigned loads and use v1int_l to interleave
1823 them. */
1824 rtx lo = gen_reg_rtx (mode);
1825 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, lo),
1826 mem_lo));
1827 emit_insn (gen_zero_extendqidi2 (gen_lowpart (DImode, hi),
1828 mem_hi));
1829 emit_insn (gen_insn_v1int_l (gen_lowpart (DImode, dest_reg),
1830 gen_lowpart (DImode, hi),
1831 gen_lowpart (DImode, lo)));
1832 }
1833
1834 return;
1835 }
1836
1837 mema = XEXP (mem, 0);
1838
1839 /* AND addresses cannot be in any alias set, since they may
1840 implicitly alias surrounding code. Ideally we'd have some alias
1841 set that covered all types except those with alignment 8 or
1842 higher. */
0a81f074 1843 addr_lo = force_reg (Pmode, plus_constant (Pmode, mema, byte_offset));
dd552284
WL
1844 mem_lo = change_address (mem, mode,
1845 gen_rtx_AND (GET_MODE (mema), addr_lo,
1846 GEN_INT (-8)));
1847 set_mem_alias_set (mem_lo, 0);
1848
1849 /* Load the high word at an address that will not fault if the low
1850 address is aligned and at the very end of a page. */
1851 last_byte_offset = (bit_offset + bitsize - 1) / BITS_PER_UNIT;
0a81f074 1852 addr_hi = force_reg (Pmode, plus_constant (Pmode, mema, last_byte_offset));
dd552284
WL
1853 mem_hi = change_address (mem, mode,
1854 gen_rtx_AND (GET_MODE (mema), addr_hi,
1855 GEN_INT (-8)));
1856 set_mem_alias_set (mem_hi, 0);
1857
1858 if (bitsize == 64)
1859 {
1860 addr_lo = make_safe_from (addr_lo, dest_reg);
1861 wide_result = dest_reg;
1862 }
1863 else
1864 {
1865 wide_result = gen_reg_rtx (mode);
1866 }
1867
1868 /* Load hi first in case dest_reg is used in mema. */
1869 emit_move_insn (hi, mem_hi);
1870 emit_move_insn (wide_result, mem_lo);
1871
1872 emit_insn (gen_insn_dblalign (gen_lowpart (DImode, wide_result),
1873 gen_lowpart (DImode, wide_result),
1874 gen_lowpart (DImode, hi), addr_lo));
1875
1876 if (bitsize != 64)
1877 {
1878 rtx extracted =
1879 extract_bit_field (gen_lowpart (DImode, wide_result),
1880 bitsize, bit_offset % BITS_PER_UNIT,
c6285bd7 1881 !sign, gen_lowpart (DImode, dest_reg),
dd552284
WL
1882 DImode, DImode);
1883
1884 if (extracted != dest_reg)
1885 emit_move_insn (dest_reg, gen_lowpart (DImode, extracted));
1886 }
1887}
1888
1889
1890/* Expand unaligned stores. */
1891static void
1892tilegx_expand_unaligned_store (rtx mem, rtx src, HOST_WIDE_INT bitsize,
1893 HOST_WIDE_INT bit_offset)
1894{
1895 HOST_WIDE_INT byte_offset = bit_offset / BITS_PER_UNIT;
1896 HOST_WIDE_INT bytesize = bitsize / BITS_PER_UNIT;
1897 HOST_WIDE_INT shift_amt;
1898 HOST_WIDE_INT i;
1899 rtx mem_addr;
1900 rtx store_val;
1901
1902 for (i = 0, shift_amt = 0; i < bytesize; i++, shift_amt += BITS_PER_UNIT)
1903 {
1904 mem_addr = adjust_address (mem, QImode, byte_offset + i);
1905
1906 if (shift_amt)
1907 {
1908 store_val = expand_simple_binop (DImode, LSHIFTRT,
1909 gen_lowpart (DImode, src),
1910 GEN_INT (shift_amt), NULL, 1,
1911 OPTAB_LIB_WIDEN);
1912 store_val = gen_lowpart (QImode, store_val);
1913 }
1914 else
1915 {
1916 store_val = gen_lowpart (QImode, src);
1917 }
1918
1919 emit_move_insn (mem_addr, store_val);
1920 }
1921}
1922
1923
1924/* Implement the movmisalign patterns. One of the operands is a
1925 memory that is not naturally aligned. Emit instructions to load
1926 it. */
1927void
1928tilegx_expand_movmisalign (enum machine_mode mode, rtx *operands)
1929{
1930 if (MEM_P (operands[1]))
1931 {
1932 rtx tmp;
1933
1934 if (register_operand (operands[0], mode))
1935 tmp = operands[0];
1936 else
1937 tmp = gen_reg_rtx (mode);
1938
1939 tilegx_expand_unaligned_load (tmp, operands[1], GET_MODE_BITSIZE (mode),
1940 0, true);
1941
1942 if (tmp != operands[0])
1943 emit_move_insn (operands[0], tmp);
1944 }
1945 else if (MEM_P (operands[0]))
1946 {
1947 if (!reg_or_0_operand (operands[1], mode))
1948 operands[1] = force_reg (mode, operands[1]);
1949
1950 tilegx_expand_unaligned_store (operands[0], operands[1],
1951 GET_MODE_BITSIZE (mode), 0);
1952 }
1953 else
1954 gcc_unreachable ();
1955
1956}
1957
1958
1959/* Implement the allocate_stack pattern (alloca). */
1960void
1961tilegx_allocate_stack (rtx op0, rtx op1)
1962{
1963 /* Technically the correct way to initialize chain_loc is with
1964 * gen_frame_mem() instead of gen_rtx_MEM(), but gen_frame_mem()
1965 * sets the alias_set to that of a frame reference. Some of our
1966 * tests rely on some unsafe assumption about when the chaining
1967 * update is done, we need to be conservative about reordering the
1968 * chaining instructions.
1969 */
1970 rtx fp_addr = gen_reg_rtx (Pmode);
1971 rtx fp_value = gen_reg_rtx (Pmode);
1972 rtx fp_loc;
1973
1974 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1975 GEN_INT (UNITS_PER_WORD)));
1976
1977 fp_loc = gen_frame_mem (Pmode, fp_addr);
1978
1979 emit_move_insn (fp_value, fp_loc);
1980
1981 op1 = force_reg (Pmode, op1);
1982
1983 emit_move_insn (stack_pointer_rtx,
1984 gen_rtx_MINUS (Pmode, stack_pointer_rtx, op1));
1985
1986 emit_move_insn (fp_addr, gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1987 GEN_INT (UNITS_PER_WORD)));
1988
1989 fp_loc = gen_frame_mem (Pmode, fp_addr);
1990
1991 emit_move_insn (fp_loc, fp_value);
1992
1993 emit_move_insn (op0, virtual_stack_dynamic_rtx);
1994}
1995\f
1996
1997
1998/* Multiplies */
1999
2000
2001/* Returns the insn_code in ENTRY. */
2002static enum insn_code
2003tilegx_multiply_get_opcode (const struct tilegx_multiply_insn_seq_entry
2004 *entry)
2005{
2006 return tilegx_multiply_insn_seq_decode_opcode[entry->compressed_opcode];
2007}
2008
2009
2010/* Returns the length of the 'op' array. */
2011static int
2012tilegx_multiply_get_num_ops (const struct tilegx_multiply_insn_seq *seq)
2013{
2014 /* The array either uses all of its allocated slots or is terminated
2015 by a bogus opcode. Either way, the array size is the index of the
2016 last valid opcode plus one. */
2017 int i;
2018 for (i = tilegx_multiply_insn_seq_MAX_OPERATIONS - 1; i >= 0; i--)
2019 if (tilegx_multiply_get_opcode (&seq->op[i]) != CODE_FOR_nothing)
2020 return i + 1;
2021
2022 /* An empty array is not allowed. */
2023 gcc_unreachable ();
2024}
2025
2026
2027/* We precompute a number of expression trees for multiplying by
2028 constants. This generates code for such an expression tree by
2029 walking through the nodes in the tree (which are conveniently
2030 pre-linearized) and emitting an instruction for each one. */
2031static void
2032tilegx_expand_constant_multiply_given_sequence (rtx result, rtx src,
2033 const struct
2034 tilegx_multiply_insn_seq *seq)
2035{
2036 int i;
2037 int num_ops;
2038
2039 /* Keep track of the subexpressions computed so far, so later
2040 instructions can refer to them. We seed the array with zero and
2041 the value being multiplied. */
2042 int num_subexprs = 2;
2043 rtx subexprs[tilegx_multiply_insn_seq_MAX_OPERATIONS + 2];
2044 subexprs[0] = const0_rtx;
2045 subexprs[1] = src;
2046
2047 /* Determine how many instructions we are going to generate. */
2048 num_ops = tilegx_multiply_get_num_ops (seq);
2049 gcc_assert (num_ops > 0
2050 && num_ops <= tilegx_multiply_insn_seq_MAX_OPERATIONS);
2051
2052 for (i = 0; i < num_ops; i++)
2053 {
2054 const struct tilegx_multiply_insn_seq_entry *entry = &seq->op[i];
2055
2056 /* Figure out where to store the output of this instruction. */
2057 const bool is_last_op = (i + 1 == num_ops);
2058 rtx out = is_last_op ? result : gen_reg_rtx (DImode);
2059
2060 enum insn_code opcode = tilegx_multiply_get_opcode (entry);
2061 if (opcode == CODE_FOR_ashldi3)
2062 {
2063 /* Handle shift by immediate. This is a special case because
2064 the meaning of the second operand is a constant shift
2065 count rather than an operand index. */
2066
2067 /* Make sure the shift count is in range. Zero should not
2068 happen. */
2069 const int shift_count = entry->rhs;
2070 gcc_assert (shift_count > 0 && shift_count < 64);
2071
2072 /* Emit the actual instruction. */
2073 emit_insn (GEN_FCN (opcode)
2074 (out, subexprs[entry->lhs],
2075 gen_rtx_CONST_INT (DImode, shift_count)));
2076 }
2077 else
2078 {
2079 /* Handle a normal two-operand instruction, such as add or
2080 shl1add. */
2081
2082 /* Make sure we are referring to a previously computed
2083 subexpression. */
2084 gcc_assert (entry->rhs < num_subexprs);
2085
2086 /* Emit the actual instruction. */
2087 emit_insn (GEN_FCN (opcode)
2088 (out, subexprs[entry->lhs], subexprs[entry->rhs]));
2089 }
2090
2091 /* Record this subexpression for use by later expressions. */
2092 subexprs[num_subexprs++] = out;
2093 }
2094}
2095
2096
2097/* bsearch helper function. */
2098static int
2099tilegx_compare_multipliers (const void *key, const void *t)
2100{
2101 long long delta =
2102 (*(const long long *) key
2103 - ((const struct tilegx_multiply_insn_seq *) t)->multiplier);
2104 return (delta < 0) ? -1 : (delta > 0);
2105}
2106
2107
2108/* Returns the tilegx_multiply_insn_seq for multiplier, or NULL if none
2109 exists. */
2110static const struct tilegx_multiply_insn_seq *
2111tilegx_find_multiply_insn_seq_for_constant (long long multiplier)
2112{
2113 return ((const struct tilegx_multiply_insn_seq *)
2114 bsearch (&multiplier, tilegx_multiply_insn_seq_table,
2115 tilegx_multiply_insn_seq_table_size,
2116 sizeof tilegx_multiply_insn_seq_table[0],
2117 tilegx_compare_multipliers));
2118}
2119
2120
2121/* Try to a expand constant multiply in DImode by looking it up in a
2122 precompiled table. OP0 is the result operand, OP1 is the source
2123 operand, and MULTIPLIER is the value of the constant. Return true
2124 if it succeeds. */
2125static bool
2126tilegx_expand_const_muldi (rtx op0, rtx op1, long long multiplier)
2127{
2128 /* See if we have precomputed an efficient way to multiply by this
2129 constant. */
2130 const struct tilegx_multiply_insn_seq *seq =
2131 tilegx_find_multiply_insn_seq_for_constant (multiplier);
2132 if (seq != NULL)
2133 {
2134 tilegx_expand_constant_multiply_given_sequence (op0, op1, seq);
2135 return true;
2136 }
2137 else
2138 return false;
2139}
2140
3aa775d6 2141
dd552284
WL
2142/* Expand the muldi pattern. */
2143bool
2144tilegx_expand_muldi (rtx op0, rtx op1, rtx op2)
2145{
2146 if (CONST_INT_P (op2))
2147 {
2148 HOST_WIDE_INT n = trunc_int_for_mode (INTVAL (op2), DImode);
2149 return tilegx_expand_const_muldi (op0, op1, n);
2150 }
2151 return false;
2152}
2153
2154
2155/* Expand a high multiply pattern in DImode. RESULT, OP1, OP2 are the
2156 operands, and SIGN is true if it's a signed multiply, and false if
2157 it's an unsigned multiply. */
2158static void
2159tilegx_expand_high_multiply (rtx result, rtx op1, rtx op2, bool sign)
2160{
2161 rtx tmp0 = gen_reg_rtx (DImode);
2162 rtx tmp1 = gen_reg_rtx (DImode);
2163 rtx tmp2 = gen_reg_rtx (DImode);
2164 rtx tmp3 = gen_reg_rtx (DImode);
2165 rtx tmp4 = gen_reg_rtx (DImode);
2166 rtx tmp5 = gen_reg_rtx (DImode);
2167 rtx tmp6 = gen_reg_rtx (DImode);
2168 rtx tmp7 = gen_reg_rtx (DImode);
2169 rtx tmp8 = gen_reg_rtx (DImode);
2170 rtx tmp9 = gen_reg_rtx (DImode);
2171 rtx tmp10 = gen_reg_rtx (DImode);
2172 rtx tmp11 = gen_reg_rtx (DImode);
2173 rtx tmp12 = gen_reg_rtx (DImode);
2174 rtx tmp13 = gen_reg_rtx (DImode);
2175 rtx result_lo = gen_reg_rtx (DImode);
2176
2177 if (sign)
2178 {
2179 emit_insn (gen_insn_mul_hs_lu (tmp0, op1, op2));
2180 emit_insn (gen_insn_mul_hs_lu (tmp1, op2, op1));
2181 emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2));
2182 emit_insn (gen_insn_mul_hs_hs (tmp3, op1, op2));
2183 }
2184 else
2185 {
2186 emit_insn (gen_insn_mul_hu_lu (tmp0, op1, op2));
2187 emit_insn (gen_insn_mul_hu_lu (tmp1, op2, op1));
2188 emit_insn (gen_insn_mul_lu_lu (tmp2, op1, op2));
2189 emit_insn (gen_insn_mul_hu_hu (tmp3, op1, op2));
2190 }
2191
2192 emit_move_insn (tmp4, (gen_rtx_ASHIFT (DImode, tmp0, GEN_INT (32))));
2193
2194 emit_move_insn (tmp5, (gen_rtx_ASHIFT (DImode, tmp1, GEN_INT (32))));
2195
2196 emit_move_insn (tmp6, (gen_rtx_PLUS (DImode, tmp4, tmp5)));
2197 emit_move_insn (result_lo, (gen_rtx_PLUS (DImode, tmp2, tmp6)));
2198
2199 emit_move_insn (tmp7, gen_rtx_LTU (DImode, tmp6, tmp4));
2200 emit_move_insn (tmp8, gen_rtx_LTU (DImode, result_lo, tmp2));
2201
2202 if (sign)
2203 {
2204 emit_move_insn (tmp9, (gen_rtx_ASHIFTRT (DImode, tmp0, GEN_INT (32))));
2205 emit_move_insn (tmp10, (gen_rtx_ASHIFTRT (DImode, tmp1, GEN_INT (32))));
2206 }
2207 else
2208 {
2209 emit_move_insn (tmp9, (gen_rtx_LSHIFTRT (DImode, tmp0, GEN_INT (32))));
2210 emit_move_insn (tmp10, (gen_rtx_LSHIFTRT (DImode, tmp1, GEN_INT (32))));
2211 }
2212
2213 emit_move_insn (tmp11, (gen_rtx_PLUS (DImode, tmp3, tmp7)));
2214 emit_move_insn (tmp12, (gen_rtx_PLUS (DImode, tmp8, tmp9)));
2215 emit_move_insn (tmp13, (gen_rtx_PLUS (DImode, tmp11, tmp12)));
2216 emit_move_insn (result, (gen_rtx_PLUS (DImode, tmp13, tmp10)));
2217}
2218
2219
2220/* Implement smuldi3_highpart. */
2221void
2222tilegx_expand_smuldi3_highpart (rtx op0, rtx op1, rtx op2)
2223{
2224 tilegx_expand_high_multiply (op0, op1, op2, true);
2225}
2226
2227
2228/* Implement umuldi3_highpart. */
2229void
2230tilegx_expand_umuldi3_highpart (rtx op0, rtx op1, rtx op2)
2231{
2232 tilegx_expand_high_multiply (op0, op1, op2, false);
2233}
2234\f
2235
2236
2237/* Compare and branches */
2238
2239/* Produce the rtx yielding a bool for a floating point
2240 comparison. */
2241static bool
2242tilegx_emit_fp_setcc (rtx res, enum rtx_code code, enum machine_mode mode,
2243 rtx op0, rtx op1)
2244{
2245 /* TODO: Certain compares again constants can be done using entirely
2246 integer operations. But you have to get the special cases right
2247 e.g. NaN, +0 == -0, etc. */
2248
2249 rtx flags;
2250 int flag_index;
2251 rtx a = force_reg (DImode, gen_lowpart (DImode, op0));
2252 rtx b = force_reg (DImode, gen_lowpart (DImode, op1));
2253
2254 flags = gen_reg_rtx (DImode);
2255
2256 if (mode == SFmode)
2257 {
2258 emit_insn (gen_insn_fsingle_add1 (flags, a, b));
2259 }
2260 else
2261 {
2262 gcc_assert (mode == DFmode);
2263 emit_insn (gen_insn_fdouble_add_flags (flags, a, b));
2264 }
2265
2266 switch (code)
2267 {
2268 case EQ: flag_index = 30; break;
2269 case NE: flag_index = 31; break;
2270 case LE: flag_index = 27; break;
2271 case LT: flag_index = 26; break;
2272 case GE: flag_index = 29; break;
2273 case GT: flag_index = 28; break;
2274 default: gcc_unreachable ();
2275 }
2276
2277 gcc_assert (GET_MODE (res) == DImode);
2278 emit_move_insn (res, gen_rtx_ZERO_EXTRACT (DImode, flags, GEN_INT (1),
2279 GEN_INT (flag_index)));
2280 return true;
2281}
2282
2283
2284/* Certain simplifications can be done to make invalid setcc
2285 operations valid. Return the final comparison, or NULL if we can't
2286 work. */
2287static bool
2288tilegx_emit_setcc_internal (rtx res, enum rtx_code code, rtx op0, rtx op1,
2289 enum machine_mode cmp_mode)
2290{
2291 rtx tmp;
2292 bool swap = false;
2293
2294 if (cmp_mode == SFmode || cmp_mode == DFmode)
2295 return tilegx_emit_fp_setcc (res, code, cmp_mode, op0, op1);
2296
2297 /* The general case: fold the comparison code to the types of
2298 compares that we have, choosing the branch as necessary. */
2299
2300 switch (code)
2301 {
2302 case EQ:
2303 case NE:
2304 case LE:
2305 case LT:
2306 case LEU:
2307 case LTU:
2308 /* We have these compares. */
2309 break;
2310
2311 case GE:
2312 case GT:
2313 case GEU:
2314 case GTU:
2315 /* We do not have these compares, so we reverse the
3aa775d6 2316 operands. */
dd552284
WL
2317 swap = true;
2318 break;
2319
2320 default:
2321 /* We should not have called this with any other code. */
2322 gcc_unreachable ();
2323 }
2324
2325 if (swap)
2326 {
2327 code = swap_condition (code);
2328 tmp = op0, op0 = op1, op1 = tmp;
2329 }
2330
2331 if (!reg_or_0_operand (op0, cmp_mode))
2332 op0 = force_reg (cmp_mode, op0);
2333
2334 if (!CONST_INT_P (op1) && !register_operand (op1, cmp_mode))
2335 op1 = force_reg (cmp_mode, op1);
2336
2337 /* Return the setcc comparison. */
2338 emit_insn (gen_rtx_SET (VOIDmode, res,
2339 gen_rtx_fmt_ee (code, DImode, op0, op1)));
2340
2341 return true;
2342}
2343
2344
2345/* Implement cstore patterns. */
2346bool
2347tilegx_emit_setcc (rtx operands[], enum machine_mode cmp_mode)
2348{
2349 return
2350 tilegx_emit_setcc_internal (operands[0], GET_CODE (operands[1]),
2351 operands[2], operands[3], cmp_mode);
2352}
2353
2354
2355/* Return whether CODE is a signed comparison. */
2356static bool
2357signed_compare_p (enum rtx_code code)
2358{
2359 return (code == EQ || code == NE || code == LT || code == LE
2360 || code == GT || code == GE);
2361}
2362
2363
2364/* Generate the comparison for a DImode conditional branch. */
2365static rtx
2366tilegx_emit_cc_test (enum rtx_code code, rtx op0, rtx op1,
2367 enum machine_mode cmp_mode, bool eq_ne_only)
2368{
2369 enum rtx_code branch_code;
2370 rtx temp;
2371
2372 if (cmp_mode == SFmode || cmp_mode == DFmode)
2373 {
2374 /* Compute a boolean saying whether the comparison is true. */
2375 temp = gen_reg_rtx (DImode);
2376 tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2377
2378 /* Test that flag. */
2379 return gen_rtx_fmt_ee (NE, VOIDmode, temp, const0_rtx);
2380 }
2381
2382 /* Check for a compare against zero using a comparison we can do
2383 directly. */
2384 if (op1 == const0_rtx
2385 && (code == EQ || code == NE
2386 || (!eq_ne_only && signed_compare_p (code))))
2387 {
2388 op0 = force_reg (cmp_mode, op0);
2389 return gen_rtx_fmt_ee (code, VOIDmode, op0, const0_rtx);
2390 }
2391
2392 /* The general case: fold the comparison code to the types of
2393 compares that we have, choosing the branch as necessary. */
2394 switch (code)
2395 {
2396 case EQ:
2397 case LE:
2398 case LT:
2399 case LEU:
2400 case LTU:
2401 /* We have these compares. */
2402 branch_code = NE;
2403 break;
2404
2405 case NE:
2406 case GE:
2407 case GT:
2408 case GEU:
2409 case GTU:
2410 /* These must be reversed (except NE, but let's
3aa775d6 2411 canonicalize). */
dd552284
WL
2412 code = reverse_condition (code);
2413 branch_code = EQ;
2414 break;
2415
2416 default:
2417 gcc_unreachable ();
2418 }
2419
2420 if (CONST_INT_P (op1) && (!satisfies_constraint_I (op1) || code == LEU))
2421 {
2422 HOST_WIDE_INT n = INTVAL (op1);
2423
2424 switch (code)
2425 {
2426 case EQ:
2427 /* Subtract off the value we want to compare against and see
2428 if we get zero. This is cheaper than creating a constant
2429 in a register. Except that subtracting -128 is more
2430 expensive than seqi to -128, so we leave that alone. */
2431 /* ??? Don't do this when comparing against symbols,
2432 otherwise we'll reduce (&x == 0x1234) to (&x-0x1234 ==
2433 0), which will be declared false out of hand (at least
2434 for non-weak). */
2435 if (n != -128
2436 && add_operand (GEN_INT (-n), DImode)
2437 && !(symbolic_operand (op0, VOIDmode)
2438 || (REG_P (op0) && REG_POINTER (op0))))
2439 {
2440 /* TODO: Use a SIMD add immediate to hit zero for tiled
3aa775d6 2441 constants in a single instruction. */
dd552284
WL
2442 if (GET_MODE (op0) != DImode)
2443 {
2444 /* Convert to DImode so we can use addli. Note that
2445 this will not actually generate any code because
2446 sign extension from SI -> DI is a no-op. I don't
2447 know if it's safe just to make a paradoxical
2448 subreg here though. */
2449 rtx temp2 = gen_reg_rtx (DImode);
2450 emit_insn (gen_extendsidi2 (temp2, op0));
2451 op0 = temp2;
2452 }
2453 else
2454 {
2455 op0 = force_reg (DImode, op0);
2456 }
2457 temp = gen_reg_rtx (DImode);
2458 emit_move_insn (temp, gen_rtx_PLUS (DImode, op0, GEN_INT (-n)));
2459 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2460 VOIDmode, temp, const0_rtx);
2461 }
2462 break;
2463
2464 case LEU:
2465 if (n == -1)
2466 break;
2467 /* FALLTHRU */
2468
2469 case LTU:
2470 /* Change ((unsigned)x < 0x1000) into !((int)x >> 12), etc.
2471 We use arithmetic shift right because it's a 3-wide op,
2472 while logical shift right is not. */
2473 {
2474 int first = exact_log2 (code == LTU ? n : n + 1);
2475 if (first != -1)
2476 {
2477 op0 = force_reg (cmp_mode, op0);
2478 temp = gen_reg_rtx (cmp_mode);
2479 emit_move_insn (temp,
2480 gen_rtx_ASHIFTRT (cmp_mode, op0,
2481 GEN_INT (first)));
2482 return gen_rtx_fmt_ee (reverse_condition (branch_code),
2483 VOIDmode, temp, const0_rtx);
2484 }
2485 }
2486 break;
2487
2488 default:
2489 break;
2490 }
2491 }
2492
2493 /* Compute a flag saying whether we should branch. */
2494 temp = gen_reg_rtx (DImode);
2495 tilegx_emit_setcc_internal (temp, code, op0, op1, cmp_mode);
2496
2497 /* Return the branch comparison. */
2498 return gen_rtx_fmt_ee (branch_code, VOIDmode, temp, const0_rtx);
2499}
2500
2501
2502/* Generate the comparison for a conditional branch. */
2503void
2504tilegx_emit_conditional_branch (rtx operands[], enum machine_mode cmp_mode)
2505{
2506 rtx cmp_rtx =
2507 tilegx_emit_cc_test (GET_CODE (operands[0]), operands[1], operands[2],
2508 cmp_mode, false);
2509 rtx branch_rtx = gen_rtx_SET (VOIDmode, pc_rtx,
2510 gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx,
2511 gen_rtx_LABEL_REF
2512 (VOIDmode,
2513 operands[3]),
2514 pc_rtx));
2515 emit_jump_insn (branch_rtx);
2516}
2517
2518
2519/* Implement the mov<mode>cc pattern. */
2520rtx
2521tilegx_emit_conditional_move (rtx cmp)
2522{
2523 return
2524 tilegx_emit_cc_test (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1),
2525 GET_MODE (XEXP (cmp, 0)), true);
2526}
2527
2528
2529/* Return true if INSN is annotated with a REG_BR_PROB note that
2530 indicates it's a branch that's predicted taken. */
2531static bool
2532cbranch_predicted_p (rtx insn)
2533{
2534 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2535
2536 if (x)
2537 {
e5af9ddd 2538 int pred_val = XINT (x, 0);
dd552284
WL
2539
2540 return pred_val >= REG_BR_PROB_BASE / 2;
2541 }
2542
2543 return false;
2544}
2545
2546
2547/* Output assembly code for a specific branch instruction, appending
2548 the branch prediction flag to the opcode if appropriate. */
2549static const char *
2550tilegx_output_simple_cbranch_with_opcode (rtx insn, const char *opcode,
2551 int regop, bool reverse_predicted)
2552{
2553 static char buf[64];
2554 sprintf (buf, "%s%s\t%%r%d, %%l0", opcode,
2555 (cbranch_predicted_p (insn) ^ reverse_predicted) ? "t" : "",
2556 regop);
2557 return buf;
2558}
2559
2560
2561/* Output assembly code for a specific branch instruction, appending
2562 the branch prediction flag to the opcode if appropriate. */
2563const char *
2564tilegx_output_cbranch_with_opcode (rtx insn, rtx *operands,
2565 const char *opcode,
2566 const char *rev_opcode, int regop)
2567{
2568 const char *branch_if_false;
2569 rtx taken, not_taken;
2570 bool is_simple_branch;
2571
2572 gcc_assert (LABEL_P (operands[0]));
2573
2574 is_simple_branch = true;
2575 if (INSN_ADDRESSES_SET_P ())
2576 {
2577 int from_addr = INSN_ADDRESSES (INSN_UID (insn));
2578 int to_addr = INSN_ADDRESSES (INSN_UID (operands[0]));
2579 int delta = to_addr - from_addr;
2580 is_simple_branch = IN_RANGE (delta, -524288, 524280);
2581 }
2582
2583 if (is_simple_branch)
2584 {
2585 /* Just a simple conditional branch. */
2586 return
2587 tilegx_output_simple_cbranch_with_opcode (insn, opcode, regop, false);
2588 }
2589
2590 /* Generate a reversed branch around a direct jump. This fallback
2591 does not use branch-likely instructions. */
2592 not_taken = gen_label_rtx ();
2593 taken = operands[0];
2594
2595 /* Generate the reversed branch to NOT_TAKEN. */
2596 operands[0] = not_taken;
2597 branch_if_false =
2598 tilegx_output_simple_cbranch_with_opcode (insn, rev_opcode, regop, true);
2599 output_asm_insn (branch_if_false, operands);
2600
2601 output_asm_insn ("j\t%l0", &taken);
2602
2603 /* Output NOT_TAKEN. */
2604 targetm.asm_out.internal_label (asm_out_file, "L",
2605 CODE_LABEL_NUMBER (not_taken));
2606 return "";
2607}
2608
2609
2610/* Output assembly code for a conditional branch instruction. */
2611const char *
2612tilegx_output_cbranch (rtx insn, rtx *operands, bool reversed)
2613{
2614 enum rtx_code code = GET_CODE (operands[1]);
2615 const char *opcode;
2616 const char *rev_opcode;
2617
2618 if (reversed)
2619 code = reverse_condition (code);
2620
2621 switch (code)
2622 {
2623 case NE:
2624 opcode = "bnez";
2625 rev_opcode = "beqz";
2626 break;
2627 case EQ:
2628 opcode = "beqz";
2629 rev_opcode = "bnez";
2630 break;
2631 case GE:
2632 opcode = "bgez";
2633 rev_opcode = "bltz";
2634 break;
2635 case GT:
2636 opcode = "bgtz";
2637 rev_opcode = "blez";
2638 break;
2639 case LE:
2640 opcode = "blez";
2641 rev_opcode = "bgtz";
2642 break;
2643 case LT:
2644 opcode = "bltz";
2645 rev_opcode = "bgez";
2646 break;
2647 default:
2648 gcc_unreachable ();
2649 }
2650
2651 return tilegx_output_cbranch_with_opcode (insn, operands, opcode,
2652 rev_opcode, 2);
2653}
2654
2655
2656/* Implement the tablejump pattern. */
2657void
2658tilegx_expand_tablejump (rtx op0, rtx op1)
2659{
2660 if (flag_pic)
2661 {
2662 rtx temp = gen_reg_rtx (Pmode);
2663 rtx temp2 = gen_reg_rtx (Pmode);
2664
1773cd77 2665 tilegx_compute_pcrel_address (temp, gen_rtx_LABEL_REF (Pmode, op1));
dd552284
WL
2666 emit_move_insn (temp2,
2667 gen_rtx_PLUS (Pmode,
2668 convert_to_mode (Pmode, op0, false),
2669 temp));
2670 op0 = temp2;
2671 }
2672
2673 emit_jump_insn (gen_tablejump_aux (op0, op1));
2674}
2675
2676
2677/* Emit barrier before an atomic, as needed for the memory MODEL. */
2678void
2679tilegx_pre_atomic_barrier (enum memmodel model)
2680{
8930883e
MK
2681 if (need_atomic_barrier_p (model, true))
2682 emit_insn (gen_memory_barrier ());
dd552284
WL
2683}
2684
2685
2686/* Emit barrier after an atomic, as needed for the memory MODEL. */
2687void
2688tilegx_post_atomic_barrier (enum memmodel model)
2689{
8930883e
MK
2690 if (need_atomic_barrier_p (model, false))
2691 emit_insn (gen_memory_barrier ());
dd552284
WL
2692}
2693
2694
2695
2696/* Expand a builtin vector binary op, by calling gen function GEN with
2697 operands in the proper modes. DEST is converted to DEST_MODE, and
2698 src0 and src1 (if DO_SRC1 is true) is converted to SRC_MODE. */
2699void
2700tilegx_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx),
2701 enum machine_mode dest_mode,
2702 rtx dest,
2703 enum machine_mode src_mode,
2704 rtx src0, rtx src1, bool do_src1)
2705{
2706 dest = gen_lowpart (dest_mode, dest);
2707
2708 if (src0 == const0_rtx)
2709 src0 = CONST0_RTX (src_mode);
2710 else
2711 src0 = gen_lowpart (src_mode, src0);
2712
2713 if (do_src1)
2714 {
2715 if (src1 == const0_rtx)
2716 src1 = CONST0_RTX (src_mode);
2717 else
2718 src1 = gen_lowpart (src_mode, src1);
2719 }
2720
2721 emit_insn ((*gen) (dest, src0, src1));
2722}
2723\f
2724
2725
2726/* Intrinsics */
2727
2728
2729struct tile_builtin_info
2730{
2731 enum insn_code icode;
2732 tree fndecl;
2733};
2734
2735static struct tile_builtin_info tilegx_builtin_info[TILEGX_BUILTIN_max] = {
2736 { CODE_FOR_adddi3, NULL }, /* add */
2737 { CODE_FOR_addsi3, NULL }, /* addx */
2738 { CODE_FOR_ssaddsi3, NULL }, /* addxsc */
2739 { CODE_FOR_anddi3, NULL }, /* and */
2740 { CODE_FOR_insn_bfexts, NULL }, /* bfexts */
2741 { CODE_FOR_insn_bfextu, NULL }, /* bfextu */
2742 { CODE_FOR_insn_bfins, NULL }, /* bfins */
2743 { CODE_FOR_clzdi2, NULL }, /* clz */
2744 { CODE_FOR_insn_cmoveqz, NULL }, /* cmoveqz */
2745 { CODE_FOR_insn_cmovnez, NULL }, /* cmovnez */
2746 { CODE_FOR_insn_cmpeq_didi, NULL }, /* cmpeq */
2747 { CODE_FOR_insn_cmpexch, NULL }, /* cmpexch */
2748 { CODE_FOR_insn_cmpexch4, NULL }, /* cmpexch4 */
2749 { CODE_FOR_insn_cmples_didi, NULL }, /* cmples */
2750 { CODE_FOR_insn_cmpleu_didi, NULL }, /* cmpleu */
2751 { CODE_FOR_insn_cmplts_didi, NULL }, /* cmplts */
2752 { CODE_FOR_insn_cmpltu_didi, NULL }, /* cmpltu */
2753 { CODE_FOR_insn_cmpne_didi, NULL }, /* cmpne */
2754 { CODE_FOR_insn_cmul, NULL }, /* cmul */
2755 { CODE_FOR_insn_cmula, NULL }, /* cmula */
2756 { CODE_FOR_insn_cmulaf, NULL }, /* cmulaf */
2757 { CODE_FOR_insn_cmulf, NULL }, /* cmulf */
2758 { CODE_FOR_insn_cmulfr, NULL }, /* cmulfr */
2759 { CODE_FOR_insn_cmulh, NULL }, /* cmulh */
2760 { CODE_FOR_insn_cmulhr, NULL }, /* cmulhr */
2761 { CODE_FOR_insn_crc32_32, NULL }, /* crc32_32 */
2762 { CODE_FOR_insn_crc32_8, NULL }, /* crc32_8 */
2763 { CODE_FOR_ctzdi2, NULL }, /* ctz */
2764 { CODE_FOR_insn_dblalign, NULL }, /* dblalign */
2765 { CODE_FOR_insn_dblalign2, NULL }, /* dblalign2 */
2766 { CODE_FOR_insn_dblalign4, NULL }, /* dblalign4 */
2767 { CODE_FOR_insn_dblalign6, NULL }, /* dblalign6 */
2768 { CODE_FOR_insn_drain, NULL }, /* drain */
2769 { CODE_FOR_insn_dtlbpr, NULL }, /* dtlbpr */
2770 { CODE_FOR_insn_exch, NULL }, /* exch */
2771 { CODE_FOR_insn_exch4, NULL }, /* exch4 */
2772 { CODE_FOR_insn_fdouble_add_flags, NULL }, /* fdouble_add_flags */
2773 { CODE_FOR_insn_fdouble_addsub, NULL }, /* fdouble_addsub */
2774 { CODE_FOR_insn_fdouble_mul_flags, NULL }, /* fdouble_mul_flags */
2775 { CODE_FOR_insn_fdouble_pack1, NULL }, /* fdouble_pack1 */
2776 { CODE_FOR_insn_fdouble_pack2, NULL }, /* fdouble_pack2 */
2777 { CODE_FOR_insn_fdouble_sub_flags, NULL }, /* fdouble_sub_flags */
2778 { CODE_FOR_insn_fdouble_unpack_max, NULL }, /* fdouble_unpack_max */
2779 { CODE_FOR_insn_fdouble_unpack_min, NULL }, /* fdouble_unpack_min */
2780 { CODE_FOR_insn_fetchadd, NULL }, /* fetchadd */
2781 { CODE_FOR_insn_fetchadd4, NULL }, /* fetchadd4 */
2782 { CODE_FOR_insn_fetchaddgez, NULL }, /* fetchaddgez */
2783 { CODE_FOR_insn_fetchaddgez4, NULL }, /* fetchaddgez4 */
2784 { CODE_FOR_insn_fetchand, NULL }, /* fetchand */
2785 { CODE_FOR_insn_fetchand4, NULL }, /* fetchand4 */
2786 { CODE_FOR_insn_fetchor, NULL }, /* fetchor */
2787 { CODE_FOR_insn_fetchor4, NULL }, /* fetchor4 */
2788 { CODE_FOR_insn_finv, NULL }, /* finv */
2789 { CODE_FOR_insn_flush, NULL }, /* flush */
2790 { CODE_FOR_insn_flushwb, NULL }, /* flushwb */
2791 { CODE_FOR_insn_fnop, NULL }, /* fnop */
2792 { CODE_FOR_insn_fsingle_add1, NULL }, /* fsingle_add1 */
2793 { CODE_FOR_insn_fsingle_addsub2, NULL }, /* fsingle_addsub2 */
2794 { CODE_FOR_insn_fsingle_mul1, NULL }, /* fsingle_mul1 */
2795 { CODE_FOR_insn_fsingle_mul2, NULL }, /* fsingle_mul2 */
2796 { CODE_FOR_insn_fsingle_pack1, NULL }, /* fsingle_pack1 */
2797 { CODE_FOR_insn_fsingle_pack2, NULL }, /* fsingle_pack2 */
2798 { CODE_FOR_insn_fsingle_sub1, NULL }, /* fsingle_sub1 */
2799 { CODE_FOR_insn_icoh, NULL }, /* icoh */
2800 { CODE_FOR_insn_ill, NULL }, /* ill */
2801 { CODE_FOR_insn_info, NULL }, /* info */
2802 { CODE_FOR_insn_infol, NULL }, /* infol */
2803 { CODE_FOR_insn_inv, NULL }, /* inv */
2804 { CODE_FOR_insn_ld, NULL }, /* ld */
2805 { CODE_FOR_insn_ld1s, NULL }, /* ld1s */
2806 { CODE_FOR_insn_ld1u, NULL }, /* ld1u */
2807 { CODE_FOR_insn_ld2s, NULL }, /* ld2s */
2808 { CODE_FOR_insn_ld2u, NULL }, /* ld2u */
2809 { CODE_FOR_insn_ld4s, NULL }, /* ld4s */
2810 { CODE_FOR_insn_ld4u, NULL }, /* ld4u */
2811 { CODE_FOR_insn_ldna, NULL }, /* ldna */
2812 { CODE_FOR_insn_ldnt, NULL }, /* ldnt */
2813 { CODE_FOR_insn_ldnt1s, NULL }, /* ldnt1s */
2814 { CODE_FOR_insn_ldnt1u, NULL }, /* ldnt1u */
2815 { CODE_FOR_insn_ldnt2s, NULL }, /* ldnt2s */
2816 { CODE_FOR_insn_ldnt2u, NULL }, /* ldnt2u */
2817 { CODE_FOR_insn_ldnt4s, NULL }, /* ldnt4s */
2818 { CODE_FOR_insn_ldnt4u, NULL }, /* ldnt4u */
2819 { CODE_FOR_insn_ld_L2, NULL }, /* ld_L2 */
2820 { CODE_FOR_insn_ld1s_L2, NULL }, /* ld1s_L2 */
2821 { CODE_FOR_insn_ld1u_L2, NULL }, /* ld1u_L2 */
2822 { CODE_FOR_insn_ld2s_L2, NULL }, /* ld2s_L2 */
2823 { CODE_FOR_insn_ld2u_L2, NULL }, /* ld2u_L2 */
2824 { CODE_FOR_insn_ld4s_L2, NULL }, /* ld4s_L2 */
2825 { CODE_FOR_insn_ld4u_L2, NULL }, /* ld4u_L2 */
2826 { CODE_FOR_insn_ldna_L2, NULL }, /* ldna_L2 */
2827 { CODE_FOR_insn_ldnt_L2, NULL }, /* ldnt_L2 */
2828 { CODE_FOR_insn_ldnt1s_L2, NULL }, /* ldnt1s_L2 */
2829 { CODE_FOR_insn_ldnt1u_L2, NULL }, /* ldnt1u_L2 */
2830 { CODE_FOR_insn_ldnt2s_L2, NULL }, /* ldnt2s_L2 */
2831 { CODE_FOR_insn_ldnt2u_L2, NULL }, /* ldnt2u_L2 */
2832 { CODE_FOR_insn_ldnt4s_L2, NULL }, /* ldnt4s_L2 */
2833 { CODE_FOR_insn_ldnt4u_L2, NULL }, /* ldnt4u_L2 */
2834 { CODE_FOR_insn_ld_miss, NULL }, /* ld_miss */
2835 { CODE_FOR_insn_ld1s_miss, NULL }, /* ld1s_miss */
2836 { CODE_FOR_insn_ld1u_miss, NULL }, /* ld1u_miss */
2837 { CODE_FOR_insn_ld2s_miss, NULL }, /* ld2s_miss */
2838 { CODE_FOR_insn_ld2u_miss, NULL }, /* ld2u_miss */
2839 { CODE_FOR_insn_ld4s_miss, NULL }, /* ld4s_miss */
2840 { CODE_FOR_insn_ld4u_miss, NULL }, /* ld4u_miss */
2841 { CODE_FOR_insn_ldna_miss, NULL }, /* ldna_miss */
2842 { CODE_FOR_insn_ldnt_miss, NULL }, /* ldnt_miss */
2843 { CODE_FOR_insn_ldnt1s_miss, NULL }, /* ldnt1s_miss */
2844 { CODE_FOR_insn_ldnt1u_miss, NULL }, /* ldnt1u_miss */
2845 { CODE_FOR_insn_ldnt2s_miss, NULL }, /* ldnt2s_miss */
2846 { CODE_FOR_insn_ldnt2u_miss, NULL }, /* ldnt2u_miss */
2847 { CODE_FOR_insn_ldnt4s_miss, NULL }, /* ldnt4s_miss */
2848 { CODE_FOR_insn_ldnt4u_miss, NULL }, /* ldnt4u_miss */
2849 { CODE_FOR_insn_lnk, NULL }, /* lnk */
2850 { CODE_FOR_memory_barrier, NULL }, /* mf */
2851 { CODE_FOR_insn_mfspr, NULL }, /* mfspr */
2852 { CODE_FOR_insn_mm, NULL }, /* mm */
2853 { CODE_FOR_insn_mnz, NULL }, /* mnz */
2854 { CODE_FOR_movdi, NULL }, /* move */
2855 { CODE_FOR_insn_mtspr, NULL }, /* mtspr */
2856 { CODE_FOR_insn_mul_hs_hs, NULL }, /* mul_hs_hs */
2857 { CODE_FOR_insn_mul_hs_hu, NULL }, /* mul_hs_hu */
2858 { CODE_FOR_insn_mul_hs_ls, NULL }, /* mul_hs_ls */
2859 { CODE_FOR_insn_mul_hs_lu, NULL }, /* mul_hs_lu */
2860 { CODE_FOR_insn_mul_hu_hu, NULL }, /* mul_hu_hu */
2861 { CODE_FOR_insn_mul_hu_ls, NULL }, /* mul_hu_ls */
2862 { CODE_FOR_insn_mul_hu_lu, NULL }, /* mul_hu_lu */
2863 { CODE_FOR_insn_mul_ls_ls, NULL }, /* mul_ls_ls */
2864 { CODE_FOR_insn_mul_ls_lu, NULL }, /* mul_ls_lu */
2865 { CODE_FOR_insn_mul_lu_lu, NULL }, /* mul_lu_lu */
2866 { CODE_FOR_insn_mula_hs_hs, NULL }, /* mula_hs_hs */
2867 { CODE_FOR_insn_mula_hs_hu, NULL }, /* mula_hs_hu */
2868 { CODE_FOR_insn_mula_hs_ls, NULL }, /* mula_hs_ls */
2869 { CODE_FOR_insn_mula_hs_lu, NULL }, /* mula_hs_lu */
2870 { CODE_FOR_insn_mula_hu_hu, NULL }, /* mula_hu_hu */
2871 { CODE_FOR_insn_mula_hu_ls, NULL }, /* mula_hu_ls */
2872 { CODE_FOR_insn_mula_hu_lu, NULL }, /* mula_hu_lu */
2873 { CODE_FOR_insn_mula_ls_ls, NULL }, /* mula_ls_ls */
2874 { CODE_FOR_insn_mula_ls_lu, NULL }, /* mula_ls_lu */
2875 { CODE_FOR_insn_mula_lu_lu, NULL }, /* mula_lu_lu */
2876 { CODE_FOR_insn_mulax, NULL }, /* mulax */
2877 { CODE_FOR_mulsi3, NULL }, /* mulx */
2878 { CODE_FOR_insn_mz, NULL }, /* mz */
2879 { CODE_FOR_insn_nap, NULL }, /* nap */
2880 { CODE_FOR_nop, NULL }, /* nop */
2881 { CODE_FOR_insn_nor_di, NULL }, /* nor */
2882 { CODE_FOR_iordi3, NULL }, /* or */
2883 { CODE_FOR_popcountdi2, NULL }, /* pcnt */
2884 { CODE_FOR_insn_prefetch_l1, NULL }, /* prefetch_l1 */
2885 { CODE_FOR_insn_prefetch_l1_fault, NULL }, /* prefetch_l1_fault */
2886 { CODE_FOR_insn_prefetch_l2, NULL }, /* prefetch_l2 */
2887 { CODE_FOR_insn_prefetch_l2_fault, NULL }, /* prefetch_l2_fault */
2888 { CODE_FOR_insn_prefetch_l3, NULL }, /* prefetch_l3 */
2889 { CODE_FOR_insn_prefetch_l3_fault, NULL }, /* prefetch_l3_fault */
2890 { CODE_FOR_insn_revbits, NULL }, /* revbits */
2891 { CODE_FOR_bswapdi2, NULL }, /* revbytes */
2892 { CODE_FOR_rotldi3, NULL }, /* rotl */
2893 { CODE_FOR_ashldi3, NULL }, /* shl */
2894 { CODE_FOR_insn_shl16insli, NULL }, /* shl16insli */
2895 { CODE_FOR_insn_shl1add, NULL }, /* shl1add */
2896 { CODE_FOR_insn_shl1addx, NULL }, /* shl1addx */
2897 { CODE_FOR_insn_shl2add, NULL }, /* shl2add */
2898 { CODE_FOR_insn_shl2addx, NULL }, /* shl2addx */
2899 { CODE_FOR_insn_shl3add, NULL }, /* shl3add */
2900 { CODE_FOR_insn_shl3addx, NULL }, /* shl3addx */
2901 { CODE_FOR_ashlsi3, NULL }, /* shlx */
2902 { CODE_FOR_ashrdi3, NULL }, /* shrs */
2903 { CODE_FOR_lshrdi3, NULL }, /* shru */
2904 { CODE_FOR_lshrsi3, NULL }, /* shrux */
2905 { CODE_FOR_insn_shufflebytes, NULL }, /* shufflebytes */
0051d3ec 2906 { CODE_FOR_insn_shufflebytes1, NULL }, /* shufflebytes1 */
dd552284
WL
2907 { CODE_FOR_insn_st, NULL }, /* st */
2908 { CODE_FOR_insn_st1, NULL }, /* st1 */
2909 { CODE_FOR_insn_st2, NULL }, /* st2 */
2910 { CODE_FOR_insn_st4, NULL }, /* st4 */
2911 { CODE_FOR_insn_stnt, NULL }, /* stnt */
2912 { CODE_FOR_insn_stnt1, NULL }, /* stnt1 */
2913 { CODE_FOR_insn_stnt2, NULL }, /* stnt2 */
2914 { CODE_FOR_insn_stnt4, NULL }, /* stnt4 */
2915 { CODE_FOR_subdi3, NULL }, /* sub */
2916 { CODE_FOR_subsi3, NULL }, /* subx */
2917 { CODE_FOR_sssubsi3, NULL }, /* subxsc */
2918 { CODE_FOR_insn_tblidxb0, NULL }, /* tblidxb0 */
2919 { CODE_FOR_insn_tblidxb1, NULL }, /* tblidxb1 */
2920 { CODE_FOR_insn_tblidxb2, NULL }, /* tblidxb2 */
2921 { CODE_FOR_insn_tblidxb3, NULL }, /* tblidxb3 */
2922 { CODE_FOR_insn_v1add, NULL }, /* v1add */
2923 { CODE_FOR_insn_v1addi, NULL }, /* v1addi */
2924 { CODE_FOR_insn_v1adduc, NULL }, /* v1adduc */
2925 { CODE_FOR_insn_v1adiffu, NULL }, /* v1adiffu */
2926 { CODE_FOR_insn_v1avgu, NULL }, /* v1avgu */
2927 { CODE_FOR_insn_v1cmpeq, NULL }, /* v1cmpeq */
2928 { CODE_FOR_insn_v1cmpeqi, NULL }, /* v1cmpeqi */
2929 { CODE_FOR_insn_v1cmples, NULL }, /* v1cmples */
2930 { CODE_FOR_insn_v1cmpleu, NULL }, /* v1cmpleu */
2931 { CODE_FOR_insn_v1cmplts, NULL }, /* v1cmplts */
2932 { CODE_FOR_insn_v1cmpltsi, NULL }, /* v1cmpltsi */
2933 { CODE_FOR_insn_v1cmpltu, NULL }, /* v1cmpltu */
2934 { CODE_FOR_insn_v1cmpltui, NULL }, /* v1cmpltui */
2935 { CODE_FOR_insn_v1cmpne, NULL }, /* v1cmpne */
2936 { CODE_FOR_insn_v1ddotpu, NULL }, /* v1ddotpu */
2937 { CODE_FOR_insn_v1ddotpua, NULL }, /* v1ddotpua */
2938 { CODE_FOR_insn_v1ddotpus, NULL }, /* v1ddotpus */
2939 { CODE_FOR_insn_v1ddotpusa, NULL }, /* v1ddotpusa */
2940 { CODE_FOR_insn_v1dotp, NULL }, /* v1dotp */
2941 { CODE_FOR_insn_v1dotpa, NULL }, /* v1dotpa */
2942 { CODE_FOR_insn_v1dotpu, NULL }, /* v1dotpu */
2943 { CODE_FOR_insn_v1dotpua, NULL }, /* v1dotpua */
2944 { CODE_FOR_insn_v1dotpus, NULL }, /* v1dotpus */
2945 { CODE_FOR_insn_v1dotpusa, NULL }, /* v1dotpusa */
2946 { CODE_FOR_insn_v1int_h, NULL }, /* v1int_h */
2947 { CODE_FOR_insn_v1int_l, NULL }, /* v1int_l */
2948 { CODE_FOR_insn_v1maxu, NULL }, /* v1maxu */
2949 { CODE_FOR_insn_v1maxui, NULL }, /* v1maxui */
2950 { CODE_FOR_insn_v1minu, NULL }, /* v1minu */
2951 { CODE_FOR_insn_v1minui, NULL }, /* v1minui */
2952 { CODE_FOR_insn_v1mnz, NULL }, /* v1mnz */
2953 { CODE_FOR_insn_v1multu, NULL }, /* v1multu */
2954 { CODE_FOR_insn_v1mulu, NULL }, /* v1mulu */
2955 { CODE_FOR_insn_v1mulus, NULL }, /* v1mulus */
2956 { CODE_FOR_insn_v1mz, NULL }, /* v1mz */
2957 { CODE_FOR_insn_v1sadau, NULL }, /* v1sadau */
2958 { CODE_FOR_insn_v1sadu, NULL }, /* v1sadu */
2959 { CODE_FOR_insn_v1shl, NULL }, /* v1shl */
2960 { CODE_FOR_insn_v1shl, NULL }, /* v1shli */
2961 { CODE_FOR_insn_v1shrs, NULL }, /* v1shrs */
2962 { CODE_FOR_insn_v1shrs, NULL }, /* v1shrsi */
2963 { CODE_FOR_insn_v1shru, NULL }, /* v1shru */
2964 { CODE_FOR_insn_v1shru, NULL }, /* v1shrui */
2965 { CODE_FOR_insn_v1sub, NULL }, /* v1sub */
2966 { CODE_FOR_insn_v1subuc, NULL }, /* v1subuc */
2967 { CODE_FOR_insn_v2add, NULL }, /* v2add */
2968 { CODE_FOR_insn_v2addi, NULL }, /* v2addi */
2969 { CODE_FOR_insn_v2addsc, NULL }, /* v2addsc */
2970 { CODE_FOR_insn_v2adiffs, NULL }, /* v2adiffs */
2971 { CODE_FOR_insn_v2avgs, NULL }, /* v2avgs */
2972 { CODE_FOR_insn_v2cmpeq, NULL }, /* v2cmpeq */
2973 { CODE_FOR_insn_v2cmpeqi, NULL }, /* v2cmpeqi */
2974 { CODE_FOR_insn_v2cmples, NULL }, /* v2cmples */
2975 { CODE_FOR_insn_v2cmpleu, NULL }, /* v2cmpleu */
2976 { CODE_FOR_insn_v2cmplts, NULL }, /* v2cmplts */
2977 { CODE_FOR_insn_v2cmpltsi, NULL }, /* v2cmpltsi */
2978 { CODE_FOR_insn_v2cmpltu, NULL }, /* v2cmpltu */
2979 { CODE_FOR_insn_v2cmpltui, NULL }, /* v2cmpltui */
2980 { CODE_FOR_insn_v2cmpne, NULL }, /* v2cmpne */
2981 { CODE_FOR_insn_v2dotp, NULL }, /* v2dotp */
2982 { CODE_FOR_insn_v2dotpa, NULL }, /* v2dotpa */
2983 { CODE_FOR_insn_v2int_h, NULL }, /* v2int_h */
2984 { CODE_FOR_insn_v2int_l, NULL }, /* v2int_l */
2985 { CODE_FOR_insn_v2maxs, NULL }, /* v2maxs */
2986 { CODE_FOR_insn_v2maxsi, NULL }, /* v2maxsi */
2987 { CODE_FOR_insn_v2mins, NULL }, /* v2mins */
2988 { CODE_FOR_insn_v2minsi, NULL }, /* v2minsi */
2989 { CODE_FOR_insn_v2mnz, NULL }, /* v2mnz */
2990 { CODE_FOR_insn_v2mulfsc, NULL }, /* v2mulfsc */
2991 { CODE_FOR_insn_v2muls, NULL }, /* v2muls */
2992 { CODE_FOR_insn_v2mults, NULL }, /* v2mults */
2993 { CODE_FOR_insn_v2mz, NULL }, /* v2mz */
2994 { CODE_FOR_insn_v2packh, NULL }, /* v2packh */
2995 { CODE_FOR_insn_v2packl, NULL }, /* v2packl */
2996 { CODE_FOR_insn_v2packuc, NULL }, /* v2packuc */
2997 { CODE_FOR_insn_v2sadas, NULL }, /* v2sadas */
2998 { CODE_FOR_insn_v2sadau, NULL }, /* v2sadau */
2999 { CODE_FOR_insn_v2sads, NULL }, /* v2sads */
3000 { CODE_FOR_insn_v2sadu, NULL }, /* v2sadu */
3001 { CODE_FOR_insn_v2shl, NULL }, /* v2shl */
3002 { CODE_FOR_insn_v2shl, NULL }, /* v2shli */
3003 { CODE_FOR_insn_v2shlsc, NULL }, /* v2shlsc */
3004 { CODE_FOR_insn_v2shrs, NULL }, /* v2shrs */
3005 { CODE_FOR_insn_v2shrs, NULL }, /* v2shrsi */
3006 { CODE_FOR_insn_v2shru, NULL }, /* v2shru */
3007 { CODE_FOR_insn_v2shru, NULL }, /* v2shrui */
3008 { CODE_FOR_insn_v2sub, NULL }, /* v2sub */
3009 { CODE_FOR_insn_v2subsc, NULL }, /* v2subsc */
3010 { CODE_FOR_insn_v4add, NULL }, /* v4add */
3011 { CODE_FOR_insn_v4addsc, NULL }, /* v4addsc */
3012 { CODE_FOR_insn_v4int_h, NULL }, /* v4int_h */
3013 { CODE_FOR_insn_v4int_l, NULL }, /* v4int_l */
3014 { CODE_FOR_insn_v4packsc, NULL }, /* v4packsc */
3015 { CODE_FOR_insn_v4shl, NULL }, /* v4shl */
3016 { CODE_FOR_insn_v4shlsc, NULL }, /* v4shlsc */
3017 { CODE_FOR_insn_v4shrs, NULL }, /* v4shrs */
3018 { CODE_FOR_insn_v4shru, NULL }, /* v4shru */
3019 { CODE_FOR_insn_v4sub, NULL }, /* v4sub */
3020 { CODE_FOR_insn_v4subsc, NULL }, /* v4subsc */
3021 { CODE_FOR_insn_wh64, NULL }, /* wh64 */
3022 { CODE_FOR_xordi3, NULL }, /* xor */
3023 { CODE_FOR_tilegx_network_barrier, NULL }, /* network_barrier */
3024 { CODE_FOR_tilegx_idn0_receive, NULL }, /* idn0_receive */
3025 { CODE_FOR_tilegx_idn1_receive, NULL }, /* idn1_receive */
3026 { CODE_FOR_tilegx_idn_send, NULL }, /* idn_send */
3027 { CODE_FOR_tilegx_udn0_receive, NULL }, /* udn0_receive */
3028 { CODE_FOR_tilegx_udn1_receive, NULL }, /* udn1_receive */
3029 { CODE_FOR_tilegx_udn2_receive, NULL }, /* udn2_receive */
3030 { CODE_FOR_tilegx_udn3_receive, NULL }, /* udn3_receive */
3031 { CODE_FOR_tilegx_udn_send, NULL }, /* udn_send */
3032};
3033
3034
3035struct tilegx_builtin_def
3036{
3037 const char *name;
3038 enum tilegx_builtin code;
3039 bool is_const;
3040 /* The first character is the return type. Subsequent characters
3041 are the argument types. See char_to_type. */
3042 const char *type;
3043};
3044
3045
3046static const struct tilegx_builtin_def tilegx_builtins[] = {
3047 { "__insn_add", TILEGX_INSN_ADD, true, "lll" },
3048 { "__insn_addi", TILEGX_INSN_ADD, true, "lll" },
3049 { "__insn_addli", TILEGX_INSN_ADD, true, "lll" },
3050 { "__insn_addx", TILEGX_INSN_ADDX, true, "iii" },
3051 { "__insn_addxi", TILEGX_INSN_ADDX, true, "iii" },
3052 { "__insn_addxli", TILEGX_INSN_ADDX, true, "iii" },
3053 { "__insn_addxsc", TILEGX_INSN_ADDXSC, true, "iii" },
3054 { "__insn_and", TILEGX_INSN_AND, true, "lll" },
3055 { "__insn_andi", TILEGX_INSN_AND, true, "lll" },
3056 { "__insn_bfexts", TILEGX_INSN_BFEXTS, true, "llll" },
3057 { "__insn_bfextu", TILEGX_INSN_BFEXTU, true, "llll" },
3058 { "__insn_bfins", TILEGX_INSN_BFINS, true, "lllll"},
3059 { "__insn_clz", TILEGX_INSN_CLZ, true, "ll" },
3060 { "__insn_cmoveqz", TILEGX_INSN_CMOVEQZ, true, "llll" },
3061 { "__insn_cmovnez", TILEGX_INSN_CMOVNEZ, true, "llll" },
3062 { "__insn_cmpeq", TILEGX_INSN_CMPEQ, true, "lll" },
3063 { "__insn_cmpeqi", TILEGX_INSN_CMPEQ, true, "lll" },
3064 { "__insn_cmpexch", TILEGX_INSN_CMPEXCH, false, "lpl" },
3065 { "__insn_cmpexch4", TILEGX_INSN_CMPEXCH4, false, "ipi" },
3066 { "__insn_cmples", TILEGX_INSN_CMPLES, true, "lll" },
3067 { "__insn_cmpleu", TILEGX_INSN_CMPLEU, true, "lll" },
3068 { "__insn_cmplts", TILEGX_INSN_CMPLTS, true, "lll" },
3069 { "__insn_cmpltsi", TILEGX_INSN_CMPLTS, true, "lll" },
3070 { "__insn_cmpltu", TILEGX_INSN_CMPLTU, true, "lll" },
3071 { "__insn_cmpltui", TILEGX_INSN_CMPLTU, true, "lll" },
3072 { "__insn_cmpne", TILEGX_INSN_CMPNE, true, "lll" },
3073 { "__insn_cmul", TILEGX_INSN_CMUL, true, "lll" },
3074 { "__insn_cmula", TILEGX_INSN_CMULA, true, "llll" },
3075 { "__insn_cmulaf", TILEGX_INSN_CMULAF, true, "llll" },
3076 { "__insn_cmulf", TILEGX_INSN_CMULF, true, "lll" },
3077 { "__insn_cmulfr", TILEGX_INSN_CMULFR, true, "lll" },
3078 { "__insn_cmulh", TILEGX_INSN_CMULH, true, "lll" },
3079 { "__insn_cmulhr", TILEGX_INSN_CMULHR, true, "lll" },
3080 { "__insn_crc32_32", TILEGX_INSN_CRC32_32, true, "lll" },
3081 { "__insn_crc32_8", TILEGX_INSN_CRC32_8, true, "lll" },
3082 { "__insn_ctz", TILEGX_INSN_CTZ, true, "ll" },
3083 { "__insn_dblalign", TILEGX_INSN_DBLALIGN, true, "lllk" },
3084 { "__insn_dblalign2", TILEGX_INSN_DBLALIGN2, true, "lll" },
3085 { "__insn_dblalign4", TILEGX_INSN_DBLALIGN4, true, "lll" },
3086 { "__insn_dblalign6", TILEGX_INSN_DBLALIGN6, true, "lll" },
3087 { "__insn_drain", TILEGX_INSN_DRAIN, false, "v" },
3088 { "__insn_dtlbpr", TILEGX_INSN_DTLBPR, false, "vl" },
3089 { "__insn_exch", TILEGX_INSN_EXCH, false, "lpl" },
3090 { "__insn_exch4", TILEGX_INSN_EXCH4, false, "ipi" },
3091 { "__insn_fdouble_add_flags", TILEGX_INSN_FDOUBLE_ADD_FLAGS, true, "lll" },
3092 { "__insn_fdouble_addsub", TILEGX_INSN_FDOUBLE_ADDSUB, true, "llll" },
3093 { "__insn_fdouble_mul_flags", TILEGX_INSN_FDOUBLE_MUL_FLAGS, true, "lll" },
3094 { "__insn_fdouble_pack1", TILEGX_INSN_FDOUBLE_PACK1, true, "lll" },
3095 { "__insn_fdouble_pack2", TILEGX_INSN_FDOUBLE_PACK2, true, "llll" },
3096 { "__insn_fdouble_sub_flags", TILEGX_INSN_FDOUBLE_SUB_FLAGS, true, "lll" },
3097 { "__insn_fdouble_unpack_max", TILEGX_INSN_FDOUBLE_UNPACK_MAX, true, "lll" },
3098 { "__insn_fdouble_unpack_min", TILEGX_INSN_FDOUBLE_UNPACK_MIN, true, "lll" },
3099 { "__insn_fetchadd", TILEGX_INSN_FETCHADD, false, "lpl" },
3100 { "__insn_fetchadd4", TILEGX_INSN_FETCHADD4, false, "ipi" },
3101 { "__insn_fetchaddgez", TILEGX_INSN_FETCHADDGEZ, false, "lpl" },
3102 { "__insn_fetchaddgez4", TILEGX_INSN_FETCHADDGEZ4, false, "ipi" },
3103 { "__insn_fetchand", TILEGX_INSN_FETCHAND, false, "lpl" },
3104 { "__insn_fetchand4", TILEGX_INSN_FETCHAND4, false, "ipi" },
3105 { "__insn_fetchor", TILEGX_INSN_FETCHOR, false, "lpl" },
3106 { "__insn_fetchor4", TILEGX_INSN_FETCHOR4, false, "ipi" },
3107 { "__insn_finv", TILEGX_INSN_FINV, false, "vk" },
3108 { "__insn_flush", TILEGX_INSN_FLUSH, false, "vk" },
3109 { "__insn_flushwb", TILEGX_INSN_FLUSHWB, false, "v" },
3110 { "__insn_fnop", TILEGX_INSN_FNOP, false, "v" },
3111 { "__insn_fsingle_add1", TILEGX_INSN_FSINGLE_ADD1, true, "lll" },
3112 { "__insn_fsingle_addsub2", TILEGX_INSN_FSINGLE_ADDSUB2, true, "llll" },
3113 { "__insn_fsingle_mul1", TILEGX_INSN_FSINGLE_MUL1, true, "lll" },
3114 { "__insn_fsingle_mul2", TILEGX_INSN_FSINGLE_MUL2, true, "lll" },
3115 { "__insn_fsingle_pack1", TILEGX_INSN_FSINGLE_PACK1, true, "ll" },
3116 { "__insn_fsingle_pack2", TILEGX_INSN_FSINGLE_PACK2, true, "lll" },
3117 { "__insn_fsingle_sub1", TILEGX_INSN_FSINGLE_SUB1, true, "lll" },
3118 { "__insn_icoh", TILEGX_INSN_ICOH, false, "vk" },
3119 { "__insn_ill", TILEGX_INSN_ILL, false, "v" },
3120 { "__insn_info", TILEGX_INSN_INFO, false, "vl" },
3121 { "__insn_infol", TILEGX_INSN_INFOL, false, "vl" },
3122 { "__insn_inv", TILEGX_INSN_INV, false, "vp" },
3123 { "__insn_ld", TILEGX_INSN_LD, false, "lk" },
3124 { "__insn_ld1s", TILEGX_INSN_LD1S, false, "lk" },
3125 { "__insn_ld1u", TILEGX_INSN_LD1U, false, "lk" },
3126 { "__insn_ld2s", TILEGX_INSN_LD2S, false, "lk" },
3127 { "__insn_ld2u", TILEGX_INSN_LD2U, false, "lk" },
3128 { "__insn_ld4s", TILEGX_INSN_LD4S, false, "lk" },
3129 { "__insn_ld4u", TILEGX_INSN_LD4U, false, "lk" },
3130 { "__insn_ldna", TILEGX_INSN_LDNA, false, "lk" },
3131 { "__insn_ldnt", TILEGX_INSN_LDNT, false, "lk" },
3132 { "__insn_ldnt1s", TILEGX_INSN_LDNT1S, false, "lk" },
3133 { "__insn_ldnt1u", TILEGX_INSN_LDNT1U, false, "lk" },
3134 { "__insn_ldnt2s", TILEGX_INSN_LDNT2S, false, "lk" },
3135 { "__insn_ldnt2u", TILEGX_INSN_LDNT2U, false, "lk" },
3136 { "__insn_ldnt4s", TILEGX_INSN_LDNT4S, false, "lk" },
3137 { "__insn_ldnt4u", TILEGX_INSN_LDNT4U, false, "lk" },
3138 { "__insn_ld_L2", TILEGX_INSN_LD_L2, false, "lk" },
3139 { "__insn_ld1s_L2", TILEGX_INSN_LD1S_L2, false, "lk" },
3140 { "__insn_ld1u_L2", TILEGX_INSN_LD1U_L2, false, "lk" },
3141 { "__insn_ld2s_L2", TILEGX_INSN_LD2S_L2, false, "lk" },
3142 { "__insn_ld2u_L2", TILEGX_INSN_LD2U_L2, false, "lk" },
3143 { "__insn_ld4s_L2", TILEGX_INSN_LD4S_L2, false, "lk" },
3144 { "__insn_ld4u_L2", TILEGX_INSN_LD4U_L2, false, "lk" },
3145 { "__insn_ldna_L2", TILEGX_INSN_LDNA_L2, false, "lk" },
3146 { "__insn_ldnt_L2", TILEGX_INSN_LDNT_L2, false, "lk" },
3147 { "__insn_ldnt1s_L2", TILEGX_INSN_LDNT1S_L2, false, "lk" },
3148 { "__insn_ldnt1u_L2", TILEGX_INSN_LDNT1U_L2, false, "lk" },
3149 { "__insn_ldnt2s_L2", TILEGX_INSN_LDNT2S_L2, false, "lk" },
3150 { "__insn_ldnt2u_L2", TILEGX_INSN_LDNT2U_L2, false, "lk" },
3151 { "__insn_ldnt4s_L2", TILEGX_INSN_LDNT4S_L2, false, "lk" },
3152 { "__insn_ldnt4u_L2", TILEGX_INSN_LDNT4U_L2, false, "lk" },
3153 { "__insn_ld_miss", TILEGX_INSN_LD_MISS, false, "lk" },
3154 { "__insn_ld1s_miss", TILEGX_INSN_LD1S_MISS, false, "lk" },
3155 { "__insn_ld1u_miss", TILEGX_INSN_LD1U_MISS, false, "lk" },
3156 { "__insn_ld2s_miss", TILEGX_INSN_LD2S_MISS, false, "lk" },
3157 { "__insn_ld2u_miss", TILEGX_INSN_LD2U_MISS, false, "lk" },
3158 { "__insn_ld4s_miss", TILEGX_INSN_LD4S_MISS, false, "lk" },
3159 { "__insn_ld4u_miss", TILEGX_INSN_LD4U_MISS, false, "lk" },
3160 { "__insn_ldna_miss", TILEGX_INSN_LDNA_MISS, false, "lk" },
3161 { "__insn_ldnt_miss", TILEGX_INSN_LDNT_MISS, false, "lk" },
3162 { "__insn_ldnt1s_miss", TILEGX_INSN_LDNT1S_MISS, false, "lk" },
3163 { "__insn_ldnt1u_miss", TILEGX_INSN_LDNT1U_MISS, false, "lk" },
3164 { "__insn_ldnt2s_miss", TILEGX_INSN_LDNT2S_MISS, false, "lk" },
3165 { "__insn_ldnt2u_miss", TILEGX_INSN_LDNT2U_MISS, false, "lk" },
3166 { "__insn_ldnt4s_miss", TILEGX_INSN_LDNT4S_MISS, false, "lk" },
3167 { "__insn_ldnt4u_miss", TILEGX_INSN_LDNT4U_MISS, false, "lk" },
3168 { "__insn_lnk", TILEGX_INSN_LNK, true, "l" },
3169 { "__insn_mf", TILEGX_INSN_MF, false, "v" },
3170 { "__insn_mfspr", TILEGX_INSN_MFSPR, false, "ll" },
3171 { "__insn_mm", TILEGX_INSN_MM, true, "lllll"},
3172 { "__insn_mnz", TILEGX_INSN_MNZ, true, "lll" },
3173 { "__insn_move", TILEGX_INSN_MOVE, true, "ll" },
3174 { "__insn_movei", TILEGX_INSN_MOVE, true, "ll" },
3175 { "__insn_moveli", TILEGX_INSN_MOVE, true, "ll" },
3176 { "__insn_mtspr", TILEGX_INSN_MTSPR, false, "vll" },
3177 { "__insn_mul_hs_hs", TILEGX_INSN_MUL_HS_HS, true, "lll" },
3178 { "__insn_mul_hs_hu", TILEGX_INSN_MUL_HS_HU, true, "lll" },
3179 { "__insn_mul_hs_ls", TILEGX_INSN_MUL_HS_LS, true, "lll" },
3180 { "__insn_mul_hs_lu", TILEGX_INSN_MUL_HS_LU, true, "lll" },
3181 { "__insn_mul_hu_hu", TILEGX_INSN_MUL_HU_HU, true, "lll" },
3182 { "__insn_mul_hu_ls", TILEGX_INSN_MUL_HU_LS, true, "lll" },
3183 { "__insn_mul_hu_lu", TILEGX_INSN_MUL_HU_LU, true, "lll" },
3184 { "__insn_mul_ls_ls", TILEGX_INSN_MUL_LS_LS, true, "lll" },
3185 { "__insn_mul_ls_lu", TILEGX_INSN_MUL_LS_LU, true, "lll" },
3186 { "__insn_mul_lu_lu", TILEGX_INSN_MUL_LU_LU, true, "lll" },
3187 { "__insn_mula_hs_hs", TILEGX_INSN_MULA_HS_HS, true, "llll" },
3188 { "__insn_mula_hs_hu", TILEGX_INSN_MULA_HS_HU, true, "llll" },
3189 { "__insn_mula_hs_ls", TILEGX_INSN_MULA_HS_LS, true, "llll" },
3190 { "__insn_mula_hs_lu", TILEGX_INSN_MULA_HS_LU, true, "llll" },
3191 { "__insn_mula_hu_hu", TILEGX_INSN_MULA_HU_HU, true, "llll" },
3192 { "__insn_mula_hu_ls", TILEGX_INSN_MULA_HU_LS, true, "llll" },
3193 { "__insn_mula_hu_lu", TILEGX_INSN_MULA_HU_LU, true, "llll" },
3194 { "__insn_mula_ls_ls", TILEGX_INSN_MULA_LS_LS, true, "llll" },
3195 { "__insn_mula_ls_lu", TILEGX_INSN_MULA_LS_LU, true, "llll" },
3196 { "__insn_mula_lu_lu", TILEGX_INSN_MULA_LU_LU, true, "llll" },
3197 { "__insn_mulax", TILEGX_INSN_MULAX, true, "iiii" },
3198 { "__insn_mulx", TILEGX_INSN_MULX, true, "iii" },
3199 { "__insn_mz", TILEGX_INSN_MZ, true, "lll" },
3200 { "__insn_nap", TILEGX_INSN_NAP, false, "v" },
3201 { "__insn_nop", TILEGX_INSN_NOP, true, "v" },
3202 { "__insn_nor", TILEGX_INSN_NOR, true, "lll" },
3203 { "__insn_or", TILEGX_INSN_OR, true, "lll" },
3204 { "__insn_ori", TILEGX_INSN_OR, true, "lll" },
3205 { "__insn_pcnt", TILEGX_INSN_PCNT, true, "ll" },
3206 { "__insn_prefetch", TILEGX_INSN_PREFETCH_L1, false, "vk" },
3207 { "__insn_prefetch_l1", TILEGX_INSN_PREFETCH_L1, false, "vk" },
3208 { "__insn_prefetch_l1_fault", TILEGX_INSN_PREFETCH_L1_FAULT, false, "vk" },
3209 { "__insn_prefetch_l2", TILEGX_INSN_PREFETCH_L2, false, "vk" },
3210 { "__insn_prefetch_l2_fault", TILEGX_INSN_PREFETCH_L2_FAULT, false, "vk" },
3211 { "__insn_prefetch_l3", TILEGX_INSN_PREFETCH_L3, false, "vk" },
3212 { "__insn_prefetch_l3_fault", TILEGX_INSN_PREFETCH_L3_FAULT, false, "vk" },
3213 { "__insn_revbits", TILEGX_INSN_REVBITS, true, "ll" },
3214 { "__insn_revbytes", TILEGX_INSN_REVBYTES, true, "ll" },
3215 { "__insn_rotl", TILEGX_INSN_ROTL, true, "lli" },
3216 { "__insn_rotli", TILEGX_INSN_ROTL, true, "lli" },
3217 { "__insn_shl", TILEGX_INSN_SHL, true, "lli" },
3218 { "__insn_shl16insli", TILEGX_INSN_SHL16INSLI, true, "lll" },
3219 { "__insn_shl1add", TILEGX_INSN_SHL1ADD, true, "lll" },
3220 { "__insn_shl1addx", TILEGX_INSN_SHL1ADDX, true, "iii" },
3221 { "__insn_shl2add", TILEGX_INSN_SHL2ADD, true, "lll" },
3222 { "__insn_shl2addx", TILEGX_INSN_SHL2ADDX, true, "iii" },
3223 { "__insn_shl3add", TILEGX_INSN_SHL3ADD, true, "lll" },
3224 { "__insn_shl3addx", TILEGX_INSN_SHL3ADDX, true, "iii" },
3225 { "__insn_shli", TILEGX_INSN_SHL, true, "lli" },
3226 { "__insn_shlx", TILEGX_INSN_SHLX, true, "iii" },
3227 { "__insn_shlxi", TILEGX_INSN_SHLX, true, "iii" },
3228 { "__insn_shrs", TILEGX_INSN_SHRS, true, "lli" },
3229 { "__insn_shrsi", TILEGX_INSN_SHRS, true, "lli" },
3230 { "__insn_shru", TILEGX_INSN_SHRU, true, "lli" },
3231 { "__insn_shrui", TILEGX_INSN_SHRU, true, "lli" },
3232 { "__insn_shrux", TILEGX_INSN_SHRUX, true, "iii" },
3233 { "__insn_shruxi", TILEGX_INSN_SHRUX, true, "iii" },
3234 { "__insn_shufflebytes", TILEGX_INSN_SHUFFLEBYTES, true, "llll" },
0051d3ec 3235 { "__insn_shufflebytes1", TILEGX_INSN_SHUFFLEBYTES1, true, "lll" },
dd552284
WL
3236 { "__insn_st", TILEGX_INSN_ST, false, "vpl" },
3237 { "__insn_st1", TILEGX_INSN_ST1, false, "vpl" },
3238 { "__insn_st2", TILEGX_INSN_ST2, false, "vpl" },
3239 { "__insn_st4", TILEGX_INSN_ST4, false, "vpl" },
3240 { "__insn_stnt", TILEGX_INSN_STNT, false, "vpl" },
3241 { "__insn_stnt1", TILEGX_INSN_STNT1, false, "vpl" },
3242 { "__insn_stnt2", TILEGX_INSN_STNT2, false, "vpl" },
3243 { "__insn_stnt4", TILEGX_INSN_STNT4, false, "vpl" },
3244 { "__insn_sub", TILEGX_INSN_SUB, true, "lll" },
3245 { "__insn_subx", TILEGX_INSN_SUBX, true, "iii" },
3246 { "__insn_subxsc", TILEGX_INSN_SUBXSC, true, "iii" },
3247 { "__insn_tblidxb0", TILEGX_INSN_TBLIDXB0, true, "lll" },
3248 { "__insn_tblidxb1", TILEGX_INSN_TBLIDXB1, true, "lll" },
3249 { "__insn_tblidxb2", TILEGX_INSN_TBLIDXB2, true, "lll" },
3250 { "__insn_tblidxb3", TILEGX_INSN_TBLIDXB3, true, "lll" },
3251 { "__insn_v1add", TILEGX_INSN_V1ADD, true, "lll" },
3252 { "__insn_v1addi", TILEGX_INSN_V1ADDI, true, "lll" },
3253 { "__insn_v1adduc", TILEGX_INSN_V1ADDUC, true, "lll" },
3254 { "__insn_v1adiffu", TILEGX_INSN_V1ADIFFU, true, "lll" },
3255 { "__insn_v1avgu", TILEGX_INSN_V1AVGU, true, "lll" },
3256 { "__insn_v1cmpeq", TILEGX_INSN_V1CMPEQ, true, "lll" },
3257 { "__insn_v1cmpeqi", TILEGX_INSN_V1CMPEQI, true, "lll" },
3258 { "__insn_v1cmples", TILEGX_INSN_V1CMPLES, true, "lll" },
3259 { "__insn_v1cmpleu", TILEGX_INSN_V1CMPLEU, true, "lll" },
3260 { "__insn_v1cmplts", TILEGX_INSN_V1CMPLTS, true, "lll" },
3261 { "__insn_v1cmpltsi", TILEGX_INSN_V1CMPLTSI, true, "lll" },
3262 { "__insn_v1cmpltu", TILEGX_INSN_V1CMPLTU, true, "lll" },
3263 { "__insn_v1cmpltui", TILEGX_INSN_V1CMPLTUI, true, "lll" },
3264 { "__insn_v1cmpne", TILEGX_INSN_V1CMPNE, true, "lll" },
3265 { "__insn_v1ddotpu", TILEGX_INSN_V1DDOTPU, true, "lll" },
3266 { "__insn_v1ddotpua", TILEGX_INSN_V1DDOTPUA, true, "llll" },
3267 { "__insn_v1ddotpus", TILEGX_INSN_V1DDOTPUS, true, "lll" },
3268 { "__insn_v1ddotpusa", TILEGX_INSN_V1DDOTPUSA, true, "llll" },
3269 { "__insn_v1dotp", TILEGX_INSN_V1DOTP, true, "lll" },
3270 { "__insn_v1dotpa", TILEGX_INSN_V1DOTPA, true, "llll" },
3271 { "__insn_v1dotpu", TILEGX_INSN_V1DOTPU, true, "lll" },
3272 { "__insn_v1dotpua", TILEGX_INSN_V1DOTPUA, true, "llll" },
3273 { "__insn_v1dotpus", TILEGX_INSN_V1DOTPUS, true, "lll" },
3274 { "__insn_v1dotpusa", TILEGX_INSN_V1DOTPUSA, true, "llll" },
3275 { "__insn_v1int_h", TILEGX_INSN_V1INT_H, true, "lll" },
3276 { "__insn_v1int_l", TILEGX_INSN_V1INT_L, true, "lll" },
3277 { "__insn_v1maxu", TILEGX_INSN_V1MAXU, true, "lll" },
3278 { "__insn_v1maxui", TILEGX_INSN_V1MAXUI, true, "lll" },
3279 { "__insn_v1minu", TILEGX_INSN_V1MINU, true, "lll" },
3280 { "__insn_v1minui", TILEGX_INSN_V1MINUI, true, "lll" },
3281 { "__insn_v1mnz", TILEGX_INSN_V1MNZ, true, "lll" },
3282 { "__insn_v1multu", TILEGX_INSN_V1MULTU, true, "lll" },
3283 { "__insn_v1mulu", TILEGX_INSN_V1MULU, true, "lll" },
3284 { "__insn_v1mulus", TILEGX_INSN_V1MULUS, true, "lll" },
3285 { "__insn_v1mz", TILEGX_INSN_V1MZ, true, "lll" },
3286 { "__insn_v1sadau", TILEGX_INSN_V1SADAU, true, "llll" },
3287 { "__insn_v1sadu", TILEGX_INSN_V1SADU, true, "lll" },
3288 { "__insn_v1shl", TILEGX_INSN_V1SHL, true, "lll" },
3289 { "__insn_v1shli", TILEGX_INSN_V1SHLI, true, "lll" },
3290 { "__insn_v1shrs", TILEGX_INSN_V1SHRS, true, "lll" },
3291 { "__insn_v1shrsi", TILEGX_INSN_V1SHRSI, true, "lll" },
3292 { "__insn_v1shru", TILEGX_INSN_V1SHRU, true, "lll" },
3293 { "__insn_v1shrui", TILEGX_INSN_V1SHRUI, true, "lll" },
3294 { "__insn_v1sub", TILEGX_INSN_V1SUB, true, "lll" },
3295 { "__insn_v1subuc", TILEGX_INSN_V1SUBUC, true, "lll" },
3296 { "__insn_v2add", TILEGX_INSN_V2ADD, true, "lll" },
3297 { "__insn_v2addi", TILEGX_INSN_V2ADDI, true, "lll" },
3298 { "__insn_v2addsc", TILEGX_INSN_V2ADDSC, true, "lll" },
3299 { "__insn_v2adiffs", TILEGX_INSN_V2ADIFFS, true, "lll" },
3300 { "__insn_v2avgs", TILEGX_INSN_V2AVGS, true, "lll" },
3301 { "__insn_v2cmpeq", TILEGX_INSN_V2CMPEQ, true, "lll" },
3302 { "__insn_v2cmpeqi", TILEGX_INSN_V2CMPEQI, true, "lll" },
3303 { "__insn_v2cmples", TILEGX_INSN_V2CMPLES, true, "lll" },
3304 { "__insn_v2cmpleu", TILEGX_INSN_V2CMPLEU, true, "lll" },
3305 { "__insn_v2cmplts", TILEGX_INSN_V2CMPLTS, true, "lll" },
3306 { "__insn_v2cmpltsi", TILEGX_INSN_V2CMPLTSI, true, "lll" },
3307 { "__insn_v2cmpltu", TILEGX_INSN_V2CMPLTU, true, "lll" },
3308 { "__insn_v2cmpltui", TILEGX_INSN_V2CMPLTUI, true, "lll" },
3309 { "__insn_v2cmpne", TILEGX_INSN_V2CMPNE, true, "lll" },
3310 { "__insn_v2dotp", TILEGX_INSN_V2DOTP, true, "lll" },
3311 { "__insn_v2dotpa", TILEGX_INSN_V2DOTPA, true, "llll" },
3312 { "__insn_v2int_h", TILEGX_INSN_V2INT_H, true, "lll" },
3313 { "__insn_v2int_l", TILEGX_INSN_V2INT_L, true, "lll" },
3314 { "__insn_v2maxs", TILEGX_INSN_V2MAXS, true, "lll" },
3315 { "__insn_v2maxsi", TILEGX_INSN_V2MAXSI, true, "lll" },
3316 { "__insn_v2mins", TILEGX_INSN_V2MINS, true, "lll" },
3317 { "__insn_v2minsi", TILEGX_INSN_V2MINSI, true, "lll" },
3318 { "__insn_v2mnz", TILEGX_INSN_V2MNZ, true, "lll" },
3319 { "__insn_v2mulfsc", TILEGX_INSN_V2MULFSC, true, "lll" },
3320 { "__insn_v2muls", TILEGX_INSN_V2MULS, true, "lll" },
3321 { "__insn_v2mults", TILEGX_INSN_V2MULTS, true, "lll" },
3322 { "__insn_v2mz", TILEGX_INSN_V2MZ, true, "lll" },
3323 { "__insn_v2packh", TILEGX_INSN_V2PACKH, true, "lll" },
3324 { "__insn_v2packl", TILEGX_INSN_V2PACKL, true, "lll" },
3325 { "__insn_v2packuc", TILEGX_INSN_V2PACKUC, true, "lll" },
3326 { "__insn_v2sadas", TILEGX_INSN_V2SADAS, true, "llll" },
3327 { "__insn_v2sadau", TILEGX_INSN_V2SADAU, true, "llll" },
3328 { "__insn_v2sads", TILEGX_INSN_V2SADS, true, "lll" },
3329 { "__insn_v2sadu", TILEGX_INSN_V2SADU, true, "lll" },
3330 { "__insn_v2shl", TILEGX_INSN_V2SHL, true, "lll" },
3331 { "__insn_v2shli", TILEGX_INSN_V2SHLI, true, "lll" },
3332 { "__insn_v2shlsc", TILEGX_INSN_V2SHLSC, true, "lll" },
3333 { "__insn_v2shrs", TILEGX_INSN_V2SHRS, true, "lll" },
3334 { "__insn_v2shrsi", TILEGX_INSN_V2SHRSI, true, "lll" },
3335 { "__insn_v2shru", TILEGX_INSN_V2SHRU, true, "lll" },
3336 { "__insn_v2shrui", TILEGX_INSN_V2SHRUI, true, "lll" },
3337 { "__insn_v2sub", TILEGX_INSN_V2SUB, true, "lll" },
3338 { "__insn_v2subsc", TILEGX_INSN_V2SUBSC, true, "lll" },
3339 { "__insn_v4add", TILEGX_INSN_V4ADD, true, "lll" },
3340 { "__insn_v4addsc", TILEGX_INSN_V4ADDSC, true, "lll" },
3341 { "__insn_v4int_h", TILEGX_INSN_V4INT_H, true, "lll" },
3342 { "__insn_v4int_l", TILEGX_INSN_V4INT_L, true, "lll" },
3343 { "__insn_v4packsc", TILEGX_INSN_V4PACKSC, true, "lll" },
3344 { "__insn_v4shl", TILEGX_INSN_V4SHL, true, "lll" },
3345 { "__insn_v4shlsc", TILEGX_INSN_V4SHLSC, true, "lll" },
3346 { "__insn_v4shrs", TILEGX_INSN_V4SHRS, true, "lll" },
3347 { "__insn_v4shru", TILEGX_INSN_V4SHRU, true, "lll" },
3348 { "__insn_v4sub", TILEGX_INSN_V4SUB, true, "lll" },
3349 { "__insn_v4subsc", TILEGX_INSN_V4SUBSC, true, "lll" },
3350 { "__insn_wh64", TILEGX_INSN_WH64, false, "vp" },
3351 { "__insn_xor", TILEGX_INSN_XOR, true, "lll" },
3352 { "__insn_xori", TILEGX_INSN_XOR, true, "lll" },
3353 { "__tile_network_barrier", TILEGX_NETWORK_BARRIER, false, "v" },
3354 { "__tile_idn0_receive", TILEGX_IDN0_RECEIVE, false, "l" },
3355 { "__tile_idn1_receive", TILEGX_IDN1_RECEIVE, false, "l" },
3356 { "__tile_idn_send", TILEGX_IDN_SEND, false, "vl" },
3357 { "__tile_udn0_receive", TILEGX_UDN0_RECEIVE, false, "l" },
3358 { "__tile_udn1_receive", TILEGX_UDN1_RECEIVE, false, "l" },
3359 { "__tile_udn2_receive", TILEGX_UDN2_RECEIVE, false, "l" },
3360 { "__tile_udn3_receive", TILEGX_UDN3_RECEIVE, false, "l" },
3361 { "__tile_udn_send", TILEGX_UDN_SEND, false, "vl" },
3362};
3363
3364
3365/* Convert a character in a builtin type string to a tree type. */
3366static tree
3367char_to_type (char c)
3368{
3369 static tree volatile_ptr_type_node = NULL;
3370 static tree volatile_const_ptr_type_node = NULL;
3371
3372 if (volatile_ptr_type_node == NULL)
3373 {
3374 volatile_ptr_type_node =
3375 build_pointer_type (build_qualified_type (void_type_node,
3376 TYPE_QUAL_VOLATILE));
3377 volatile_const_ptr_type_node =
3378 build_pointer_type (build_qualified_type (void_type_node,
3379 TYPE_QUAL_CONST
3380 | TYPE_QUAL_VOLATILE));
3381 }
3382
3383 switch (c)
3384 {
3385 case 'v':
3386 return void_type_node;
3387 case 'i':
3388 return unsigned_type_node;
3389 case 'l':
3390 return long_long_unsigned_type_node;
3391 case 'p':
3392 return volatile_ptr_type_node;
3393 case 'k':
3394 return volatile_const_ptr_type_node;
3395 default:
3396 gcc_unreachable ();
3397 }
3398}
3399
3400
3401/* Implement TARGET_INIT_BUILTINS. */
3402static void
3403tilegx_init_builtins (void)
3404{
3405 size_t i;
3406
3407 for (i = 0; i < ARRAY_SIZE (tilegx_builtins); i++)
3408 {
3409 const struct tilegx_builtin_def *p = &tilegx_builtins[i];
3410 tree ftype, ret_type, arg_type_list = void_list_node;
3411 tree decl;
3412 int j;
3413
3414 for (j = strlen (p->type) - 1; j > 0; j--)
3415 {
3416 arg_type_list =
3417 tree_cons (NULL_TREE, char_to_type (p->type[j]), arg_type_list);
3418 }
3419
3420 ret_type = char_to_type (p->type[0]);
3421
3422 ftype = build_function_type (ret_type, arg_type_list);
3423
3424 decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
3425 NULL, NULL);
3426
3427 if (p->is_const)
3428 TREE_READONLY (decl) = 1;
3429 TREE_NOTHROW (decl) = 1;
3430
3431 if (tilegx_builtin_info[p->code].fndecl == NULL)
3432 tilegx_builtin_info[p->code].fndecl = decl;
3433 }
3434}
3435
3436
3437/* Implement TARGET_EXPAND_BUILTIN. */
3438static rtx
3439tilegx_expand_builtin (tree exp,
3440 rtx target,
3441 rtx subtarget ATTRIBUTE_UNUSED,
3442 enum machine_mode mode ATTRIBUTE_UNUSED,
3443 int ignore ATTRIBUTE_UNUSED)
3444{
3445#define MAX_BUILTIN_ARGS 4
3446
3447 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
3448 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
3449 tree arg;
3450 call_expr_arg_iterator iter;
3451 enum insn_code icode;
3452 rtx op[MAX_BUILTIN_ARGS + 1], pat;
3453 int opnum;
3454 bool nonvoid;
3455 insn_gen_fn fn;
3456
3457 if (fcode >= TILEGX_BUILTIN_max)
3458 internal_error ("bad builtin fcode");
3459 icode = tilegx_builtin_info[fcode].icode;
3460 if (icode == 0)
3461 internal_error ("bad builtin icode");
3462
3463 nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
3464
3465 opnum = nonvoid;
3466 FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
3aa775d6
WL
3467 {
3468 const struct insn_operand_data *insn_op;
dd552284 3469
3aa775d6
WL
3470 if (arg == error_mark_node)
3471 return NULL_RTX;
3472 if (opnum > MAX_BUILTIN_ARGS)
3473 return NULL_RTX;
dd552284 3474
3aa775d6 3475 insn_op = &insn_data[icode].operand[opnum];
dd552284 3476
3aa775d6 3477 op[opnum] = expand_expr (arg, NULL_RTX, insn_op->mode, EXPAND_NORMAL);
dd552284 3478
3aa775d6
WL
3479 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3480 {
3481 enum machine_mode opmode = insn_op->mode;
dd552284 3482
3aa775d6
WL
3483 /* pointer_operand and pmode_register_operand operands do
3484 not specify a mode, so use the operand's mode instead
3485 (which should always be right by the time we get here,
3486 except for constants, which are VOIDmode). */
3487 if (opmode == VOIDmode)
3488 {
3489 enum machine_mode m = GET_MODE (op[opnum]);
3490 gcc_assert (m == Pmode || m == VOIDmode);
3491 opmode = Pmode;
3492 }
dd552284 3493
3aa775d6
WL
3494 op[opnum] = copy_to_mode_reg (opmode, op[opnum]);
3495 }
dd552284 3496
3aa775d6
WL
3497 if (!(*insn_op->predicate) (op[opnum], insn_op->mode))
3498 {
3499 /* We still failed to meet the predicate even after moving
3500 into a register. Assume we needed an immediate. */
3501 error_at (EXPR_LOCATION (exp),
3502 "operand must be an immediate of the right size");
3503 return const0_rtx;
3504 }
dd552284 3505
3aa775d6
WL
3506 opnum++;
3507 }
dd552284
WL
3508
3509 if (nonvoid)
3510 {
3511 enum machine_mode tmode = insn_data[icode].operand[0].mode;
3512 if (!target
3513 || GET_MODE (target) != tmode
3514 || !(*insn_data[icode].operand[0].predicate) (target, tmode))
3515 {
3516 if (tmode == VOIDmode)
3517 {
3518 /* get the mode from the return type. */
3519 tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl)));
3520 }
3521 target = gen_reg_rtx (tmode);
3522 }
3523 op[0] = target;
3524 }
3525
3526 fn = GEN_FCN (icode);
3527 switch (opnum)
3528 {
3529 case 0:
3530 pat = fn (NULL_RTX);
3531 break;
3532 case 1:
3533 pat = fn (op[0]);
3534 break;
3535 case 2:
3536 pat = fn (op[0], op[1]);
3537 break;
3538 case 3:
3539 pat = fn (op[0], op[1], op[2]);
3540 break;
3541 case 4:
3542 pat = fn (op[0], op[1], op[2], op[3]);
3543 break;
3544 case 5:
3545 pat = fn (op[0], op[1], op[2], op[3], op[4]);
3546 break;
3547 default:
3548 gcc_unreachable ();
3549 }
3550 if (!pat)
3551 return NULL_RTX;
3552 emit_insn (pat);
3553
3554 if (nonvoid)
3555 return target;
3556 else
3557 return const0_rtx;
3558}
3559
3560
3561/* Implement TARGET_BUILTIN_DECL. */
3562static tree
3563tilegx_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
3564{
3565 if (code >= TILEGX_BUILTIN_max)
3566 return error_mark_node;
3567
3568 return tilegx_builtin_info[code].fndecl;
3569}
3570\f
3571
3572
3573/* Stack frames */
3574
3575/* Return whether REGNO needs to be saved in the stack frame. */
3576static bool
3577need_to_save_reg (unsigned int regno)
3578{
3579 if (!fixed_regs[regno] && !call_used_regs[regno]
3580 && df_regs_ever_live_p (regno))
3581 return true;
3582
3583 if (flag_pic
3584 && (regno == PIC_OFFSET_TABLE_REGNUM
3585 || regno == TILEGX_PIC_TEXT_LABEL_REGNUM)
3586 && (crtl->uses_pic_offset_table || crtl->saves_all_registers))
3587 return true;
3588
3589 if (crtl->calls_eh_return)
3590 {
3591 unsigned i;
3592 for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; i++)
3593 {
3594 if (regno == EH_RETURN_DATA_REGNO (i))
3595 return true;
3596 }
3597 }
3598
3599 return false;
3600}
3601
3602
3603/* Return the size of the register savev area. This function is only
3604 correct starting with local register allocation */
3605static int
3606tilegx_saved_regs_size (void)
3607{
3608 int reg_save_size = 0;
3609 int regno;
3610 int offset_to_frame;
3611 int align_mask;
3612
3613 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3614 if (need_to_save_reg (regno))
3615 reg_save_size += UNITS_PER_WORD;
3616
3617 /* Pad out the register save area if necessary to make
3618 frame_pointer_rtx be as aligned as the stack pointer. */
3619 offset_to_frame = crtl->args.pretend_args_size + reg_save_size;
3620 align_mask = (STACK_BOUNDARY / BITS_PER_UNIT) - 1;
3621 reg_save_size += (-offset_to_frame) & align_mask;
3622
3623 return reg_save_size;
3624}
3625
3626
3627/* Round up frame size SIZE. */
3628static int
3629round_frame_size (int size)
3630{
3631 return ((size + STACK_BOUNDARY / BITS_PER_UNIT - 1)
3632 & -STACK_BOUNDARY / BITS_PER_UNIT);
3633}
3634
3635
3636/* Emit a store in the stack frame to save REGNO at address ADDR, and
3637 emit the corresponding REG_CFA_OFFSET note described by CFA and
3638 CFA_OFFSET. Return the emitted insn. */
3639static rtx
3640frame_emit_store (int regno, int regno_note, rtx addr, rtx cfa,
3641 int cfa_offset)
3642{
3643 rtx reg = gen_rtx_REG (DImode, regno);
3644 rtx mem = gen_frame_mem (DImode, addr);
3645 rtx mov = gen_movdi (mem, reg);
3646
3647 /* Describe what just happened in a way that dwarf understands. We
3648 use temporary registers to hold the address to make scheduling
3649 easier, and use the REG_CFA_OFFSET to describe the address as an
3650 offset from the CFA. */
3651 rtx reg_note = gen_rtx_REG (DImode, regno_note);
3652 rtx cfa_relative_addr = gen_rtx_PLUS (Pmode, cfa, GEN_INT (cfa_offset));
3653 rtx cfa_relative_mem = gen_frame_mem (DImode, cfa_relative_addr);
3654 rtx real = gen_rtx_SET (VOIDmode, cfa_relative_mem, reg_note);
3655 add_reg_note (mov, REG_CFA_OFFSET, real);
3656
3657 return emit_insn (mov);
3658}
3659
3660
3661/* Emit a load in the stack frame to load REGNO from address ADDR.
3662 Add a REG_CFA_RESTORE note to CFA_RESTORES if CFA_RESTORES is
3663 non-null. Return the emitted insn. */
3664static rtx
3665frame_emit_load (int regno, rtx addr, rtx *cfa_restores)
3666{
3667 rtx reg = gen_rtx_REG (DImode, regno);
3668 rtx mem = gen_frame_mem (DImode, addr);
3669 if (cfa_restores)
3670 *cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, *cfa_restores);
3671 return emit_insn (gen_movdi (reg, mem));
3672}
3673
3674
3675/* Helper function to set RTX_FRAME_RELATED_P on instructions,
3676 including sequences. */
3677static rtx
3678set_frame_related_p (void)
3679{
3680 rtx seq = get_insns ();
3681 rtx insn;
3682
3683 end_sequence ();
3684
3685 if (!seq)
3686 return NULL_RTX;
3687
3688 if (INSN_P (seq))
3689 {
3690 insn = seq;
3691 while (insn != NULL_RTX)
3692 {
3693 RTX_FRAME_RELATED_P (insn) = 1;
3694 insn = NEXT_INSN (insn);
3695 }
3696 seq = emit_insn (seq);
3697 }
3698 else
3699 {
3700 seq = emit_insn (seq);
3701 RTX_FRAME_RELATED_P (seq) = 1;
3702 }
3703 return seq;
3704}
3705
3706
3707#define FRP(exp) (start_sequence (), exp, set_frame_related_p ())
3708
3709/* This emits code for 'sp += offset'.
3710
3711 The ABI only allows us to modify 'sp' in a single 'addi' or
3712 'addli', so the backtracer understands it. Larger amounts cannot
3713 use those instructions, so are added by placing the offset into a
3714 large register and using 'add'.
3715
3716 This happens after reload, so we need to expand it ourselves. */
3717static rtx
3718emit_sp_adjust (int offset, int *next_scratch_regno, bool frame_related,
3719 rtx reg_notes)
3720{
3721 rtx to_add;
3722 rtx imm_rtx = GEN_INT (offset);
3723
3724 rtx insn;
3725 if (satisfies_constraint_J (imm_rtx))
3726 {
3727 /* We can add this using a single immediate add. */
3728 to_add = imm_rtx;
3729 }
3730 else
3731 {
3732 rtx tmp = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3733 tilegx_expand_set_const64 (tmp, imm_rtx);
3734 to_add = tmp;
3735 }
3736
3737 /* Actually adjust the stack pointer. */
3738 if (TARGET_32BIT)
3739 insn = gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx, to_add);
3740 else
3741 insn = gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx, to_add);
3742
3743 insn = emit_insn (insn);
3744 REG_NOTES (insn) = reg_notes;
3745
3746 /* Describe what just happened in a way that dwarf understands. */
3747 if (frame_related)
3748 {
3749 rtx real = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
3750 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3751 imm_rtx));
3752 RTX_FRAME_RELATED_P (insn) = 1;
3753 add_reg_note (insn, REG_CFA_ADJUST_CFA, real);
3754 }
3755
3756 return insn;
3757}
3758
3759
3760/* Return whether the current function is leaf. This takes into
3761 account whether the function calls tls_get_addr. */
3762static bool
3763tilegx_current_function_is_leaf (void)
3764{
416ff32e 3765 return crtl->is_leaf && !cfun->machine->calls_tls_get_addr;
dd552284
WL
3766}
3767
3768
3769/* Return the frame size. */
3770static int
3771compute_total_frame_size (void)
3772{
3773 int total_size = (get_frame_size () + tilegx_saved_regs_size ()
3774 + crtl->outgoing_args_size
3775 + crtl->args.pretend_args_size);
3776
3777 if (!tilegx_current_function_is_leaf () || cfun->calls_alloca)
3778 {
3779 /* Make room for save area in callee. */
3780 total_size += STACK_POINTER_OFFSET;
3781 }
3782
3783 return round_frame_size (total_size);
3784}
3785
3786
3787/* Return nonzero if this function is known to have a null epilogue.
3788 This allows the optimizer to omit jumps to jumps if no stack was
3789 created. */
3790bool
3791tilegx_can_use_return_insn_p (void)
3792{
3793 return (reload_completed
3794 && cfun->static_chain_decl == 0
3795 && compute_total_frame_size () == 0
3796 && tilegx_current_function_is_leaf ()
3797 && !crtl->profile && !df_regs_ever_live_p (TILEGX_LINK_REGNUM));
3798}
3799
3800
3801/* Returns an rtx for a stack slot at 'FP + offset_from_fp'. If there
3802 is a frame pointer, it computes the value relative to
3803 that. Otherwise it uses the stack pointer. */
3804static rtx
3805compute_frame_addr (int offset_from_fp, int *next_scratch_regno)
3806{
3807 rtx base_reg_rtx, tmp_reg_rtx, offset_rtx;
3808 int offset_from_base;
3809
3810 if (frame_pointer_needed)
3811 {
3812 base_reg_rtx = hard_frame_pointer_rtx;
3813 offset_from_base = offset_from_fp;
3814 }
3815 else
3816 {
3817 int offset_from_sp = compute_total_frame_size () + offset_from_fp;
3818 offset_from_base = offset_from_sp;
3819 base_reg_rtx = stack_pointer_rtx;
3820 }
3821
3822 if (offset_from_base == 0)
3823 return base_reg_rtx;
3824
3825 /* Compute the new value of the stack pointer. */
3826 tmp_reg_rtx = gen_rtx_REG (Pmode, (*next_scratch_regno)--);
3827 offset_rtx = GEN_INT (offset_from_base);
3828
3829 if (!add_operand (offset_rtx, Pmode))
3830 {
3831 expand_set_cint64 (tmp_reg_rtx, offset_rtx);
3832 offset_rtx = tmp_reg_rtx;
3833 }
3834
3835 emit_insn (gen_rtx_SET (VOIDmode, tmp_reg_rtx,
3836 gen_rtx_PLUS (Pmode, base_reg_rtx, offset_rtx)));
3837
3838 return tmp_reg_rtx;
3839}
3840
3841
3842/* The stack frame looks like this:
3843 +-------------+
3844 | ... |
3845 | incoming |
3846 | stack args |
3847 AP -> +-------------+
3848 | caller's HFP|
3849 +-------------+
3850 | lr save |
3851 HFP -> +-------------+
3852 | var args |
3853 | reg save | crtl->args.pretend_args_size bytes
3854 +-------------+
3855 | ... |
3856 | saved regs | tilegx_saved_regs_size() bytes
3857 FP -> +-------------+
3858 | ... |
3859 | vars | get_frame_size() bytes
3860 +-------------+
3861 | ... |
3862 | outgoing |
3863 | stack args | crtl->outgoing_args_size bytes
3864 +-------------+
3865 | HFP | ptr_size bytes (only here if nonleaf / alloca)
3866 +-------------+
3867 | callee lr | ptr_size bytes (only here if nonleaf / alloca)
3868 | save |
3869 SP -> +-------------+
3870
3871 HFP == incoming SP.
3872
3873 For functions with a frame larger than 32767 bytes, or which use
3874 alloca (), r52 is used as a frame pointer. Otherwise there is no
3875 frame pointer.
3876
3877 FP is saved at SP+ptr_size before calling a subroutine so the callee
3878 can chain. */
3879void
3880tilegx_expand_prologue (void)
3881{
3882#define ROUND_ROBIN_SIZE 4
3883 /* We round-robin through four scratch registers to hold temporary
3884 addresses for saving registers, to make instruction scheduling
3885 easier. */
3886 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
3887 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
3888 };
3889 rtx insn, cfa;
3890 unsigned int which_scratch;
3891 int offset, start_offset, regno;
3892
3893 /* A register that holds a copy of the incoming fp. */
3894 int fp_copy_regno = -1;
3895
3896 /* A register that holds a copy of the incoming sp. */
3897 int sp_copy_regno = -1;
3898
3899 /* Next scratch register number to hand out (postdecrementing). */
3900 int next_scratch_regno = 29;
3901
3902 int total_size = compute_total_frame_size ();
3903
3904 if (flag_stack_usage_info)
3905 current_function_static_stack_size = total_size;
3906
3907 /* Save lr first in its special location because code after this
3908 might use the link register as a scratch register. */
3909 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM) || crtl->calls_eh_return)
3910 FRP (frame_emit_store (TILEGX_LINK_REGNUM, TILEGX_LINK_REGNUM,
3911 stack_pointer_rtx, stack_pointer_rtx, 0));
3912
3913 if (total_size == 0)
3914 {
3915 /* Load the PIC register if needed. */
3916 if (flag_pic && crtl->uses_pic_offset_table)
3917 load_pic_register (false);
3918
3919 return;
3920 }
3921
3922 cfa = stack_pointer_rtx;
3923
3924 if (frame_pointer_needed)
3925 {
3926 fp_copy_regno = next_scratch_regno--;
3927
3928 /* Copy the old frame pointer aside so we can save it later. */
3929 insn =
3930 FRP (emit_move_insn (gen_rtx_REG (word_mode, fp_copy_regno),
3931 gen_lowpart (word_mode, hard_frame_pointer_rtx)));
3932 add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
3933
3934 /* Set up the frame pointer. */
3935 insn = FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
3936 add_reg_note (insn, REG_CFA_DEF_CFA, hard_frame_pointer_rtx);
3937 cfa = hard_frame_pointer_rtx;
3938 REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
3939
3940 /* fp holds a copy of the incoming sp, in case we need to store
3aa775d6 3941 it. */
dd552284
WL
3942 sp_copy_regno = HARD_FRAME_POINTER_REGNUM;
3943 }
3944 else if (!tilegx_current_function_is_leaf ())
3945 {
3946 /* Copy the old stack pointer aside so we can save it later. */
3947 sp_copy_regno = next_scratch_regno--;
95f2389a
WL
3948 emit_move_insn (gen_rtx_REG (Pmode, sp_copy_regno),
3949 stack_pointer_rtx);
dd552284
WL
3950 }
3951
3952 if (tilegx_current_function_is_leaf ())
3953 {
3954 /* No need to store chain pointer to caller's frame. */
3955 emit_sp_adjust (-total_size, &next_scratch_regno,
3956 !frame_pointer_needed, NULL_RTX);
3957 }
3958 else
3959 {
3960 /* Save the frame pointer (incoming sp value) to support
3961 backtracing. First we need to create an rtx with the store
3962 address. */
3963 rtx chain_addr = gen_rtx_REG (Pmode, next_scratch_regno--);
3964 rtx size_rtx = GEN_INT (-(total_size - UNITS_PER_WORD));
dd552284
WL
3965
3966 if (add_operand (size_rtx, Pmode))
3967 {
3968 /* Expose more parallelism by computing this value from the
3969 original stack pointer, not the one after we have pushed
3970 the frame. */
3971 rtx p = gen_rtx_PLUS (Pmode, stack_pointer_rtx, size_rtx);
3972 emit_insn (gen_rtx_SET (VOIDmode, chain_addr, p));
3973 emit_sp_adjust (-total_size, &next_scratch_regno,
3974 !frame_pointer_needed, NULL_RTX);
3975 }
3976 else
3977 {
3978 /* The stack frame is large, so just store the incoming sp
3979 value at *(new_sp + UNITS_PER_WORD). */
3980 rtx p;
3981 emit_sp_adjust (-total_size, &next_scratch_regno,
3982 !frame_pointer_needed, NULL_RTX);
3983 p = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3984 GEN_INT (UNITS_PER_WORD));
3985 emit_insn (gen_rtx_SET (VOIDmode, chain_addr, p));
3986 }
3987
3988 /* Save our frame pointer for backtrace chaining. */
95f2389a
WL
3989 emit_insn (gen_movdi (gen_frame_mem (DImode, chain_addr),
3990 gen_rtx_REG (DImode, sp_copy_regno)));
dd552284
WL
3991 }
3992
3993 /* Compute where to start storing registers we need to save. */
3994 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
3995 offset = start_offset;
3996
3997 /* Store all registers that need saving. */
3998 which_scratch = 0;
3999 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
4000 if (need_to_save_reg (regno))
4001 {
4002 rtx r = reg_save_addr[which_scratch];
4003 int from_regno;
4004 int cfa_offset = frame_pointer_needed ? offset : total_size + offset;
4005
4006 if (r == NULL_RTX)
4007 {
0a514f47
WL
4008 int prev_scratch_regno = next_scratch_regno;
4009 r = compute_frame_addr (offset, &next_scratch_regno);
4010 if (prev_scratch_regno != next_scratch_regno)
4011 reg_save_addr[which_scratch] = r;
dd552284
WL
4012 }
4013 else
4014 {
4015 /* Advance to the next stack slot to store this
4016 register. */
4017 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
4018 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
4019 emit_insn (gen_rtx_SET (VOIDmode, r, p));
4020 }
4021
4022 /* Save this register to the stack (but use the old fp value
4023 we copied aside if appropriate). */
4024 from_regno =
4025 (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM)
4026 ? fp_copy_regno : regno;
4027 FRP (frame_emit_store (from_regno, regno, r, cfa, cfa_offset));
4028
4029 offset -= UNITS_PER_WORD;
4030 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
4031 }
4032
4033 /* If profiling, force that to happen after the frame is set up. */
4034 if (crtl->profile)
4035 emit_insn (gen_blockage ());
4036
4037 /* Load the PIC register if needed. */
4038 if (flag_pic && crtl->uses_pic_offset_table)
4039 load_pic_register (false);
4040}
4041
4042
4043/* Implement the epilogue and sibcall_epilogue patterns. SIBCALL_P is
4044 true for a sibcall_epilogue pattern, and false for an epilogue
4045 pattern. */
4046void
4047tilegx_expand_epilogue (bool sibcall_p)
4048{
4049 /* We round-robin through four scratch registers to hold temporary
4050 addresses for saving registers, to make instruction scheduling
4051 easier. */
4052 rtx reg_save_addr[ROUND_ROBIN_SIZE] = {
4053 NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX
4054 };
4055 rtx last_insn, insn;
4056 unsigned int which_scratch;
4057 int offset, start_offset, regno;
4058 rtx cfa_restores = NULL_RTX;
4059
4060 /* A register that holds a copy of the incoming fp. */
4061 int fp_copy_regno = -1;
4062
4063 /* Next scratch register number to hand out (postdecrementing). */
4064 int next_scratch_regno = 29;
4065
4066 int total_size = compute_total_frame_size ();
4067
4068 last_insn = get_last_insn ();
4069
4070 /* Load lr first since we are going to need it first. */
4071 insn = NULL;
4072 if (df_regs_ever_live_p (TILEGX_LINK_REGNUM))
4073 {
4074 insn = frame_emit_load (TILEGX_LINK_REGNUM,
4075 compute_frame_addr (0, &next_scratch_regno),
4076 &cfa_restores);
4077 }
4078
4079 if (total_size == 0)
4080 {
4081 if (insn)
4082 {
4083 RTX_FRAME_RELATED_P (insn) = 1;
4084 REG_NOTES (insn) = cfa_restores;
4085 }
4086 goto done;
4087 }
4088
4089 /* Compute where to start restoring registers. */
4090 start_offset = -crtl->args.pretend_args_size - UNITS_PER_WORD;
4091 offset = start_offset;
4092
4093 if (frame_pointer_needed)
4094 fp_copy_regno = next_scratch_regno--;
4095
4096 /* Restore all callee-saved registers. */
4097 which_scratch = 0;
4098 for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
4099 if (need_to_save_reg (regno))
4100 {
4101 rtx r = reg_save_addr[which_scratch];
4102 if (r == NULL_RTX)
4103 {
4104 r = compute_frame_addr (offset, &next_scratch_regno);
4105 reg_save_addr[which_scratch] = r;
4106 }
4107 else
4108 {
4109 /* Advance to the next stack slot to store this register. */
4110 int stride = ROUND_ROBIN_SIZE * -UNITS_PER_WORD;
4111 rtx p = gen_rtx_PLUS (Pmode, r, GEN_INT (stride));
4112 emit_insn (gen_rtx_SET (VOIDmode, r, p));
4113 }
4114
4115 if (fp_copy_regno >= 0 && regno == HARD_FRAME_POINTER_REGNUM)
4116 frame_emit_load (fp_copy_regno, r, NULL);
4117 else
4118 frame_emit_load (regno, r, &cfa_restores);
4119
4120 offset -= UNITS_PER_WORD;
4121 which_scratch = (which_scratch + 1) % ROUND_ROBIN_SIZE;
4122 }
4123
4124 if (!tilegx_current_function_is_leaf ())
4125 cfa_restores =
4126 alloc_reg_note (REG_CFA_RESTORE, stack_pointer_rtx, cfa_restores);
4127
4128 emit_insn (gen_blockage ());
4129
95f2389a 4130 if (frame_pointer_needed)
dd552284
WL
4131 {
4132 /* Restore the old stack pointer by copying from the frame
3aa775d6 4133 pointer. */
dd552284
WL
4134 if (TARGET_32BIT)
4135 {
4136 insn = emit_insn (gen_sp_restore_32bit (stack_pointer_rtx,
4137 hard_frame_pointer_rtx));
4138 }
4139 else
4140 {
4141 insn = emit_insn (gen_sp_restore (stack_pointer_rtx,
4142 hard_frame_pointer_rtx));
4143 }
4144 RTX_FRAME_RELATED_P (insn) = 1;
4145 REG_NOTES (insn) = cfa_restores;
4146 add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx);
4147 }
4148 else
4149 {
4150 insn = emit_sp_adjust (total_size, &next_scratch_regno, true,
4151 cfa_restores);
4152 }
4153
95f2389a
WL
4154 if (crtl->calls_eh_return)
4155 {
4156 if (TARGET_32BIT)
4157 emit_insn (gen_sp_adjust_32bit (stack_pointer_rtx, stack_pointer_rtx,
4158 EH_RETURN_STACKADJ_RTX));
4159 else
4160 emit_insn (gen_sp_adjust (stack_pointer_rtx, stack_pointer_rtx,
4161 EH_RETURN_STACKADJ_RTX));
4162 }
4163
dd552284
WL
4164 /* Restore the old frame pointer. */
4165 if (frame_pointer_needed)
4166 {
4167 insn = emit_move_insn (gen_lowpart (DImode, hard_frame_pointer_rtx),
4168 gen_rtx_REG (DImode, fp_copy_regno));
4169 add_reg_note (insn, REG_CFA_RESTORE, hard_frame_pointer_rtx);
4170 }
4171
4172 /* Mark the pic registers as live outside of the function. */
4173 if (flag_pic)
4174 {
4175 emit_use (cfun->machine->text_label_rtx);
4176 emit_use (cfun->machine->got_rtx);
4177 }
4178
4179done:
4180 if (!sibcall_p)
4181 {
4182 emit_jump_insn (gen__return ());
4183 }
4184 else
4185 {
4186 emit_use (gen_rtx_REG (Pmode, TILEGX_LINK_REGNUM));
4187 }
4188
4189 /* Mark all insns we just emitted as frame-related. */
4190 for (; last_insn != NULL_RTX; last_insn = next_insn (last_insn))
4191 RTX_FRAME_RELATED_P (last_insn) = 1;
4192}
4193
4194#undef ROUND_ROBIN_SIZE
4195
4196
4197/* Implement INITIAL_ELIMINATION_OFFSET. */
4198int
4199tilegx_initial_elimination_offset (int from, int to)
4200{
4201 int total_size = compute_total_frame_size ();
4202
4203 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
4204 {
4205 return (total_size - crtl->args.pretend_args_size
4206 - tilegx_saved_regs_size ());
4207 }
4208 else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
4209 {
4210 return -(crtl->args.pretend_args_size + tilegx_saved_regs_size ());
4211 }
4212 else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
4213 {
4214 return STACK_POINTER_OFFSET + total_size;
4215 }
4216 else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
4217 {
4218 return STACK_POINTER_OFFSET;
4219 }
4220 else
4221 gcc_unreachable ();
4222}
4223
4224
4225/* Return an RTX indicating where the return address to the calling
4226 function can be found. */
4227rtx
4228tilegx_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
4229{
4230 if (count != 0)
4231 return const0_rtx;
4232
4233 return get_hard_reg_initial_val (Pmode, TILEGX_LINK_REGNUM);
4234}
4235
4236
4237/* Implement EH_RETURN_HANDLER_RTX. The MEM needs to be volatile to
4238 prevent it from being deleted. */
4239rtx
4240tilegx_eh_return_handler_rtx (void)
4241{
4242 rtx tmp = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
4243 MEM_VOLATILE_P (tmp) = true;
4244 return tmp;
4245}
4246\f
4247
4248
4249/* Registers */
4250
4251/* Implemnet TARGET_CONDITIONAL_REGISTER_USAGE. */
4252static void
4253tilegx_conditional_register_usage (void)
4254{
4255 global_regs[TILEGX_NETORDER_REGNUM] = 1;
4256 /* TILEGX_PIC_TEXT_LABEL_REGNUM is conditionally used. It is a
4257 member of fixed_regs, and therefore must be member of
4258 call_used_regs, but it is not a member of call_really_used_regs[]
4259 because it is not clobbered by a call. */
4260 if (TILEGX_PIC_TEXT_LABEL_REGNUM != INVALID_REGNUM)
4261 {
4262 fixed_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1;
4263 call_used_regs[TILEGX_PIC_TEXT_LABEL_REGNUM] = 1;
4264 }
4265 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
4266 {
4267 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
4268 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
4269 }
4270}
4271
4272
4273/* Implement TARGET_FRAME_POINTER_REQUIRED. */
4274static bool
4275tilegx_frame_pointer_required (void)
4276{
4277 return crtl->calls_eh_return || cfun->calls_alloca;
4278}
4279\f
4280
4281
4282/* Scheduling and reorg */
4283
4284/* Return the length of INSN. LENGTH is the initial length computed
4285 by attributes in the machine-description file. This is where we
4286 account for bundles. */
4287int
4288tilegx_adjust_insn_length (rtx insn, int length)
4289{
4290 enum machine_mode mode = GET_MODE (insn);
4291
4292 /* A non-termininating instruction in a bundle has length 0. */
4293 if (mode == SImode)
4294 return 0;
4295
4296 /* By default, there is not length adjustment. */
4297 return length;
4298}
4299
4300
4301/* Implement TARGET_SCHED_ISSUE_RATE. */
4302static int
4303tilegx_issue_rate (void)
4304{
4305 return 3;
4306}
4307
4308
4309/* Return the rtx for the jump target. */
4310static rtx
4311get_jump_target (rtx branch)
4312{
4313 if (CALL_P (branch))
4314 {
4315 rtx call;
4316 call = PATTERN (branch);
4317
4318 if (GET_CODE (call) == PARALLEL)
4319 call = XVECEXP (call, 0, 0);
4320
4321 if (GET_CODE (call) == SET)
4322 call = SET_SRC (call);
4323
4324 if (GET_CODE (call) == CALL)
4325 return XEXP (XEXP (call, 0), 0);
4326 }
4327 return 0;
4328}
4329
3aa775d6 4330
dd552284
WL
4331/* Implement TARGET_SCHED_ADJUST_COST. */
4332static int
4333tilegx_sched_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
4334{
4335 /* If we have a true dependence, INSN is a call, and DEP_INSN
4336 defines a register that is needed by the call (argument or stack
4337 pointer) , set its latency to 0 so that it can be bundled with
4338 the call. Explicitly check for and exclude the case when
4339 DEP_INSN defines the target of the jump. */
4340 if (CALL_P (insn) && REG_NOTE_KIND (link) == REG_DEP_TRUE)
4341 {
4342 rtx target = get_jump_target (insn);
4343 if (!REG_P (target) || !set_of (target, dep_insn))
4344 return 0;
4345 }
4346
4347 return cost;
4348}
4349
4350
4351/* Skip over irrelevant NOTEs and such and look for the next insn we
4352 would consider bundling. */
4353static rtx
4354next_insn_to_bundle (rtx r, rtx end)
4355{
4356 for (; r != end; r = NEXT_INSN (r))
4357 {
4358 if (NONDEBUG_INSN_P (r)
4359 && GET_CODE (PATTERN (r)) != USE
4360 && GET_CODE (PATTERN (r)) != CLOBBER)
4361 return r;
4362 }
4363
4364 return NULL_RTX;
4365}
4366
4367
4368/* Go through all insns, and use the information generated during
4369 scheduling to generate SEQUENCEs to represent bundles of
4370 instructions issued simultaneously. */
4371static void
4372tilegx_gen_bundles (void)
4373{
4374 basic_block bb;
4375 FOR_EACH_BB (bb)
3aa775d6
WL
4376 {
4377 rtx insn, next;
4378 rtx end = NEXT_INSN (BB_END (bb));
dd552284 4379
3aa775d6
WL
4380 for (insn = next_insn_to_bundle (BB_HEAD (bb), end); insn; insn = next)
4381 {
4382 next = next_insn_to_bundle (NEXT_INSN (insn), end);
dd552284 4383
3aa775d6
WL
4384 /* Never wrap {} around inline asm. */
4385 if (GET_CODE (PATTERN (insn)) != ASM_INPUT)
4386 {
4387 if (next == NULL_RTX || GET_MODE (next) == TImode
4388 /* NOTE: The scheduler incorrectly believes a call
4389 insn can execute in the same cycle as the insn
4390 after the call. This is of course impossible.
4391 Really we need to fix the scheduler somehow, so
4392 the code after the call gets scheduled
4393 optimally. */
4394 || CALL_P (insn))
4395 {
4396 /* Mark current insn as the end of a bundle. */
4397 PUT_MODE (insn, QImode);
4398 }
4399 else
4400 {
4401 /* Mark it as part of a bundle. */
4402 PUT_MODE (insn, SImode);
4403 }
4404 }
4405 }
4406 }
dd552284
WL
4407}
4408
4409
4410/* Replace OLD_INSN with NEW_INSN. */
4411static void
4412replace_insns (rtx old_insn, rtx new_insns)
4413{
4414 if (new_insns)
4415 emit_insn_before (new_insns, old_insn);
4416
4417 delete_insn (old_insn);
4418}
4419
4420
4421/* Returns true if INSN is the first instruction of a pc-relative
4422 address compuatation. */
4423static bool
4424match_pcrel_step1 (rtx insn)
4425{
4426 rtx pattern = PATTERN (insn);
4427 rtx src;
4428
4429 if (GET_CODE (pattern) != SET)
4430 return false;
4431
4432 src = SET_SRC (pattern);
4433
4434 return (GET_CODE (src) == CONST
4435 && GET_CODE (XEXP (src, 0)) == UNSPEC
4436 && XINT (XEXP (src, 0), 1) == UNSPEC_HW1_LAST_PCREL);
4437}
4438
4439
4440/* Do the first replacement step in tilegx_fixup_pcrel_references. */
4441static void
4442replace_mov_pcrel_step1 (rtx insn)
4443{
4444 rtx pattern = PATTERN (insn);
4445 rtx unspec;
4446 rtx opnds[2];
4447 rtx new_insns;
4448
4449 gcc_assert (GET_CODE (pattern) == SET);
4450 opnds[0] = SET_DEST (pattern);
4451
4452 gcc_assert (GET_CODE (SET_SRC (pattern)) == CONST);
4453
4454 unspec = XEXP (SET_SRC (pattern), 0);
4455 gcc_assert (GET_CODE (unspec) == UNSPEC);
4456 gcc_assert (XINT (unspec, 1) == UNSPEC_HW1_LAST_PCREL);
4457 opnds[1] = XVECEXP (unspec, 0, 0);
4458
4459 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4460 if (GET_CODE (opnds[1]) != SYMBOL_REF)
4461 return;
4462
4463 start_sequence ();
4464
4465 if (flag_pic != 1)
4466 {
4467 if (TARGET_32BIT)
4468 emit_insn (gen_mov_got32_step1_32bit (opnds[0], opnds[1]));
4469 else
4470 emit_insn (gen_mov_got32_step1 (opnds[0], opnds[1]));
4471 }
4472
4473 new_insns = get_insns ();
4474 end_sequence ();
4475
4476 replace_insns (insn, new_insns);
4477}
4478
4479
4480/* Returns true if INSN is the second instruction of a pc-relative
4481 address compuatation. */
4482static bool
4483match_pcrel_step2 (rtx insn)
4484{
7afd1a8e
WL
4485 rtx unspec;
4486 rtx addr;
4487
dd552284
WL
4488 if (TARGET_32BIT)
4489 {
4490 if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli_32bit)
4491 return false;
4492 }
4493 else
4494 {
4495 if (recog_memoized (insn) != CODE_FOR_insn_addr_shl16insli)
4496 return false;
4497 }
4498
7afd1a8e
WL
4499 unspec = SET_SRC (PATTERN (insn));
4500 addr = XVECEXP (unspec, 0, 1);
dd552284 4501
7afd1a8e
WL
4502 return (GET_CODE (addr) == CONST
4503 && GET_CODE (XEXP (addr, 0)) == UNSPEC
4504 && XINT (XEXP (addr, 0), 1) == UNSPEC_HW0_PCREL);
dd552284
WL
4505}
4506
4507
4508/* Do the second replacement step in tilegx_fixup_pcrel_references. */
4509static void
4510replace_mov_pcrel_step2 (rtx insn)
4511{
4512 rtx pattern = PATTERN (insn);
4513 rtx unspec;
7afd1a8e 4514 rtx addr;
dd552284
WL
4515 rtx opnds[3];
4516 rtx new_insns;
4517 rtx got_rtx = tilegx_got_rtx ();
4518
4519 gcc_assert (GET_CODE (pattern) == SET);
4520 opnds[0] = SET_DEST (pattern);
4521
7afd1a8e
WL
4522 unspec = SET_SRC (pattern);
4523 gcc_assert (GET_CODE (unspec) == UNSPEC);
4524 gcc_assert (XINT (unspec, 1) == UNSPEC_INSN_ADDR_SHL16INSLI);
4525
4526 opnds[1] = XVECEXP (unspec, 0, 0);
4527
4528 addr = XVECEXP (unspec, 0, 1);
4529 gcc_assert (GET_CODE (addr) == CONST);
4530
4531 unspec = XEXP (addr, 0);
dd552284
WL
4532 gcc_assert (GET_CODE (unspec) == UNSPEC);
4533 gcc_assert (XINT (unspec, 1) == UNSPEC_HW0_PCREL);
dd552284
WL
4534 opnds[2] = XVECEXP (unspec, 0, 0);
4535
4536 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4537 if (GET_CODE (opnds[2]) != SYMBOL_REF)
4538 return;
4539
4540 start_sequence ();
4541
4542 if (flag_pic == 1)
4543 {
4544 if (TARGET_32BIT)
4545 emit_insn (gen_add_got16_32bit (opnds[0], got_rtx, opnds[2]));
4546 else
4547 emit_insn (gen_add_got16 (opnds[0], got_rtx, opnds[2]));
4548 }
4549 else
4550 {
4551 if (TARGET_32BIT)
4552 emit_insn (gen_mov_got32_step2_32bit
4553 (opnds[0], opnds[1], opnds[2]));
4554 else
4555 emit_insn (gen_mov_got32_step2 (opnds[0], opnds[1], opnds[2]));
4556 }
4557
4558 new_insns = get_insns ();
4559 end_sequence ();
4560
4561 replace_insns (insn, new_insns);
4562}
4563
4564
4565/* Do the third replacement step in tilegx_fixup_pcrel_references. */
4566static void
4567replace_mov_pcrel_step3 (rtx insn)
4568{
4569 rtx pattern = PATTERN (insn);
4570 rtx unspec;
4571 rtx opnds[4];
4572 rtx new_insns;
4573 rtx got_rtx = tilegx_got_rtx ();
4574 rtx text_label_rtx = tilegx_text_label_rtx ();
4575
4576 gcc_assert (GET_CODE (pattern) == SET);
4577 opnds[0] = SET_DEST (pattern);
4578
4579 unspec = SET_SRC (pattern);
4580 gcc_assert (GET_CODE (unspec) == UNSPEC);
4581 gcc_assert (XINT (unspec, 1) == UNSPEC_MOV_PCREL_STEP3);
4582
4583 opnds[1] = got_rtx;
4584
4585 if (XVECEXP (unspec, 0, 0) == text_label_rtx)
4586 opnds[2] = XVECEXP (unspec, 0, 1);
4587 else
4588 {
4589 gcc_assert (XVECEXP (unspec, 0, 1) == text_label_rtx);
4590 opnds[2] = XVECEXP (unspec, 0, 0);
4591 }
4592
4593 opnds[3] = XVECEXP (unspec, 0, 2);
4594
4595 /* We only need to replace SYMBOL_REFs, not LABEL_REFs. */
4596 if (GET_CODE (opnds[3]) != SYMBOL_REF)
4597 return;
4598
4599 start_sequence ();
4600
4601 if (flag_pic == 1)
4602 {
4603 emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[2]));
4604 }
4605 else
4606 {
4607 emit_move_insn (opnds[0], gen_rtx_PLUS (Pmode, opnds[1], opnds[2]));
4608 emit_move_insn (opnds[0], gen_const_mem (Pmode, opnds[0]));
4609 }
4610
4611 new_insns = get_insns ();
4612 end_sequence ();
4613
4614 replace_insns (insn, new_insns);
4615}
4616
4617
4618/* We generate PC relative SYMBOL_REFs as an optimization, to avoid
4619 going through the GOT when the symbol is local to the compilation
4620 unit. But such a symbol requires that the common text_label that
4621 we generate at the beginning of the function be in the same section
4622 as the reference to the SYMBOL_REF. This may not be true if we
4623 generate hot/cold sections. This function looks for such cases and
4624 replaces such references with the longer sequence going through the
4625 GOT.
4626
4627 We expect following instruction sequence:
4628 moveli tmp1, hw1_last(x-.L_PICLNK) [1]
4629 shl16insli tmp2, tmp1, hw0(x-.L_PICLNK) [2]
4630 add<x> tmp3, txt_label_reg, tmp2 [3]
4631
4632 If we're compiling -fpic, we replace with the following sequence
4633 (the numbers in brackets match the instructions they're replacing
4634 above).
4635
4636 add<x>li tmp2, got_reg, hw0_last_got(x) [2]
4637 ld<4> tmp3, tmp2 [3]
4638
4639 If we're compiling -fPIC, we replace the first instruction with:
4640
4641 moveli tmp1, hw1_last_got(x) [1]
4642 shl16insli tmp2, tmp1, hw0_got(x) [2]
4643 add<x> tmp3, got_reg, tmp2 [3]
4644 ld<4> tmp3, tmp3 [3]
4645
4646 Note that we're careful to disturb the instruction sequence as
4647 little as possible, since it's very late in the compilation
4648 process. */
4649static void
4650tilegx_fixup_pcrel_references (void)
4651{
4652 rtx insn, next_insn;
4653 bool same_section_as_entry = true;
4654
4655 for (insn = get_insns (); insn; insn = next_insn)
4656 {
4657 next_insn = NEXT_INSN (insn);
4658
4659 if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
4660 {
4661 same_section_as_entry = !same_section_as_entry;
4662 continue;
4663 }
4664
4665 if (same_section_as_entry)
4666 continue;
4667
4668 if (!(INSN_P (insn)
4669 && GET_CODE (PATTERN (insn)) != USE
4670 && GET_CODE (PATTERN (insn)) != CLOBBER))
4671 continue;
4672
4673 if (TARGET_32BIT)
4674 {
4675 if (match_pcrel_step1 (insn))
4676 replace_mov_pcrel_step1 (insn);
4677 else if (match_pcrel_step2 (insn))
4678 replace_mov_pcrel_step2 (insn);
4679 else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3_32bit)
4680 replace_mov_pcrel_step3 (insn);
4681 }
4682 else
4683 {
4684 if (match_pcrel_step1 (insn))
4685 replace_mov_pcrel_step1 (insn);
4686 else if (match_pcrel_step2 (insn))
4687 replace_mov_pcrel_step2 (insn);
4688 else if (recog_memoized (insn) == CODE_FOR_mov_pcrel_step3)
4689 replace_mov_pcrel_step3 (insn);
4690 }
4691 }
4692}
4693
4694
4695/* Ensure that no var tracking notes are emitted in the middle of a
4696 three-instruction bundle. */
4697static void
4698reorder_var_tracking_notes (void)
4699{
4700 basic_block bb;
4701 FOR_EACH_BB (bb)
4702 {
4703 rtx insn, next;
4704 rtx queue = NULL_RTX;
4705 bool in_bundle = false;
4706
4707 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4708 {
4709 next = NEXT_INSN (insn);
4710
4711 if (INSN_P (insn))
4712 {
4713 /* Emit queued up notes at the last instruction of a
4714 bundle. */
4715 if (GET_MODE (insn) == QImode)
4716 {
4717 while (queue)
4718 {
4719 rtx next_queue = PREV_INSN (queue);
4720 PREV_INSN (NEXT_INSN (insn)) = queue;
4721 NEXT_INSN (queue) = NEXT_INSN (insn);
4722 NEXT_INSN (insn) = queue;
4723 PREV_INSN (queue) = insn;
4724 queue = next_queue;
4725 }
4726 in_bundle = false;
4727 }
4728 else if (GET_MODE (insn) == SImode)
4729 in_bundle = true;
4730 }
4731 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4732 {
4733 if (in_bundle)
4734 {
4735 rtx prev = PREV_INSN (insn);
4736 PREV_INSN (next) = prev;
4737 NEXT_INSN (prev) = next;
4738
4739 PREV_INSN (insn) = queue;
4740 queue = insn;
4741 }
4742 }
4743 }
4744 }
4745}
4746
4747
4748/* Perform machine dependent operations on the rtl chain INSNS. */
4749static void
4750tilegx_reorg (void)
4751{
4752 /* We are freeing block_for_insn in the toplev to keep compatibility
4753 with old MDEP_REORGS that are not CFG based. Recompute it
4754 now. */
4755 compute_bb_for_insn ();
4756
4757 if (flag_reorder_blocks_and_partition)
4758 {
4759 tilegx_fixup_pcrel_references ();
4760 }
4761
4762 if (flag_schedule_insns_after_reload)
4763 {
4764 split_all_insns ();
4765
4766 timevar_push (TV_SCHED2);
4767 schedule_insns ();
4768 timevar_pop (TV_SCHED2);
4769
4770 /* Examine the schedule to group into bundles. */
4771 tilegx_gen_bundles ();
4772 }
4773
4774 df_analyze ();
4775
4776 if (flag_var_tracking)
4777 {
4778 timevar_push (TV_VAR_TRACKING);
4779 variable_tracking_main ();
4780 reorder_var_tracking_notes ();
4781 timevar_pop (TV_VAR_TRACKING);
4782 }
4783
4784 df_finish_pass (false);
4785}
4786\f
4787
4788
4789/* Assembly */
4790
4791/* Select a format to encode pointers in exception handling data.
4792 CODE is 0 for data, 1 for code labels, 2 for function pointers.
4793 GLOBAL is true if the symbol may be affected by dynamic
4794 relocations. */
4795int
4796tilegx_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
4797{
192ea533
WL
4798 int type = TARGET_32BIT ? DW_EH_PE_sdata4 : DW_EH_PE_sdata8;
4799 return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type;
dd552284
WL
4800}
4801
4802
4803/* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
4804static void
4805tilegx_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
4806 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
4807 tree function)
4808{
4809 rtx this_rtx, insn, funexp, addend;
4810
4811 /* Pretend to be a post-reload pass while generating rtl. */
4812 reload_completed = 1;
4813
4814 /* Mark the end of the (empty) prologue. */
4815 emit_note (NOTE_INSN_PROLOGUE_END);
4816
4817 /* Find the "this" pointer. If the function returns a structure,
4818 the structure return pointer is in $1. */
4819 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
4820 this_rtx = gen_rtx_REG (Pmode, 1);
4821 else
4822 this_rtx = gen_rtx_REG (Pmode, 0);
4823
4824 /* Add DELTA to THIS_RTX. */
4825 if (!(delta >= -32868 && delta <= 32767))
4826 {
4827 addend = gen_rtx_REG (Pmode, 29);
4828 emit_move_insn (addend, GEN_INT (delta));
4829 }
4830 else
4831 addend = GEN_INT (delta);
4832
4833 if (TARGET_32BIT)
4834 emit_insn (gen_addsi3 (this_rtx, this_rtx, addend));
4835 else
4836 emit_insn (gen_adddi3 (this_rtx, this_rtx, addend));
4837
4838 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
4839 if (vcall_offset)
4840 {
4841 rtx tmp;
4842
4843 tmp = gen_rtx_REG (Pmode, 29);
4844 emit_move_insn (tmp, gen_rtx_MEM (Pmode, this_rtx));
4845
4846 if (!(vcall_offset >= -32868 && vcall_offset <= 32767))
4847 {
4848 addend = gen_rtx_REG (Pmode, 28);
4849 emit_move_insn (addend, GEN_INT (vcall_offset));
4850 }
4851 else
4852 addend = GEN_INT (vcall_offset);
4853
4854 if (TARGET_32BIT)
4855 emit_insn (gen_addsi3 (tmp, tmp, addend));
4856 else
4857 emit_insn (gen_adddi3 (tmp, tmp, addend));
4858
4859 emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
4860
4861 if (TARGET_32BIT)
4862 emit_insn (gen_addsi3 (this_rtx, this_rtx, tmp));
4863 else
4864 emit_insn (gen_adddi3 (this_rtx, this_rtx, tmp));
4865 }
4866
4867 /* Generate a tail call to the target function. */
4868 if (!TREE_USED (function))
4869 {
4870 assemble_external (function);
4871 TREE_USED (function) = 1;
4872 }
4873 funexp = XEXP (DECL_RTL (function), 0);
4874 funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
4875 insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
4876 SIBLING_CALL_P (insn) = 1;
4877
4878 /* Run just enough of rest_of_compilation to get the insns emitted.
4879 There's not really enough bulk here to make other passes such as
4880 instruction scheduling worth while. Note that use_thunk calls
4881 assemble_start_function and assemble_end_function.
4882
4883 We don't currently bundle, but the instruciton sequence is all
4884 serial except for the tail call, so we're only wasting one cycle.
4885 */
4886 insn = get_insns ();
dd552284
WL
4887 shorten_branches (insn);
4888 final_start_function (insn, file, 1);
4889 final (insn, file, 1);
4890 final_end_function ();
4891
4892 /* Stop pretending to be a post-reload pass. */
4893 reload_completed = 0;
4894}
4895
4896
4897/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
4898static void
4899tilegx_asm_trampoline_template (FILE *file)
4900{
4901 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4902 if (TARGET_32BIT)
4903 {
4904 fprintf (file, "\tlnk r10\n");
4905 fprintf (file, "\taddxi r10, r10, 32\n");
4906 fprintf (file, "\tld4s_add r11, r10, %d\n", ptr_mode_size);
4907 fprintf (file, "\tld4s r10, r10\n");
4908 fprintf (file, "\tjr r11\n");
4909 fprintf (file, "\t.word 0 # <function address>\n");
4910 fprintf (file, "\t.word 0 # <static chain value>\n");
4911 }
4912 else
4913 {
4914 fprintf (file, "\tlnk r10\n");
4915 fprintf (file, "\taddi r10, r10, 32\n");
4916 fprintf (file, "\tld_add r11, r10, %d\n", ptr_mode_size);
4917 fprintf (file, "\tld r10, r10\n");
4918 fprintf (file, "\tjr r11\n");
4919 fprintf (file, "\t.quad 0 # <function address>\n");
4920 fprintf (file, "\t.quad 0 # <static chain value>\n");
4921 }
4922}
4923
4924
4925/* Implement TARGET_TRAMPOLINE_INIT. */
4926static void
4927tilegx_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
4928{
4929 rtx fnaddr, chaddr;
4930 rtx mem;
4931 rtx begin_addr, end_addr;
4932 int ptr_mode_size = GET_MODE_SIZE (ptr_mode);
4933
4934 fnaddr = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
4935 chaddr = copy_to_reg (static_chain);
4936
4937 emit_block_move (m_tramp, assemble_trampoline_template (),
4938 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
4939
4940 mem = adjust_address (m_tramp, ptr_mode,
4941 TRAMPOLINE_SIZE - 2 * ptr_mode_size);
4942 emit_move_insn (mem, fnaddr);
4943 mem = adjust_address (m_tramp, ptr_mode,
4944 TRAMPOLINE_SIZE - ptr_mode_size);
4945 emit_move_insn (mem, chaddr);
4946
4947 /* Get pointers to the beginning and end of the code block. */
4948 begin_addr = force_reg (Pmode, XEXP (m_tramp, 0));
0a81f074 4949 end_addr = force_reg (Pmode, plus_constant (Pmode, XEXP (m_tramp, 0),
dd552284
WL
4950 TRAMPOLINE_SIZE));
4951
4952 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__clear_cache"),
4953 LCT_NORMAL, VOIDmode, 2, begin_addr, Pmode,
4954 end_addr, Pmode);
4955}
4956
4957
4958/* Implement TARGET_PRINT_OPERAND. */
4959static void
4960tilegx_print_operand (FILE *file, rtx x, int code)
4961{
4962 switch (code)
4963 {
4964 case 'c':
3aa775d6 4965 /* Print the compare operator opcode for conditional moves. */
dd552284
WL
4966 switch (GET_CODE (x))
4967 {
4968 case EQ:
4969 fputs ("z", file);
4970 break;
4971 case NE:
4972 fputs ("nz", file);
4973 break;
4974 default:
4975 output_operand_lossage ("invalid %%c operand");
4976 }
4977 return;
4978
4979 case 'C':
3aa775d6 4980 /* Print the compare operator opcode for conditional moves. */
dd552284
WL
4981 switch (GET_CODE (x))
4982 {
4983 case EQ:
4984 fputs ("nz", file);
4985 break;
4986 case NE:
4987 fputs ("z", file);
4988 break;
4989 default:
4990 output_operand_lossage ("invalid %%C operand");
4991 }
4992 return;
4993
4994 case 'd':
4995 {
3aa775d6 4996 /* Print the compare operator opcode for conditional moves. */
dd552284
WL
4997 switch (GET_CODE (x))
4998 {
4999 case EQ:
5000 fputs ("eq", file);
5001 break;
5002 case NE:
5003 fputs ("ne", file);
5004 break;
5005 default:
5006 output_operand_lossage ("invalid %%d operand");
5007 }
5008 return;
5009 }
5010
5011 case 'D':
5012 {
3aa775d6 5013 /* Print the compare operator opcode for conditional moves. */
dd552284
WL
5014 switch (GET_CODE (x))
5015 {
5016 case EQ:
5017 fputs ("ne", file);
5018 break;
5019 case NE:
5020 fputs ("eq", file);
5021 break;
5022 default:
5023 output_operand_lossage ("invalid %%D operand");
5024 }
5025 return;
5026 }
5027
5028 case 'H':
5029 {
5030 if (GET_CODE (x) == CONST
5031 && GET_CODE (XEXP (x, 0)) == UNSPEC)
5032 {
5033 rtx addr = XVECEXP (XEXP (x, 0), 0, 0);
5034 int unspec = XINT (XEXP (x, 0), 1);
5035 const char *opstr = NULL;
5036 switch (unspec)
5037 {
5038 case UNSPEC_HW0:
5039 case UNSPEC_HW0_PCREL:
5040 opstr = "hw0";
5041 break;
5042 case UNSPEC_HW1:
1773cd77 5043 case UNSPEC_HW1_PCREL:
dd552284
WL
5044 opstr = "hw1";
5045 break;
5046 case UNSPEC_HW2:
5047 opstr = "hw2";
5048 break;
5049 case UNSPEC_HW3:
5050 opstr = "hw3";
5051 break;
5052 case UNSPEC_HW0_LAST:
5053 opstr = "hw0_last";
5054 break;
5055 case UNSPEC_HW1_LAST:
5056 case UNSPEC_HW1_LAST_PCREL:
5057 opstr = "hw1_last";
5058 break;
5059 case UNSPEC_HW2_LAST:
1773cd77 5060 case UNSPEC_HW2_LAST_PCREL:
dd552284
WL
5061 opstr = "hw2_last";
5062 break;
5063 case UNSPEC_HW0_GOT:
5064 opstr = "hw0_got";
5065 break;
5066 case UNSPEC_HW0_LAST_GOT:
5067 opstr = "hw0_last_got";
5068 break;
5069 case UNSPEC_HW1_LAST_GOT:
5070 opstr = "hw1_last_got";
5071 break;
5072 case UNSPEC_HW0_TLS_GD:
5073 opstr = "hw0_tls_gd";
5074 break;
5075 case UNSPEC_HW1_LAST_TLS_GD:
5076 opstr = "hw1_last_tls_gd";
5077 break;
5078 case UNSPEC_HW0_TLS_IE:
5079 opstr = "hw0_tls_ie";
5080 break;
5081 case UNSPEC_HW1_LAST_TLS_IE:
5082 opstr = "hw1_last_tls_ie";
5083 break;
5084 case UNSPEC_HW0_TLS_LE:
5085 opstr = "hw0_tls_le";
5086 break;
5087 case UNSPEC_HW1_LAST_TLS_LE:
5088 opstr = "hw1_last_tls_le";
5089 break;
1773cd77
WL
5090 case UNSPEC_HW0_PLT_PCREL:
5091 opstr = "hw0_plt";
5092 break;
5093 case UNSPEC_HW1_PLT_PCREL:
5094 opstr = "hw1_plt";
5095 break;
5096 case UNSPEC_HW1_LAST_PLT_PCREL:
5097 opstr = "hw1_last_plt";
5098 break;
5099 case UNSPEC_HW2_LAST_PLT_PCREL:
5100 opstr = "hw2_last_plt";
5101 break;
dd552284
WL
5102 default:
5103 output_operand_lossage ("invalid %%H specifier");
5104 }
5105
5106 fputs (opstr, file);
5107 fputc ('(', file);
5108 output_addr_const (file, addr);
5109
5110 if (unspec == UNSPEC_HW0_PCREL
1773cd77
WL
5111 || unspec == UNSPEC_HW1_PCREL
5112 || unspec == UNSPEC_HW1_LAST_PCREL
5113 || unspec == UNSPEC_HW2_LAST_PCREL
5114 || unspec == UNSPEC_HW0_PLT_PCREL
5115 || unspec == UNSPEC_HW1_PLT_PCREL
5116 || unspec == UNSPEC_HW1_LAST_PLT_PCREL
5117 || unspec == UNSPEC_HW2_LAST_PLT_PCREL)
dd552284
WL
5118 {
5119 rtx addr2 = XVECEXP (XEXP (x, 0), 0, 1);
5120 fputs (" - " , file);
5121 output_addr_const (file, addr2);
5122 }
5123
5124 fputc (')', file);
5125 return;
5126 }
5127 else if (symbolic_operand (x, VOIDmode))
5128 {
5129 output_addr_const (file, x);
5130 return;
5131 }
5132 }
5133 /* FALLTHRU */
5134
5135 case 'h':
5136 {
5137 /* Print the low 16 bits of a constant. */
5138 HOST_WIDE_INT i;
5139 if (CONST_INT_P (x))
5140 i = INTVAL (x);
5141 else if (GET_CODE (x) == CONST_DOUBLE)
5142 i = CONST_DOUBLE_LOW (x);
5143 else
5144 {
5145 output_operand_lossage ("invalid %%h operand");
5146 return;
5147 }
5148 i = trunc_int_for_mode (i, HImode);
5149 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
5150 return;
5151 }
5152
5153 case 'I':
5154 /* Print an auto-inc memory operand. */
5155 if (!MEM_P (x))
5156 {
5157 output_operand_lossage ("invalid %%I operand");
5158 return;
5159 }
5160
5161 output_memory_reference_mode = GET_MODE (x);
5162 output_memory_autoinc_first = true;
5163 output_address (XEXP (x, 0));
5164 output_memory_reference_mode = VOIDmode;
5165 return;
5166
5167 case 'i':
5168 /* Print an auto-inc memory operand. */
5169 if (!MEM_P (x))
5170 {
5171 output_operand_lossage ("invalid %%i operand");
5172 return;
5173 }
5174
5175 output_memory_reference_mode = GET_MODE (x);
5176 output_memory_autoinc_first = false;
5177 output_address (XEXP (x, 0));
5178 output_memory_reference_mode = VOIDmode;
5179 return;
5180
5181 case 'j':
5182 {
5183 /* Print the low 8 bits of a constant. */
5184 HOST_WIDE_INT i;
5185 if (CONST_INT_P (x))
5186 i = INTVAL (x);
5187 else if (GET_CODE (x) == CONST_DOUBLE)
5188 i = CONST_DOUBLE_LOW (x);
5189 else if (GET_CODE (x) == CONST_VECTOR
5190 && CONST_INT_P (CONST_VECTOR_ELT (x, 0)))
5191 i = INTVAL (CONST_VECTOR_ELT (x, 0));
5192 else
5193 {
5194 output_operand_lossage ("invalid %%j operand");
5195 return;
5196 }
5197 i = trunc_int_for_mode (i, QImode);
5198 fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
5199 return;
5200 }
5201
5202 case 'P':
5203 {
5204 /* Print a constant plus one. */
5205 if (!CONST_INT_P (x))
5206 {
5207 output_operand_lossage ("invalid %%P operand");
5208 return;
5209 }
5210 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + 1);
5211 return;
5212 }
5213
5214 case 'm':
5215 case 'M':
5216 {
5217 /* Print a bfextu-style bit range. */
5218 int first_bit, last_bit;
5219 HOST_WIDE_INT flip = (code == 'm') ? ~0 : 0;
5220
5221 if (!CONST_INT_P (x)
5222 || !tilegx_bitfield_operand_p (INTVAL (x) ^ flip,
5223 &first_bit, &last_bit))
5224 {
5225 output_operand_lossage ("invalid %%%c operand", code);
5226 return;
5227 }
5228
5229 fprintf (file, "%d, %d", first_bit, last_bit);
5230 return;
5231 }
5232
5233 case 'N':
5234 {
5235 const char *reg = NULL;
5236
5237 /* Print a network register. */
5238 if (!CONST_INT_P (x))
5239 {
5240 output_operand_lossage ("invalid %%N operand");
5241 return;
5242 }
5243
5244 switch (INTVAL (x))
5245 {
5246 case TILEGX_NETREG_IDN0: reg = "idn0"; break;
5247 case TILEGX_NETREG_IDN1: reg = "idn1"; break;
5248 case TILEGX_NETREG_UDN0: reg = "udn0"; break;
5249 case TILEGX_NETREG_UDN1: reg = "udn1"; break;
5250 case TILEGX_NETREG_UDN2: reg = "udn2"; break;
5251 case TILEGX_NETREG_UDN3: reg = "udn3"; break;
5252 default:
5253 gcc_unreachable ();
5254 }
5255
5256 fprintf (file, reg);
5257 return;
5258 }
5259
5260 case 'p':
5261 if (GET_CODE (x) == SYMBOL_REF)
5262 {
5263 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
5264 fprintf (file, "plt(");
5265 output_addr_const (file, x);
5266 if (flag_pic && !SYMBOL_REF_LOCAL_P (x))
5267 fprintf (file, ")");
5268 }
5269 else
5270 output_addr_const (file, x);
5271 return;
5272
5273 case 'r':
5274 /* In this case we need a register. Use 'zero' if the operand
3aa775d6 5275 is const0_rtx. */
dd552284
WL
5276 if (x == const0_rtx
5277 || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
5278 {
5279 fputs ("zero", file);
5280 return;
5281 }
5282 else if (!REG_P (x))
5283 {
5284 output_operand_lossage ("invalid operand for 'r' specifier");
5285 return;
5286 }
5287 /* FALLTHRU */
5288
5289 case 0:
5290 if (REG_P (x))
5291 {
5292 fprintf (file, "%s", reg_names[REGNO (x)]);
5293 return;
5294 }
5295 else if (MEM_P (x))
5296 {
5297 output_memory_reference_mode = VOIDmode;
5298 output_address (XEXP (x, 0));
5299 return;
5300 }
5301 else
5302 {
5303 output_addr_const (file, x);
5304 return;
5305 }
5306 }
5307
5308 debug_rtx (x);
5309 output_operand_lossage ("unable to print out operand yet; code == %d (%c)",
5310 code, code);
5311}
5312
5313
5314/* Implement TARGET_PRINT_OPERAND_ADDRESS. */
5315static void
5316tilegx_print_operand_address (FILE *file, rtx addr)
5317{
5318 if (GET_CODE (addr) == POST_DEC
5319 || GET_CODE (addr) == POST_INC)
5320 {
5321 int offset = GET_MODE_SIZE (output_memory_reference_mode);
5322
5323 gcc_assert (output_memory_reference_mode != VOIDmode);
5324
5325 if (output_memory_autoinc_first)
5326 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
5327 else
5328 fprintf (file, "%d",
5329 GET_CODE (addr) == POST_DEC ? -offset : offset);
5330 }
5331 else if (GET_CODE (addr) == POST_MODIFY)
5332 {
5333 gcc_assert (output_memory_reference_mode != VOIDmode);
5334
5335 gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
5336
5337 if (output_memory_autoinc_first)
5338 fprintf (file, "%s", reg_names[REGNO (XEXP (addr, 0))]);
5339 else
5340 fprintf (file, HOST_WIDE_INT_PRINT_DEC,
5341 INTVAL (XEXP (XEXP (addr, 1), 1)));
5342 }
5343 else
5344 tilegx_print_operand (file, addr, 'r');
5345}
5346
5347
5348/* Machine mode of current insn, for determining curly brace
5349 placement. */
5350static enum machine_mode insn_mode;
5351
5352
5353/* Implement FINAL_PRESCAN_INSN. This is used to emit bundles. */
5354void
5355tilegx_final_prescan_insn (rtx insn)
5356{
5357 /* Record this for tilegx_asm_output_opcode to examine. */
5358 insn_mode = GET_MODE (insn);
5359}
5360
5361
3aa775d6 5362/* While emitting asm, are we currently inside '{' for a bundle? */
dd552284
WL
5363static bool tilegx_in_bundle = false;
5364
5365/* Implement ASM_OUTPUT_OPCODE. Prepend/append curly braces as
5366 appropriate given the bundling information recorded by
5367 tilegx_gen_bundles. */
5368const char *
5369tilegx_asm_output_opcode (FILE *stream, const char *code)
5370{
5371 bool pseudo = !strcmp (code, "pseudo");
5372
5373 if (!tilegx_in_bundle && insn_mode == SImode)
5374 {
5375 /* Start a new bundle. */
5376 fprintf (stream, "{\n\t");
5377 tilegx_in_bundle = true;
5378 }
5379
5380 if (tilegx_in_bundle && insn_mode == QImode)
5381 {
5382 /* Close an existing bundle. */
5383 static char buf[100];
5384
5385 gcc_assert (strlen (code) + 3 + 1 < sizeof (buf));
5386
5387 strcpy (buf, pseudo ? "" : code);
5388 strcat (buf, "\n\t}");
5389 tilegx_in_bundle = false;
5390
5391 return buf;
5392 }
5393 else
5394 {
5395 return pseudo ? "" : code;
5396 }
5397}
5398
5399
5400/* Output assembler code to FILE to increment profiler label # LABELNO
5401 for profiling a function entry. */
5402void
5403tilegx_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
5404{
5405 if (tilegx_in_bundle)
5406 {
5407 fprintf (file, "\t}\n");
5408 }
5409
5410 if (flag_pic)
5411 {
5412 fprintf (file,
5413 "\t{\n"
5414 "\tmove\tr10, lr\n"
4b3fa92c 5415 "\tjal\tplt(%s)\n"
dd552284
WL
5416 "\t}\n", MCOUNT_NAME);
5417 }
5418 else
5419 {
5420 fprintf (file,
5421 "\t{\n"
5422 "\tmove\tr10, lr\n"
5423 "\tjal\t%s\n"
3aa775d6 5424 "\t}\n", MCOUNT_NAME);
dd552284
WL
5425 }
5426
5427 tilegx_in_bundle = false;
5428}
5429
5430
5431/* Implement TARGET_ASM_FILE_END. */
5432static void
5433tilegx_file_end (void)
5434{
5435 if (NEED_INDICATE_EXEC_STACK)
5436 file_end_indicate_exec_stack ();
5437}
5438
5439
5440
5441#undef TARGET_HAVE_TLS
5442#define TARGET_HAVE_TLS HAVE_AS_TLS
5443
5444#undef TARGET_OPTION_OVERRIDE
5445#define TARGET_OPTION_OVERRIDE tilegx_option_override
5446
5447#undef TARGET_SCALAR_MODE_SUPPORTED_P
5448#define TARGET_SCALAR_MODE_SUPPORTED_P tilegx_scalar_mode_supported_p
5449
5450#undef TARGET_VECTOR_MODE_SUPPORTED_P
5451#define TARGET_VECTOR_MODE_SUPPORTED_P tilegx_vector_mode_supported_p
5452
5453#undef TARGET_CANNOT_FORCE_CONST_MEM
5454#define TARGET_CANNOT_FORCE_CONST_MEM tilegx_cannot_force_const_mem
5455
5456#undef TARGET_FUNCTION_OK_FOR_SIBCALL
5457#define TARGET_FUNCTION_OK_FOR_SIBCALL tilegx_function_ok_for_sibcall
5458
5459#undef TARGET_PASS_BY_REFERENCE
5460#define TARGET_PASS_BY_REFERENCE tilegx_pass_by_reference
5461
5462#undef TARGET_RETURN_IN_MEMORY
5463#define TARGET_RETURN_IN_MEMORY tilegx_return_in_memory
5464
5465#undef TARGET_MODE_REP_EXTENDED
5466#define TARGET_MODE_REP_EXTENDED tilegx_mode_rep_extended
5467
5468#undef TARGET_FUNCTION_ARG_BOUNDARY
5469#define TARGET_FUNCTION_ARG_BOUNDARY tilegx_function_arg_boundary
5470
5471#undef TARGET_FUNCTION_ARG
5472#define TARGET_FUNCTION_ARG tilegx_function_arg
5473
5474#undef TARGET_FUNCTION_ARG_ADVANCE
5475#define TARGET_FUNCTION_ARG_ADVANCE tilegx_function_arg_advance
5476
5477#undef TARGET_FUNCTION_VALUE
5478#define TARGET_FUNCTION_VALUE tilegx_function_value
5479
5480#undef TARGET_LIBCALL_VALUE
5481#define TARGET_LIBCALL_VALUE tilegx_libcall_value
5482
5483#undef TARGET_FUNCTION_VALUE_REGNO_P
5484#define TARGET_FUNCTION_VALUE_REGNO_P tilegx_function_value_regno_p
5485
5486#undef TARGET_PROMOTE_FUNCTION_MODE
5487#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5488
5489#undef TARGET_PROMOTE_PROTOTYPES
5490#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
5491
5492#undef TARGET_BUILD_BUILTIN_VA_LIST
5493#define TARGET_BUILD_BUILTIN_VA_LIST tilegx_build_builtin_va_list
5494
5495#undef TARGET_EXPAND_BUILTIN_VA_START
5496#define TARGET_EXPAND_BUILTIN_VA_START tilegx_va_start
5497
5498#undef TARGET_SETUP_INCOMING_VARARGS
5499#define TARGET_SETUP_INCOMING_VARARGS tilegx_setup_incoming_varargs
5500
5501#undef TARGET_GIMPLIFY_VA_ARG_EXPR
5502#define TARGET_GIMPLIFY_VA_ARG_EXPR tilegx_gimplify_va_arg_expr
5503
5504#undef TARGET_RTX_COSTS
5505#define TARGET_RTX_COSTS tilegx_rtx_costs
5506
5507#undef TARGET_SHIFT_TRUNCATION_MASK
5508#define TARGET_SHIFT_TRUNCATION_MASK tilegx_shift_truncation_mask
5509
5510#undef TARGET_INIT_LIBFUNCS
5511#define TARGET_INIT_LIBFUNCS tilegx_init_libfuncs
5512
5513/* Limit to what we can reach in one addli. */
5514#undef TARGET_MIN_ANCHOR_OFFSET
5515#define TARGET_MIN_ANCHOR_OFFSET -32768
5516#undef TARGET_MAX_ANCHOR_OFFSET
5517#define TARGET_MAX_ANCHOR_OFFSET 32767
5518
5519#undef TARGET_LEGITIMATE_CONSTANT_P
5520#define TARGET_LEGITIMATE_CONSTANT_P tilegx_legitimate_constant_p
5521
5522#undef TARGET_LEGITIMATE_ADDRESS_P
5523#define TARGET_LEGITIMATE_ADDRESS_P tilegx_legitimate_address_p
5524
5525#undef TARGET_LEGITIMIZE_ADDRESS
5526#define TARGET_LEGITIMIZE_ADDRESS tilegx_legitimize_address
5527
5528#undef TARGET_DELEGITIMIZE_ADDRESS
5529#define TARGET_DELEGITIMIZE_ADDRESS tilegx_delegitimize_address
5530
5531#undef TARGET_INIT_BUILTINS
5532#define TARGET_INIT_BUILTINS tilegx_init_builtins
5533
5534#undef TARGET_BUILTIN_DECL
5535#define TARGET_BUILTIN_DECL tilegx_builtin_decl
5536
3aa775d6 5537#undef TARGET_EXPAND_BUILTIN
dd552284
WL
5538#define TARGET_EXPAND_BUILTIN tilegx_expand_builtin
5539
5540#undef TARGET_CONDITIONAL_REGISTER_USAGE
5541#define TARGET_CONDITIONAL_REGISTER_USAGE tilegx_conditional_register_usage
5542
5543#undef TARGET_FRAME_POINTER_REQUIRED
5544#define TARGET_FRAME_POINTER_REQUIRED tilegx_frame_pointer_required
5545
5546#undef TARGET_DELAY_SCHED2
5547#define TARGET_DELAY_SCHED2 true
5548
5549#undef TARGET_DELAY_VARTRACK
5550#define TARGET_DELAY_VARTRACK true
5551
5552#undef TARGET_SCHED_ISSUE_RATE
5553#define TARGET_SCHED_ISSUE_RATE tilegx_issue_rate
5554
5555#undef TARGET_SCHED_ADJUST_COST
5556#define TARGET_SCHED_ADJUST_COST tilegx_sched_adjust_cost
5557
5558#undef TARGET_MACHINE_DEPENDENT_REORG
5559#define TARGET_MACHINE_DEPENDENT_REORG tilegx_reorg
5560
5561#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5562#define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
5563 hook_bool_const_tree_hwi_hwi_const_tree_true
5564
5565#undef TARGET_ASM_OUTPUT_MI_THUNK
5566#define TARGET_ASM_OUTPUT_MI_THUNK tilegx_output_mi_thunk
5567
5568#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5569#define TARGET_ASM_TRAMPOLINE_TEMPLATE tilegx_asm_trampoline_template
5570
5571#undef TARGET_TRAMPOLINE_INIT
5572#define TARGET_TRAMPOLINE_INIT tilegx_trampoline_init
5573
5574#undef TARGET_PRINT_OPERAND
5575#define TARGET_PRINT_OPERAND tilegx_print_operand
5576
5577#undef TARGET_PRINT_OPERAND_ADDRESS
5578#define TARGET_PRINT_OPERAND_ADDRESS tilegx_print_operand_address
5579
5580#undef TARGET_ASM_FILE_END
5581#define TARGET_ASM_FILE_END tilegx_file_end
5582
5583#undef TARGET_ASM_ALIGNED_DI_OP
5584#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
5585
1d0216c8
RS
5586#undef TARGET_CAN_USE_DOLOOP_P
5587#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
dd552284
WL
5588
5589struct gcc_target targetm = TARGET_INITIALIZER;
5590
5591#include "gt-tilegx.h"