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