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