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