*bbp = NULL;
}
+/* Add an edge from the source bb FROM_BB to the sink bb TO_BB. */
+
static void
bb_add_edge (gbbS* from_bb, gbbS *to_bb)
{
}
else
{
- /* Get the tail of the list. */
+ /* Get the head of the list. */
tmpedge = from_bb->out_gedges;
while (tmpedge)
{
add_bb_at_ginsn (const symbolS *func, gcfgS *gcfg, ginsnS *ginsn, gbbS *prev_bb,
int *errp);
+/* Return the already existing basic block (if present), which begins with
+ GINSN, in the given GCFG. Return NULL otherwise. */
+
static gbbS *
find_bb (gcfgS *gcfg, ginsnS *ginsn)
{
break;
}
}
- /* Must be found if ginsn is visited. */
+ /* Must be found because ginsn is visited. */
gas_assert (found_bb);
}
return found_bb;
}
+/* Get the basic block starting at GINSN in the GCFG.
+
+ If not already present, the function will make one, while adding an edge
+ from the PREV_BB to it. */
+
static gbbS *
find_or_make_bb (const symbolS *func, gcfgS *gcfg, ginsnS *ginsn, gbbS *prev_bb,
int *errp)
gbbS *found_bb = NULL;
found_bb = find_bb (gcfg, ginsn);
- if (found_bb)
- return found_bb;
+ if (!found_bb)
+ found_bb = add_bb_at_ginsn (func, gcfg, ginsn, prev_bb, errp);
+
+ gas_assert (found_bb);
+ gas_assert (found_bb->first_ginsn == ginsn);
- return add_bb_at_ginsn (func, gcfg, ginsn, prev_bb, errp);
+ return found_bb;
}
-/* Add the basic block starting at GINSN to the given GCFG.
- Also adds an edge from the PREV_BB to the newly added basic block.
+/* Add basic block(s) for all reachable, unvisited ginsns, starting from GINSN,
+ to the given GCFG. Also add an edge from the PREV_BB to the root of the
+ newly added basic block(s).
- This is a recursive function which returns the root of the added
- basic blocks. */
+ This is a recursive function which returns the root of the added basic
+ blocks. */
static gbbS *
add_bb_at_ginsn (const symbolS *func, gcfgS *gcfg, ginsnS *ginsn, gbbS *prev_bb,
int *errp)
{
+ gbbS *root_bb = NULL;
gbbS *current_bb = NULL;
ginsnS *target_ginsn = NULL;
const symbolS *taken_label;
+ /* Create a new bb. N.B. The caller must ensure bb with this ginsn does not
+ already exist. */
+ gas_assert (!find_bb (gcfg, ginsn));
+ root_bb = XCNEW (gbbS);
+ cfg_add_bb (gcfg, root_bb);
+ root_bb->first_ginsn = ginsn;
+
+ current_bb = root_bb;
+
while (ginsn)
{
/* Skip these as they may be right after a GINSN_TYPE_RETURN.
end of bb, and a logical exit from function. */
if (GINSN_F_FUNC_END_P (ginsn))
{
+ /* Dont mark them visited yet though, leaving the option of these
+ being visited via other control flows as applicable. */
ginsn = ginsn->next;
continue;
}
bb_add_edge (prev_bb, current_bb);
break;
}
- else if (current_bb && GINSN_F_USER_LABEL_P (ginsn))
+ else if (current_bb && current_bb->first_ginsn != ginsn
+ && GINSN_F_USER_LABEL_P (ginsn))
{
- /* Create new bb starting at this label ginsn. */
+ /* Create new bb starting at ginsn for (user-defined) label. This is
+ likely going to be a destination of a some control flow. */
prev_bb = current_bb;
- find_or_make_bb (func, gcfg, ginsn, prev_bb, errp);
+ current_bb = find_or_make_bb (func, gcfg, ginsn, prev_bb, errp);
+ bb_add_edge (prev_bb, current_bb);
break;
}
if (current_bb == NULL)
{
- /* Create a new bb. */
current_bb = XCNEW (gbbS);
cfg_add_bb (gcfg, current_bb);
+ current_bb->first_ginsn = ginsn;
/* Add edge for the Not Taken, or Fall-through path. */
if (prev_bb)
bb_add_edge (prev_bb, current_bb);
}
- if (current_bb->first_ginsn == NULL)
- current_bb->first_ginsn = ginsn;
-
ginsn->visited = true;
current_bb->num_ginsns++;
current_bb->last_ginsn = ginsn;
taken_label = ginsn->src[0].sym;
gas_assert (taken_label);
- /* Preserve the prev_bb to be the dominator bb as we are
- going to follow the taken path of the conditional branch
- soon. */
+ /* Preserve the prev_bb to be the source bb as we are going to
+ follow the taken path of the conditional branch soon. */
prev_bb = current_bb;
/* Follow the target on the taken path. */
target_ginsn = label_ginsn_map_find (taken_label);
/* Add the bb for the target of the taken branch. */
if (target_ginsn)
- find_or_make_bb (func, gcfg, target_ginsn, prev_bb, errp);
+ {
+ current_bb = find_or_make_bb (func, gcfg, target_ginsn,
+ prev_bb, errp);
+ gas_assert (prev_bb);
+ bb_add_edge (prev_bb, current_bb);
+ current_bb = NULL;
+ }
else
{
*errp = GCFG_JLABEL_NOT_PRESENT;
_("missing label '%s' in func '%s' may result in imprecise cfg"),
S_GET_NAME (taken_label), S_GET_NAME (func));
}
- /* Add the bb for the fall through path. */
- find_or_make_bb (func, gcfg, ginsn->next, prev_bb, errp);
+
+ if (ginsn->type == GINSN_TYPE_JUMP_COND)
+ {
+ /* Add the bb for the fall through path. */
+ current_bb = find_or_make_bb (func, gcfg, ginsn->next,
+ prev_bb, errp);
+ gas_assert (prev_bb);
+ bb_add_edge (prev_bb, current_bb);
+ current_bb = NULL;
+ }
+ else
+ {
+ /* Unconditional jump. Current BB has been processed. */
+ current_bb = NULL;
+ /* We'll come back to the ginsns following these (local)
+ unconditional jmps from another path if they are indeed
+ reachable code. */
+ break;
+ }
}
else
{
gas_assert (ginsn->type == GINSN_TYPE_RETURN
|| (ginsn->type == GINSN_TYPE_JUMP
&& !ginsn_direct_local_jump_p (ginsn)));
+ /* Current BB has been processed. */
+ current_bb = NULL;
+
/* We'll come back to the ginsns following GINSN_TYPE_RETURN or
other (non-local) unconditional jmps from another path if they
are indeed reachable code. */
break;
}
-
- /* Current BB has been processed. */
- current_bb = NULL;
}
+
ginsn = ginsn->next;
}
- return current_bb;
+ return root_bb;
}
static int
--- /dev/null
+#as: --scfi=experimental -W
+#as:
+#objdump: -Wf
+#name: Synthesize CFI in presence of control flow 4
+#...
+Contents of the .eh_frame section:
+
+00000000 0+0014 0+0000 CIE
+ Version: 1
+ Augmentation: "zR"
+ Code alignment factor: 1
+ Data alignment factor: -8
+ Return address column: 16
+ Augmentation data: 1b
+ DW_CFA_def_cfa: r7 \(rsp\) ofs 8
+ DW_CFA_offset: r16 \(rip\) at cfa-8
+ DW_CFA_nop
+ DW_CFA_nop
+
+0+0018 0+002c 0+001c FDE cie=00000000 pc=0000000000000000..0000000000000045
+ DW_CFA_advance_loc: 1 to 0000000000000001
+ DW_CFA_def_cfa_offset: 16
+ DW_CFA_offset: r3 \(rbx\) at cfa-16
+ DW_CFA_advance_loc: 6 to 0000000000000007
+ DW_CFA_def_cfa_offset: 32
+ DW_CFA_advance_loc: 15 to 0000000000000016
+ DW_CFA_remember_state
+ DW_CFA_advance_loc: 4 to 000000000000001a
+ DW_CFA_def_cfa_offset: 16
+ DW_CFA_advance_loc: 1 to 000000000000001b
+ DW_CFA_restore: r3 \(rbx\)
+ DW_CFA_def_cfa_offset: 8
+ DW_CFA_advance_loc: 1 to 000000000000001c
+ DW_CFA_restore_state
+ DW_CFA_advance_loc: 35 to 000000000000003f
+ DW_CFA_def_cfa_offset: 16
+ DW_CFA_advance_loc: 1 to 0000000000000040
+ DW_CFA_restore: r3 \(rbx\)
+ DW_CFA_def_cfa_offset: 8
+ DW_CFA_nop
+#...
+
+#pass