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