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