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