gimple_seq gsi_split_seq_before (gimple_stmt_iterator *i) { gimple_seq_node cur, prev; gimple_seq old_seq, new_seq; cur = i->ptr; /* How can we possibly split after the end? */ gcc_assert (cur); prev = cur->prev; old_seq = i->seq; new_seq = gimple_seq_alloc (); i->seq = new_seq; /* Set the limits on NEW_SEQ. */ gimple_seq_set_first (new_seq, cur); gimple_seq_set_last (new_seq, gimple_seq_last (old_seq)); /* Cut OLD_SEQ before I. */ gimple_seq_set_last (old_seq, prev); cur->prev = NULL; if (prev) prev->next = NULL; else gimple_seq_set_first (old_seq, NULL); return new_seq; }
void gsi_split_seq_before (gimple_stmt_iterator *i, gimple_seq *pnew_seq) { gimple_seq_node cur, prev; gimple_seq old_seq; cur = i->ptr; /* How can we possibly split after the end? */ gcc_assert (cur); prev = cur->prev; old_seq = *i->seq; if (!prev->next) *i->seq = NULL; i->seq = pnew_seq; /* Set the limits on NEW_SEQ. */ gimple_seq_set_first (pnew_seq, cur); gimple_seq_set_last (pnew_seq, gimple_seq_last (old_seq)); /* Cut OLD_SEQ before I. */ gimple_seq_set_last (&old_seq, prev); if (prev->next) prev->next = NULL; }
void gsi_insert_seq_after_without_update (gimple_stmt_iterator *i, gimple_seq seq, enum gsi_iterator_update mode) { gimple_seq_node first, last; if (seq == NULL) return; /* Don't allow inserting a sequence into itself. */ gcc_assert (seq != i->seq); first = gimple_seq_first (seq); last = gimple_seq_last (seq); gimple_seq_set_first (seq, NULL); gimple_seq_set_last (seq, NULL); gimple_seq_free (seq); /* Empty sequences need no work. */ if (!first || !last) { gcc_assert (first == last); return; } gsi_insert_seq_nodes_after (i, first, last, mode); }
static void gsi_insert_seq_nodes_before (gimple_stmt_iterator *i, gimple_seq_node first, gimple_seq_node last, enum gsi_iterator_update mode) { basic_block bb; gimple_seq_node cur = i->ptr; gcc_assert (!cur || cur->prev); if ((bb = gsi_bb (*i)) != NULL) update_bb_for_stmts (first, last, bb); /* Link SEQ before CUR in the sequence. */ if (cur) { first->prev = cur->prev; if (first->prev->next) first->prev->next = first; else gimple_seq_set_first (i->seq, first); last->next = cur; cur->prev = last; } else { gimple_seq_node itlast = gimple_seq_last (*i->seq); /* If CUR is NULL, we link at the end of the sequence (this case happens when gsi_after_labels is called for a basic block that contains only labels, so it returns an iterator after the end of the block, and we need to insert before it; it might be cleaner to add a flag to the iterator saying whether we are at the start or end of the list). */ last->next = NULL; if (itlast) { first->prev = itlast; itlast->next = first; } else gimple_seq_set_first (i->seq, first); gimple_seq_set_last (i->seq, last); } /* Update the iterator, if requested. */ switch (mode) { case GSI_NEW_STMT: case GSI_CONTINUE_LINKING: i->ptr = first; break; case GSI_SAME_STMT: break; default: gcc_unreachable (); } }
static void gsi_insert_seq_nodes_after (gimple_stmt_iterator *i, gimple_seq_node first, gimple_seq_node last, enum gsi_iterator_update m) { basic_block bb; gimple_seq_node cur = i->ptr; gcc_assert (!cur || cur->prev); /* If the iterator is inside a basic block, we need to update the basic block information for all the nodes between FIRST and LAST. */ if ((bb = gsi_bb (*i)) != NULL) update_bb_for_stmts (first, last, bb); /* Link SEQ after CUR. */ if (cur) { last->next = cur->next; if (last->next) { last->next->prev = last; } else gimple_seq_set_last (i->seq, last); first->prev = cur; cur->next = first; } else { gcc_assert (!gimple_seq_last (*i->seq)); last->next = NULL; gimple_seq_set_first (i->seq, first); gimple_seq_set_last (i->seq, last); } /* Update the iterator, if requested. */ switch (m) { case GSI_NEW_STMT: i->ptr = first; break; case GSI_CONTINUE_LINKING: i->ptr = last; break; case GSI_SAME_STMT: gcc_assert (cur); break; default: gcc_unreachable (); } }
gimple_seq gsi_split_seq_after (gimple_stmt_iterator i) { gimple_seq_node cur, next; gimple_seq *pold_seq, new_seq; cur = i.ptr; /* How can we possibly split after the end, or before the beginning? */ gcc_assert (cur && cur->next); next = cur->next; pold_seq = i.seq; gimple_seq_set_first (&new_seq, next); gimple_seq_set_last (&new_seq, gimple_seq_last (*pold_seq)); gimple_seq_set_last (pold_seq, cur); cur->next = NULL; return new_seq; }
static unsigned int lower_function_body (void) { struct lower_data data; gimple_seq body = gimple_body (current_function_decl); gimple_seq lowered_body; gimple_stmt_iterator i; gimple bind; tree t; gimple x; /* The gimplifier should've left a body of exactly one statement, namely a GIMPLE_BIND. */ gcc_assert (gimple_seq_first (body) == gimple_seq_last (body) && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND); memset (&data, 0, sizeof (data)); data.block = DECL_INITIAL (current_function_decl); BLOCK_SUBBLOCKS (data.block) = NULL_TREE; BLOCK_CHAIN (data.block) = NULL_TREE; TREE_ASM_WRITTEN (data.block) = 1; data.return_statements.create (8); bind = gimple_seq_first_stmt (body); lowered_body = NULL; gimple_seq_add_stmt (&lowered_body, bind); i = gsi_start (lowered_body); lower_gimple_bind (&i, &data); i = gsi_last (lowered_body); /* If the function falls off the end, we need a null return statement. If we've already got one in the return_statements vector, we don't need to do anything special. Otherwise build one by hand. */ if (gimple_seq_may_fallthru (lowered_body) && (data.return_statements.is_empty () || gimple_return_retval (data.return_statements.last().stmt) != NULL)) { x = gimple_build_return (NULL); gimple_set_location (x, cfun->function_end_locus); gimple_set_block (x, DECL_INITIAL (current_function_decl)); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); } /* If we lowered any return statements, emit the representative at the end of the function. */ while (!data.return_statements.is_empty ()) { return_statements_t t = data.return_statements.pop (); x = gimple_build_label (t.label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING); } /* If the function calls __builtin_setjmp, we need to emit the computed goto that will serve as the unique dispatcher for all the receivers. */ if (data.calls_builtin_setjmp) { tree disp_label, disp_var, arg; /* Build 'DISP_LABEL:' and insert. */ disp_label = create_artificial_label (cfun->function_end_locus); /* This mark will create forward edges from every call site. */ DECL_NONLOCAL (disp_label) = 1; cfun->has_nonlocal_label = 1; x = gimple_build_label (disp_label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);' and insert. */ disp_var = create_tmp_var (ptr_type_node, "setjmpvar"); arg = build_addr (disp_label, current_function_decl); t = builtin_decl_implicit (BUILT_IN_SETJMP_DISPATCHER); x = gimple_build_call (t, 1, arg); gimple_call_set_lhs (x, disp_var); /* Build 'goto DISP_VAR;' and insert. */ gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); x = gimple_build_goto (disp_var); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); } /* Once the old body has been lowered, replace it with the new lowered sequence. */ gimple_set_body (current_function_decl, lowered_body); gcc_assert (data.block == DECL_INITIAL (current_function_decl)); BLOCK_SUBBLOCKS (data.block) = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); clear_block_marks (data.block); data.return_statements.release (); return 0; }
static unsigned int lower_function_body (void) { struct lower_data data; gimple_seq body = gimple_body (current_function_decl); gimple_seq lowered_body; gimple_stmt_iterator i; gimple bind; gimple x; /* The gimplifier should've left a body of exactly one statement, namely a GIMPLE_BIND. */ gcc_assert (gimple_seq_first (body) == gimple_seq_last (body) && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND); memset (&data, 0, sizeof (data)); data.block = DECL_INITIAL (current_function_decl); BLOCK_SUBBLOCKS (data.block) = NULL_TREE; BLOCK_CHAIN (data.block) = NULL_TREE; TREE_ASM_WRITTEN (data.block) = 1; data.return_statements.create (8); bind = gimple_seq_first_stmt (body); lowered_body = NULL; gimple_seq_add_stmt (&lowered_body, bind); i = gsi_start (lowered_body); lower_gimple_bind (&i, &data); i = gsi_last (lowered_body); /* If the function falls off the end, we need a null return statement. If we've already got one in the return_statements vector, we don't need to do anything special. Otherwise build one by hand. */ if (gimple_seq_may_fallthru (lowered_body) && (data.return_statements.is_empty () || (gimple_return_retval (data.return_statements.last().stmt) != NULL))) { x = gimple_build_return (NULL); gimple_set_location (x, cfun->function_end_locus); gimple_set_block (x, DECL_INITIAL (current_function_decl)); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); } /* If we lowered any return statements, emit the representative at the end of the function. */ while (!data.return_statements.is_empty ()) { return_statements_t t = data.return_statements.pop (); x = gimple_build_label (t.label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING); } /* Once the old body has been lowered, replace it with the new lowered sequence. */ gimple_set_body (current_function_decl, lowered_body); gcc_assert (data.block == DECL_INITIAL (current_function_decl)); BLOCK_SUBBLOCKS (data.block) = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); clear_block_marks (data.block); data.return_statements.release (); return 0; }
static unsigned int lower_function_body (void) { struct lower_data data; gimple_seq body = gimple_body (current_function_decl); gimple_seq lowered_body; gimple_stmt_iterator i; gimple *bind; gimple *x; /* The gimplifier should've left a body of exactly one statement, namely a GIMPLE_BIND. */ gcc_assert (gimple_seq_first (body) == gimple_seq_last (body) && gimple_code (gimple_seq_first_stmt (body)) == GIMPLE_BIND); memset (&data, 0, sizeof (data)); data.block = DECL_INITIAL (current_function_decl); BLOCK_SUBBLOCKS (data.block) = NULL_TREE; BLOCK_CHAIN (data.block) = NULL_TREE; TREE_ASM_WRITTEN (data.block) = 1; data.return_statements.create (8); bind = gimple_seq_first_stmt (body); lowered_body = NULL; gimple_seq_add_stmt (&lowered_body, bind); i = gsi_start (lowered_body); lower_gimple_bind (&i, &data); i = gsi_last (lowered_body); /* If we had begin stmt markers from e.g. PCH, but this compilation doesn't want them, lower_stmt will have cleaned them up; we can now clear the flag that indicates we had them. */ if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers) { /* This counter needs not be exact, but before lowering it will most certainly be. */ gcc_assert (cfun->debug_marker_count == 0); cfun->debug_nonbind_markers = false; } /* If the function falls off the end, we need a null return statement. If we've already got one in the return_statements vector, we don't need to do anything special. Otherwise build one by hand. */ bool may_fallthru = gimple_seq_may_fallthru (lowered_body); if (may_fallthru && (data.return_statements.is_empty () || (gimple_return_retval (data.return_statements.last().stmt) != NULL))) { x = gimple_build_return (NULL); gimple_set_location (x, cfun->function_end_locus); gimple_set_block (x, DECL_INITIAL (current_function_decl)); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); may_fallthru = false; } /* If we lowered any return statements, emit the representative at the end of the function. */ while (!data.return_statements.is_empty ()) { return_statements_t t = data.return_statements.pop (); x = gimple_build_label (t.label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING); if (may_fallthru) { /* Remove the line number from the representative return statement. It now fills in for the fallthru too. Failure to remove this will result in incorrect results for coverage analysis. */ gimple_set_location (t.stmt, UNKNOWN_LOCATION); may_fallthru = false; } } /* Once the old body has been lowered, replace it with the new lowered sequence. */ gimple_set_body (current_function_decl, lowered_body); gcc_assert (data.block == DECL_INITIAL (current_function_decl)); BLOCK_SUBBLOCKS (data.block) = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); clear_block_marks (data.block); data.return_statements.release (); return 0; }