Fix datatype analysis of conditional IL operators (CALC, CALCN, RETC, RETCN, JMPC, JMPCN, S and R)
authormjsousa
Wed, 21 Aug 2013 21:26:55 +0100
changeset 838 13ea7c080018
parent 837 e0184feaebd2
child 839 99d9ef4d210b
Fix datatype analysis of conditional IL operators (CALC, CALCN, RETC, RETCN, JMPC, JMPCN, S and R)
stage3/narrow_candidate_datatypes.cc
stage3/narrow_candidate_datatypes.hh
--- a/stage3/narrow_candidate_datatypes.cc	Wed Aug 21 21:14:50 2013 +0100
+++ b/stage3/narrow_candidate_datatypes.cc	Wed Aug 21 21:26:55 2013 +0100
@@ -1102,18 +1102,19 @@
 	 * but narrow algorithm has not yet been able to determine what datatype it should take? This is strange,
 	 * and most probably an error!
 	 */
-	if ((NULL != il_operand->datatype) && (NULL == datatype))
-		ERROR;
+	if ((NULL != il_operand->datatype) && (NULL == datatype)) ERROR;
 
 	/* If the il_operand's datatype has already been set previously, and
 	 * the narrow algorithm has already determined the datatype the il_operand should take!
 	 *   ...we just make sure that the new datatype is the same as the current il_operand's datatype
 	 */
 	if ((NULL != il_operand->datatype)  && (NULL != datatype)) {
-		/* Only one of the two datatypes is an invalid_type_name_c? This implies they are diferent!! */
-		if ((!get_datatype_info_c::is_type_valid(datatype)) ^ ((!get_datatype_info_c::is_type_valid(il_operand->datatype)))) ERROR;
+		/* Both datatypes are an invalid_type_name_c. This implies they are the same!! */
+		if ((!get_datatype_info_c::is_type_valid(datatype)) && ((!get_datatype_info_c::is_type_valid(il_operand->datatype)))) 
+			return NULL;;
 		/* OK, so both the datatypes are valid, but are they equal? */
-		if ( !get_datatype_info_c::is_type_equal(il_operand->datatype, datatype)) ERROR; 
+		if ( !get_datatype_info_c::is_type_equal(il_operand->datatype, datatype)) 
+			ERROR; 
 		/* The datatypes are the same. We have nothing to do, so we simply return! */
 		return NULL;
 	}
@@ -1184,19 +1185,59 @@
 
 
 
-
-void *narrow_candidate_datatypes_c::handle_il_instruction(symbol_c *symbol) {
-	/*
-	 * NOTE 2: We do not need to call prev_il_instruction->accept(*this), as the object to which prev_il_instruction
-	 *         is pointing to will be later narrowed by the call from the for() loop of the instruction_list_c
-	 *         (or simple_instr_list_c), which iterates backwards.
-	 */
-	if (NULL != symbol->datatype) // next IL instructions were able to determine the datatype this instruction should produce
-		/* set the desired datatype of the previous il instruction */
-		set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
-  
-	/* set the datatype for the operand */
-	set_il_operand_datatype(il_operand, symbol->datatype);
+/* Narrow IL operators whose execution is conditional on the boolean value in the accumulator.
+ * Basically, narrow the JMPC, JMPCN, RETC, RETCN, CALC, and CALCN operators!
+ * Also does part of the S and R operator narrowing!!!
+ */
+void *narrow_candidate_datatypes_c::narrow_conditional_operator(symbol_c *symbol) {
+	/* if the next IL instructions needs us to provide a datatype other than a BOOL or a SAFEBOOL, 
+	 * then we have an internal compiler error - most likely in fill_candidate_datatypes_c 
+	 */
+	// I (mario) am confident the fill/narrow algorithms are working correctly, so for now we can disable the assertions!
+	//if ((NULL != symbol->datatype) && (!get_datatype_info_c::is_BOOL_compatible(symbol->datatype))) ERROR;
+	//if (symbol->candidate_datatypes.size() > 2) ERROR; /* may contain, at most, a BOOL and a SAFEBOOL */
+
+	/* NOTE: If there is no IL instruction following this S, R, CALC, CALCN, JMPC, JMPCN, RETC, or RETCN instruction,
+	 *       we must still provide a bool_type_name_c datatype (if possible, i.e. if it exists in the candidate datatype list).
+	 *       If it is not possible, we set it to NULL
+	 * 
+	 * NOTE: Note that this algorithm we are implementing is slightly wrong. 
+	 *        (a) It ignores that a SAFEBOOL may be needed instead of a BOOL datatype. 
+	 *        (b) It also ignores that this method gets to be called twice on the same 
+	 *            object (the narrow algorithm runs through the IL list twice in order to
+	 *            handle forward JMPs), so the assumption that we must immediately set our
+	 *            own datatype if we get called with a NULL symbol->datatype is incorrect 
+	 *           (it may be that the second time it is called it will be with the correct datatype!).
+	 * 
+	 *       These two issues (a) and (b) together means that we should only really be setting our own
+	 *       datatype if we are certain that the following IL instructions will never set it for us
+	 *       - basically if the following IL instruction is a LD, or a JMP to a LD, or a JMP to a JMP to a LD,
+	 *        etc..., or a conditional JMP whose both branches go to LD, etc...!!!
+	 *       
+	 *       At the moment, it seems to me that we would need to write a visitor class to do this for us!
+	 *       I currently have other things on my mind at the moment, so I will leave this for later...
+	 *       For the moment we just set it to BOOL, and ignore the support of SAFEBOOL!
+	 */
+	if (NULL == symbol->datatype) set_datatype(&get_datatype_info_c::bool_type_name /* datatype*/, symbol /* symbol */);
+	if (NULL == symbol->datatype) ERROR; // the BOOL is not on the candidate_datatypes! Strange... Probably a bug in fill_candidate_datatype_c
+
+	/* set the required datatype of the previous IL instruction, i.e. a bool_type_name_c! */
+	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
+	return NULL;
+}
+
+
+
+void *narrow_candidate_datatypes_c::narrow_S_and_R_operator(symbol_c *symbol, const char *param_name, symbol_c *called_fb_declaration) {
+	if (NULL != called_fb_declaration) 
+	  /* FB call semantics */  
+	  return narrow_implicit_il_fb_call(symbol, param_name, called_fb_declaration); 
+	
+	/* Set/Reset semantics */  
+	narrow_conditional_operator(symbol);
+	/* set the datatype for the il_operand */
+	if ((NULL != il_operand) && (il_operand->candidate_datatypes.size() > 0))
+		set_il_operand_datatype(il_operand, il_operand->candidate_datatypes[0]);
 	return NULL;
 }
 
@@ -1238,28 +1279,20 @@
 	return NULL;
 }
 
-void *narrow_candidate_datatypes_c::visit(NOT_operator_c *symbol) {
-	/* NOTE: the standard allows syntax in which the NOT operator is followed by an optional <il_operand>
-	 *              NOT [<il_operand>]
-	 *       However, it does not define the semantic of the NOT operation when the <il_operand> is specified.
-	 *       We therefore consider it an error if an il_operand is specified!
-	 *       This error will be detected in print_datatypes_error_c!!
-	 */
-	/* This operator does not change the data type, it simply inverts the bits in the ANT_BIT data types! */
-	/* So, we set the desired datatype of the previous il instruction */
-	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
-	return NULL;
-}
-
-void *narrow_candidate_datatypes_c::visit(S_operator_c *symbol)  {
-	if (NULL != symbol->called_fb_declaration) /* FB call semantics */  return narrow_implicit_il_fb_call(symbol, "S",  symbol->called_fb_declaration); 
-	else                                       /* Reset   semantics */  return handle_il_instruction(symbol);
-}
-
-void *narrow_candidate_datatypes_c::visit(R_operator_c *symbol)  {
-	if (NULL != symbol->called_fb_declaration) /* FB call semantics */  return narrow_implicit_il_fb_call(symbol, "R",  symbol->called_fb_declaration); 
-	else                                       /* Reset   semantics */  return handle_il_instruction(symbol);
-}
+
+
+/* NOTE: the standard allows syntax in which the NOT operator is followed by an optional <il_operand>
+ *              NOT [<il_operand>]
+ *       However, it does not define the semantic of the NOT operation when the <il_operand> is specified.
+ *       We therefore consider it an error if an il_operand is specified!
+ *       This error will be detected in print_datatypes_error_c!!
+ */
+/* This operator does not change the data type, it simply inverts the bits in the ANT_BIT data types! */
+/* So, we merely set the desired datatype of the previous il instruction */
+void *narrow_candidate_datatypes_c::visit( NOT_operator_c *symbol)  {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);return NULL;}
+
+void *narrow_candidate_datatypes_c::visit(   S_operator_c *symbol)  {return narrow_S_and_R_operator   (symbol, "S",   symbol->called_fb_declaration);}
+void *narrow_candidate_datatypes_c::visit(   R_operator_c *symbol)  {return narrow_S_and_R_operator   (symbol, "R",   symbol->called_fb_declaration);}
 
 void *narrow_candidate_datatypes_c::visit(  S1_operator_c *symbol)  {return narrow_implicit_il_fb_call(symbol, "S1",  symbol->called_fb_declaration);}
 void *narrow_candidate_datatypes_c::visit(  R1_operator_c *symbol)  {return narrow_implicit_il_fb_call(symbol, "R1",  symbol->called_fb_declaration);}
@@ -1289,44 +1322,17 @@
 void *narrow_candidate_datatypes_c::visit(  NE_operator_c *symbol)  {return narrow_binary_operator(widen_CMP_table, symbol);}
 
 
-
-
-void *narrow_candidate_datatypes_c::narrow_conditional_flow_control_IL_instruction(symbol_c *symbol) {
-	/* if the next IL instructions needs us to provide a datatype other than a bool, 
-	 * then we have an internal compiler error - most likely in fill_candidate_datatypes_c 
-	 */
-	if ((NULL != symbol->datatype) && (!get_datatype_info_c::is_BOOL_compatible(symbol->datatype))) ERROR;
-	if (symbol->candidate_datatypes.size() > 1) ERROR;
-
-	/* NOTE: If there is no IL instruction following this CALC, CALCN, JMPC, JMPC, ..., instruction,
-	 *       we must still provide a bool_type_name_c datatype (if possible, i.e. if it exists in the candidate datatype list).
-	 *       If it is not possible, we set it to NULL
-	 */
-	if (symbol->candidate_datatypes.size() == 0)    symbol->datatype = NULL;
-	else    symbol->datatype = symbol->candidate_datatypes[0]; /* i.e. a bool_type_name_c! */
-	if ((NULL != symbol->datatype) && (!get_datatype_info_c::is_BOOL_compatible(symbol->datatype))) ERROR;
-
-	/* set the required datatype of the previous IL instruction, i.e. a bool_type_name_c! */
-	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
-	return NULL;
-}
-
-
-// SYM_REF0(CAL_operator_c)
-// SYM_REF0(CALC_operator_c)
-// SYM_REF0(CALCN_operator_c)
-/* called from visit(il_fb_call_c *) {symbol->il_call_operator->accpet(*this)} */
+/* visitors to CAL_operator_c, CALC_operator_c and CALCN_operator_c are called from visit(il_fb_call_c *) {symbol->il_call_operator->accept(*this)} */
 /* NOTE: The CAL, JMP and RET instructions simply set the desired datatype of the previous il instruction since they do not change the value in the current/default IL variable */
-/* called from il_fb_call_c (symbol->il_call_operator->accpet(*this) ) */
 void *narrow_candidate_datatypes_c::visit(  CAL_operator_c *symbol) {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); return NULL;}
 void *narrow_candidate_datatypes_c::visit(  RET_operator_c *symbol) {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); return NULL;}
 void *narrow_candidate_datatypes_c::visit(  JMP_operator_c *symbol) {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); return NULL;}
-void *narrow_candidate_datatypes_c::visit( CALC_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(CALCN_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit( RETC_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(RETCN_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit( JMPC_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(JMPCN_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit( CALC_operator_c *symbol) {return narrow_conditional_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit(CALCN_operator_c *symbol) {return narrow_conditional_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit( RETC_operator_c *symbol) {return narrow_conditional_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit(RETCN_operator_c *symbol) {return narrow_conditional_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit( JMPC_operator_c *symbol) {return narrow_conditional_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit(JMPCN_operator_c *symbol) {return narrow_conditional_operator(symbol);}
 
 /* Symbol class handled together with function call checks */
 // void *visit(il_assign_operator_c *symbol, variable_name);
--- a/stage3/narrow_candidate_datatypes.hh	Wed Aug 21 21:14:50 2013 +0100
+++ b/stage3/narrow_candidate_datatypes.hh	Wed Aug 21 21:26:55 2013 +0100
@@ -71,21 +71,20 @@
 
     bool is_widening_compatible(const struct widen_entry widen_table[], symbol_c *left_type, symbol_c *right_type, symbol_c *result_type, bool *deprecated_status = NULL);
 
-    void  narrow_function_invocation(symbol_c *f_call, generic_function_call_t fcall_data);
-    void  narrow_nonformal_call     (symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL);
-    void  narrow_formal_call        (symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL);
-    void *narrow_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration);
-
-    void *set_il_operand_datatype   (symbol_c *il_operand, symbol_c *datatype);
-    void *handle_il_instruction     (symbol_c *symbol);
+    void *narrow_spec_init           (symbol_c *symbol, symbol_c *type_decl, symbol_c *init_value);
+    void *narrow_type_decl           (symbol_c *symbol, symbol_c *type_name, symbol_c *spec_init);
+    void  narrow_function_invocation (symbol_c *f_call, generic_function_call_t fcall_data);
+    void  narrow_nonformal_call      (symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL);
+    void  narrow_formal_call         (symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL);
+    void *narrow_implicit_il_fb_call (symbol_c *symbol, const char *param_name, symbol_c *&called_fb_declaration);
+    void *narrow_S_and_R_operator    (symbol_c *symbol, const char *param_name, symbol_c * called_fb_declaration);
+    void *narrow_conditional_operator(symbol_c *symbol);
     void *narrow_binary_operator    (const struct widen_entry widen_table[], symbol_c *symbol,                                     bool *deprecated_operation = NULL);
     void *narrow_binary_expression  (const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool *deprecated_operation = NULL, bool allow_enums = false);
     void *narrow_equality_comparison(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool *deprecated_operation = NULL);
 
-    void *narrow_spec_init(symbol_c *symbol, symbol_c *type_decl, symbol_c *init_value);
-    void *narrow_type_decl(symbol_c *symbol, symbol_c *type_name, symbol_c *spec_init);
-
-    void *narrow_conditional_flow_control_IL_instruction(symbol_c *symbol);
+    void *set_il_operand_datatype    (symbol_c *il_operand, symbol_c *datatype);
+
 
 
   public: