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