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