+ t = gimple_build_goto (tmp_rs.label);
+ gimple_set_location (t, gimple_location (stmt));
+ gimple_set_block (t, gimple_block (stmt));
+ gsi_insert_before (gsi, t, GSI_SAME_STMT);
+ gsi_remove (gsi, false);
+}
+
+/* Lower a __builtin_setjmp TSI.
+
+ __builtin_setjmp is passed a pointer to an array of five words (not
+ all will be used on all machines). It operates similarly to the C
+ library function of the same name, but is more efficient.
+
+ It is lowered into 3 other builtins, namely __builtin_setjmp_setup,
+ __builtin_setjmp_dispatcher and __builtin_setjmp_receiver, but with
+ __builtin_setjmp_dispatcher shared among all the instances; that's
+ why it is only emitted at the end by lower_function_body.
+
+ After full lowering, the body of the function should look like:
+
+ {
+ void * setjmpvar.0;
+ int D.1844;
+ int D.2844;
+
+ [...]
+
+ __builtin_setjmp_setup (&buf, &<D1847>);
+ D.1844 = 0;
+ goto <D1846>;
+ <D1847>:;
+ __builtin_setjmp_receiver (&<D1847>);
+ D.1844 = 1;
+ <D1846>:;
+ if (D.1844 == 0) goto <D1848>; else goto <D1849>;
+
+ [...]
+
+ __builtin_setjmp_setup (&buf, &<D2847>);
+ D.2844 = 0;
+ goto <D2846>;
+ <D2847>:;
+ __builtin_setjmp_receiver (&<D2847>);
+ D.2844 = 1;
+ <D2846>:;
+ if (D.2844 == 0) goto <D2848>; else goto <D2849>;
+
+ [...]
+
+ <D3850>:;
+ return;
+ <D3853>: [non-local];
+ setjmpvar.0 = __builtin_setjmp_dispatcher (&<D3853>);
+ goto setjmpvar.0;
+ }
+
+ The dispatcher block will be both the unique destination of all the
+ abnormal call edges and the unique source of all the abnormal edges
+ to the receivers, thus keeping the complexity explosion localized. */
+
+static void
+lower_builtin_setjmp (gimple_stmt_iterator *gsi)
+{
+ gimple stmt = gsi_stmt (*gsi);
+ tree cont_label = create_artificial_label ();
+ tree next_label = create_artificial_label ();
+ tree dest, t, arg;
+ gimple g;
+
+ /* NEXT_LABEL is the label __builtin_longjmp will jump to. Its address is
+ passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver. */
+ FORCED_LABEL (next_label) = 1;
+
+ dest = gimple_call_lhs (stmt);
+
+ /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */
+ arg = build_addr (next_label, current_function_decl);
+ t = implicit_built_in_decls[BUILT_IN_SETJMP_SETUP];
+ g = gimple_build_call (t, 2, gimple_call_arg (stmt, 0), arg);
+ gimple_set_location (g, gimple_location (stmt));
+ gimple_set_block (g, gimple_block (stmt));
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+
+ /* Build 'DEST = 0' and insert. */
+ if (dest)
+ {
+ g = gimple_build_assign (dest, fold_convert (TREE_TYPE (dest),
+ integer_zero_node));
+ gimple_set_location (g, gimple_location (stmt));
+ gimple_set_block (g, gimple_block (stmt));
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ }
+
+ /* Build 'goto CONT_LABEL' and insert. */
+ g = gimple_build_goto (cont_label);
+ gsi_insert_before (gsi, g, TSI_SAME_STMT);
+
+ /* Build 'NEXT_LABEL:' and insert. */
+ g = gimple_build_label (next_label);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+
+ /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */
+ arg = build_addr (next_label, current_function_decl);
+ t = implicit_built_in_decls[BUILT_IN_SETJMP_RECEIVER];
+ g = gimple_build_call (t, 1, arg);
+ gimple_set_location (g, gimple_location (stmt));
+ gimple_set_block (g, gimple_block (stmt));
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+
+ /* Build 'DEST = 1' and insert. */
+ if (dest)
+ {
+ g = gimple_build_assign (dest, fold_convert (TREE_TYPE (dest),
+ integer_one_node));
+ gimple_set_location (g, gimple_location (stmt));
+ gimple_set_block (g, gimple_block (stmt));
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ }
+
+ /* Build 'CONT_LABEL:' and insert. */
+ g = gimple_build_label (cont_label);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+
+ /* Remove the call to __builtin_setjmp. */
+ gsi_remove (gsi, false);