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