stage3/constant_folding.cc
changeset 982 760b26477193
parent 981 aad6aa35ce60
child 983 ead554e12195
equal deleted inserted replaced
981:aad6aa35ce60 982:760b26477193
   801 #endif
   801 #endif
   802 
   802 
   803 
   803 
   804 
   804 
   805 constant_folding_c::constant_folding_c(symbol_c *symbol) {
   805 constant_folding_c::constant_folding_c(symbol_c *symbol) {
       
   806     current_resource = NULL;
       
   807     current_configuration = NULL;
   806     fixed_init_value_ = false;
   808     fixed_init_value_ = false;
   807     function_pou_ = false;
   809     function_pou_ = false;
   808     error_count = 0;
   810     error_count = 0;
   809     warning_found = false;
   811     warning_found = false;
   810     current_display_error_level = 0;
   812     current_display_error_level = 0;
   828 
   830 
   829 int constant_folding_c::get_error_count() {
   831 int constant_folding_c::get_error_count() {
   830 	return error_count;
   832 	return error_count;
   831 }
   833 }
   832 
   834 
       
   835 
       
   836 /***************************/
       
   837 /* B 0 - Programming Model */
       
   838 /***************************/
       
   839 /* 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 */
       
   840 // SYM_LIST(library_c, enumvalue_symtable_t enumvalue_symtable;)
       
   841   /* The constant propagation algorithm propagates the constant values to all the locations
       
   842    * in the code where expressions can be determined to have a fixed value.
       
   843    *  e.g.:   var1 := 99;
       
   844    *          var2[var1] := 42; <-- with constant propagation, we know we are accessing var2[99] here!
       
   845    * 
       
   846    * An important question in constant propagation is whether we should use the values of 
       
   847    * VAR_GLOBAL CONSTANT variables as a constant. The problem here is that the 
       
   848    * constant value of each global variable can only be declared in a configuration,
       
   849    * but a POU may eventually be used from different configurations.
       
   850    * 
       
   851    * For example:
       
   852    *     CONFIGURATION conf1
       
   853    *       VAR_GLOBAL CONSTANT global_const : INT := 42; END_VAR
       
   854    *       PROGRAM prog1 WITH TaskX : Prog1_t;
       
   855    *     END_CONFIGURATION
       
   856    * 
       
   857    *     CONFIGURATION conf2
       
   858    *       VAR_GLOBAL CONSTANT global_const : INT := 18; END_VAR
       
   859    *       PROGRAM prog1 WITH TaskX : Prog1_t;
       
   860    *     END_CONFIGURATION
       
   861    * 
       
   862    *     PROGRAM Prog1_t
       
   863    *      VAR_EXTERN COSNTANT  global_const : INT; END_VAR  <--- NOTE: 61131-3 syntax does not allow const value to be set here!
       
   864    *      VAR .... END_VAR
       
   865    *       array_var[global_const] := 0;
       
   866    *     END_PROGRAM
       
   867    * 
       
   868    *  Considering the above code, where Prog1_t is instanciated in both conf1 and conf2,
       
   869    *  and therefore where the 'constant' var_global may actually take two possible values
       
   870    *  (42 and 18), it would be incorrect to consider the var_global variable a constant in
       
   871    *  the constant propagation algorithm.
       
   872    *  This means that when doing constant propagation of the Prog1_t POU, we should consider
       
   873    *  all global variables (including the 'constant') as non-constant - this actually makes
       
   874    *  the algorithm much easier!).
       
   875    * 
       
   876    *  However, matiec has implemented an extension where we allow arrays whose size may be 
       
   877    *  defined using symbolic variables, whose value can be determined at compile time 
       
   878    *  (typically VAR CONSTANT variables). To really become usefull, this extension must allow
       
   879    *  the same var_global constant to be used in declaring arrays in both configuration as
       
   880    *  well as in some other POUs.
       
   881    * 
       
   882    *   e.g.:
       
   883    *     CONFIGURATION conf2
       
   884    *       VAR_GLOBAL CONSTANT global_const : INT := 18; END_VAR
       
   885    *       VAR_GLOBAL          global_array : ARRAY [1..global_const] OF INT; END_VAR
       
   886    *       PROGRAM prog1 WITH TaskX : Prog1_t;
       
   887    *     END_CONFIGURATION
       
   888    * 
       
   889    *     PROGRAM Prog1_t
       
   890    *      VAR_EXTERN COSNTANT  global_const : INT; END_VAR  <--- NOTE: 61131-3 syntax does not allow const value to be set here!
       
   891    *      VAR_EXTERN           global_array : ARRAY [1..global_const] OF INT; END_VAR
       
   892    *      VAR .... END_VAR
       
   893    *       global_array[global_const] := 0;
       
   894    *     END_PROGRAM
       
   895    * 
       
   896    * The above requirement means that we MUST therefore do the propagation of constant values
       
   897    * from a var_global constant to the corresponding var_external in the POUs. 
       
   898    * This implies 3 things:
       
   899    *   1) We must detect when two configurations use the same POU and set distinct values
       
   900    *       to the same var_global - we emit a warning/error (which should we emit?)
       
   901    *   2) Even if each POU is used by only one configuration, we must warn the user that
       
   902    *       the generated code may not be safely turned into a library to be later linked
       
   903    *       to other configurations
       
   904    *   3) To do the propagation of the var_global const value to the var_external,
       
   905    *       we must first analyse all the configurations in the library. 
       
   906    *       - When analysing a configuration, we store all the constant values in the 
       
   907    *         global_values[] map, and call from within the configuration context all the POUs
       
   908    *         instantiated inside this configuration (basically, we do the constant propagation 
       
   909    *         of each POU with the global_values[] map preloaded with all the constant values).
       
   910    *         This means that we may evetually do constant folding of the same POU type multiple
       
   911    *         times (if it is instantiated multiple times in the same configuration, or once
       
   912    *         in several configurations). This should not be a problem because the constant
       
   913    *         propagation algorithm is idem-potent (assuming the same constant values in the 
       
   914    *         beginning), and we can use these multiple calls to the same POU to detect if
       
   915    *         the situation mentioned in (1) is ocurring.
       
   916    *       - After analysing all the configurations, we analyse all the other POUs that have
       
   917    *         not yet been called (because they are not instantiated directly from within
       
   918    *         any configuration - e.g. functions, and most FBs!).
       
   919    *       It is for this reason (3) why we have the two loops on the following code!
       
   920    */
       
   921 void *constant_folding_c::visit(library_c *symbol) {
       
   922   int i;
       
   923   
       
   924   for (i = 0; i < symbol->n; i++) {
       
   925     // first analyse the configurations
       
   926     if (NULL != dynamic_cast<configuration_declaration_c *>(symbol->elements[i]))
       
   927       symbol->elements[i]->accept(*this);
       
   928   }
       
   929 
       
   930   for (i = 0; i < symbol->n; i++) {
       
   931     /* NOTE: we will be re-visiting all the POUs that were already called indirectly through the
       
   932      *       visit(program_configuration_c) of vist(fb_task_c) visitors during the previous for
       
   933      *       loop. However, this is OK as the only difference would be how the VAR_EXTERN are handled,
       
   934      *       and that is taken care of in the visit(external_declaration_c) visitor!
       
   935      */
       
   936     if (NULL == dynamic_cast<configuration_declaration_c *>(symbol->elements[i]))
       
   937       symbol->elements[i]->accept(*this);
       
   938   }
       
   939   
       
   940   return NULL;
       
   941 }
   833 
   942 
   834 /*********************/
   943 /*********************/
   835 /* B 1.2 - Constants */
   944 /* B 1.2 - Constants */
   836 /*********************/
   945 /*********************/
   837 /******************************/
   946 /******************************/
  1006 
  1115 
  1007 
  1116 
  1008 /******************************************/
  1117 /******************************************/
  1009 /* B 1.4.3 - Declaration & Initialisation */
  1118 /* B 1.4.3 - Declaration & Initialisation */
  1010 /******************************************/
  1119 /******************************************/
  1011 
       
  1012 /* Do the constant folding for VAR_EXTERNAL and VAR_GLOBAL pairs.
       
  1013  *  This function is called from the declaration_check_c, since it has easy access to the extern<->global pairing information
       
  1014  *  needed for this function to work.
       
  1015  */
       
  1016 int constant_folding_c::handle_var_extern_global_pair(symbol_c *extern_var_name, symbol_c *extern_var_decl, symbol_c *global_var_name, symbol_c *global_var_decl) {  
       
  1017   // the minimum infor we must get to make sense
       
  1018   if (NULL == global_var_decl) ERROR;
       
  1019   if (NULL == extern_var_name) ERROR;
       
  1020   
       
  1021   symbol_c *init_value = type_initial_value_c::get(global_var_decl);  
       
  1022   if (NULL == init_value)   return 0; // this is probably a FB datatype, for which no initial value exists! Do nothing and return.
       
  1023   
       
  1024   // Do constant folding of the initial value!
       
  1025   //   This is required since this function may be called before we do the iterative constant folding of the complete library!
       
  1026   init_value->accept(*this);  
       
  1027   
       
  1028   if (NULL != extern_var_name) extern_var_name->const_value = init_value->const_value;
       
  1029   if (NULL != extern_var_decl) extern_var_decl->const_value = init_value->const_value;  // Note that each external variable declaration has its own datatype specification, so we can set this symbol's const_value too!
       
  1030   // we could leave the constant folding of the global variable itself for later, when we iteratively visit the whole library, but there is nor harm in doing it now!
       
  1031   if (NULL != global_var_name) global_var_name->const_value = init_value->const_value;
       
  1032   if (NULL != global_var_decl) global_var_decl->const_value = init_value->const_value;  // Note that each external variable declaration has its own datatype specification, so we can set this symbol's const_value too!
       
  1033   return 0;
       
  1034 }
       
  1035 
       
  1036 
       
  1037   
  1120   
  1038 void *constant_folding_c::handle_var_decl(symbol_c *var_list, bool fixed_init_value) {
  1121 void *constant_folding_c::handle_var_decl(symbol_c *var_list, bool fixed_init_value) {
  1039   fixed_init_value_ = fixed_init_value;
  1122   fixed_init_value_ = fixed_init_value;
  1040   var_list->accept(*this); 
  1123   var_list->accept(*this); 
  1041   fixed_init_value_ = false; 
  1124   fixed_init_value_ = false; 
  1165 // void *constant_folding_c::visit(external_declaration_list_c *symbol) {} // Not needed: we inherit from iterator_c
  1248 // void *constant_folding_c::visit(external_declaration_list_c *symbol) {} // Not needed: we inherit from iterator_c
  1166 
  1249 
  1167 /*  global_var_name ':' (simple_specification|subrange_specification|enumerated_specification|array_specification|prev_declared_structure_type_name|function_block_type_name */
  1250 /*  global_var_name ':' (simple_specification|subrange_specification|enumerated_specification|array_specification|prev_declared_structure_type_name|function_block_type_name */
  1168 //SYM_REF2(external_declaration_c, global_var_name, specification)
  1251 //SYM_REF2(external_declaration_c, global_var_name, specification)
  1169 void *constant_folding_c::visit(external_declaration_c *symbol) {
  1252 void *constant_folding_c::visit(external_declaration_c *symbol) {
  1170   // Note that specification->const_value will have been set by handle_var_extern_global_pair(), which is called from declaration_check_c
  1253   // The syntax does not allow VAR_EXTERN to be initialized. We must get the initial value from the corresponding VAR_GLOBAL declaration
       
  1254   /* However, we only do this is if the visit() method for the Program/FB in which this VAR_EXTERN is found was called from the visit(configurtion/resource) visitor!
       
  1255    * When we are called from the visit(library_c) visitor, we do not have the required information to do this!
       
  1256    */ 
       
  1257   if (NULL != current_configuration)
       
  1258     symbol->specification->const_value = var_global_values[get_var_name_c::get_name(symbol->global_var_name)->value];
       
  1259   
  1171   symbol->global_var_name->const_value = symbol->specification->const_value;
  1260   symbol->global_var_name->const_value = symbol->specification->const_value;
  1172   if (fixed_init_value_) {
  1261   if (fixed_init_value_) {
       
  1262 //  values[symbol->global_var_name->get_value()] = symbol->specification->const_value;
  1173     values[get_var_name_c::get_name(symbol->global_var_name)->value] = symbol->specification->const_value;
  1263     values[get_var_name_c::get_name(symbol->global_var_name)->value] = symbol->specification->const_value;
  1174   }
  1264   }
  1175   // 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)
  1265   // 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)
  1176   symbol->specification->accept(*this);  // should never get to change the const_value of the symbol->specification symbol (only its children!).
  1266   symbol->specification->accept(*this);  // should never get to change the const_value of the symbol->specification symbol (only its children!).
  1177   return NULL;
  1267   return NULL;
  1367 /* 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 */
  1457 /* 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 */
  1368 // SYM_REF5(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, 
  1458 // SYM_REF5(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, 
  1369 //          enumvalue_symtable_t enumvalue_symtable; localvar_symbmap_t localvar_symbmap; localvar_symbvec_t localvar_symbvec;)
  1459 //          enumvalue_symtable_t enumvalue_symtable; localvar_symbmap_t localvar_symbmap; localvar_symbvec_t localvar_symbvec;)
  1370 void *constant_folding_c::visit(configuration_declaration_c *symbol) {
  1460 void *constant_folding_c::visit(configuration_declaration_c *symbol) {
  1371 	values.clear(); /* Clear global map */
  1461 	values.clear(); /* Clear global map */
       
  1462 
  1372 	/* Add initial value of all declared variables into Values map. */
  1463 	/* Add initial value of all declared variables into Values map. */
  1373 	function_pou_ = false;
  1464 	function_pou_ = false;
  1374 	return iterator_visitor_c::visit(symbol); // let the base iterator class handle the rest (basically iterate through the whole configuration and do the constant folding!
  1465 	current_configuration = symbol;
       
  1466 	iterator_visitor_c::visit(symbol); // let the base iterator class handle the rest (basically iterate through the whole configuration and do the constant folding!
       
  1467 	current_configuration = NULL;
       
  1468 	return NULL;
  1375 }
  1469 }
  1376 
  1470 
  1377 
  1471 
  1378 /* helper symbol for configuration_declaration */
  1472 /* helper symbol for configuration_declaration */
  1379 // SYM_LIST(resource_declaration_list_c)           // Not needed: we inherit from iterator_c
  1473 // SYM_LIST(resource_declaration_list_c)           // Not needed: we inherit from iterator_c
  1387 /* 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 */
  1481 /* 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 */
  1388 // SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration, 
  1482 // SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration, 
  1389 //          enumvalue_symtable_t enumvalue_symtable; localvar_symbmap_t localvar_symbmap; localvar_symbvec_t localvar_symbvec;)
  1483 //          enumvalue_symtable_t enumvalue_symtable; localvar_symbmap_t localvar_symbmap; localvar_symbvec_t localvar_symbvec;)
  1390 void *constant_folding_c::visit(resource_declaration_c *symbol) {
  1484 void *constant_folding_c::visit(resource_declaration_c *symbol) {
  1391 	values.push(); /* Create inner scope */
  1485 	values.push(); /* Create inner scope */
       
  1486 
  1392 	/* Add initial value of all declared variables into Values map. */
  1487 	/* Add initial value of all declared variables into Values map. */
  1393 	function_pou_ = false;
  1488 	function_pou_ = false;
  1394 	iterator_visitor_c::visit(symbol); // let the base iterator class handle the rest (basically iterate through the whole configuration and do the constant folding!
  1489 	symbol->global_var_declarations->accept(*this);
       
  1490 
       
  1491 	var_global_values = values;
       
  1492 	values.clear();
       
  1493 	current_resource = symbol;
       
  1494 	symbol->resource_declaration->accept(*this);
       
  1495 	current_resource = NULL;
       
  1496 	values = var_global_values;
       
  1497 // 	iterator_visitor_c::visit(symbol); // let the base iterator class handle the rest (basically iterate through the whole configuration and do the constant folding!
       
  1498 
  1395 	values.pop(); /* Delete inner scope */
  1499 	values.pop(); /* Delete inner scope */
  1396 	return NULL;
  1500 	return NULL;
  1397 }
  1501 }
  1398 
  1502 
  1399 
  1503 
  1400 
  1504 
  1401 /* task_configuration_list program_configuration_list */
  1505 /* task_configuration_list program_configuration_list */
  1402 // SYM_REF2(single_resource_declaration_c, task_configuration_list, program_configuration_list)
  1506 // SYM_REF2(single_resource_declaration_c, task_configuration_list, program_configuration_list)
       
  1507 
  1403 /* helper symbol for single_resource_declaration */
  1508 /* helper symbol for single_resource_declaration */
  1404 // SYM_LIST(task_configuration_list_c)
  1509 // SYM_LIST(task_configuration_list_c)
  1405 /* helper symbol for single_resource_declaration */
  1510 /* helper symbol for single_resource_declaration */
  1406 // SYM_LIST(program_configuration_list_c)
  1511 // SYM_LIST(program_configuration_list_c)
  1407 /* helper symbol for: (access_path, instance_specific_init) */
  1512 /* helper symbol for: (access_path, instance_specific_init) */
  1412 // SYM_REF2(program_output_reference_c, program_name, symbolic_variable)
  1517 // SYM_REF2(program_output_reference_c, program_name, symbolic_variable)
  1413 /*  TASK task_name task_initialization */
  1518 /*  TASK task_name task_initialization */
  1414 // SYM_REF2(task_configuration_c, task_name, task_initialization)
  1519 // SYM_REF2(task_configuration_c, task_name, task_initialization)
  1415 /*  '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' */
  1520 /*  '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' */
  1416 // SYM_REF3(task_initialization_c, single_data_source, interval_data_source, priority_data_source)
  1521 // SYM_REF3(task_initialization_c, single_data_source, interval_data_source, priority_data_source)
       
  1522 
  1417 /*  PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] */
  1523 /*  PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] */
  1418 /* NOTE: The parameter 'called_prog_declaration'is used to pass data between stage 3 and stage4 */
  1524 /* NOTE: The parameter 'called_prog_declaration'is used to pass data between stage 3 and stage4 */
  1419 // SYM_REF5(program_configuration_c, retain_option, program_name, task_name, program_type_name, prog_conf_elements,
  1525 // SYM_REF5(program_configuration_c, retain_option, program_name, task_name, program_type_name, prog_conf_elements,
  1420 //          symbol_c *called_prog_declaration;)
  1526 //          symbol_c *called_prog_declaration;)
       
  1527 void *constant_folding_c::visit(program_configuration_c *symbol) {
       
  1528 	/* find the declaration (i.e. the datatype) of the program being instantiated */
       
  1529 	// NOTE: we do not use symbol->datatype so this cost propagation algorithm will not depend on the fill/narrow datatypes algorithm!
       
  1530 	program_type_symtable_t::iterator itr = program_type_symtable.find(symbol->program_type_name);
       
  1531 	if (itr == program_type_symtable.end()) ERROR; // syntax parsing should not allow this!
       
  1532 	program_declaration_c *prog_type = itr->second;
       
  1533 	if (NULL == prog_type) ERROR; // syntax parsing should not allow this!
       
  1534 	prog_type->accept(*this);
       
  1535 
       
  1536 	if (NULL != symbol->prog_conf_elements)
       
  1537 		symbol->prog_conf_elements->accept(*this);
       
  1538 	return NULL;
       
  1539 }
       
  1540 
       
  1541 
  1421 /* prog_conf_elements ',' prog_conf_element */
  1542 /* prog_conf_elements ',' prog_conf_element */
  1422 // SYM_LIST(prog_conf_elements_c)
  1543 // SYM_LIST(prog_conf_elements_c)
       
  1544 
  1423 /*  fb_name WITH task_name */
  1545 /*  fb_name WITH task_name */
  1424 // SYM_REF2(fb_task_c, fb_name, task_name)
  1546 // SYM_REF2(fb_task_c, fb_name, task_name)
       
  1547 void *constant_folding_c::visit(fb_task_c *symbol) {
       
  1548 	/* find the declaration (i.e. the datatype) of the FB being instantiated */
       
  1549 	// NOTE: we do not use symbol->datatype so this cost propagation algorithm will not depend on the fill/narrow datatypes algorithm!
       
  1550 	symbol_c *fb_type_name = NULL;
       
  1551 	
       
  1552 	if ((NULL == fb_type_name) && (NULL != current_configuration)) {
       
  1553 		search_var_instance_decl_c search_scope(current_configuration);
       
  1554 		fb_type_name = search_scope.get_decl(symbol->fb_name);
       
  1555 	}
       
  1556 	if ((NULL == fb_type_name) && (NULL != current_resource)) {
       
  1557 		search_var_instance_decl_c search_scope(current_resource);
       
  1558 		fb_type_name = search_scope.get_decl(symbol->fb_name);
       
  1559 	}
       
  1560 	if (NULL == fb_type_name) ERROR;
       
  1561 	
       
  1562 	function_block_type_symtable_t::iterator itr = function_block_type_symtable.find(fb_type_name);
       
  1563 	if (itr == function_block_type_symtable.end()) ERROR; // syntax parsing should not allow this!
       
  1564 	function_block_declaration_c *fb_type_decl = itr->second;
       
  1565 	if (NULL == fb_type_decl) ERROR;	
       
  1566 	fb_type_decl->accept(*this);
       
  1567 	return NULL;
       
  1568 }
       
  1569 
       
  1570 
       
  1571 
  1425 /*  any_symbolic_variable ASSIGN prog_data_source */
  1572 /*  any_symbolic_variable ASSIGN prog_data_source */
  1426 // SYM_REF2(prog_cnxn_assign_c, symbolic_variable, prog_data_source)
  1573 // SYM_REF2(prog_cnxn_assign_c, symbolic_variable, prog_data_source)
  1427 /* any_symbolic_variable SENDTO data_sink */
  1574 /* any_symbolic_variable SENDTO data_sink */
  1428 // SYM_REF2(prog_cnxn_sendto_c, symbolic_variable, data_sink)
  1575 // SYM_REF2(prog_cnxn_sendto_c, symbolic_variable, data_sink)
  1429 /* VAR_CONFIG instance_specific_init_list END_VAR */
  1576 /* VAR_CONFIG instance_specific_init_list END_VAR */