PIPS
Controlizer phase to build the Hierarchical Control Flow Graph

lint More...

+ Collaboration diagram for Controlizer phase to build the Hierarchical Control Flow Graph:

Modules

 Desugaring functions used to transform
 non well structured à la Fortran do-loop into an equivalent code with tests and gotos.
 

Macros

#define LABEL_TABLES_SIZE   10
 
#define LABEL_TABLES_SIZE   10
 
#define ADD_PRED_IF_NOT_ALREADY_HERE(pred, c)   (gen_once(pred,control_predecessors(c)))
 In C, we can have some "goto" inside a block from outside, that translate as any complex control graph into an "unstructured" in the PIPS jargon. More...
 
#define ADD_PRED_AND_COPY_IF_NOT_ALREADY_HERE(pred, c)   (gen_once(pred,gen_copy_seq(control_predecessors(c))))
 
#define UPDATE_CONTROL(c, s, pd, sc)
 Update control c by setting its statement to s, by unioning its predecessor set with pd, and by setting its successor set to sc (i.e. More...
 
#define PREDS_OF_SUCCS   1
 
#define SUCCS_OF_PREDS   2
 

Functions

static control make_conditional_control (statement st)
 In C, we can have some "goto" inside a block from outside, that translates as any complex control graph into an "unstructured" in the PIPS jargon. More...
 
static control get_label_control (string name)
 Get the control node associated to a label name. More...
 
static void update_used_labels (hash_table used_labels, string name, statement st)
 Mark a statement as related to a label. More...
 
static hash_table union_used_labels (hash_table l1, hash_table l2)
 Unions 2 hash maps that list statements referencing labels into one. More...
 
static bool covers_labels_p (statement st, hash_table used_labels)
 Compute whether all the label references in a statement are in a given label name to statement list local mapping. More...
 
static void create_statements_of_label (statement st)
 Update the global module-level Label_statements table according to the labels a statement references. More...
 
static void create_statements_of_labels (statement st)
 Initialize the global Label_statements mapping for the module that associates for any label in the module the statements that refer to it. More...
 
static bool controlize_loop (control c_res, control succ, hash_table used_labels)
 Computes the control graph of a Fortran do-loop statement. More...
 
static bool controlize_forloop (control c_res, control succ, hash_table used_labels)
 Computes the control graph of a C for loop statement. More...
 
static bool controlize_whileloop (control c_res, control succ, hash_table used_labels)
 Computes the control graph of a Fortran or C while loop statement. More...
 
static bool controlize_repeatloop (control c_res, control succ, hash_table used_labels)
 Computes the control graph of a C repeat until loop statement. More...
 
static void move_declaration_control_node_declarations_to_statement (list ctls)
 Move all the declarations found in a list of control to a given statement. More...
 
control find_exit_control_node (list ctls, control succ)
 Find the exit node of a sub-CFG defined by the list of nodes ctls and by the first node to execute when finished. More...
 
control find_or_create_exit_control_node (list ctls, control succ)
 FI: remake of function above, incomplete backward approach, now obsolete because the forward approach works. More...
 
static bool controlize_sequence (control c_res, control succ, hash_table used_labels)
 Computes the control graph of a sequence statement. More...
 
static bool controlize_test (control c_res, control succ, hash_table used_labels)
 Builds the control node of a test statement. More...
 
static bool controlize_goto (control c_res, control succ, hash_table used_labels)
 Deal with "goto" when building the HCFG. More...
 
static bool controlize_call (control c_res, control succ)
 Controlize a call statement. More...
 
bool controlize_statement (control c_res, control succ, hash_table used_labels)
 Controlize a statement that is in a control node, that is restructure it to have a HCFG recursively (a hierarchical control flow graph). More...
 
statement hcfg (statement st)
 Compute the hierarchical control flow graph (HCFG) of a statement. More...
 
static bool controlize (statement st, control pred, control succ, control c_res, hash_table used_labels)
 Computes in c_res the control node of the statement st whose predecessor control node is pred and successor succ. More...
 
static void patch_references (int how, control fnode, control tnode)
 PATCH_REFERENCES replaces all occurrences of FNODE by TNODE in the predecessors or successors lists of its predecessors or successors list (according to HOW, PREDS_OF_SUCCS or SUCCS_OF_PREDS). More...
 
static void add_proper_successor_to_predecessor (control pred, control c_res)
 
static bool controlize_call (statement st, control pred, control succ, control c_res)
 CONTROLIZE_CALL controlizes the call C of statement ST in C_RES. More...
 
statement loop_header (statement sl)
 LOOP_HEADER, LOOP_TEST and LOOP_INC build the desugaring phases of a do-loop L for the loop header (i=1), the test (i<10) and the increment (i=i+1). More...
 
statement loop_test (statement sl)
 
statement loop_inc (statement sl)
 
static bool controlize_loop (statement st, loop l, control pred, control succ, control c_res, hash_table used_labels)
 CONTROLIZE_LOOP computes in C_RES the control graph of the loop L (of statement ST) with PREDecessor and SUCCessor. More...
 
static statement whileloop_test (statement sl)
 Generate a test statement ts for exiting loop sl. More...
 
static bool controlize_whileloop (statement st, whileloop l, control pred, control succ, control c_res, hash_table used_labels)
 CONTROLIZE_WHILELOOP computes in C_RES the control graph of the loop L (of statement ST) with PREDecessor and SUCCessor. More...
 
statement forloop_header (statement sl)
 
statement forloop_test (statement sl)
 
statement forloop_inc (statement sl)
 
static bool controlize_forloop (statement st, forloop l, control pred, control succ, control c_res, hash_table used_labels)
 
static control compact_list (list ctls, control c_end)
 Take a list of controls ctls coming from a controlize_list() and compact the successive statements, i.e. More...
 
static list controlize_list_1 (list sts, control i_pred, control i_succ, control i_c_res, hash_table used_labels)
 Do the equivalent of a mapcar of controlize on statement list sts. More...
 
static bool controlize_list (statement st, list sts, control pred, control succ, control c_res, hash_table used_labels)
 Computes in c_res the control graph of the list sts (of statement st) with pred predecessor and succ successor. More...
 
static bool controlize_test (statement st, test t, control pred, control succ, control c_res, hash_table used_labels)
 Builds the control node of a statement st in c_res which is a test statement t. More...
 
static void init_label (string name, statement st)
 INIT_LABEL puts the reference in the statement ST to the label NAME int the Label_statements table and allocate a slot in the Label_control table. More...
 
static void create_statements_of_labels (st)
 
static unstructured simplified_unstructured (control top, control bottom, control res)
 SIMPLIFIED_UNSTRUCTURED tries to get rid of top-level and useless unstructured nodes. More...
 
unstructured control_graph (statement st)
 CONTROL_GRAPH returns the control graph of the statement ST. More...
 

Variables

static hash_table Label_statements
 This maps label names to the list of statements where they appear (either as definition or reference). More...
 
static hash_table Label_control
 This maps label names to their (possible forward) control nodes. More...
 
static list Unreachable
 UNREACHABLE is the hook used as a predecessor of statements that are following a goto. More...
 
static hash_table Label_statements
 LABEL_STATEMENTS maps label names to the list of statements where they appear (either as definition or reference). More...
 
static hash_table Label_control
 LABEL_CONTROL maps label names to their (possible forward) control nodes. More...
 

Detailed Description

lint

It computes the Hierarchical Control Flow Graph of a given statement according the control hierarchy.

It is used in PIPS to transform the output of the parsers (the PARSED_CODE resource) into HCFG code (the CODE resource).

For example if there are some "goto" in a program, it will encapsulate the unstructured graph into an "unstructured" object covering all the gotos and their label targets to localize the messy part. Then this object is put into a normal statement so that, seen from above, the code keep a good hierarchy.

In PIPS the RI (Internal Representation or AST) is quite simple so that it is easy to deal with. But the counterpart is that some complex control structures need to be "unsugared". For example switch/case/break/default are transformed into tests, goto and label, for(;;) with break or continue are transformed into while() loops with goto/label, and so on. It is up to the prettyprinter to recover the high level construction if needed (...and possible).

In the case of C, it is far more complicated than with Fortran77 that was targeted by PIPS at the beginning because we need to deal with variable scoping according to their block definitions that may not be the same hierarchy that the HCFG, for example when you have a goto inside a block from outside and when you have local variables in the block. In C99 it is even worse since you can have executable declarations.

There are other phases in PIPS that can be used later to operate on the CODE to optimize it further.

Even if there is no fundamental reason that we cannot controlize an already controlized code, it is not implemented yet. For example, it could be useful to modify some CODE by adding some goto or complex control code and call again the controlizer on the CODE to have nice unstructured back instead of building correct unstructured statements from scratch or using some CODE dump-and-reparse as it is done in some PIPS phases (outliner...).

TODO: a zen-er version of the recursion that avoid passing along the successor everywhere since we know at entry that it is the only successor of the main control node.

This is the new version of the controlizer version rewritten by Ronan.nosp@m..Ker.nosp@m.yell@.nosp@m.hpc-.nosp@m.proje.nosp@m.ct.c.nosp@m.om

It computes the Hierarchical Control Flow Graph of a given statement according the control hierarchy.

It is used in PIPS to transform the output of the parsers (the PARSED_CODE resource) into HCFG code (the PARSED_CODE resource).

For example if there are some "goto" in a program, it will encapsulated the unstructured graph in an "unstructured" object covering all the goto and their label targets to localize the messy part and this object is put into a normal statement so that seen from above the code keep a good hierarchy.

In PIPS the RI (Internal Representation or AST) is quite simple so that it is easy to deal with. But the counterpart is that some complex control structures need to be "unsugared". For example switch/case/break/default are transformed into tests, goto and label, for(;;) with break or continue are transformed into while() loops with goto/label, and so on.

There are other phases in PIPS that can be used later to operate on the CODE to optimize it further.

WARNINGS:

. Temporary locations malloc()ed while recursing in the process are often not freed (to be done latter ... if required)

. The desugaring of DO loops is not perfect (in case of side-effects inside loop ranges.

Pierre Jouvelot (27/5/89) <- this is a French date :-)

MODIFICATIONS (historian fun):

. hash_get interface modification: in one hash table an undefined key meant an error; in another one an undefined key was associated to the default value empty_list; this worked as long as NULL was returned as NOT_FOUND value (i.e. HASH_UNDEFINED_VALUE); this would work again if HASH_UNDEFINED_VALUE can be user definable; Francois Irigoin, 7 Sept. 90

Macro Definition Documentation

◆ ADD_PRED_AND_COPY_IF_NOT_ALREADY_HERE

#define ADD_PRED_AND_COPY_IF_NOT_ALREADY_HERE (   pred,
 
)    (gen_once(pred,gen_copy_seq(control_predecessors(c))))

Definition at line 151 of file old_controlizer.c.

◆ ADD_PRED_IF_NOT_ALREADY_HERE

#define ADD_PRED_IF_NOT_ALREADY_HERE (   pred,
 
)    (gen_once(pred,control_predecessors(c)))

In C, we can have some "goto" inside a block from outside, that translate as any complex control graph into an "unstructured" in the PIPS jargon.

Unfortunately, that means it break the structured block nesting that may carry declarations with the scoping information.

So we need to track this scope information independently of the control graph. This is the aim of this declaration scope stack that is used to track scoping during visiting the RI. FI -> PJ:

The naming for ADD_PRED et ADD_SUCC is misleading. ADD_SUCC is in fact a SET_SUCC. ADD_PRED is UNION_PRED. When used to Newgen but not to control, ADD_SUCC reduces readability.

Furthermore, ADD_SUCC() is dangerous when used on a control that is a test since the position in the successor list is significant. true successors are in the odd positions (the first element is of rank one). false successors are in the odd position. Add control "pred" to the predecessor set of control c if not already here

Definition at line 150 of file old_controlizer.c.

◆ LABEL_TABLES_SIZE [1/2]

#define LABEL_TABLES_SIZE   10

Definition at line 115 of file controlizer.c.

◆ LABEL_TABLES_SIZE [2/2]

#define LABEL_TABLES_SIZE   10

Definition at line 101 of file old_controlizer.c.

◆ PREDS_OF_SUCCS

#define PREDS_OF_SUCCS   1

Definition at line 171 of file old_controlizer.c.

◆ SUCCS_OF_PREDS

#define SUCCS_OF_PREDS   2

Definition at line 172 of file old_controlizer.c.

◆ UPDATE_CONTROL

#define UPDATE_CONTROL (   c,
  s,
  pd,
  sc 
)
Value:
{ \
control_statement(c)=s; \
MAPL(preds, {control_predecessors(c) = \
ADD_PRED_IF_NOT_ALREADY_HERE(CONTROL(CAR(preds)), c);}, \
pd); \
gen_free_list(pd);\
gen_free_list( control_successors(c));\
control_successors(c)=sc; \
}
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
#define control_predecessors(x)
Definition: ri.h:943
#define CONTROL(x)
CONTROL.
Definition: ri.h:910
#define control_successors(x)
Definition: ri.h:945

Update control c by setting its statement to s, by unioning its predecessor set with pd, and by setting its successor set to sc (i.e.

previous successors are lost, but not previous predecessors).

Note: This macro does not preserve the consistency of the control flow graph as pd's successor list and sc predecessor list are not updated.

Definition at line 161 of file old_controlizer.c.

Function Documentation

◆ add_proper_successor_to_predecessor()

static void add_proper_successor_to_predecessor ( control  pred,
control  c_res 
)
static

Replaces the following statement:

control_successors(pred) = ADD_SUCC(c_res, pred);

Usually, too much of a mess: do not try to be too strict!

Do whatever was done before and let memory leak!

Definition at line 365 of file old_controlizer.c.

366 {
367  /* Replaces the following statement: */
368  /* control_successors(pred) = ADD_SUCC(c_res, pred); */
369 
370  /* Usually, too much of a mess: do not try to be too strict! */
371  /*
372  if(statement_test_p(control_statement(pred))) {
373  control_successors(pred) = gen_nconc(control_successors(pred),
374  CONS(CONTROL, c_res, NIL));
375  pips_assert("While building the CFG, "
376  "a test control node may have one or two successors",
377  gen_length(control_successors(pred))<=2);
378  }
379  else {
380  if(gen_length(control_successors(pred))==0) {
381  control_successors(pred) = CONS(CONTROL, c_res, NIL);
382  }
383  else if(gen_length(control_successors(pred))==1) {
384  if(gen_in_list_p(succ,control_successors(pred))) {
385  ;
386  }
387  else {
388  pips_internal_error("Two or more candidate successors "
389  "for a standard statement: %p and %p\n",
390  succ, CONTROL(CAR(control_successors(pred))));
391  }
392  }
393  else {
394  pips_internal_error("Two or more successors for non-test node %p",
395  pred);
396  }
397  }
398  */
399 
401  if(!gen_in_list_p(c_res, control_successors(pred))) {
403  CONS(CONTROL, c_res, NIL));
404  }
405  pips_assert("While building the CFG, "
406  "a test control node may have one or two successors",
407  gen_length(control_successors(pred))<=2);
408  }
409  else {
410  /* Do whatever was done before and let memory leak! */
412  control_successors(pred) = CONS(CONTROL, c_res, NIL);
413  }
414 }
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
size_t gen_length(const list l)
Definition: list.c:150
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
bool statement_test_p(statement)
Definition: statement.c:343
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define control_statement(x)
Definition: ri.h:941

References CONS, CONTROL, control_statement, control_successors, gen_free_list(), gen_in_list_p(), gen_length(), gen_nconc(), NIL, pips_assert, and statement_test_p().

Referenced by controlize(), controlize_call(), controlize_forloop(), controlize_loop(), controlize_test(), and controlize_whileloop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ compact_list()

static control compact_list ( list  ctls,
control  c_end 
)
static

Take a list of controls ctls coming from a controlize_list() and compact the successive statements, i.e.

concatenates (i=1) followed by (j=2) in a single control with a block statement (i=1;j=2).

Returns
the last control node of the remaining control list. It may not be c_end if this one has been fused with a previous control node.

Added a set to avoid investigating a removed node. Many memory leaks removed. RK.

This procedure cannot be replaced by fuse_sequences_in_unstructured() since the API is not the same and because of various goto from/to outside, this control list may belong to quite larger unstructured.

Pointer to the end of the current unstructured:

Empty statement control list, clearly nothing to do:

This is the iterator on the first element of the control list:

Do not reprocess an already seen node.

We are at a non structured node or at the exit: keep the node and go on inspecting next node from the list. RK

Ok, succ is defined. RK

Verify if the control node is not reachable on its label:

There is a label that may be used on this control node: do not fuse

This happens quite often in Syntax with no consequences; this leads to a core dump for C_syntax/block_scope13.c

Do not fuse: go to next control node:

If it is not a loop on c_res, fuse the nodes:

You need a new block to fuse and to respect the scopes

Remove the useless control:

We are at the end and the last node has disappeared... Update the pointer to the new one:

Definition at line 1063 of file old_controlizer.c.

1065 {
1066  control c_res;
1067  set processed_nodes;
1068  /* Pointer to the end of the current unstructured: */
1069  control c_last = c_end ;
1070 
1071  ifdebug(5) {
1072  pips_debug(5, "Begin with list c_end %p, ctls:", c_end);
1074  fprintf(stderr, "\n");
1075  }
1076 
1077  if (ENDP(ctls)) {
1078  /* Empty statement control list, clearly nothing to do: */
1079  return c_last;
1080  }
1081 
1082  processed_nodes = set_make(set_pointer);
1083 
1084  /* This is the iterator on the first element of the control list: */
1085  c_res = CONTROL(CAR(ctls));
1086 
1087  for(ctls = CDR(ctls); !ENDP(ctls); ctls = CDR(ctls)) {
1088  cons *succs, *succs_of_succ;
1089  instruction i, succ_i;
1090  statement st, succ_st;
1091  control succ;
1092 
1093  if (set_belong_p(processed_nodes, (char *) c_res)) {
1094  /* Do not reprocess an already seen node. */
1095  c_res = CONTROL(CAR(ctls));
1096  continue;
1097  }
1098 
1099  if (gen_length(succs=control_successors(c_res)) != 1 ||
1100  gen_length(control_predecessors(succ=CONTROL(CAR(succs)))) != 1 ||
1101  gen_length(succs_of_succ=control_successors(succ)) != 1 ||
1102  CONTROL(CAR(succs_of_succ)) == c_res ) {
1103  /* We are at a non structured node or at the exit: keep
1104  the node and go on inspecting next node from the
1105  list. RK */
1106  c_res = CONTROL(CAR(ctls));
1107  continue;
1108  }
1109 
1110  st = control_statement(c_res) ;
1111 
1112  // NL: If it's uncomment, it remove some pragma in some case, I don't
1113  // know why. For instance C_syntax/pragma05
1114  // // if there is an extension for the statement don't make fusion
1115  // if (!empty_extensions_p(statement_extensions(st))) {
1116  // c_res = CONTROL(CAR(ctls));
1117  // continue;
1118  // }
1119 
1120  ifdebug(1) {
1122  pips_assert("st is a block or a continue or st carries no delarations",
1123  statement_block_p(st)
1124  || continue_statement_p(st)
1125  || ENDP(statement_declarations(st)));
1126  }
1127  /* Ok, succ is defined. RK */
1128  succ_st = control_statement(succ);
1129  set_add_element(processed_nodes, processed_nodes, (char *) succ);
1130 
1134  /* Verify if the control node is not reachable on its label: */
1136  string ln = entity_name(l);
1137  control c = get_label_control(ln);
1138  if(!control_undefined_p(c)) {
1139  /* There is a label that may be used on this control node: do
1140  not fuse */
1141  if (c==succ) {
1142  /* This happens quite often in Syntax with no
1143  consequences; this leads to a core dump for
1144  C_syntax/block_scope13.c */
1145  pips_debug(2, "Do not fuse control %p since we will have a latent goto on it through label \"%s\"\n",
1146  c_res, ln);
1147  /* Do not fuse: go to next control node: */
1148  c_res = CONTROL(CAR(ctls));
1149  continue;
1150  }
1151  else
1152  pips_internal_error("Inconsistent hash table Label_control: "
1153  "same label points towards two different controls");
1154  }
1155  }
1156  if(c_res != succ) {
1157  /* If it is not a loop on c_res, fuse the nodes: */
1159  || (statement_block_p(succ_st) && !ENDP(statement_declarations(succ_st)))
1160  || (statement_block_p(succ_st) && !empty_extensions_p(statement_extensions(succ_st)))
1161  ) {
1162  /* You need a new block to fuse and to respect the scopes */
1164  CONS(STATEMENT, succ_st, NIL)));
1165  control_statement(c_res) =
1170  i,NIL,NULL,
1172  ;
1173  }
1174  else {
1175  if(!ENDP(statement_declarations(st))
1176  && !continue_statement_p(st)) {
1177  pips_user_warning("Declarations carried by a statement \"%s\""
1178  " which is not a block nor a continue!\n",
1180  }
1183  control_statement(c_res) =
1188  i,NIL,NULL,
1190  }
1191  if(instruction_block_p(succ_i=statement_instruction(succ_st))){
1192  instruction_block(i) =
1194  instruction_block(succ_i));
1195  pips_debug(8, "Free statement %p with identification %s from control succ %p\n",
1196  succ_st, statement_identification(succ_st), succ);
1198  free_statement(succ_st);
1199  succ_st = statement_undefined;
1201  }
1202  else {
1203  instruction_block(i) =
1205  CONS(STATEMENT, succ_st, NIL));
1206  }
1207  }
1208  ifdebug(1) {
1209  pips_assert("control succ and its statement are consistent",
1210  control_consistent_p(succ));
1211  }
1212  /* Remove the useless control: */
1215  }
1216 
1217  if(succ == c_last) {
1218  /* We are at the end and the last node has
1219  disappeared... Update the pointer to the new one: */
1220  c_last = c_res;
1221  break;
1222  }
1223  ifdebug(1) {
1225  statement_consistent_p(succ_st);
1226  }
1227  }
1228  set_free(processed_nodes);
1229  return c_last;
1230 }
bool statement_consistent_p(statement p)
Definition: ri.c:2195
statement make_statement(entity a1, intptr_t a2, intptr_t a3, string a4, instruction a5, list a6, string a7, extensions a8, synchronization a9)
Definition: ri.c:2222
bool control_consistent_p(control p)
Definition: ri.c:496
synchronization make_synchronization_none(void)
Definition: ri.c:2424
void free_statement(statement p)
Definition: ri.c:2189
bool return_label_p(const char *s)
Definition: entity_names.c:272
void display_address_of_control_nodes(list cs)
Display the adresses a list of control nodes.
Definition: control.c:612
void remove_a_control_from_an_unstructured(control c)
Remove a control node from a control graph.
Definition: control.c:992
instruction make_instruction_block(list statements)
Build an instruction block from a list of statements.
Definition: instruction.c:106
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
string statement_identification(statement)
Like external_statement_identification(), but with internal information, the hexadecimal address of t...
Definition: statement.c:1700
bool continue_statement_p(statement)
Test if a statement is a CONTINUE, that is the FORTRAN nop, the ";" in C or the "pass" in Python....
Definition: statement.c:203
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_user_warning
Definition: misc-local.h:146
#define pips_internal_error
Definition: misc-local.h:149
#define STATEMENT_ORDERING_UNDEFINED
mapping.h inclusion
Definition: newgen-local.h:35
void set_free(set)
Definition: set.c:332
bool set_belong_p(const set, const void *)
Definition: set.c:194
@ set_pointer
Definition: newgen_set.h:44
set set_make(set_type)
Create an empty set of any type but hash_private.
Definition: set.c:102
set set_add_element(set, const set, const void *)
Definition: set.c:152
#define string_undefined
Definition: newgen_types.h:40
static control get_label_control(string name)
Get the control node associated to a label name.
#define instruction_block_p(i)
#define statement_block_p(stat)
#define STATEMENT_NUMBER_UNDEFINED
default values
#define instruction_block(i)
entity entity_empty_label(void)
Definition: entity.c:1105
bool entity_empty_label_p(entity e)
Definition: entity.c:666
bool empty_extensions_p(extensions es)
Definition: extension.c:50
extensions empty_extensions(void)
extension.c
Definition: extension.c:43
#define instruction_undefined
Definition: ri.h:1454
#define statement_label(x)
Definition: ri.h:2450
#define entity_name(x)
Definition: ri.h:2790
#define statement_extensions(x)
Definition: ri.h:2464
#define control_undefined_p(x)
Definition: ri.h:917
#define statement_declarations(x)
Definition: ri.h:2460
#define statement_instruction(x)
Definition: ri.h:2458
#define statement_undefined_p(x)
Definition: ri.h:2420
#define statement_undefined
Definition: ri.h:2419
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
#define ifdebug(n)
Definition: sg.c:47
FI: I do not understand why the type is duplicated at the set level.
Definition: set.c:59
The structure used to build lists in NewGen.
Definition: newgen_list.h:41

References CAR, CDR, CONS, continue_statement_p(), CONTROL, control_consistent_p(), control_predecessors, control_statement, control_successors, control_undefined_p, display_address_of_control_nodes(), empty_extensions(), empty_extensions_p(), ENDP, entity_empty_label(), entity_empty_label_p(), entity_name, fprintf(), free_statement(), gen_length(), gen_nconc(), get_label_control(), ifdebug, instruction_block, instruction_block_p, instruction_undefined, make_instruction_block(), make_statement(), make_synchronization_none(), NIL, pips_assert, pips_debug, pips_internal_error, pips_user_warning, remove_a_control_from_an_unstructured(), return_label_p(), set_add_element(), set_belong_p(), set_free(), set_make(), set_pointer, STATEMENT, statement_block_p, statement_consistent_p(), statement_declarations, statement_extensions, statement_identification(), statement_instruction, statement_label, STATEMENT_NUMBER_UNDEFINED, STATEMENT_ORDERING_UNDEFINED, statement_undefined, statement_undefined_p, and string_undefined.

Referenced by controlize_list().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ control_graph()

unstructured control_graph ( statement  st)

CONTROL_GRAPH returns the control graph of the statement ST.

Since the controlizer does not seem to accept GOTO inside sequence from outside but it appears in the code with READ/WRITE with I/O exceptions (end=, etc), first remove useless blocks. RK

To track declaration scoping independently of control structure:

FI: structured or not, let's build an unstructured...

Clean up scoping stack:

The statement st is not consistent anymore here.

Since the controlizer is a sensitive pass, avoid leaking basic errors...

Parameters
stt

Definition at line 2190 of file old_controlizer.c.

2191 {
2192  control result, top, bottom;
2193  hash_table used_labels = hash_table_make(hash_string, 0);
2195 
2196  ifdebug(1) {
2197  pips_assert("Statement should be OK.", statement_consistent_p(st));
2198  set_bool_property("PRETTYPRINT_BLOCKS", true);
2199  set_bool_property("PRETTYPRINT_EMPTY_BLOCKS", true);
2200  }
2201 
2202  /* Since the controlizer does not seem to accept GOTO inside
2203  sequence from outside but it appears in the code with
2204  READ/WRITE with I/O exceptions (end=, etc), first remove
2205  useless blocks. RK */
2206  clean_up_sequences(st);
2207 
2208  ifdebug(1) {
2210  }
2211 
2215 
2216  result = make_conditional_control(st);
2219  Unreachable = NIL;
2220 
2221  ifdebug(1) {
2223  }
2224 
2225  /* To track declaration scoping independently of control structure: */
2226  make_scoping_statement_stack();
2227 
2228  /* FI: structured or not, let's build an unstructured... */
2229  (void) controlize(st, top, bottom, result, used_labels);
2230 
2231  /* Clean up scoping stack: */
2232  free_scoping_statement_stack();
2233 
2234  /* The statement st is not consistent anymore here. */
2235  //statement_consistent_p(st);
2236 
2237  if(!ENDP(Unreachable)) {
2238  pips_user_warning("Some statements are unreachable\n");
2239  pips_user_warning("Unreachable statements:\n");
2241  // This interesting information makes library control dependent on library prettyprint
2242  pips_user_warning("Statement:\n%s\n", text_to_string(statement_to_text(s)));
2243  if (statement_number(s) != -1) {
2244  pips_user_warning("Statement number: %d\n", statement_number(s));
2245  }
2246  }
2247  }
2250  hash_table_free(used_labels);
2251 
2252  u = simplified_unstructured(top, bottom, result);
2253 
2254  ifdebug(5) {
2255  pips_debug(1,
2256  "Nodes in unstructured %p (entry %p, exit %p) from entry:\n",
2259  pips_debug(1, "Accessible nodes from exit:\n");
2261  }
2262 
2263  /* Since the controlizer is a sensitive pass, avoid leaking basic
2264  errors... */
2265  ifdebug(1) {
2267  }
2268 
2271 
2272  ifdebug(1) {
2275  pips_assert("Unstructured should be OK.", unstructured_consistent_p(u));
2276  }
2277 
2278  return(u);
2279 }
bool unstructured_consistent_p(unstructured p)
Definition: ri.c:2751
control make_control(statement a1, list a2, list a3)
Definition: ri.c:523
bool clean_up_sequences(statement s)
Recursively clean up the statement sequences by fusing them if possible and by removing useless one.
void display_linked_control_nodes(control c)
Display all the control nodes reached or reachable from c for debugging purpose.
Definition: control.c:629
void check_control_coherency(control c)
Test the coherency of a control node network from a control node.
Definition: control.c:487
static hash_table Label_control
LABEL_CONTROL maps label names to their (possible forward) control nodes.
static list Unreachable
UNREACHABLE is the hook used as a predecessor of statements that are following a goto.
static void create_statements_of_labels(st)
static hash_table Label_statements
LABEL_STATEMENTS maps label names to the list of statements where they appear (either as definition o...
#define LABEL_TABLES_SIZE
static bool controlize(statement st, control pred, control succ, control c_res, hash_table used_labels)
Computes in c_res the control node of the statement st whose predecessor control node is pred and suc...
static unstructured simplified_unstructured(control top, control bottom, control res)
SIMPLIFIED_UNSTRUCTURED tries to get rid of top-level and useless unstructured nodes.
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
statement make_plain_continue_statement(void)
Make a simple continue statement to be used as a NOP or ";" in C.
Definition: statement.c:964
hash_table hash_table_make(hash_key_type key_type, size_t size)
Definition: hash.c:294
void hash_table_free(hash_table htp)
this function deletes a hash table that is no longer useful.
Definition: hash.c:327
@ hash_string
Definition: newgen_hash.h:32
static control make_conditional_control(statement st)
Make a control node from a statement if needed.
text statement_to_text(statement)
Definition: statement.c:124
void set_bool_property(const char *, bool)
void reset_unstructured_number()
Reset the unstructured number for a new module reordering.
Definition: reorder.c:56
bool unstructured_reorder(unstructured u)
Reorder an unstructured.
Definition: reorder.c:166
#define unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
#define unstructured_undefined
Definition: ri.h:2980
#define unstructured_exit(x)
Definition: ri.h:3006
#define statement_number(x)
Definition: ri.h:2452
string text_to_string(text t)
SG: moved here from ricedg.
Definition: print.c:239

◆ controlize()

static bool controlize ( statement  st,
control  pred,
control  succ,
control  c_res,
hash_table  used_labels 
)
static

Computes in c_res the control node of the statement st whose predecessor control node is pred and successor succ.

The used_LABELS is modified to deal with local use of labels.

The invariant is that it links predecessors and successors of c_res, updates the successors of pred and the predecessors of succ.

In fact, it cannot update the successors of pred because it cannot know which successor of pred c_RES is when pred is associated to a test. pred and c_res must be linked together when you enter controlize(), or they must be linked later by the caller. But they cannot be linked here thru the successor list of pred and, if the consistency is true here, they cannot be linked either by the predecessor list of succ. If they are linked later, it is useless to pass pred down. If they are linked earlier, they might have to be unlinked when structured code is found.

Returns
true if the current statement isn't a structured control.

print_statement(st);

A C block may have a label and even goto from outside on it.

A block may only contain declarations with initializations and side effects on the store

Empty block

If st carries local declarations, so should the statement associated to c_res.

Get the label name of the statement the goto point to:

Memory leak in CONS(CONTROL, pred, NIL). Also forgot to unlink the predecessor of the former successor of pred. RK

control_successors(pred) = ADD_SUCC(c_res, pred);

I do not know why, but my following code does not work. So I put back former one above... :-( RK.

FI: IO calls may have control effects; they should be handled here!

SG+EC:some label may have been lost in the process fix it here instead of understanding why

PJ: controlize_call() controlize any "nice" statement

no break

pips_debug(1, "st %p at exit:\n", st);

print_statement(st);

The declarations may be preserved at a lower level if(!ENDP(statement_declarations(st)) && ENDP(statement_declarations(control_statement(c_res)))) { pips_internal_error("Lost local declarations"); }

Update the association between the current statement and its label:

Definition at line 1969 of file old_controlizer.c.

1974 {
1976  entity elabel = statement_label(st);
1977  string label = entity_name(elabel);
1978  bool controlized = false;
1979  control n_succ = control_undefined; // To be used in case of goto
1980 
1981  ifdebug(5) {
1982  pips_debug(1,
1983  "Begin with (st = %p, pred = %p, succ = %p, c_res = %p)\n"
1984  "st at entry:\n",
1985  st, pred, succ, c_res);
1986  ifdebug(1) {
1988  }
1989  /* print_statement(st); */
1990  /*
1991  pips_assert("pred is a predecessor of c_res",
1992  gen_in_list_p(pred, control_predecessors(c_res)));
1993  pips_assert("c_res is a successor of pred",
1994  gen_in_list_p(c_res, control_successors(pred)));
1995  */
1996  pips_debug(1, "Begin with result c_res %p:\n", c_res);
2000  check_control_coherency(c_res);
2001  }
2002 
2003  switch(instruction_tag(i)) {
2004  case is_instruction_block: {
2005  /* A C block may have a label and even goto from outside on it. */
2006  /* A block may only contain declarations with initializations
2007  and side effects on the store */
2008  if(ENDP(instruction_block(i))) {
2009  /* Empty block */
2010  controlized = controlize_call(st, pred, succ, c_res);
2011  ifdebug(1) {
2013  }
2014  }
2015  else {
2016  ifdebug(1) {
2018  }
2019  scoping_statement_push(st);
2020  controlized = controlize_list(st, instruction_block(i),
2021  pred, succ, c_res, used_labels);
2022  ifdebug(1) {
2024  }
2025 
2026  ifdebug(5) {
2027  pips_debug(1, "CFG consistency check before list6 controlization."
2028  " Control \"pred\" %p:\n", pred);
2030  pips_debug(1, "Control \"succ\" %p:\n", succ);
2032 
2035  check_control_coherency(c_res);
2036  }
2037  /* If st carries local declarations, so should the statement
2038  associated to c_res. */
2039  if(controlized && !ENDP(statement_declarations(st))
2042  pips_user_warning("Some local declarations may have been lost\n");
2043  }
2044  scoping_statement_pop();
2045  ifdebug(1) {
2047  }
2048  }
2049  break;
2050  }
2051  case is_instruction_test:
2052  controlized = controlize_test(st, instruction_test(i),
2053  pred, succ, c_res, used_labels);
2054  ifdebug(1) {
2056  }
2057  break;
2058  case is_instruction_loop:
2059  controlized = controlize_loop(st, instruction_loop(i),
2060  pred, succ, c_res, used_labels);
2061  ifdebug(1) {
2063  }
2064  break;
2066  controlized = controlize_whileloop(st, instruction_whileloop(i),
2067  pred, succ, c_res, used_labels);
2068  ifdebug(1) {
2070  }
2071  break;
2072  case is_instruction_goto: {
2073  /* Get the label name of the statement the goto point to: */
2074  string name = entity_name(statement_label(instruction_goto(i)));
2076 
2079  // Well, let's try this for the time being. What is the scope?!?
2082 
2083  n_succ = get_label_control(name);
2084 
2085  ifdebug(5) {
2086  pips_debug(1, "CFG consistency check before goto controlization."
2087  " Control \"pred\" %p:\n", pred);
2089  pips_debug(1, "Control \"n_succ\" %p:\n", n_succ);
2092  check_control_coherency(n_succ);
2093  check_control_coherency(c_res);
2094  }
2095 
2096  /* Memory leak in CONS(CONTROL, pred, NIL). Also forgot to
2097  unlink the predecessor of the former successor of pred. RK */
2098  /* control_successors(pred) = ADD_SUCC(c_res, pred); */
2100  UPDATE_CONTROL(c_res, nop,
2101  CONS(CONTROL, pred, NIL),
2102  CONS(CONTROL, n_succ, NIL));
2103  control_predecessors(n_succ) = ADD_PRED_IF_NOT_ALREADY_HERE(c_res, n_succ);
2104  /* I do not know why, but my following code does not work. So
2105  I put back former one above... :-( RK. */
2106 #if 0
2107  /* Use my procedures instead to set a GOTO from pred to
2108  c_res. RK */
2109  if (gen_length(control_successors(pred)) == 1)
2111  link_2_control_nodes(pred, c_res);
2112  link_2_control_nodes(c_res, n_succ);
2113  /* Hmmm... A memory leak on the previous statement of c_res? */
2114  control_statement(c_res) = nop;
2115 #endif
2116  update_used_labels(used_labels, name, st);
2117  controlized = true;
2118  break;
2119  }
2120  case is_instruction_call:
2121  /* FI: IO calls may have control effects; they should be handled here! */
2122  controlized = controlize_call(st, pred, succ, c_res);
2123  ifdebug(1) {
2125  }
2126  break;
2128  pips_assert("We are really dealing with a for loop",
2130  controlized = controlize_forloop(st, instruction_forloop(i),
2131  pred, succ, c_res, used_labels);
2132  ifdebug(1) {
2134  }
2135  /* SG+EC:some label may have been lost in the process
2136  fix it here instead of understanding why */
2137  if(!same_entity_p(statement_label(st),elabel)) {
2138  statement_label(st)=elabel;
2139  }
2140  break;
2142  /* PJ: controlize_call() controlize any "nice" statement */
2143  controlized = return_instruction_p(i) || controlize_call(st, pred, succ, c_res);
2144 
2145  ifdebug(1) {
2147  }
2148  break;
2150  pips_internal_error("is_instruction_unstructured not treated, never happen?");
2151  break;
2153  pips_internal_error("is_instruction_multitest not treated, never happen?");
2154  break;
2155  default:
2156  pips_internal_error("Unknown instruction tag %d", instruction_tag(i));
2157  /* no break */
2158  }
2159 
2160  ifdebug(5) {
2162  /* pips_debug(1, "st %p at exit:\n", st); */
2163  /* print_statement(st); */
2164  pips_debug(1, "Resulting Control c_res %p at exit:\n", c_res);
2166  fprintf(stderr, "---\n");
2167  /* The declarations may be preserved at a lower level
2168  if(!ENDP(statement_declarations(st))
2169  && ENDP(statement_declarations(control_statement(c_res)))) {
2170  pips_internal_error("Lost local declarations");
2171  }
2172  */
2174  if(control_undefined_p(n_succ))
2176  else
2177  check_control_coherency(n_succ);
2178  check_control_coherency(c_res);
2179  }
2180 
2181  /* Update the association between the current statement and its label:
2182  */
2183  update_used_labels(used_labels, label, st);
2184 
2185  return(controlized);
2186 }
void unlink_2_control_nodes(control source, control target)
Remove all edged between 2 control nodes.
Definition: control.c:1276
void link_2_control_nodes(control source, control target)
Add an edge between 2 control nodes.
Definition: control.c:1193
static bool controlize_call(statement st, control pred, control succ, control c_res)
CONTROLIZE_CALL controlizes the call C of statement ST in C_RES.
static bool controlize_forloop(statement st, forloop l, control pred, control succ, control c_res, hash_table used_labels)
static bool controlize_test(statement st, test t, control pred, control succ, control c_res, hash_table used_labels)
Builds the control node of a statement st in c_res which is a test statement t.
static void add_proper_successor_to_predecessor(control pred, control c_res)
static bool controlize_whileloop(statement st, whileloop l, control pred, control succ, control c_res, hash_table used_labels)
CONTROLIZE_WHILELOOP computes in C_RES the control graph of the loop L (of statement ST) with PREDece...
#define ADD_PRED_IF_NOT_ALREADY_HERE(pred, c)
In C, we can have some "goto" inside a block from outside, that translate as any complex control grap...
static bool controlize_loop(statement st, loop l, control pred, control succ, control c_res, hash_table used_labels)
CONTROLIZE_LOOP computes in C_RES the control graph of the loop L (of statement ST) with PREDecessor ...
#define UPDATE_CONTROL(c, s, pd, sc)
Update control c by setting its statement to s, by unioning its predecessor set with pd,...
static bool controlize_list(statement st, list sts, control pred, control succ, control c_res, hash_table used_labels)
Computes in c_res the control graph of the list sts (of statement st) with pred predecessor and succ ...
bool return_instruction_p(instruction i)
Test if an instruction is a C or Fortran "return".
Definition: instruction.c:185
statement make_continue_statement(entity)
Definition: statement.c:953
static void update_used_labels(hash_table used_labels, string name, statement st)
Add the reference to the label NAME in the statement ST.
#define is_instruction_block
soft block->sequence transition
bool same_entity_p(entity e1, entity e2)
predicates on entities
Definition: entity.c:1321
void print_entities(list l)
Definition: entity.c:167
#define control_undefined
Definition: ri.h:916
#define instruction_loop(x)
Definition: ri.h:1520
#define instruction_goto(x)
Definition: ri.h:1526
#define instruction_forloop_p(x)
Definition: ri.h:1536
@ is_instruction_goto
Definition: ri.h:1473
@ is_instruction_unstructured
Definition: ri.h:1475
@ is_instruction_whileloop
Definition: ri.h:1472
@ is_instruction_expression
Definition: ri.h:1478
@ is_instruction_test
Definition: ri.h:1470
@ is_instruction_multitest
Definition: ri.h:1476
@ is_instruction_call
Definition: ri.h:1474
@ is_instruction_forloop
Definition: ri.h:1477
@ is_instruction_loop
Definition: ri.h:1471
#define instruction_tag(x)
Definition: ri.h:1511
#define instruction_forloop(x)
Definition: ri.h:1538
#define instruction_whileloop(x)
Definition: ri.h:1523
#define statement_comments(x)
Definition: ri.h:2456
#define statement_decls_text(x)
Definition: ri.h:2462
#define instruction_test(x)
Definition: ri.h:1517

References ADD_PRED_IF_NOT_ALREADY_HERE, add_proper_successor_to_predecessor(), CAR, check_control_coherency(), CONS, CONTROL, control_predecessors, control_statement, control_successors, control_undefined, control_undefined_p, controlize_call(), controlize_forloop(), controlize_list(), controlize_loop(), controlize_test(), controlize_whileloop(), display_linked_control_nodes(), ENDP, entity_name, fprintf(), gen_length(), get_label_control(), ifdebug, instruction_block, instruction_forloop, instruction_forloop_p, instruction_goto, instruction_loop, instruction_tag, instruction_test, instruction_whileloop, is_instruction_block, is_instruction_call, is_instruction_expression, is_instruction_forloop, is_instruction_goto, is_instruction_loop, is_instruction_multitest, is_instruction_test, is_instruction_unstructured, is_instruction_whileloop, link_2_control_nodes(), make_continue_statement(), NIL, pips_assert, pips_debug, pips_internal_error, pips_user_warning, print_entities(), return_instruction_p(), same_entity_p(), statement_comments, statement_consistent_p(), statement_declarations, statement_decls_text, statement_instruction, statement_label, statement_number, unlink_2_control_nodes(), UPDATE_CONTROL, and update_used_labels().

Referenced by control_graph(), controlize_forloop(), controlize_list_1(), controlize_loop(), controlize_test(), and controlize_whileloop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_call() [1/2]

static bool controlize_call ( control  c_res,
control  succ 
)
static

Controlize a call statement.

The deal is to correctly manage STOP; since we don't know how to do it yet, we assume this is a usual call with a continuation !

To avoid non-standard successors, IO statement with multiple continuations are not dealt with here. The END= and ERR= clauses are simulated by hidden tests.

Parameters
[in]c_resis the control node with a call statement to controlize
[in]succis the control node successor of c_res
Returns
false since we do nothing, so no non-structured graph generation yet...

Definition at line 2455 of file controlizer.c.

2457 {
2458  statement st = control_statement(c_res);
2459  pips_debug(5, "(st = %p, c_res = %p, succ = %p)\n",
2460  st, c_res, succ);
2461 
2462  return false;
2463 }

References control_statement, and pips_debug.

Referenced by controlize_statement().

+ Here is the caller graph for this function:

◆ controlize_call() [2/2]

static bool controlize_call ( statement  st,
control  pred,
control  succ,
control  c_res 
)
static

CONTROLIZE_CALL controlizes the call C of statement ST in C_RES.

The deal is to correctly manage STOP; since we don't know how to do it, so we assume this is a usual call with a continuation !!

To avoid non-standard successors, IO statement with multiple continuations are not dealt with here. The END= and ERR= clauses are simulated by hidden tests.

control_successors(pred) = ADD_SUCC(c_res, pred);

Definition at line 425 of file old_controlizer.c.

429 {
430  pips_debug(5, "(st = %p, pred = %p, succ = %p, c_res = %p)\n",
431  st, pred, succ, c_res);
432 
434  CONS(CONTROL, succ, NIL));
435 
436  /* control_successors(pred) = ADD_SUCC(c_res, pred); */
439  return(false);
440 }
#define ADD_PRED_AND_COPY_IF_NOT_ALREADY_HERE(pred, c)

References ADD_PRED_AND_COPY_IF_NOT_ALREADY_HERE, ADD_PRED_IF_NOT_ALREADY_HERE, add_proper_successor_to_predecessor(), CONS, CONTROL, control_predecessors, NIL, pips_debug, and UPDATE_CONTROL.

Referenced by controlize().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_forloop() [1/2]

static bool controlize_forloop ( control  c_res,
control  succ,
hash_table  used_labels 
)
static

Computes the control graph of a C for loop statement.

Parameters
[in,out]c_resis the entry control node with the for loop statement to controlize. If the for loop has complex control code such as some goto to outside, it is transformed into an equivalent control graph.
[in,out]succmust be the control node successor of c_res that will be the current end of the control node sequence and an exit node
[in,out]used_labelsis a hash table mapping a label name to a list of statements that use it, as their label or because it is a goto to it
Returns
true if the code is not a structured control.

To track the statement related to labels inside the loop body:

Remove the loop body from the loop just in case we want to prettyprint our work in progress:

Create a control node to host the loop body and insert it in the control graph:

We also insert a dummy node between the body and the exit that will be used for the incrementation because if the control body has goto to succ node, we will have trouble to insert it later:

TODO switch(get_prettyprint_language_tag()) { case is_language_fortran: case is_language_fortran95: cs = strdup(concatenate(prev_comm, get_comment_sentinel(), " DO loop ", lab, " with exit had to be desugared\n", NULL)); break; case is_language_c: cs = prev_comm; break; default: pips_internal_error("This language is not handled !"); break; }

Recurse by controlizing inside the loop:

First the easy way. We have a kindly control-localized loop body, revert to the original code

Remove the control node from the control graph by carefully relinking around:

Remove also the dummy increment node that has not been used either:

Move the loop body into its own loop:

We are in trouble since the loop body is not locally structured, there are goto from inside or outside the loop body. So we replace the do-loop with a desugared version with an equivalent control graph.

Update the increment control node with the real computation:

First remove the dummy statement added above:

And put "i = i + s" instead:

Now build the desugared loop:

We can replace the former loop statement by the new header. That means that all pragma, comment, extensions, label on the previous loop stay on this.

Add the continuation test between the header and the body that are already connected:

Detach the increment node from the loop exit

And reconnect it to the test node to make the loop:

Add the else branch of the test toward the loop exit:

Detach the succ node from the body node

We can remove

Keep track of labels that were used by the statements of the loop:

Definition at line 723 of file controlizer.c.

726 {
727  /* To track the statement related to labels inside the loop body: */
728  hash_table loop_used_labels = hash_table_make(hash_string, 0);
729  statement sl = control_statement(c_res);
730 
731  pips_debug(5, "(st = %p, c_res = %p, succ = %p)\n", sl, c_res, succ);
732 
733  forloop l = statement_forloop(sl);
734  statement body_s = forloop_body(l);
735 
736  /* Remove the loop body from the loop just in case we want to
737  prettyprint our work in progress: */
738  //loop_body(l) = statement_undefined;
740  /* Create a control node to host the loop body and insert it in the
741  control graph: */
742  control c_body = make_conditional_control(body_s);
743  insert_control_in_arc(c_body, c_res, succ);
744  /* We also insert a dummy node between the body and the exit that will
745  be used for the incrementation because if the control body has goto
746  to succ node, we will have trouble to insert it later: */
748  insert_control_in_arc(c_inc, c_body, succ);
749  /* TODO
750  switch(get_prettyprint_language_tag()) {
751  case is_language_fortran:
752  case is_language_fortran95:
753  cs = strdup(concatenate(prev_comm,
754  get_comment_sentinel(),
755  " DO loop ",
756  lab,
757  " with exit had to be desugared\n",
758  NULL));
759  break;
760  case is_language_c:
761  cs = prev_comm;
762  break;
763  default:
764  pips_internal_error("This language is not handled !");
765  break;
766  }
767  */
768  /* Recurse by controlizing inside the loop: */
769  // link_2_control_nodes(c_body, c_inc); already done by insert_control_in_arc
770  bool controlized = controlize_statement(c_body, c_inc, loop_used_labels);
771 
772  if (!controlized) {
773  /* First the easy way. We have a kindly control-localized loop body,
774  revert to the original code */
775  pips_debug(6, "Since we can keep the do-loop, remove the useless control node %p that was allocated for the loop_body.\n", c_body);
777  /* Remove the control node from the control graph by carefully
778  relinking around: */
780  /* Remove also the dummy increment node that has not been used
781  either: */
783  /* Move the loop body into its own loop: */
784  forloop_body(l) = body_s;
785  }
786  else {
787  /* We are in trouble since the loop body is not locally structured,
788  there are goto from inside or outside the loop body. So we
789  replace the do-loop with a desugared version with an equivalent
790  control graph. */
791  /* Update the increment control node with the real computation: */
792  /* First remove the dummy statement added above: */
794  /* And put "i = i + s" instead: */
796  /* Now build the desugared loop: */
797  /* We can replace the former loop statement by the new header. That
798  means that all pragma, comment, extensions, label on the previous
799  loop stay on this. */
801  /* Add the continuation test between the header and the body that are
802  already connected: */
804  insert_control_in_arc(c_test, c_res, c_body);
805  /* Detach the increment node from the loop exit */
806  unlink_2_control_nodes(c_inc, succ);
807  /* And reconnect it to the test node to make the loop: */
809  /* Add the else branch of the test toward the loop exit: */
810  // link_2_control_nodes(c_test, succ) does not support distinction
811  // between true and false branch as first and second successors
812  // FI: I hesitated to define a new loe level procedure in ri-util/control.c
814  CONS(CONTROL, succ, NIL));
816  CONS(CONTROL, c_test, NIL));
817  /* Detach the succ node from the body node */
818  //unlink_2_control_nodes(c_body, succ);
819  /* We can remove */
820  }
821 
822  /* Keep track of labels that were used by the statements of the loop: */
823  union_used_labels( used_labels, loop_used_labels);
824  hash_table_free(loop_used_labels);
825 
826  pips_debug(5, "Exiting\n");
827 
828  return controlized;
829 }
static string c_test(test t, bool breakable)
void insert_control_in_arc(control c, control before, control after)
Insert a control node between 2 connected control nodes.
Definition: control.c:1299
static control make_conditional_control(statement st)
In C, we can have some "goto" inside a block from outside, that translates as any complex control gra...
Definition: controlizer.c:173
bool controlize_statement(control c_res, control succ, hash_table used_labels)
Controlize a statement that is in a control node, that is restructure it to have a HCFG recursively (...
Definition: controlizer.c:2493
static hash_table union_used_labels(hash_table l1, hash_table l2)
Unions 2 hash maps that list statements referencing labels into one.
Definition: controlizer.c:270
statement unsugared_forloop_inc(statement sl)
Definition: controlizer.c:569
statement unsugared_forloop_header(statement sl)
Definition: controlizer.c:474
statement unsugared_forloop_test(statement sl)
Definition: controlizer.c:518
forloop statement_forloop(statement)
Get the forloop of a statement.
Definition: statement.c:1426
#define forloop_body(x)
Definition: ri.h:1372

References c_test(), CONS, CONTROL, control_predecessors, control_statement, control_successors, controlize_statement(), forloop_body, free_statement(), gen_nconc(), hash_string, hash_table_free(), hash_table_make(), insert_control_in_arc(), link_2_control_nodes(), make_conditional_control(), make_control(), make_plain_continue_statement(), NIL, pips_debug, remove_a_control_from_an_unstructured(), statement_forloop(), statement_undefined, union_used_labels(), unlink_2_control_nodes(), unsugared_forloop_header(), unsugared_forloop_inc(), and unsugared_forloop_test().

Referenced by controlize_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_forloop() [2/2]

static bool controlize_forloop ( statement  st,
forloop  l,
control  pred,
control  succ,
control  c_res,
hash_table  used_labels 
)
static

To avoid gcc warning about possible non-initialization

Try an unsafe conversion to a Fortran style DO loop: it assumes that the loop body does not define the loop index, but effects are not yet available when the controlizer is run.

If the DO conversion has failed, the WHILE conversion may be requested

As a sequence cannot carry comments, the for loop comments are moved to the while loop

These three fields have been re-used or freed by the previous call

Quite a lot of sharing between st and d_st

Since we may have replaced a statement that may have comments and labels by a sequence, do not forget to forward them where they can be:

The for loop cannot be preserved as a control structure

NN : I do not know how to deal with this, the following code does not always work

pips_internal_error("Forloop with goto not implemented yet");

control_successors(pred) = ADD_SUCC(c_res, pred);

Definition at line 822 of file old_controlizer.c.

828 {
829  hash_table loop_used_labels = hash_table_make(hash_string, 0);
833  bool controlized = false; /* To avoid gcc warning about possible
834  non-initialization */
835 
836  pips_debug(5, "(st = %p, pred = %p, succ = %p, c_res = %p)\n",
837  st, pred, succ, c_res);
838  ifdebug(1) {
840  }
841 
842  controlize(forloop_body(l), c_test, c_inc, c_body, loop_used_labels);
843 
844  ifdebug(1) {
846  }
847 
848  if (covers_labels_p(forloop_body(l),loop_used_labels)) {
850 
851  /* Try an unsafe conversion to a Fortran style DO loop: it assumes
852  that the loop body does not define the loop index, but effects are
853  not yet available when the controlizer is run. */
854  if(get_bool_property("FOR_TO_DO_LOOP_IN_CONTROLIZER")) {
855  forloop_body(l)= control_statement(c_body);
856  sequence new_l = for_to_do_loop_conversion(l,st);
857 
858  if(!sequence_undefined_p(new_l)) {
859  ni = make_instruction_sequence( new_l);
860  }
861  }
862 
863  /* If the DO conversion has failed, the WHILE conversion may be requested */
864  if(instruction_undefined_p(ni)) {
865  if(get_bool_property("FOR_TO_WHILE_LOOP_IN_CONTROLIZER")) {
866  /* As a sequence cannot carry comments, the for loop comments
867  are moved to the while loop */
871  control_statement(c_body),
873 
874  /* These three fields have been re-used or freed by the previous call */
878 
879  ni = make_instruction_sequence(wls);
880  }
881  else {
885  control_statement(c_body));
886 
887  ni = make_instruction_forloop(new_l);
888  }
889  }
890 
891  gen_remove(&control_successors(c_body), c_res);
892  gen_remove(&control_predecessors(c_body), c_res);
893  gen_remove(&control_predecessors(c_res), c_body);
894 
895  /* Quite a lot of sharing between st and d_st*/
896  st = normalize_statement(st);
898  statement_number(st),
901  ni,
905  ifdebug(1) {
908  }
909  /* Since we may have replaced a statement that may have comments and
910  labels by a sequence, do not forget to forward them where they can
911  be: */
913  ifdebug(1) {
915  }
916 
917  UPDATE_CONTROL(c_res,
918  d_st,
920  CONS(CONTROL, succ, NIL));
921  controlized = false;
923  }
924  else /* The for loop cannot be preserved as a control structure*/
925  {
926  /* NN : I do not know how to deal with this, the following code does not always work
927 
928  pips_internal_error("Forloop with goto not implemented yet");*/
929 
933  CONS(CONTROL, c_res, CONS(CONTROL, c_inc, NIL)),
935  CONS(CONTROL, succ, CONS(CONTROL, c_body, NIL));
937  control_statement(c_inc) = forloop_inc(st);
939  UPDATE_CONTROL(c_res,
940  forloop_header(st),
942  CONS(CONTROL, c_test, NIL));
943  controlized = true ;
945  }
947  /* control_successors(pred) = ADD_SUCC(c_res, pred); */
948 
950 
951  union_used_labels( used_labels, loop_used_labels);
952  hash_table_free(loop_used_labels);
953 
954  pips_debug(5, "Exiting\n");
955 
956  return(controlized);
957 }
instruction make_instruction_forloop(forloop _field_)
Definition: ri.c:1193
instruction make_instruction_sequence(sequence _field_)
Definition: ri.c:1169
extensions copy_extensions(extensions p)
EXTENSIONS.
Definition: ri.c:947
forloop make_forloop(expression a1, expression a2, expression a3, statement a4)
Definition: ri.c:1025
sequence for_to_do_loop_conversion(forloop, statement)
Try to convert a C-like for-loop into a Fortran-like do-loop.
sequence for_to_while_loop_conversion(expression, expression, expression, statement, extensions)
Build a sequence with a while-loop from for-loop parameters.
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
statement forloop_header(statement sl)
statement forloop_inc(statement sl)
statement forloop_test(statement sl)
void gen_remove(list *cpp, const void *o)
remove all occurences of item o from list *cpp, which is thus modified.
Definition: list.c:685
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
void fix_statement_attributes_if_sequence(statement)
Apply fix_sequence_statement_attributes() on the statement only if it really a sequence.
Definition: statement.c:2078
statement normalize_statement(statement)
Make (a bit more) sure that s is gen_defined_p in spite of poor decision for empty fields and that st...
Definition: statement.c:4035
#define true
Definition: newgen_types.h:81
static bool covers_labels_p(statement st, hash_table used_labels)
Compute whether all the label references in a statement are in a given label name to statement list m...
static hash_table union_used_labels(hash_table l1, hash_table l2)
Unions 2 used-label hash maps.
#define forloop_initialization(x)
Definition: ri.h:1366
#define forloop_increment(x)
Definition: ri.h:1370
#define instruction_undefined_p(x)
Definition: ri.h:1455
#define expression_undefined
Definition: ri.h:1223
#define forloop_condition(x)
Definition: ri.h:1368
#define sequence_undefined_p(x)
Definition: ri.h:2339
char * strdup()
return(s1)

References ADD_PRED_AND_COPY_IF_NOT_ALREADY_HERE, ADD_PRED_IF_NOT_ALREADY_HERE, add_proper_successor_to_predecessor(), c_test(), check_control_coherency(), CONS, CONTROL, control_predecessors, control_statement, control_successors, controlize(), copy_extensions(), covers_labels_p(), expression_undefined, fix_statement_attributes_if_sequence(), for_to_do_loop_conversion(), for_to_while_loop_conversion(), forloop_body, forloop_condition, forloop_header(), forloop_inc(), forloop_increment, forloop_initialization, forloop_test(), free_statement(), gen_copy_seq(), gen_remove(), get_bool_property(), hash_string, hash_table_free(), hash_table_make(), ifdebug, instruction_undefined, instruction_undefined_p, make_conditional_control(), make_control(), make_forloop(), make_instruction_forloop(), make_instruction_sequence(), make_plain_continue_statement(), make_statement(), make_synchronization_none(), NIL, normalize_statement(), pips_debug, sequence_undefined_p, statement_comments, statement_consistent_p(), statement_declarations, statement_decls_text, statement_extensions, statement_label, statement_number, STATEMENT_ORDERING_UNDEFINED, strdup(), true, union_used_labels(), and UPDATE_CONTROL.

Referenced by controlize().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_goto()

static bool controlize_goto ( control  c_res,
control  succ,
hash_table  used_labels 
)
static

Deal with "goto" when building the HCFG.

Parameters
[in,out]c_resis the control node with the "goto" statement (that is an empty one in the unstructured since the "goto" in the HCFG is an arc, no longer a statement) that will point to a new control node with the given label
[in,out]succis the control node successor of c_res. Except if it is also the target of the "goto" by chance, it will become unreachable.
[in,out]used_labelsis a hash table mapping a label name to a list of statements that use it, as their label or because they are a goto to it

Get the label name of the statement the goto points to:

Since the goto by itself is transformed into an arc in the control graph, the "goto" statement is no longer used. But some informations associated to the "goto" statement such as a comment or an extension must survive, so we keep them in a nop statement that will receive its attribute and will be the source arc representing the goto:

Disconnect the target statement:

Get the control node associated with the label we want to go to:

Since it is a goto just on the next statement, nothing to do and it is not unstructured. But st must no longer be associated to name in hash table Label_statements.

The goto target is somewhere else, so it is clearly unstructured:

Disconnect the nop from the successor:

And add the edge in place of the goto from c_res to n_succ:

Add st as locally related to this label name but do not add the target since it may be non local:

Definition at line 2362 of file controlizer.c.

2365 {
2366  bool controlized;
2367  statement st = control_statement(c_res);
2368  statement go_to = statement_goto(st);
2369  /* Get the label name of the statement the goto points to: */
2370  string name = entity_name(statement_label(go_to));
2371  /* Since the goto by itself is transformed into an arc in the control
2372  graph, the "goto" statement is no longer used. But some informations
2373  associated to the "goto" statement such as a comment or an extension
2374  must survive, so we keep them in a nop statement that will receive
2375  its attribute and will be the source arc representing the goto: */
2377  /* Disconnect the target statement: */
2379  free_instruction(i);
2381 
2382  /* Get the control node associated with the label we want to go to: */
2383  control n_succ = get_label_control(name);
2384 
2385  ifdebug(5) {
2386  pips_debug(5, "After freeing the goto, from c_res = %p:\n", c_res);
2388  check_control_coherency(c_res);
2389  pips_debug(5, "From n_succ = %p:\n", n_succ);
2391  check_control_coherency(n_succ);
2392  }
2393  if (succ == n_succ) {
2394  /* Since it is a goto just on the next statement, nothing to do and it
2395  is not unstructured. But st must no longer be associated to name
2396  in hash table Label_statements. */
2397  list sl = (list) hash_get_default_empty_list(Label_statements, (void *) name);
2398  if(gen_in_list_p((void *) st, sl)) {
2399  gen_remove(&sl, (void *) st);
2400  hash_update(Label_statements, (void *) name, (void *) sl);
2401  }
2402  else {
2403  pips_internal_error("Label %s associated to statement %p is not associated"
2404  " to statement %p in hash table Label_statements\n");
2405  }
2406  controlized = false;
2407  }
2408  else {
2409  /* The goto target is somewhere else, so it is clearly
2410  unstructured: */
2411  controlized = true;
2412  pips_debug(5, "Unstructured goto to label %s: control n_succ %p\n"
2413  "\tSo statement in control %p is now unreachable from this way\n",
2414  name, n_succ, succ);
2415  /* Disconnect the nop from the successor:*/
2416  unlink_2_control_nodes(c_res, succ);
2417  /* And add the edge in place of the goto from c_res to n_succ: */
2418  link_2_control_nodes(c_res, n_succ);
2419 
2420  /* Add st as locally related to this label name but do not add the
2421  target since it may be non local: */
2422  update_used_labels(used_labels, name, st);
2423 
2424  ifdebug(5) {
2425  pips_debug(5, "After freeing the goto, from c_res = %p:\n", c_res);
2427  check_control_coherency(c_res);
2428  pips_debug(5, "From n_succ = %p:\n", succ);
2431  }
2432  ifdebug(1)
2433  check_control_coherency(n_succ);
2434  }
2435  return controlized;
2436 }
void free_instruction(instruction p)
Definition: ri.c:1118
static void update_used_labels(hash_table used_labels, string name, statement st)
Mark a statement as related to a label.
Definition: controlizer.c:235
static control get_label_control(string name)
Get the control node associated to a label name.
Definition: controlizer.c:207
instruction make_continue_instruction()
Creates a CONTINUE instruction, that is the FORTRAN nop, the ";" in C or the "pass" in Python for exa...
Definition: instruction.c:79
statement statement_goto(statement)
Get the goto of a statement.
Definition: statement.c:1396
void hash_update(hash_table htp, const void *key, const void *val)
update key->val in htp, that MUST be pre-existent.
Definition: hash.c:491
list hash_get_default_empty_list(const hash_table h, const void *k)
Like hash_get() but returns an empty list instead of HASH_UNDEFINED_VALUE when a key is not found.
Definition: hash.c:475
struct cons * list
Definition: newgen_types.h:106

References check_control_coherency(), control_statement, display_linked_control_nodes(), entity_name, free_instruction(), gen_in_list_p(), gen_remove(), get_label_control(), hash_get_default_empty_list(), hash_update(), ifdebug, instruction_goto, Label_statements, link_2_control_nodes(), make_continue_instruction(), pips_debug, pips_internal_error, statement_goto(), statement_instruction, statement_label, statement_undefined, unlink_2_control_nodes(), and update_used_labels().

Referenced by controlize_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_list()

static bool controlize_list ( statement  st,
list  sts,
control  pred,
control  succ,
control  c_res,
hash_table  used_labels 
)
static

Computes in c_res the control graph of the list sts (of statement st) with pred predecessor and succ successor.

We try to minimize the number of graphs by looking for graphs with one node only and picking the statement in that case.

Returns
true if the code is not a structured control.

Empty statement list. It looks like from controlize() that we cannot be called with an empty statement list... So I guess this is dead code here. RK

Should be empty_comments ?

FI: the statement extension of st is lost

What happens to the declarations and comments attached to st?

Create a control node to hold what was the statement block, with the first statement in it:

Do the real transformation of a statement list into a control graph:

Compute if there are goto from/to the statements of the statement list:

We are in trouble since we will have an unstructured with goto from or to outside this statement sequence, but the statement sequence that define the scoping rules is going to disappear... So we gather all the declaration and push them up:

Since we have generated a big control graph from what could be a more structured statement block, try to restructure things a little bit, with c_last pointing to the last control node of the list:

To avoid compact list: c_last = c_end;

There is no GOTO to/from outside the statement list: hierarchize the control graph.

Unlink the c_block from the unstructured. RK.

c_block is a lonely control node:

PJ: fragile attempt at keeping local declarations and their scope

FI: Can't we remove the declarations in st? Why are they gen_copy_seq?

‍**it will add block for statement before add the extension

FI: no need to update declarations as the code is structured

The control is kept in an unstructured:

FI: So here you are putting declarations in an unstructured? No surprise we end up in trouble later.

Not a good idea from mine to add this free... RK free_statement(control_statement(c_res));

FI: when going down controlize list, these two nodes are already linked, and they are relinked unconditionnally by link_2_control_nodes() which does not check that its input assumption is met.

Update c_res to reflect c_block in fact:

We alredy have pred linked to c_block and the exit node linked to succ. RK

Definition at line 1358 of file old_controlizer.c.

1364 {
1365  hash_table block_used_labels = hash_table_make(hash_string, 0);
1366  control c_block = control_undefined;
1368  control c_last = c_end;
1369  list ctls;
1370  bool controlized;
1371  bool hierarchized_labels;
1372 
1373  ifdebug(1) {
1374  pips_debug(5, "Begin with (st = %p, pred = %p, succ = %p, c_res = %p)\n",
1375  st, pred, succ, c_res);
1376  ifdebug(8) {
1377  pips_debug(8, "\nControl nodes linked to pred = %p:\n", pred);
1379  pips_debug(8, "\n");
1380  }
1381 
1385  check_control_coherency(c_res);
1386  }
1387 
1388  if(ENDP(sts)) {
1389  /* Empty statement list. It looks like from controlize() that we
1390  cannot be called with an empty statement list... So I guess this
1391  is dead code here. RK */
1393  string dt
1395  strdup("")
1397  string ct = string_undefined_p(statement_comments(st))?
1398  string_undefined /* Should be empty_comments ? */
1399  : strdup(statement_comments(st));
1400 
1401  /* FI: the statement extension of st is lost */
1403  NIL, NIL);
1404  /*
1405  pips_assert("declarations are preserved in control",
1406  gen_length(statement_declarations(st))
1407  ==gen_length(statement_declarations(control_statement(c_block))));
1408  */
1409  }
1410  else {
1411  /* What happens to the declarations and comments attached to st? */
1412  /* Create a control node to hold what was the statement block, with
1413  the first statement in it: */
1414  c_block = make_conditional_control(STATEMENT(CAR(sts)));
1415  /*
1416  pips_assert("declarations are preserved in conditional control",
1417  gen_length(statement_declarations(st))
1418  ==gen_length(statement_declarations(control_statement(c_block))));
1419  */
1420  }
1421 
1422  ifdebug(1) {
1424  }
1425 
1426  /* Do the real transformation of a statement list into a control
1427  graph: */
1428  ctls = controlize_list_1(sts, pred, c_end, c_block, block_used_labels);
1429 
1430  /* Compute if there are goto from/to the statements of the statement
1431  list: */
1432  hierarchized_labels = covers_labels_p(st, block_used_labels);
1433 
1434  if (!hierarchized_labels) {
1435  /* We are in trouble since we will have an unstructured with goto
1436  from or to outside this statement sequence, but the statement
1437  sequence that define the scoping rules is going to disappear...
1438  So we gather all the declaration and push them up: */
1440  }
1441  /* Since we have generated a big control graph from what could be a
1442  more structured statement block, try to restructure things a little
1443  bit, with c_last pointing to the last control node of the list: */
1444  c_last = compact_list(ctls, c_end);
1445  /* To avoid compact list: c_last = c_end; */
1446  //c_last = c_end;
1447  gen_free_list(ctls);
1448  ifdebug(5) {
1449  pips_debug(5, "Nodes from c_block %p\n", c_block);
1451  pips_debug(5, "Nodes from c_last %p\n", c_last);
1453  }
1454  /*
1455  pips_assert("declarations are preserved in list",
1456  gen_length(statement_declarations(st))
1457  ==gen_length(statement_declarations(control_statement(c_block))));
1458  */
1459 
1460  if (hierarchized_labels) {
1461  /* There is no GOTO to/from outside the statement list:
1462  hierarchize the control graph. */
1463  statement new_st = statement_undefined;
1464 
1465  /* Unlink the c_block from the unstructured. RK. */
1466  unlink_2_control_nodes(pred, c_block);
1467  unlink_2_control_nodes(c_block, c_end);
1468 
1469  if(ENDP(control_predecessors(c_block)) &&
1470  ENDP(control_successors(c_block))) {
1471  /* c_block is a lonely control node: */
1472  new_st = control_statement(c_block);
1473 
1474  ///* FI: fragile attempt at keeping local declarations and their scope */
1475  ///* Does not work when st has been changed... */
1476  //if(/*!statement_block_p(new_st) &&*/ !ENDP(statement_declarations(st))) {
1477  // /* new_st = st*/;
1478  //}
1479 
1480  /* PJ: fragile attempt at keeping local declarations and their scope */
1481  ifdebug(1) {
1483  }
1484  if(!ENDP(statement_declarations(st))) {
1485  pips_assert("the declarations are carried by a block",
1486  statement_block_p(st));
1487  ifdebug(8) {
1488  pips_debug(8, "Block declarations to copy: ");
1490  pips_debug(8, "End of declarations.\n");
1491  }
1492  if(statement_block_p(new_st)) {
1493  if(ENDP(statement_declarations(new_st))) {
1494  statement_declarations(new_st) =
1496  }
1497  else {
1498  new_st = make_block_statement(CONS(STATEMENT, new_st, NIL));
1499  statement_declarations(new_st) =
1501  }
1502  }
1503  else {
1504  new_st = make_block_statement(CONS(STATEMENT, new_st, NIL));
1505  statement_declarations(new_st) =
1507  }
1508  /* FI: Can't we remove the declarations in st? Why are
1509  they gen_copy_seq? */
1510  }
1512  ///* it will add block for statement before add the extension
1513  // * ie, statement* -> { statement* }
1514  // * not need in fact,
1515  // * either block is already present, so no need to add
1516  // * or block are useless, so no need to add
1517  // */
1518  //if (!instruction_block_p(statement_instruction(new_st))
1519  // && instruction_block_p(statement_instruction(st))
1520  // ) {
1521  // new_st = make_block_statement(CONS(STATEMENT, new_st, NIL));
1522  //}
1524  }
1525 
1527  free_control(c_block);
1528 
1529  /* FI: no need to update declarations as the code is structured */
1530  ifdebug(1) {
1532  }
1533  }
1534  else {
1535  /* The control is kept in an unstructured: */
1536  unstructured u = make_unstructured(c_block, c_last);
1537  instruction i =
1539 
1540  ifdebug(1) {
1543  }
1544  /* FI: So here you are putting declarations in an
1545  unstructured? No surprise we end up in trouble
1546  later. */
1547  st = normalize_statement(st);
1548  if(ENDP(statement_declarations(st))) {
1550  statement_number(st),
1553  i,
1557  }
1558  else {
1559  statement us =
1561  statement_number(st),
1564  i,
1565  NIL,
1566  strdup(""),
1568  new_st =
1572  empty_comments);
1574  statement_instruction(new_st) =
1576  }
1577  }
1578 
1579  /* Not a good idea from mine to add this free... RK
1580  free_statement(control_statement(c_res)); */
1581 
1582  control_statement(c_res) = new_st;
1583 
1584  /* FI: when going down controlize list, these two nodes are
1585  already linked, and they are relinked unconditionnally by
1586  link_2_control_nodes() which does not check that its input
1587  assumption is met. */
1588  unlink_2_control_nodes(pred, c_res);
1589 
1590  link_2_control_nodes(pred, c_res);
1591  link_2_control_nodes(c_res, succ);
1592  controlized = false;
1593  }
1594  else {
1595  pips_debug(2, "There are goto to/from outside this statement list\n");
1596  /* Update c_res to reflect c_block in fact: */
1597  /* We alredy have pred linked to c_block and the exit node
1598  linked to succ. RK */
1599  UPDATE_CONTROL(c_res,
1600  control_statement(c_block),
1602  control_successors(c_block));
1604  control_successors(c_end) = CONS(CONTROL, succ, NIL);
1605  patch_references(PREDS_OF_SUCCS, c_block, c_res);
1606  patch_references(SUCCS_OF_PREDS, c_block, c_res);
1607  controlized = true;
1608  /*
1609  pips_assert("declarations are preserved",
1610  gen_length(statement_declarations(st))
1611  ==gen_length(statement_declarations(control_statement(c_res))));
1612  */
1613  }
1614 
1615  ifdebug(1) {
1617  }
1618 
1619  union_used_labels(used_labels, block_used_labels);
1620 
1621  hash_table_free(block_used_labels);
1622 
1623  pips_debug(5, "Exiting with controlized = %s\n",
1624  bool_to_string(controlized));
1625  ifdebug(1) {
1626  ifdebug(8) {
1627  pips_debug(8, "\nNodes linked to pred %p\n", pred);
1629  pips_debug(8, "\n");
1630  }
1633  check_control_coherency(c_res);
1634  /*
1635  pips_assert("declarations are preserved",
1636  gen_length(statement_declarations(st))
1637  ==gen_length(statement_declarations(control_statement(c_res))));
1638  */
1639 
1641  }
1642  return(controlized);
1643 }
unstructured make_unstructured(control a1, control a2)
Definition: ri.c:2778
void free_control(control p)
Definition: ri.c:490
instruction make_instruction(enum instruction_utype tag, void *val)
Definition: ri.c:1166
statement make_block_statement(list)
Make a block statement from a list of statement.
Definition: statement.c:616
statement make_empty_statement_with_declarations_and_comments(list, string, string)
Build an empty statement with declaration list, declaration text and comment.
Definition: statement.c:638
#define PREDS_OF_SUCCS
static control compact_list(list ctls, control c_end)
Take a list of controls ctls coming from a controlize_list() and compact the successive statements,...
static list controlize_list_1(list sts, control i_pred, control i_succ, control i_c_res, hash_table used_labels)
Do the equivalent of a mapcar of controlize on statement list sts.
#define SUCCS_OF_PREDS
static void patch_references(int how, control fnode, control tnode)
PATCH_REFERENCES replaces all occurrences of FNODE by TNODE in the predecessors or successors lists o...
list gen_full_copy_list(list l)
Copy a list structure with element copy.
Definition: list.c:535
string bool_to_string(bool)
Definition: string.c:243
#define string_undefined_p(s)
Definition: newgen_types.h:41
static void move_declaration_control_node_declarations_to_statement(list ctls)
Move all the declarations found in a list of control to a given statement.
#define empty_comments
Empty comments (i.e.
#define extensions_undefined_p(x)
Definition: ri.h:1309
#define extensions_extension(x)
Definition: ri.h:1330

References ADD_PRED_IF_NOT_ALREADY_HERE, bool_to_string(), CAR, check_control_coherency(), compact_list(), CONS, CONTROL, control_predecessors, control_statement, control_successors, control_undefined, controlize_list_1(), copy_extensions(), covers_labels_p(), display_linked_control_nodes(), empty_comments, empty_extensions(), empty_extensions_p(), ENDP, entity_empty_label(), extensions_extension, extensions_undefined_p, free_control(), gen_copy_seq(), gen_free_list(), gen_full_copy_list(), hash_string, hash_table_free(), hash_table_make(), ifdebug, is_instruction_unstructured, link_2_control_nodes(), make_block_statement(), make_conditional_control(), make_control(), make_empty_statement_with_declarations_and_comments(), make_instruction(), make_instruction_block(), make_plain_continue_statement(), make_statement(), make_synchronization_none(), make_unstructured(), move_declaration_control_node_declarations_to_statement(), NIL, normalize_statement(), patch_references(), pips_assert, pips_debug, PREDS_OF_SUCCS, print_entities(), STATEMENT, statement_block_p, statement_comments, statement_consistent_p(), statement_declarations, statement_decls_text, statement_extensions, statement_instruction, statement_number, STATEMENT_ORDERING_UNDEFINED, statement_undefined, strdup(), string_undefined, string_undefined_p, SUCCS_OF_PREDS, union_used_labels(), unlink_2_control_nodes(), unstructured_control, unstructured_exit, and UPDATE_CONTROL.

Referenced by controlize().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_list_1()

static list controlize_list_1 ( list  sts,
control  i_pred,
control  i_succ,
control  i_c_res,
hash_table  used_labels 
)
static

Do the equivalent of a mapcar of controlize on statement list sts.

The trick is to keep a list of the controls to compact them later. Note that if a statement is controlized, then the predecessor has to be computed (i.e. is not the previous control of sts); this is the purpose of c_in.

This function used to update its formal parameters pred and c_res, which makes stack visualization and debugging difficult.

The list of all the control nodes associated to this statement list:

On all the statement list:

Create a control node for the successor of this statement if not the last one:

Controlize the current statement:

Keep track of the control node associated to this statement:

Keep track globally of the unreachable code:

ifdebug(2) {

pips_debug(2, "There is a new unreachable statement:\n");

print_statement(st);

}

The previous controlize() returned a non structured control

Insert c_in as a predecessor of c_next

RK: I do not understand why this is needed...

If the next control node is unreachable, it will not be connected to the previous predecessor, so allocate a new one so that it has a predecessor that is completely unconnected of previous control graph.

The next control node is the control node of the next statement:

The consistency check should be applied to all elements in ctls. Let's hope all controls in ctls are linked one way or the other.

Since we built the list in reverse order to have a O(n) construction:

Definition at line 1243 of file old_controlizer.c.

1247  {
1248  /* The list of all the control nodes associated to this statement
1249  list: */
1250  list ctls = NIL;
1251  control pred = i_pred;
1252  control succ = i_succ;
1253  control c_res = i_c_res;
1254 
1255  /* On all the statement list: */
1256  for(; !ENDP(sts); sts = CDR(sts)) {
1257  statement st = STATEMENT(CAR(sts));
1258  /* Create a control node for the successor of this statement if
1259  not the last one: */
1260  control c_next = ENDP(CDR(sts)) ? succ :
1262  bool controlized;
1263  bool unreachable;
1264 
1265  ifdebug(5) {
1266  pips_debug(5, "Nodes linked with pred %p:\n", pred);
1268  }
1269 
1270  ifdebug(1) {
1273  check_control_coherency(c_next);
1274  check_control_coherency(c_res);
1275  }
1276 
1277  /* Controlize the current statement: */
1278  controlized = controlize(st, pred, c_next, c_res, used_labels);
1279  unreachable = ENDP(control_predecessors(c_next));
1280 
1281  /* Keep track of the control node associated to this statement: */
1282  ctls = CONS(CONTROL, c_res, ctls);
1283 
1284  if (unreachable) {
1285  /* Keep track globally of the unreachable code: */
1287  /* ifdebug(2) { */
1288  /* pips_debug(2, "There is a new unreachable statement:\n"); */
1289  /* print_statement(st); */
1290  /* } */
1291  }
1292 
1293  if (controlized) {
1294  /* The previous controlize() returned a non structured control */
1296 
1297  ctls = CONS(CONTROL, c_in, ctls);
1298  /* Insert c_in as a predecessor of c_next
1299 
1300  RK: I do not understand why this is needed...
1301  */
1303  control_successors(c_in) = CONS(CONTROL, c_next, NIL);
1305  control_predecessors(c_next) = CONS(CONTROL, c_in, NIL) ;
1306  pred = c_in;
1307  }
1308  else {
1309  /* If the next control node is unreachable, it will not be
1310  connected to the previous predecessor, so allocate a new one
1311  so that it has a predecessor that is completely unconnected of
1312  previous control graph. */
1313  pred = (unreachable) ?
1315  c_res;
1316  }
1317  /* The next control node is the control node of the next
1318  statement: */
1319  c_res = c_next ;
1320  }
1321 
1322  ifdebug(1) {
1323  /* The consistency check should be applied to all elements in
1324  ctls. Let's hope all controls in ctls are linked one way or
1325  the other. */
1326  control c = CONTROL(CAR(ctls));
1327  pips_debug(5, "Nodes from c %p\n", c);
1330 
1333  check_control_coherency(c_res);
1334  pips_debug(5, "(pred = %p, succ = %p, c_res = %p)\n",
1335  pred, succ, c_res);
1336  pips_debug(5, "Nodes from pred %p\n", pred);
1338  pips_debug(5, "Nodes from succ %p\n", succ);
1340  pips_debug(5, "Nodes from c_res %p\n", c_res);
1342  }
1343 
1344  /* Since we built the list in reverse order to have a O(n)
1345  construction: */
1346  return gen_nreverse(ctls);
1347 }
FILE * c_in
Definition: c_syntax.h:291
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304

References c_in, CAR, CDR, check_control_coherency(), CONS, CONTROL, control_predecessors, control_successors, controlize(), display_linked_control_nodes(), ENDP, gen_nreverse(), ifdebug, make_conditional_control(), make_control(), make_plain_continue_statement(), NIL, patch_references(), pips_debug, STATEMENT, SUCCS_OF_PREDS, and Unreachable.

Referenced by controlize_list().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_loop() [1/2]

static bool controlize_loop ( control  c_res,
control  succ,
hash_table  used_labels 
)
static

Computes the control graph of a Fortran do-loop statement.

Parameters
[in,out]c_resis the entry control node with the do-loop statement to controlize. If the do-loop has complex control code such as some goto to outside, it is transformed into an equivalent control graph.
[in,out]succmust be the control node successor of c_res that will be the current end of the control node sequence and an exit node
[in,out]used_labelsis a hash table mapping a label name to a list of statements that use it, as their label or because it is a goto to it
Returns
true if the code is not a structured control.

To track the statement related to labels inside the loop body:

Remove the loop body from the loop just in case we want to prettyprint our work in progress:

Create a control node to host the loop body and insert it in the control graph:

We also insert a dummy node between the body and the exit that will be used for the incrementation because if the control body has goto to succ node, we will have trouble to insert it later:

TODO switch(get_prettyprint_language_tag()) { case is_language_fortran: case is_language_fortran95: cs = strdup(concatenate(prev_comm, get_comment_sentinel(), " DO loop ", lab, " with exit had to be desugared\n", NULL)); break; case is_language_c: cs = prev_comm; break; default: pips_internal_error("This language is not handled !"); break; }

Recurse by controlizing inside the loop:

First the easy way. We have a kindly control-localized loop body, revert to the original code

Remove the control node from the control graph by carefully relinking around:

Remove also the dummy increment node that has not been used either:

Move the loop body into its own loop:

We are in trouble since the loop body is not locally structured, there are goto from inside or outside the loop body. So we replace the do-loop with a desugared version with an equivalent control graph.

Update the increment control node with the real computation:

First remove the dummy statement added above:

And put "i = i + s" instead:

Now build the desugared loop:

We can replace the former loop statement by the new header. That means that all pragma, comment, extensions, label on the previous loop stay on this.

Add the continuation test between the header and the body that are already connected:

Detach the increment node from the loop exit

And reconnect it to the test node to make the loop:

Add the else branch of the test toward the loop exit:

Detach the succ node from the body node

We can remove

Keep track of labels that were used by the statements of the loop:

Definition at line 597 of file controlizer.c.

600 {
601  /* To track the statement related to labels inside the loop body: */
602  hash_table loop_used_labels = hash_table_make(hash_string, 0);
603  statement sl = control_statement(c_res);
604 
605  pips_debug(5, "(st = %p, c_res = %p, succ = %p)\n", sl, c_res, succ);
606 
607  loop l = statement_loop(sl);
608  statement body_s = loop_body(l);
609 
610  /* Remove the loop body from the loop just in case we want to
611  prettyprint our work in progress: */
612  //loop_body(l) = statement_undefined;
614  /* Create a control node to host the loop body and insert it in the
615  control graph: */
616  control c_body = make_conditional_control(body_s);
617  insert_control_in_arc(c_body, c_res, succ);
618  /* We also insert a dummy node between the body and the exit that will
619  be used for the incrementation because if the control body has goto
620  to succ node, we will have trouble to insert it later: */
622  insert_control_in_arc(c_inc, c_body, succ);
623  /* TODO
624  switch(get_prettyprint_language_tag()) {
625  case is_language_fortran:
626  case is_language_fortran95:
627  cs = strdup(concatenate(prev_comm,
628  get_comment_sentinel(),
629  " DO loop ",
630  lab,
631  " with exit had to be desugared\n",
632  NULL));
633  break;
634  case is_language_c:
635  cs = prev_comm;
636  break;
637  default:
638  pips_internal_error("This language is not handled !");
639  break;
640  }
641  */
642  /* Recurse by controlizing inside the loop: */
643  // FI: this seems redundant with the above call to insert_control_in_arc()
644  //link_2_control_nodes(c_body, c_inc);
645  bool controlized = controlize_statement(c_body, c_inc, loop_used_labels);
646 
647  if (!controlized) {
648  /* First the easy way. We have a kindly control-localized loop body,
649  revert to the original code */
650  pips_debug(6, "Since we can keep the do-loop, remove the useless control node %p that was allocated for the loop_body.\n", c_body);
652  /* Remove the control node from the control graph by carefully
653  relinking around: */
655  /* Remove also the dummy increment node that has not been used
656  either: */
658  /* Move the loop body into its own loop: */
659  loop_body(l) = body_s;
660  }
661  else {
662  /* We are in trouble since the loop body is not locally structured,
663  there are goto from inside or outside the loop body. So we
664  replace the do-loop with a desugared version with an equivalent
665  control graph. */
666  /* Update the increment control node with the real computation: */
667  /* First remove the dummy statement added above: */
669  /* And put "i = i + s" instead: */
671  /* Now build the desugared loop: */
672  /* We can replace the former loop statement by the new header. That
673  means that all pragma, comment, extensions, label on the previous
674  loop stay on this. */
676  /* Add the continuation test between the header and the body that are
677  already connected: */
679  insert_control_in_arc(c_test, c_res, c_body);
680  /* Detach the increment node from the loop exit */
681  unlink_2_control_nodes(c_inc, succ);
682  /* And reconnect it to the test node to make the loop: */
684  /* Add the else branch of the test toward the loop exit: */
685  // FI: try to get the true and false successors at the right location...
686  // link_2_control_nodes(c_test, succ);
687  //control_successors(c_test) = gen_nconc(control_successors(c_test),
688  // CONS(CONTROL, succ, NIL));
689  //control_successors(c_test) = gen_nreverse(control_successors(c_test));
692  CONS(CONTROL, c_test, NIL));
693  /* Detach the succ node from the body node */
694  //unlink_2_control_nodes(c_body, succ);
695  /* We can remove */
696  }
697 
698  /* Keep track of labels that were used by the statements of the loop: */
699  union_used_labels( used_labels, loop_used_labels);
700  hash_table_free(loop_used_labels);
701 
702  pips_debug(5, "Exiting\n");
703 
704  return controlized;
705 }
statement unsugared_loop_inc(statement sl)
Do an index increment instruction for do-loop unsugaring.
Definition: controlizer.c:554
statement unsugared_loop_test(statement sl)
Do a crude test of end of do-loop for do-loop unsugaring.
Definition: controlizer.c:502
statement unsugared_loop_header(statement sl)
LOOP_HEADER, LOOP_TEST and LOOP_INC build the desugaring phases of a do-loop L for the loop header (i...
Definition: controlizer.c:463
loop statement_loop(statement)
Get the loop of a statement.
Definition: statement.c:1374
#define loop_body(x)
Definition: ri.h:1644

References c_test(), CONS, CONTROL, control_predecessors, control_statement, control_successors, controlize_statement(), free_statement(), gen_nconc(), hash_string, hash_table_free(), hash_table_make(), insert_control_in_arc(), link_2_control_nodes(), loop_body, make_conditional_control(), make_control(), make_plain_continue_statement(), NIL, pips_debug, remove_a_control_from_an_unstructured(), statement_loop(), statement_undefined, union_used_labels(), unlink_2_control_nodes(), unsugared_loop_header(), unsugared_loop_inc(), and unsugared_loop_test().

Referenced by controlize_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_loop() [2/2]

static bool controlize_loop ( statement  st,
loop  l,
control  pred,
control  succ,
control  c_res,
hash_table  used_labels 
)
static

CONTROLIZE_LOOP computes in C_RES the control graph of the loop L (of statement ST) with PREDecessor and SUCCessor.

control_successors(pred) = ADD_SUCC(c_res, pred);

Definition at line 536 of file old_controlizer.c.

542 {
543  hash_table loop_used_labels = hash_table_make(hash_string, 0);
547  bool controlized;
548 
549  pips_debug(5, "(st = %p, pred = %p, succ = %p, c_res = %p)\n",
550  st, pred, succ, c_res);
551 
552  controlize(loop_body(l), c_test, c_inc, c_body, loop_used_labels);
553 
554  if(covers_labels_p(loop_body(l),loop_used_labels)) {
555  loop new_l = make_loop(loop_index(l),
556  loop_range(l),
557  control_statement(c_body),
558  loop_label(l),
559  loop_execution(l),
560  loop_locals(l));
561 
562  st = normalize_statement(st);
563  UPDATE_CONTROL(c_res,
565  statement_number(st),
567  statement_comments(st),
573  CONS(CONTROL, succ, NIL)) ;
574  controlized = false;
576  }
577  else {
580  CONS(CONTROL, c_res, CONS(CONTROL, c_inc, NIL)),
582  CONS(CONTROL, succ, CONS(CONTROL, c_body, NIL));
583  control_statement(c_inc) = loop_inc(st);
585  UPDATE_CONTROL(c_res,
586  loop_header(st),
588  CONS(CONTROL, c_test, NIL));
589  controlized = true ;
591  }
593  /* control_successors(pred) = ADD_SUCC(c_res, pred); */
594 
595  union_used_labels( used_labels, loop_used_labels);
596  hash_table_free(loop_used_labels);
597 
598  pips_debug(5, "Exiting\n");
599 
600  return(controlized);
601 }
loop make_loop(entity a1, range a2, statement a3, entity a4, execution a5, list a6)
Definition: ri.c:1301
statement loop_header(statement sl)
LOOP_HEADER, LOOP_TEST and LOOP_INC build the desugaring phases of a do-loop L for the loop header (i...
statement loop_test(statement sl)
statement loop_inc(statement sl)
#define loop_execution(x)
Definition: ri.h:1648
#define loop_label(x)
Definition: ri.h:1646
#define loop_locals(x)
Definition: ri.h:1650
#define loop_range(x)
Definition: ri.h:1642
#define loop_index(x)
Definition: ri.h:1640

References ADD_PRED_AND_COPY_IF_NOT_ALREADY_HERE, ADD_PRED_IF_NOT_ALREADY_HERE, add_proper_successor_to_predecessor(), c_test(), CONS, CONTROL, control_predecessors, control_statement, control_successors, controlize(), copy_extensions(), covers_labels_p(), gen_copy_seq(), hash_string, hash_table_free(), hash_table_make(), is_instruction_loop, loop_body, loop_execution, loop_header(), loop_inc(), loop_index, loop_label, loop_locals, loop_range, loop_test(), make_conditional_control(), make_control(), make_instruction(), make_loop(), make_plain_continue_statement(), make_statement(), make_synchronization_none(), NIL, normalize_statement(), pips_debug, statement_comments, statement_declarations, statement_decls_text, statement_extensions, statement_label, statement_number, STATEMENT_ORDERING_UNDEFINED, strdup(), true, union_used_labels(), and UPDATE_CONTROL.

Referenced by controlize().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_repeatloop()

static bool controlize_repeatloop ( control  c_res,
control  succ,
hash_table  used_labels 
)
static

Computes the control graph of a C repeat until loop statement.

Parameters
[in,out]c_resis the entry control node with the do-loop statement to controlize. If the do-loop has complex control code such as some goto to outside, it is transformed into an equivalent control graph.
[in,out]succmust be the control node successor of c_res that will be the current end of the control node sequence and an exit node
[in,out]used_labelsis a hash table mapping a label name to a list of statements that use it, as their label or because it is a goto to it
Returns
true if the code is not a structured control.

To track the statement related to labels inside the loop body:

Remove the loop body from the loop just in case we want to prettyprint our work in progress:

Create a control node to host the loop body and insert it in the control graph:

We also insert a dummy node between the body and the exit that will be used for the incrementation because if the control body has goto to succ node, we will have trouble to insert it later:

TODO switch(get_prettyprint_language_tag()) { case is_language_fortran: case is_language_fortran95: cs = strdup(concatenate(prev_comm, get_comment_sentinel(), " DO loop ", lab, " with exit had to be desugared\n", NULL)); break; case is_language_c: cs = prev_comm; break; default: pips_internal_error("This language is not handled !"); break; }

Recurse by controlizing inside the loop:

First the easy way. We have a kindly control-localized loop body, revert to the original code

Remove the control node from the control graph by carefully relinking around:

Remove also the dummy increment node that has not been used either:

Move the loop body into its own loop:

We are in trouble since the loop body is not locally structured, there are goto from inside or outside the loop body. So we replace the do-loop with a desugared version with an equivalent control graph.

Update the increment control node with the real computation:

First remove the dummy statement added above:

And put "i = i + s" instead:

Now build the desugared loop:

We can replace the former loop statement by the new header. That means that all pragma, comment, extensions, label on the previous loop stay on this.

Add the continuation test between the header and the body that are already connected:

Detach the increment node from the loop exit

And reconnect it to the test node to make the loop:

Add the else branch of the test toward the loop exit:

We can remove

Add the else branch of the test toward the loop exit: arc ordering matters

Keep track of labels that were used by the statements of the loop:

Definition at line 990 of file controlizer.c.

993 {
994  /* To track the statement related to labels inside the loop body: */
995  hash_table loop_used_labels = hash_table_make(hash_string, 0);
996  statement sl = control_statement(c_res);
997 
998  pips_debug(5, "(st = %p, c_res = %p, succ = %p)\n", sl, c_res, succ);
999 
1000  whileloop wl = statement_whileloop(sl);
1001  statement body_s = whileloop_body(wl);
1002 
1003  /* Remove the loop body from the loop just in case we want to
1004  prettyprint our work in progress: */
1006  /* Create a control node to host the loop body and insert it in the
1007  control graph: */
1008  control c_body = make_conditional_control(body_s);
1009  //insert_control_in_arc(c_body, c_res, succ);
1010  /* We also insert a dummy node between the body and the exit that will
1011  be used for the incrementation because if the control body has goto
1012  to succ node, we will have trouble to insert it later: */
1013  //control c_inc = make_control(make_plain_continue_statement(), NIL, NIL);
1014  //insert_control_in_arc(c_inc, c_body, succ);
1015  /* TODO
1016  switch(get_prettyprint_language_tag()) {
1017  case is_language_fortran:
1018  case is_language_fortran95:
1019  cs = strdup(concatenate(prev_comm,
1020  get_comment_sentinel(),
1021  " DO loop ",
1022  lab,
1023  " with exit had to be desugared\n",
1024  NULL));
1025  break;
1026  case is_language_c:
1027  cs = prev_comm;
1028  break;
1029  default:
1030  pips_internal_error("This language is not handled !");
1031  break;
1032  }
1033  */
1035  /* Recurse by controlizing inside the loop: */
1036  link_2_control_nodes(c_body, c_test);
1037  bool controlized = controlize_statement(c_body, c_test, loop_used_labels);
1038 
1039  if (!controlized) {
1040  /* First the easy way. We have a kindly control-localized loop body,
1041  revert to the original code */
1042  pips_debug(6, "Since we can keep the do-loop, remove the useless control node %p that was allocated for the loop_body.\n", c_body);
1044  /* Remove the control node from the control graph by carefully
1045  relinking around: */
1047  /* Remove also the dummy increment node that has not been used
1048  either: */
1049  //remove_a_control_from_an_unstructured(c_inc);
1050  /* Move the loop body into its own loop: */
1051  whileloop_body(wl) = body_s;
1052  }
1053  else {
1054  /* We are in trouble since the loop body is not locally structured,
1055  there are goto from inside or outside the loop body. So we
1056  replace the do-loop with a desugared version with an equivalent
1057  control graph. */
1058  /* Update the increment control node with the real computation: */
1059  /* First remove the dummy statement added above: */
1060  //free_statement(control_statement(c_inc));
1061  /* And put "i = i + s" instead: */
1062  //control_statement(c_inc) = unsugared_loop_inc(sl);
1063  /* Now build the desugared loop: */
1064  /* We can replace the former loop statement by the new header. That
1065  means that all pragma, comment, extensions, label on the previous
1066  loop stay on this. */
1068  /* Add the continuation test between the header and the body that are
1069  already connected: */
1070  //control c_test = make_control(unsugared_loop_test(sl), NIL, NIL);
1071  // insert_control_in_arc(c_test, c_res, c_body);
1072  /* Detach the increment node from the loop exit */
1073  //unlink_2_control_nodes(c_inc, succ);
1074  /* And reconnect it to the test node to make the loop: */
1075  //link_2_control_nodes(c_inc, c_test);
1076  //link_2_control_nodes(c_body, c_test);
1077  //link_2_control_nodes(c_test, c_res);
1078  /* Add the else branch of the test toward the loop exit: */
1079  //link_2_control_nodes(c_test, succ);
1080  /* We can remove */
1081  unlink_2_control_nodes(c_res, succ);
1082  link_2_control_nodes(c_res, c_body);
1083  /* Add the else branch of the test toward the loop exit: arc
1084  ordering matters */
1085  unlink_2_control_nodes(c_test, c_body);
1086  //link_2_control_nodes(c_test, succ);
1087  //link_2_control_nodes(c_test, c_body);
1088  link_3_control_nodes(c_test, c_body, succ);
1089 
1090  pips_assert("c_test is a test with two successors",
1093  pips_assert("c_body may have two successors if it is a test",
1094  ( gen_length(control_successors(c_body))==2
1095  && statement_test_p(control_statement(c_body)) )
1096  ||
1097  ( gen_length(control_successors(c_body))==1
1098  && !statement_test_p(control_statement(c_body)) )
1099  );
1100  pips_assert("c_res should not be a test",
1101  gen_length(control_successors(c_res))==1
1102  && !statement_test_p(control_statement(c_res)) );
1103  }
1104 
1105  /* Keep track of labels that were used by the statements of the loop: */
1106  union_used_labels( used_labels, loop_used_labels);
1107  hash_table_free(loop_used_labels);
1108 
1109  pips_debug(5, "Exiting\n");
1110 
1111  return controlized;
1112 }
void link_3_control_nodes(control c_test, control c_then, control c_else)
Add an edge between 2 control nodes.
Definition: control.c:1249
statement unsugared_whileloop_test(statement sl)
Definition: controlizer.c:531
statement unsugared_whileloop_header(statement sl __attribute__((__unused__)))
Definition: controlizer.c:484
whileloop statement_whileloop(statement)
Get the whileloop of a statement.
Definition: statement.c:1383
#define whileloop_body(x)
Definition: ri.h:3162

References c_test(), control_statement, control_successors, controlize_statement(), gen_length(), hash_string, hash_table_free(), hash_table_make(), link_2_control_nodes(), link_3_control_nodes(), make_conditional_control(), make_control(), make_plain_continue_statement(), NIL, pips_assert, pips_debug, remove_a_control_from_an_unstructured(), statement_test_p(), statement_undefined, statement_whileloop(), union_used_labels(), unlink_2_control_nodes(), unsugared_whileloop_header(), unsugared_whileloop_test(), and whileloop_body.

Referenced by controlize_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_sequence()

static bool controlize_sequence ( control  c_res,
control  succ,
hash_table  used_labels 
)
static

Computes the control graph of a sequence statement.

We try to minimize the number of graphs by looking for graphs with one node only and picking the statement in that case.

Parameters
[in,out]c_resis the entry control node with the sequence statement to controlize. It may be at exit the entry control node of a potential unstructured
[in,out]succmust be the control node successor of c_res that will be the current end of the control node sequence and an exit node
[in,out]used_labelsis a hash table mapping a label name to a list of statements that use it, as their label or because it is a goto to it
Returns
true if the code is not a structured control, i.e. it has to be "controlized", i.e. transformed into an "unstructured".

Also, side effect on hash table Label_statements if ever a goto is replaced by a continue because it points to the very next statement, via an indirect call to controlize_goto().

To see if the control graph will stay local or not:

A C block may have a label and even goto from outside on it.

To track variable scoping, track this statement

Get the list of statements in the block statement:

The list of all the control nodes associated to this statement list:

To track where to insert the current control node of a sequence element:

We first transform a structured block of statement in a thread of control node with all the statements that we insert from c_res up to succ:

Create a new control node for this statement, or retrieve one if it as a label:

Keep track of the control node associated to this statement. Note that the list is built in reverse order:

The next control node will be inserted after the new created node:

Now do the real controlizer job on the previously inserted thread of control nodes.

Note that we iterate in the reverse order of the statements since the control list was built up in reverse order. Indeed doing this in reverse order is simpler to write with this "next" stuff because we already have the current element and the successor "succ".

Recurse on each statement: controlized has been initialized to false

The currently processed element will be the successor of the one to be processed:

&& !statement_test_p(control_statement(c))

Each control node of the sequence is indeed well structured, that each control node is without any goto from or to outside itself. So we can keep the original sequence back!

Easy, just remove all the control nodes of the sequence and relink around the control graph:

Do not forget to detach the statement of its control node since we do not want the statement to be freed at the same time:

Remove the control node from the control graph by carefully relinking around:

So, there is some unstructured stuff. We can consider 2 cases to simplify the generated code:

  • If the unstructured control code is local to the sequence statements, we can keep some locality by encapsulated this mess into an unstructured so that from outside this unstructured the code is view as structured (the H in HCFG!).
  • If not, there are some goto to or from control nodes outside of the sequence statement and then we cannot do anything and return the control graph marked as with control side effect.

Remove the sequence list but not the statements themselves since each one has been moved into a control node:

There are no goto from/to the statements of the statement list, so we can encapsulate all this local control graph in an "unstructured" statement:

Get the local exit node that is the head of the control list since it was built in reverse order. Note that ctls cannot be empty here because it an empty statement sequence should be structured by definition and caught by the previous test.

FI: when the last statement is controlized, there is no guarantee any longer that the control corrresponding to the last statement of the sequence is the exit node. Also, an exit node should have no successor by definition. To avoid the issue, we could systematically add a nop statement to the sequence. Or we could check that the last control node has no successors, else look for the node connected to succ (might be dangerous because succ may not really be part of the code) and, if no such node is found because the sequence loops forever, create a new unreachable control node with a NOP statement.

First detach the local graph:

FI: Not such a good idea to return succ as exit control node...

Reconnect around the unstructured:

And create the local "unstructured" statement to take this local graph:

Make sure that the new unstructured u is not linked to code sitting above

We keep the old block statement since it may old extensions, declarations... If useless, it should be removed later by another phase. So, move the unstructured statement as the only statement of the block:

From outside of this block statement, everything is hierarchized, so we claim it:

There are some goto from or to external control nodes, so we cannot localize stuff.

Keep the empty block statement for extensions and declarations:

Integrate the statements related to the labels inside its statement to the current statement itself:

Remove local label association hash map:

‍**Revert to the variable scope of the outer block statement: *‍/

Definition at line 1914 of file controlizer.c.

1916  {
1917  statement st = control_statement(c_res);
1918  /* To see if the control graph will stay local or not: */
1919  hash_table block_used_labels = hash_table_make(hash_string, 0);
1920  bool controlized = false;
1921 
1922  pips_assert("st it a statement sequence", statement_sequence_p(st));
1923 
1924  ifdebug(5) {
1925  pips_debug(5, "Entering with nodes linked with c_res %p:\n", c_res);
1927  }
1928  ifdebug(1) {
1929  check_control_coherency(c_res);
1931  }
1932 
1933  scoping_statement_push(st);
1934 
1935  /* A C block may have a label and even goto from outside on it. */
1936  /* To track variable scoping, track this statement */
1937  // TODO scoping_statement_push(st);
1938 
1939  /* Get the list of statements in the block statement: */
1940  list sts = statement_block(st);
1941  /* The list of all the control nodes associated to this statement
1942  list: */
1943  list ctls = NIL;
1944 
1945  /* To track where to insert the current control node of a sequence
1946  element: */
1947  control pred = c_res;
1948  /* We first transform a structured block of statement in a thread of
1949  control node with all the statements that we insert from c_res up to
1950  succ: */
1951  bool must_be_controlized_p = false;
1952  //bool previous_control_preexisting_p = false;
1953 
1954  FOREACH(STATEMENT, s, sts) {
1955  /* Create a new control node for this statement, or retrieve one
1956  if it as a label: */
1958  //bool control_preexisting_p = false;
1959 
1960  // FI: I'm not sure this is enough to detect that
1961  // make_conditional_control() has not made a new control but
1962  // retrieved a control by its label...
1963  //if(!ENDP(control_successors(c)) || !ENDP(control_predecessors(c)) ) {
1964  // FI: too bad if the label is unused... or used locally... or is
1965  // useless as happens after inlining for FREIA: "goto l1;l1: ;"
1966  if(!unlabelled_statement_p(s)) {
1967  pips_debug(8, "This control %p pre-existed. "
1968  "The sequence cannot be controlized.\n", c);
1969  must_be_controlized_p = true;
1970  //control_preexisting_p = true;
1971  }
1972 
1973  // "insert_control_in_arc(c, pred, succ);" with additional checks
1974  unlink_2_control_nodes(pred,succ); // whether they are linked or not
1975  if(ENDP(control_successors(pred)))
1976  link_2_control_nodes(pred, c);
1977  if(ENDP(control_successors(c)))
1978  link_2_control_nodes(c, succ);
1979 
1980 
1981  /* Keep track of the control node associated to this statement. Note
1982  that the list is built in reverse order: */
1983  ctls = CONS(CONTROL, c, ctls);
1984  /* The next control node will be inserted after the new created node: */
1985  pred = c;
1986  //previous_control_preexisting_p = control_preexisting_p;
1987  }
1988 
1989  // FI: check that this is a neat sequence if it does not must be controlized
1990  if(!must_be_controlized_p) {
1991  FOREACH(CONTROL, c, ctls) {
1992  pips_assert("c may have only one successor even if it is a test "
1993  "a this point",
1996  ||
1999  );
2000  }
2001  }
2002 
2003  /* Now do the real controlizer job on the previously inserted thread of
2004  control nodes. */
2005  /* Note that we iterate in the reverse order of the
2006  statements since the control list was built up in reverse
2007  order. Indeed doing this in reverse order is simpler to write with
2008  this "next" stuff because we already have the current element and the
2009  successor "succ". */
2010  control next = succ;
2011  pips_debug(5, "Controlize each statement sequence node in reverse order:\n");
2012  FOREACH(CONTROL, c, ctls) {
2013  /* Recurse on each statement: controlized has been initialized to
2014  false */
2015  controlized |= controlize_statement(c, next, block_used_labels);
2016  /* The currently processed element will be the successor of the one to
2017  be processed: */
2018  next = c;
2019  }
2020 
2021  if (!controlized && !must_be_controlized_p) {
2022 
2023  // FI: check that this is a neat sequence
2024  FOREACH(CONTROL, c, ctls) {
2025  if(controlized) // unstructured case: impossible
2026  pips_assert("c may have two successors only if it is a test",
2029  ||
2032  );
2033  else // the sequence is structured: always
2034  pips_assert("c may have two successors only if it is a test",
2037  ||
2039  // FI: the test may not be unstructured; a
2040  // structured test has only one successor
2041  /* && !statement_test_p(control_statement(c))*/ )
2042  );
2043  }
2044  /* Each control node of the sequence is indeed well structured, that
2045  each control node is without any goto from or to outside itself. So
2046  we can keep the original sequence back! */
2047  pips_debug(5, "Keep a statement sequence and thus remove"
2048  " previously allocated control nodes for the sequence.\n");
2049  /* Easy, just remove all the control nodes of the sequence and relink
2050  around the control graph: */
2051  FOREACH(CONTROL, c, ctls) {
2053  int nsucc = (int) gen_length(control_successors(c));
2054  /* Do not forget to detach the statement of its control node since
2055  we do not want the statement to be freed at the same time: */
2056  pips_debug(6, "Removing useless control node %p.\n", c);
2058 
2059  if(statement_test_p(s)) {
2060  // FI: this had not been planned by Ronan
2061  if(nsucc==1) {
2062  // FI: might this happen when a test is found out well-structured?
2064  }
2065  else {
2066  pips_assert("a test has two successors\n", nsucc==2);
2068  }
2069  }
2070  else {
2071  if(nsucc<=1) {
2072  pips_assert("a non test has one successor at most\n", nsucc<=1);
2073  /* Remove the control node from the control graph by carefully
2074  relinking around: */
2076  }
2077  else {
2078  pips_debug(1, "Abnormal control: not a test, two successors.\n");
2080  }
2081  }
2082  }
2083  // You may have to fix C89 declarations if some unstructured has
2084  // been created below in the recursion
2085  if(get_bool_property("C89_CODE_GENERATION")) {
2087  }
2088  }
2089  else {
2090  /* So, there is some unstructured stuff. We can consider 2 cases to
2091  simplify the generated code:
2092 
2093  - If the unstructured control code is local to the sequence
2094  statements, we can keep some locality by encapsulated this mess
2095  into an unstructured so that from outside this unstructured the
2096  code is view as structured (the H in HCFG!).
2097 
2098  - If not, there are some goto to or from control nodes outside of
2099  the sequence statement and then we cannot do anything and return
2100  the control graph marked as with control side effect.
2101  */
2102  bool covers_p = covers_labels_p(st, block_used_labels);
2103  /* Remove the sequence list but not the statements themselves since
2104  each one has been moved into a control node: */
2107 
2108  // FI: this fails because st has been gutted out... covers_p must
2109  // be computed earlier
2110  if (covers_p) {
2111  /* There are no goto from/to the statements of the statement list,
2112  so we can encapsulate all this local control graph in an
2113  "unstructured" statement: */
2114  /* Get the local exit node that is the head of the control list
2115  since it was built in reverse order. Note that ctls cannot be
2116  empty here because it an empty statement sequence should be
2117  structured by definition and caught by the previous test. */
2118  /* FI: when the last statement is controlized, there is no
2119  guarantee any longer that the control corrresponding to the
2120  last statement of the sequence is the exit node. Also, an
2121  exit node should have no successor by definition. To avoid
2122  the issue, we could systematically add a nop statement to the
2123  sequence. Or we could check that the last control node has no
2124  successors, else look for the node connected to succ (might
2125  be dangerous because succ may not really be part of the code)
2126  and, if no such node is found because the sequence loops
2127  forever, create a new unreachable control node with a NOP
2128  statement. */
2129  // control exit = CONTROL(CAR(ctls));
2130  control exit = find_exit_control_node(ctls, succ);
2131  //control exit = find_or_create_exit_control_node(ctls, succ);
2132  control entry = CONTROL(CAR(gen_last(ctls)));
2133  pips_debug(5, "Create a local unstructured with entry node %p and exit node %p\n", entry, exit);
2134 
2135  /* First detach the local graph: */
2136  unlink_2_control_nodes(c_res, entry);
2137  /* FI: Not such a good idea to return succ as exit control node... */
2139  /* Reconnect around the unstructured: */
2140  link_2_control_nodes(c_res, succ);
2141  /* And create the local "unstructured" statement to take this local
2142  graph: */
2143  unstructured u = make_unstructured(entry, exit);
2144  ifdebug(1) {
2145  check_control_coherency(entry);
2147 
2148  /* Make sure that the new unstructured u is not linked to code
2149  sitting above */
2150  list linked_nodes = NIL;
2151  control_map_get_blocs(entry, &linked_nodes);
2152  if(gen_in_list_p(c_res, linked_nodes)) {
2153  list cp = NIL;
2154  list vp = NIL;
2155  find_a_control_path(entry, c_res, &cp, &vp, 0);
2157  pips_internal_error("Some issue due to \"c_res\" with covers_p\n");
2158  }
2159  else if(gen_in_list_p(succ, linked_nodes)) {
2160  list cp = NIL;
2161  list vp = NIL;
2162  find_a_control_path(entry, c_res, &cp, &vp, 0);
2164  pips_internal_error("Some issue due to \"succ\" with covers_p\n");
2165  }
2166  }
2167 
2168  statement u_s =
2170  /* We keep the old block statement since it may old extensions,
2171  declarations... If useless, it should be removed later by another
2172  phase. So, move the unstructured statement as the only statement
2173  of the block: */
2175  CONS(STATEMENT, u_s, NIL);
2176  // You may have to fix C89 declarations if some unstructured has
2177  // been created below in the recursion
2178  //if(get_bool_property("C89_CODE_GENERATION")) {
2180  //}
2181  /* From outside of this block statement, everything is hierarchized,
2182  so we claim it: */
2183  controlized = false;
2184  }
2185  else {
2186  /* There are some goto from or to external control nodes, so we
2187  cannot localize stuff. */
2188  pips_debug(5, "There are goto to/from outside this statement list"
2189  " so keep control nodes without any hierarchy here.\n");
2190  /* Keep the empty block statement for extensions and declarations: */
2191  // FI; maybe for extensions, but certainly not for declarations;
2192  // similar code to flatten_code must be used to rename the local
2193  // variables and to move them up the AST; see sequence04.c for instance
2195  NIL;
2196  // TODO move declarations up, keep extensions & here
2198  controlized = true;
2199  }
2200  }
2201  /* Integrate the statements related to the labels inside its statement
2202  to the current statement itself: */
2203  union_used_labels(used_labels, block_used_labels);
2204  /* Remove local label association hash map: */
2205  hash_table_free(block_used_labels);
2206 
2207 #if 0
2208 // TODO
2209  if (!hierarchized_labels) {
2210  /* We are in trouble since we will have an unstructured with goto
2211  from or to outside this statement sequence, but the statement
2212  sequence that define the scoping rules is going to disappear...
2213  So we gather all the declaration and push them up: */
2215  }
2216 #endif
2217  ///* Revert to the variable scope of the outer block statement: */
2218  // TODO scoping_statement_pop();
2219  scoping_statement_pop();
2221 
2222  return controlized;
2223 }
instruction make_instruction_unstructured(unstructured _field_)
Definition: ri.c:1187
void const char const char const int
statement instruction_to_statement(instruction)
Build a statement from a give instruction.
Definition: statement.c:597
void remove_a_control_from_an_unstructured_without_relinking(control c)
It removes a control node from its successor and predecessor.
Definition: control.c:1031
void print_control_nodes(list l)
Display identification of a list of control nodes.
Definition: control.c:589
void control_map_get_blocs(control c, list *l)
Build recursively the list of all controls reachable from a control of an unstructured.
Definition: control.c:75
void find_a_control_path(control b, control e, list *pp, list *vp, int dir)
Build recursively a control path from b to e.
Definition: control.c:107
static bool covers_labels_p(statement st, hash_table used_labels)
Compute whether all the label references in a statement are in a given label name to statement list l...
Definition: controlizer.c:294
control find_exit_control_node(list ctls, control succ)
Find the exit node of a sub-CFG defined by the list of nodes ctls and by the first node to execute wh...
Definition: controlizer.c:1739
static void move_declaration_control_node_declarations_to_statement(list ctls)
Move all the declarations found in a list of control to a given statement.
Definition: controlizer.c:1506
list gen_last(list l)
Return the last element of a list.
Definition: list.c:578
sequence statement_sequence(statement)
Get the sequence of a statement sequence.
Definition: statement.c:1328
list statement_block(statement)
Get the list of block statements of a statement sequence.
Definition: statement.c:1338
bool unlabelled_statement_p(statement)
Definition: statement.c:402
bool statement_sequence_p(statement)
Statement classes induced from instruction type.
Definition: statement.c:335
void fix_block_statement_declarations(statement)
s is assumed to be a block statement and its declarations field is assumed to be correct,...
Definition: statement.c:2930
#define exit(code)
Definition: misc-local.h:54
#define sequence_statements(x)
Definition: ri.h:2360
#define instruction_sequence(x)
Definition: ri.h:1514
Pvecteur cp
pointeur sur l'egalite ou l'inegalite courante
Definition: sc_read.c:87

References CAR, check_control_coherency(), CONS, CONTROL, control_map_get_blocs(), control_statement, control_successors, controlize_statement(), covers_labels_p(), cp, display_linked_control_nodes(), ENDP, exit, find_a_control_path(), find_exit_control_node(), fix_block_statement_declarations(), FOREACH, gen_free_list(), gen_in_list_p(), gen_last(), gen_length(), get_bool_property(), hash_string, hash_table_free(), hash_table_make(), ifdebug, instruction_sequence, instruction_to_statement(), int, link_2_control_nodes(), make_conditional_control(), make_instruction_unstructured(), make_unstructured(), move_declaration_control_node_declarations_to_statement(), NIL, pips_assert, pips_debug, pips_internal_error, print_control_nodes(), remove_a_control_from_an_unstructured(), remove_a_control_from_an_unstructured_without_relinking(), sequence_statements, STATEMENT, statement_block(), statement_consistent_p(), statement_instruction, statement_sequence(), statement_sequence_p(), statement_test_p(), statement_undefined, union_used_labels(), unlabelled_statement_p(), and unlink_2_control_nodes().

Referenced by controlize_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_statement()

bool controlize_statement ( control  c_res,
control  succ,
hash_table  used_labels 
)

Controlize a statement that is in a control node, that is restructure it to have a HCFG recursively (a hierarchical control flow graph).

Parameters
[in,out]c_resis the control node with the main statement to controlize. c_res should already own the statement at entry that will be recursively controlized. c_res can be seen as a potential unstructured entry node.
[in,out]succis the successor control node of c_res at entry. It may be no longer the case at exit if for example the code is unreachable or there is a goto to elsewhere in @p_res. succ can be seen as a potential unstructured exit node.
[in,out]used_labelsis a way to define a community of label we encounter in a top-down approac during the recursion with their related statements. With it, during the bottom-up approach, we can use it to know if a statement can be control-hierarchized or not. More concretely, it is a hash table mapping a label name to a list of statements that reference it, as their label or because it is a goto to it. This hash map is modified to represent local labels with their local related statements. This table is used later to know if all the statements associated to local labels are local or not. If they are local, the statement can be hierarchized since there is no goto from or to outside location.
Returns
true if the current statement isn't a structured control.

Get the statement to controlized from its control node owner. The invariant is that this statement remains in its control node through the controlizer process. Only the content of the statement may change.

print_statement(st);

Apply the controlizer on a statement sequence, basically by considering it as a control node sequence

Go on with a test:

Controlize a DO-loop à la Fortran:

Controlize a while() or do { } while() loop:

The hard case, the goto, that will add some trouble in this well structured world...

Controlize some function call (that hides many things in PIPS)

FI: IO calls may have control effects; they should be handled here!

PJ: controlize_call() controlize any "nice" statement, so even a C expression used as an instruction:

print_statement(st);

The declarations may be preserved at a lower level if(!ENDP(statement_declarations(st)) && ENDP(statement_declarations(control_statement(c_res)))) { pips_internal_error("Lost local declarations"); }

Update the association between the current statement and its label (the empty label is ignored by update_used_labels()):

Parameters
c_res_res
succucc
used_labelssed_labels

Definition at line 2493 of file controlizer.c.

2496 {
2497  /* Get the statement to controlized from its control node owner. The
2498  invariant is that this statement remains in its control node through
2499  the controlizer process. Only the content of the statement may
2500  change. */
2501  statement st = control_statement(c_res);
2503  bool controlized = false;
2504 
2505  ifdebug(5) {
2506  pips_debug(1,
2507  "Begin with (st = %p, c_res = %p, succ = %p)\n"
2508  "st at entry:\n",
2509  st, c_res, succ);
2511  /* print_statement(st); */
2512  pips_debug(1, "Control list from c_res %p:\n", c_res);
2515  check_control_coherency(c_res);
2516  }
2517 
2518  switch(instruction_tag(i)) {
2519 
2520  case is_instruction_block:
2521  /* Apply the controlizer on a statement sequence, basically by
2522  considering it as a control node sequence */
2523  controlized = controlize_sequence(c_res, succ, used_labels);
2524  break;
2525 
2526  case is_instruction_test:
2527  /* Go on with a test: */
2528  controlized = controlize_test(c_res, succ, used_labels);
2529  break;
2530 
2531  case is_instruction_loop:
2532  /* Controlize a DO-loop à la Fortran: */
2533  controlized = controlize_loop(c_res, succ, used_labels);
2534  break;
2535 
2536  case is_instruction_whileloop: {
2537  /* Controlize a while() or do { } while() loop: */
2540  controlized = controlize_whileloop(c_res, succ, used_labels);
2541  else
2542  controlized = controlize_repeatloop(c_res, succ, used_labels);
2544  break;
2545  }
2546 
2547  case is_instruction_goto: {
2548  /* The hard case, the goto, that will add some trouble in this well
2549  structured world... */
2550  controlized = controlize_goto(c_res, succ, used_labels);
2551 
2552  break;
2553  }
2554 
2555  case is_instruction_call:
2556  /* Controlize some function call (that hides many things in PIPS) */
2557  /* FI: IO calls may have control effects; they should be handled here! */
2558  // FI: no specific handling of return? controlized = return_instruction_p(i)
2559  controlized = controlize_call(c_res, succ);
2561  break;
2562 
2564  pips_assert("We are really dealing with a for loop",
2566  controlized = controlize_forloop(c_res, succ, used_labels);
2568  break;
2569 
2572  if(expression_reference_p(e)) {
2573  controlized = false;
2574  }
2575  else if(expression_call_p(e))
2576  /* PJ: controlize_call() controlize any "nice" statement, so even a C
2577  expression used as an instruction: */
2578  controlized = controlize_call(c_res, succ);
2580  break;
2581  }
2582 
2583  default:
2584  pips_internal_error("Unknown instruction tag %d", instruction_tag(i));
2585  }
2586 
2588  ifdebug(5) {
2589  pips_debug(1, "st %p at exit:\n", st);
2590  /* print_statement(st); */
2591  pips_debug(1, "Resulting Control c_res %p at exit:\n", c_res);
2593  fprintf(stderr, "---\n");
2594  /* The declarations may be preserved at a lower level
2595  if(!ENDP(statement_declarations(st))
2596  && ENDP(statement_declarations(control_statement(c_res)))) {
2597  pips_internal_error("Lost local declarations");
2598  }
2599  */
2600 
2602  check_control_coherency(c_res);
2603  }
2604 
2605  /* Update the association between the current statement and its
2606  label (the empty label is ignored by update_used_labels()):
2607  */
2608  string label = entity_name(statement_label(st));
2609  update_used_labels(used_labels, label, st);
2610 
2611  return controlized;
2612 }
static bool controlize_whileloop(control c_res, control succ, hash_table used_labels)
Computes the control graph of a Fortran or C while loop statement.
Definition: controlizer.c:847
static bool controlize_forloop(control c_res, control succ, hash_table used_labels)
Computes the control graph of a C for loop statement.
Definition: controlizer.c:723
static bool controlize_sequence(control c_res, control succ, hash_table used_labels)
Computes the control graph of a sequence statement.
Definition: controlizer.c:1914
static bool controlize_loop(control c_res, control succ, hash_table used_labels)
Computes the control graph of a Fortran do-loop statement.
Definition: controlizer.c:597
static bool controlize_repeatloop(control c_res, control succ, hash_table used_labels)
Computes the control graph of a C repeat until loop statement.
Definition: controlizer.c:990
static bool controlize_test(control c_res, control succ, hash_table used_labels)
Builds the control node of a test statement.
Definition: controlizer.c:2238
static bool controlize_call(control c_res, control succ)
Controlize a call statement.
Definition: controlizer.c:2455
static bool controlize_goto(control c_res, control succ, hash_table used_labels)
Deal with "goto" when building the HCFG.
Definition: controlizer.c:2362
bool expression_call_p(expression e)
Definition: expression.c:415
bool expression_reference_p(expression e)
Test if an expression is a reference.
Definition: expression.c:528
#define whileloop_evaluation(x)
Definition: ri.h:3166
#define instruction_expression(x)
Definition: ri.h:1541
#define evaluation_before_p(x)
Definition: ri.h:1159

References check_control_coherency(), control_statement, controlize_call(), controlize_forloop(), controlize_goto(), controlize_loop(), controlize_repeatloop(), controlize_sequence(), controlize_test(), controlize_whileloop(), display_linked_control_nodes(), entity_name, evaluation_before_p, expression_call_p(), expression_reference_p(), fprintf(), ifdebug, instruction_expression, instruction_forloop_p, instruction_tag, instruction_whileloop, is_instruction_block, is_instruction_call, is_instruction_expression, is_instruction_forloop, is_instruction_goto, is_instruction_loop, is_instruction_test, is_instruction_whileloop, pips_assert, pips_debug, pips_internal_error, statement_consistent_p(), statement_instruction, statement_label, update_used_labels(), and whileloop_evaluation.

Referenced by controlize_forloop(), controlize_loop(), controlize_repeatloop(), controlize_sequence(), controlize_test(), controlize_whileloop(), and hcfg().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_test() [1/2]

static bool controlize_test ( control  c_res,
control  succ,
hash_table  used_labels 
)
static

Builds the control node of a test statement.

Parameters
[in,out]c_resis the control node with the test statement (if/then/else)
[in,out]succis the control node successor of c_res
[in,out]used_labelsis a hash table mapping a label name to a list of statements that use it, as their label or because it is a goto to it
Returns
true if the control node generated is not structured.

The statements of each branch:

Create a control node for each branch of the test:

pips_debug(1, "THEN at entry:\n");

print_statement(s_t);

pips_debug(1, "c_then at entry:\n");

print_statement(control_statement(c_then));

pips_debug(1, "ELSE at entry:\n");

print_statement(s_f);

pips_debug(1, "c_else at entry:\n");

print_statement(control_statement(c_else));

Use 2 hash table to figure out the label references in each branch to know if we will able to restructure them later:

Insert the control nodes for the branch into the current control sequence:

First disconnect the sequence:

Then insert the 2 nodes for each branch, in the correct order since the "then" branch is the first successor of the test and the "else" branch is the second one:

Now we can controlize each branch statement to deal with some control flow fun:

If all the label jumped to from the THEN/ELSE statements are in their respective statement, we can replace the unstructured test by a structured one back:

FI: this test returns a wrong result for if02.c. The reason might be again controlize_goto() or a consequence of the two calls to controlize_statement() above.

Remove the old unstructured control graph:

c_then & c_else are no longer useful:

The test statement is a structured test:

Keep the unstructured test. Normalize the unstructured test where in the control node of the test, the branch statements must be empty since the real code is in the 2 control node successors:

Warn we have an unstructured test:

Update the used labels hash map from the 2 test branches

The local hash tables are no longer useful:

pips_debug(1, "IF at exit:\n");

print_statement(st);

Definition at line 2238 of file controlizer.c.

2241 {
2242  bool controlized;
2243  statement st = control_statement(c_res);
2244  test t = statement_test(st);
2245  /* The statements of each branch: */
2246  statement s_t = test_true(t);
2247  statement s_f = test_false(t);
2248  /* Create a control node for each branch of the test: */
2249  control c_then = make_conditional_control(s_t);
2250  control c_else = make_conditional_control(s_f);
2251 
2252  pips_debug(5, "Entering (st = %p, c_res = %p, succ = %p)\n",
2253  st, c_res, succ);
2254 
2255  ifdebug(5) {
2256  /* pips_debug(1, "THEN at entry:\n"); */
2257  /* print_statement(s_t); */
2258  /* pips_debug(1, "c_then at entry:\n"); */
2259  /* print_statement(control_statement(c_then)); */
2260  /* pips_debug(1, "ELSE at entry:\n"); */
2261  /* print_statement(s_f); */
2262  /* pips_debug(1, "c_else at entry:\n"); */
2263  /* print_statement(control_statement(c_else)); */
2265  check_control_coherency(c_res);
2266  }
2267 
2268  /* Use 2 hash table to figure out the label references in each branch to
2269  know if we will able to restructure them later: */
2270  hash_table t_used_labels = hash_table_make(hash_string, 0);
2271  hash_table f_used_labels = hash_table_make(hash_string, 0);
2272 
2273  /* Insert the control nodes for the branch into the current control
2274  sequence: */
2275  /* First disconnect the sequence: */
2276  unlink_2_control_nodes(c_res, succ);
2277 
2278  /* Then insert the 2 nodes for each branch, in the correct order since
2279  the "then" branch is the first successor of the test and the "else"
2280  branch is the second one: */
2281  // Correct order: link_2_control_nodes add the new arc in the
2282  // first slot; so reverse linking of c_else and c_then
2283  link_3_control_nodes(c_res, c_then, c_else);
2284  link_2_control_nodes(c_else, succ);
2285  //link_2_control_nodes(c_res, c_then);
2286  link_2_control_nodes(c_then, succ);
2287 
2288  /* Now we can controlize each branch statement to deal with some control
2289  flow fun: */
2290  controlize_statement(c_then, succ, t_used_labels);
2291  controlize_statement(c_else, succ, f_used_labels);
2292 
2293  /* If all the label jumped to from the THEN/ELSE statements are in their
2294  respective statement, we can replace the unstructured test by a
2295  structured one back: */
2296  /* FI: this test returns a wrong result for if02.c. The reason
2297  might be again controlize_goto() or a consequence of the two
2298  calls to controlize_statement() above. */
2299  if(covers_labels_p(s_t, t_used_labels)
2300  && covers_labels_p(s_f, f_used_labels)) {
2301  pips_debug(5, "Restructure the IF at control %p\n", c_res);
2302  test_true(t) = control_statement(c_then);
2303  test_false(t) = control_statement(c_else);
2304  /* Remove the old unstructured control graph: */
2307  /* c_then & c_else are no longer useful: */
2310  // You do not want to relink too much, but you should relink a minimum
2311  link_2_control_nodes(c_res, succ);
2312 
2313  /* The test statement is a structured test: */
2314  controlized = false;
2315  }
2316  else {
2317  pips_debug(5, "Destructure the IF at control %p\n", c_res);
2318  /* Keep the unstructured test. Normalize the unstructured test where
2319  in the control node of the test, the branch statements must be
2320  empty since the real code is in the 2 control node successors: */
2323  /* Warn we have an unstructured test: */
2324  controlized = true;
2325  }
2326 
2327  /* Update the used labels hash map from the 2 test branches */
2328  union_used_labels(used_labels,
2329  union_used_labels(t_used_labels, f_used_labels));
2330 
2331  /* The local hash tables are no longer useful: */
2332  hash_table_free(t_used_labels);
2333  hash_table_free(f_used_labels);
2334 
2335  ifdebug(5) {
2336  /* pips_debug(1, "IF at exit:\n"); */
2337  /* print_statement(st); */
2340  check_control_coherency(c_res);
2341  }
2342  pips_debug(5, "Exiting\n");
2343 
2344  return controlized;
2345 }
test statement_test(statement)
Get the test of a statement.
Definition: statement.c:1348
#define test_false(x)
Definition: ri.h:2837
#define test_true(x)
Definition: ri.h:2835

References check_control_coherency(), control_statement, controlize_statement(), covers_labels_p(), display_linked_control_nodes(), hash_string, hash_table_free(), hash_table_make(), ifdebug, link_2_control_nodes(), link_3_control_nodes(), make_conditional_control(), make_plain_continue_statement(), pips_debug, remove_a_control_from_an_unstructured_without_relinking(), statement_test(), statement_undefined, test_false, test_true, union_used_labels(), and unlink_2_control_nodes().

Referenced by controlize_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_test() [2/2]

static bool controlize_test ( statement  st,
test  t,
control  pred,
control  succ,
control  c_res,
hash_table  used_labels 
)
static

Builds the control node of a statement st in c_res which is a test statement t.

Returns
true if the control node generated is not structured_.

pips_debug(1, "THEN at entry:\n");

print_statement(s_t);

pips_debug(1, "c1 at entry:\n");

print_statement(control_statement(c1));

pips_debug(1, "ELSE at entry:\n");

print_statement(s_f);

pips_debug(1, "c2 at entry:\n");

print_statement(control_statement(c2));

Just put the IF statement in c_res so that add_proper_successor_to_predecessor() that may be called from the next controlize() here behave correctly:

If all the label jumped to from the THEN/ELSE statements are in their respecive statement, we can replace the unstructured test by a structured one:

c1 & c2 are no longer useful:

Be very careful when chaining c_res as successor of pred: if pred is associated to a test, the position of c_res as first or second successor of c_res is unknown. It should have been set by the caller.

You might survive, using the fact that the true branch has been processed first because of the order of the two recursive calls to controlize(). The false branch whill be linked as second successor. But another controlize_xxx might have decided to link pred and c_res before calling controlize() and controlize_test(). Too much guessing IMHO (FI).

control_successors(pred) = ADD_SUCC(c_res, pred);

pips_debug(1, "IF at exit:\n");

print_statement(st);

Definition at line 1651 of file old_controlizer.c.

1657 {
1658  hash_table
1659  t_used_labels = hash_table_make(hash_string, 0),
1660  f_used_labels = hash_table_make(hash_string, 0);
1664  statement s_t = test_true(t);
1665  statement s_f = test_false(t);
1666  bool controlized;
1667 
1668  pips_debug(5, "Entering (st = %p, pred = %p, succ = %p, c_res = %p)\n",
1669  st, pred, succ, c_res);
1670 
1671  ifdebug(5) {
1672  /* pips_debug(1, "THEN at entry:\n"); */
1673  /* print_statement(s_t); */
1674  /* pips_debug(1, "c1 at entry:\n"); */
1675  /* print_statement(control_statement(c1)); */
1676  /* pips_debug(1, "ELSE at entry:\n"); */
1677  /* print_statement(s_f); */
1678  /* pips_debug(1, "c2 at entry:\n"); */
1679  /* print_statement(control_statement(c2)); */
1682  check_control_coherency(c_res);
1683  }
1684 
1685  controlize(s_t, c_res, c_join, c1, t_used_labels);
1686  /* Just put the IF statement in c_res so that
1687  add_proper_successor_to_predecessor() that may be called from the
1688  next controlize() here behave correctly: */
1689  control_statement(c_res) = st;
1690  controlize(s_f, c_res, c_join, c2, f_used_labels);
1691 
1692  if(covers_labels_p(s_t, t_used_labels) &&
1693  covers_labels_p(s_f, f_used_labels)) {
1694  /* If all the label jumped to from the THEN/ELSE statements are in
1695  their respecive statement, we can replace the unstructured test by
1696  a structured one: */
1697  test it = make_test(test_condition(t),
1698  control_statement(c1),
1699  control_statement(c2));
1700  /* c1 & c2 are no longer useful: */
1703 
1704  st = normalize_statement(st);
1705  UPDATE_CONTROL(c_res,
1707  statement_number(st),
1715  CONS(CONTROL, succ, NIL));
1717  controlized = false;
1718  }
1719  else {
1720  // Keep the unstructured test:
1721  UPDATE_CONTROL(c_res, st,
1723  CONS(CONTROL, c1, CONS(CONTROL, c2, NIL)));
1726  control_predecessors(succ) = ADD_PRED_IF_NOT_ALREADY_HERE(c_join, succ);
1727  control_successors(c_join) = CONS(CONTROL, succ, NIL);
1728  controlized = true;
1729  }
1730 
1731  /* Be very careful when chaining c_res as successor of pred: if pred is
1732  associated to a test, the position of c_res as first or second
1733  successor of c_res is unknown. It should have been set by the
1734  caller.
1735 
1736  You might survive, using the fact that the true branch has been
1737  processed first because of the order of the two recursive calls to
1738  controlize(). The false branch whill be linked as second
1739  successor. But another controlize_xxx might have decided to link pred
1740  and c_res before calling controlize() and controlize_test(). Too much
1741  guessing IMHO (FI). */
1742 
1743  /* control_successors(pred) = ADD_SUCC(c_res, pred); */
1745 
1746  union_used_labels(used_labels,
1747  union_used_labels(t_used_labels, f_used_labels));
1748 
1749  hash_table_free(t_used_labels);
1750  hash_table_free(f_used_labels);
1751 
1752  ifdebug(5) {
1753  /* pips_debug(1, "IF at exit:\n"); */
1754  /* print_statement(st); */
1758  check_control_coherency(c_res);
1759  }
1760  pips_debug(5, "Exiting\n");
1761 
1762  return(controlized);
1763 }
test make_test(expression a1, statement a2, statement a3)
Definition: ri.c:2607
void free_a_control_without_its_statement(control c)
Remove a control node without touching its statement, its predecessors and successors,...
Definition: control.c:1087
#define test_condition(x)
Definition: ri.h:2833

References ADD_PRED_AND_COPY_IF_NOT_ALREADY_HERE, ADD_PRED_IF_NOT_ALREADY_HERE, add_proper_successor_to_predecessor(), check_control_coherency(), CONS, CONTROL, control_predecessors, control_statement, control_successors, controlize(), copy_extensions(), covers_labels_p(), display_linked_control_nodes(), free_a_control_without_its_statement(), gen_copy_seq(), hash_string, hash_table_free(), hash_table_make(), ifdebug, is_instruction_test, make_conditional_control(), make_control(), make_instruction(), make_plain_continue_statement(), make_statement(), make_synchronization_none(), make_test(), NIL, normalize_statement(), pips_debug, statement_comments, statement_declarations, statement_decls_text, statement_extensions, statement_label, statement_number, STATEMENT_ORDERING_UNDEFINED, strdup(), test_condition, test_false, test_true, union_used_labels(), and UPDATE_CONTROL.

Referenced by controlize().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_whileloop() [1/2]

static bool controlize_whileloop ( control  c_res,
control  succ,
hash_table  used_labels 
)
static

Computes the control graph of a Fortran or C while loop statement.

Parameters
[in,out]c_resis the entry control node with the do-loop statement to controlize. If the do-loop has complex control code such as some goto to outside, it is transformed into an equivalent control graph.
[in,out]succmust be the control node successor of c_res that will be the current end of the control node sequence and an exit node
[in,out]used_labelsis a hash table mapping a label name to a list of statements that use it, as their label or because it is a goto to it
Returns
true if the code is not a structured control.

To track the statement related to labels inside the loop body:

Remove the loop body from the loop just in case we want to prettyprint our work in progress:

Create a control node to host the loop body and insert it in the control graph:

TODO switch(get_prettyprint_language_tag()) { case is_language_fortran: case is_language_fortran95: cs = strdup(concatenate(prev_comm, get_comment_sentinel(), " DO loop ", lab, " with exit had to be desugared\n", NULL)); break; case is_language_c: cs = prev_comm; break; default: pips_internal_error("This language is not handled !"); break; }

Recurse by controlizing inside the loop:

First the easy way. We have a kindly control-localized loop body, revert to the original code

Remove the control node from the control graph by carefully relinking around:

Remove also the dummy increment node that has not been used either:

Move the loop body into its own loop:

We are in trouble since the loop body is not locally structured, there are goto from inside or outside the loop body. So we replace the while loop with a desugared version with an equivalent control graph.

Update the increment control node with the real computation:

First remove the dummy statement added above:

And put "i = i + s" instead:

Now build the desugared loop:

We can replace the former loop statement by the new header. That means that all pragma, comment, extensions, label on the previous loop stay on this.

Add the continuation test between the header and the body that are already connected:

Detach succ from the loop body exit

And reconnect it to the test node to make the loop:

Add the else branch of the test toward the loop exit: arc ordering matters

Keep track of labels that were used by the statements of the loop:

Definition at line 847 of file controlizer.c.

850 {
851  /* To track the statement related to labels inside the loop body: */
852  hash_table loop_used_labels = hash_table_make(hash_string, 0);
853  statement sl = control_statement(c_res);
854 
855  pips_debug(5, "(st = %p, c_res = %p, succ = %p)\n", sl, c_res, succ);
856 
858  statement body_s = whileloop_body(wl);
859 
860  /* Remove the loop body from the loop just in case we want to
861  prettyprint our work in progress: */
862  // incompatible with debugging code
863  //whileloop_body(wl) = statement_undefined;
865 
866  /* Create a control node to host the loop body and insert it in the
867  control graph: */
868  control c_body = make_conditional_control(body_s);
869  // FI: if c_test were already available, it should be used instead
870  // of succ
871  // insert_control_in_arc(c_body, c_res, succ);
872 
873  // FI: this should be language neutral. The prettyprinter is
874  // supposed to fix comments according to language rules...
875  /* TODO
876  switch(get_prettyprint_language_tag()) {
877  case is_language_fortran:
878  case is_language_fortran95:
879  cs = strdup(concatenate(prev_comm,
880  get_comment_sentinel(),
881  " DO loop ",
882  lab,
883  " with exit had to be desugared\n",
884  NULL));
885  break;
886  case is_language_c:
887  cs = prev_comm;
888  break;
889  default:
890  pips_internal_error("This language is not handled !");
891  break;
892  }
893  */
894 
896  /* Recurse by controlizing inside the loop: */
897  link_2_control_nodes(c_body, c_test);
898  bool controlized = controlize_statement(c_body, c_test, loop_used_labels);
899 
900  if (!controlized) {
901  /* First the easy way. We have a kindly control-localized loop body,
902  revert to the original code */
903  pips_debug(6, "Since we can keep the whileloop, remove the useless control node %p that was allocated for the loop_body.\n", c_body);
905  /* Remove the control node from the control graph by carefully
906  relinking around: */
908  /* Remove also the dummy increment node that has not been used
909  either: */
910  //remove_a_control_from_an_unstructured(c_inc);
911  /* Move the loop body into its own loop: */
912  whileloop_body(wl) = body_s;
913  }
914  else {
915  /* We are in trouble since the loop body is not locally structured,
916  there are goto from inside or outside the loop body. So we
917  replace the while loop with a desugared version with an equivalent
918  control graph. */
919  /* Update the increment control node with the real computation: */
920  /* First remove the dummy statement added above: */
921  //free_statement(control_statement(c_inc));
922  /* And put "i = i + s" instead: */
923  //control_statement(c_inc) = unsugared_loop_inc(sl);
924  /* Now build the desugared loop: */
925  /* We can replace the former loop statement by the new header. That
926  means that all pragma, comment, extensions, label on the previous
927  loop stay on this. */
928  //control_statement(c_res) = unsugared_loop_header(sl);
929  // FI: c_res is useless and should be identified with c_test
931  /* Add the continuation test between the header and the body that are
932  already connected: */
933  //control c_test = make_control(unsugared_loop_test(sl), NIL, NIL);
934  unlink_2_control_nodes(c_res, succ);
936  //insert_control_in_arc(c_test, c_res, c_body);
937  /* Detach succ from the loop body exit */
938  //unlink_2_control_nodes(c_body, succ);
939  /* And reconnect it to the test node to make the loop: */
940  //link_2_control_nodes(c_body, c_test);
941  /* Add the else branch of the test toward the loop exit: arc
942  ordering matters */
944  //link_2_control_nodes(c_test, succ);
945  //link_2_control_nodes(c_test, c_body);
946  link_3_control_nodes(c_test, c_body, succ);
947  // link_2_control_nodes(c_test, c_res);
948  //unlink_2_control_nodes(c_res, succ);
949 
950  pips_assert("c_test is a test with two successors",
953  pips_assert("c_body may have two successors if it is a test",
954  ( gen_length(control_successors(c_body))==2
955  && statement_test_p(control_statement(c_body)) )
956  ||
957  ( gen_length(control_successors(c_body))==1
958  && !statement_test_p(control_statement(c_body)) )
959  );
960  pips_assert("c_res should not be a test",
961  gen_length(control_successors(c_res))==1
962  && !statement_test_p(control_statement(c_res)) );
963  }
964 
965  /* Keep track of labels that were used by the statements of the loop: */
966  union_used_labels( used_labels, loop_used_labels);
967  hash_table_free(loop_used_labels);
968 
969  pips_debug(5, "Exiting\n");
970 
971  return controlized;
972 }

References c_test(), control_statement, control_successors, controlize_statement(), gen_length(), hash_string, hash_table_free(), hash_table_make(), link_2_control_nodes(), link_3_control_nodes(), make_conditional_control(), make_control(), make_plain_continue_statement(), NIL, pips_assert, pips_debug, remove_a_control_from_an_unstructured(), statement_test_p(), statement_undefined, statement_whileloop(), union_used_labels(), unlink_2_control_nodes(), unsugared_whileloop_header(), unsugared_whileloop_test(), and whileloop_body.

Referenced by controlize_statement().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ controlize_whileloop() [2/2]

static bool controlize_whileloop ( statement  st,
whileloop  l,
control  pred,
control  succ,
control  c_res,
hash_table  used_labels 
)
static

CONTROLIZE_WHILELOOP computes in C_RES the control graph of the loop L (of statement ST) with PREDecessor and SUCCessor.

Derived by FI from controlize_loop() NN : What about other kind of whileloop, evaluation = after ? TO BE IMPLEMENTED

The edges between c_res and c_body, created by the above call to controlize are useless. The edge succ from c_res to c_body is erased by the UPDATE_CONTROL macro.

control_predecessors(c_res) = CONS(CONTROL, pred, control_predecessors(c_res));

ADD_PRED(pred, c_res);

Cannot be consistent yet!

ifdebug(5) check_control_coherency(c_res);

control_successors(pred) = ADD_SUCC(c_res, pred);

Definition at line 692 of file old_controlizer.c.

698 {
699  hash_table loop_used_labels = hash_table_make(hash_string, 0);
701  bool controlized;
702 
703  pips_debug(5, "(st = %p, pred = %p, succ = %p, c_res = %p)\n",
704  st, pred, succ, c_res);
705 
706  controlize(whileloop_body(l), c_res, c_res, c_body, loop_used_labels);
707 
708  if(covers_labels_p(whileloop_body(l),loop_used_labels)) {
710  control_statement(c_body),
711  whileloop_label(l),
713 
714  /* The edges between c_res and c_body, created by the above call to
715  * controlize are useless. The edge succ
716  * from c_res to c_body is erased by the UPDATE_CONTROL macro.
717  */
718  gen_remove(&control_successors(c_body), c_res);
719  gen_remove(&control_predecessors(c_body), c_res);
720  gen_remove(&control_predecessors(c_res), c_body);
721 
722  st = normalize_statement(st);
723  UPDATE_CONTROL(c_res,
725  statement_number(st),
729  new_l),
734  CONS(CONTROL, succ, NIL));
735  controlized = false;
736  }
737  else {
738  control_statement(c_res) = whileloop_test(st);
739  /* control_predecessors(c_res) =
740  CONS(CONTROL, pred, control_predecessors(c_res)); */
741  /* ADD_PRED(pred, c_res); */
742  control_predecessors(c_res) =
743  gen_once(pred, control_predecessors(c_res));
744  control_successors(c_res) =
745  CONS(CONTROL, succ, control_successors(c_res));
746  controlized = true ;
747  /* Cannot be consistent yet! */
748  /* ifdebug(5) check_control_coherency(c_res); */
749  }
752  /* control_successors(pred) = ADD_SUCC(c_res, pred); */
753 
755 
756  union_used_labels( used_labels, loop_used_labels);
757  hash_table_free(loop_used_labels);
758 
759  pips_debug(5, "Exiting\n");
760 
761  return(controlized);
762 }
whileloop make_whileloop(expression a1, statement a2, entity a3, evaluation a4)
Definition: ri.c:2937
static statement whileloop_test(statement sl)
Generate a test statement ts for exiting loop sl.
list gen_once(const void *vo, list l)
Prepend an item to a list only if it is not already in the list.
Definition: list.c:722
#define whileloop_label(x)
Definition: ri.h:3164
#define whileloop_condition(x)
Definition: ri.h:3160

References ADD_PRED_AND_COPY_IF_NOT_ALREADY_HERE, ADD_PRED_IF_NOT_ALREADY_HERE, add_proper_successor_to_predecessor(), check_control_coherency(), CONS, CONTROL, control_predecessors, control_statement, control_successors, controlize(), copy_extensions(), covers_labels_p(), gen_copy_seq(), gen_once(), gen_remove(), hash_string, hash_table_free(), hash_table_make(), ifdebug, is_instruction_whileloop, make_conditional_control(), make_instruction(), make_statement(), make_synchronization_none(), make_whileloop(), NIL, normalize_statement(), pips_debug, statement_comments, statement_declarations, statement_decls_text, statement_extensions, statement_label, statement_number, STATEMENT_ORDERING_UNDEFINED, strdup(), true, union_used_labels(), UPDATE_CONTROL, whileloop_body, whileloop_condition, whileloop_evaluation, whileloop_label, and whileloop_test().

Referenced by controlize().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ covers_labels_p()

static bool covers_labels_p ( statement  st,
hash_table  used_labels 
)
static

Compute whether all the label references in a statement are in a given label name to statement list local mapping.

Parameters
st[in]is the statement we want to check if it owns all allusions to the given label name in the used_labels mapping
[in]used_labelsis a hash table mapping a label name to a list of statements that use it (à la Label_statements), as their own label or because it is a goto to it
Returns
true if all the label allusions in st are covered by the used_labels mapping.

print_statement(st);

For all the labels in used_labels:

The statements using a label name in used_labels:

For all the statements associated to this label name:

In one special case, def may have lost its use of a label: if it is a goto to the next statement (see controlize_goto()). Then it is a simple continue. This special configuration never happens, except in code generated by the inlining pass... or written by a weird programmer. It seems easier to keep Label_statements consistent rather than fix the problem here.

Verify that def is in all the statements associated globally to the label name according to module-level Label_statements.

Not useful to go on:

Definition at line 294 of file controlizer.c.

295  {
296  ifdebug(5) {
297  pips_debug(5, "Statement %td (%p): \n ", statement_number(st), st);
298  /* print_statement(st); */
299  }
300  /* For all the labels in used_labels: */
301  void * cl = NULL;
302  list stats = NIL;
303  string name = string_undefined;
304  while((cl=hash_table_scan(used_labels, cl, (void **) &name, (void **) &stats))) {
305  // HASH_MAP(name, sts, {
306  /* The statements using a label name in used_labels: */
307  //list stats = (list) sts;
308 
309  /* For all the statements associated to this label name: */
310  list sl = (list) hash_get_default_empty_list(Label_statements, (void *) name);
311  FOREACH(STATEMENT, def, sl) {
312  /* In one special case, def may have lost its use of a label:
313  if it is a goto to the next statement (see
314  controlize_goto()). Then it is a simple
315  continue. This special configuration never happens, except
316  in code generated by the inlining pass... or written by a
317  weird programmer. It seems easier to keep Label_statements
318  consistent rather than fix the problem here. */
319  bool found = false;
320  /* Verify that def is in all the statements associated globally to
321  the label name according to module-level Label_statements. */
322  FOREACH(STATEMENT, st, stats) {
323  found |= st == def;
324  }
325 
326  if (!found) {
327  pips_debug(5, "does not cover label %s\n", (char *) name);
328  /* Not useful to go on: */
329  return(false);
330  }
331  }
332  }
333  //}, used_labels);
334 
335  ifdebug(5)
336  fprintf(stderr, "covers its label usage\n");
337 
338  return(true);
339 }
void * hash_table_scan(hash_table htp, void *hentryp_arg, void **pkey, void **pval)
Definition: hash.c:844
static char * usage
Definition: pips.c:63

References FOREACH, fprintf(), hash_get_default_empty_list(), hash_table_scan(), ifdebug, Label_statements, NIL, pips_debug, STATEMENT, statement_number, and string_undefined.

Referenced by controlize_sequence(), and controlize_test().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ create_statements_of_label()

static void create_statements_of_label ( statement  st)
static

Update the global module-level Label_statements table according to the labels a statement references.

It also creates a control node for this statement if it has a label and register it to the module-global Label_control table.

A statement can reference a label if it is its own label or if the statement is indeed a goto to this label.

Label found in Fortran do-loop to set loop boundary or in Fortran IO using some FORMAT through its label are not considered here since it is not related to control flow.

Parameters
[in]stis the statement to look at for labels

Add the statement to its own label reference, if needed:

Associate globally the statement to its own label:

Create the control node with the statement inside:

If the statement is a goto, add to the target label a reference to this statement:

Associate the statement to the target label:

Do nothing special for other kind of instructions

Definition at line 398 of file controlizer.c.

398  {
399  instruction i;
400 
401  /* Add the statement to its own label reference, if needed: */
402  string name = entity_name(statement_label(st));
403  if (!empty_global_label_p(name)) {
404  /* Associate globally the statement to its own label: */
406  /* Create the control node with the statement inside: */
407  control c = make_control(st, NIL, NIL);
408  pips_debug(8, "control %p allocated for label \"%s\"", c, name);
409  hash_put(Label_control, name, (char *)c);
410  }
411 
412  switch(instruction_tag(i = statement_instruction(st))) {
413  /* If the statement is a goto, add to the target label a reference to
414  this statement: */
415  case is_instruction_goto: {
416  string where = entity_name(statement_label(instruction_goto(i)));
417  /* Associate the statement to the target label: */
419  break;
420  }
421 
423  pips_internal_error("Found unstructured", "");
424 
425  default:
426  /* Do nothing special for other kind of instructions */
427  ;
428  }
429 }
bool empty_global_label_p(const char *gln)
Definition: entity_names.c:264
void hash_put(hash_table htp, const void *key, const void *val)
This functions stores a couple (key,val) in the hash table pointed to by htp.
Definition: hash.c:364

References empty_global_label_p(), entity_name, hash_put(), instruction_goto, instruction_tag, is_instruction_goto, is_instruction_unstructured, Label_control, Label_statements, make_control(), NIL, pips_debug, pips_internal_error, statement_instruction, statement_label, and update_used_labels().

Referenced by create_statements_of_labels().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ create_statements_of_labels() [1/2]

static void create_statements_of_labels ( st  )
static

Definition at line 1822 of file old_controlizer.c.

1824 {
1825  gen_recurse(st,
1827  gen_true,
1829 }
#define gen_recurse(start, domain_number, flt, rwt)
Definition: genC.h:283
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
static void create_statements_of_label(statement st)
CREATE_STATEMENTS_OF_LABELS gathers in the Label_statements table all the references to the useful la...
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362

References create_statements_of_label(), gen_recurse, gen_true(), and statement_domain.

Referenced by control_graph().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ create_statements_of_labels() [2/2]

static void create_statements_of_labels ( statement  st)
static

Initialize the global Label_statements mapping for the module that associates for any label in the module the statements that refer to it.

Parameters
[in]stis the module (top) statement

Apply create_statements_of_label() on all the module statements

Definition at line 437 of file controlizer.c.

437  {
438  /* Apply create_statements_of_label() on all the module statements */
439  gen_recurse(st,
441  gen_true,
443 }
static void create_statements_of_label(statement st)
Update the global module-level Label_statements table according to the labels a statement references.
Definition: controlizer.c:398

References create_statements_of_label(), gen_recurse, gen_true(), and statement_domain.

Referenced by hcfg().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_exit_control_node()

control find_exit_control_node ( list  ctls,
control  succ 
)

Find the exit node of a sub-CFG defined by the list of nodes ctls and by the first node to execute when finished.

The entry node of the sub-CFG is the last node of the ctls list, because it is built backwards.

RK: ctls is built backwards: hence its exit node is the first node in the list.

FI: in fact, it's a bit more complicated...

The underlying purpose of this function only called from controlize_sequence(() is to help separate a sub CFG with only one entry and one exit point from the global graph. The entry node is easy to find as CONTROL(CAR(gen_last(ctls))). The exit node may be anywhere because of the goto statements. The succ node is the first node executed after the CFG defined by ctls. But it may have no predecessor or only some of its predecessors belong to the global graph but not to the local graph. So we are interested in predecessors of succ that are reachable from the entry node. Unless we are lucky because succ has only one predecessor and this predecessor has only one successor, succ. In that case, the predecessor of succ is the exit node.

The control graph may be altered with a newly allocated node or not.

Parameters
ctlslist of the control nodes belonging to the subgraph to isolate
succ is the first control node not in ctls to be executed after the nodes in ctls.
Returns
exit, the existing or newly allocated exit node. The subgraph defined by ctls is updated when a new node is allocated.

Two algorithms at least are possible: we can either start from the predecessors of succ and check that a backward control path to the entry of ctls exists, or we can start from entry and look for control paths reaching succ. The second approach is implemented here. tatic

look for a successor of entry that is a predecessor of succ

succ may be unreachable because ctls loops on itself

Parameters
ctlstls
succucc

Definition at line 1739 of file controlizer.c.

1740 {
1741  control exit = CONTROL(CAR(ctls));
1742  control entry = CONTROL(CAR(gen_last(ctls)));
1743 
1744  ifdebug(8) {
1745  FOREACH(CONTROL, c, ctls) {
1747  }
1749  }
1750 
1753  && CONTROL(CAR(control_successors(exit)))==succ))) {
1754  /* look for a successor of entry that is a predecessor of succ */
1755  list visited = NIL;
1756  list to_be_visited = gen_copy_seq(control_successors(entry));
1757  bool found_p = false;
1759 
1760  while(!ENDP(to_be_visited)) {
1761  FOREACH(CONTROL, c, to_be_visited) {
1762  if(gen_in_list_p(succ, control_successors(c))) {
1765 
1766  insert_control_in_arc(exit, c, succ);
1767  found_p = true;
1768  }
1769  if(c!=succ) { // Should always be true...
1770  visited = CONS(CONTROL, c, visited);
1771  gen_remove(&to_be_visited, c);
1773  if(!gen_in_list_p(s, visited)
1774  && !gen_in_list_p(s, to_be_visited)
1775  && s!=succ && s!=exit)
1776  // update the loop variable... within the two nested loops
1777  to_be_visited = CONS(CONTROL, s, to_be_visited);
1778  }
1779  }
1780  else {
1781  pips_internal_error("design error\n.");
1782  }
1783  }
1784  }
1785 
1786  gen_free_list(visited);
1787  gen_free_list(to_be_visited);
1788 
1789  if(!found_p) {
1790  /* succ may be unreachable because ctls loops on itself*/
1792  }
1793  }
1794 
1795  ifdebug(8) {
1796  FOREACH(CONTROL, c, ctls) {
1798  }
1800  }
1801 
1802 return exit;
1803 }

References CAR, check_control_coherency(), CONS, CONTROL, control_successors, control_undefined, control_undefined_p, ENDP, exit, FOREACH, gen_copy_seq(), gen_free_list(), gen_in_list_p(), gen_last(), gen_length(), gen_remove(), ifdebug, insert_control_in_arc(), make_control(), make_plain_continue_statement(), NIL, and pips_internal_error.

Referenced by controlize_sequence().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_or_create_exit_control_node()

control find_or_create_exit_control_node ( list  ctls,
control  succ 
)

FI: remake of function above, incomplete backward approach, now obsolete because the forward approach works.

But who knows? The complexity of the backward approach might be lower than the complexity of the forward approach?

Because of the recursive descent in the AST...

Let's try to use an existing node as exit node

A new node is needed as exit node

The CFG contains an infinite loop and succ is never reached?

FI: we might need to check that the predecessor is not still c_res?

Why would we link it to succ to have it unlinked by the caller?

succ must be removed from the current CFG. Its predecessors within the current CFG must be moved onto the new exit node

Is c in the current CFG or in anoter one at a higher level? Typical case: the current sequence is a test branch and hence succ has two predecessors at the higher level

orward_control_path_p(entry, c)

hpftest62b.f: the sequence below pulls an extra statement in the unstructured that is being built

Parameters
ctlstls
succucc

Definition at line 1809 of file controlizer.c.

1810 {
1812  //control entry = CONTROL(CAR(gen_last(ctls)));
1813 
1814  ifdebug(8) {
1815  FOREACH(CONTROL, c, ctls) {
1817  }
1819  }
1820 
1821  /* Because of the recursive descent in the AST... */
1822  pips_assert("succ has only one successor or none",
1823  gen_length(control_successors(succ))<=1);
1824 
1825  /* Let's try to use an existing node as exit node */
1826  if(gen_length(control_predecessors(succ))==1) {
1828  if(gen_length(control_successors(c))==1) {
1829  pips_debug(8, "succ has a fitting predecessor as exit.\n");
1830  exit = c;
1831  }
1832  }
1833 
1834  if(control_undefined_p(exit)) {
1835  /* A new node is needed as exit node */
1837  if(gen_length(control_predecessors(succ))==0) {
1838  /* The CFG contains an infinite loop and succ is never reached? */
1839  /* FI: we might need to check that the predecessor is not still
1840  c_res? */
1841  /* Why would we link it to succ to have it unlinked by the
1842  caller? */
1843  pips_debug(8, "succ is unreachable and a new exit node %p is created.\n",
1844  exit);
1845  }
1846  else {
1847  /* succ must be removed from the current CFG. Its predecessors within
1848  the current CFG must be moved onto the new exit node */
1849  FOREACH(CONTROL, c, control_predecessors(succ)) {
1850  /* Is c in the current CFG or in anoter one at a higher
1851  level? Typical case: the current sequence is a test branch
1852  and hence succ has two predecessors at the higher level */
1853  if(1 /*forward_control_path_p(entry, c)*/) {
1854  // FI: could we use link and unlink of control nodes?
1855  list pcl = list_undefined;
1856  for(pcl = control_successors(c); !ENDP(pcl); POP(pcl)) {
1857  control cc = CONTROL(CAR(pcl));
1858  if(cc==succ)
1859  CONTROL_(CAR(pcl))=exit;
1860  }
1862  CONS(CONTROL, c, NIL));
1863  }
1864  }
1865  //control_predecessors(exit) = control_predecessors(succ);
1866  //control_predecessors(succ) = CONS(CONTROL, exit, NIL);
1867  /* hpftest62b.f: the sequence below pulls an extra statement in
1868  the unstructured that is being built */
1869  /*
1870  statement fs = control_statement(succ);
1871  statement es = control_statement(exit);
1872  control_statement(exit) = fs;
1873  control_statement(succ) = es;
1874  */
1875  pips_debug(8, "succ is reachable thru %d control paths "
1876  "but a new exit node %p is created.\n",
1878  }
1879  }
1880 
1881  ifdebug(8) {
1882  FOREACH(CONTROL, c, ctls) {
1884  }
1886  }
1887 
1888 return exit;
1889 }
#define POP(l)
Modify a list pointer to point on the next element of the list.
Definition: newgen_list.h:59
#define list_undefined
Undefined list definition :-)
Definition: newgen_list.h:69
#define CONTROL_(x)
Definition: ri.h:913

References CAR, check_control_coherency(), CONS, CONTROL, CONTROL_, control_predecessors, control_successors, control_undefined, control_undefined_p, ENDP, exit, FOREACH, gen_length(), gen_nconc(), ifdebug, list_undefined, make_control(), make_plain_continue_statement(), NIL, pips_assert, pips_debug, and POP.

+ Here is the call graph for this function:

◆ forloop_header()

statement forloop_header ( statement  sl)
Parameters
sll

Definition at line 765 of file old_controlizer.c.

766 {
770 
771  return hs;
772 }
instruction make_instruction_expression(expression _field_)
Definition: ri.c:1196

References forloop_initialization, instruction_forloop, instruction_to_statement(), make_instruction_expression(), statement_instruction, and statement_number.

Referenced by controlize_forloop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ forloop_inc()

statement forloop_inc ( statement  sl)

ifdebug(8) {

pips_debug(8, "Increment expression: ");

print_expression(inc);

}

Parameters
sll

Definition at line 806 of file old_controlizer.c.

807 {
809  expression inc = forloop_increment(l);
812 
813  /* ifdebug(8) { */
814  /* pips_debug(8, "Increment expression: "); */
815  /* print_expression(inc); */
816  /* } */
817 
818  return is;
819 }

References forloop_increment, instruction_forloop, instruction_to_statement(), make_instruction_expression(), statement_instruction, and statement_number.

Referenced by controlize_forloop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ forloop_test()

statement forloop_test ( statement  sl)

strdup("")

ifdebug(8) {

pips_debug(8, "Condition expression: ");

print_expression(cond);

}

Parameters
sll

Definition at line 775 of file old_controlizer.c.

776 {
778  expression cond = forloop_condition(l);
781  copy_expression(cond),
782  NIL));
787  string csl = statement_comments(sl);
788  string cs = empty_comments_p(csl)? empty_comments /* strdup("") */ : strdup(csl);
789 
791  statement_number(sl),
793  cs,
796 
797  /* ifdebug(8) { */
798  /* pips_debug(8, "Condition expression: "); */
799  /* print_expression(cond); */
800  /* } */
801 
802  return ts;
803 }
call make_call(entity a1, list a2)
Definition: ri.c:269
expression make_expression(syntax a1, normalized a2)
Definition: ri.c:886
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
syntax make_syntax(enum syntax_utype tag, void *val)
Definition: ri.c:2491
bool empty_comments_p(const char *)
Definition: statement.c:107
#define C_NOT_OPERATOR_NAME
entity entity_intrinsic(const char *name)
FI: I do not understand this function name (see next one!).
Definition: entity.c:1292
#define normalized_undefined
Definition: ri.h:1745
@ is_syntax_call
Definition: ri.h:2693
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217

References C_NOT_OPERATOR_NAME, CONS, copy_expression(), copy_extensions(), empty_comments, empty_comments_p(), entity_empty_label(), entity_intrinsic(), EXPRESSION, forloop_condition, instruction_forloop, is_instruction_test, is_syntax_call, make_call(), make_expression(), make_instruction(), make_plain_continue_statement(), make_statement(), make_synchronization_none(), make_syntax(), make_test(), NIL, normalized_undefined, statement_comments, statement_extensions, statement_instruction, statement_number, STATEMENT_ORDERING_UNDEFINED, and strdup().

Referenced by controlize_forloop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_label_control()

static control get_label_control ( string  name)
static

Get the control node associated to a label name.

It looks for the label name into the Label_control table.

The name must be the complete entity name, not a local or a user name.

Parameters
[in]nameis the string name of the label entity

The label must exist in the table.

Returns
the associated control node.

Definition at line 207 of file controlizer.c.

207  {
208  control c;
209 
210  pips_assert("label is not the empty label", !empty_global_label_p(name)) ;
211  c = (control) hash_get(Label_control, name);
212  pips_assert("c is defined", c != (control) HASH_UNDEFINED_VALUE);
213  pips_assert("c is a control", check_control(c));
214  ifdebug(2) {
216  }
217  return(c);
218 }
control check_control(control p)
Definition: ri.c:493
void * hash_get(const hash_table htp, const void *key)
this function retrieves in the hash table pointed to by htp the couple whose key is equal to key.
Definition: hash.c:449
struct _newgen_struct_control_ * control
#define HASH_UNDEFINED_VALUE
value returned by hash_get() when the key is not found; could also be called HASH_KEY_NOT_FOUND,...
Definition: newgen_hash.h:56

References check_control(), check_control_coherency(), empty_global_label_p(), hash_get(), HASH_UNDEFINED_VALUE, ifdebug, Label_control, and pips_assert.

Referenced by controlize_goto().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ hcfg()

statement hcfg ( statement  st)

Compute the hierarchical control flow graph (HCFG) of a statement.

Parameters
stis the statement we want to "controlize"
Returns
the unstructured with the control graph

To help debugging, force some properties:

Initialize an empty association from label to the statements using them:

Initialize global tables:

Build the global table associating for any label all the statements that refer to it:

Construct the entry and exit control node of the unstructured to generate. First get the control node for all the code:

And make a successor node that is an empty instruction at first:

By default the entry is just connected to the exit that is the successor:

To track declaration scoping independently of control structure:

Build the HCFG from the module statement:

Since this HCFG computation is quite general, we may have really an unstructured at the top level, which is not possible when dealing from the parser output.

The 2 control nodes are indeed still a simple sequence, so it is a structured statement at the top level and it is useless to build an unstructured to store it.

Really remove the useless by contruction statement too:

For all the other case, it is not structured code at top level, so build an unstructured statement to represent it:

Clean up scoping stack:

Reset the tables used

Since the controlizer is a sensitive pass, avoid leaking basic errors...

Parameters
stt

Definition at line 2621 of file controlizer.c.

2622 {
2623  statement result;
2624 
2625  pips_assert("Statement should be OK.", statement_consistent_p(st));
2626  ifdebug(1) {
2627  /* To help debugging, force some properties: */
2628  set_bool_property("PRETTYPRINT_BLOCKS", true);
2629  set_bool_property("PRETTYPRINT_EMPTY_BLOCKS", true);
2630  }
2631 
2632  /* Initialize an empty association from label to the statements using
2633  them: */
2634  hash_table used_labels = hash_table_make(hash_string, 0);
2635 
2636  /* Initialize global tables: */
2639  /* Build the global table associating for any label all the statements
2640  that refer to it: */
2642 
2643  /* Construct the entry and exit control node of the unstructured to
2644  generate. First get the control node for all the code: */
2645  control entry = make_conditional_control(st);
2646  /* And make a successor node that is an empty instruction at first: */
2648  /* By default the entry is just connected to the exit that is the
2649  successor: */
2650  link_2_control_nodes(entry, exit);
2651 
2652  /* To track declaration scoping independently of control structure: */
2653  make_scoping_statement_stack();
2654 
2655  /* Build the HCFG from the module statement: */
2656  (void) controlize_statement(entry, exit, used_labels);
2657 
2658  /* Since this HCFG computation is quite general, we may have really an
2659  unstructured at the top level, which is not possible when dealing
2660  from the parser output. */
2661  if (gen_length(control_successors(entry)) == 1
2662  && CONTROL(CAR(control_successors(entry))) == exit) {
2663  /* The 2 control nodes are indeed still a simple sequence, so it is
2664  a structured statement at the top level and it is useless to
2665  build an unstructured to store it. */
2666  result = control_statement(entry);
2668  /* Really remove the useless by contruction statement too: */
2670  }
2671  else {
2672  /* For all the other case, it is not structured code at top level, so
2673  build an unstructured statement to represent it: */
2674  unstructured u = make_unstructured(entry, exit);
2676  }
2677 
2678  /* Clean up scoping stack: */
2679  free_scoping_statement_stack();
2680 
2681  /* Reset the tables used */
2684  hash_table_free(used_labels);
2685 
2686  /* Since the controlizer is a sensitive pass, avoid leaking basic
2687  errors... */
2688  pips_assert("Statement should be OK.", statement_consistent_p(result));
2689 
2690  return result;
2691 }
static void create_statements_of_labels(statement st)
Initialize the global Label_statements mapping for the module that associates for any label in the mo...
Definition: controlizer.c:437

◆ init_label()

static void init_label ( string  name,
statement  st 
)
static

INIT_LABEL puts the reference in the statement ST to the label NAME int the Label_statements table and allocate a slot in the Label_control table.

Just append st to the list of statements pointing to this label.

Definition at line 1769 of file old_controlizer.c.

1772 {
1773  if(!empty_global_label_p(name)) {
1775  list sts = CONS(STATEMENT, st, used);
1776  /* Just append st to the list of statements pointing to
1777  this label. */
1778  if (hash_defined_p(Label_statements, name))
1779  hash_update(Label_statements, name, sts);
1780  else
1781  hash_put(Label_statements, name, sts);
1782 
1783  if (! hash_defined_p(Label_control, name)) {
1785  control c = make_control( new_st, NIL, NIL);
1786  pips_debug(8, "control %p allocated for label \"%s\"", c, name);
1787  hash_put(Label_control, name, c);
1788  }
1789  }
1790 }
bool hash_defined_p(const hash_table htp, const void *key)
true if key has e value in htp.
Definition: hash.c:484

References CONS, empty_global_label_p(), hash_defined_p(), hash_get_default_empty_list(), hash_put(), hash_update(), Label_control, Label_statements, make_continue_statement(), make_control(), NIL, pips_debug, STATEMENT, and statement_label.

Referenced by create_statements_of_label().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ loop_header()

statement loop_header ( statement  sl)

LOOP_HEADER, LOOP_TEST and LOOP_INC build the desugaring phases of a do-loop L for the loop header (i=1), the test (i<10) and the increment (i=i+1).

Parameters
sll

Definition at line 446 of file old_controlizer.c.

447 {
448  loop l = statement_loop(sl);
450 
452 
455 
456  return hs;
457 }
statement make_assign_statement(expression, expression)
Definition: statement.c:583
expression make_entity_expression(entity e, cons *inds)
Definition: expression.c:176
#define range_lower(x)
Definition: ri.h:2288

References loop_index, loop_range, make_assign_statement(), make_entity_expression(), NIL, range_lower, statement_loop(), statement_number, and statement_undefined.

Referenced by controlize_loop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ loop_inc()

statement loop_inc ( statement  sl)
Parameters
sll

Definition at line 511 of file old_controlizer.c.

512 {
513  loop l = statement_loop(sl);
516  call c = make_call(entity_intrinsic(PLUS_OPERATOR_NAME), // Even for C code?
518  I,
521  NIL)));
522  expression I_plus_one =
526 
527  is = make_assign_statement(II, I_plus_one);
529 
530  return is;
531 }
#define PLUS_OPERATOR_NAME
#define range_increment(x)
Definition: ri.h:2292

References CONS, entity_intrinsic(), EXPRESSION, is_syntax_call, loop_index, loop_range, make_assign_statement(), make_call(), make_entity_expression(), make_expression(), make_syntax(), NIL, normalized_undefined, PLUS_OPERATOR_NAME, range_increment, statement_loop(), statement_number, and statement_undefined.

Referenced by controlize_loop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ loop_test()

statement loop_test ( statement  sl)

empty_comments

Parameters
sll

Definition at line 459 of file old_controlizer.c.

460 {
461  loop l = statement_loop(sl);
463  string cs = string_undefined;
469  NIL)));
474  string csl = statement_comments(sl);
475  string prev_comm = empty_comments_p(csl)? /* empty_comments */ strdup("") : strdup(csl);
476  const char* lab;
477 
479  lab = ""; // FI: to be replaced by a symbolic constant
480  else
481  lab = label_local_name(loop_label(l));
482 
484  switch(lt) {
485  case is_language_fortran:
487  cs = strdup(concatenate(prev_comm,
488  comment_sentinel(lt),
489  " DO loop ",
490  lab,
491  " with exit had to be desugared\n",
492  NULL));
493  break;
494  case is_language_c:
495  cs = prev_comm;
496  break;
497  default:
498  pips_internal_error("This language is not handled !");
499  break;
500  }
501 
503  statement_number(sl),
505  cs,
508  return ts;
509 }
string comment_sentinel(tag)
Start a single line comment.
Definition: statement.c:4420
enum language_utype get_prettyprint_language_tag()
Definition: language.c:67
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
int tag
TAG.
Definition: newgen_types.h:92
#define GREATER_THAN_OPERATOR_NAME
const char * label_local_name(entity e)
END_EOLE.
Definition: entity.c:604
#define range_upper(x)
Definition: ri.h:2290
@ is_language_fortran
Definition: ri.h:1566
@ is_language_fortran95
Definition: ri.h:1568
@ is_language_c
Definition: ri.h:1567

References comment_sentinel(), concatenate(), CONS, copy_extensions(), empty_comments_p(), entity_empty_label(), entity_empty_label_p(), entity_intrinsic(), EXPRESSION, get_prettyprint_language_tag(), GREATER_THAN_OPERATOR_NAME, is_instruction_test, is_language_c, is_language_fortran, is_language_fortran95, is_syntax_call, label_local_name(), loop_index, loop_label, loop_range, make_call(), make_entity_expression(), make_expression(), make_instruction(), make_plain_continue_statement(), make_statement(), make_synchronization_none(), make_syntax(), make_test(), NIL, normalized_undefined, pips_internal_error, range_upper, statement_comments, statement_extensions, statement_loop(), statement_number, STATEMENT_ORDERING_UNDEFINED, statement_undefined, strdup(), and string_undefined.

Referenced by controlize_loop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ make_conditional_control()

static control make_conditional_control ( statement  st)
static

In C, we can have some "goto" inside a block from outside, that translates as any complex control graph into an "unstructured" in the PIPS jargon.

Unfortunately, that means it break the structured block nesting that may carry declarations with the scoping information.

So we need to track this scope information independently of the control graph. This is the aim of this declaration scope stack that is used to track scoping during visiting the RI. Make a control node around a statement if not already done

It is like the make_control() constructor except when the statement st has a label and is already referenced in Label_control. Thus return the control node that already owns this statement.

Parameters
[in]stis the statement we want a control node around
Returns
the new (in the case of a statement without a label) or already associated (in the case of a statement with a label) control node with the statement inside.

It returns NULL if the statement has a label but it is not associated to any control node yet

FI: the call sites do not seem to check if c==NULL...

No label, so there cannot be a control already associated to a label

Get back the control node associated with this statement label. Since we store control object in this hash table, use cast. We rely on the fact that NIL for a list is indeed NULL...

Definition at line 173 of file controlizer.c.

173  {
174  string label = entity_name(statement_label(st));
176 
177  if (empty_global_label_p(label))
178  /* No label, so there cannot be a control already associated to a
179  label */
180  c = make_control(st, NIL, NIL);
181  else
182  /* Get back the control node associated with this statement
183  label. Since we store control object in this hash table, use
184  cast. We rely on the fact that NIL for a list is indeed
185  NULL... */
187 
188  pips_assert("c==0 || control_consistent_p(c)",
189  c==0 || control_consistent_p(c));
190 
191  return c;
192 }

References control_consistent_p(), control_undefined, empty_global_label_p(), entity_name, hash_get_default_empty_list(), Label_control, make_control(), NIL, pips_assert, and statement_label.

Referenced by controlize_forloop(), controlize_loop(), controlize_repeatloop(), controlize_sequence(), controlize_test(), controlize_whileloop(), and hcfg().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ move_declaration_control_node_declarations_to_statement()

static void move_declaration_control_node_declarations_to_statement ( list  ctls)
static

Move all the declarations found in a list of control to a given statement.

Maintain the initializations where they belong. See Control/block_scope5n.

@ctls is a list of control nodes

It is useful in the controlizer to keep scoping of declarations even with unstructured that may destroy the variable scoping rules.

If there are conflict names on declarations, they are renamed.

It relies on correct calls to push_declarations()/pop_declarations() before to track where to put the declarations.

No block statement above, so it is hard to move something there :-)

The variables created in case of name conflict

Look for conflicting names:

There is a conflict name between a declaration in the current statement block and one in the statement block above:

Create a new variable with a non conflicting name without inserting a new statement declaration which is likely to be lost because s_above is currently represented as a list of control nodes not as a standard sequence.

Add the inner declaration to the upper statement later

Remove the inner declaration from the inner statement block:

Add all the declarations to the statement block above and preserve the order:

Replace initializations in declarations by assignment statements, when possible; see split_initializations(); do not worry about variable renaming yet

If old is declared in s, its declaration must be removed and replaced if necessary by an assignment with its initial value... It seems tricky at first if many variables are declared simultaneously but is does not matter if all have to be substituted. Oops for functional declarations...

FI: it would be better to use a comma expression in order to replace a statement by a unique statement

chain icl to c, assume ctls is a list over a control sequence...

The nodes in icl must be linked together

They should be added into ctls too... because the initialization expressions may require some renaming... but nctls probably takes care of that.

Replace all references to old variables to references to the new ones in all the corresponding control nodes by in the code

We should free in some way the old variable...

Definition at line 1506 of file controlizer.c.

1506  {
1507  statement s = scoping_statement_head();
1508  list declarations = statement_declarations(s);
1509  statement s_above = scoping_statement_nth(2);
1510  list nctls = NIL; // build a new list of controls to include the
1511  // initialization statements that are derived from
1512  // the declaration statements
1513 
1514  pips_debug(2, "Dealing with block statement %p included into block"
1515  " statement %p\n", s, s_above);
1516 
1517  if (s_above == NULL)
1518  /* No block statement above, so it is hard to move something there :-) */
1519  return;
1520 
1521  list declarations_above = statement_declarations(s_above);
1522  list new_declarations = NIL;
1523  /* The variables created in case of name conflict */
1524  list new_variables = NIL;
1525  hash_table old_to_new_variables = hash_table_make(hash_chunk, 0);
1526 
1527  /* Look for conflicting names: */
1528  FOREACH(ENTITY, e, declarations) {
1529  const char * name = entity_user_name(e);
1530  bool conflict = false;
1531  FOREACH(ENTITY, e_above, declarations_above) {
1532  const char * name_above = entity_user_name(e_above);
1533  pips_debug(2, "Comparing variables %s and %s\n",
1534  entity_name(e), entity_name(e_above));
1535 
1536  if (strcmp(name, name_above) == 0) {
1537  /* There is a conflict name between a declaration in the current
1538  statement block and one in the statement block above: */
1539  conflict = true;
1540  break;
1541  }
1542  }
1543  entity v;
1544  if (conflict) {
1545  pips_debug(2, "Conflict on variable %s\n", entity_name(e));
1546 
1547  /* Create a new variable with a non conflicting name without
1548  inserting a new statement declaration which is likely to be
1549  lost because s_above is currently represented as a list of
1550  control nodes not as a standard sequence. */
1552  s_above,
1553  "",
1554  "_",
1556  false);
1557  new_variables = gen_entity_cons(v , new_variables);
1558  hash_put_or_update(old_to_new_variables, e, v);
1559  // FI: I do not understand how v can already be in
1560  // new_declarations since v has just been cloned!
1561  // if(!gen_in_list_p(v, new_declarations))
1562  // new_declarations = gen_entity_cons(v , new_declarations);
1563  // The new variable v has already been added to the declarations
1564  // of s_above. The code would be easuer to understand if e were
1565  // added to these declarations in the else clause.
1566  }
1567  else {
1568  v = e;
1569  /* Add the inner declaration to the upper statement later */
1570  new_declarations = gen_entity_cons(v , new_declarations);
1571  }
1572  }
1573 
1574  /* Remove the inner declaration from the inner statement block:
1575  */
1578 
1579  /* Add all the declarations to the statement block above and
1580  preserve the order: */
1581  new_declarations = gen_nreverse(new_declarations);
1582  statement_declarations(s_above) = gen_nconc(declarations_above,
1583  new_declarations);
1584  FOREACH(ENTITY, dv, new_variables) {
1585  // This does not seem to work because the above statement is being
1586  // controlized. Hence, the new declaration statements are simply
1587  // ignored... It might be better to rely on the block declaration
1588  // list and to fix the declarations a posteriori, maybe at the end
1589  // of controlize_statement(). The other option is to generate C99
1590  // code with declarations anywhere in the execution flow
1591  //add_declaration_statement(s_above, dv);
1592  ;
1593  }
1594 
1595  // Even with C99 code, the initializations should not be moved,
1596  // even when the initial value is numerically known. See
1597  // Control/block_scope5n. Unless the variable is static. See
1598  // Control/block_scope13.c
1599  if(true || get_bool_property("C89_CODE_GENERATION")) {
1600  /* Replace initializations in declarations by assignment
1601  statements, when possible; see split_initializations(); do not
1602  worry about variable renaming yet */
1603  FOREACH(CONTROL, c, ctls) {
1605  nctls = gen_nconc(nctls, CONS(CONTROL, c, NIL));
1606  // FI: the entity must also be substituted in the
1607  // initializations contained by the declarations. Also old
1608  // declarations must be transformed into assignments.
1609  if(declaration_statement_p(s)) {
1610  int sn = statement_number(s);
1611  list icl = NIL;
1612  /* If old is declared in s, its declaration must be removed
1613  and replaced if necessary by an assignment with its
1614  initial value... It seems tricky at first if many
1615  variables are declared simultaneously but is does not
1616  matter if all have to be substituted. Oops for
1617  functional declarations... */
1618  list dvl = statement_declarations(s);
1619  //list il = NIL; // initialization list
1620  FOREACH(ENTITY, dv, dvl) {
1621  if(!entity_static_variable_p(dv)) {
1622  value iv = entity_initial(dv);
1623  if(!value_unknown_p(iv)) {
1626  statement is = make_assign_statement(lhs, ie);
1627  statement_number(is) = sn;
1628  control ic = make_control(is, NIL, NIL);
1629  /* FI: it would be better to use a comma expression in
1630  order to replace a statement by a unique statement */
1631  nctls = gen_nconc(nctls, CONS(CONTROL, ic, NIL));
1632  icl = gen_nconc(icl, CONS(CONTROL, ic, NIL));
1633  entity n = (entity) hash_get(old_to_new_variables, (void *) dv);
1634  n = HASH_UNDEFINED_VALUE==n? dv : n;
1637  }
1638  }
1639  }
1640  /* chain icl to c, assume ctls is a list over a control sequence... */
1641  if(!ENDP(icl)) {
1642  pips_assert("c has one successor (but may be zero with"
1643  " dead code behind declarations:-(",
1645  control succ = CONTROL(CAR(control_successors(c)));
1646  control fic = CONTROL(CAR(icl));
1647  control cic = fic;
1648  control lic = CONTROL(CAR(gen_last(icl)));
1649  FOREACH(CONTROL, nc, CDR(icl)) {
1650  /* The nodes in icl must be linked together */
1651  link_2_control_nodes(cic, nc);
1652  cic = nc;
1653  }
1654  unlink_2_control_nodes(c, succ);
1655  link_2_control_nodes(c, fic);
1656  link_2_control_nodes(lic, succ);
1657  /* They should be added into ctls too... because the
1658  initialization expressions may require some
1659  renaming... but nctls probably takes care of that. */
1660  gen_free_list(icl);
1661  }
1663  }
1664  }
1665  }
1666  else
1667  nctls = gen_copy_seq(ctls);
1668 
1669  /* Replace all references to old variables to references to the new
1670  ones in all the corresponding control nodes by in the code */
1671  void * ccp = NULL; // current couple pointer
1672  entity old, new;
1673  while((ccp = hash_table_scan(old_to_new_variables, ccp, (void *) &old, (void *) &new))) {
1674  //HASH_MAP(old, new, {
1675  FOREACH(CONTROL, c, nctls) {
1677  if(true || !get_bool_property("C89_CODE_GENERATION")) { // C99 assumed
1678  if(declaration_statement_p(s)) {
1679  list dl = statement_declarations(s);
1680  list cl;
1681  for(cl=dl; !ENDP(cl); POP(cl)) {
1682  entity dv = ENTITY(CAR(cl));
1683  if(dv==old)
1684  ENTITY_(CAR(cl)) = new;
1685  }
1686  }
1687  }
1688  replace_entity(s, old, new);
1689  }
1690  /* We should free in some way the old variable... */
1691  //}, old_to_new_variables);
1692  }
1693  hash_table_free(old_to_new_variables);
1694 
1695  return;
1696 }
value make_value_unknown(void)
Definition: ri.c:2847
list gen_entity_cons(entity p, list l)
Definition: ri.c:2537
void free_value(value p)
Definition: ri.c:2787
struct _newgen_struct_entity_ * entity
Definition: abc_private.h:14
void replace_entity(void *s, entity old, entity new)
per variable version of replace_entities.
Definition: replace.c:113
bool declaration_statement_p(statement)
Had to be optimized according to Beatrice Creusillet.
Definition: statement.c:224
@ hash_chunk
Definition: newgen_hash.h:32
#define hash_put_or_update(h, k, v)
Definition: newgen_hash.h:80
const char * entity_user_name(entity e)
Since entity_local_name may contain PIPS special characters such as prefixes (label,...
Definition: entity.c:487
entity entity_to_module_entity(entity e)
Find the enclosing module of an entity.
Definition: entity.c:2053
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
bool entity_static_variable_p(entity)
return true if the entity is declared with the keyword static
Definition: variable.c:1146
expression variable_initial_expression(entity)
Returns a copy of the initial (i.e.
Definition: variable.c:1899
entity generic_clone_variable_with_unique_name(entity, statement, string, string, entity, bool)
clone a variable with a new name.
Definition: variable.c:509
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define value_unknown_p(x)
Definition: ri.h:3077
#define ENTITY_(x)
Definition: ri.h:2758
#define entity_initial(x)
Definition: ri.h:2796

References CAR, CDR, CONS, CONTROL, control_statement, control_successors, declaration_statement_p(), ENDP, ENTITY, ENTITY_, entity_initial, entity_name, entity_static_variable_p(), entity_to_expression(), entity_to_module_entity(), entity_user_name(), FOREACH, free_value(), gen_copy_seq(), gen_entity_cons(), gen_free_list(), gen_last(), gen_length(), gen_nconc(), gen_nreverse(), generic_clone_variable_with_unique_name(), get_bool_property(), hash_chunk, hash_get(), hash_put_or_update, hash_table_free(), hash_table_make(), hash_table_scan(), HASH_UNDEFINED_VALUE, link_2_control_nodes(), make_assign_statement(), make_control(), make_value_unknown(), NIL, pips_assert, pips_debug, POP, replace_entity(), statement_declarations, statement_number, unlink_2_control_nodes(), value_unknown_p, and variable_initial_expression().

Referenced by controlize_sequence().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ patch_references()

static void patch_references ( int  how,
control  fnode,
control  tnode 
)
static

PATCH_REFERENCES replaces all occurrences of FNODE by TNODE in the predecessors or successors lists of its predecessors or successors list (according to HOW, PREDS_OF_SUCCS or SUCCS_OF_PREDS).

Move all the connection of:

  • the predecessors of FNODE to point to TNODE
  • or the successors of FNODE to point from TNODE

Definition at line 185 of file old_controlizer.c.

188 {
189  MAPL(preds, {
190  control pred = CONTROL(CAR(preds));
191 
192  MAPL(succs, {
193  if(CONTROL(CAR(succs)) == fnode)
194  CONTROL_(CAR(succs)) = tnode;
195  }, (how == SUCCS_OF_PREDS) ?
196  control_successors(pred) :
197  control_predecessors(pred));
198  }, (how == SUCCS_OF_PREDS) ?
199  control_predecessors(fnode) :
200  control_successors(fnode));
201 }
#define MAPL(_map_list_cp, _code, _l)
Apply some code on the addresses of all the elements of a list.
Definition: newgen_list.h:203

References CAR, CONTROL, CONTROL_, control_predecessors, control_successors, MAPL, and SUCCS_OF_PREDS.

Referenced by controlize_list(), and controlize_list_1().

+ Here is the caller graph for this function:

◆ simplified_unstructured()

static unstructured simplified_unstructured ( control  top,
control  bottom,
control  res 
)
static

SIMPLIFIED_UNSTRUCTURED tries to get rid of top-level and useless unstructured nodes.

top is the entry node, bottom the exit node. result is ? (see assert below... Looks like it is the second node. RK)

All the comments below are from RK who is reverse engineering all that stuff... :-(

Looks like there are many memory leaks.

There are goto on the entry node:

The entry node is not a simple node sequence:

The second node has more than 1 goto on it:

Second node is not a simple node sequence:

The third node is not the exit node:

The exit node has more than 1 goto on it:

The exit node has a successor:

Here we have a sequence of 3 control node: top, res and bottom.

If the second node is an unstructured, just return it instead of top and bottom: (??? Lot of assumptions. RK)

Just keep the second node as an unstructured with only 1 control node:

Definition at line 1843 of file old_controlizer.c.

1846 {
1847  list succs;
1848  statement st;
1849  unstructured u;
1850  instruction i;
1851 
1852  ifdebug(4) {
1853  pips_debug(4, "Accessible nodes from top:\n");
1856  pips_debug(1, "Accessible nodes from bottom:\n");
1858  check_control_coherency(bottom);
1859  pips_debug(1, "Accessible nodes from res:\n");
1862  }
1863 
1864  ifdebug(1) {
1865  control_consistent_p(top);
1866 
1867  control_consistent_p(bottom);
1868  }
1869 
1870  u = make_unstructured(top, bottom);
1871 
1872  ifdebug(1) {
1874  }
1875 
1876  if(!ENDP(control_predecessors(top))) {
1877  free_control(res);
1878  /* There are goto on the entry node: */
1879  return(u);
1880  }
1881 
1882  if(gen_length(succs=control_successors(top)) != 1) {
1883  free_control(res);
1884  /* The entry node is not a simple node sequence: */
1885  return(u);
1886  }
1887 
1888  pips_assert("The successor of \"top\" is \"res\"",
1889  CONTROL(CAR(succs)) == res);
1890 
1891  if(gen_length(control_predecessors(res)) != 1) {
1892  free_control(res);
1893  /* The second node has more than 1 goto on it: */
1894  return(u);
1895  }
1896 
1897  if(gen_length(succs=control_successors(res)) != 1) {
1898  free_control(res);
1899  /* Second node is not a simple node sequence: */
1900  return(u);
1901  }
1902 
1903  if(CONTROL(CAR(succs)) != bottom) {
1904  /* The third node is not the exit node: */
1905  return(u);
1906  }
1907 
1908  if(gen_length(control_predecessors(bottom)) != 1) {
1909  free_control(res);
1910  /* The exit node has more than 1 goto on it: */
1911  return(u);
1912  }
1913 
1914  if(!ENDP(control_successors(bottom))) {
1915  free_control(res);
1916  /* The exit node has a successor: */
1917  return(u);
1918  }
1919 
1920  /* Here we have a sequence of 3 control node: top, res and
1921  bottom. */
1925  st = control_statement(res);
1926 
1928  /* If the second node is an unstructured, just return it
1929  instead of top and bottom: (??? Lot of assumptions. RK) */
1930  ifdebug(1) {
1932  }
1935  free_statement(st);
1936  return iu;
1937  }
1938 
1939  /* Just keep the second node as an unstructured with only 1
1940  control node: */
1942  ifdebug(1) {
1944  }
1945  return(u);
1946 }
#define instruction_unstructured_p(x)
Definition: ri.h:1530
#define instruction_unstructured(x)
Definition: ri.h:1532

References CAR, check_control_coherency(), CONTROL, control_consistent_p(), control_predecessors, control_statement, control_successors, display_linked_control_nodes(), ENDP, free_control(), free_statement(), gen_free_list(), gen_length(), ifdebug, instruction_unstructured, instruction_unstructured_p, make_unstructured(), NIL, pips_assert, pips_debug, statement_instruction, unstructured_consistent_p(), unstructured_control, unstructured_exit, and unstructured_undefined.

Referenced by control_graph().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ union_used_labels()

static hash_table union_used_labels ( hash_table  l1,
hash_table  l2 
)
static

Unions 2 hash maps that list statements referencing labels into one.

Parameters
[in,out]l1is the hash map used as source and target
[in]l2is the other hash map
Returns
l1 that is the union of l1 and l2 interpreted as in the context of update_used_labels()

Definition at line 270 of file controlizer.c.

271  {
272  HASH_MAP(name, sts, {
273  FOREACH(STATEMENT, s, sts) {
274  update_used_labels(l1, name, s);
275  };
276  }, l2);
277  return l1;
278 }
#define HASH_MAP(k, v, code, ht)
Definition: newgen_hash.h:60

References FOREACH, HASH_MAP, STATEMENT, and update_used_labels().

Referenced by controlize_forloop(), controlize_loop(), controlize_repeatloop(), controlize_sequence(), controlize_test(), and controlize_whileloop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_used_labels()

static void update_used_labels ( hash_table  used_labels,
string  name,
statement  st 
)
static

Mark a statement as related to a label.

A used_label is a hash_table that maps the label name to the list of statements that reference it.

A statement can appear many times for a given label

Parameters
used_labels[in,out]is the hash table used to record the statements related to a label. It is not updated for empty labels.
name[in]is the label entity name. It may be the empty label.
st[in]is the statement to be recorded as related to the label

Do something only if there is a label:

Get a previous list of statements related to this label:

Add the given statement to the list

If there was already something associated to the label, register the new list:

Or create a new entry:

FI: This debug message happens a lot after inlining? In spite of the source parsing, line numbers are not assigned?

Definition at line 235 of file controlizer.c.

237  {
238  list sts ;
239 
240  /* Do something only if there is a label: */
241  if (!empty_global_label_p(name)) {
242  list new_sts;
243  /* Get a previous list of statements related to this label: */
244  sts = hash_get_default_empty_list(used_labels, name) ;
245  /* Add the given statement to the list */
246  new_sts = CONS(STATEMENT, st, sts);
247  if (hash_defined_p(used_labels, name))
248  /* If there was already something associated to the label, register
249  the new list: */
250  hash_update(used_labels, name, new_sts);
251  else
252  /* Or create a new entry: */
253  hash_put(used_labels, name, new_sts);
254  /* FI: This debug message happens a lot after inlining? In spite
255  of the source parsing, line numbers are not assigned? */
256  pips_debug(5, "Reference to statement %d seen\n",
257  (int) statement_number( st )) ;
258  }
259 }

References CONS, empty_global_label_p(), hash_defined_p(), hash_get_default_empty_list(), hash_put(), hash_update(), pips_debug, STATEMENT, and statement_number.

Referenced by controlize_goto(), controlize_statement(), create_statements_of_label(), and union_used_labels().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ whileloop_test()

static statement whileloop_test ( statement  sl)
static

Generate a test statement ts for exiting loop sl.

There should be no sharing between sl and ts.

string prev_comm = empty_comments_p(csl)? "" : strdup(csl);

strdup("")

Definition at line 607 of file old_controlizer.c.

608 {
611  string cs = string_undefined;
612  call c = call_undefined;
613 
614  switch (get_prettyprint_language_tag()) {
615  case is_language_fortran:
619  NIL));
620  break;
621  case is_language_c:
625  NIL));
626  break;
628  pips_internal_error("Need to update F95 case");
629  break;
630  default:
631  pips_internal_error("Language unknown !");
632  break;
633  }
634 
639  string csl = statement_comments(sl);
640  /* string prev_comm = empty_comments_p(csl)? "" : strdup(csl); */
641  string prev_comm = empty_comments_p(csl)? empty_comments /* strdup("") */ : strdup(csl);
642  const char* lab ;
643 
645  switch (lt) {
646  case is_language_fortran:
649  cs = strdup(concatenate(prev_comm,
650  comment_sentinel(lt),
651  " DO WHILE loop ",
652  "with GO TO exit had to be desugared\n",
653  NULL));
654  } else {
656  cs = strdup(concatenate(prev_comm,
657  comment_sentinel(lt),
658  " DO WHILE loop ",
659  lab,
660  " with GO TO exit had to be desugared\n",
661  NULL));
662  }
663  break;
664  case is_language_c:
665  cs = prev_comm;
666  break;
667  default:
668  pips_internal_error("Language unknown !");
669  break;
670  }
671 
672 
674  statement_number(sl),
676  cs,
679 
680  return ts;
681 }
#define NOT_OPERATOR_NAME
#define call_undefined
Definition: ri.h:685

References C_NOT_OPERATOR_NAME, call_undefined, comment_sentinel(), concatenate(), CONS, copy_expression(), copy_extensions(), empty_comments, empty_comments_p(), entity_empty_label(), entity_empty_label_p(), entity_intrinsic(), EXPRESSION, get_prettyprint_language_tag(), instruction_whileloop, is_instruction_test, is_language_c, is_language_fortran, is_language_fortran95, is_syntax_call, label_local_name(), make_call(), make_expression(), make_instruction(), make_plain_continue_statement(), make_statement(), make_synchronization_none(), make_syntax(), make_test(), NIL, normalized_undefined, NOT_OPERATOR_NAME, pips_internal_error, statement_comments, statement_extensions, statement_instruction, statement_number, STATEMENT_ORDERING_UNDEFINED, statement_undefined, strdup(), string_undefined, whileloop_condition, and whileloop_label.

Referenced by controlize_whileloop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ Label_control [1/2]

hash_table Label_control
static

This maps label names to their (possible forward) control nodes.

That is each statement with a label target is in a control that owns this statement.

Since the code is analyzed from the beginning, we may have some labels that map to control node with no statement if their target statement has not been encountered yet, in the case of forward gotos for example.

Definition at line 139 of file controlizer.c.

Referenced by create_statements_of_label(), get_label_control(), hcfg(), and make_conditional_control().

◆ Label_control [2/2]

hash_table Label_control
static

LABEL_CONTROL maps label names to their (possible forward) control nodes.

Definition at line 119 of file old_controlizer.c.

Referenced by control_graph(), get_label_control(), init_label(), and make_conditional_control().

◆ Label_statements [1/2]

hash_table Label_statements
static

This maps label names to the list of statements where they appear (either as definition or reference).

This is a global table to all the module.

There are some other local tables used elsewhere in the code to have a more hierarchical owning information

Definition at line 126 of file controlizer.c.

Referenced by controlize_goto(), covers_labels_p(), create_statements_of_label(), and hcfg().

◆ Label_statements [2/2]

hash_table Label_statements
static

LABEL_STATEMENTS maps label names to the list of statements where they appear (either as definition or reference).

Definition at line 114 of file old_controlizer.c.

Referenced by control_graph(), covers_labels_p(), and init_label().

◆ Unreachable

list Unreachable
static

UNREACHABLE is the hook used as a predecessor of statements that are following a goto.

The list of unreachable statements is kept in the successors list.

Definition at line 109 of file old_controlizer.c.

Referenced by control_graph(), and controlize_list_1().