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