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