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