Implement TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS hook.
[official-gcc.git] / gcc / config / nds32 / nds32-isr.c
blob8b4c0720348f922616916fb95ffaa170800653c2
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 "input.h"
28 #include "alias.h"
29 #include "symtab.h"
30 #include "tree.h"
31 #include "stor-layout.h"
32 #include "varasm.h"
33 #include "calls.h"
34 #include "rtl.h"
35 #include "regs.h"
36 #include "hard-reg-set.h"
37 #include "insn-config.h" /* Required by recog.h. */
38 #include "conditions.h"
39 #include "output.h"
40 #include "insn-attr.h" /* For DFA state_t. */
41 #include "insn-codes.h" /* For CODE_FOR_xxx. */
42 #include "reload.h" /* For push_reload(). */
43 #include "flags.h"
44 #include "function.h"
45 #include "insn-config.h"
46 #include "expmed.h"
47 #include "dojump.h"
48 #include "explow.h"
49 #include "emit-rtl.h"
50 #include "stmt.h"
51 #include "expr.h"
52 #include "recog.h"
53 #include "diagnostic-core.h"
54 #include "dominance.h"
55 #include "cfg.h"
56 #include "cfgrtl.h"
57 #include "cfganal.h"
58 #include "lcm.h"
59 #include "cfgbuild.h"
60 #include "cfgcleanup.h"
61 #include "predict.h"
62 #include "basic-block.h"
63 #include "df.h"
64 #include "tm_p.h"
65 #include "tm-constrs.h"
66 #include "optabs.h" /* For GEN_FCN. */
67 #include "target.h"
68 #include "target-def.h"
69 #include "langhooks.h" /* For add_builtin_function(). */
70 #include "builtins.h"
72 /* ------------------------------------------------------------------------ */
74 /* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
75 0 for reset handler with __attribute__((reset())),
76 1-8 for exception handler with __attribute__((exception(1,...,8))),
77 and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
78 We use an array to record essential information for each vector. */
79 static struct nds32_isr_info nds32_isr_vectors[NDS32_N_ISR_VECTORS];
81 /* ------------------------------------------------------------------------ */
83 /* A helper function to emit section head template. */
84 static void
85 nds32_emit_section_head_template (char section_name[],
86 char symbol_name[],
87 int align_value,
88 bool object_p)
90 const char *flags_str;
91 const char *type_str;
93 flags_str = (object_p) ? "\"a\"" : "\"ax\"";
94 type_str = (object_p) ? "@object" : "@function";
96 fprintf (asm_out_file, "\t.section\t%s, %s\n", section_name, flags_str);
97 fprintf (asm_out_file, "\t.align\t%d\n", align_value);
98 fprintf (asm_out_file, "\t.global\t%s\n", symbol_name);
99 fprintf (asm_out_file, "\t.type\t%s, %s\n", symbol_name, type_str);
100 fprintf (asm_out_file, "%s:\n", symbol_name);
103 /* A helper function to emit section tail template. */
104 static void
105 nds32_emit_section_tail_template (char symbol_name[])
107 fprintf (asm_out_file, "\t.size\t%s, .-%s\n", symbol_name, symbol_name);
110 /* Function to emit isr jump table section. */
111 static void
112 nds32_emit_isr_jmptbl_section (int vector_id)
114 char section_name[100];
115 char symbol_name[100];
117 /* Prepare jmptbl section and symbol name. */
118 snprintf (section_name, sizeof (section_name),
119 ".nds32_jmptbl.%02d", vector_id);
120 snprintf (symbol_name, sizeof (symbol_name),
121 "_nds32_jmptbl_%02d", vector_id);
123 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
124 fprintf (asm_out_file, "\t.word\t%s\n",
125 nds32_isr_vectors[vector_id].func_name);
126 nds32_emit_section_tail_template (symbol_name);
129 /* Function to emit isr vector section. */
130 static void
131 nds32_emit_isr_vector_section (int vector_id)
133 unsigned int vector_number_offset = 0;
134 const char *c_str = "CATEGORY";
135 const char *sr_str = "SR";
136 const char *nt_str = "NT";
137 const char *vs_str = "VS";
138 char first_level_handler_name[100];
139 char section_name[100];
140 char symbol_name[100];
142 /* Set the vector number offset so that we can calculate
143 the value that user specifies in the attribute.
144 We also prepare the category string for first level handler name. */
145 switch (nds32_isr_vectors[vector_id].category)
147 case NDS32_ISR_INTERRUPT:
148 vector_number_offset = 9;
149 c_str = "i";
150 break;
151 case NDS32_ISR_EXCEPTION:
152 vector_number_offset = 0;
153 c_str = "e";
154 break;
155 case NDS32_ISR_NONE:
156 case NDS32_ISR_RESET:
157 /* Normally it should not be here. */
158 gcc_unreachable ();
159 break;
162 /* Prepare save reg string for first level handler name. */
163 switch (nds32_isr_vectors[vector_id].save_reg)
165 case NDS32_SAVE_ALL:
166 sr_str = "sa";
167 break;
168 case NDS32_PARTIAL_SAVE:
169 sr_str = "ps";
170 break;
173 /* Prepare nested type string for first level handler name. */
174 switch (nds32_isr_vectors[vector_id].nested_type)
176 case NDS32_NESTED:
177 nt_str = "ns";
178 break;
179 case NDS32_NOT_NESTED:
180 nt_str = "nn";
181 break;
182 case NDS32_NESTED_READY:
183 nt_str = "nr";
184 break;
187 /* Currently we have 4-byte or 16-byte size for each vector.
188 If it is 4-byte, the first level handler name has suffix string "_4b". */
189 vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
191 /* Now we can create first level handler name. */
192 snprintf (first_level_handler_name, sizeof (first_level_handler_name),
193 "_nds32_%s_%s_%s%s", c_str, sr_str, nt_str, vs_str);
195 /* Prepare vector section and symbol name. */
196 snprintf (section_name, sizeof (section_name),
197 ".nds32_vector.%02d", vector_id);
198 snprintf (symbol_name, sizeof (symbol_name),
199 "_nds32_vector_%02d%s", vector_id, vs_str);
202 /* Everything is ready. We can start emit vector section content. */
203 nds32_emit_section_head_template (section_name, symbol_name,
204 floor_log2 (nds32_isr_vector_size), false);
206 /* According to the vector size, the instructions in the
207 vector section may be different. */
208 if (nds32_isr_vector_size == 4)
210 /* This block is for 4-byte vector size.
211 Hardware $VID support is necessary and only one instruction
212 is needed in vector section. */
213 fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
214 first_level_handler_name);
216 else
218 /* This block is for 16-byte vector size.
219 There is NO hardware $VID so that we need several instructions
220 such as pushing GPRs and preparing software vid at vector section.
221 For pushing GPRs, there are four variations for
222 16-byte vector content and we have to handle each combination.
223 For preparing software vid, note that the vid need to
224 be substracted vector_number_offset. */
225 if (TARGET_REDUCED_REGS)
227 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
229 /* Case of reduced set registers and save_all attribute. */
230 fprintf (asm_out_file, "\t! reduced set regs + save_all\n");
231 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
232 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
235 else
237 /* Case of reduced set registers and partial_save attribute. */
238 fprintf (asm_out_file, "\t! reduced set regs + partial_save\n");
239 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
240 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
243 else
245 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
247 /* Case of full set registers and save_all attribute. */
248 fprintf (asm_out_file, "\t! full set regs + save_all\n");
249 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
251 else
253 /* Case of full set registers and partial_save attribute. */
254 fprintf (asm_out_file, "\t! full set regs + partial_save\n");
255 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
256 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
260 fprintf (asm_out_file, "\tmovi\t$r0, %d ! preparing software vid\n",
261 vector_id - vector_number_offset);
262 fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
263 first_level_handler_name);
266 nds32_emit_section_tail_template (symbol_name);
269 /* Function to emit isr reset handler content.
270 Including all jmptbl/vector references, jmptbl section,
271 vector section, nmi handler section, and warm handler section. */
272 static void
273 nds32_emit_isr_reset_content (void)
275 unsigned int i;
276 unsigned int total_n_vectors;
277 const char *vs_str;
278 char reset_handler_name[100];
279 char section_name[100];
280 char symbol_name[100];
282 total_n_vectors = nds32_isr_vectors[0].total_n_vectors;
283 vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
285 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n");
287 /* Create references in .rodata according to total number of vectors. */
288 fprintf (asm_out_file, "\t.section\t.rodata\n");
289 fprintf (asm_out_file, "\t.align\t2\n");
291 /* Emit jmptbl references. */
292 fprintf (asm_out_file, "\t ! references to jmptbl section entries\n");
293 for (i = 0; i < total_n_vectors; i++)
294 fprintf (asm_out_file, "\t.word\t_nds32_jmptbl_%02d\n", i);
296 /* Emit vector references. */
297 fprintf (asm_out_file, "\t ! references to vector section entries\n");
298 for (i = 0; i < total_n_vectors; i++)
299 fprintf (asm_out_file, "\t.word\t_nds32_vector_%02d%s\n", i, vs_str);
301 /* Emit jmptbl_00 section. */
302 snprintf (section_name, sizeof (section_name), ".nds32_jmptbl.00");
303 snprintf (symbol_name, sizeof (symbol_name), "_nds32_jmptbl_00");
305 fprintf (asm_out_file, "\t! ....................................\n");
306 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
307 fprintf (asm_out_file, "\t.word\t%s\n",
308 nds32_isr_vectors[0].func_name);
309 nds32_emit_section_tail_template (symbol_name);
311 /* Emit vector_00 section. */
312 snprintf (section_name, sizeof (section_name), ".nds32_vector.00");
313 snprintf (symbol_name, sizeof (symbol_name), "_nds32_vector_00%s", vs_str);
314 snprintf (reset_handler_name, sizeof (reset_handler_name),
315 "_nds32_reset%s", vs_str);
317 fprintf (asm_out_file, "\t! ....................................\n");
318 nds32_emit_section_head_template (section_name, symbol_name,
319 floor_log2 (nds32_isr_vector_size), false);
320 fprintf (asm_out_file, "\tj\t%s ! jump to reset handler\n",
321 reset_handler_name);
322 nds32_emit_section_tail_template (symbol_name);
324 /* Emit nmi handler section. */
325 snprintf (section_name, sizeof (section_name), ".nds32_nmih");
326 snprintf (symbol_name, sizeof (symbol_name), "_nds32_nmih");
328 fprintf (asm_out_file, "\t! ....................................\n");
329 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
330 fprintf (asm_out_file, "\t.word\t%s\n",
331 (strlen (nds32_isr_vectors[0].nmi_name) == 0)
332 ? "0"
333 : nds32_isr_vectors[0].nmi_name);
334 nds32_emit_section_tail_template (symbol_name);
336 /* Emit warm handler section. */
337 snprintf (section_name, sizeof (section_name), ".nds32_wrh");
338 snprintf (symbol_name, sizeof (symbol_name), "_nds32_wrh");
340 fprintf (asm_out_file, "\t! ....................................\n");
341 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
342 fprintf (asm_out_file, "\t.word\t%s\n",
343 (strlen (nds32_isr_vectors[0].warm_name) == 0)
344 ? "0"
345 : nds32_isr_vectors[0].warm_name);
346 nds32_emit_section_tail_template (symbol_name);
348 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - END !\n");
351 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
352 to check if there are any conflict isr-specific attributes being set.
353 We need to check:
354 1. Only 'save_all' or 'partial_save' in the attributes.
355 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
356 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
357 void
358 nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
360 int save_all_p, partial_save_p;
361 int nested_p, not_nested_p, nested_ready_p;
362 int intr_p, excp_p, reset_p;
364 /* Initialize variables. */
365 save_all_p = partial_save_p = 0;
366 nested_p = not_nested_p = nested_ready_p = 0;
367 intr_p = excp_p = reset_p = 0;
369 /* We must check at MOST one attribute to set save-reg. */
370 if (lookup_attribute ("save_all", func_attrs))
371 save_all_p = 1;
372 if (lookup_attribute ("partial_save", func_attrs))
373 partial_save_p = 1;
375 if ((save_all_p + partial_save_p) > 1)
376 error ("multiple save reg attributes to function %qD", func_decl);
378 /* We must check at MOST one attribute to set nested-type. */
379 if (lookup_attribute ("nested", func_attrs))
380 nested_p = 1;
381 if (lookup_attribute ("not_nested", func_attrs))
382 not_nested_p = 1;
383 if (lookup_attribute ("nested_ready", func_attrs))
384 nested_ready_p = 1;
386 if ((nested_p + not_nested_p + nested_ready_p) > 1)
387 error ("multiple nested types attributes to function %qD", func_decl);
389 /* We must check at MOST one attribute to
390 set interrupt/exception/reset. */
391 if (lookup_attribute ("interrupt", func_attrs))
392 intr_p = 1;
393 if (lookup_attribute ("exception", func_attrs))
394 excp_p = 1;
395 if (lookup_attribute ("reset", func_attrs))
396 reset_p = 1;
398 if ((intr_p + excp_p + reset_p) > 1)
399 error ("multiple interrupt attributes to function %qD", func_decl);
402 /* Function to construct isr vectors information array.
403 We DO NOT HAVE TO check if the attributes are valid
404 because those works are supposed to be done on
405 nds32_merge_decl_attributes() and nds32_insert_attributes(). */
406 void
407 nds32_construct_isr_vectors_information (tree func_attrs,
408 const char *func_name)
410 tree save_all, partial_save;
411 tree nested, not_nested, nested_ready;
412 tree intr, excp, reset;
414 save_all = lookup_attribute ("save_all", func_attrs);
415 partial_save = lookup_attribute ("partial_save", func_attrs);
417 nested = lookup_attribute ("nested", func_attrs);
418 not_nested = lookup_attribute ("not_nested", func_attrs);
419 nested_ready = lookup_attribute ("nested_ready", func_attrs);
421 intr = lookup_attribute ("interrupt", func_attrs);
422 excp = lookup_attribute ("exception", func_attrs);
423 reset = lookup_attribute ("reset", func_attrs);
425 /* If there is no interrupt/exception/reset, we can return immediately. */
426 if (!intr && !excp && !reset)
427 return;
429 /* If we are here, either we have interrupt/exception,
430 or reset attribute. */
431 if (intr || excp)
433 tree id_list;
435 /* Prepare id list so that we can traverse and set vector id. */
436 id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp));
438 while (id_list)
440 tree id;
441 int vector_id;
442 unsigned int vector_number_offset;
444 /* The way to handle interrupt or exception is the same,
445 we just need to take care of actual vector number.
446 For interrupt(0..63), the actual vector number is (9..72).
447 For exception(1..8), the actual vector number is (1..8). */
448 vector_number_offset = (intr) ? (9) : (0);
450 /* Pick up each vector id value. */
451 id = TREE_VALUE (id_list);
452 /* Add vector_number_offset to get actual vector number. */
453 vector_id = TREE_INT_CST_LOW (id) + vector_number_offset;
455 /* Enable corresponding vector and set function name. */
456 nds32_isr_vectors[vector_id].category = (intr)
457 ? (NDS32_ISR_INTERRUPT)
458 : (NDS32_ISR_EXCEPTION);
459 strcpy (nds32_isr_vectors[vector_id].func_name, func_name);
461 /* Set register saving scheme. */
462 if (save_all)
463 nds32_isr_vectors[vector_id].save_reg = NDS32_SAVE_ALL;
464 else if (partial_save)
465 nds32_isr_vectors[vector_id].save_reg = NDS32_PARTIAL_SAVE;
467 /* Set nested type. */
468 if (nested)
469 nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED;
470 else if (not_nested)
471 nds32_isr_vectors[vector_id].nested_type = NDS32_NOT_NESTED;
472 else if (nested_ready)
473 nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED_READY;
475 /* Advance to next id. */
476 id_list = TREE_CHAIN (id_list);
479 else
481 tree id_list;
482 tree id;
483 tree nmi, warm;
485 /* Deal with reset attribute. Its vector number is always 0. */
486 nds32_isr_vectors[0].category = NDS32_ISR_RESET;
488 /* Prepare id_list and identify id value so that
489 we can set total number of vectors. */
490 id_list = TREE_VALUE (reset);
491 id = TREE_VALUE (id_list);
493 /* The total vectors = interrupt + exception numbers + reset.
494 There are 8 exception and 1 reset in nds32 architecture. */
495 nds32_isr_vectors[0].total_n_vectors = TREE_INT_CST_LOW (id) + 8 + 1;
496 strcpy (nds32_isr_vectors[0].func_name, func_name);
498 /* Retrieve nmi and warm function. */
499 nmi = lookup_attribute ("nmi", func_attrs);
500 warm = lookup_attribute ("warm", func_attrs);
502 if (nmi != NULL_TREE)
504 tree nmi_func_list;
505 tree nmi_func;
507 nmi_func_list = TREE_VALUE (nmi);
508 nmi_func = TREE_VALUE (nmi_func_list);
510 /* Record nmi function name. */
511 strcpy (nds32_isr_vectors[0].nmi_name,
512 IDENTIFIER_POINTER (nmi_func));
515 if (warm != NULL_TREE)
517 tree warm_func_list;
518 tree warm_func;
520 warm_func_list = TREE_VALUE (warm);
521 warm_func = TREE_VALUE (warm_func_list);
523 /* Record warm function name. */
524 strcpy (nds32_isr_vectors[0].warm_name,
525 IDENTIFIER_POINTER (warm_func));
530 /* A helper function to handle isr stuff at the beginning of asm file. */
531 void
532 nds32_asm_file_start_for_isr (void)
534 int i;
536 /* Initialize isr vector information array before compiling functions. */
537 for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
539 nds32_isr_vectors[i].category = NDS32_ISR_NONE;
540 strcpy (nds32_isr_vectors[i].func_name, "");
541 nds32_isr_vectors[i].save_reg = NDS32_PARTIAL_SAVE;
542 nds32_isr_vectors[i].nested_type = NDS32_NOT_NESTED;
543 nds32_isr_vectors[i].total_n_vectors = 0;
544 strcpy (nds32_isr_vectors[i].nmi_name, "");
545 strcpy (nds32_isr_vectors[i].warm_name, "");
549 /* A helper function to handle isr stuff at the end of asm file. */
550 void
551 nds32_asm_file_end_for_isr (void)
553 int i;
555 /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
556 for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
557 if (nds32_isr_vectors[i].category != NDS32_ISR_NONE)
558 break;
560 if (i == NDS32_N_ISR_VECTORS)
561 return;
563 /* At least one vector is NOT NDS32_ISR_NONE,
564 we should output isr vector information. */
565 fprintf (asm_out_file, "\t! ------------------------------------\n");
566 fprintf (asm_out_file, "\t! The isr vector information:\n");
567 fprintf (asm_out_file, "\t! ------------------------------------\n");
569 /* Check reset handler first. Its vector number is always 0. */
570 if (nds32_isr_vectors[0].category == NDS32_ISR_RESET)
572 nds32_emit_isr_reset_content ();
573 fprintf (asm_out_file, "\t! ------------------------------------\n");
576 /* Check other vectors, starting from vector number 1. */
577 for (i = 1; i < NDS32_N_ISR_VECTORS; i++)
579 if (nds32_isr_vectors[i].category == NDS32_ISR_INTERRUPT
580 || nds32_isr_vectors[i].category == NDS32_ISR_EXCEPTION)
582 /* Found one vector which is interupt or exception.
583 Output its jmptbl and vector section content. */
584 fprintf (asm_out_file, "\t! interrupt/exception vector %02d\n", i);
585 fprintf (asm_out_file, "\t! ------------------------------------\n");
586 nds32_emit_isr_jmptbl_section (i);
587 fprintf (asm_out_file, "\t! ....................................\n");
588 nds32_emit_isr_vector_section (i);
589 fprintf (asm_out_file, "\t! ------------------------------------\n");
594 /* Return true if FUNC is a isr function. */
595 bool
596 nds32_isr_function_p (tree func)
598 tree t_intr;
599 tree t_excp;
600 tree t_reset;
602 tree attrs;
604 if (TREE_CODE (func) != FUNCTION_DECL)
605 abort ();
607 attrs = DECL_ATTRIBUTES (func);
609 t_intr = lookup_attribute ("interrupt", attrs);
610 t_excp = lookup_attribute ("exception", attrs);
611 t_reset = lookup_attribute ("reset", attrs);
613 return ((t_intr != NULL_TREE)
614 || (t_excp != NULL_TREE)
615 || (t_reset != NULL_TREE));
618 /* ------------------------------------------------------------------------ */