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