1 /* Handle exceptional things in C++.
2 Copyright (C) 1989, 92-97, 1998 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.
7 This file is part of GNU CC.
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)
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.
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. */
38 rtx expand_builtin_return_addr
PROTO((enum built_in_function
, int, rtx
));
40 /* Holds the fndecl for __builtin_return_address. */
41 tree builtin_return_address_fndecl
;
43 /* A couple of backend routines from m88k.c */
45 /* Used to cache a call to __builtin_return_address. */
46 static tree BuiltinReturnAddress
;
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
));
60 expand_asm (build_string (strlen (str
)+1, str
));
65 /* This is the startup, and finish stuff per exception table. */
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"
72 #ifdef EXCEPT_SECTION_ASM_OP
76 void *exception_handler
;
78 #endif /* EXCEPT_SECTION_ASM_OP */
80 #ifdef EXCEPT_SECTION_ASM_OP
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
85 asm (EXCEPT_SECTION_ASM_OP
);
86 exception_table __EXCEPTION_TABLE__
[1] = { (void*)0, (void*)0, (void*)0 };
87 asm (TEXT_SECTION_ASM_OP
);
89 #endif /* EXCEPT_SECTION_ASM_OP */
91 #ifdef EXCEPT_SECTION_ASM_OP
93 /* we need to know where the end of the exception table is... so this
96 asm (EXCEPT_SECTION_ASM_OP
);
97 exception_table __EXCEPTION_END__
[1] = { (void*)-1, (void*)-1, (void*)-1 };
98 asm (TEXT_SECTION_ASM_OP
);
100 #endif /* EXCEPT_SECTION_ASM_OP */
105 #include "insn-flags.h"
108 /* ======================================================================
109 Briefly the algorithm works like this:
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.
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).
129 +---------------------------------------------------------------+
130 |XXX: Will need modification to deal with partially |
131 | constructed arrays of objects |
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 |
137 +---------------------------------------------------------------+
139 When a catch block is encountered, there is a lot of work to be
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
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.
165 ===================================================================== */
167 /* local globals for function calls
168 ====================================================================== */
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
;
174 /* Used to cache __find_first_exception_table_match for throw. */
175 static tree FirstExceptionMatch
;
177 /* Used to cache a call to __unwind_function. */
180 /* ====================================================================== */
183 /* ========================================================================= */
187 /* local globals - these local globals are for storing data necessary for
188 generating the exception table and code in the correct order.
190 ========================================================================= */
192 /* Holds the pc for doing "throw" */
193 static tree saved_pc
;
195 extern int throw_used
;
196 extern rtx catch_clauses
;
198 /* ========================================================================= */
200 /* Cheesyness to save some typing. Returns the return value rtx. */
203 do_function_call (func
, params
, return_type
)
204 tree func
, params
, return_type
;
207 func_call
= build_function_call (func
, params
);
208 expand_call (func_call
, NULL_RTX
, 0);
209 if (return_type
!= NULL_TREE
)
210 return hard_function_value (return_type
, func_call
);
214 /* ========================================================================= */
216 /* sets up all the global eh stuff that needs to be initialized at the
217 start of compilation.
220 - Setting up all the function call trees. */
223 init_exception_processing ()
225 tree unexpected_fndecl
, terminate_fndecl
;
226 tree set_unexpected_fndecl
, set_terminate_fndecl
;
227 tree catch_match_fndecl
;
228 tree find_first_exception_match_fndecl
;
234 tree vtype
= build_function_type (void_type_node
, void_list_node
);
237 tree PFV
= build_pointer_type (vtype
);
239 /* Arg list for the build_function_type call for set_terminate and
241 tree pfvlist
= tree_cons (NULL_TREE
, PFV
, void_list_node
);
243 /* void (*pfvtype (void (*) ()))() */
244 tree pfvtype
= build_function_type (PFV
, pfvlist
);
246 set_terminate_fndecl
= auto_function (get_identifier ("set_terminate"),
247 pfvtype
, NOT_BUILT_IN
);
248 set_unexpected_fndecl
= auto_function (get_identifier ("set_unexpected"),
249 pfvtype
, NOT_BUILT_IN
);
250 unexpected_fndecl
= auto_function (get_identifier ("unexpected"),
251 vtype
, NOT_BUILT_IN
);
252 terminate_fndecl
= auto_function (get_identifier ("terminate"),
253 vtype
, NOT_BUILT_IN
);
254 TREE_THIS_VOLATILE (terminate_fndecl
) = 1;
256 push_lang_context (lang_name_c
);
259 = builtin_function (flag_rtti
260 ? "__throw_type_match_rtti"
261 : "__throw_type_match",
262 build_function_type (ptr_type_node
,
263 tree_cons (NULL_TREE
, ptr_type_node
,
264 tree_cons (NULL_TREE
, ptr_type_node
,
265 tree_cons (NULL_TREE
, ptr_type_node
,
267 NOT_BUILT_IN
, NULL_PTR
);
268 find_first_exception_match_fndecl
269 = builtin_function ("__find_first_exception_table_match",
270 build_function_type (ptr_type_node
,
271 tree_cons (NULL_TREE
, ptr_type_node
,
273 NOT_BUILT_IN
, NULL_PTR
);
275 = builtin_function ("__unwind_function",
276 build_function_type (void_type_node
,
277 tree_cons (NULL_TREE
, ptr_type_node
,
279 NOT_BUILT_IN
, NULL_PTR
);
281 Unexpected
= default_conversion (unexpected_fndecl
);
282 Terminate
= terminate_fndecl
;
283 SetTerminate
= default_conversion (set_terminate_fndecl
);
284 SetUnexpected
= default_conversion (set_unexpected_fndecl
);
285 CatchMatch
= default_conversion (catch_match_fndecl
);
286 FirstExceptionMatch
= default_conversion (find_first_exception_match_fndecl
);
287 Unwind
= default_conversion (unwind_fndecl
);
288 BuiltinReturnAddress
= default_conversion (builtin_return_address_fndecl
);
292 d
= build_decl (VAR_DECL
, get_identifier ("__eh_pc"), ptr_type_node
);
294 DECL_EXTERNAL (d
) = 1;
295 DECL_ARTIFICIAL (d
) = 1;
296 cp_finish_decl (d
, NULL_TREE
, NULL_TREE
, 0, 0);
299 /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
300 be protected with __terminate. */
301 protect_cleanup_actions_with_terminate
= 1;
304 /* Retrieve a pointer to the cp_eh_info node for the current exception. */
311 fn
= get_identifier ("__cp_exception_info");
312 if (IDENTIFIER_GLOBAL_VALUE (fn
))
313 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
318 /* Declare cp_eh_info * __cp_exception_info (void),
319 as defined in exception.cc. */
320 push_obstacks_nochange ();
321 end_temporary_allocation ();
323 /* struct cp_eh_info. This must match exception.cc. Note that this
324 type is not pushed anywhere. */
325 t
= make_lang_type (RECORD_TYPE
);
326 fields
[0] = build_lang_field_decl (FIELD_DECL
, get_identifier ("value"),
328 fields
[1] = build_lang_field_decl (FIELD_DECL
, get_identifier ("type"),
330 fields
[2] = build_lang_field_decl
331 (FIELD_DECL
, get_identifier ("cleanup"),
332 build_pointer_type (build_function_type
333 (ptr_type_node
, tree_cons
334 (NULL_TREE
, ptr_type_node
, void_list_node
))));
335 fields
[3] = build_lang_field_decl (FIELD_DECL
, get_identifier ("caught"),
337 fields
[4] = build_lang_field_decl (FIELD_DECL
, get_identifier ("next"),
338 build_pointer_type (t
));
339 fields
[5] = build_lang_field_decl
340 (FIELD_DECL
, get_identifier ("handlers"), long_integer_type_node
);
341 /* N.B.: The fourth field LEN is expected to be
342 the number of fields - 1, not the total number of fields. */
343 finish_builtin_type (t
, "cp_eh_info", fields
, 5, ptr_type_node
);
344 t
= build_pointer_type (t
);
346 /* And now the function. */
347 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
348 build_function_type (t
, void_list_node
));
349 DECL_EXTERNAL (fn
) = 1;
350 TREE_PUBLIC (fn
) = 1;
351 DECL_ARTIFICIAL (fn
) = 1;
352 pushdecl_top_level (fn
);
353 make_function_rtl (fn
);
354 assemble_external (fn
);
357 return build_function_call (fn
, NULL_TREE
);
360 /* Retrieve a pointer to the cp_eh_info node for the current exception
361 and save it in the current binding level. */
366 tree decl
, fn
= call_eh_info ();
368 /* Remember the pointer to the current exception info; it won't change
369 during this catch block. */
370 decl
= build_decl (VAR_DECL
, get_identifier ("__exception_info"),
372 DECL_ARTIFICIAL (decl
) = 1;
373 DECL_INITIAL (decl
) = fn
;
374 decl
= pushdecl (decl
);
375 cp_finish_decl (decl
, fn
, NULL_TREE
, 0, 0);
378 /* Returns a reference to the cp_eh_info node for the current exception. */
383 /* Look for the pointer pushed in push_eh_info. */
384 tree t
= lookup_name (get_identifier ("__exception_info"), 0);
385 return build_indirect_ref (t
, NULL_PTR
);
388 /* Returns a reference to the current exception object. */
393 return build_component_ref (get_eh_info (), get_identifier ("value"),
397 /* Returns a reference to the current exception type. */
402 return build_component_ref (get_eh_info (), get_identifier ("type"),
406 /* Returns a reference to whether or not the current exception
412 return build_component_ref (get_eh_info (), get_identifier ("caught"),
416 /* Returns a reference to whether or not the current exception
422 return build_component_ref (get_eh_info (), get_identifier ("handlers"),
426 /* Build a type value for use at runtime for a type that is matched
427 against by the exception handling system. */
430 build_eh_type_type (type
)
436 if (type
== error_mark_node
)
437 return error_mark_node
;
439 /* peel back references, so they match. */
440 if (TREE_CODE (type
) == REFERENCE_TYPE
)
441 type
= TREE_TYPE (type
);
443 /* Peel off cv qualifiers. */
444 type
= TYPE_MAIN_VARIANT (type
);
448 return build1 (ADDR_EXPR
, ptr_type_node
, get_typeid (type
));
451 typestring
= build_overload_name (type
, 1, 1);
452 exp
= combine_strings (build_string (strlen (typestring
)+1, typestring
));
453 return build1 (ADDR_EXPR
, ptr_type_node
, exp
);
456 /* Build a type value for use at runtime for a exp that is thrown or
457 matched against by the exception handling system. */
465 exp
= build_typeid (exp
);
466 return build1 (ADDR_EXPR
, ptr_type_node
, exp
);
468 return build_eh_type_type (TREE_TYPE (exp
));
471 /* Build up a call to __cp_pop_exception, to destroy the exception object
472 for the current catch block. HANDLER is either true or false, telling
473 the library whether or not it is being called from an exception handler;
474 if it is, it avoids destroying the object on rethrow. */
480 fn
= get_identifier ("__cp_pop_exception");
481 if (IDENTIFIER_GLOBAL_VALUE (fn
))
482 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
485 /* Declare void __cp_pop_exception (void *),
486 as defined in exception.cc. */
487 push_obstacks_nochange ();
488 end_temporary_allocation ();
491 build_function_type (void_type_node
, tree_cons
492 (NULL_TREE
, ptr_type_node
, void_list_node
)));
493 DECL_EXTERNAL (fn
) = 1;
494 TREE_PUBLIC (fn
) = 1;
495 DECL_ARTIFICIAL (fn
) = 1;
496 pushdecl_top_level (fn
);
497 make_function_rtl (fn
);
498 assemble_external (fn
);
502 /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
503 cleanup
= lookup_name (get_identifier ("__exception_info"), 0);
504 cleanup
= build_function_call (fn
, expr_tree_cons
505 (NULL_TREE
, cleanup
, NULL_TREE
));
509 /* This routine creates the cleanup for the current exception. */
516 expand_expr (build_unary_op (PREINCREMENT_EXPR
, get_eh_handlers (), 1),
517 const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
519 yes
= suspend_momentary ();
520 /* All cleanups must last longer than normal. */
521 expand_decl_cleanup (NULL_TREE
, do_pop_exception ());
522 resume_momentary (yes
);
525 /* call this to start a catch block. Typename is the typename, and identifier
526 is the variable to place the object in or NULL if the variable doesn't
527 matter. If typename is NULL, that means its a "catch (...)" or catch
528 everything. In that case we don't need to do any type checking.
529 (ie: it ends up as the "else" clause rather than an "else if" clause) */
532 expand_start_catch_block (declspecs
, declarator
)
533 tree declspecs
, declarator
;
536 tree decl
= NULL_TREE
;
539 if (processing_template_decl
)
543 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
,
546 decl
= build_min_nt (DECL_STMT
, copy_to_permanent (declarator
),
547 copy_to_permanent (declspecs
),
557 /* If we are not doing setjmp/longjmp EH, because we are reordered
558 out of line, we arrange to rethrow in the outer context so as to
559 skip through the terminate region we are nested in, should we
560 encounter an exception in the catch handler. We also need to do
561 this because we are not physically within the try block, if any,
562 that contains this catch block.
564 Matches the end in expand_end_catch_block. */
565 if (! exceptions_via_longjmp
)
566 expand_eh_region_start ();
568 /* Create a binding level for the eh_info and the exception object
571 expand_start_bindings (0);
573 false_label_rtx
= gen_label_rtx ();
574 push_label_entry (&false_label_stack
, false_label_rtx
, NULL_TREE
);
576 emit_line_note (input_filename
, lineno
);
582 decl
= grokdeclarator (declarator
, declspecs
, CATCHPARM
, 1, NULL_TREE
);
584 if (decl
== NULL_TREE
)
585 error ("invalid catch parameter");
591 rtx call_rtx
, return_value_rtx
;
594 /* Make sure we mark the catch param as used, otherwise we'll get
595 a warning about an unused ((anonymous)). */
596 TREE_USED (decl
) = 1;
598 /* Figure out the type that the initializer is. */
599 init_type
= TREE_TYPE (decl
);
600 if (TREE_CODE (init_type
) != REFERENCE_TYPE
601 && TREE_CODE (init_type
) != POINTER_TYPE
)
602 init_type
= build_reference_type (init_type
);
604 exp
= get_eh_value ();
606 /* Since pointers are passed by value, initialize a reference to
607 pointer catch parm with the address of the value slot. */
608 if (TREE_CODE (init_type
) == REFERENCE_TYPE
609 && TREE_CODE (TREE_TYPE (init_type
)) == POINTER_TYPE
)
610 exp
= build_unary_op (ADDR_EXPR
, exp
, 1);
612 exp
= expr_tree_cons (NULL_TREE
,
613 build_eh_type_type (TREE_TYPE (decl
)),
614 expr_tree_cons (NULL_TREE
,
616 expr_tree_cons (NULL_TREE
, exp
, NULL_TREE
)));
617 exp
= build_function_call (CatchMatch
, exp
);
618 call_rtx
= expand_call (exp
, NULL_RTX
, 0);
619 assemble_external (TREE_OPERAND (CatchMatch
, 0));
621 return_value_rtx
= hard_function_value (ptr_type_node
, exp
);
623 /* did the throw type match function return TRUE? */
624 emit_cmp_insn (return_value_rtx
, const0_rtx
, EQ
, NULL_RTX
,
625 GET_MODE (return_value_rtx
), 0, 0);
627 /* if it returned FALSE, jump over the catch block, else fall into it */
628 emit_jump_insn (gen_beq (false_label_rtx
));
632 /* Create a binding level for the parm. */
634 expand_start_bindings (0);
636 init
= convert_from_reference (make_tree (init_type
, call_rtx
));
638 /* If the constructor for the catch parm exits via an exception, we
639 must call terminate. See eh23.C. */
640 if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl
)))
642 int yes
= suspend_momentary ();
643 tree term
= build_function_call (Terminate
, NULL_TREE
);
644 resume_momentary (yes
);
646 /* Generate the copy constructor call directly so we can wrap it.
647 See also expand_default_init. */
648 init
= ocp_convert (TREE_TYPE (decl
), init
,
649 CONV_IMPLICIT
|CONV_FORCE_TEMP
, 0);
650 init
= build (TRY_CATCH_EXPR
, TREE_TYPE (init
), init
, term
);
653 /* Let `cp_finish_decl' know that this initializer is ok. */
654 DECL_INITIAL (decl
) = init
;
655 decl
= pushdecl (decl
);
657 cp_finish_decl (decl
, init
, NULL_TREE
, 0, LOOKUP_ONLYCONVERTING
);
663 /* Create a binding level for the parm. */
665 expand_start_bindings (0);
667 /* Fall into the catch all section. */
670 init
= build_modify_expr (get_eh_caught (), NOP_EXPR
, integer_one_node
);
671 expand_expr (init
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
673 emit_line_note (input_filename
, lineno
);
678 /* Call this to end a catch block. Its responsible for emitting the
679 code to handle jumping back to the correct place, and for emitting
680 the label to jump to if this catch block didn't match. */
683 expand_end_catch_block ()
688 /* Cleanup the EH parameter. */
689 expand_end_bindings (getdecls (), kept_level_p (), 0);
690 poplevel (kept_level_p (), 1, 0);
692 /* Cleanup the EH object. */
693 expand_end_bindings (getdecls (), kept_level_p (), 0);
694 poplevel (kept_level_p (), 1, 0);
696 if (! exceptions_via_longjmp
)
698 /* If we are not doing setjmp/longjmp EH, we need an extra
699 region around the whole catch block to skip through the
700 terminate region we are nested in. */
702 tree t
= make_node (RTL_EXPR
);
703 TREE_TYPE (t
) = void_type_node
;
704 RTL_EXPR_RTL (t
) = const0_rtx
;
705 TREE_SIDE_EFFECTS (t
) = 1;
706 do_pending_stack_adjust ();
707 start_sequence_for_rtl_expr (t
);
709 expand_internal_throw (outer_context_label_stack
->u
.rlabel
);
711 do_pending_stack_adjust ();
712 RTL_EXPR_SEQUENCE (t
) = get_insns ();
715 /* For the rethrow region. */
716 expand_eh_region_end (t
);
719 /* Fall to outside the try statement when done executing handler and
720 we fall off end of handler. This is jump Lresume in the
722 expand_goto (top_label_entry (&caught_return_label_stack
));
724 expand_leftover_cleanups ();
726 /* label we emit to jump to if this catch block didn't match. */
727 /* This the closing } in the `if (eq) {' of the documentation. */
728 emit_label (pop_label_entry (&false_label_stack
));
731 /* unwind the stack. */
734 do_unwind (inner_throw_label
)
735 rtx inner_throw_label
;
737 #if defined (SPARC_STACK_ALIGN) /* was sparc */
738 /* This doesn't work for the flat model sparc, nor does it need to
739 as the default unwinder is only used to unwind non-flat frames. */
745 /* Call to __builtin_return_address. */
746 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
747 fcall
= build_function_call (BuiltinReturnAddress
, params
);
748 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
749 /* In the return, the new pc is pc+8, as the value coming in is
750 really the address of the call insn, not the next insn. */
751 temp
= gen_reg_rtx (Pmode
);
752 emit_move_insn (temp
, inner_throw_label
);
753 emit_move_insn (next_pc
, plus_constant (temp
, -8));
754 emit_insn (gen_rtx (USE
, VOIDmode
, gen_rtx (REG
, SImode
, 31)));
755 easy_expand_asm ("ret");
756 easy_expand_asm ("restore");
759 #if defined (ARM_FRAME_RTX) /* was __arm */
760 if (flag_omit_frame_pointer
)
761 sorry ("this implementation of exception handling requires a frame pointer");
763 emit_move_insn (stack_pointer_rtx
,
764 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -8)));
765 emit_move_insn (hard_frame_pointer_rtx
,
766 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -12)));
768 #if defined (TARGET_88000) /* was m88k */
769 rtx temp_frame
= frame_pointer_rtx
;
771 temp_frame
= memory_address (Pmode
, temp_frame
);
772 temp_frame
= copy_to_reg (gen_rtx (MEM
, Pmode
, temp_frame
));
774 /* hopefully this will successfully pop the frame! */
775 emit_move_insn (frame_pointer_rtx
, temp_frame
);
776 emit_move_insn (stack_pointer_rtx
, frame_pointer_rtx
);
777 emit_move_insn (arg_pointer_rtx
, frame_pointer_rtx
);
778 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
779 (HOST_WIDE_INT
)m88k_debugger_offset (stack_pointer_rtx
, 0))));
782 emit_insn (gen_add2_insn (arg_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
783 -(HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
785 emit_move_insn (stack_pointer_rtx
, arg_pointer_rtx
);
787 emit_insn (gen_add2_insn (stack_pointer_rtx
, gen_rtx (CONST_INT
, VOIDmode
,
788 (HOST_WIDE_INT
)m88k_debugger_offset (arg_pointer_rtx
, 0))));
791 #if ! defined (TARGET_88000) && ! defined (ARM_FRAME_RTX) && ! defined (SPARC_STACK_ALIGN)
797 /* I would like to do this here, but the move below doesn't seem to work. */
798 /* Call to __builtin_return_address. */
799 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
800 fcall
= build_function_call (BuiltinReturnAddress
, params
);
801 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
803 emit_move_insn (next_pc
, inner_throw_label
);
804 /* So, for now, just pass throw label to stack unwinder. */
806 params
= expr_tree_cons (NULL_TREE
, make_tree (ptr_type_node
,
807 inner_throw_label
), NULL_TREE
);
809 do_function_call (Unwind
, params
, NULL_TREE
);
810 assemble_external (TREE_OPERAND (Unwind
, 0));
816 /* Is called from expand_exception_blocks to generate the code in a function
817 to "throw" if anything in the function needs to perform a throw.
819 expands "throw" as the following pseudo code:
822 eh = find_first_exception_match (saved_pc);
823 if (!eh) goto gotta_rethrow_it;
827 saved_pc = __builtin_return_address (0);
828 pop_to_previous_level ();
832 expand_builtin_throw ()
834 #ifndef DWARF2_UNWIND_INFO
840 rtx gotta_rethrow_it
;
841 rtx gotta_call_terminate
;
853 params
= void_list_node
;
854 t
= make_call_declarator (get_identifier ("__throw"), params
, NULL_TREE
,
856 start_function (decl_tree_cons (NULL_TREE
,
857 get_identifier ("void"),
858 decl_tree_cons (NULL_TREE
,
859 get_identifier ("static"),
866 expand_start_bindings (0);
868 gotta_rethrow_it
= gen_label_rtx ();
869 gotta_call_terminate
= gen_label_rtx ();
871 /* These two can be frontend specific. If wanted, they can go in
873 /* Do we have a valid object we are throwing? */
875 emit_cmp_insn (expand_expr (t
, NULL_RTX
, Pmode
, 0),
876 const0_rtx
, EQ
, NULL_RTX
,
877 GET_MODE (DECL_RTL (t
)), 0, 0);
878 emit_jump_insn (gen_beq (gotta_call_terminate
));
880 /* search for an exception handler for the saved_pc */
881 handler
= do_function_call (FirstExceptionMatch
,
882 expr_tree_cons (NULL_TREE
, saved_pc
,
885 assemble_external (TREE_OPERAND (FirstExceptionMatch
, 0));
887 /* did we find one? */
888 emit_cmp_insn (handler
, const0_rtx
, EQ
, NULL_RTX
,
889 GET_MODE (handler
), 0, 0);
891 /* if not, jump to gotta_rethrow_it */
892 emit_jump_insn (gen_beq (gotta_rethrow_it
));
896 ret_val
= expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS
,
897 0, hard_frame_pointer_rtx
);
899 /* Set it up so that we continue at the handler. */
900 emit_move_insn (ret_val
, handler
);
901 #ifdef RETURN_ADDR_OFFSET
902 x
= plus_constant (ret_val
, -RETURN_ADDR_OFFSET
);
904 emit_move_insn (ret_val
, x
);
907 expand_null_return ();
910 top_of_loop
= gen_label_rtx ();
911 emit_label (top_of_loop
);
913 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
914 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
916 saved_pcnthrow
= gen_reg_rtx (Pmode
);
917 emit_move_insn (saved_pcnthrow
, hard_function_value (ptr_type_node
,
922 /* Call to __builtin_return_address. */
923 #if defined (ARM_FRAME_RTX) /* was __arm */
924 /* This should be moved into arm.h:RETURN_ADDR_RTX */
925 /* This replaces a 'call' to __builtin_return_address */
926 next_pc
= gen_reg_rtx (Pmode
);
927 emit_move_insn (next_pc
,
928 gen_rtx (MEM
, Pmode
, plus_constant (hard_frame_pointer_rtx
, -4)));
930 params
= expr_tree_cons (NULL_TREE
, integer_zero_node
, NULL_TREE
);
931 fcall
= build_function_call (BuiltinReturnAddress
, params
);
932 next_pc
= expand_expr (fcall
, NULL_RTX
, Pmode
, 0);
935 /* Did __builtin_return_address return a valid address? */
936 emit_cmp_insn (next_pc
, const0_rtx
, EQ
, NULL_RTX
,
937 GET_MODE (next_pc
), 0, 0);
939 emit_jump_insn (gen_beq (gotta_call_terminate
));
941 next_pc
= eh_outer_context (next_pc
);
944 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
945 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
949 x
= validize_mem (gen_rtx (MEM
, Pmode
, saved_pcnthrow
));
950 emit_move_insn (validize_mem (gen_rtx (MEM
, Pmode
, x
)),
952 #ifdef FUNCTION_OUTGOING_VALUE
953 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
),
954 validize_mem (gen_rtx (MEM
, Pmode
,
955 plus_constant (saved_pcnthrow
,
956 GET_MODE_SIZE (Pmode
)))));
957 emit_insn (gen_rtx (USE
, VOIDmode
,
958 FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
)));
963 emit_move_insn (eh_saved_pc_rtx
, next_pc
);
965 after_unwind
= gen_label_rtx ();
966 do_unwind (gen_rtx (LABEL_REF
, Pmode
, after_unwind
));
968 emit_label (after_unwind
);
970 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
971 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
973 t
= build_function_type (void_type_node
, void_list_node
);
974 t
= make_tree (build_pointer_type (t
),
975 hard_function_value (ptr_type_node
,
977 t
= build_function_call (t
, NULL_TREE
);
978 expand_expr (t
, const0_rtx
, VOIDmode
, 0);
984 /* no it didn't --> therefore we need to call terminate */
985 emit_label (gotta_call_terminate
);
986 do_function_call (Terminate
, NULL_TREE
, NULL_TREE
);
990 /* code to deal with unwinding and looking for it again */
991 emit_label (gotta_rethrow_it
);
992 ret_val
= expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS
,
993 0, hard_frame_pointer_rtx
);
995 /* Set it up so that we continue inside, at the top of the loop. */
996 emit_move_insn (ret_val
, gen_rtx (LABEL_REF
, Pmode
, top_of_loop
));
997 #ifdef RETURN_ADDR_OFFSET
998 x
= plus_constant (ret_val
, -RETURN_ADDR_OFFSET
);
1000 emit_move_insn (ret_val
, x
);
1003 #ifdef DONT_ACCESS_GBLS_AFTER_EPILOGUE
1004 if (DONT_ACCESS_GBLS_AFTER_EPILOGUE
)
1006 rtx x
= emit_library_call_value (gen_rtx (SYMBOL_REF
, Pmode
,
1010 /* This is to get a version of throw that will throw properly. */
1011 emit_move_insn (validize_mem (gen_rtx (MEM
, Pmode
,
1012 plus_constant (x
, GET_MODE_SIZE (Pmode
)))),
1014 #ifdef FUNCTION_OUTGOING_VALUE
1015 emit_move_insn (FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
),
1017 emit_insn (gen_rtx (USE
, VOIDmode
, FUNCTION_OUTGOING_VALUE (ptr_type_node
, NULL_TREE
)));
1022 /* Fall into epilogue to unwind prologue. */
1025 expand_end_bindings (getdecls (), 1, 0);
1029 finish_function (lineno
, 0, 0);
1030 #endif /* DWARF2_UNWIND_INFO */
1035 expand_start_eh_spec ()
1037 expand_eh_region_start ();
1041 expand_end_eh_spec (raises
)
1044 tree expr
, second_try
;
1045 rtx check
= gen_label_rtx ();
1047 rtx ret
= gen_reg_rtx (Pmode
);
1048 rtx flag
= gen_reg_rtx (TYPE_MODE (integer_type_node
));
1049 rtx end
= gen_label_rtx ();
1051 expr
= make_node (RTL_EXPR
);
1052 TREE_TYPE (expr
) = void_type_node
;
1053 RTL_EXPR_RTL (expr
) = const0_rtx
;
1054 TREE_SIDE_EFFECTS (expr
) = 1;
1055 do_pending_stack_adjust ();
1056 start_sequence_for_rtl_expr (expr
);
1057 cont
= gen_label_rtx ();
1058 emit_move_insn (ret
, gen_rtx (LABEL_REF
, Pmode
, cont
));
1061 jumpif (make_tree (integer_type_node
, flag
), end
);
1062 do_function_call (Terminate
, NULL_TREE
, NULL_TREE
);
1064 do_pending_stack_adjust ();
1065 RTL_EXPR_SEQUENCE (expr
) = get_insns ();
1070 expr
= make_node (RTL_EXPR
);
1071 TREE_TYPE (expr
) = void_type_node
;
1072 RTL_EXPR_RTL (expr
) = const0_rtx
;
1073 TREE_SIDE_EFFECTS (expr
) = 1;
1074 do_pending_stack_adjust ();
1075 start_sequence_for_rtl_expr (expr
);
1077 cont
= gen_label_rtx ();
1078 emit_move_insn (ret
, gen_rtx (LABEL_REF
, Pmode
, cont
));
1081 jumpif (make_tree (integer_type_node
, flag
), end
);
1082 expand_eh_region_start ();
1083 do_function_call (Unexpected
, NULL_TREE
, NULL_TREE
);
1084 assemble_external (TREE_OPERAND (Unexpected
, 0));
1087 expand_eh_region_end (second_try
);
1090 emit_move_insn (flag
, const1_rtx
);
1091 cont
= gen_label_rtx ();
1098 tree match_type
= TREE_VALUE (raises
);
1102 /* check TREE_VALUE (raises) here */
1103 exp
= get_eh_value ();
1104 exp
= expr_tree_cons (NULL_TREE
,
1105 build_eh_type_type (match_type
),
1106 expr_tree_cons (NULL_TREE
,
1108 expr_tree_cons (NULL_TREE
, exp
, NULL_TREE
)));
1109 exp
= build_function_call (CatchMatch
, exp
);
1110 assemble_external (TREE_OPERAND (CatchMatch
, 0));
1115 raises
= TREE_CHAIN (raises
);
1117 emit_move_insn (flag
, const0_rtx
);
1119 emit_indirect_jump (ret
);
1122 do_pending_stack_adjust ();
1123 RTL_EXPR_SEQUENCE (expr
) = get_insns ();
1126 expand_eh_region_end (expr
);
1129 /* This is called to expand all the toplevel exception handling
1130 finalization for a function. It should only be called once per
1134 expand_exception_blocks ()
1136 do_pending_stack_adjust ();
1137 push_to_sequence (catch_clauses
);
1138 expand_leftover_cleanups ();
1139 do_pending_stack_adjust ();
1140 catch_clauses
= get_insns ();
1143 /* Do this after we expand leftover cleanups, so that the
1144 expand_eh_region_end that expand_end_eh_spec does will match the
1145 right expand_eh_region_start, and make sure it comes out before
1146 the terminate protected region. */
1147 if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl
)))
1149 expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl
)));
1150 do_pending_stack_adjust ();
1151 push_to_sequence (catch_clauses
);
1152 expand_leftover_cleanups ();
1153 do_pending_stack_adjust ();
1154 catch_clauses
= get_insns ();
1160 rtx funcend
= gen_label_rtx ();
1161 emit_jump (funcend
);
1163 /* We cannot protect n regions this way if we must flow into the
1164 EH region through the top of the region, as we have to with
1165 the setjmp/longjmp approach. */
1166 if (exceptions_via_longjmp
== 0)
1168 expand_eh_region_start ();
1171 emit_insns (catch_clauses
);
1172 catch_clauses
= NULL_RTX
;
1174 if (exceptions_via_longjmp
== 0)
1175 expand_eh_region_end (build_function_call (Terminate
, NULL_TREE
));
1177 expand_leftover_cleanups ();
1179 emit_label (funcend
);
1186 static int counter
= 0;
1187 int old_interface_unknown
= interface_unknown
;
1192 push_cp_function_context (NULL_TREE
);
1193 push_to_top_level ();
1195 /* No need to mangle this. */
1196 push_lang_context (lang_name_c
);
1198 interface_unknown
= 1;
1200 params
= void_list_node
;
1201 /* tcf stands for throw clean function. */
1202 sprintf (name
, "__tcf_%d", counter
++);
1203 t
= make_call_declarator (get_identifier (name
), params
, NULL_TREE
,
1205 start_function (decl_tree_cons (NULL_TREE
, get_identifier ("static"),
1208 store_parm_decls ();
1212 expand_start_bindings (0);
1213 emit_line_note (input_filename
, lineno
);
1215 interface_unknown
= old_interface_unknown
;
1217 pop_lang_context ();
1219 return current_function_decl
;
1225 expand_end_bindings (getdecls (), 1, 0);
1229 finish_function (lineno
, 0, 0);
1231 pop_from_top_level ();
1232 pop_cp_function_context (NULL_TREE
);
1235 /* Expand a throw statement. This follows the following
1238 1. Allocate space to save the current PC onto the stack.
1239 2. Generate and emit a label and save its address into the
1240 newly allocated stack space since we can't save the pc directly.
1241 3. If this is the first call to throw in this function:
1242 generate a label for the throw block
1243 4. jump to the throw block label. */
1251 static tree cleanup_type
;
1259 tree cleanup
= NULL_TREE
, e
;
1261 /* throw expression */
1262 /* First, decay it. */
1263 exp
= decay_conversion (exp
);
1265 /* cleanup_type is void (*)(void *, int),
1266 the internal type of a destructor. */
1267 if (cleanup_type
== NULL_TREE
)
1269 push_obstacks_nochange ();
1270 end_temporary_allocation ();
1271 cleanup_type
= build_pointer_type
1272 (build_function_type
1273 (void_type_node
, tree_cons
1274 (NULL_TREE
, ptr_type_node
, tree_cons
1275 (NULL_TREE
, integer_type_node
, void_list_node
))));
1279 if (TREE_CODE (TREE_TYPE (exp
)) == POINTER_TYPE
)
1281 throw_type
= build_eh_type (exp
);
1282 exp
= build_reinterpret_cast (ptr_type_node
, exp
);
1288 /* Make a copy of the thrown object. WP 15.1.5 */
1289 exp
= build_new (NULL_TREE
, TREE_TYPE (exp
),
1290 build_expr_list (NULL_TREE
, exp
),
1293 if (exp
== error_mark_node
)
1294 error (" in thrown expression");
1296 object
= build_indirect_ref (exp
, NULL_PTR
);
1297 throw_type
= build_eh_type (object
);
1299 if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object
)))
1301 cleanup
= lookup_fnfields (TYPE_BINFO (TREE_TYPE (object
)),
1302 dtor_identifier
, 0);
1303 cleanup
= TREE_VALUE (cleanup
);
1304 mark_used (cleanup
);
1305 mark_addressable (cleanup
);
1306 /* Pretend it's a normal function. */
1307 cleanup
= build1 (ADDR_EXPR
, cleanup_type
, cleanup
);
1311 if (cleanup
== NULL_TREE
)
1313 cleanup
= build_int_2 (0, 0);
1314 TREE_TYPE (cleanup
) = cleanup_type
;
1317 fn
= get_identifier ("__cp_push_exception");
1318 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1319 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1322 /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
1323 as defined in exception.cc. */
1325 push_obstacks_nochange ();
1326 end_temporary_allocation ();
1328 (NULL_TREE
, ptr_type_node
, tree_cons
1329 (NULL_TREE
, ptr_type_node
, tree_cons
1330 (NULL_TREE
, cleanup_type
, void_list_node
)));
1331 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
1332 build_function_type (void_type_node
, tmp
));
1333 DECL_EXTERNAL (fn
) = 1;
1334 TREE_PUBLIC (fn
) = 1;
1335 DECL_ARTIFICIAL (fn
) = 1;
1336 pushdecl_top_level (fn
);
1337 make_function_rtl (fn
);
1338 assemble_external (fn
);
1342 /* The throw expression is a full-expression. */
1343 exp
= build1 (CLEANUP_POINT_EXPR
, TREE_TYPE (exp
), exp
);
1344 e
= expr_tree_cons (NULL_TREE
, exp
, expr_tree_cons
1345 (NULL_TREE
, throw_type
, expr_tree_cons
1346 (NULL_TREE
, cleanup
, NULL_TREE
)));
1347 e
= build_function_call (fn
, e
);
1348 expand_expr (e
, const0_rtx
, VOIDmode
, 0);
1352 /* rethrow current exception; note that it's no longer caught. */
1354 tree fn
= get_identifier ("__uncatch_exception");
1355 if (IDENTIFIER_GLOBAL_VALUE (fn
))
1356 fn
= IDENTIFIER_GLOBAL_VALUE (fn
);
1359 /* Declare void __uncatch_exception (void)
1360 as defined in exception.cc. */
1361 push_obstacks_nochange ();
1362 end_temporary_allocation ();
1363 fn
= build_lang_decl (FUNCTION_DECL
, fn
,
1364 build_function_type (void_type_node
,
1366 DECL_EXTERNAL (fn
) = 1;
1367 TREE_PUBLIC (fn
) = 1;
1368 DECL_ARTIFICIAL (fn
) = 1;
1369 pushdecl_top_level (fn
);
1370 make_function_rtl (fn
);
1371 assemble_external (fn
);
1375 exp
= build_function_call (fn
, NULL_TREE
);
1376 expand_expr (exp
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1379 if (exceptions_via_longjmp
)
1383 /* This is the label that represents where in the code we were, when
1384 we got an exception. This needs to be updated when we rethrow an
1385 exception, so that the matching routine knows to search out. */
1386 label
= gen_label_rtx ();
1389 expand_internal_throw (label
);
1393 /* Build a throw expression. */
1399 if (e
!= error_mark_node
)
1401 if (processing_template_decl
)
1402 return build_min (THROW_EXPR
, void_type_node
, e
);
1403 e
= build1 (THROW_EXPR
, void_type_node
, e
);
1404 TREE_SIDE_EFFECTS (e
) = 1;