OSDN Git Service

Mon Oct 6 09:27:29 1997 Jason Merrill <jason@yorick.cygnus.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / except.c
1 /* Handle exceptional things in C++.
2    Copyright (C) 1989, 92-95, 1996 Free Software Foundation, Inc.
3    Contributed by Michael Tiemann <tiemann@cygnus.com>
4    Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
5    initial re-implementation courtesy Tad Hunt.
6
7 This file is part of GNU CC.
8
9 GNU CC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 GNU CC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU CC; see the file COPYING.  If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24
25 #include "config.h"
26 #include <stdio.h>
27 #include "tree.h"
28 #include "rtl.h"
29 #include "cp-tree.h"
30 #include "flags.h"
31 #include "obstack.h"
32 #include "expr.h"
33 #include "output.h"
34 #include "except.h"
35 #include "function.h"
36 #include "defaults.h"
37
38 rtx expand_builtin_return_addr  PROTO((enum built_in_function, int, rtx));
39
40 /* Holds the fndecl for __builtin_return_address.  */
41 tree builtin_return_address_fndecl;
42
43 /* A couple of backend routines from m88k.c */
44
45 /* Used to cache a call to __builtin_return_address.  */
46 static tree BuiltinReturnAddress;
47      
48 static void easy_expand_asm PROTO((char *));
49 static void push_eh_cleanup PROTO((void));
50 static void do_unwind PROTO((rtx));
51 static rtx do_function_call PROTO((tree, tree, tree));
52 static tree build_eh_type_type PROTO((tree));
53 static tree build_eh_type PROTO((tree));
54 static void expand_end_eh_spec PROTO((tree));
55
56 static void
57 easy_expand_asm (str)
58      char *str;
59 {
60   expand_asm (build_string (strlen (str)+1, str));
61 }
62
63
64 #if 0
65 /* This is the startup, and finish stuff per exception table.  */
66
67 /* XXX - Tad: exception handling section */
68 #ifndef EXCEPT_SECTION_ASM_OP
69 #define EXCEPT_SECTION_ASM_OP   "section\t.gcc_except_table,\"a\",@progbits"
70 #endif
71
72 #ifdef EXCEPT_SECTION_ASM_OP
73 typedef struct {
74     void *start_region;
75     void *end_region;
76     void *exception_handler;
77  } exception_table;
78 #endif /* EXCEPT_SECTION_ASM_OP */
79
80 #ifdef EXCEPT_SECTION_ASM_OP
81
82  /* on machines which support it, the exception table lives in another section,
83         but it needs a label so we can reference it...  This sets up that
84     label! */
85 asm (EXCEPT_SECTION_ASM_OP);
86 exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
87 asm (TEXT_SECTION_ASM_OP);
88
89 #endif /* EXCEPT_SECTION_ASM_OP */
90
91 #ifdef EXCEPT_SECTION_ASM_OP
92
93  /* we need to know where the end of the exception table is... so this
94     is how we do it! */
95
96 asm (EXCEPT_SECTION_ASM_OP);
97 exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
98 asm (TEXT_SECTION_ASM_OP);
99
100 #endif /* EXCEPT_SECTION_ASM_OP */
101
102 #endif
103
104 #include "decl.h"
105 #include "insn-flags.h"
106 #include "obstack.h"
107
108 /* ======================================================================
109    Briefly the algorithm works like this:
110
111      When a constructor or start of a try block is encountered,
112      push_eh_entry (&eh_stack) is called.  Push_eh_entry () creates a
113      new entry in the unwind protection stack and returns a label to
114      output to start the protection for that block.
115
116      When a destructor or end try block is encountered, pop_eh_entry
117      (&eh_stack) is called.  Pop_eh_entry () returns the eh_entry it
118      created when push_eh_entry () was called.  The eh_entry structure
119      contains three things at this point.  The start protect label,
120      the end protect label, and the exception handler label.  The end
121      protect label should be output before the call to the destructor
122      (if any). If it was a destructor, then its parse tree is stored
123      in the finalization variable in the eh_entry structure.  Otherwise
124      the finalization variable is set to NULL to reflect the fact that
125      is the the end of a try block.  Next, this modified eh_entry node
126      is enqueued in the finalizations queue by calling
127      enqueue_eh_entry (&queue,entry).
128
129         +---------------------------------------------------------------+
130         |XXX: Will need modification to deal with partially             |
131         |                       constructed arrays of objects           |
132         |                                                               |
133         |       Basically, this consists of keeping track of how many   |
134         |       of the objects have been constructed already (this      |
135         |       should be in a register though, so that shouldn't be a  |
136         |       problem.                                                |
137         +---------------------------------------------------------------+
138
139      When a catch block is encountered, there is a lot of work to be
140      done.
141
142      Since we don't want to generate the catch block inline with the
143      regular flow of the function, we need to have some way of doing
144      so.  Luckily, we can use sequences to defer the catch sections.
145      When the start of a catch block is encountered, we start the
146      sequence.  After the catch block is generated, we end the
147      sequence.
148
149      Next we must insure that when the catch block is executed, all
150      finalizations for the matching try block have been completed.  If
151      any of those finalizations throw an exception, we must call
152      terminate according to the ARM (section r.15.6.1).  What this
153      means is that we need to dequeue and emit finalizations for each
154      entry in the eh_queue until we get to an entry with a NULL
155      finalization field.  For any of the finalization entries, if it
156      is not a call to terminate (), we must protect it by giving it
157      another start label, end label, and exception handler label,
158      setting its finalization tree to be a call to terminate (), and
159      enqueue'ing this new eh_entry to be output at an outer level.
160      Finally, after all that is done, we can get around to outputting
161      the catch block which basically wraps all the "catch (...) {...}"
162      statements in a big if/then/else construct that matches the
163      correct block to call.
164      
165      ===================================================================== */
166
167 /* local globals for function calls
168    ====================================================================== */
169
170 /* Used to cache "terminate", "unexpected", "set_terminate", and
171    "set_unexpected" after default_conversion. (lib-except.c)  */
172 static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
173
174 /* Used to cache __find_first_exception_table_match for throw.  */
175 static tree FirstExceptionMatch;
176
177 /* Used to cache a call to __unwind_function.  */
178 static tree Unwind;
179
180 /* Holds a ready to emit call to "terminate".  */
181 static tree TerminateFunctionCall;
182
183 static tree empty_fndecl;
184
185 /* ====================================================================== */
186
187
188 /* ========================================================================= */
189
190
191
192 /* local globals - these local globals are for storing data necessary for
193    generating the exception table and code in the correct order.
194
195    ========================================================================= */
196
197 /* Holds the pc for doing "throw" */
198 static tree saved_pc;
199 /* Holds the type of the thing being thrown.  */
200 static tree saved_throw_type;
201 /* Holds the value being thrown.  */
202 static tree saved_throw_value;
203 /* Holds the cleanup for the value being thrown.  */
204 static tree saved_cleanup;
205 /* Indicates if we are in a catch clause.  */
206 static tree saved_in_catch;
207
208 extern int throw_used;
209 extern rtx catch_clauses;
210
211 /* ========================================================================= */
212
213 /* Cheesyness to save some typing.  Returns the return value rtx.  */
214
215 static rtx
216 do_function_call (func, params, return_type)
217      tree func, params, return_type;
218 {
219   tree func_call;
220   func_call = build_function_call (func, params);
221   expand_call (func_call, NULL_RTX, 0);
222   if (return_type != NULL_TREE)
223     return hard_function_value (return_type, func_call);
224   return NULL_RTX;
225 }
226
227 /* ========================================================================= */
228
229 /* sets up all the global eh stuff that needs to be initialized at the
230    start of compilation.
231
232    This includes:
233                 - Setting up all the function call trees.  */
234
235 void
236 init_exception_processing ()
237 {
238   tree unexpected_fndecl, terminate_fndecl;
239   tree set_unexpected_fndecl, set_terminate_fndecl;
240   tree catch_match_fndecl;
241   tree find_first_exception_match_fndecl;
242   tree unwind_fndecl;
243   tree declspecs;
244   tree d;
245
246   /* void vtype () */
247   tree vtype = build_function_type (void_type_node, void_list_node);
248   
249   /* void (*)() */
250   tree PFV = build_pointer_type (vtype);
251
252   /* Arg list for the build_function_type call for set_terminate and
253      set_unexpected.  */
254   tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
255
256   /* void (*pfvtype (void (*) ()))() */
257   tree pfvtype = build_function_type (PFV, pfvlist);
258
259   set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
260                                         pfvtype, NOT_BUILT_IN);
261   set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
262                                          pfvtype, NOT_BUILT_IN);
263   unexpected_fndecl = auto_function (get_identifier ("unexpected"),
264                                      vtype, NOT_BUILT_IN);
265   terminate_fndecl = auto_function (get_identifier ("terminate"),
266                                     vtype, NOT_BUILT_IN);
267   TREE_THIS_VOLATILE (terminate_fndecl) = 1;
268
269   push_lang_context (lang_name_c);
270
271   catch_match_fndecl
272     = builtin_function (flag_rtti
273                         ? "__throw_type_match_rtti"
274                         : "__throw_type_match",
275                         build_function_type (ptr_type_node,
276                                              tree_cons (NULL_TREE, ptr_type_node,
277                                                         tree_cons (NULL_TREE, ptr_type_node,
278                                                                    tree_cons (NULL_TREE, ptr_type_node,
279                                                                               void_list_node)))),
280                         NOT_BUILT_IN, NULL_PTR);
281   find_first_exception_match_fndecl
282     = builtin_function ("__find_first_exception_table_match",
283                         build_function_type (ptr_type_node,
284                                              tree_cons (NULL_TREE, ptr_type_node,
285                                                         void_list_node)),
286                         NOT_BUILT_IN, NULL_PTR);
287   unwind_fndecl
288     = builtin_function ("__unwind_function",
289                         build_function_type (void_type_node,
290                                              tree_cons (NULL_TREE, ptr_type_node,
291                                                         void_list_node)),
292                         NOT_BUILT_IN, NULL_PTR);
293   empty_fndecl
294     = builtin_function ("__empty",
295                         vtype,
296                         NOT_BUILT_IN, NULL_PTR);
297   DECL_EXTERNAL (empty_fndecl) = 1;
298   TREE_PUBLIC (empty_fndecl) = 1;
299
300   Unexpected = default_conversion (unexpected_fndecl);
301   Terminate = default_conversion (terminate_fndecl);
302   SetTerminate = default_conversion (set_terminate_fndecl);
303   SetUnexpected = default_conversion (set_unexpected_fndecl);
304   CatchMatch = default_conversion (catch_match_fndecl);
305   FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
306   Unwind = default_conversion (unwind_fndecl);
307   BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
308
309   TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
310
311   pop_lang_context ();
312
313   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
314   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
315   d = start_decl (d, declspecs, 0);
316   DECL_COMMON (d) = 1;
317   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
318   saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
319
320   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
321   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
322   d = start_decl (d, declspecs, 0);
323   DECL_COMMON (d) = 1;
324   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
325   saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
326
327   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
328   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
329   d = start_decl (d, declspecs, 0);
330   DECL_COMMON (d) = 1;
331   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
332   saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
333
334   declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
335   d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_cleanup"));
336   d = make_call_declarator (d, void_list_node, NULL_TREE, NULL_TREE);
337   d = start_decl (d, declspecs, 0);
338   DECL_COMMON (d) = 1;
339   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
340   saved_cleanup = lookup_name (get_identifier ("__eh_cleanup"), 0);
341
342   declspecs = tree_cons (NULL_TREE, get_identifier ("bool"), NULL_TREE);
343   d = get_identifier ("__eh_in_catch");
344   d = start_decl (d, declspecs, 0);
345   DECL_COMMON (d) = 1;
346   cp_finish_decl (d, NULL_TREE, NULL_TREE, 1, 0);
347   saved_in_catch = lookup_name (get_identifier ("__eh_in_catch"), 0);
348
349   /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
350      be protected with __terminate.  */
351   protect_cleanup_actions_with_terminate = 1;
352 }
353
354 /* Build a type value for use at runtime for a type that is matched
355    against by the exception handling system.  */
356
357 static tree
358 build_eh_type_type (type)
359      tree type;
360 {
361   char *typestring;
362   tree exp;
363
364   if (type == error_mark_node)
365     return error_mark_node;
366
367   /* peel back references, so they match.  */
368   if (TREE_CODE (type) == REFERENCE_TYPE)
369     type = TREE_TYPE (type);
370
371   /* Peel off cv qualifiers.  */
372   type = TYPE_MAIN_VARIANT (type);
373
374   if (flag_rtti)
375     {
376       return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
377     }
378
379   typestring = build_overload_name (type, 1, 1);
380   exp = combine_strings (build_string (strlen (typestring)+1, typestring));
381   return build1 (ADDR_EXPR, ptr_type_node, exp);
382 }
383
384 /* Build a type value for use at runtime for a exp that is thrown or
385    matched against by the exception handling system.  */
386
387 static tree
388 build_eh_type (exp)
389      tree exp;
390 {
391   if (flag_rtti)
392     {
393       exp = build_typeid (exp);
394       return build1 (ADDR_EXPR, ptr_type_node, exp);
395     }
396   return build_eh_type_type (TREE_TYPE (exp));
397 }
398
399 /* This routine creates the cleanup for the exception handling object.  */
400
401 static void
402 push_eh_cleanup ()
403 {
404   /* All cleanups must last longer than normal.  */
405   int yes = suspend_momentary ();
406
407   /* Arrange to do a dynamically scoped cleanup upon exit from this region.  */
408   tree cleanup = build_function_call (saved_cleanup, NULL_TREE);
409   cleanup = build (COMPOUND_EXPR, void_type_node, cleanup,
410                    build_modify_expr (saved_in_catch, NOP_EXPR,
411                                       build_modify_expr (saved_throw_type, NOP_EXPR, integer_zero_node)));
412   expand_decl_cleanup (NULL_TREE, cleanup);
413
414   resume_momentary (yes);
415 }
416
417
418 /* call this to start a catch block. Typename is the typename, and identifier
419    is the variable to place the object in or NULL if the variable doesn't
420    matter.  If typename is NULL, that means its a "catch (...)" or catch
421    everything.  In that case we don't need to do any type checking.
422    (ie: it ends up as the "else" clause rather than an "else if" clause) */
423
424 void
425 expand_start_catch_block (declspecs, declarator)
426      tree declspecs, declarator;
427 {
428   rtx false_label_rtx;
429   tree decl = NULL_TREE;
430   tree init;
431
432   if (processing_template_decl)
433     {
434       if (declspecs)
435         {
436           decl = grokdeclarator (declarator, declspecs, CATCHPARM,
437                                  1, NULL_TREE);
438           pushdecl (decl);
439           decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
440                                copy_to_permanent (declspecs),
441                                NULL_TREE);
442           add_tree (decl);
443         }
444       return;
445     }
446
447   if (! doing_eh (1))
448     return;
449
450   /* Create a binding level for the parm.  */
451   pushlevel (0);
452   expand_start_bindings (0);
453
454   false_label_rtx = gen_label_rtx ();
455   push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
456
457   emit_line_note (input_filename, lineno);
458
459   if (declspecs)
460     {
461       tree exp;
462       rtx call_rtx, return_value_rtx;
463       tree init_type;
464
465       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
466
467       if (decl == NULL_TREE)
468         {
469           error ("invalid catch parameter");
470
471           /* This is cheap, but we want to maintain the data
472              structures.  */
473
474           expand_eh_region_start ();
475
476           return;
477         }
478
479       /* Make sure we mark the catch param as used, otherwise we'll get
480          a warning about an unused ((anonymous)).  */
481       TREE_USED (decl) = 1;
482
483       /* Figure out the type that the initializer is.  */
484       init_type = TREE_TYPE (decl);
485       if (TREE_CODE (init_type) != REFERENCE_TYPE
486           && TREE_CODE (init_type) != POINTER_TYPE)
487         init_type = build_reference_type (init_type);
488
489       exp = saved_throw_value;
490       exp = tree_cons (NULL_TREE,
491                        build_eh_type_type (TREE_TYPE (decl)),
492                        tree_cons (NULL_TREE,
493                                   saved_throw_type,
494                                   tree_cons (NULL_TREE, exp, NULL_TREE)));
495       exp = build_function_call (CatchMatch, exp);
496       call_rtx = expand_call (exp, NULL_RTX, 0);
497       assemble_external (TREE_OPERAND (CatchMatch, 0));
498
499       return_value_rtx = hard_function_value (ptr_type_node, exp);
500
501       /* did the throw type match function return TRUE? */
502       emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
503                     GET_MODE (return_value_rtx), 0, 0);
504
505       /* if it returned FALSE, jump over the catch block, else fall into it */
506       emit_jump_insn (gen_beq (false_label_rtx));
507
508       push_eh_cleanup ();
509
510       init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
511
512       /* Do we need the below two lines? */
513       /* Let `cp_finish_decl' know that this initializer is ok.  */
514       DECL_INITIAL (decl) = init;
515       decl = pushdecl (decl);
516       cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
517     }
518   else
519     {
520       push_eh_cleanup ();
521
522       /* Fall into the catch all section.  */
523     }
524
525   emit_move_insn (DECL_RTL (saved_in_catch), const1_rtx);
526
527   /* If we are not doing setjmp/longjmp EH, because we are reordered
528      out of line, we arrange to rethrow in the outer context so as to
529      skip through the terminate region we are nested in, should we
530      encounter an exception in the catch handler.
531
532      If we are doing setjmp/longjmp EH, we need to skip through the EH
533      object cleanup region.  This isn't quite right, as we really need
534      to clean the object up, but we cannot do that until we track
535      multiple EH objects.
536
537      Matches the end in expand_end_catch_block.  */
538   expand_eh_region_start ();
539
540   emit_line_note (input_filename, lineno);
541 }
542
543
544
545 /* Call this to end a catch block.  Its responsible for emitting the
546    code to handle jumping back to the correct place, and for emitting
547    the label to jump to if this catch block didn't match.  */
548
549 void
550 expand_end_catch_block ()
551 {
552   rtx start_region_label_rtx;
553   rtx end_region_label_rtx;
554   tree decls, t;
555
556   if (! doing_eh (1))
557     return;
558
559   t = make_node (RTL_EXPR);
560   TREE_TYPE (t) = void_type_node;
561   RTL_EXPR_RTL (t) = const0_rtx;
562   TREE_SIDE_EFFECTS (t) = 1;
563   start_sequence_for_rtl_expr (t);
564
565   if (exceptions_via_longjmp)
566     {
567       /* If we are doing setjmp/longjmp EH, we need to skip through
568          the EH object cleanup region.  This isn't quite right, as we
569          really need to clean the object up, but we cannot do that
570          until we track multiple EH objects.  */
571
572       emit_library_call (sjpopnthrow_libfunc, 0, VOIDmode, 0);
573       emit_barrier ();
574     }
575   else
576     {
577       /* If we are not doing setjmp/longjmp EH, we need an extra
578          region around the whole catch block to skip through the
579          terminate region we are nested in.  */
580
581       expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
582     }
583
584   RTL_EXPR_SEQUENCE (t) = get_insns ();
585   end_sequence ();
586
587   /* Matches the start in expand_start_catch_block.  */
588   expand_eh_region_end (t);
589
590   /* Fall to outside the try statement when done executing handler and
591      we fall off end of handler.  This is jump Lresume in the
592      documentation.  */
593   expand_goto (top_label_entry (&caught_return_label_stack));
594
595   expand_leftover_cleanups ();
596
597   /* Cleanup the EH parameter.  */
598   expand_end_bindings (getdecls (), kept_level_p (), 0);
599   poplevel (kept_level_p (), 1, 0);
600       
601   /* label we emit to jump to if this catch block didn't match.  */
602   /* This the closing } in the `if (eq) {' of the documentation.  */
603   emit_label (pop_label_entry (&false_label_stack));
604 }
605
606 /* unwind the stack.  */
607
608 static void
609 do_unwind (inner_throw_label)
610      rtx inner_throw_label;
611 {
612 #if defined (SPARC_STACK_ALIGN) /* was sparc */
613   /* This doesn't work for the flat model sparc, nor does it need to
614      as the default unwinder is only used to unwind non-flat frames.  */
615   tree fcall;
616   tree params;
617   rtx next_pc;
618   rtx temp;
619
620   /* Call to  __builtin_return_address. */
621   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
622   fcall = build_function_call (BuiltinReturnAddress, params);
623   next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
624   /* In the return, the new pc is pc+8, as the value coming in is
625      really the address of the call insn, not the next insn.  */
626   temp = gen_reg_rtx (Pmode);
627   emit_move_insn (temp, inner_throw_label);
628   emit_move_insn (next_pc, plus_constant (temp, -8));
629   emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31)));
630   easy_expand_asm ("ret");
631   easy_expand_asm ("restore");
632   emit_barrier ();
633 #endif
634 #if defined (ARM_FRAME_RTX)  /* was __arm */
635   if (flag_omit_frame_pointer)
636     sorry ("this implementation of exception handling requires a frame pointer");
637
638   emit_move_insn (stack_pointer_rtx,
639                   gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
640   emit_move_insn (hard_frame_pointer_rtx,
641                   gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
642 #endif
643 #if defined (TARGET_88000) /* was m88k */
644   rtx temp_frame = frame_pointer_rtx;
645
646   temp_frame = memory_address (Pmode, temp_frame);
647   temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
648
649   /* hopefully this will successfully pop the frame! */
650   emit_move_insn (frame_pointer_rtx, temp_frame);
651   emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
652   emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
653   emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
654                                                      (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
655
656 #if 0
657   emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
658                                                    -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
659
660   emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
661
662   emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
663                                                      (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
664 #endif
665 #endif
666 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
667   tree fcall;
668   tree params;
669   rtx next_pc;
670
671 #if 0
672   /* I would like to do this here, but the move below doesn't seem to work.  */
673   /* Call to  __builtin_return_address.  */
674   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
675   fcall = build_function_call (BuiltinReturnAddress, params);
676   next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
677
678   emit_move_insn (next_pc, inner_throw_label);
679   /* So, for now, just pass throw label to stack unwinder.  */
680 #endif
681   params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
682                                             inner_throw_label), NULL_TREE);
683   
684   do_function_call (Unwind, params, NULL_TREE);
685   assemble_external (TREE_OPERAND (Unwind, 0));
686   emit_barrier ();
687 #endif
688 }
689
690
691 /* Is called from expand_exception_blocks to generate the code in a function
692    to "throw" if anything in the function needs to perform a throw.
693
694    expands "throw" as the following pseudo code:
695
696         throw:
697                 eh = find_first_exception_match (saved_pc);
698             if (!eh) goto gotta_rethrow_it;
699                 goto eh;
700
701         gotta_rethrow_it:
702                 saved_pc = __builtin_return_address (0);
703                 pop_to_previous_level ();
704                 goto throw;  */
705
706 void
707 expand_builtin_throw ()
708 {
709 #ifndef DWARF2_UNWIND_INFO
710   tree fcall;
711   tree params;
712   rtx handler;
713   rtx saved_pcnthrow;
714   rtx next_pc;
715   rtx gotta_rethrow_it;
716   rtx gotta_call_terminate;
717   rtx after_unwind;
718   rtx top_of_loop;
719   tree t;
720   rtx x;
721
722   if (! doing_eh (0))
723     return;
724
725   if (! throw_used)
726     return;
727
728   params = void_list_node;
729   t = make_call_declarator (get_identifier ("__throw"), params, NULL_TREE,
730                             NULL_TREE);
731   start_function (decl_tree_cons (NULL_TREE,
732                                   get_identifier ("void"),
733                                   decl_tree_cons (NULL_TREE,
734                                                   get_identifier ("static"),
735                                                   NULL_TREE)),
736                   t, NULL_TREE, 0);
737   store_parm_decls ();
738   pushlevel (0);
739   clear_last_expr ();
740   push_momentary ();
741   expand_start_bindings (0);
742
743   gotta_rethrow_it = gen_label_rtx ();
744   gotta_call_terminate = gen_label_rtx ();
745
746   /* These two can be frontend specific.  If wanted, they can go in
747      expand_throw.  */
748   /* Do we have a valid object we are throwing? */
749   emit_cmp_insn (DECL_RTL (saved_throw_type), const0_rtx, EQ, NULL_RTX,
750                  GET_MODE (DECL_RTL (saved_throw_type)), 0, 0);
751   emit_jump_insn (gen_beq (gotta_call_terminate));
752
753   /* search for an exception handler for the saved_pc */
754   handler = do_function_call (FirstExceptionMatch,
755                               tree_cons (NULL_TREE, saved_pc,
756                                          NULL_TREE),
757                               ptr_type_node);
758   assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
759
760   /* did we find one? */
761   emit_cmp_insn (handler, const0_rtx, EQ, NULL_RTX,
762                  GET_MODE (handler), 0, 0);
763
764   /* if not, jump to gotta_rethrow_it */
765   emit_jump_insn (gen_beq (gotta_rethrow_it));
766
767   {
768     rtx ret_val, x;
769     ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
770                                           0, hard_frame_pointer_rtx);
771
772     /* Set it up so that we continue at the handler.  */
773     emit_move_insn (ret_val, handler);
774 #ifdef RETURN_ADDR_OFFSET
775     x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
776     if (x != ret_val)
777       emit_move_insn (ret_val, x);
778 #endif
779
780     expand_null_return ();
781   }
782
783   top_of_loop = gen_label_rtx ();
784   emit_label (top_of_loop);
785   
786 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
787   if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
788     {
789       saved_pcnthrow = gen_reg_rtx (Pmode);
790       emit_move_insn (saved_pcnthrow, hard_function_value (ptr_type_node,
791                                                            NULL_TREE));
792     }
793 #endif
794       
795   /* Call to  __builtin_return_address.  */
796 #if defined (ARM_FRAME_RTX)  /* was __arm */
797   /* This should be moved into arm.h:RETURN_ADDR_RTX */
798   /* This replaces a 'call' to __builtin_return_address */
799   next_pc = gen_reg_rtx (Pmode);
800   emit_move_insn (next_pc,
801                   gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
802 #else
803   params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
804   fcall = build_function_call (BuiltinReturnAddress, params);
805   next_pc = expand_expr (fcall, NULL_RTX, Pmode, 0);
806 #endif
807
808   /* Did __builtin_return_address return a valid address?  */
809   emit_cmp_insn (next_pc, const0_rtx, EQ, NULL_RTX,
810                  GET_MODE (next_pc), 0, 0);
811
812   emit_jump_insn (gen_beq (gotta_call_terminate));
813
814   next_pc = eh_outer_context (next_pc);
815
816   /* Yes it did.  */
817 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
818   if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
819     {
820       rtx x;
821
822       x = validize_mem (gen_rtx (MEM, Pmode, saved_pcnthrow));
823       emit_move_insn (validize_mem (gen_rtx (MEM, Pmode, x)),
824                       next_pc);
825 #ifdef FUNCTION_OUTGOING_VALUE  
826       emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
827                       validize_mem (gen_rtx (MEM, Pmode,
828                                              plus_constant (saved_pcnthrow,
829                                                             GET_MODE_SIZE (Pmode)))));
830       emit_insn (gen_rtx (USE, VOIDmode,
831                           FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
832 #endif
833     }
834   else
835 #endif
836     emit_move_insn (eh_saved_pc_rtx, next_pc);
837
838   after_unwind = gen_label_rtx ();
839   do_unwind (gen_rtx (LABEL_REF, Pmode, after_unwind));
840
841   emit_label (after_unwind);
842
843 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
844   if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
845     {
846       t = make_tree (build_pointer_type (TREE_TYPE (empty_fndecl)),
847                      hard_function_value (ptr_type_node,
848                                           NULL_TREE));
849       t = build_function_call (t, NULL_TREE);
850       expand_expr (t, const0_rtx, VOIDmode, 0);
851     }
852   else
853 #endif
854     emit_throw ();
855
856   /* no it didn't --> therefore we need to call terminate */
857   emit_label (gotta_call_terminate);
858   do_function_call (Terminate, NULL_TREE, NULL_TREE);
859   assemble_external (TREE_OPERAND (Terminate, 0));
860
861   {
862     rtx ret_val, x;
863     /* code to deal with unwinding and looking for it again */
864     emit_label (gotta_rethrow_it);
865     ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
866                                           0, hard_frame_pointer_rtx);
867
868     /* Set it up so that we continue inside, at the top of the loop.  */
869     emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
870 #ifdef RETURN_ADDR_OFFSET
871     x = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
872     if (x != ret_val)
873       emit_move_insn (ret_val, x);
874 #endif
875
876 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
877     if (DONT_ACCESS_GBLS_AFTER_EPILOGUE)
878       {
879         rtx x = emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode,
880                                                   "__eh_pcnthrow"),
881                                          NULL_RTX, 1,
882                                          Pmode, 0);
883         /* This is to get a version of throw that will throw properly.  */
884         emit_move_insn (validize_mem (gen_rtx (MEM, Pmode,
885                                                plus_constant (x, GET_MODE_SIZE (Pmode)))),
886                         throw_libfunc);
887 #ifdef FUNCTION_OUTGOING_VALUE  
888         emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE),
889                         x);
890         emit_insn (gen_rtx (USE, VOIDmode, FUNCTION_OUTGOING_VALUE (ptr_type_node, NULL_TREE)));
891 #endif
892       }
893 #endif
894
895     /* Fall into epilogue to unwind prologue.  */
896   }
897
898   expand_end_bindings (getdecls (), 1, 0);
899   poplevel (1, 0, 0);
900   pop_momentary ();
901
902   finish_function (lineno, 0, 0);
903 #endif /* DWARF2_UNWIND_INFO */
904 }
905
906
907 void
908 expand_start_eh_spec ()
909 {
910   expand_eh_region_start ();
911 }
912
913 static void
914 expand_end_eh_spec (raises)
915      tree raises;
916 {
917   tree expr, second_try;
918   rtx check = gen_label_rtx ();
919   rtx cont;
920   rtx ret = gen_reg_rtx (Pmode);
921   rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
922   rtx end = gen_label_rtx ();
923
924   expr = make_node (RTL_EXPR);
925   TREE_TYPE (expr) = void_type_node;
926   RTL_EXPR_RTL (expr) = const0_rtx;
927   TREE_SIDE_EFFECTS (expr) = 1;
928   start_sequence_for_rtl_expr (expr);
929   cont = gen_label_rtx ();
930   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
931   emit_jump (check);
932   emit_label (cont);
933   jumpif (make_tree (integer_type_node, flag), end);
934   do_function_call (Terminate, NULL_TREE, NULL_TREE);
935   assemble_external (TREE_OPERAND (Terminate, 0));
936   emit_barrier ();
937   RTL_EXPR_SEQUENCE (expr) = get_insns ();
938   end_sequence ();
939   
940   second_try = expr;
941
942   expr = make_node (RTL_EXPR);
943   TREE_TYPE (expr) = void_type_node;
944   RTL_EXPR_RTL (expr) = const0_rtx;
945   TREE_SIDE_EFFECTS (expr) = 1;
946   start_sequence_for_rtl_expr (expr);
947
948   cont = gen_label_rtx ();
949   emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
950   emit_jump (check);
951   emit_label (cont);
952   jumpif (make_tree (integer_type_node, flag), end);
953   expand_eh_region_start ();
954   do_function_call (Unexpected, NULL_TREE, NULL_TREE);
955   assemble_external (TREE_OPERAND (Unexpected, 0));
956   emit_barrier ();
957
958   expand_eh_region_end (second_try);
959   
960   emit_label (check);
961   emit_move_insn (flag, const1_rtx);
962   cont = gen_label_rtx ();
963   while (raises)
964     {
965       tree exp;
966       tree match_type = TREE_VALUE (raises);
967       
968       if (match_type)
969         {
970           /* check TREE_VALUE (raises) here */
971           exp = saved_throw_value;
972           exp = tree_cons (NULL_TREE,
973                            build_eh_type_type (match_type),
974                            tree_cons (NULL_TREE,
975                                       saved_throw_type,
976                                       tree_cons (NULL_TREE, exp, NULL_TREE)));
977           exp = build_function_call (CatchMatch, exp);
978           assemble_external (TREE_OPERAND (CatchMatch, 0));
979
980           jumpif (exp, cont);
981         }
982
983       raises = TREE_CHAIN (raises);
984     }
985   emit_move_insn (flag, const0_rtx);
986   emit_label (cont);
987   emit_indirect_jump (ret);
988   emit_label (end);
989   
990   RTL_EXPR_SEQUENCE (expr) = get_insns ();
991   end_sequence ();
992   
993   expand_eh_region_end (expr);
994 }
995
996 /* This is called to expand all the toplevel exception handling
997    finalization for a function.  It should only be called once per
998    function.  */
999
1000 void
1001 expand_exception_blocks ()
1002 {
1003   push_to_sequence (catch_clauses);
1004   expand_leftover_cleanups ();
1005   catch_clauses = get_insns ();
1006   end_sequence ();
1007
1008   /* Do this after we expand leftover cleanups, so that the
1009      expand_eh_region_end that expand_end_eh_spec does will match the
1010      right expand_eh_region_start, and make sure it comes out before
1011      the terminate protected region.  */
1012   if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
1013     {
1014      expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
1015      push_to_sequence (catch_clauses);
1016      expand_leftover_cleanups ();
1017      catch_clauses = get_insns ();
1018      end_sequence ();
1019     }
1020
1021   if (catch_clauses)
1022     {
1023       rtx funcend = gen_label_rtx ();
1024       emit_jump (funcend);
1025
1026       /* We cannot protect n regions this way if we must flow into the
1027          EH region through the top of the region, as we have to with
1028          the setjmp/longjmp approach.  */
1029       if (exceptions_via_longjmp == 0)
1030         {
1031           /* Is this necessary?  */
1032           assemble_external (TREE_OPERAND (Terminate, 0));
1033
1034           expand_eh_region_start ();
1035         }
1036
1037       emit_insns (catch_clauses);
1038       catch_clauses = NULL_RTX;
1039
1040       if (exceptions_via_longjmp == 0)
1041         expand_eh_region_end (TerminateFunctionCall);
1042
1043       expand_leftover_cleanups ();
1044
1045       emit_label (funcend);
1046     }
1047 }
1048
1049 tree
1050 start_anon_func ()
1051 {
1052   static int counter = 0;
1053   int old_interface_unknown = interface_unknown;
1054   char name[32];
1055   tree params;
1056   tree t;
1057
1058   push_cp_function_context (NULL_TREE);
1059   push_to_top_level ();
1060
1061   /* No need to mangle this.  */
1062   push_lang_context (lang_name_c);
1063
1064   interface_unknown = 1;
1065
1066   params = void_list_node;
1067   /* tcf stands for throw clean funciton.  */
1068   sprintf (name, "__tcf_%d", counter++);
1069   t = make_call_declarator (get_identifier (name), params, NULL_TREE,
1070                             NULL_TREE);
1071   start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
1072                                   void_list_node),
1073                   t, NULL_TREE, 0);
1074   store_parm_decls ();
1075   pushlevel (0);
1076   clear_last_expr ();
1077   push_momentary ();
1078   expand_start_bindings (0);
1079   emit_line_note (input_filename, lineno);
1080
1081   interface_unknown = old_interface_unknown;
1082
1083   pop_lang_context ();
1084
1085   return current_function_decl;
1086 }
1087
1088 void
1089 end_anon_func ()
1090 {
1091   expand_end_bindings (getdecls (), 1, 0);
1092   poplevel (1, 0, 0);
1093   pop_momentary ();
1094
1095   finish_function (lineno, 0, 0);
1096
1097   pop_from_top_level ();
1098   pop_cp_function_context (NULL_TREE);
1099 }
1100
1101 /* Expand a throw statement.  This follows the following
1102    algorithm:
1103
1104         1. Allocate space to save the current PC onto the stack.
1105         2. Generate and emit a label and save its address into the
1106                 newly allocated stack space since we can't save the pc directly.
1107         3. If this is the first call to throw in this function:
1108                 generate a label for the throw block
1109         4. jump to the throw block label.  */
1110
1111 void
1112 expand_throw (exp)
1113      tree exp;
1114 {
1115   rtx label;
1116
1117   if (! doing_eh (1))
1118     return;
1119
1120   if (exp)
1121     {
1122       tree throw_type;
1123       tree cleanup = empty_fndecl, e;
1124
1125       /* throw expression */
1126       /* First, decay it.  */
1127       exp = decay_conversion (exp);
1128
1129       if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
1130         {
1131           throw_type = build_eh_type (exp);
1132           exp = build_reinterpret_cast (ptr_type_node, exp);
1133         }
1134       else
1135         {
1136           tree object;
1137
1138           /* Make a copy of the thrown object.  WP 15.1.5  */
1139           exp = build_new (NULL_TREE, TREE_TYPE (exp),
1140                            build_tree_list (NULL_TREE, exp),
1141                            0);
1142
1143           if (exp == error_mark_node)
1144             error ("  in thrown expression");
1145
1146           object = build_indirect_ref (exp, NULL_PTR);
1147           throw_type = build_eh_type (object);
1148
1149           /* Build __tcf_ function. */
1150           cleanup = start_anon_func ();
1151           object = build_delete (TREE_TYPE (exp), saved_throw_value, 
1152                                  integer_three_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
1153           expand_expr (object, const0_rtx, VOIDmode, 0);
1154           end_anon_func ();
1155           mark_addressable (cleanup);
1156         }
1157
1158       if (cleanup == empty_fndecl)
1159         assemble_external (empty_fndecl);
1160         
1161       e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
1162       expand_expr (e, const0_rtx, VOIDmode, 0);
1163
1164       e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
1165       e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
1166       expand_expr (e, const0_rtx, VOIDmode, 0);
1167
1168       cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
1169       cleanup = build_modify_expr (saved_cleanup, NOP_EXPR, cleanup);
1170       expand_expr (cleanup, const0_rtx, VOIDmode, 0);
1171     }
1172   else
1173     {
1174       /* rethrow current exception */
1175       /* This part is easy, as we don't have to do anything else.  */
1176     }
1177
1178   if (exceptions_via_longjmp)
1179     emit_throw ();
1180   else
1181     {
1182       /* This is the label that represents where in the code we were, when
1183          we got an exception.  This needs to be updated when we rethrow an
1184          exception, so that the matching routine knows to search out.  */
1185       label = gen_label_rtx ();
1186       emit_label (label);
1187
1188       expand_internal_throw (label);
1189     }
1190 }
1191
1192 /* Build a throw expression.  */
1193
1194 tree
1195 build_throw (e)
1196      tree e;
1197 {
1198   if (e != error_mark_node)
1199     {
1200       if (processing_template_decl)
1201         return build_min (THROW_EXPR, void_type_node, e);
1202       e = build1 (THROW_EXPR, void_type_node, e);
1203       TREE_SIDE_EFFECTS (e) = 1;
1204       TREE_USED (e) = 1;
1205     }
1206   return e;
1207 }