1 /* ginsn.h - GAS instruction representation.
2 Copyright (C) 2023 Free Software Foundation, Inc.
4 This file is part of GAS, the GNU Assembler.
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
26 #ifdef TARGET_USE_GINSN
28 static const char *const ginsn_type_names
[] =
30 #define _GINSN_TYPE_ITEM(NAME, STR) STR,
32 #undef _GINSN_TYPE_ITEM
38 ginsnS
*ginsn
= XCNEW (ginsnS
);
43 ginsn_init (enum ginsn_type type
, const symbolS
*sym
, bool real_p
)
45 ginsnS
*ginsn
= ginsn_alloc ();
49 ginsn
->flags
|= GINSN_F_INSN_REAL
;
54 ginsn_cleanup (ginsnS
**ginsnp
)
58 if (!ginsnp
|| !*ginsnp
)
64 scfi_ops_cleanup (ginsn
->scfi_ops
);
65 ginsn
->scfi_ops
= NULL
;
73 ginsn_set_src (struct ginsn_src
*src
, enum ginsn_src_type type
, unsigned int reg
,
80 /* Even when the use-case is SCFI, the value of reg may be > SCFI_MAX_REG_ID.
81 E.g., in AMD64, push fs etc. */
83 src
->immdisp
= immdisp
;
87 ginsn_set_dst (struct ginsn_dst
*dst
, enum ginsn_dst_type type
, unsigned int reg
,
96 if (type
== GINSN_DST_INDIRECT
)
101 ginsn_set_file_line (ginsnS
*ginsn
, const char *file
, unsigned int line
)
111 ginsn_get_src1 (ginsnS
*ginsn
)
113 return &ginsn
->src
[0];
117 ginsn_get_src2 (ginsnS
*ginsn
)
119 return &ginsn
->src
[1];
123 ginsn_get_dst (ginsnS
*ginsn
)
129 ginsn_get_src_reg (struct ginsn_src
*src
)
135 ginsn_get_src_type (struct ginsn_src
*src
)
141 ginsn_get_src_disp (struct ginsn_src
*src
)
147 ginsn_get_src_imm (struct ginsn_src
*src
)
153 ginsn_get_dst_reg (struct ginsn_dst
*dst
)
159 ginsn_get_dst_type (struct ginsn_dst
*dst
)
165 ginsn_get_dst_disp (struct ginsn_dst
*dst
)
171 label_ginsn_map_insert (const symbolS
*label
, ginsnS
*ginsn
)
173 const char *name
= S_GET_NAME (label
);
174 str_hash_insert (frchain_now
->frch_ginsn_data
->label_ginsn_map
,
175 name
, ginsn
, 0 /* noreplace. */);
179 label_ginsn_map_find (const symbolS
*label
)
181 const char *name
= S_GET_NAME (label
);
183 = (ginsnS
*) str_hash_find (frchain_now
->frch_ginsn_data
->label_ginsn_map
,
189 ginsn_new_phantom (const symbolS
*sym
)
191 ginsnS
*ginsn
= ginsn_alloc ();
192 ginsn
->type
= GINSN_TYPE_PHANTOM
;
194 /* By default, GINSN_F_INSN_REAL is not set in ginsn->flags. */
199 ginsn_new_symbol (const symbolS
*sym
, bool func_begin_p
)
201 ginsnS
*ginsn
= ginsn_alloc ();
202 ginsn
->type
= GINSN_TYPE_SYMBOL
;
205 ginsn
->flags
|= GINSN_F_FUNC_MARKER
;
210 ginsn_new_symbol_func_begin (const symbolS
*sym
)
212 return ginsn_new_symbol (sym
, true);
216 ginsn_new_symbol_func_end (const symbolS
*sym
)
218 return ginsn_new_symbol (sym
, false);
222 ginsn_new_symbol_user_label (const symbolS
*sym
)
224 ginsnS
*ginsn
= ginsn_new_symbol (sym
, false);
225 ginsn
->flags
|= GINSN_F_USER_LABEL
;
230 ginsn_new_add (const symbolS
*sym
, bool real_p
,
231 enum ginsn_src_type src1_type
, unsigned int src1_reg
, offsetT src1_disp
,
232 enum ginsn_src_type src2_type
, unsigned int src2_reg
, offsetT src2_disp
,
233 enum ginsn_dst_type dst_type
, unsigned int dst_reg
, offsetT dst_disp
)
235 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_ADD
, sym
, real_p
);
237 ginsn_set_src (&ginsn
->src
[0], src1_type
, src1_reg
, src1_disp
);
238 ginsn_set_src (&ginsn
->src
[1], src2_type
, src2_reg
, src2_disp
);
240 ginsn_set_dst (&ginsn
->dst
, dst_type
, dst_reg
, dst_disp
);
246 ginsn_new_and (const symbolS
*sym
, bool real_p
,
247 enum ginsn_src_type src1_type
, unsigned int src1_reg
, offsetT src1_disp
,
248 enum ginsn_src_type src2_type
, unsigned int src2_reg
, offsetT src2_disp
,
249 enum ginsn_dst_type dst_type
, unsigned int dst_reg
, offsetT dst_disp
)
251 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_AND
, sym
, real_p
);
253 ginsn_set_src (&ginsn
->src
[0], src1_type
, src1_reg
, src1_disp
);
254 ginsn_set_src (&ginsn
->src
[1], src2_type
, src2_reg
, src2_disp
);
256 ginsn_set_dst (&ginsn
->dst
, dst_type
, dst_reg
, dst_disp
);
262 ginsn_new_call (const symbolS
*sym
, bool real_p
,
263 enum ginsn_src_type src_type
, unsigned int src_reg
,
264 const symbolS
*src_text_sym
)
267 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_CALL
, sym
, real_p
);
269 ginsn_set_src (&ginsn
->src
[0], src_type
, src_reg
, 0);
271 if (src_type
== GINSN_SRC_SYMBOL
)
272 ginsn
->src
[0].sym
= src_text_sym
;
278 ginsn_new_jump (const symbolS
*sym
, bool real_p
,
279 enum ginsn_src_type src_type
, unsigned int src_reg
,
280 const symbolS
*src_ginsn_sym
)
282 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_JUMP
, sym
, real_p
);
284 ginsn_set_src (&ginsn
->src
[0], src_type
, src_reg
, 0);
286 if (src_type
== GINSN_SRC_SYMBOL
)
287 ginsn
->src
[0].sym
= src_ginsn_sym
;
293 ginsn_new_jump_cond (const symbolS
*sym
, bool real_p
,
294 enum ginsn_src_type src_type
, unsigned int src_reg
,
295 const symbolS
*src_ginsn_sym
)
297 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_JUMP_COND
, sym
, real_p
);
299 ginsn_set_src (&ginsn
->src
[0], src_type
, src_reg
, 0);
301 if (src_type
== GINSN_SRC_SYMBOL
)
302 ginsn
->src
[0].sym
= src_ginsn_sym
;
308 ginsn_new_mov (const symbolS
*sym
, bool real_p
,
309 enum ginsn_src_type src_type
, unsigned int src_reg
, offsetT src_disp
,
310 enum ginsn_dst_type dst_type
, unsigned int dst_reg
, offsetT dst_disp
)
312 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_MOV
, sym
, real_p
);
314 ginsn_set_src (&ginsn
->src
[0], src_type
, src_reg
, src_disp
);
316 ginsn_set_dst (&ginsn
->dst
, dst_type
, dst_reg
, dst_disp
);
322 ginsn_new_store (const symbolS
*sym
, bool real_p
,
323 enum ginsn_src_type src_type
, unsigned int src_reg
,
324 enum ginsn_dst_type dst_type
, unsigned int dst_reg
, offsetT dst_disp
)
326 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_STORE
, sym
, real_p
);
328 ginsn_set_src (&ginsn
->src
[0], src_type
, src_reg
, 0);
330 gas_assert (dst_type
== GINSN_DST_INDIRECT
);
331 ginsn_set_dst (&ginsn
->dst
, dst_type
, dst_reg
, dst_disp
);
337 ginsn_new_load (const symbolS
*sym
, bool real_p
,
338 enum ginsn_src_type src_type
, unsigned int src_reg
, offsetT src_disp
,
339 enum ginsn_dst_type dst_type
, unsigned int dst_reg
)
341 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_LOAD
, sym
, real_p
);
343 gas_assert (src_type
== GINSN_SRC_INDIRECT
);
344 ginsn_set_src (&ginsn
->src
[0], src_type
, src_reg
, src_disp
);
346 ginsn_set_dst (&ginsn
->dst
, dst_type
, dst_reg
, 0);
352 ginsn_new_sub (const symbolS
*sym
, bool real_p
,
353 enum ginsn_src_type src1_type
, unsigned int src1_reg
, offsetT src1_disp
,
354 enum ginsn_src_type src2_type
, unsigned int src2_reg
, offsetT src2_disp
,
355 enum ginsn_dst_type dst_type
, unsigned int dst_reg
, offsetT dst_disp
)
357 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_SUB
, sym
, real_p
);
359 ginsn_set_src (&ginsn
->src
[0], src1_type
, src1_reg
, src1_disp
);
360 ginsn_set_src (&ginsn
->src
[1], src2_type
, src2_reg
, src2_disp
);
362 ginsn_set_dst (&ginsn
->dst
, dst_type
, dst_reg
, dst_disp
);
367 /* PS: Note this API does not identify the displacement values of
368 src1/src2/dst. At this time, it is unnecessary for correctness to support
369 the additional argument. */
372 ginsn_new_other (const symbolS
*sym
, bool real_p
,
373 enum ginsn_src_type src1_type
, unsigned int src1_val
,
374 enum ginsn_src_type src2_type
, unsigned int src2_val
,
375 enum ginsn_dst_type dst_type
, unsigned int dst_reg
)
377 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_OTHER
, sym
, real_p
);
379 ginsn_set_src (&ginsn
->src
[0], src1_type
, src1_val
, src1_val
);
380 /* GINSN_SRC_INDIRECT src2_type is not expected. */
381 gas_assert (src2_type
!= GINSN_SRC_INDIRECT
);
382 ginsn_set_src (&ginsn
->src
[1], src2_type
, src2_val
, src2_val
);
384 ginsn_set_dst (&ginsn
->dst
, dst_type
, dst_reg
, 0);
390 ginsn_new_return (const symbolS
*sym
, bool real_p
)
392 ginsnS
*ginsn
= ginsn_init (GINSN_TYPE_RETURN
, sym
, real_p
);
397 ginsn_set_where (ginsnS
*ginsn
)
401 file
= as_where (&line
);
402 ginsn_set_file_line (ginsn
, file
, line
);
406 ginsn_link_next (ginsnS
*ginsn
, ginsnS
*next
)
410 /* Avoid data corruption by limiting the scope of the API. */
411 if (!ginsn
|| ginsn
->next
)
420 ginsn_track_reg_p (unsigned int dw2reg
, enum ginsn_gen_mode gmode
)
422 bool track_p
= false;
424 if (gmode
== GINSN_GEN_SCFI
&& dw2reg
<= SCFI_MAX_REG_ID
)
426 /* FIXME - rename this to tc_ ? */
427 track_p
|= SCFI_CALLEE_SAVED_REG_P (dw2reg
);
428 track_p
|= (dw2reg
== REG_FP
);
429 track_p
|= (dw2reg
== REG_SP
);
436 ginsn_indirect_jump_p (ginsnS
*ginsn
)
442 ret_p
= (ginsn
->type
== GINSN_TYPE_JUMP
443 && ginsn
->src
[0].type
== GINSN_SRC_REG
);
448 ginsn_direct_local_jump_p (ginsnS
*ginsn
)
454 ret_p
|= (ginsn
->type
== GINSN_TYPE_JUMP
455 && ginsn
->src
[0].type
== GINSN_SRC_SYMBOL
);
460 ginsn_src_print (struct ginsn_src
*src
)
463 char *src_str
= XNEWVEC (char, len
);
465 memset (src_str
, 0, len
);
470 snprintf (src_str
, len
, "%%r%d, ", ginsn_get_src_reg (src
));
473 snprintf (src_str
, len
, "%lld, ",
474 (long long int) ginsn_get_src_imm (src
));
476 case GINSN_SRC_INDIRECT
:
477 snprintf (src_str
, len
, "[%%r%d+%lld], ", ginsn_get_src_reg (src
),
478 (long long int) ginsn_get_src_disp (src
));
488 ginsn_dst_print (struct ginsn_dst
*dst
)
490 size_t len
= GINSN_LISTING_OPND_LEN
;
491 char *dst_str
= XNEWVEC (char, len
);
493 memset (dst_str
, 0, len
);
495 if (dst
->type
== GINSN_DST_REG
)
497 char *buf
= XNEWVEC (char, 32);
498 sprintf (buf
, "%%r%d", ginsn_get_dst_reg (dst
));
499 strcat (dst_str
, buf
);
501 else if (dst
->type
== GINSN_DST_INDIRECT
)
503 char *buf
= XNEWVEC (char, 32);
504 sprintf (buf
, "[%%r%d+%lld]", ginsn_get_dst_reg (dst
),
505 (long long int) ginsn_get_dst_disp (dst
));
506 strcat (dst_str
, buf
);
509 gas_assert (strlen (dst_str
) < GINSN_LISTING_OPND_LEN
);
515 ginsn_type_func_marker_print (ginsnS
*ginsn
)
518 static const char * const ginsn_sym_strs
[] =
519 { "", "FUNC_BEGIN", "FUNC_END" };
521 if (GINSN_F_FUNC_BEGIN_P (ginsn
))
523 else if (GINSN_F_FUNC_END_P (ginsn
))
526 return ginsn_sym_strs
[id
];
530 ginsn_print (ginsnS
*ginsn
)
532 struct ginsn_src
*src
;
533 struct ginsn_dst
*dst
;
535 size_t len
= GINSN_LISTING_LEN
;
536 char *ginsn_str
= XNEWVEC (char, len
);
538 memset (ginsn_str
, 0, len
);
540 str_size
= snprintf (ginsn_str
, GINSN_LISTING_LEN
, "ginsn: %s",
541 ginsn_type_names
[ginsn
->type
]);
542 gas_assert (str_size
>= 0 && str_size
< GINSN_LISTING_LEN
);
544 /* For some ginsn types, no further information is printed for now. */
545 if (ginsn
->type
== GINSN_TYPE_CALL
546 || ginsn
->type
== GINSN_TYPE_RETURN
)
548 else if (ginsn
->type
== GINSN_TYPE_SYMBOL
)
550 if (GINSN_F_USER_LABEL_P (ginsn
))
551 str_size
+= snprintf (ginsn_str
+ str_size
,
552 GINSN_LISTING_LEN
- str_size
,
553 " %s", S_GET_NAME (ginsn
->sym
));
555 str_size
+= snprintf (ginsn_str
+ str_size
,
556 GINSN_LISTING_LEN
- str_size
,
557 " %s", ginsn_type_func_marker_print (ginsn
));
562 src
= ginsn_get_src1 (ginsn
);
563 str_size
+= snprintf (ginsn_str
+ str_size
, GINSN_LISTING_LEN
- str_size
,
564 " %s", ginsn_src_print (src
));
565 gas_assert (str_size
>= 0 && str_size
< GINSN_LISTING_LEN
);
568 src
= ginsn_get_src2 (ginsn
);
569 str_size
+= snprintf (ginsn_str
+ str_size
, GINSN_LISTING_LEN
- str_size
,
570 "%s", ginsn_src_print (src
));
571 gas_assert (str_size
>= 0 && str_size
< GINSN_LISTING_LEN
);
574 dst
= ginsn_get_dst (ginsn
);
575 str_size
+= snprintf (ginsn_str
+ str_size
, GINSN_LISTING_LEN
- str_size
,
576 "%s", ginsn_dst_print (dst
));
579 gas_assert (str_size
>= 0 && str_size
< GINSN_LISTING_LEN
);
584 gbb_cleanup (gbbS
**bbp
)
595 free (bb
->entry_state
);
596 bb
->entry_state
= NULL
;
600 free (bb
->exit_state
);
601 bb
->exit_state
= NULL
;
608 bb_add_edge (gbbS
* from_bb
, gbbS
*to_bb
)
610 gedgeS
*tmpedge
= NULL
;
614 if (!from_bb
|| !to_bb
)
617 /* Create a new edge object. */
618 gedge
= XCNEW (gedgeS
);
619 gedge
->dst_bb
= to_bb
;
621 gedge
->visited
= false;
624 if (from_bb
->out_gedges
== NULL
)
626 from_bb
->out_gedges
= gedge
;
627 from_bb
->num_out_gedges
++;
631 /* Get the tail of the list. */
632 tmpedge
= from_bb
->out_gedges
;
635 /* Do not add duplicate edges. Duplicated edges will cause unwanted
636 failures in the forward and backward passes for SCFI. */
637 if (tmpedge
->dst_bb
== to_bb
)
643 tmpedge
= tmpedge
->next
;
650 tmpedge
->next
= gedge
;
651 from_bb
->num_out_gedges
++;
659 cfg_add_bb (gcfgS
*gcfg
, gbbS
*gbb
)
661 gbbS
*last_bb
= NULL
;
667 last_bb
= gcfg
->root_bb
;
668 while (last_bb
->next
)
669 last_bb
= last_bb
->next
;
675 gbb
->id
= gcfg
->num_gbbs
;
679 add_bb_at_ginsn (const symbolS
*func
, gcfgS
*gcfg
, ginsnS
*ginsn
, gbbS
*prev_bb
,
683 find_bb (gcfgS
*gcfg
, ginsnS
*ginsn
)
685 gbbS
*found_bb
= NULL
;
693 cfg_for_each_bb (gcfg
, gbb
)
695 if (gbb
->first_ginsn
== ginsn
)
701 /* Must be found if ginsn is visited. */
702 gas_assert (found_bb
);
709 find_or_make_bb (const symbolS
*func
, gcfgS
*gcfg
, ginsnS
*ginsn
, gbbS
*prev_bb
,
712 gbbS
*found_bb
= NULL
;
714 found_bb
= find_bb (gcfg
, ginsn
);
718 return add_bb_at_ginsn (func
, gcfg
, ginsn
, prev_bb
, errp
);
721 /* Add the basic block starting at GINSN to the given GCFG.
722 Also adds an edge from the PREV_BB to the newly added basic block.
724 This is a recursive function which returns the root of the added
728 add_bb_at_ginsn (const symbolS
*func
, gcfgS
*gcfg
, ginsnS
*ginsn
, gbbS
*prev_bb
,
731 gbbS
*current_bb
= NULL
;
732 ginsnS
*target_ginsn
= NULL
;
733 const symbolS
*taken_label
;
737 /* Skip these as they may be right after a GINSN_TYPE_RETURN.
738 For GINSN_TYPE_RETURN, we have already considered that as
739 end of bb, and a logical exit from function. */
740 if (GINSN_F_FUNC_END_P (ginsn
))
748 /* If the ginsn has been visited earlier, the bb must exist by now
750 prev_bb
= current_bb
;
751 current_bb
= find_bb (gcfg
, ginsn
);
752 gas_assert (current_bb
);
753 /* Add edge from the prev_bb. */
755 bb_add_edge (prev_bb
, current_bb
);
758 else if (current_bb
&& GINSN_F_USER_LABEL_P (ginsn
))
760 /* Create new bb starting at this label ginsn. */
761 prev_bb
= current_bb
;
762 find_or_make_bb (func
, gcfg
, ginsn
, prev_bb
, errp
);
766 if (current_bb
== NULL
)
768 /* Create a new bb. */
769 current_bb
= XCNEW (gbbS
);
770 cfg_add_bb (gcfg
, current_bb
);
771 /* Add edge for the Not Taken, or Fall-through path. */
773 bb_add_edge (prev_bb
, current_bb
);
776 if (current_bb
->first_ginsn
== NULL
)
777 current_bb
->first_ginsn
= ginsn
;
779 ginsn
->visited
= true;
780 current_bb
->num_ginsns
++;
781 current_bb
->last_ginsn
= ginsn
;
783 /* Note that BB is _not_ split on ginsn of type GINSN_TYPE_CALL. */
784 if (ginsn
->type
== GINSN_TYPE_JUMP
785 || ginsn
->type
== GINSN_TYPE_JUMP_COND
786 || ginsn
->type
== GINSN_TYPE_RETURN
)
788 /* Indirect Jumps or direct jumps to symbols non-local to the
789 function must not be seen here. The caller must have already
791 gas_assert (!ginsn_indirect_jump_p (ginsn
));
792 if (ginsn
->type
== GINSN_TYPE_JUMP
)
793 gas_assert (ginsn_direct_local_jump_p (ginsn
));
795 /* Direct Jumps. May include conditional or unconditional change of
796 flow. What is important for CFG creation is that the target be
797 local to function. */
798 if (ginsn
->type
== GINSN_TYPE_JUMP_COND
799 || ginsn_direct_local_jump_p (ginsn
))
801 gas_assert (ginsn
->src
[0].type
== GINSN_SRC_SYMBOL
);
802 taken_label
= ginsn
->src
[0].sym
;
803 gas_assert (taken_label
);
805 /* Preserve the prev_bb to be the dominator bb as we are
806 going to follow the taken path of the conditional branch
808 prev_bb
= current_bb
;
810 /* Follow the target on the taken path. */
811 target_ginsn
= label_ginsn_map_find (taken_label
);
812 /* Add the bb for the target of the taken branch. */
814 find_or_make_bb (func
, gcfg
, target_ginsn
, prev_bb
, errp
);
817 *errp
= GCFG_JLABEL_NOT_PRESENT
;
818 as_warn_where (ginsn
->file
, ginsn
->line
,
819 _("missing label '%s' in func '%s' may result in imprecise cfg"),
820 S_GET_NAME (taken_label
), S_GET_NAME (func
));
822 /* Add the bb for the fall through path. */
823 find_or_make_bb (func
, gcfg
, ginsn
->next
, prev_bb
, errp
);
825 else if (ginsn
->type
== GINSN_TYPE_RETURN
)
827 /* We'll come back to the ginsns following GINSN_TYPE_RETURN
828 from another path if they are indeed reachable code. */
832 /* Current BB has been processed. */
842 gbbs_compare (const void *v1
, const void *v2
)
844 const gbbS
*bb1
= *(const gbbS
**) v1
;
845 const gbbS
*bb2
= *(const gbbS
**) v2
;
847 if (bb1
->first_ginsn
->id
< bb2
->first_ginsn
->id
)
849 else if (bb1
->first_ginsn
->id
> bb2
->first_ginsn
->id
)
851 else if (bb1
->first_ginsn
->id
== bb2
->first_ginsn
->id
)
857 /* Synthesize DWARF CFI and emit it. */
860 ginsn_pass_execute_scfi (const symbolS
*func
, gcfgS
*gcfg
, gbbS
*root_bb
)
862 int err
= scfi_synthesize_dw2cfi (func
, gcfg
, root_bb
);
864 scfi_emit_dw2cfi (func
);
869 /* Traverse the list of ginsns for the function and warn if some
870 ginsns are not visited.
872 FIXME - this code assumes the caller has already performed a pass over
873 ginsns such that the reachable ginsns are already marked. Revisit this - we
874 should ideally make this pass self-sufficient. */
877 ginsn_pass_warn_unreachable_code (const symbolS
*func
,
878 gcfgS
*gcfg ATTRIBUTE_UNUSED
,
882 bool unreach_p
= false;
884 if (!gcfg
|| !func
|| !root_ginsn
)
891 /* Some ginsns of type GINSN_TYPE_SYMBOL remain unvisited. Some
892 may even be excluded from the CFG as they are not reachable, given
893 their function, e.g., user labels after return machine insn. */
895 && !GINSN_F_FUNC_END_P (ginsn
)
896 && !GINSN_F_USER_LABEL_P (ginsn
))
905 as_warn_where (ginsn
->file
, ginsn
->line
,
906 _("GINSN: found unreachable code in func '%s'"),
913 gcfg_get_bbs_in_prog_order (gcfgS
*gcfg
, gbbS
**prog_order_bbs
)
921 cfg_for_each_bb (gcfg
, gbb
)
923 gas_assert (i
< gcfg
->num_gbbs
);
924 prog_order_bbs
[i
++] = gbb
;
927 qsort (prog_order_bbs
, gcfg
->num_gbbs
, sizeof (gbbS
*), gbbs_compare
);
930 /* Build the control flow graph for the ginsns of the function.
932 It is important that the target adds an appropriate ginsn:
934 - GINSN_TYPE_JUMP_COND,
937 at the associated points in the function. The correctness of the CFG
938 depends on the accuracy of these 'change of flow instructions'. */
941 gcfg_build (const symbolS
*func
, int *errp
)
946 gcfg
= XCNEW (gcfgS
);
947 first_ginsn
= frchain_now
->frch_ginsn_data
->gins_rootP
;
948 add_bb_at_ginsn (func
, gcfg
, first_ginsn
, NULL
/* prev_bb. */, errp
);
954 gcfg_cleanup (gcfgS
**gcfgp
)
958 gedgeS
*edge
, *next_edge
;
960 if (!gcfgp
|| !*gcfgp
)
964 bb
= gcfg_get_rootbb (cfg
);
970 /* Cleanup all the edges. */
971 edge
= bb
->out_gedges
;
974 next_edge
= edge
->next
;
988 gcfg_get_rootbb (gcfgS
*gcfg
)
992 if (!gcfg
|| !gcfg
->num_gbbs
)
995 rootbb
= gcfg
->root_bb
;
1001 gcfg_print (const gcfgS
*gcfg
, FILE *outfile
)
1004 gedgeS
*gedge
= NULL
;
1005 uint64_t total_ginsns
= 0;
1007 cfg_for_each_bb(gcfg
, gbb
)
1009 fprintf (outfile
, "BB [%" PRIu64
"] with num insns: %" PRIu64
,
1010 gbb
->id
, gbb
->num_ginsns
);
1011 fprintf (outfile
, " [insns: %u to %u]\n",
1012 gbb
->first_ginsn
->line
, gbb
->last_ginsn
->line
);
1013 total_ginsns
+= gbb
->num_ginsns
;
1014 bb_for_each_edge(gbb
, gedge
)
1015 fprintf (outfile
, " outgoing edge to %" PRIu64
"\n",
1018 fprintf (outfile
, "\nTotal ginsns in all GBBs = %" PRIu64
"\n",
1023 frch_ginsn_data_init (const symbolS
*func
, symbolS
*start_addr
,
1024 enum ginsn_gen_mode gmode
)
1026 /* FIXME - error out if prev object is not free'd ? */
1027 frchain_now
->frch_ginsn_data
= XCNEW (struct frch_ginsn_data
);
1029 frchain_now
->frch_ginsn_data
->mode
= gmode
;
1030 /* Annotate with the current function symbol. */
1031 frchain_now
->frch_ginsn_data
->func
= func
;
1032 /* Create a new start address symbol now. */
1033 frchain_now
->frch_ginsn_data
->start_addr
= start_addr
;
1034 /* Assume the set of ginsn are apt for CFG creation, by default. */
1035 frchain_now
->frch_ginsn_data
->gcfg_apt_p
= true;
1037 frchain_now
->frch_ginsn_data
->label_ginsn_map
= str_htab_create ();
1041 frch_ginsn_data_cleanup (void)
1043 ginsnS
*ginsn
= NULL
;
1044 ginsnS
*next_ginsn
= NULL
;
1046 ginsn
= frchain_now
->frch_ginsn_data
->gins_rootP
;
1049 next_ginsn
= ginsn
->next
;
1050 ginsn_cleanup (&ginsn
);
1054 if (frchain_now
->frch_ginsn_data
->label_ginsn_map
)
1055 htab_delete (frchain_now
->frch_ginsn_data
->label_ginsn_map
);
1057 free (frchain_now
->frch_ginsn_data
);
1058 frchain_now
->frch_ginsn_data
= NULL
;
1061 /* Append GINSN to the list of ginsns for the current function being
1065 frch_ginsn_data_append (ginsnS
*ginsn
)
1067 ginsnS
*last
= NULL
;
1068 ginsnS
*temp
= NULL
;
1074 if (frchain_now
->frch_ginsn_data
->gins_lastP
)
1075 id
= frchain_now
->frch_ginsn_data
->gins_lastP
->id
;
1077 /* Do the necessary preprocessing on the set of input GINSNs:
1078 - Update each ginsn with its ID.
1079 While you iterate, also keep gcfg_apt_p updated by checking whether any
1080 ginsn is inappropriate for GCFG creation. */
1086 if (ginsn_indirect_jump_p (temp
)
1087 || (ginsn
->type
== GINSN_TYPE_JUMP
1088 && !ginsn_direct_local_jump_p (temp
)))
1089 frchain_now
->frch_ginsn_data
->gcfg_apt_p
= false;
1091 if (listing
& LISTING_GINSN_SCFI
)
1092 listing_newline (ginsn_print (temp
));
1094 /* The input GINSN may be a linked list of multiple ginsns chained
1095 together. Find the last ginsn in the input chain of ginsns. */
1101 /* Link in the ginsn to the tail. */
1102 if (!frchain_now
->frch_ginsn_data
->gins_rootP
)
1103 frchain_now
->frch_ginsn_data
->gins_rootP
= ginsn
;
1105 ginsn_link_next (frchain_now
->frch_ginsn_data
->gins_lastP
, ginsn
);
1107 frchain_now
->frch_ginsn_data
->gins_lastP
= last
;
1113 frch_ginsn_gen_mode (void)
1115 enum ginsn_gen_mode gmode
= GINSN_GEN_NONE
;
1117 if (frchain_now
->frch_ginsn_data
)
1118 gmode
= frchain_now
->frch_ginsn_data
->mode
;
1124 ginsn_data_begin (const symbolS
*func
)
1128 /* The previous block of asm must have been processed by now. */
1129 if (frchain_now
->frch_ginsn_data
)
1130 as_bad (_("GINSN process for prev func not done"));
1132 /* FIXME - hard code the mode to GINSN_GEN_SCFI.
1133 This can be changed later when other passes on ginsns are formalised. */
1134 frch_ginsn_data_init (func
, symbol_temp_new_now (), GINSN_GEN_SCFI
);
1136 /* Create and insert ginsn with function begin marker. */
1137 ginsn
= ginsn_new_symbol_func_begin (func
);
1138 frch_ginsn_data_append (ginsn
);
1144 ginsn_data_end (const symbolS
*label
)
1149 const symbolS
*func
;
1152 if (!frchain_now
->frch_ginsn_data
)
1155 /* Insert Function end marker. */
1156 ginsn
= ginsn_new_symbol_func_end (label
);
1157 frch_ginsn_data_append (ginsn
);
1159 func
= frchain_now
->frch_ginsn_data
->func
;
1161 /* Build the cfg of ginsn(s) of the function. */
1162 if (!frchain_now
->frch_ginsn_data
->gcfg_apt_p
)
1164 as_bad (_("untraceable control flow for func '%s'"),
1169 gcfg
= gcfg_build (func
, &err
);
1171 root_bb
= gcfg_get_rootbb (gcfg
);
1174 as_bad (_("Bad cfg of ginsn of func '%s'"), S_GET_NAME (func
));
1178 /* Execute the desired passes on ginsns. */
1179 err
= ginsn_pass_execute_scfi (func
, gcfg
, root_bb
);
1183 /* Other passes, e.g., warn for unreachable code can be enabled too. */
1184 ginsn
= frchain_now
->frch_ginsn_data
->gins_rootP
;
1185 err
= ginsn_pass_warn_unreachable_code (func
, gcfg
, ginsn
);
1189 gcfg_cleanup (&gcfg
);
1190 frch_ginsn_data_cleanup ();
1195 /* Add GINSN_TYPE_SYMBOL type ginsn for user-defined labels. These may be
1196 branch targets, and hence are necessary for control flow graph. */
1199 ginsn_frob_label (const symbolS
*label
)
1201 ginsnS
*label_ginsn
;
1205 if (frchain_now
->frch_ginsn_data
)
1207 /* PS: Note how we keep the actual LABEL symbol as ginsn->sym.
1208 Take care to avoid inadvertent updates or cleanups of symbols. */
1209 label_ginsn
= ginsn_new_symbol_user_label (label
);
1210 /* Keep the location updated. */
1211 file
= as_where (&line
);
1212 ginsn_set_file_line (label_ginsn
, file
, line
);
1214 frch_ginsn_data_append (label_ginsn
);
1216 label_ginsn_map_insert (label
, label_ginsn
);
1221 ginsn_data_func_symbol (void)
1223 const symbolS
*func
= NULL
;
1225 if (frchain_now
->frch_ginsn_data
)
1226 func
= frchain_now
->frch_ginsn_data
->func
;
1234 ginsn_data_begin (const symbolS
*func ATTRIBUTE_UNUSED
)
1236 as_bad (_("ginsn unsupported for target"));
1241 ginsn_data_end (const symbolS
*label ATTRIBUTE_UNUSED
)
1243 as_bad (_("ginsn unsupported for target"));
1248 ginsn_frob_label (const symbolS
*sym ATTRIBUTE_UNUSED
)
1254 ginsn_data_func_symbol (void)
1259 #endif /* TARGET_USE_GINSN. */