1 /* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler
2    Copyright (C) 2012-2018 Free Software Foundation, Inc.
3    Contributed by Andes Technology Corporation.
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 /* ------------------------------------------------------------------------ */
22 
23 #define IN_TARGET_CODE 1
24 
25 #include "config.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "backend.h"
29 #include "target.h"
30 #include "rtl.h"
31 #include "tree.h"
32 #include "stringpool.h"
33 #include "attribs.h"
34 #include "diagnostic-core.h"
35 #include "output.h"
36 
37 /* ------------------------------------------------------------------------ */
38 
39 /* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
40    0 for reset handler with __attribute__((reset())),
41    1-8 for exception handler with __attribute__((exception(1,...,8))),
42    and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
43    We use an array to record essential information for each vector.  */
44 static struct nds32_isr_info nds32_isr_vectors[NDS32_N_ISR_VECTORS];
45 
46 /* ------------------------------------------------------------------------ */
47 
48 /* A helper function to emit section head template.  */
49 static void
nds32_emit_section_head_template(char section_name[],char symbol_name[],int align_value,bool object_p)50 nds32_emit_section_head_template (char section_name[],
51 				  char symbol_name[],
52 				  int align_value,
53 				  bool object_p)
54 {
55   const char *flags_str;
56   const char *type_str;
57 
58   flags_str = (object_p) ? "\"a\"" : "\"ax\"";
59   type_str = (object_p) ? "@object" : "@function";
60 
61   fprintf (asm_out_file, "\t.section\t%s, %s\n", section_name, flags_str);
62   fprintf (asm_out_file, "\t.align\t%d\n", align_value);
63   fprintf (asm_out_file, "\t.global\t%s\n", symbol_name);
64   fprintf (asm_out_file, "\t.type\t%s, %s\n", symbol_name, type_str);
65   fprintf (asm_out_file, "%s:\n", symbol_name);
66 }
67 
68 /* A helper function to emit section tail template.  */
69 static void
nds32_emit_section_tail_template(char symbol_name[])70 nds32_emit_section_tail_template (char symbol_name[])
71 {
72   fprintf (asm_out_file, "\t.size\t%s, .-%s\n", symbol_name, symbol_name);
73 }
74 
75 /* Function to emit isr jump table section.  */
76 static void
nds32_emit_isr_jmptbl_section(int vector_id)77 nds32_emit_isr_jmptbl_section (int vector_id)
78 {
79   char section_name[100];
80   char symbol_name[100];
81 
82   /* Prepare jmptbl section and symbol name.  */
83   snprintf (section_name, sizeof (section_name),
84 	    ".nds32_jmptbl.%02d", vector_id);
85   snprintf (symbol_name, sizeof (symbol_name),
86 	    "_nds32_jmptbl_%02d", vector_id);
87 
88   nds32_emit_section_head_template (section_name, symbol_name, 2, true);
89   fprintf (asm_out_file, "\t.word\t%s\n",
90 			 nds32_isr_vectors[vector_id].func_name);
91   nds32_emit_section_tail_template (symbol_name);
92 }
93 
94 /* Function to emit isr vector section.  */
95 static void
nds32_emit_isr_vector_section(int vector_id)96 nds32_emit_isr_vector_section (int vector_id)
97 {
98   unsigned int vector_number_offset = 0;
99   const char *c_str = "CATEGORY";
100   const char *sr_str = "SR";
101   const char *nt_str = "NT";
102   const char *vs_str = "VS";
103   char first_level_handler_name[100];
104   char section_name[100];
105   char symbol_name[100];
106 
107   /* Set the vector number offset so that we can calculate
108      the value that user specifies in the attribute.
109      We also prepare the category string for first level handler name.  */
110   switch (nds32_isr_vectors[vector_id].category)
111     {
112     case NDS32_ISR_INTERRUPT:
113       vector_number_offset = 9;
114       c_str = "i";
115       break;
116     case NDS32_ISR_EXCEPTION:
117       vector_number_offset = 0;
118       c_str = "e";
119       break;
120     case NDS32_ISR_NONE:
121     case NDS32_ISR_RESET:
122       /* Normally it should not be here.  */
123       gcc_unreachable ();
124       break;
125     }
126 
127   /* Prepare save reg string for first level handler name.  */
128   switch (nds32_isr_vectors[vector_id].save_reg)
129     {
130     case NDS32_SAVE_ALL:
131       sr_str = "sa";
132       break;
133     case NDS32_PARTIAL_SAVE:
134       sr_str = "ps";
135       break;
136     }
137 
138   /* Prepare nested type string for first level handler name.  */
139   switch (nds32_isr_vectors[vector_id].nested_type)
140     {
141     case NDS32_NESTED:
142       nt_str = "ns";
143       break;
144     case NDS32_NOT_NESTED:
145       nt_str = "nn";
146       break;
147     case NDS32_NESTED_READY:
148       nt_str = "nr";
149       break;
150     }
151 
152   /* Currently we have 4-byte or 16-byte size for each vector.
153      If it is 4-byte, the first level handler name has suffix string "_4b".  */
154   vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
155 
156   /* Now we can create first level handler name.  */
157   snprintf (first_level_handler_name, sizeof (first_level_handler_name),
158 	    "_nds32_%s_%s_%s%s", c_str, sr_str, nt_str, vs_str);
159 
160   /* Prepare vector section and symbol name.  */
161   snprintf (section_name, sizeof (section_name),
162 	    ".nds32_vector.%02d", vector_id);
163   snprintf (symbol_name, sizeof (symbol_name),
164 	    "_nds32_vector_%02d%s", vector_id, vs_str);
165 
166 
167   /* Everything is ready.  We can start emit vector section content.  */
168   nds32_emit_section_head_template (section_name, symbol_name,
169 				    floor_log2 (nds32_isr_vector_size), false);
170 
171   /* According to the vector size, the instructions in the
172      vector section may be different.  */
173   if (nds32_isr_vector_size == 4)
174     {
175       /* This block is for 4-byte vector size.
176 	 Hardware $VID support is necessary and only one instruction
177 	 is needed in vector section.  */
178       fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
179 			     first_level_handler_name);
180     }
181   else
182     {
183       /* This block is for 16-byte vector size.
184 	 There is NO hardware $VID so that we need several instructions
185 	 such as pushing GPRs and preparing software vid at vector section.
186 	 For pushing GPRs, there are four variations for
187 	 16-byte vector content and we have to handle each combination.
188 	 For preparing software vid, note that the vid need to
189 	 be substracted vector_number_offset.  */
190       if (TARGET_REDUCED_REGS)
191 	{
192 	  if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
193 	    {
194 	      /* Case of reduced set registers and save_all attribute.  */
195 	      fprintf (asm_out_file, "\t! reduced set regs + save_all\n");
196 	      fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
197 	      fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
198 
199 	    }
200 	  else
201 	    {
202 	      /* Case of reduced set registers and partial_save attribute.  */
203 	      fprintf (asm_out_file, "\t! reduced set regs + partial_save\n");
204 	      fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
205 	      fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
206 	    }
207 	}
208       else
209 	{
210 	  if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
211 	    {
212 	      /* Case of full set registers and save_all attribute.  */
213 	      fprintf (asm_out_file, "\t! full set regs + save_all\n");
214 	      fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
215 	    }
216 	  else
217 	    {
218 	      /* Case of full set registers and partial_save attribute.  */
219 	      fprintf (asm_out_file, "\t! full set regs + partial_save\n");
220 	      fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
221 	      fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
222 	    }
223 	}
224 
225       fprintf (asm_out_file, "\tmovi\t$r0, %d ! preparing software vid\n",
226 			     vector_id - vector_number_offset);
227       fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
228 			     first_level_handler_name);
229     }
230 
231   nds32_emit_section_tail_template (symbol_name);
232 }
233 
234 /* Function to emit isr reset handler content.
235    Including all jmptbl/vector references, jmptbl section,
236    vector section, nmi handler section, and warm handler section.  */
237 static void
nds32_emit_isr_reset_content(void)238 nds32_emit_isr_reset_content (void)
239 {
240   unsigned int i;
241   unsigned int total_n_vectors;
242   const char *vs_str;
243   char reset_handler_name[100];
244   char section_name[100];
245   char symbol_name[100];
246 
247   total_n_vectors = nds32_isr_vectors[0].total_n_vectors;
248   vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
249 
250   fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n");
251 
252   /* Create references in .rodata according to total number of vectors.  */
253   fprintf (asm_out_file, "\t.section\t.rodata\n");
254   fprintf (asm_out_file, "\t.align\t2\n");
255 
256   /* Emit jmptbl references.  */
257   fprintf (asm_out_file, "\t ! references to jmptbl section entries\n");
258   for (i = 0; i < total_n_vectors; i++)
259     fprintf (asm_out_file, "\t.word\t_nds32_jmptbl_%02d\n", i);
260 
261   /* Emit vector references.  */
262   fprintf (asm_out_file, "\t ! references to vector section entries\n");
263   for (i = 0; i < total_n_vectors; i++)
264     fprintf (asm_out_file, "\t.word\t_nds32_vector_%02d%s\n", i, vs_str);
265 
266   /* Emit jmptbl_00 section.  */
267   snprintf (section_name, sizeof (section_name), ".nds32_jmptbl.00");
268   snprintf (symbol_name, sizeof (symbol_name), "_nds32_jmptbl_00");
269 
270   fprintf (asm_out_file, "\t! ....................................\n");
271   nds32_emit_section_head_template (section_name, symbol_name, 2, true);
272   fprintf (asm_out_file, "\t.word\t%s\n",
273 			 nds32_isr_vectors[0].func_name);
274   nds32_emit_section_tail_template (symbol_name);
275 
276   /* Emit vector_00 section.  */
277   snprintf (section_name, sizeof (section_name), ".nds32_vector.00");
278   snprintf (symbol_name, sizeof (symbol_name), "_nds32_vector_00%s", vs_str);
279   snprintf (reset_handler_name, sizeof (reset_handler_name),
280 	    "_nds32_reset%s", vs_str);
281 
282   fprintf (asm_out_file, "\t! ....................................\n");
283   nds32_emit_section_head_template (section_name, symbol_name,
284 				    floor_log2 (nds32_isr_vector_size), false);
285   fprintf (asm_out_file, "\tj\t%s ! jump to reset handler\n",
286 			 reset_handler_name);
287   nds32_emit_section_tail_template (symbol_name);
288 
289   /* Emit nmi handler section.  */
290   snprintf (section_name, sizeof (section_name), ".nds32_nmih");
291   snprintf (symbol_name, sizeof (symbol_name), "_nds32_nmih");
292 
293   fprintf (asm_out_file, "\t! ....................................\n");
294   nds32_emit_section_head_template (section_name, symbol_name, 2, true);
295   fprintf (asm_out_file, "\t.word\t%s\n",
296 			 (strlen (nds32_isr_vectors[0].nmi_name) == 0)
297 			 ? "0"
298 			 : nds32_isr_vectors[0].nmi_name);
299   nds32_emit_section_tail_template (symbol_name);
300 
301   /* Emit warm handler section.  */
302   snprintf (section_name, sizeof (section_name), ".nds32_wrh");
303   snprintf (symbol_name, sizeof (symbol_name), "_nds32_wrh");
304 
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 			 (strlen (nds32_isr_vectors[0].warm_name) == 0)
309 			 ? "0"
310 			 : nds32_isr_vectors[0].warm_name);
311   nds32_emit_section_tail_template (symbol_name);
312 
313   fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - END !\n");
314 }
315 
316 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
317    to check if there are any conflict isr-specific attributes being set.
318    We need to check:
319      1. Only 'save_all' or 'partial_save' in the attributes.
320      2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
321      3. Only 'interrupt', 'exception', or 'reset' in the attributes.  */
322 void
nds32_check_isr_attrs_conflict(tree func_decl,tree func_attrs)323 nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
324 {
325   int save_all_p, partial_save_p;
326   int nested_p, not_nested_p, nested_ready_p;
327   int intr_p, excp_p, reset_p;
328 
329   /* Initialize variables.  */
330   save_all_p = partial_save_p = 0;
331   nested_p = not_nested_p = nested_ready_p = 0;
332   intr_p = excp_p = reset_p = 0;
333 
334   /* We must check at MOST one attribute to set save-reg.  */
335   if (lookup_attribute ("save_all", func_attrs))
336     save_all_p = 1;
337   if (lookup_attribute ("partial_save", func_attrs))
338     partial_save_p = 1;
339 
340   if ((save_all_p + partial_save_p) > 1)
341     error ("multiple save reg attributes to function %qD", func_decl);
342 
343   /* We must check at MOST one attribute to set nested-type.  */
344   if (lookup_attribute ("nested", func_attrs))
345     nested_p = 1;
346   if (lookup_attribute ("not_nested", func_attrs))
347     not_nested_p = 1;
348   if (lookup_attribute ("nested_ready", func_attrs))
349     nested_ready_p = 1;
350 
351   if ((nested_p + not_nested_p + nested_ready_p) > 1)
352     error ("multiple nested types attributes to function %qD", func_decl);
353 
354   /* We must check at MOST one attribute to
355      set interrupt/exception/reset.  */
356   if (lookup_attribute ("interrupt", func_attrs))
357     intr_p = 1;
358   if (lookup_attribute ("exception", func_attrs))
359     excp_p = 1;
360   if (lookup_attribute ("reset", func_attrs))
361     reset_p = 1;
362 
363   if ((intr_p + excp_p + reset_p) > 1)
364     error ("multiple interrupt attributes to function %qD", func_decl);
365 }
366 
367 /* Function to construct isr vectors information array.
368    We DO NOT HAVE TO check if the attributes are valid
369    because those works are supposed to be done on
370    nds32_merge_decl_attributes() and nds32_insert_attributes().  */
371 void
nds32_construct_isr_vectors_information(tree func_attrs,const char * func_name)372 nds32_construct_isr_vectors_information (tree func_attrs,
373 					 const char *func_name)
374 {
375   tree save_all, partial_save;
376   tree nested, not_nested, nested_ready;
377   tree intr, excp, reset;
378 
379   save_all     = lookup_attribute ("save_all", func_attrs);
380   partial_save = lookup_attribute ("partial_save", func_attrs);
381 
382   nested       = lookup_attribute ("nested", func_attrs);
383   not_nested   = lookup_attribute ("not_nested", func_attrs);
384   nested_ready = lookup_attribute ("nested_ready", func_attrs);
385 
386   intr  = lookup_attribute ("interrupt", func_attrs);
387   excp  = lookup_attribute ("exception", func_attrs);
388   reset = lookup_attribute ("reset", func_attrs);
389 
390   /* If there is no interrupt/exception/reset, we can return immediately.  */
391   if (!intr && !excp && !reset)
392     return;
393 
394   /* If we are here, either we have interrupt/exception,
395      or reset attribute.  */
396   if (intr || excp)
397     {
398       tree id_list;
399 
400       /* Prepare id list so that we can traverse and set vector id.  */
401       id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp));
402 
403       while (id_list)
404 	{
405 	  tree id;
406 	  int vector_id;
407 	  unsigned int vector_number_offset;
408 
409 	  /* The way to handle interrupt or exception is the same,
410 	     we just need to take care of actual vector number.
411 	     For interrupt(0..63), the actual vector number is (9..72).
412 	     For exception(1..8), the actual vector number is (1..8).  */
413 	  vector_number_offset = (intr) ? (9) : (0);
414 
415 	  /* Pick up each vector id value.  */
416 	  id = TREE_VALUE (id_list);
417 	  /* Add vector_number_offset to get actual vector number.  */
418 	  vector_id = TREE_INT_CST_LOW (id) + vector_number_offset;
419 
420 	  /* Enable corresponding vector and set function name.  */
421 	  nds32_isr_vectors[vector_id].category = (intr)
422 						  ? (NDS32_ISR_INTERRUPT)
423 						  : (NDS32_ISR_EXCEPTION);
424 	  strcpy (nds32_isr_vectors[vector_id].func_name, func_name);
425 
426 	  /* Set register saving scheme.  */
427 	  if (save_all)
428 	    nds32_isr_vectors[vector_id].save_reg = NDS32_SAVE_ALL;
429 	  else if (partial_save)
430 	    nds32_isr_vectors[vector_id].save_reg = NDS32_PARTIAL_SAVE;
431 
432 	  /* Set nested type.  */
433 	  if (nested)
434 	    nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED;
435 	  else if (not_nested)
436 	    nds32_isr_vectors[vector_id].nested_type = NDS32_NOT_NESTED;
437 	  else if (nested_ready)
438 	    nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED_READY;
439 
440 	  /* Advance to next id.  */
441 	  id_list = TREE_CHAIN (id_list);
442 	}
443     }
444   else
445     {
446       tree id_list;
447       tree id;
448       tree nmi, warm;
449 
450       /* Deal with reset attribute.  Its vector number is always 0.  */
451       nds32_isr_vectors[0].category = NDS32_ISR_RESET;
452 
453       /* Prepare id_list and identify id value so that
454 	 we can set total number of vectors.  */
455       id_list = TREE_VALUE (reset);
456       id = TREE_VALUE (id_list);
457 
458       /* The total vectors = interrupt + exception numbers + reset.
459 	 There are 8 exception and 1 reset in nds32 architecture.  */
460       nds32_isr_vectors[0].total_n_vectors = TREE_INT_CST_LOW (id) + 8 + 1;
461       strcpy (nds32_isr_vectors[0].func_name, func_name);
462 
463       /* Retrieve nmi and warm function.  */
464       nmi  = lookup_attribute ("nmi", func_attrs);
465       warm = lookup_attribute ("warm", func_attrs);
466 
467       if (nmi != NULL_TREE)
468 	{
469 	  tree nmi_func_list;
470 	  tree nmi_func;
471 
472 	  nmi_func_list = TREE_VALUE (nmi);
473 	  nmi_func = TREE_VALUE (nmi_func_list);
474 
475 	  /* Record nmi function name.  */
476 	  strcpy (nds32_isr_vectors[0].nmi_name,
477 		  IDENTIFIER_POINTER (nmi_func));
478 	}
479 
480       if (warm != NULL_TREE)
481 	{
482 	  tree warm_func_list;
483 	  tree warm_func;
484 
485 	  warm_func_list = TREE_VALUE (warm);
486 	  warm_func = TREE_VALUE (warm_func_list);
487 
488 	  /* Record warm function name.  */
489 	  strcpy (nds32_isr_vectors[0].warm_name,
490 		  IDENTIFIER_POINTER (warm_func));
491 	}
492     }
493 }
494 
495 /* A helper function to handle isr stuff at the beginning of asm file.  */
496 void
nds32_asm_file_start_for_isr(void)497 nds32_asm_file_start_for_isr (void)
498 {
499   int i;
500 
501   /* Initialize isr vector information array before compiling functions.  */
502   for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
503     {
504       nds32_isr_vectors[i].category = NDS32_ISR_NONE;
505       strcpy (nds32_isr_vectors[i].func_name, "");
506       nds32_isr_vectors[i].save_reg = NDS32_PARTIAL_SAVE;
507       nds32_isr_vectors[i].nested_type = NDS32_NOT_NESTED;
508       nds32_isr_vectors[i].total_n_vectors = 0;
509       strcpy (nds32_isr_vectors[i].nmi_name, "");
510       strcpy (nds32_isr_vectors[i].warm_name, "");
511     }
512 }
513 
514 /* A helper function to handle isr stuff at the end of asm file.  */
515 void
nds32_asm_file_end_for_isr(void)516 nds32_asm_file_end_for_isr (void)
517 {
518   int i;
519 
520   /* If all the vectors are NDS32_ISR_NONE, we can return immediately.  */
521   for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
522     if (nds32_isr_vectors[i].category != NDS32_ISR_NONE)
523       break;
524 
525   if (i == NDS32_N_ISR_VECTORS)
526     return;
527 
528   /* At least one vector is NOT NDS32_ISR_NONE,
529      we should output isr vector information.  */
530   fprintf (asm_out_file, "\t! ------------------------------------\n");
531   fprintf (asm_out_file, "\t! The isr vector information:\n");
532   fprintf (asm_out_file, "\t! ------------------------------------\n");
533 
534   /* Check reset handler first.  Its vector number is always 0.  */
535   if (nds32_isr_vectors[0].category == NDS32_ISR_RESET)
536     {
537       nds32_emit_isr_reset_content ();
538       fprintf (asm_out_file, "\t! ------------------------------------\n");
539     }
540 
541   /* Check other vectors, starting from vector number 1.  */
542   for (i = 1; i < NDS32_N_ISR_VECTORS; i++)
543     {
544       if (nds32_isr_vectors[i].category == NDS32_ISR_INTERRUPT
545 	  || nds32_isr_vectors[i].category == NDS32_ISR_EXCEPTION)
546 	{
547 	  /* Found one vector which is interupt or exception.
548 	     Output its jmptbl and vector section content.  */
549 	  fprintf (asm_out_file, "\t! interrupt/exception vector %02d\n", i);
550 	  fprintf (asm_out_file, "\t! ------------------------------------\n");
551 	  nds32_emit_isr_jmptbl_section (i);
552 	  fprintf (asm_out_file, "\t! ....................................\n");
553 	  nds32_emit_isr_vector_section (i);
554 	  fprintf (asm_out_file, "\t! ------------------------------------\n");
555 	}
556     }
557 }
558 
559 /* Return true if FUNC is a isr function.  */
560 bool
nds32_isr_function_p(tree func)561 nds32_isr_function_p (tree func)
562 {
563   tree t_intr;
564   tree t_excp;
565   tree t_reset;
566 
567   tree attrs;
568 
569   if (TREE_CODE (func) != FUNCTION_DECL)
570     abort ();
571 
572   attrs = DECL_ATTRIBUTES (func);
573 
574   t_intr  = lookup_attribute ("interrupt", attrs);
575   t_excp  = lookup_attribute ("exception", attrs);
576   t_reset = lookup_attribute ("reset", attrs);
577 
578   return ((t_intr != NULL_TREE)
579 	  || (t_excp != NULL_TREE)
580 	  || (t_reset != NULL_TREE));
581 }
582 
583 /* ------------------------------------------------------------------------ */
584