* config/pa/linux-atomic.c (__kernel_cmpxchg): Reorder arguments to
[official-gcc.git] / gcc / config / nds32 / nds32-isr.c
blobedbabc49c11ca06bc218dd2cfbfe390646012bbf
1 /* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2015 Free Software Foundation, Inc.
3 Contributed by Andes Technology Corporation.
5 This file is part of GCC.
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.
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.
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/>. */
21 /* ------------------------------------------------------------------------ */
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "alias.h"
28 #include "symtab.h"
29 #include "tree.h"
30 #include "stor-layout.h"
31 #include "varasm.h"
32 #include "calls.h"
33 #include "rtl.h"
34 #include "regs.h"
35 #include "hard-reg-set.h"
36 #include "insn-config.h" /* Required by recog.h. */
37 #include "conditions.h"
38 #include "output.h"
39 #include "insn-attr.h" /* For DFA state_t. */
40 #include "insn-codes.h" /* For CODE_FOR_xxx. */
41 #include "reload.h" /* For push_reload(). */
42 #include "flags.h"
43 #include "function.h"
44 #include "insn-config.h"
45 #include "expmed.h"
46 #include "dojump.h"
47 #include "explow.h"
48 #include "emit-rtl.h"
49 #include "stmt.h"
50 #include "expr.h"
51 #include "recog.h"
52 #include "diagnostic-core.h"
53 #include "dominance.h"
54 #include "cfg.h"
55 #include "cfgrtl.h"
56 #include "cfganal.h"
57 #include "lcm.h"
58 #include "cfgbuild.h"
59 #include "cfgcleanup.h"
60 #include "predict.h"
61 #include "basic-block.h"
62 #include "df.h"
63 #include "tm_p.h"
64 #include "tm-constrs.h"
65 #include "optabs.h" /* For GEN_FCN. */
66 #include "target.h"
67 #include "langhooks.h" /* For add_builtin_function(). */
68 #include "builtins.h"
70 /* ------------------------------------------------------------------------ */
72 /* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
73 0 for reset handler with __attribute__((reset())),
74 1-8 for exception handler with __attribute__((exception(1,...,8))),
75 and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
76 We use an array to record essential information for each vector. */
77 static struct nds32_isr_info nds32_isr_vectors[NDS32_N_ISR_VECTORS];
79 /* ------------------------------------------------------------------------ */
81 /* A helper function to emit section head template. */
82 static void
83 nds32_emit_section_head_template (char section_name[],
84 char symbol_name[],
85 int align_value,
86 bool object_p)
88 const char *flags_str;
89 const char *type_str;
91 flags_str = (object_p) ? "\"a\"" : "\"ax\"";
92 type_str = (object_p) ? "@object" : "@function";
94 fprintf (asm_out_file, "\t.section\t%s, %s\n", section_name, flags_str);
95 fprintf (asm_out_file, "\t.align\t%d\n", align_value);
96 fprintf (asm_out_file, "\t.global\t%s\n", symbol_name);
97 fprintf (asm_out_file, "\t.type\t%s, %s\n", symbol_name, type_str);
98 fprintf (asm_out_file, "%s:\n", symbol_name);
101 /* A helper function to emit section tail template. */
102 static void
103 nds32_emit_section_tail_template (char symbol_name[])
105 fprintf (asm_out_file, "\t.size\t%s, .-%s\n", symbol_name, symbol_name);
108 /* Function to emit isr jump table section. */
109 static void
110 nds32_emit_isr_jmptbl_section (int vector_id)
112 char section_name[100];
113 char symbol_name[100];
115 /* Prepare jmptbl section and symbol name. */
116 snprintf (section_name, sizeof (section_name),
117 ".nds32_jmptbl.%02d", vector_id);
118 snprintf (symbol_name, sizeof (symbol_name),
119 "_nds32_jmptbl_%02d", vector_id);
121 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
122 fprintf (asm_out_file, "\t.word\t%s\n",
123 nds32_isr_vectors[vector_id].func_name);
124 nds32_emit_section_tail_template (symbol_name);
127 /* Function to emit isr vector section. */
128 static void
129 nds32_emit_isr_vector_section (int vector_id)
131 unsigned int vector_number_offset = 0;
132 const char *c_str = "CATEGORY";
133 const char *sr_str = "SR";
134 const char *nt_str = "NT";
135 const char *vs_str = "VS";
136 char first_level_handler_name[100];
137 char section_name[100];
138 char symbol_name[100];
140 /* Set the vector number offset so that we can calculate
141 the value that user specifies in the attribute.
142 We also prepare the category string for first level handler name. */
143 switch (nds32_isr_vectors[vector_id].category)
145 case NDS32_ISR_INTERRUPT:
146 vector_number_offset = 9;
147 c_str = "i";
148 break;
149 case NDS32_ISR_EXCEPTION:
150 vector_number_offset = 0;
151 c_str = "e";
152 break;
153 case NDS32_ISR_NONE:
154 case NDS32_ISR_RESET:
155 /* Normally it should not be here. */
156 gcc_unreachable ();
157 break;
160 /* Prepare save reg string for first level handler name. */
161 switch (nds32_isr_vectors[vector_id].save_reg)
163 case NDS32_SAVE_ALL:
164 sr_str = "sa";
165 break;
166 case NDS32_PARTIAL_SAVE:
167 sr_str = "ps";
168 break;
171 /* Prepare nested type string for first level handler name. */
172 switch (nds32_isr_vectors[vector_id].nested_type)
174 case NDS32_NESTED:
175 nt_str = "ns";
176 break;
177 case NDS32_NOT_NESTED:
178 nt_str = "nn";
179 break;
180 case NDS32_NESTED_READY:
181 nt_str = "nr";
182 break;
185 /* Currently we have 4-byte or 16-byte size for each vector.
186 If it is 4-byte, the first level handler name has suffix string "_4b". */
187 vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
189 /* Now we can create first level handler name. */
190 snprintf (first_level_handler_name, sizeof (first_level_handler_name),
191 "_nds32_%s_%s_%s%s", c_str, sr_str, nt_str, vs_str);
193 /* Prepare vector section and symbol name. */
194 snprintf (section_name, sizeof (section_name),
195 ".nds32_vector.%02d", vector_id);
196 snprintf (symbol_name, sizeof (symbol_name),
197 "_nds32_vector_%02d%s", vector_id, vs_str);
200 /* Everything is ready. We can start emit vector section content. */
201 nds32_emit_section_head_template (section_name, symbol_name,
202 floor_log2 (nds32_isr_vector_size), false);
204 /* According to the vector size, the instructions in the
205 vector section may be different. */
206 if (nds32_isr_vector_size == 4)
208 /* This block is for 4-byte vector size.
209 Hardware $VID support is necessary and only one instruction
210 is needed in vector section. */
211 fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
212 first_level_handler_name);
214 else
216 /* This block is for 16-byte vector size.
217 There is NO hardware $VID so that we need several instructions
218 such as pushing GPRs and preparing software vid at vector section.
219 For pushing GPRs, there are four variations for
220 16-byte vector content and we have to handle each combination.
221 For preparing software vid, note that the vid need to
222 be substracted vector_number_offset. */
223 if (TARGET_REDUCED_REGS)
225 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
227 /* Case of reduced set registers and save_all attribute. */
228 fprintf (asm_out_file, "\t! reduced set regs + save_all\n");
229 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
230 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
233 else
235 /* Case of reduced set registers and partial_save attribute. */
236 fprintf (asm_out_file, "\t! reduced set regs + partial_save\n");
237 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
238 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
241 else
243 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
245 /* Case of full set registers and save_all attribute. */
246 fprintf (asm_out_file, "\t! full set regs + save_all\n");
247 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
249 else
251 /* Case of full set registers and partial_save attribute. */
252 fprintf (asm_out_file, "\t! full set regs + partial_save\n");
253 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
254 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
258 fprintf (asm_out_file, "\tmovi\t$r0, %d ! preparing software vid\n",
259 vector_id - vector_number_offset);
260 fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
261 first_level_handler_name);
264 nds32_emit_section_tail_template (symbol_name);
267 /* Function to emit isr reset handler content.
268 Including all jmptbl/vector references, jmptbl section,
269 vector section, nmi handler section, and warm handler section. */
270 static void
271 nds32_emit_isr_reset_content (void)
273 unsigned int i;
274 unsigned int total_n_vectors;
275 const char *vs_str;
276 char reset_handler_name[100];
277 char section_name[100];
278 char symbol_name[100];
280 total_n_vectors = nds32_isr_vectors[0].total_n_vectors;
281 vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
283 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n");
285 /* Create references in .rodata according to total number of vectors. */
286 fprintf (asm_out_file, "\t.section\t.rodata\n");
287 fprintf (asm_out_file, "\t.align\t2\n");
289 /* Emit jmptbl references. */
290 fprintf (asm_out_file, "\t ! references to jmptbl section entries\n");
291 for (i = 0; i < total_n_vectors; i++)
292 fprintf (asm_out_file, "\t.word\t_nds32_jmptbl_%02d\n", i);
294 /* Emit vector references. */
295 fprintf (asm_out_file, "\t ! references to vector section entries\n");
296 for (i = 0; i < total_n_vectors; i++)
297 fprintf (asm_out_file, "\t.word\t_nds32_vector_%02d%s\n", i, vs_str);
299 /* Emit jmptbl_00 section. */
300 snprintf (section_name, sizeof (section_name), ".nds32_jmptbl.00");
301 snprintf (symbol_name, sizeof (symbol_name), "_nds32_jmptbl_00");
303 fprintf (asm_out_file, "\t! ....................................\n");
304 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
305 fprintf (asm_out_file, "\t.word\t%s\n",
306 nds32_isr_vectors[0].func_name);
307 nds32_emit_section_tail_template (symbol_name);
309 /* Emit vector_00 section. */
310 snprintf (section_name, sizeof (section_name), ".nds32_vector.00");
311 snprintf (symbol_name, sizeof (symbol_name), "_nds32_vector_00%s", vs_str);
312 snprintf (reset_handler_name, sizeof (reset_handler_name),
313 "_nds32_reset%s", vs_str);
315 fprintf (asm_out_file, "\t! ....................................\n");
316 nds32_emit_section_head_template (section_name, symbol_name,
317 floor_log2 (nds32_isr_vector_size), false);
318 fprintf (asm_out_file, "\tj\t%s ! jump to reset handler\n",
319 reset_handler_name);
320 nds32_emit_section_tail_template (symbol_name);
322 /* Emit nmi handler section. */
323 snprintf (section_name, sizeof (section_name), ".nds32_nmih");
324 snprintf (symbol_name, sizeof (symbol_name), "_nds32_nmih");
326 fprintf (asm_out_file, "\t! ....................................\n");
327 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
328 fprintf (asm_out_file, "\t.word\t%s\n",
329 (strlen (nds32_isr_vectors[0].nmi_name) == 0)
330 ? "0"
331 : nds32_isr_vectors[0].nmi_name);
332 nds32_emit_section_tail_template (symbol_name);
334 /* Emit warm handler section. */
335 snprintf (section_name, sizeof (section_name), ".nds32_wrh");
336 snprintf (symbol_name, sizeof (symbol_name), "_nds32_wrh");
338 fprintf (asm_out_file, "\t! ....................................\n");
339 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
340 fprintf (asm_out_file, "\t.word\t%s\n",
341 (strlen (nds32_isr_vectors[0].warm_name) == 0)
342 ? "0"
343 : nds32_isr_vectors[0].warm_name);
344 nds32_emit_section_tail_template (symbol_name);
346 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - END !\n");
349 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
350 to check if there are any conflict isr-specific attributes being set.
351 We need to check:
352 1. Only 'save_all' or 'partial_save' in the attributes.
353 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
354 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
355 void
356 nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
358 int save_all_p, partial_save_p;
359 int nested_p, not_nested_p, nested_ready_p;
360 int intr_p, excp_p, reset_p;
362 /* Initialize variables. */
363 save_all_p = partial_save_p = 0;
364 nested_p = not_nested_p = nested_ready_p = 0;
365 intr_p = excp_p = reset_p = 0;
367 /* We must check at MOST one attribute to set save-reg. */
368 if (lookup_attribute ("save_all", func_attrs))
369 save_all_p = 1;
370 if (lookup_attribute ("partial_save", func_attrs))
371 partial_save_p = 1;
373 if ((save_all_p + partial_save_p) > 1)
374 error ("multiple save reg attributes to function %qD", func_decl);
376 /* We must check at MOST one attribute to set nested-type. */
377 if (lookup_attribute ("nested", func_attrs))
378 nested_p = 1;
379 if (lookup_attribute ("not_nested", func_attrs))
380 not_nested_p = 1;
381 if (lookup_attribute ("nested_ready", func_attrs))
382 nested_ready_p = 1;
384 if ((nested_p + not_nested_p + nested_ready_p) > 1)
385 error ("multiple nested types attributes to function %qD", func_decl);
387 /* We must check at MOST one attribute to
388 set interrupt/exception/reset. */
389 if (lookup_attribute ("interrupt", func_attrs))
390 intr_p = 1;
391 if (lookup_attribute ("exception", func_attrs))
392 excp_p = 1;
393 if (lookup_attribute ("reset", func_attrs))
394 reset_p = 1;
396 if ((intr_p + excp_p + reset_p) > 1)
397 error ("multiple interrupt attributes to function %qD", func_decl);
400 /* Function to construct isr vectors information array.
401 We DO NOT HAVE TO check if the attributes are valid
402 because those works are supposed to be done on
403 nds32_merge_decl_attributes() and nds32_insert_attributes(). */
404 void
405 nds32_construct_isr_vectors_information (tree func_attrs,
406 const char *func_name)
408 tree save_all, partial_save;
409 tree nested, not_nested, nested_ready;
410 tree intr, excp, reset;
412 save_all = lookup_attribute ("save_all", func_attrs);
413 partial_save = lookup_attribute ("partial_save", func_attrs);
415 nested = lookup_attribute ("nested", func_attrs);
416 not_nested = lookup_attribute ("not_nested", func_attrs);
417 nested_ready = lookup_attribute ("nested_ready", func_attrs);
419 intr = lookup_attribute ("interrupt", func_attrs);
420 excp = lookup_attribute ("exception", func_attrs);
421 reset = lookup_attribute ("reset", func_attrs);
423 /* If there is no interrupt/exception/reset, we can return immediately. */
424 if (!intr && !excp && !reset)
425 return;
427 /* If we are here, either we have interrupt/exception,
428 or reset attribute. */
429 if (intr || excp)
431 tree id_list;
433 /* Prepare id list so that we can traverse and set vector id. */
434 id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp));
436 while (id_list)
438 tree id;
439 int vector_id;
440 unsigned int vector_number_offset;
442 /* The way to handle interrupt or exception is the same,
443 we just need to take care of actual vector number.
444 For interrupt(0..63), the actual vector number is (9..72).
445 For exception(1..8), the actual vector number is (1..8). */
446 vector_number_offset = (intr) ? (9) : (0);
448 /* Pick up each vector id value. */
449 id = TREE_VALUE (id_list);
450 /* Add vector_number_offset to get actual vector number. */
451 vector_id = TREE_INT_CST_LOW (id) + vector_number_offset;
453 /* Enable corresponding vector and set function name. */
454 nds32_isr_vectors[vector_id].category = (intr)
455 ? (NDS32_ISR_INTERRUPT)
456 : (NDS32_ISR_EXCEPTION);
457 strcpy (nds32_isr_vectors[vector_id].func_name, func_name);
459 /* Set register saving scheme. */
460 if (save_all)
461 nds32_isr_vectors[vector_id].save_reg = NDS32_SAVE_ALL;
462 else if (partial_save)
463 nds32_isr_vectors[vector_id].save_reg = NDS32_PARTIAL_SAVE;
465 /* Set nested type. */
466 if (nested)
467 nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED;
468 else if (not_nested)
469 nds32_isr_vectors[vector_id].nested_type = NDS32_NOT_NESTED;
470 else if (nested_ready)
471 nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED_READY;
473 /* Advance to next id. */
474 id_list = TREE_CHAIN (id_list);
477 else
479 tree id_list;
480 tree id;
481 tree nmi, warm;
483 /* Deal with reset attribute. Its vector number is always 0. */
484 nds32_isr_vectors[0].category = NDS32_ISR_RESET;
486 /* Prepare id_list and identify id value so that
487 we can set total number of vectors. */
488 id_list = TREE_VALUE (reset);
489 id = TREE_VALUE (id_list);
491 /* The total vectors = interrupt + exception numbers + reset.
492 There are 8 exception and 1 reset in nds32 architecture. */
493 nds32_isr_vectors[0].total_n_vectors = TREE_INT_CST_LOW (id) + 8 + 1;
494 strcpy (nds32_isr_vectors[0].func_name, func_name);
496 /* Retrieve nmi and warm function. */
497 nmi = lookup_attribute ("nmi", func_attrs);
498 warm = lookup_attribute ("warm", func_attrs);
500 if (nmi != NULL_TREE)
502 tree nmi_func_list;
503 tree nmi_func;
505 nmi_func_list = TREE_VALUE (nmi);
506 nmi_func = TREE_VALUE (nmi_func_list);
508 /* Record nmi function name. */
509 strcpy (nds32_isr_vectors[0].nmi_name,
510 IDENTIFIER_POINTER (nmi_func));
513 if (warm != NULL_TREE)
515 tree warm_func_list;
516 tree warm_func;
518 warm_func_list = TREE_VALUE (warm);
519 warm_func = TREE_VALUE (warm_func_list);
521 /* Record warm function name. */
522 strcpy (nds32_isr_vectors[0].warm_name,
523 IDENTIFIER_POINTER (warm_func));
528 /* A helper function to handle isr stuff at the beginning of asm file. */
529 void
530 nds32_asm_file_start_for_isr (void)
532 int i;
534 /* Initialize isr vector information array before compiling functions. */
535 for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
537 nds32_isr_vectors[i].category = NDS32_ISR_NONE;
538 strcpy (nds32_isr_vectors[i].func_name, "");
539 nds32_isr_vectors[i].save_reg = NDS32_PARTIAL_SAVE;
540 nds32_isr_vectors[i].nested_type = NDS32_NOT_NESTED;
541 nds32_isr_vectors[i].total_n_vectors = 0;
542 strcpy (nds32_isr_vectors[i].nmi_name, "");
543 strcpy (nds32_isr_vectors[i].warm_name, "");
547 /* A helper function to handle isr stuff at the end of asm file. */
548 void
549 nds32_asm_file_end_for_isr (void)
551 int i;
553 /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
554 for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
555 if (nds32_isr_vectors[i].category != NDS32_ISR_NONE)
556 break;
558 if (i == NDS32_N_ISR_VECTORS)
559 return;
561 /* At least one vector is NOT NDS32_ISR_NONE,
562 we should output isr vector information. */
563 fprintf (asm_out_file, "\t! ------------------------------------\n");
564 fprintf (asm_out_file, "\t! The isr vector information:\n");
565 fprintf (asm_out_file, "\t! ------------------------------------\n");
567 /* Check reset handler first. Its vector number is always 0. */
568 if (nds32_isr_vectors[0].category == NDS32_ISR_RESET)
570 nds32_emit_isr_reset_content ();
571 fprintf (asm_out_file, "\t! ------------------------------------\n");
574 /* Check other vectors, starting from vector number 1. */
575 for (i = 1; i < NDS32_N_ISR_VECTORS; i++)
577 if (nds32_isr_vectors[i].category == NDS32_ISR_INTERRUPT
578 || nds32_isr_vectors[i].category == NDS32_ISR_EXCEPTION)
580 /* Found one vector which is interupt or exception.
581 Output its jmptbl and vector section content. */
582 fprintf (asm_out_file, "\t! interrupt/exception vector %02d\n", i);
583 fprintf (asm_out_file, "\t! ------------------------------------\n");
584 nds32_emit_isr_jmptbl_section (i);
585 fprintf (asm_out_file, "\t! ....................................\n");
586 nds32_emit_isr_vector_section (i);
587 fprintf (asm_out_file, "\t! ------------------------------------\n");
592 /* Return true if FUNC is a isr function. */
593 bool
594 nds32_isr_function_p (tree func)
596 tree t_intr;
597 tree t_excp;
598 tree t_reset;
600 tree attrs;
602 if (TREE_CODE (func) != FUNCTION_DECL)
603 abort ();
605 attrs = DECL_ATTRIBUTES (func);
607 t_intr = lookup_attribute ("interrupt", attrs);
608 t_excp = lookup_attribute ("exception", attrs);
609 t_reset = lookup_attribute ("reset", attrs);
611 return ((t_intr != NULL_TREE)
612 || (t_excp != NULL_TREE)
613 || (t_reset != NULL_TREE));
616 /* ------------------------------------------------------------------------ */