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