return cfg_hooks->can_duplicate_block_p (bb);
}
-/* Duplicates basic block BB and redirects edge E to it. Returns the
- new basic block. The new basic block is placed after the basic block
- AFTER. */
+/* Duplicate basic block BB, place it after AFTER (if non-null) and redirect
+ edge E to it (if non-null). Return the new basic block.
+
+ If BB contains a returns_twice call, the caller is responsible for recreating
+ incoming abnormal edges corresponding to the "second return" for the copy.
+ gimple_can_duplicate_bb_p rejects such blocks, while RTL likes to live
+ dangerously.
+
+ If BB has incoming abnormal edges for some other reason, their destinations
+ should be tied to label(s) of the original BB and not the copy. */
basic_block
duplicate_block (basic_block bb, edge e, basic_block after, copy_bb_data *id)
{
gimple *g = gsi_stmt (gsi);
- /* An IFN_GOMP_SIMT_ENTER_ALLOC/IFN_GOMP_SIMT_EXIT call must be
+ /* Prohibit duplication of returns_twice calls, otherwise associated
+ abnormal edges also need to be duplicated properly.
+ An IFN_GOMP_SIMT_ENTER_ALLOC/IFN_GOMP_SIMT_EXIT call must be
duplicated as part of its group, or not at all.
The IFN_GOMP_SIMT_VOTE_ANY and IFN_GOMP_SIMT_XCHG_* are part of such a
group, so the same holds there. */
if (is_gimple_call (g)
- && (gimple_call_internal_p (g, IFN_GOMP_SIMT_ENTER_ALLOC)
+ && (gimple_call_flags (g) & ECF_RETURNS_TWICE
+ || gimple_call_internal_p (g, IFN_GOMP_SIMT_ENTER_ALLOC)
|| gimple_call_internal_p (g, IFN_GOMP_SIMT_EXIT)
|| gimple_call_internal_p (g, IFN_GOMP_SIMT_VOTE_ANY)
|| gimple_call_internal_p (g, IFN_GOMP_SIMT_XCHG_BFLY)