diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c index c635010c69fc7d984fe1f7267a83821f07c42a7a..6fccadb7b4768b0ad61fe2f6af778f7966af6e6b 100644 --- a/gcc/bb-reorder.c +++ b/gcc/bb-reorder.c @@ -2116,6 +2116,46 @@ fix_crossing_conditional_branches (void) { rtx_insn *old_jump = BB_END (cur_bb); + /* If asm goto has a crossing_edge, redirect it to a new bb and + insert an unconditional jump to orig dest from the new bb. + In some architecture that conditional branches can not span + all of memory, the unconditional jump will transfer into + indirect jump in fix_crossing_unconditional_branches (). */ + rtx asm_op = extract_asm_operands (PATTERN (old_jump)); + if (asm_op) + { + rtx_code_label *new_label = gen_label_rtx (); + basic_block old_dest = crossing_edge->dest; + + /* Put the new label and a jump in the new basic block. */ + rtx_insn *label = emit_label (new_label); + rtx_code_label *old_label = block_label (old_dest); + rtx_insn *jump = emit_jump_insn (targetm.gen_jump (old_label)); + JUMP_LABEL (jump) = old_label; + + /* Create the new basic block and put it in last position. */ + basic_block last_bb = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb; + basic_block new_bb = create_basic_block (label, jump, last_bb); + new_bb->aux = last_bb->aux; + last_bb->aux = new_bb; + /* Make sure the new bb count is the same as crossing edge. */ + new_bb->count = crossing_edge->count (); + + emit_barrier_after_bb (new_bb); + + new_edge = make_single_succ_edge (new_bb, old_dest, 0); + new_edge->flags |= EDGE_CROSSING; + /* Make sure the new basic block is in the same partition. */ + BB_SET_PARTITION (new_bb, BB_PARTITION (old_dest)); + /* Make orignal edge jump to new dest. */ + redirect_edge_and_branch (crossing_edge, new_bb); + crossing_edge->flags &= ~EDGE_CROSSING; + if (dump_file) + fprintf (dump_file, "\nRedirect asm goto from bb %d" + " to bb %d.\n\n", + old_dest->index, new_bb->index); + } + /* Check to make sure the jump instruction is a conditional jump. */ diff --git a/gcc/ira.c b/gcc/ira.c index 681ec2f46f9d9c57b47ed740f6fbe78fb617216f..24afaf8dc417f336d9661d4402ae628896cb4c7d 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -3918,6 +3918,7 @@ static void indirect_jump_optimize (void) { basic_block bb; + basic_block dest_bb = NULL; bool rebuild_p = false; FOR_EACH_BB_REVERSE_FN (bb, cfun) @@ -3927,6 +3928,25 @@ indirect_jump_optimize (void) || find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX)) continue; + /* In pass reorder_blocks_and_partition, if the architecture does + not have unconditional branches that can span all of memory, + convert crossing unconditional branches into indirect jumps. + We should avoid optimizing indirect jumps across different + partitions here. */ + if (flag_reorder_blocks_and_partition && !HAS_LONG_UNCOND_BRANCH) + { + if (JUMP_LABEL (insn) && BLOCK_FOR_INSN (JUMP_LABEL (insn))) + dest_bb = BLOCK_FOR_INSN (JUMP_LABEL (insn)); + + if (dest_bb && BB_PARTITION (bb) != BB_PARTITION (dest_bb)) + { + if (dump_file) + fprintf (dump_file, "\nSkip indirect_jump_optimize due to" + " edge crossing different partition.\n"); + continue; + } + } + rtx x = pc_set (insn); if (!x || !REG_P (SET_SRC (x))) continue; diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/bb-reorder-and-inline-asm.c b/gcc/testsuite/gcc.dg/rtl/aarch64/bb-reorder-and-inline-asm.c new file mode 100644 index 0000000000000000000000000000000000000000..fe960746d63b648810fb87a75958a5b8a525c962 --- /dev/null +++ b/gcc/testsuite/gcc.dg/rtl/aarch64/bb-reorder-and-inline-asm.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target aarch64-*-* } } */ +/* { dg-options "-O2 -freorder-blocks-and-partition -save-temps -fdump-rtl-bbpart" } */ + +int a; +__attribute__((__cold__)) int b(char *); +void d(void) { +e: + for (; a;) + ; + b(""); + asm goto("" : : : : c); + asm(""); +c: + goto e; +} + +/* { dg-final { scan-assembler-times {d.cold:} 1 } } */ \ No newline at end of file