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