Do constant propagation of instantiated FBs, so that variable sized arrays can be declared in FBs too.
authormjsousa
Sun, 11 Jan 2015 20:49:55 +0000
changeset 988 3b12a6cf9fbd
parent 987 562b67922966
child 989 d4f8931d80cd
Do constant propagation of instantiated FBs, so that variable sized arrays can be declared in FBs too.
stage3/constant_folding.cc
stage3/constant_folding.hh
--- a/stage3/constant_folding.cc	Sun Jan 11 19:44:37 2015 +0000
+++ b/stage3/constant_folding.cc	Sun Jan 11 20:49:55 2015 +0000
@@ -1241,7 +1241,8 @@
     current_configuration = NULL;
     fixed_init_value_ = false;
     function_pou_ = false;
-}
+    values = NULL;
+  }
 
 
 constant_propagation_c::~constant_propagation_c(void) {}
@@ -1385,16 +1386,16 @@
 #if DO_CONSTANT_PROPAGATION__
 void *constant_propagation_c::visit(symbolic_variable_c *symbol) {
 	std::string varName = get_var_name_c::get_name(symbol->var_name)->value;
-	if (values.count(varName) > 0) 
-		symbol->const_value = values[varName];
+	if (values->count(varName) > 0) 
+		symbol->const_value = (*values)[varName];
 	return NULL;
 }
 #endif  // DO_CONSTANT_PROPAGATION__
 
 void *constant_propagation_c::visit(symbolic_constant_c *symbol) {
 	std::string varName = get_var_name_c::get_name(symbol->var_name)->value;
-	if (values.count(varName) > 0) 
-		symbol->const_value = values[varName];
+	if (values->count(varName) > 0) 
+		symbol->const_value = (*values)[varName];
 	return NULL;
 }
 
@@ -1410,7 +1411,7 @@
   return NULL;
 }
 
-void *constant_propagation_c::handle_var_list_decl(symbol_c *var_list, symbol_c *type_decl) {
+void *constant_propagation_c::handle_var_list_decl(symbol_c *var_list, symbol_c *type_decl, bool is_global_var) {
   type_decl->accept(*this);  // Do constant folding of the initial value, and literals in subranges! (we will probably be doing this multiple times for the same init value, but this is safe as the cvalue is idem-potent)
   symbol_c *init_value = type_initial_value_c::get(type_decl);  
   if (NULL == init_value)   {return NULL;} // this is probably a FB datatype, for which no initial value exists! Do nothing and return.
@@ -1428,7 +1429,11 @@
     }
     list->elements[i]->const_value = init_value->const_value;
     if (fixed_init_value_) {
-      values[var_name->value] = init_value->const_value;
+      (*values)[var_name->value] = init_value->const_value;
+      if (is_global_var)
+        // also store it in the var_global_values map!!
+        // Notice that global variables are also placed in the values map!!
+        var_global_values[var_name->value] = init_value->const_value;
     }
   }
   return NULL;
@@ -1462,7 +1467,23 @@
 //SYM_REF2(structured_var_init_decl_c, var1_list, initialized_structure) // We do not yet handle structures!
 
 /* fb_name_list ':' function_block_type_name ASSIGN structure_initialization */
-//SYM_REF2(fb_name_decl_c, fb_name_list, fb_spec_init)                   // We do not yet handle FBs!
+//SYM_REF2(fb_name_decl_c, fb_name_list, fb_spec_init)
+void *constant_propagation_c::visit(fb_name_decl_c *symbol) {
+  /* A FB has been instantiated inside the POU currently being analysed. We must therefore visit this FB's type declaration
+   *  and give a chance of the VAR_EXTERNs in that FB to get the const values from the global variables currently in scope!
+   */
+  /* find the declaration (i.e. the datatype) of the FB being instantiated */
+  // NOTE: we do not use symbol->datatype so this const propagation algorithm will not depend on the fill/narrow datatypes algorithm!
+  symbol_c *fb_type_name = spec_init_sperator_c::get_spec(symbol->fb_spec_init);
+  function_block_type_symtable_t::iterator itr = function_block_type_symtable.find(fb_type_name);
+  if (itr == function_block_type_symtable.end()) ERROR; // syntax parsing should not allow this!
+  function_block_declaration_c *fb_type = itr->second;
+  if (NULL == fb_type) ERROR; // syntax parsing should not allow this!
+  // TODO: detect whether we are already currently visiting this exact same FB declaration (possible with -p option), so we do not get into an infinite loop!!
+  fb_type->accept(*this);
+  return NULL;
+}
+
 
 /* fb_name_list ',' fb_name */
 //SYM_LIST(fb_name_list_c)                                               // Not needed!
@@ -1565,8 +1586,8 @@
   
   symbol->global_var_name->const_value = symbol->specification->const_value;
   if (fixed_init_value_) {
-//  values[symbol->global_var_name->get_value()] = symbol->specification->const_value;
-    values[get_var_name_c::get_name(symbol->global_var_name)->value] = symbol->specification->const_value;
+//  (*values)[symbol->global_var_name->get_value()] = symbol->specification->const_value;
+    (*values)[get_var_name_c::get_name(symbol->global_var_name)->value] = symbol->specification->const_value;
   }
   // If the datatype specification is a subrange or array, do constant folding of all the literals in that type declaration... (ex: literals in array subrange limits)
   symbol->specification->accept(*this);  // should never get to change the const_value of the symbol->specification symbol (only its children!).
@@ -1615,11 +1636,11 @@
   global_var_spec_c *var_spec = dynamic_cast<global_var_spec_c *>(symbol->global_var_spec);
   if (NULL == var_spec) {
     // global_var_spec is a global_var_list_c
-    return handle_var_list_decl(symbol->global_var_spec, symbol->type_specification);
+    return handle_var_list_decl(symbol->global_var_spec, symbol->type_specification, true /* is global */);
   } else {
     global_var_list_c var_list;
     var_list.add_element(var_spec->global_var_name);
-    return handle_var_list_decl(&var_list, symbol->type_specification);
+    return handle_var_list_decl(&var_list, symbol->type_specification, true /* is global */);
   }
 }
 
@@ -1679,12 +1700,19 @@
 /* enumvalue_symtable is filled in by enum_declaration_check_c, during stage3 semantic verification, with a list of all enumerated constants declared inside this POU */
 //SYM_REF4(function_declaration_c, derived_function_name, type_name, var_declarations_list, function_body, enumvalue_symtable_t enumvalue_symtable;)
 void *constant_propagation_c::visit(function_declaration_c *symbol) {
-	values.clear(); /* Clear global map */
+	map_values_t local_values, *prev_pou_values;
+	prev_pou_values = values; // store the current values map of whoever called this Function (a program, configuration, or resource)
+	values = &local_values;
+	var_global_values.push(); /* Create inner scope - Not really needed, but do it just to be consistent. */
+
 	/* Add initial value of all declared variables into Values map. */
 	function_pou_ = true;
 	symbol->var_declarations_list->accept(*this);
 	function_pou_ = false;
 	symbol->function_body->accept(*this);
+
+	var_global_values.pop(); /* Delete inner scope */
+	values = prev_pou_values;
 	return NULL;
 }
 
@@ -1712,11 +1740,18 @@
 /* enumvalue_symtable is filled in by enum_declaration_check_c, during stage3 semantic verification, with a list of all enumerated constants declared inside this POU */
 //SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body, enumvalue_symtable_t enumvalue_symtable;)
 void *constant_propagation_c::visit(function_block_declaration_c *symbol) {
-	values.clear(); /* Clear global map */
+	map_values_t local_values, *prev_pou_values;
+	prev_pou_values = values; // store the current values map of whoever instantited this FB (a program, configuration, or resource)
+	values = &local_values;
+	var_global_values.push(); /* Create inner scope */
+
 	/* Add initial value of all declared variables into Values map. */
 	function_pou_ = false;
 	symbol->var_declarations->accept(*this);
 	symbol->fblock_body->accept(*this);
+
+	var_global_values.pop(); /* Delete inner scope */
+	values = prev_pou_values;
 	return NULL;
 }
 
@@ -1739,11 +1774,18 @@
 /*  PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */
 //SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body, enumvalue_symtable_t enumvalue_symtable;)
 void *constant_propagation_c::visit(program_declaration_c *symbol) {
-	values.clear(); /* Clear global map */
+	map_values_t local_values, *prev_pou_values;
+	prev_pou_values = values; // store the current values map of whoever instantited this Program (a configuration, or resource)
+	values = &local_values;
+	var_global_values.push(); /* Create inner scope */
+
 	/* Add initial value of all declared variables into Values map. */
 	function_pou_ = false;
 	symbol->var_declarations->accept(*this);
 	symbol->function_block_body->accept(*this);
+
+	var_global_values.pop(); /* Delete inner scope */
+	values = prev_pou_values;
 	return NULL;
 }
 
@@ -1764,13 +1806,17 @@
 // SYM_REF5(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, 
 //          enumvalue_symtable_t enumvalue_symtable; localvar_symbmap_t localvar_symbmap; localvar_symbvec_t localvar_symbvec;)
 void *constant_propagation_c::visit(configuration_declaration_c *symbol) {
-	values.clear(); /* Clear global map */
+	map_values_t local_values;
+	values = &local_values;
+	var_global_values.clear(); /* Clear global variables map */
 
 	/* Add initial value of all declared variables into Values map. */
 	function_pou_ = false;
 	current_configuration = symbol;
 	iterator_visitor_c::visit(symbol); // let the base iterator class handle the rest (basically iterate through the whole configuration and do the constant folding!
 	current_configuration = NULL;
+
+	values = NULL;
 	return NULL;
 }
 
@@ -1788,21 +1834,20 @@
 // SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration, 
 //          enumvalue_symtable_t enumvalue_symtable; localvar_symbmap_t localvar_symbmap; localvar_symbvec_t localvar_symbvec;)
 void *constant_propagation_c::visit(resource_declaration_c *symbol) {
-	values.push(); /* Create inner scope */
+	var_global_values.push(); /* Create inner scope */
+	values->push(); /* Create inner scope */
 
 	/* Add initial value of all declared variables into Values map. */
 	function_pou_ = false;
 	symbol->global_var_declarations->accept(*this);
 
-	var_global_values = values;
-	values.clear();
 	current_resource = symbol;
 	symbol->resource_declaration->accept(*this);
 	current_resource = NULL;
-	values = var_global_values;
 // 	iterator_visitor_c::visit(symbol); // let the base iterator class handle the rest (basically iterate through the whole configuration and do the constant folding!
 
-	values.pop(); /* Delete inner scope */
+	var_global_values.pop(); /* Delete inner scope */
+	values->pop(); /* Delete inner scope */
 	return NULL;
 }
 
@@ -1915,7 +1960,7 @@
 	symbol->r_exp->accept(*this);
 	symbol->l_exp->accept(*this); // if the lvalue has an array, do contant folding of the array indexes!
 	symbol->l_exp->const_value = symbol->r_exp->const_value;
-	values[get_var_name_c::get_name(symbol->l_exp)->value] = symbol->l_exp->const_value;
+	(*values)[get_var_name_c::get_name(symbol->l_exp)->value] = symbol->l_exp->const_value;
 	return NULL;
 }
 
@@ -1957,7 +2002,7 @@
 	values_incoming = values; /* save incoming status */
 	symbol->beg_expression->accept(*this);
 	symbol->end_expression->accept(*this);
-	values[get_var_name_c::get_name(symbol->control_variable)->value]._int64.status = const_value_c::cs_non_const;
+	(*values)[get_var_name_c::get_name(symbol->control_variable)->value]._int64.status = const_value_c::cs_non_const;
 
 	/* Optimize dead code */
 	if (NULL != symbol->by_expression) {
--- a/stage3/constant_folding.hh	Sun Jan 11 19:44:37 2015 +0000
+++ b/stage3/constant_folding.hh	Sun Jan 11 20:49:55 2015 +0000
@@ -210,9 +210,9 @@
   private:
     symbol_c *current_resource;
     symbol_c *current_configuration;
-    map_values_t values;
+    map_values_t *values;
     map_values_t var_global_values;
-    void *handle_var_list_decl(symbol_c *var_list, symbol_c *type_decl);
+    void *handle_var_list_decl(symbol_c *var_list, symbol_c *type_decl, bool is_global_var = false);
     void *handle_var_decl     (symbol_c *var_list, bool fixed_init_value);
     // Flag to indicate whether the variables in the variable declaration list will always have a fixed value when the POU is executed!
     // VAR CONSTANT ... END_VAR will always be true
@@ -251,6 +251,7 @@
     void *visit(  external_declaration_c     *symbol);
     void *visit(global_var_decl_c            *symbol);
     void *visit( var1_init_decl_c            *symbol);
+    void *visit(   fb_name_decl_c            *symbol);
 
     /**************************************/
     /* B.1.5 - Program organization units */