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