]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/nvptx/nvptx.c
2015-06-04 Andrew MacLeod <amacleod@redhat.com>
[thirdparty/gcc.git] / gcc / config / nvptx / nvptx.c
CommitLineData
8ce80784 1/* Target code for NVPTX.
d353bf18 2 Copyright (C) 2014-2015 Free Software Foundation, Inc.
8ce80784 3 Contributed by Bernd Schmidt <bernds@codesourcery.com>
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21#include "config.h"
6401d4b8 22#include <sstream>
8ce80784 23#include "system.h"
24#include "coretypes.h"
25#include "tm.h"
26#include "rtl.h"
b20a8bb4 27#include "hash-set.h"
b20a8bb4 28#include "vec.h"
b20a8bb4 29#include "input.h"
30#include "alias.h"
31#include "symtab.h"
b20a8bb4 32#include "inchash.h"
8ce80784 33#include "tree.h"
34#include "insn-flags.h"
35#include "output.h"
36#include "insn-attr.h"
37#include "insn-codes.h"
d53441c8 38#include "hashtab.h"
39#include "hard-reg-set.h"
40#include "function.h"
41#include "flags.h"
42#include "statistics.h"
d53441c8 43#include "insn-config.h"
44#include "expmed.h"
45#include "dojump.h"
46#include "explow.h"
47#include "calls.h"
48#include "emit-rtl.h"
49#include "varasm.h"
50#include "stmt.h"
8ce80784 51#include "expr.h"
52#include "regs.h"
53#include "optabs.h"
54#include "recog.h"
55#include "ggc.h"
56#include "timevar.h"
57#include "tm_p.h"
58#include "tm-preds.h"
59#include "tm-constrs.h"
8ce80784 60#include "langhooks.h"
61#include "dbxout.h"
62#include "target.h"
63#include "target-def.h"
64#include "diagnostic.h"
65#include "predict.h"
66#include "basic-block.h"
67#include "cfgrtl.h"
68#include "stor-layout.h"
8ce80784 69#include "df.h"
70#include "builtins.h"
8ce80784 71
72/* Record the function decls we've written, and the libfuncs and function
73 decls corresponding to them. */
74static std::stringstream func_decls;
b0c5be65 75
76struct declared_libfunc_hasher : ggc_cache_hasher<rtx>
77{
78 static hashval_t hash (rtx x) { return htab_hash_pointer (x); }
79 static bool equal (rtx a, rtx b) { return a == b; }
80};
81
82static GTY((cache))
83 hash_table<declared_libfunc_hasher> *declared_libfuncs_htab;
84
85 struct tree_hasher : ggc_cache_hasher<tree>
86{
87 static hashval_t hash (tree t) { return htab_hash_pointer (t); }
88 static bool equal (tree a, tree b) { return a == b; }
89};
90
91static GTY((cache)) hash_table<tree_hasher> *declared_fndecls_htab;
92static GTY((cache)) hash_table<tree_hasher> *needed_fndecls_htab;
8ce80784 93
94/* Allocate a new, cleared machine_function structure. */
95
96static struct machine_function *
97nvptx_init_machine_status (void)
98{
99 struct machine_function *p = ggc_cleared_alloc<machine_function> ();
100 p->ret_reg_mode = VOIDmode;
101 return p;
102}
103
104/* Implement TARGET_OPTION_OVERRIDE. */
105
106static void
107nvptx_option_override (void)
108{
109 init_machine_status = nvptx_init_machine_status;
110 /* Gives us a predictable order, which we need especially for variables. */
111 flag_toplevel_reorder = 1;
112 /* Assumes that it will see only hard registers. */
113 flag_var_tracking = 0;
114 write_symbols = NO_DEBUG;
115 debug_info_level = DINFO_LEVEL_NONE;
116
b0c5be65 117 declared_fndecls_htab = hash_table<tree_hasher>::create_ggc (17);
118 needed_fndecls_htab = hash_table<tree_hasher>::create_ggc (17);
8ce80784 119 declared_libfuncs_htab
b0c5be65 120 = hash_table<declared_libfunc_hasher>::create_ggc (17);
8ce80784 121}
122
123/* Return the mode to be used when declaring a ptx object for OBJ.
124 For objects with subparts such as complex modes this is the mode
125 of the subpart. */
126
127machine_mode
128nvptx_underlying_object_mode (rtx obj)
129{
130 if (GET_CODE (obj) == SUBREG)
131 obj = SUBREG_REG (obj);
132 machine_mode mode = GET_MODE (obj);
133 if (mode == TImode)
134 return DImode;
135 if (COMPLEX_MODE_P (mode))
136 return GET_MODE_INNER (mode);
137 return mode;
138}
139
140/* Return a ptx type for MODE. If PROMOTE, then use .u32 for QImode to
141 deal with ptx ideosyncracies. */
142
143const char *
144nvptx_ptx_type_from_mode (machine_mode mode, bool promote)
145{
146 switch (mode)
147 {
148 case BLKmode:
149 return ".b8";
150 case BImode:
151 return ".pred";
152 case QImode:
153 if (promote)
154 return ".u32";
155 else
156 return ".u8";
157 case HImode:
158 return ".u16";
159 case SImode:
160 return ".u32";
161 case DImode:
162 return ".u64";
163
164 case SFmode:
165 return ".f32";
166 case DFmode:
167 return ".f64";
168
169 default:
170 gcc_unreachable ();
171 }
172}
173
174/* Return the number of pieces to use when dealing with a pseudo of *PMODE.
175 Alter *PMODE if we return a number greater than one. */
176
177static int
178maybe_split_mode (machine_mode *pmode)
179{
180 machine_mode mode = *pmode;
181
182 if (COMPLEX_MODE_P (mode))
183 {
184 *pmode = GET_MODE_INNER (mode);
185 return 2;
186 }
187 else if (mode == TImode)
188 {
189 *pmode = DImode;
190 return 2;
191 }
192 return 1;
193}
194
195/* Like maybe_split_mode, but only return whether or not the mode
196 needs to be split. */
197static bool
198nvptx_split_reg_p (machine_mode mode)
199{
200 if (COMPLEX_MODE_P (mode))
201 return true;
202 if (mode == TImode)
203 return true;
204 return false;
205}
206
207#define PASS_IN_REG_P(MODE, TYPE) \
208 ((GET_MODE_CLASS (MODE) == MODE_INT \
209 || GET_MODE_CLASS (MODE) == MODE_FLOAT \
210 || ((GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT \
211 || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \
212 && !AGGREGATE_TYPE_P (TYPE))) \
213 && (MODE) != TImode)
214
215#define RETURN_IN_REG_P(MODE) \
216 ((GET_MODE_CLASS (MODE) == MODE_INT \
217 || GET_MODE_CLASS (MODE) == MODE_FLOAT) \
218 && GET_MODE_SIZE (MODE) <= 8)
219\f
220/* Perform a mode promotion for a function argument with MODE. Return
221 the promoted mode. */
222
223static machine_mode
224arg_promotion (machine_mode mode)
225{
226 if (mode == QImode || mode == HImode)
227 return SImode;
228 return mode;
229}
230
231/* Write the declaration of a function arg of TYPE to S. I is the index
232 of the argument, MODE its mode. NO_ARG_TYPES is true if this is for
233 a decl with zero TYPE_ARG_TYPES, i.e. an old-style C decl. */
234
235static int
236write_one_arg (std::stringstream &s, tree type, int i, machine_mode mode,
237 bool no_arg_types)
238{
239 if (!PASS_IN_REG_P (mode, type))
240 mode = Pmode;
241
242 int count = maybe_split_mode (&mode);
243
244 if (count == 2)
245 {
246 write_one_arg (s, NULL_TREE, i, mode, false);
247 write_one_arg (s, NULL_TREE, i + 1, mode, false);
248 return i + 1;
249 }
250
251 if (no_arg_types && !AGGREGATE_TYPE_P (type))
252 {
253 if (mode == SFmode)
254 mode = DFmode;
255 mode = arg_promotion (mode);
256 }
257
258 if (i > 0)
259 s << ", ";
260 s << ".param" << nvptx_ptx_type_from_mode (mode, false) << " %in_ar"
261 << (i + 1) << (mode == QImode || mode == HImode ? "[1]" : "");
262 if (mode == BLKmode)
263 s << "[" << int_size_in_bytes (type) << "]";
264 return i;
265}
266
267/* Look for attributes in ATTRS that would indicate we must write a function
268 as a .entry kernel rather than a .func. Return true if one is found. */
269
270static bool
271write_as_kernel (tree attrs)
272{
273 return (lookup_attribute ("kernel", attrs) != NULL_TREE
274 || lookup_attribute ("omp target entrypoint", attrs) != NULL_TREE);
275}
276
277/* Write a function decl for DECL to S, where NAME is the name to be used. */
278
279static void
280nvptx_write_function_decl (std::stringstream &s, const char *name, const_tree decl)
281{
282 tree fntype = TREE_TYPE (decl);
283 tree result_type = TREE_TYPE (fntype);
284 tree args = TYPE_ARG_TYPES (fntype);
285 tree attrs = DECL_ATTRIBUTES (decl);
286 bool kernel = write_as_kernel (attrs);
287 bool is_main = strcmp (name, "main") == 0;
288 bool args_from_decl = false;
289
290 /* We get:
291 NULL in TYPE_ARG_TYPES, for old-style functions
292 NULL in DECL_ARGUMENTS, for builtin functions without another
293 declaration.
294 So we have to pick the best one we have. */
295 if (args == 0)
296 {
297 args = DECL_ARGUMENTS (decl);
298 args_from_decl = true;
299 }
300
301 if (DECL_EXTERNAL (decl))
302 s << ".extern ";
303 else if (TREE_PUBLIC (decl))
304 s << ".visible ";
305
306 if (kernel)
307 s << ".entry ";
308 else
309 s << ".func ";
310
311 /* Declare the result. */
312 bool return_in_mem = false;
313 if (TYPE_MODE (result_type) != VOIDmode)
314 {
315 machine_mode mode = TYPE_MODE (result_type);
316 if (!RETURN_IN_REG_P (mode))
317 return_in_mem = true;
318 else
319 {
320 mode = arg_promotion (mode);
321 s << "(.param" << nvptx_ptx_type_from_mode (mode, false)
322 << " %out_retval)";
323 }
324 }
325
326 if (name[0] == '*')
327 s << (name + 1);
328 else
329 s << name;
330
331 /* Declare argument types. */
332 if ((args != NULL_TREE
333 && !(TREE_CODE (args) == TREE_LIST && TREE_VALUE (args) == void_type_node))
334 || is_main
335 || return_in_mem
336 || DECL_STATIC_CHAIN (decl))
337 {
338 s << "(";
339 int i = 0;
340 bool any_args = false;
341 if (return_in_mem)
342 {
343 s << ".param.u" << GET_MODE_BITSIZE (Pmode) << " %in_ar1";
344 i++;
345 }
346 while (args != NULL_TREE)
347 {
348 tree type = args_from_decl ? TREE_TYPE (args) : TREE_VALUE (args);
349 machine_mode mode = TYPE_MODE (type);
350
351 if (mode != VOIDmode)
352 {
353 i = write_one_arg (s, type, i, mode,
354 TYPE_ARG_TYPES (fntype) == 0);
355 any_args = true;
356 i++;
357 }
358 args = TREE_CHAIN (args);
359 }
360 if (stdarg_p (fntype))
361 {
362 gcc_assert (i > 0);
363 s << ", .param.u" << GET_MODE_BITSIZE (Pmode) << " %in_argp";
364 }
365 if (DECL_STATIC_CHAIN (decl))
366 {
367 if (i > 0)
368 s << ", ";
369 s << ".reg.u" << GET_MODE_BITSIZE (Pmode)
370 << reg_names [STATIC_CHAIN_REGNUM];
371 }
372 if (!any_args && is_main)
373 s << ".param.u32 %argc, .param.u" << GET_MODE_BITSIZE (Pmode)
374 << " %argv";
375 s << ")";
376 }
377}
378
379/* Walk either ARGTYPES or ARGS if the former is null, and write out part of
380 the function header to FILE. If WRITE_COPY is false, write reg
381 declarations, otherwise write the copy from the incoming argument to that
382 reg. RETURN_IN_MEM indicates whether to start counting arg numbers at 1
383 instead of 0. */
384
385static void
386walk_args_for_param (FILE *file, tree argtypes, tree args, bool write_copy,
387 bool return_in_mem)
388{
389 int i;
390
391 bool args_from_decl = false;
392 if (argtypes == 0)
393 args_from_decl = true;
394 else
395 args = argtypes;
396
397 for (i = return_in_mem ? 1 : 0; args != NULL_TREE; args = TREE_CHAIN (args))
398 {
399 tree type = args_from_decl ? TREE_TYPE (args) : TREE_VALUE (args);
400 machine_mode mode = TYPE_MODE (type);
401
402 if (mode == VOIDmode)
403 break;
404
405 if (!PASS_IN_REG_P (mode, type))
406 mode = Pmode;
407
408 int count = maybe_split_mode (&mode);
409 if (count == 1)
410 {
411 if (argtypes == NULL && !AGGREGATE_TYPE_P (type))
412 {
413 if (mode == SFmode)
414 mode = DFmode;
415
416 }
417 mode = arg_promotion (mode);
418 }
419 while (count-- > 0)
420 {
421 i++;
422 if (write_copy)
423 fprintf (file, "\tld.param%s %%ar%d, [%%in_ar%d];\n",
424 nvptx_ptx_type_from_mode (mode, false), i, i);
425 else
426 fprintf (file, "\t.reg%s %%ar%d;\n",
427 nvptx_ptx_type_from_mode (mode, false), i);
428 }
429 }
430}
431
432/* Write a .func or .kernel declaration (not a definition) along with
433 a helper comment for use by ld. S is the stream to write to, DECL
434 the decl for the function with name NAME. */
435
436static void
437write_function_decl_and_comment (std::stringstream &s, const char *name, const_tree decl)
438{
439 s << "// BEGIN";
440 if (TREE_PUBLIC (decl))
441 s << " GLOBAL";
442 s << " FUNCTION DECL: ";
443 if (name[0] == '*')
444 s << (name + 1);
445 else
446 s << name;
447 s << "\n";
448 nvptx_write_function_decl (s, name, decl);
449 s << ";\n";
450}
451
452/* Check NAME for special function names and redirect them by returning a
453 replacement. This applies to malloc, free and realloc, for which we
454 want to use libgcc wrappers, and call, which triggers a bug in ptxas. */
455
456static const char *
457nvptx_name_replacement (const char *name)
458{
459 if (strcmp (name, "call") == 0)
460 return "__nvptx_call";
461 if (strcmp (name, "malloc") == 0)
462 return "__nvptx_malloc";
463 if (strcmp (name, "free") == 0)
464 return "__nvptx_free";
465 if (strcmp (name, "realloc") == 0)
466 return "__nvptx_realloc";
467 return name;
468}
469
470/* If DECL is a FUNCTION_DECL, check the hash table to see if we
471 already encountered it, and if not, insert it and write a ptx
472 declarations that will be output at the end of compilation. */
473
474static bool
475nvptx_record_fndecl (tree decl, bool force = false)
476{
477 if (decl == NULL_TREE || TREE_CODE (decl) != FUNCTION_DECL
478 || !DECL_EXTERNAL (decl))
479 return true;
480
481 if (!force && TYPE_ARG_TYPES (TREE_TYPE (decl)) == NULL_TREE)
482 return false;
483
b0c5be65 484 tree *slot = declared_fndecls_htab->find_slot (decl, INSERT);
8ce80784 485 if (*slot == NULL)
486 {
487 *slot = decl;
488 const char *name = get_fnname_from_decl (decl);
489 name = nvptx_name_replacement (name);
490 write_function_decl_and_comment (func_decls, name, decl);
491 }
492 return true;
493}
494
495/* Record that we need to emit a ptx decl for DECL. Either do it now, or
496 record it for later in case we have no argument information at this
497 point. */
498
499void
500nvptx_record_needed_fndecl (tree decl)
501{
502 if (nvptx_record_fndecl (decl))
503 return;
504
b0c5be65 505 tree *slot = needed_fndecls_htab->find_slot (decl, INSERT);
8ce80784 506 if (*slot == NULL)
507 *slot = decl;
508}
509
510/* Implement ASM_DECLARE_FUNCTION_NAME. Writes the start of a ptx
511 function, including local var decls and copies from the arguments to
512 local regs. */
513
514void
515nvptx_declare_function_name (FILE *file, const char *name, const_tree decl)
516{
517 tree fntype = TREE_TYPE (decl);
518 tree result_type = TREE_TYPE (fntype);
519
520 name = nvptx_name_replacement (name);
521
522 std::stringstream s;
523 write_function_decl_and_comment (s, name, decl);
524 s << "// BEGIN";
525 if (TREE_PUBLIC (decl))
526 s << " GLOBAL";
527 s << " FUNCTION DEF: ";
528
529 if (name[0] == '*')
530 s << (name + 1);
531 else
532 s << name;
533 s << "\n";
534
535 nvptx_write_function_decl (s, name, decl);
536 fprintf (file, "%s", s.str().c_str());
537
538 bool return_in_mem = false;
539 if (TYPE_MODE (result_type) != VOIDmode)
540 {
541 machine_mode mode = TYPE_MODE (result_type);
542 if (!RETURN_IN_REG_P (mode))
543 return_in_mem = true;
544 }
545
546 fprintf (file, "\n{\n");
547
548 /* Ensure all arguments that should live in a register have one
549 declared. We'll emit the copies below. */
550 walk_args_for_param (file, TYPE_ARG_TYPES (fntype), DECL_ARGUMENTS (decl),
551 false, return_in_mem);
552 if (return_in_mem)
553 fprintf (file, "\t.reg.u%d %%ar1;\n", GET_MODE_BITSIZE (Pmode));
554 else if (TYPE_MODE (result_type) != VOIDmode)
555 {
556 machine_mode mode = arg_promotion (TYPE_MODE (result_type));
557 fprintf (file, ".reg%s %%retval;\n",
558 nvptx_ptx_type_from_mode (mode, false));
559 }
560
561 if (stdarg_p (fntype))
562 fprintf (file, "\t.reg.u%d %%argp;\n", GET_MODE_BITSIZE (Pmode));
563
564 fprintf (file, "\t.reg.u%d %s;\n", GET_MODE_BITSIZE (Pmode),
565 reg_names[OUTGOING_STATIC_CHAIN_REGNUM]);
566
567 /* Declare the pseudos we have as ptx registers. */
568 int maxregs = max_reg_num ();
569 for (int i = LAST_VIRTUAL_REGISTER + 1; i < maxregs; i++)
570 {
571 if (regno_reg_rtx[i] != const0_rtx)
572 {
573 machine_mode mode = PSEUDO_REGNO_MODE (i);
574 int count = maybe_split_mode (&mode);
575 if (count > 1)
576 {
577 while (count-- > 0)
578 fprintf (file, "\t.reg%s %%r%d$%d;\n",
579 nvptx_ptx_type_from_mode (mode, true),
580 i, count);
581 }
582 else
583 fprintf (file, "\t.reg%s %%r%d;\n",
584 nvptx_ptx_type_from_mode (mode, true),
585 i);
586 }
587 }
588
589 /* The only reason we might be using outgoing args is if we call a stdargs
590 function. Allocate the space for this. If we called varargs functions
591 without passing any variadic arguments, we'll see a reference to outargs
592 even with a zero outgoing_args_size. */
593 HOST_WIDE_INT sz = crtl->outgoing_args_size;
594 if (sz == 0)
595 sz = 1;
596 if (cfun->machine->has_call_with_varargs)
597 fprintf (file, "\t.reg.u%d %%outargs;\n"
f03df321 598 "\t.local.align 8 .b8 %%outargs_ar[" HOST_WIDE_INT_PRINT_DEC"];\n",
8ce80784 599 BITS_PER_WORD, sz);
600 if (cfun->machine->punning_buffer_size > 0)
601 fprintf (file, "\t.reg.u%d %%punbuffer;\n"
602 "\t.local.align 8 .b8 %%punbuffer_ar[%d];\n",
603 BITS_PER_WORD, cfun->machine->punning_buffer_size);
604
605 /* Declare a local variable for the frame. */
606 sz = get_frame_size ();
607 if (sz > 0 || cfun->machine->has_call_with_sc)
608 {
609 fprintf (file, "\t.reg.u%d %%frame;\n"
f03df321 610 "\t.local.align 8 .b8 %%farray[" HOST_WIDE_INT_PRINT_DEC"];\n",
8ce80784 611 BITS_PER_WORD, sz == 0 ? 1 : sz);
612 fprintf (file, "\tcvta.local.u%d %%frame, %%farray;\n",
613 BITS_PER_WORD);
614 }
615
616 if (cfun->machine->has_call_with_varargs)
617 fprintf (file, "\tcvta.local.u%d %%outargs, %%outargs_ar;\n",
618 BITS_PER_WORD);
619 if (cfun->machine->punning_buffer_size > 0)
620 fprintf (file, "\tcvta.local.u%d %%punbuffer, %%punbuffer_ar;\n",
621 BITS_PER_WORD);
622
623 /* Now emit any copies necessary for arguments. */
624 walk_args_for_param (file, TYPE_ARG_TYPES (fntype), DECL_ARGUMENTS (decl),
625 true, return_in_mem);
626 if (return_in_mem)
627 fprintf (file, "ld.param.u%d %%ar1, [%%in_ar1];\n",
628 GET_MODE_BITSIZE (Pmode));
629 if (stdarg_p (fntype))
630 fprintf (file, "ld.param.u%d %%argp, [%%in_argp];\n",
631 GET_MODE_BITSIZE (Pmode));
632}
633
634/* Output a return instruction. Also copy the return value to its outgoing
635 location. */
636
637const char *
638nvptx_output_return (void)
639{
640 tree fntype = TREE_TYPE (current_function_decl);
641 tree result_type = TREE_TYPE (fntype);
642 if (TYPE_MODE (result_type) != VOIDmode)
643 {
644 machine_mode mode = TYPE_MODE (result_type);
645 if (RETURN_IN_REG_P (mode))
646 {
647 mode = arg_promotion (mode);
648 fprintf (asm_out_file, "\tst.param%s\t[%%out_retval], %%retval;\n",
649 nvptx_ptx_type_from_mode (mode, false));
650 }
651 }
652
653 return "ret;";
654}
655
656/* Construct a function declaration from a call insn. This can be
657 necessary for two reasons - either we have an indirect call which
658 requires a .callprototype declaration, or we have a libcall
659 generated by emit_library_call for which no decl exists. */
660
661static void
662write_func_decl_from_insn (std::stringstream &s, rtx result, rtx pat,
663 rtx callee)
664{
665 bool callprototype = register_operand (callee, Pmode);
666 const char *name = "_";
667 if (!callprototype)
668 {
669 name = XSTR (callee, 0);
670 name = nvptx_name_replacement (name);
671 s << "// BEGIN GLOBAL FUNCTION DECL: " << name << "\n";
672 }
673 s << (callprototype ? "\t.callprototype\t" : "\t.extern .func ");
674
675 if (result != NULL_RTX)
676 {
677 s << "(.param";
678 s << nvptx_ptx_type_from_mode (arg_promotion (GET_MODE (result)),
679 false);
680 s << " ";
681 if (callprototype)
682 s << "_";
683 else
684 s << "%out_retval";
685 s << ")";
686 }
687
688 s << name;
689
690 int nargs = XVECLEN (pat, 0) - 1;
691 if (nargs > 0)
692 {
693 s << " (";
694 for (int i = 0; i < nargs; i++)
695 {
696 rtx t = XEXP (XVECEXP (pat, 0, i + 1), 0);
697 machine_mode mode = GET_MODE (t);
698 int count = maybe_split_mode (&mode);
699
700 while (count-- > 0)
701 {
702 s << ".param";
703 s << nvptx_ptx_type_from_mode (mode, false);
704 s << " ";
705 if (callprototype)
706 s << "_";
707 else
708 s << "%arg" << i;
709 if (mode == QImode || mode == HImode)
710 s << "[1]";
711 if (i + 1 < nargs || count > 0)
712 s << ", ";
713 }
714 }
715 s << ")";
716 }
717 s << ";\n";
718}
719
720/* Terminate a function by writing a closing brace to FILE. */
721
722void
723nvptx_function_end (FILE *file)
724{
725 fprintf (file, "\t}\n");
726}
727\f
728/* Decide whether we can make a sibling call to a function. For ptx, we
729 can't. */
730
731static bool
732nvptx_function_ok_for_sibcall (tree, tree)
733{
734 return false;
735}
736
737/* Implement the TARGET_CALL_ARGS hook. Record information about one
738 argument to the next call. */
739
740static void
741nvptx_call_args (rtx arg, tree funtype)
742{
743 if (cfun->machine->start_call == NULL_RTX)
744 {
745 cfun->machine->call_args = NULL;
746 cfun->machine->funtype = funtype;
747 cfun->machine->start_call = const0_rtx;
748 }
749 if (arg == pc_rtx)
750 return;
751
752 rtx_expr_list *args_so_far = cfun->machine->call_args;
753 if (REG_P (arg))
754 cfun->machine->call_args = alloc_EXPR_LIST (VOIDmode, arg, args_so_far);
755}
756
757/* Implement the corresponding END_CALL_ARGS hook. Clear and free the
758 information we recorded. */
759
760static void
761nvptx_end_call_args (void)
762{
763 cfun->machine->start_call = NULL_RTX;
764 free_EXPR_LIST_list (&cfun->machine->call_args);
765}
766
767/* Emit the sequence for a call. */
768
769void
770nvptx_expand_call (rtx retval, rtx address)
771{
772 int nargs;
773 rtx callee = XEXP (address, 0);
774 rtx pat, t;
775 rtvec vec;
776 bool external_decl = false;
777
778 nargs = 0;
779 for (t = cfun->machine->call_args; t; t = XEXP (t, 1))
780 nargs++;
781
782 bool has_varargs = false;
783 tree decl_type = NULL_TREE;
784
785 if (!call_insn_operand (callee, Pmode))
786 {
787 callee = force_reg (Pmode, callee);
788 address = change_address (address, QImode, callee);
789 }
790
791 if (GET_CODE (callee) == SYMBOL_REF)
792 {
793 tree decl = SYMBOL_REF_DECL (callee);
794 if (decl != NULL_TREE)
795 {
796 decl_type = TREE_TYPE (decl);
797 if (DECL_STATIC_CHAIN (decl))
798 cfun->machine->has_call_with_sc = true;
799 if (DECL_EXTERNAL (decl))
800 external_decl = true;
801 }
802 }
803 if (cfun->machine->funtype
804 /* It's possible to construct testcases where we call a variable.
805 See compile/20020129-1.c. stdarg_p will crash so avoid calling it
806 in such a case. */
807 && (TREE_CODE (cfun->machine->funtype) == FUNCTION_TYPE
808 || TREE_CODE (cfun->machine->funtype) == METHOD_TYPE)
809 && stdarg_p (cfun->machine->funtype))
810 {
811 has_varargs = true;
812 cfun->machine->has_call_with_varargs = true;
813 }
814 vec = rtvec_alloc (nargs + 1 + (has_varargs ? 1 : 0));
815 pat = gen_rtx_PARALLEL (VOIDmode, vec);
816 if (has_varargs)
817 {
818 rtx this_arg = gen_reg_rtx (Pmode);
819 if (Pmode == DImode)
820 emit_move_insn (this_arg, stack_pointer_rtx);
821 else
822 emit_move_insn (this_arg, stack_pointer_rtx);
823 XVECEXP (pat, 0, nargs + 1) = gen_rtx_USE (VOIDmode, this_arg);
824 }
825
826 int i;
827 rtx arg;
828 for (i = 1, arg = cfun->machine->call_args; arg; arg = XEXP (arg, 1), i++)
829 {
830 rtx this_arg = XEXP (arg, 0);
831 XVECEXP (pat, 0, i) = gen_rtx_USE (VOIDmode, this_arg);
832 }
833
834 rtx tmp_retval = retval;
835 t = gen_rtx_CALL (VOIDmode, address, const0_rtx);
836 if (retval != NULL_RTX)
837 {
838 if (!nvptx_register_operand (retval, GET_MODE (retval)))
839 tmp_retval = gen_reg_rtx (GET_MODE (retval));
d1f9b275 840 t = gen_rtx_SET (tmp_retval, t);
8ce80784 841 }
842 XVECEXP (pat, 0, 0) = t;
843 if (!REG_P (callee)
844 && (decl_type == NULL_TREE
845 || (external_decl && TYPE_ARG_TYPES (decl_type) == NULL_TREE)))
846 {
b0c5be65 847 rtx *slot = declared_libfuncs_htab->find_slot (callee, INSERT);
8ce80784 848 if (*slot == NULL)
849 {
850 *slot = callee;
851 write_func_decl_from_insn (func_decls, retval, pat, callee);
852 }
853 }
854 emit_call_insn (pat);
855 if (tmp_retval != retval)
856 emit_move_insn (retval, tmp_retval);
857}
858
859/* Implement TARGET_FUNCTION_ARG. */
860
861static rtx
862nvptx_function_arg (cumulative_args_t, machine_mode mode,
863 const_tree, bool named)
864{
865 if (mode == VOIDmode)
866 return NULL_RTX;
867
868 if (named)
869 return gen_reg_rtx (mode);
870 return NULL_RTX;
871}
872
873/* Implement TARGET_FUNCTION_INCOMING_ARG. */
874
875static rtx
876nvptx_function_incoming_arg (cumulative_args_t cum_v, machine_mode mode,
877 const_tree, bool named)
878{
879 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
880 if (mode == VOIDmode)
881 return NULL_RTX;
882
883 if (!named)
884 return NULL_RTX;
885
886 /* No need to deal with split modes here, the only case that can
887 happen is complex modes and those are dealt with by
888 TARGET_SPLIT_COMPLEX_ARG. */
889 return gen_rtx_UNSPEC (mode,
890 gen_rtvec (1, GEN_INT (1 + cum->count)),
891 UNSPEC_ARG_REG);
892}
893
894/* Implement TARGET_FUNCTION_ARG_ADVANCE. */
895
896static void
897nvptx_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
898 const_tree type ATTRIBUTE_UNUSED,
899 bool named ATTRIBUTE_UNUSED)
900{
901 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
902 if (mode == TImode)
903 cum->count += 2;
904 else
905 cum->count++;
906}
907
908/* Handle the TARGET_STRICT_ARGUMENT_NAMING target hook.
909
910 For nvptx, we know how to handle functions declared as stdarg: by
911 passing an extra pointer to the unnamed arguments. However, the
912 Fortran frontend can produce a different situation, where a
913 function pointer is declared with no arguments, but the actual
914 function and calls to it take more arguments. In that case, we
915 want to ensure the call matches the definition of the function. */
916
917static bool
918nvptx_strict_argument_naming (cumulative_args_t cum_v)
919{
920 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
921 return cum->fntype == NULL_TREE || stdarg_p (cum->fntype);
922}
923
924/* Implement TARGET_FUNCTION_ARG_BOUNDARY. */
925
926static unsigned int
927nvptx_function_arg_boundary (machine_mode mode, const_tree type)
928{
929 unsigned int boundary = type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode);
930
931 if (boundary > BITS_PER_WORD)
932 return 2 * BITS_PER_WORD;
933
934 if (mode == BLKmode)
935 {
936 HOST_WIDE_INT size = int_size_in_bytes (type);
937 if (size > 4)
938 return 2 * BITS_PER_WORD;
939 if (boundary < BITS_PER_WORD)
940 {
941 if (size >= 3)
942 return BITS_PER_WORD;
943 if (size >= 2)
944 return 2 * BITS_PER_UNIT;
945 }
946 }
947 return boundary;
948}
949
950/* TARGET_FUNCTION_VALUE implementation. Returns an RTX representing the place
951 where function FUNC returns or receives a value of data type TYPE. */
952
953static rtx
954nvptx_function_value (const_tree type, const_tree func ATTRIBUTE_UNUSED,
955 bool outgoing)
956{
957 int unsignedp = TYPE_UNSIGNED (type);
958 machine_mode orig_mode = TYPE_MODE (type);
959 machine_mode mode = promote_function_mode (type, orig_mode,
960 &unsignedp, NULL_TREE, 1);
961 if (outgoing)
962 return gen_rtx_REG (mode, NVPTX_RETURN_REGNUM);
963 if (cfun->machine->start_call == NULL_RTX)
964 /* Pretend to return in a hard reg for early uses before pseudos can be
965 generated. */
966 return gen_rtx_REG (mode, NVPTX_RETURN_REGNUM);
967 return gen_reg_rtx (mode);
968}
969
970/* Implement TARGET_LIBCALL_VALUE. */
971
972static rtx
973nvptx_libcall_value (machine_mode mode, const_rtx)
974{
975 if (cfun->machine->start_call == NULL_RTX)
976 /* Pretend to return in a hard reg for early uses before pseudos can be
977 generated. */
978 return gen_rtx_REG (mode, NVPTX_RETURN_REGNUM);
979 return gen_reg_rtx (mode);
980}
981
982/* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
983
984static bool
985nvptx_function_value_regno_p (const unsigned int regno)
986{
987 return regno == NVPTX_RETURN_REGNUM;
988}
989
990/* Types with a mode other than those supported by the machine are passed by
991 reference in memory. */
992
993static bool
994nvptx_pass_by_reference (cumulative_args_t, machine_mode mode,
995 const_tree type, bool)
996{
997 return !PASS_IN_REG_P (mode, type);
998}
999
1000/* Implement TARGET_RETURN_IN_MEMORY. */
1001
1002static bool
1003nvptx_return_in_memory (const_tree type, const_tree)
1004{
1005 machine_mode mode = TYPE_MODE (type);
1006 if (!RETURN_IN_REG_P (mode))
1007 return true;
1008 return false;
1009}
1010
1011/* Implement TARGET_PROMOTE_FUNCTION_MODE. */
1012
1013static machine_mode
1014nvptx_promote_function_mode (const_tree type, machine_mode mode,
1015 int *punsignedp,
1016 const_tree funtype, int for_return)
1017{
1018 if (type == NULL_TREE)
1019 return mode;
1020 if (for_return)
1021 return promote_mode (type, mode, punsignedp);
1022 /* For K&R-style functions, try to match the language promotion rules to
1023 minimize type mismatches at assembly time. */
1024 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
1025 && type != NULL_TREE
1026 && !AGGREGATE_TYPE_P (type))
1027 {
1028 if (mode == SFmode)
1029 mode = DFmode;
1030 mode = arg_promotion (mode);
1031 }
1032
1033 return mode;
1034}
1035
1036/* Implement TARGET_STATIC_CHAIN. */
1037
1038static rtx
1039nvptx_static_chain (const_tree fndecl, bool incoming_p)
1040{
1041 if (!DECL_STATIC_CHAIN (fndecl))
1042 return NULL;
1043
1044 if (incoming_p)
1045 return gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
1046 else
1047 return gen_rtx_REG (Pmode, OUTGOING_STATIC_CHAIN_REGNUM);
1048}
1049\f
1050/* Emit a comparison COMPARE, and return the new test to be used in the
1051 jump. */
1052
1053rtx
1054nvptx_expand_compare (rtx compare)
1055{
1056 rtx pred = gen_reg_rtx (BImode);
1057 rtx cmp = gen_rtx_fmt_ee (GET_CODE (compare), BImode,
1058 XEXP (compare, 0), XEXP (compare, 1));
d1f9b275 1059 emit_insn (gen_rtx_SET (pred, cmp));
8ce80784 1060 return gen_rtx_NE (BImode, pred, const0_rtx);
1061}
1062
1063/* When loading an operand ORIG_OP, verify whether an address space
1064 conversion to generic is required, and if so, perform it. Also
1065 check for SYMBOL_REFs for function decls and call
1066 nvptx_record_needed_fndecl as needed.
1067 Return either the original operand, or the converted one. */
1068
1069rtx
1070nvptx_maybe_convert_symbolic_operand (rtx orig_op)
1071{
1072 if (GET_MODE (orig_op) != Pmode)
1073 return orig_op;
1074
1075 rtx op = orig_op;
1076 while (GET_CODE (op) == PLUS || GET_CODE (op) == CONST)
1077 op = XEXP (op, 0);
1078 if (GET_CODE (op) != SYMBOL_REF)
1079 return orig_op;
1080
1081 tree decl = SYMBOL_REF_DECL (op);
1082 if (decl && TREE_CODE (decl) == FUNCTION_DECL)
1083 {
1084 nvptx_record_needed_fndecl (decl);
1085 return orig_op;
1086 }
1087
1088 addr_space_t as = nvptx_addr_space_from_address (op);
1089 if (as == ADDR_SPACE_GENERIC)
1090 return orig_op;
1091
1092 enum unspec code;
1093 code = (as == ADDR_SPACE_GLOBAL ? UNSPEC_FROM_GLOBAL
1094 : as == ADDR_SPACE_LOCAL ? UNSPEC_FROM_LOCAL
1095 : as == ADDR_SPACE_SHARED ? UNSPEC_FROM_SHARED
1096 : as == ADDR_SPACE_CONST ? UNSPEC_FROM_CONST
1097 : UNSPEC_FROM_PARAM);
1098 rtx dest = gen_reg_rtx (Pmode);
d1f9b275 1099 emit_insn (gen_rtx_SET (dest, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig_op),
1100 code)));
8ce80784 1101 return dest;
1102}
1103\f
1104/* Returns true if X is a valid address for use in a memory reference. */
1105
1106static bool
1107nvptx_legitimate_address_p (machine_mode, rtx x, bool)
1108{
1109 enum rtx_code code = GET_CODE (x);
1110
1111 switch (code)
1112 {
1113 case REG:
1114 return true;
1115
1116 case PLUS:
1117 if (REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1)))
1118 return true;
1119 return false;
1120
1121 case CONST:
1122 case SYMBOL_REF:
1123 case LABEL_REF:
1124 return true;
1125
1126 default:
1127 return false;
1128 }
1129}
1130
1131/* Implement HARD_REGNO_MODE_OK. We barely use hard regs, but we want
1132 to ensure that the return register's mode isn't changed. */
1133
1134bool
1135nvptx_hard_regno_mode_ok (int regno, machine_mode mode)
1136{
1137 if (regno != NVPTX_RETURN_REGNUM
1138 || cfun == NULL || cfun->machine->ret_reg_mode == VOIDmode)
1139 return true;
1140 return mode == cfun->machine->ret_reg_mode;
1141}
1142\f
1143/* Convert an address space AS to the corresponding ptx string. */
1144
1145const char *
1146nvptx_section_from_addr_space (addr_space_t as)
1147{
1148 switch (as)
1149 {
1150 case ADDR_SPACE_CONST:
1151 return ".const";
1152
1153 case ADDR_SPACE_GLOBAL:
1154 return ".global";
1155
1156 case ADDR_SPACE_SHARED:
1157 return ".shared";
1158
1159 case ADDR_SPACE_GENERIC:
1160 return "";
1161
1162 default:
1163 gcc_unreachable ();
1164 }
1165}
1166
1167/* Determine whether DECL goes into .const or .global. */
1168
1169const char *
1170nvptx_section_for_decl (const_tree decl)
1171{
1172 bool is_const = (CONSTANT_CLASS_P (decl)
1173 || TREE_CODE (decl) == CONST_DECL
1174 || TREE_READONLY (decl));
1175 if (is_const)
1176 return ".const";
1177
1178 return ".global";
1179}
1180
1181/* Look for a SYMBOL_REF in ADDR and return the address space to be used
1182 for the insn referencing this address. */
1183
1184addr_space_t
1185nvptx_addr_space_from_address (rtx addr)
1186{
1187 while (GET_CODE (addr) == PLUS || GET_CODE (addr) == CONST)
1188 addr = XEXP (addr, 0);
1189 if (GET_CODE (addr) != SYMBOL_REF)
1190 return ADDR_SPACE_GENERIC;
1191
1192 tree decl = SYMBOL_REF_DECL (addr);
1193 if (decl == NULL_TREE || TREE_CODE (decl) == FUNCTION_DECL)
1194 return ADDR_SPACE_GENERIC;
1195
1196 bool is_const = (CONSTANT_CLASS_P (decl)
1197 || TREE_CODE (decl) == CONST_DECL
1198 || TREE_READONLY (decl));
1199 if (is_const)
1200 return ADDR_SPACE_CONST;
1201
1202 return ADDR_SPACE_GLOBAL;
1203}
1204\f
1205/* Machinery to output constant initializers. */
1206
1207/* Used when assembling integers to ensure data is emitted in
1208 pieces whose size matches the declaration we printed. */
1209static unsigned int decl_chunk_size;
1210static machine_mode decl_chunk_mode;
1211/* Used in the same situation, to keep track of the byte offset
1212 into the initializer. */
1213static unsigned HOST_WIDE_INT decl_offset;
1214/* The initializer part we are currently processing. */
1215static HOST_WIDE_INT init_part;
1216/* The total size of the object. */
1217static unsigned HOST_WIDE_INT object_size;
1218/* True if we found a skip extending to the end of the object. Used to
1219 assert that no data follows. */
1220static bool object_finished;
1221
1222/* Write the necessary separator string to begin a new initializer value. */
1223
1224static void
1225begin_decl_field (void)
1226{
1227 /* We never see decl_offset at zero by the time we get here. */
1228 if (decl_offset == decl_chunk_size)
1229 fprintf (asm_out_file, " = { ");
1230 else
1231 fprintf (asm_out_file, ", ");
1232}
1233
1234/* Output the currently stored chunk as an initializer value. */
1235
1236static void
1237output_decl_chunk (void)
1238{
1239 begin_decl_field ();
1240 output_address (gen_int_mode (init_part, decl_chunk_mode));
1241 init_part = 0;
1242}
1243
1244/* Add value VAL sized SIZE to the data we're emitting, and keep writing
1245 out chunks as they fill up. */
1246
1247static void
1248nvptx_assemble_value (HOST_WIDE_INT val, unsigned int size)
1249{
1250 unsigned HOST_WIDE_INT chunk_offset = decl_offset % decl_chunk_size;
1251 gcc_assert (!object_finished);
1252 while (size > 0)
1253 {
1254 int this_part = size;
1255 if (chunk_offset + this_part > decl_chunk_size)
1256 this_part = decl_chunk_size - chunk_offset;
1257 HOST_WIDE_INT val_part;
1258 HOST_WIDE_INT mask = 2;
1259 mask <<= this_part * BITS_PER_UNIT - 1;
1260 val_part = val & (mask - 1);
1261 init_part |= val_part << (BITS_PER_UNIT * chunk_offset);
1262 val >>= BITS_PER_UNIT * this_part;
1263 size -= this_part;
1264 decl_offset += this_part;
1265 if (decl_offset % decl_chunk_size == 0)
1266 output_decl_chunk ();
1267
1268 chunk_offset = 0;
1269 }
1270}
1271
1272/* Target hook for assembling integer object X of size SIZE. */
1273
1274static bool
1275nvptx_assemble_integer (rtx x, unsigned int size, int ARG_UNUSED (aligned_p))
1276{
1277 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST)
1278 {
1279 gcc_assert (size = decl_chunk_size);
1280 if (decl_offset % decl_chunk_size != 0)
1281 sorry ("cannot emit unaligned pointers in ptx assembly");
1282 decl_offset += size;
1283 begin_decl_field ();
1284
1285 HOST_WIDE_INT off = 0;
1286 if (GET_CODE (x) == CONST)
1287 x = XEXP (x, 0);
1288 if (GET_CODE (x) == PLUS)
1289 {
1290 off = INTVAL (XEXP (x, 1));
1291 x = XEXP (x, 0);
1292 }
1293 if (GET_CODE (x) == SYMBOL_REF)
1294 {
1295 nvptx_record_needed_fndecl (SYMBOL_REF_DECL (x));
1296 fprintf (asm_out_file, "generic(");
1297 output_address (x);
1298 fprintf (asm_out_file, ")");
1299 }
1300 if (off != 0)
1301 fprintf (asm_out_file, " + " HOST_WIDE_INT_PRINT_DEC, off);
1302 return true;
1303 }
1304
1305 HOST_WIDE_INT val;
1306 switch (GET_CODE (x))
1307 {
1308 case CONST_INT:
1309 val = INTVAL (x);
1310 break;
1311 case CONST_DOUBLE:
1312 gcc_unreachable ();
1313 break;
1314 default:
1315 gcc_unreachable ();
1316 }
1317
1318 nvptx_assemble_value (val, size);
1319 return true;
1320}
1321
1322/* Output SIZE zero bytes. We ignore the FILE argument since the
1323 functions we're calling to perform the output just use
1324 asm_out_file. */
1325
1326void
1327nvptx_output_skip (FILE *, unsigned HOST_WIDE_INT size)
1328{
1329 if (decl_offset + size >= object_size)
1330 {
1331 if (decl_offset % decl_chunk_size != 0)
1332 nvptx_assemble_value (0, decl_chunk_size);
1333 object_finished = true;
1334 return;
1335 }
1336
1337 while (size > decl_chunk_size)
1338 {
1339 nvptx_assemble_value (0, decl_chunk_size);
1340 size -= decl_chunk_size;
1341 }
1342 while (size-- > 0)
1343 nvptx_assemble_value (0, 1);
1344}
1345
1346/* Output a string STR with length SIZE. As in nvptx_output_skip we
1347 ignore the FILE arg. */
1348
1349void
1350nvptx_output_ascii (FILE *, const char *str, unsigned HOST_WIDE_INT size)
1351{
1352 for (unsigned HOST_WIDE_INT i = 0; i < size; i++)
1353 nvptx_assemble_value (str[i], 1);
1354}
1355
1356/* Called when the initializer for a decl has been completely output through
1357 combinations of the three functions above. */
1358
1359static void
1360nvptx_assemble_decl_end (void)
1361{
1362 if (decl_offset != 0)
1363 {
1364 if (!object_finished && decl_offset % decl_chunk_size != 0)
1365 nvptx_assemble_value (0, decl_chunk_size);
1366
1367 fprintf (asm_out_file, " }");
1368 }
1369 fprintf (asm_out_file, ";\n");
1370}
1371
1372/* Start a declaration of a variable of TYPE with NAME to
1373 FILE. IS_PUBLIC says whether this will be externally visible.
1374 Here we just write the linker hint and decide on the chunk size
1375 to use. */
1376
1377static void
1378init_output_initializer (FILE *file, const char *name, const_tree type,
1379 bool is_public)
1380{
1381 fprintf (file, "// BEGIN%s VAR DEF: ", is_public ? " GLOBAL" : "");
1382 assemble_name_raw (file, name);
1383 fputc ('\n', file);
1384
1385 if (TREE_CODE (type) == ARRAY_TYPE)
1386 type = TREE_TYPE (type);
1387 int sz = int_size_in_bytes (type);
1388 if ((TREE_CODE (type) != INTEGER_TYPE
1389 && TREE_CODE (type) != ENUMERAL_TYPE
1390 && TREE_CODE (type) != REAL_TYPE)
1391 || sz < 0
1392 || sz > HOST_BITS_PER_WIDE_INT)
1393 type = ptr_type_node;
1394 decl_chunk_size = int_size_in_bytes (type);
1395 decl_chunk_mode = int_mode_for_mode (TYPE_MODE (type));
1396 decl_offset = 0;
1397 init_part = 0;
1398 object_finished = false;
1399}
1400
1401/* Implement TARGET_ASM_DECLARE_CONSTANT_NAME. Begin the process of
1402 writing a constant variable EXP with NAME and SIZE and its
1403 initializer to FILE. */
1404
1405static void
1406nvptx_asm_declare_constant_name (FILE *file, const char *name,
1407 const_tree exp, HOST_WIDE_INT size)
1408{
1409 tree type = TREE_TYPE (exp);
1410 init_output_initializer (file, name, type, false);
1411 fprintf (file, "\t.const .align %d .u%d ",
1412 TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT,
1413 decl_chunk_size * BITS_PER_UNIT);
1414 assemble_name (file, name);
1415 fprintf (file, "[" HOST_WIDE_INT_PRINT_DEC "]",
1416 (size + decl_chunk_size - 1) / decl_chunk_size);
1417 object_size = size;
1418}
1419
1420/* Implement the ASM_DECLARE_OBJECT_NAME macro. Used to start writing
1421 a variable DECL with NAME to FILE. */
1422
1423void
1424nvptx_declare_object_name (FILE *file, const char *name, const_tree decl)
1425{
1426 if (decl && DECL_SIZE (decl))
1427 {
1428 tree type = TREE_TYPE (decl);
1429 unsigned HOST_WIDE_INT size;
1430
1431 init_output_initializer (file, name, type, TREE_PUBLIC (decl));
1432 size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
1433 const char *section = nvptx_section_for_decl (decl);
1434 fprintf (file, "\t%s%s .align %d .u%d ",
1435 TREE_PUBLIC (decl) ? " .visible" : "", section,
1436 DECL_ALIGN (decl) / BITS_PER_UNIT,
1437 decl_chunk_size * BITS_PER_UNIT);
1438 assemble_name (file, name);
1439 if (size > 0)
1440 fprintf (file, "[" HOST_WIDE_INT_PRINT_DEC "]",
1441 (size + decl_chunk_size - 1) / decl_chunk_size);
1442 else
1443 object_finished = true;
1444 object_size = size;
1445 }
1446}
1447
1448/* Implement TARGET_ASM_GLOBALIZE_LABEL by doing nothing. */
1449
1450static void
1451nvptx_globalize_label (FILE *, const char *)
1452{
1453}
1454
1455/* Implement TARGET_ASM_ASSEMBLE_UNDEFINED_DECL. Write an extern
1456 declaration only for variable DECL with NAME to FILE. */
1457static void
1458nvptx_assemble_undefined_decl (FILE *file, const char *name, const_tree decl)
1459{
1460 if (TREE_CODE (decl) != VAR_DECL)
1461 return;
1462 const char *section = nvptx_section_for_decl (decl);
1463 fprintf (file, "// BEGIN%s VAR DECL: ", TREE_PUBLIC (decl) ? " GLOBAL" : "");
1464 assemble_name_raw (file, name);
1465 fputs ("\n", file);
1466 HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
1467 fprintf (file, ".extern %s .b8 ", section);
1468 assemble_name_raw (file, name);
1469 if (size > 0)
f03df321 1470 fprintf (file, "[" HOST_WIDE_INT_PRINT_DEC"]", size);
8ce80784 1471 fprintf (file, ";\n\n");
1472}
1473
1474/* Output INSN, which is a call to CALLEE with result RESULT. For ptx, this
1475 involves writing .param declarations and in/out copies into them. */
1476
1477const char *
1478nvptx_output_call_insn (rtx_insn *insn, rtx result, rtx callee)
1479{
1480 char buf[256];
1481 static int labelno;
1482 bool needs_tgt = register_operand (callee, Pmode);
1483 rtx pat = PATTERN (insn);
1484 int nargs = XVECLEN (pat, 0) - 1;
1485 tree decl = NULL_TREE;
1486
1487 fprintf (asm_out_file, "\t{\n");
1488 if (result != NULL)
1489 {
1490 fprintf (asm_out_file, "\t\t.param%s %%retval_in;\n",
1491 nvptx_ptx_type_from_mode (arg_promotion (GET_MODE (result)),
1492 false));
1493 }
1494
1495 if (GET_CODE (callee) == SYMBOL_REF)
1496 {
1497 decl = SYMBOL_REF_DECL (callee);
1498 if (decl && DECL_EXTERNAL (decl))
1499 nvptx_record_fndecl (decl);
1500 }
1501
1502 if (needs_tgt)
1503 {
1504 ASM_GENERATE_INTERNAL_LABEL (buf, "LCT", labelno);
1505 labelno++;
1506 ASM_OUTPUT_LABEL (asm_out_file, buf);
1507 std::stringstream s;
1508 write_func_decl_from_insn (s, result, pat, callee);
1509 fputs (s.str().c_str(), asm_out_file);
1510 }
1511
1512 for (int i = 0, argno = 0; i < nargs; i++)
1513 {
1514 rtx t = XEXP (XVECEXP (pat, 0, i + 1), 0);
1515 machine_mode mode = GET_MODE (t);
1516 int count = maybe_split_mode (&mode);
1517
1518 while (count-- > 0)
1519 fprintf (asm_out_file, "\t\t.param%s %%out_arg%d%s;\n",
1520 nvptx_ptx_type_from_mode (mode, false), argno++,
1521 mode == QImode || mode == HImode ? "[1]" : "");
1522 }
1523 for (int i = 0, argno = 0; i < nargs; i++)
1524 {
1525 rtx t = XEXP (XVECEXP (pat, 0, i + 1), 0);
1526 gcc_assert (REG_P (t));
1527 machine_mode mode = GET_MODE (t);
1528 int count = maybe_split_mode (&mode);
1529
1530 if (count == 1)
1531 fprintf (asm_out_file, "\t\tst.param%s [%%out_arg%d], %%r%d;\n",
1532 nvptx_ptx_type_from_mode (mode, false), argno++,
1533 REGNO (t));
1534 else
1535 {
1536 int n = 0;
1537 while (count-- > 0)
1538 fprintf (asm_out_file, "\t\tst.param%s [%%out_arg%d], %%r%d$%d;\n",
1539 nvptx_ptx_type_from_mode (mode, false), argno++,
1540 REGNO (t), n++);
1541 }
1542 }
1543
1544 fprintf (asm_out_file, "\t\tcall ");
1545 if (result != NULL_RTX)
1546 fprintf (asm_out_file, "(%%retval_in), ");
1547
1548 if (decl)
1549 {
1550 const char *name = get_fnname_from_decl (decl);
1551 name = nvptx_name_replacement (name);
1552 assemble_name (asm_out_file, name);
1553 }
1554 else
1555 output_address (callee);
1556
1557 if (nargs > 0 || (decl && DECL_STATIC_CHAIN (decl)))
1558 {
1559 fprintf (asm_out_file, ", (");
1560 int i, argno;
1561 for (i = 0, argno = 0; i < nargs; i++)
1562 {
1563 rtx t = XEXP (XVECEXP (pat, 0, i + 1), 0);
1564 machine_mode mode = GET_MODE (t);
1565 int count = maybe_split_mode (&mode);
1566
1567 while (count-- > 0)
1568 {
1569 fprintf (asm_out_file, "%%out_arg%d", argno++);
1570 if (i + 1 < nargs || count > 0)
1571 fprintf (asm_out_file, ", ");
1572 }
1573 }
1574 if (decl && DECL_STATIC_CHAIN (decl))
1575 {
1576 if (i > 0)
1577 fprintf (asm_out_file, ", ");
1578 fprintf (asm_out_file, "%s",
1579 reg_names [OUTGOING_STATIC_CHAIN_REGNUM]);
1580 }
1581
1582 fprintf (asm_out_file, ")");
1583 }
1584 if (needs_tgt)
1585 {
1586 fprintf (asm_out_file, ", ");
1587 assemble_name (asm_out_file, buf);
1588 }
1589 fprintf (asm_out_file, ";\n");
1590 if (result != NULL_RTX)
1591 return "ld.param%t0\t%0, [%%retval_in];\n\t}";
1592
1593 return "}";
1594}
1595
1596/* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
1597
1598static bool
1599nvptx_print_operand_punct_valid_p (unsigned char c)
1600{
1601 return c == '.' || c== '#';
1602}
1603
1604static void nvptx_print_operand (FILE *, rtx, int);
1605
1606/* Subroutine of nvptx_print_operand; used to print a memory reference X to FILE. */
1607
1608static void
1609nvptx_print_address_operand (FILE *file, rtx x, machine_mode)
1610{
1611 rtx off;
1612 if (GET_CODE (x) == CONST)
1613 x = XEXP (x, 0);
1614 switch (GET_CODE (x))
1615 {
1616 case PLUS:
1617 off = XEXP (x, 1);
1618 output_address (XEXP (x, 0));
1619 fprintf (file, "+");
1620 output_address (off);
1621 break;
1622
1623 case SYMBOL_REF:
1624 case LABEL_REF:
1625 output_addr_const (file, x);
1626 break;
1627
1628 default:
1629 gcc_assert (GET_CODE (x) != MEM);
1630 nvptx_print_operand (file, x, 0);
1631 break;
1632 }
1633}
1634
1635/* Write assembly language output for the address ADDR to FILE. */
1636
1637static void
1638nvptx_print_operand_address (FILE *file, rtx addr)
1639{
1640 nvptx_print_address_operand (file, addr, VOIDmode);
1641}
1642
1643/* Print an operand, X, to FILE, with an optional modifier in CODE.
1644
1645 Meaning of CODE:
1646 . -- print the predicate for the instruction or an emptry string for an
1647 unconditional one.
1648 # -- print a rounding mode for the instruction
1649
1650 A -- print an address space identifier for a MEM
1651 c -- print an opcode suffix for a comparison operator, including a type code
1652 d -- print a CONST_INT as a vector dimension (x, y, or z)
1653 f -- print a full reg even for something that must always be split
1654 t -- print a type opcode suffix, promoting QImode to 32 bits
1655 T -- print a type size in bits
1656 u -- print a type opcode suffix without promotions. */
1657
1658static void
1659nvptx_print_operand (FILE *file, rtx x, int code)
1660{
1661 rtx orig_x = x;
1662 machine_mode op_mode;
1663
1664 if (code == '.')
1665 {
1666 x = current_insn_predicate;
1667 if (x)
1668 {
1669 unsigned int regno = REGNO (XEXP (x, 0));
1670 fputs ("[", file);
1671 if (GET_CODE (x) == EQ)
1672 fputs ("!", file);
1673 fputs (reg_names [regno], file);
1674 fputs ("]", file);
1675 }
1676 return;
1677 }
1678 else if (code == '#')
1679 {
1680 fputs (".rn", file);
1681 return;
1682 }
1683
1684 enum rtx_code x_code = GET_CODE (x);
1685
1686 switch (code)
1687 {
1688 case 'A':
1689 {
1690 addr_space_t as = nvptx_addr_space_from_address (XEXP (x, 0));
1691 fputs (nvptx_section_from_addr_space (as), file);
1692 }
1693 break;
1694
1695 case 'd':
1696 gcc_assert (x_code == CONST_INT);
1697 if (INTVAL (x) == 0)
1698 fputs (".x", file);
1699 else if (INTVAL (x) == 1)
1700 fputs (".y", file);
1701 else if (INTVAL (x) == 2)
1702 fputs (".z", file);
1703 else
1704 gcc_unreachable ();
1705 break;
1706
1707 case 't':
1708 op_mode = nvptx_underlying_object_mode (x);
1709 fprintf (file, "%s", nvptx_ptx_type_from_mode (op_mode, true));
1710 break;
1711
1712 case 'u':
1713 op_mode = nvptx_underlying_object_mode (x);
1714 fprintf (file, "%s", nvptx_ptx_type_from_mode (op_mode, false));
1715 break;
1716
1717 case 'T':
1718 fprintf (file, "%d", GET_MODE_BITSIZE (GET_MODE (x)));
1719 break;
1720
1721 case 'j':
1722 fprintf (file, "@");
1723 goto common;
1724
1725 case 'J':
1726 fprintf (file, "@!");
1727 goto common;
1728
1729 case 'c':
1730 op_mode = GET_MODE (XEXP (x, 0));
1731 switch (x_code)
1732 {
1733 case EQ:
1734 fputs (".eq", file);
1735 break;
1736 case NE:
1737 if (FLOAT_MODE_P (op_mode))
1738 fputs (".neu", file);
1739 else
1740 fputs (".ne", file);
1741 break;
1742 case LE:
1743 fputs (".le", file);
1744 break;
1745 case GE:
1746 fputs (".ge", file);
1747 break;
1748 case LT:
1749 fputs (".lt", file);
1750 break;
1751 case GT:
1752 fputs (".gt", file);
1753 break;
1754 case LEU:
1755 fputs (".ls", file);
1756 break;
1757 case GEU:
1758 fputs (".hs", file);
1759 break;
1760 case LTU:
1761 fputs (".lo", file);
1762 break;
1763 case GTU:
1764 fputs (".hi", file);
1765 break;
1766 case LTGT:
1767 fputs (".ne", file);
1768 break;
1769 case UNEQ:
1770 fputs (".equ", file);
1771 break;
1772 case UNLE:
1773 fputs (".leu", file);
1774 break;
1775 case UNGE:
1776 fputs (".geu", file);
1777 break;
1778 case UNLT:
1779 fputs (".ltu", file);
1780 break;
1781 case UNGT:
1782 fputs (".gtu", file);
1783 break;
1784 case UNORDERED:
1785 fputs (".nan", file);
1786 break;
1787 case ORDERED:
1788 fputs (".num", file);
1789 break;
1790 default:
1791 gcc_unreachable ();
1792 }
1793 if (FLOAT_MODE_P (op_mode)
1794 || x_code == EQ || x_code == NE
1795 || x_code == GEU || x_code == GTU
1796 || x_code == LEU || x_code == LTU)
1797 fputs (nvptx_ptx_type_from_mode (op_mode, true), file);
1798 else
1799 fprintf (file, ".s%d", GET_MODE_BITSIZE (op_mode));
1800 break;
1801 default:
1802 common:
1803 switch (x_code)
1804 {
1805 case SUBREG:
1806 x = SUBREG_REG (x);
1807 /* fall through */
1808
1809 case REG:
1810 if (HARD_REGISTER_P (x))
1811 fprintf (file, "%s", reg_names[REGNO (x)]);
1812 else
1813 fprintf (file, "%%r%d", REGNO (x));
1814 if (code != 'f' && nvptx_split_reg_p (GET_MODE (x)))
1815 {
1816 gcc_assert (GET_CODE (orig_x) == SUBREG
1817 && !nvptx_split_reg_p (GET_MODE (orig_x)));
1818 fprintf (file, "$%d", SUBREG_BYTE (orig_x) / UNITS_PER_WORD);
1819 }
1820 break;
1821
1822 case MEM:
1823 fputc ('[', file);
1824 nvptx_print_address_operand (file, XEXP (x, 0), GET_MODE (x));
1825 fputc (']', file);
1826 break;
1827
1828 case CONST_INT:
1829 output_addr_const (file, x);
1830 break;
1831
1832 case CONST:
1833 case SYMBOL_REF:
1834 case LABEL_REF:
1835 /* We could use output_addr_const, but that can print things like
1836 "x-8", which breaks ptxas. Need to ensure it is output as
1837 "x+-8". */
1838 nvptx_print_address_operand (file, x, VOIDmode);
1839 break;
1840
1841 case CONST_DOUBLE:
1842 long vals[2];
1843 REAL_VALUE_TYPE real;
1844 REAL_VALUE_FROM_CONST_DOUBLE (real, x);
1845 real_to_target (vals, &real, GET_MODE (x));
1846 vals[0] &= 0xffffffff;
1847 vals[1] &= 0xffffffff;
1848 if (GET_MODE (x) == SFmode)
1849 fprintf (file, "0f%08lx", vals[0]);
1850 else
1851 fprintf (file, "0d%08lx%08lx", vals[1], vals[0]);
1852 break;
1853
1854 default:
1855 output_addr_const (file, x);
1856 }
1857 }
1858}
1859\f
1860/* Record replacement regs used to deal with subreg operands. */
1861struct reg_replace
1862{
1863 rtx replacement[MAX_RECOG_OPERANDS];
1864 machine_mode mode;
1865 int n_allocated;
1866 int n_in_use;
1867};
1868
1869/* Allocate or reuse a replacement in R and return the rtx. */
1870
1871static rtx
1872get_replacement (struct reg_replace *r)
1873{
1874 if (r->n_allocated == r->n_in_use)
1875 r->replacement[r->n_allocated++] = gen_reg_rtx (r->mode);
1876 return r->replacement[r->n_in_use++];
1877}
1878
1879/* Clean up subreg operands. In ptx assembly, everything is typed, and
1880 the presence of subregs would break the rules for most instructions.
1881 Replace them with a suitable new register of the right size, plus
1882 conversion copyin/copyout instructions. */
1883
1884static void
1885nvptx_reorg (void)
1886{
1887 struct reg_replace qiregs, hiregs, siregs, diregs;
1888 rtx_insn *insn, *next;
1889
1890 /* We are freeing block_for_insn in the toplev to keep compatibility
1891 with old MDEP_REORGS that are not CFG based. Recompute it now. */
1892 compute_bb_for_insn ();
1893
1894 df_clear_flags (DF_LR_RUN_DCE);
1895 df_analyze ();
1896
1897 thread_prologue_and_epilogue_insns ();
1898
1899 qiregs.n_allocated = 0;
1900 hiregs.n_allocated = 0;
1901 siregs.n_allocated = 0;
1902 diregs.n_allocated = 0;
1903 qiregs.mode = QImode;
1904 hiregs.mode = HImode;
1905 siregs.mode = SImode;
1906 diregs.mode = DImode;
1907
1908 for (insn = get_insns (); insn; insn = next)
1909 {
1910 next = NEXT_INSN (insn);
1911 if (!NONDEBUG_INSN_P (insn)
1912 || asm_noperands (insn) >= 0
1913 || GET_CODE (PATTERN (insn)) == USE
1914 || GET_CODE (PATTERN (insn)) == CLOBBER)
1915 continue;
1916 qiregs.n_in_use = 0;
1917 hiregs.n_in_use = 0;
1918 siregs.n_in_use = 0;
1919 diregs.n_in_use = 0;
1920 extract_insn (insn);
1921 enum attr_subregs_ok s_ok = get_attr_subregs_ok (insn);
1922 for (int i = 0; i < recog_data.n_operands; i++)
1923 {
1924 rtx op = recog_data.operand[i];
1925 if (GET_CODE (op) != SUBREG)
1926 continue;
1927
1928 rtx inner = SUBREG_REG (op);
1929
1930 machine_mode outer_mode = GET_MODE (op);
1931 machine_mode inner_mode = GET_MODE (inner);
1932 gcc_assert (s_ok);
1933 if (s_ok
1934 && (GET_MODE_PRECISION (inner_mode)
1935 >= GET_MODE_PRECISION (outer_mode)))
1936 continue;
1937 gcc_assert (SCALAR_INT_MODE_P (outer_mode));
1938 struct reg_replace *r = (outer_mode == QImode ? &qiregs
1939 : outer_mode == HImode ? &hiregs
1940 : outer_mode == SImode ? &siregs
1941 : &diregs);
1942 rtx new_reg = get_replacement (r);
1943
1944 if (recog_data.operand_type[i] != OP_OUT)
1945 {
1946 enum rtx_code code;
1947 if (GET_MODE_PRECISION (inner_mode)
1948 < GET_MODE_PRECISION (outer_mode))
1949 code = ZERO_EXTEND;
1950 else
1951 code = TRUNCATE;
1952
d1f9b275 1953 rtx pat = gen_rtx_SET (new_reg,
8ce80784 1954 gen_rtx_fmt_e (code, outer_mode, inner));
1955 emit_insn_before (pat, insn);
1956 }
1957
1958 if (recog_data.operand_type[i] != OP_IN)
1959 {
1960 enum rtx_code code;
1961 if (GET_MODE_PRECISION (inner_mode)
1962 < GET_MODE_PRECISION (outer_mode))
1963 code = TRUNCATE;
1964 else
1965 code = ZERO_EXTEND;
1966
d1f9b275 1967 rtx pat = gen_rtx_SET (inner,
8ce80784 1968 gen_rtx_fmt_e (code, inner_mode, new_reg));
1969 emit_insn_after (pat, insn);
1970 }
1971 validate_change (insn, recog_data.operand_loc[i], new_reg, false);
1972 }
1973 }
1974
1975 int maxregs = max_reg_num ();
1976 regstat_init_n_sets_and_refs ();
1977
1978 for (int i = LAST_VIRTUAL_REGISTER + 1; i < maxregs; i++)
1979 if (REG_N_SETS (i) == 0 && REG_N_REFS (i) == 0)
1980 regno_reg_rtx[i] = const0_rtx;
1981 regstat_free_n_sets_and_refs ();
1982}
1983\f
1984/* Handle a "kernel" attribute; arguments as in
1985 struct attribute_spec.handler. */
1986
1987static tree
1988nvptx_handle_kernel_attribute (tree *node, tree name, tree ARG_UNUSED (args),
1989 int ARG_UNUSED (flags), bool *no_add_attrs)
1990{
1991 tree decl = *node;
1992
1993 if (TREE_CODE (decl) != FUNCTION_DECL)
1994 {
1995 error ("%qE attribute only applies to functions", name);
1996 *no_add_attrs = true;
1997 }
1998
1999 else if (TREE_TYPE (TREE_TYPE (decl)) != void_type_node)
2000 {
2001 error ("%qE attribute requires a void return type", name);
2002 *no_add_attrs = true;
2003 }
2004
2005 return NULL_TREE;
2006}
2007
2008/* Table of valid machine attributes. */
2009static const struct attribute_spec nvptx_attribute_table[] =
2010{
2011 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
2012 affects_type_identity } */
2013 { "kernel", 0, 0, true, false, false, nvptx_handle_kernel_attribute, false },
2014 { NULL, 0, 0, false, false, false, NULL, false }
2015};
2016\f
2017/* Limit vector alignments to BIGGEST_ALIGNMENT. */
2018
2019static HOST_WIDE_INT
2020nvptx_vector_alignment (const_tree type)
2021{
2022 HOST_WIDE_INT align = tree_to_shwi (TYPE_SIZE (type));
2023
2024 return MIN (align, BIGGEST_ALIGNMENT);
2025}
2026\f
9c08fbb3 2027/* Record a symbol for mkoffload to enter into the mapping table. */
2028
2029static void
2030nvptx_record_offload_symbol (tree decl)
2031{
2032 fprintf (asm_out_file, "//:%s_MAP %s\n",
2033 TREE_CODE (decl) == VAR_DECL ? "VAR" : "FUNC",
2034 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
2035}
2036
8ce80784 2037/* Implement TARGET_ASM_FILE_START. Write the kinds of things ptxas expects
2038 at the start of a file. */
2039
2040static void
2041nvptx_file_start (void)
2042{
2043 fputs ("// BEGIN PREAMBLE\n", asm_out_file);
2044 fputs ("\t.version\t3.1\n", asm_out_file);
2045 fputs ("\t.target\tsm_30\n", asm_out_file);
2046 fprintf (asm_out_file, "\t.address_size %d\n", GET_MODE_BITSIZE (Pmode));
2047 fputs ("// END PREAMBLE\n", asm_out_file);
2048}
2049
8ce80784 2050/* Write out the function declarations we've collected. */
2051
2052static void
2053nvptx_file_end (void)
2054{
b0c5be65 2055 hash_table<tree_hasher>::iterator iter;
2056 tree decl;
2057 FOR_EACH_HASH_TABLE_ELEMENT (*needed_fndecls_htab, decl, tree, iter)
2058 nvptx_record_fndecl (decl, true);
8ce80784 2059 fputs (func_decls.str().c_str(), asm_out_file);
2060}
2061\f
2062#undef TARGET_OPTION_OVERRIDE
2063#define TARGET_OPTION_OVERRIDE nvptx_option_override
2064
2065#undef TARGET_ATTRIBUTE_TABLE
2066#define TARGET_ATTRIBUTE_TABLE nvptx_attribute_table
2067
2068#undef TARGET_LEGITIMATE_ADDRESS_P
2069#define TARGET_LEGITIMATE_ADDRESS_P nvptx_legitimate_address_p
2070
2071#undef TARGET_PROMOTE_FUNCTION_MODE
2072#define TARGET_PROMOTE_FUNCTION_MODE nvptx_promote_function_mode
2073
2074#undef TARGET_FUNCTION_ARG
2075#define TARGET_FUNCTION_ARG nvptx_function_arg
2076#undef TARGET_FUNCTION_INCOMING_ARG
2077#define TARGET_FUNCTION_INCOMING_ARG nvptx_function_incoming_arg
2078#undef TARGET_FUNCTION_ARG_ADVANCE
2079#define TARGET_FUNCTION_ARG_ADVANCE nvptx_function_arg_advance
2080#undef TARGET_FUNCTION_ARG_BOUNDARY
2081#define TARGET_FUNCTION_ARG_BOUNDARY nvptx_function_arg_boundary
2082#undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY
2083#define TARGET_FUNCTION_ARG_ROUND_BOUNDARY nvptx_function_arg_boundary
2084#undef TARGET_PASS_BY_REFERENCE
2085#define TARGET_PASS_BY_REFERENCE nvptx_pass_by_reference
2086#undef TARGET_FUNCTION_VALUE_REGNO_P
2087#define TARGET_FUNCTION_VALUE_REGNO_P nvptx_function_value_regno_p
2088#undef TARGET_FUNCTION_VALUE
2089#define TARGET_FUNCTION_VALUE nvptx_function_value
2090#undef TARGET_LIBCALL_VALUE
2091#define TARGET_LIBCALL_VALUE nvptx_libcall_value
2092#undef TARGET_FUNCTION_OK_FOR_SIBCALL
2093#define TARGET_FUNCTION_OK_FOR_SIBCALL nvptx_function_ok_for_sibcall
2094#undef TARGET_SPLIT_COMPLEX_ARG
2095#define TARGET_SPLIT_COMPLEX_ARG hook_bool_const_tree_true
2096#undef TARGET_RETURN_IN_MEMORY
2097#define TARGET_RETURN_IN_MEMORY nvptx_return_in_memory
2098#undef TARGET_OMIT_STRUCT_RETURN_REG
2099#define TARGET_OMIT_STRUCT_RETURN_REG true
2100#undef TARGET_STRICT_ARGUMENT_NAMING
2101#define TARGET_STRICT_ARGUMENT_NAMING nvptx_strict_argument_naming
2102#undef TARGET_STATIC_CHAIN
2103#define TARGET_STATIC_CHAIN nvptx_static_chain
2104
2105#undef TARGET_CALL_ARGS
2106#define TARGET_CALL_ARGS nvptx_call_args
2107#undef TARGET_END_CALL_ARGS
2108#define TARGET_END_CALL_ARGS nvptx_end_call_args
2109
2110#undef TARGET_ASM_FILE_START
2111#define TARGET_ASM_FILE_START nvptx_file_start
2112#undef TARGET_ASM_FILE_END
2113#define TARGET_ASM_FILE_END nvptx_file_end
2114#undef TARGET_ASM_GLOBALIZE_LABEL
2115#define TARGET_ASM_GLOBALIZE_LABEL nvptx_globalize_label
2116#undef TARGET_ASM_ASSEMBLE_UNDEFINED_DECL
2117#define TARGET_ASM_ASSEMBLE_UNDEFINED_DECL nvptx_assemble_undefined_decl
2118#undef TARGET_PRINT_OPERAND
2119#define TARGET_PRINT_OPERAND nvptx_print_operand
2120#undef TARGET_PRINT_OPERAND_ADDRESS
2121#define TARGET_PRINT_OPERAND_ADDRESS nvptx_print_operand_address
2122#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
2123#define TARGET_PRINT_OPERAND_PUNCT_VALID_P nvptx_print_operand_punct_valid_p
2124#undef TARGET_ASM_INTEGER
2125#define TARGET_ASM_INTEGER nvptx_assemble_integer
2126#undef TARGET_ASM_DECL_END
2127#define TARGET_ASM_DECL_END nvptx_assemble_decl_end
2128#undef TARGET_ASM_DECLARE_CONSTANT_NAME
2129#define TARGET_ASM_DECLARE_CONSTANT_NAME nvptx_asm_declare_constant_name
2130#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
2131#define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true
2132#undef TARGET_ASM_NEED_VAR_DECL_BEFORE_USE
2133#define TARGET_ASM_NEED_VAR_DECL_BEFORE_USE true
2134
2135#undef TARGET_MACHINE_DEPENDENT_REORG
2136#define TARGET_MACHINE_DEPENDENT_REORG nvptx_reorg
2137#undef TARGET_NO_REGISTER_ALLOCATION
2138#define TARGET_NO_REGISTER_ALLOCATION true
2139
9c08fbb3 2140#undef TARGET_RECORD_OFFLOAD_SYMBOL
2141#define TARGET_RECORD_OFFLOAD_SYMBOL nvptx_record_offload_symbol
2142
8ce80784 2143#undef TARGET_VECTOR_ALIGNMENT
2144#define TARGET_VECTOR_ALIGNMENT nvptx_vector_alignment
2145
2146struct gcc_target targetm = TARGET_INITIALIZER;
2147
2148#include "gt-nvptx.h"