make sure all IL operands are narrowed (datatype checking algorithm)
authormjsousa
Wed, 21 Aug 2013 16:08:50 +0100
changeset 836 149398f525a7
parent 835 182036ed6475
child 837 e0184feaebd2
make sure all IL operands are narrowed (datatype checking algorithm)
stage3/narrow_candidate_datatypes.cc
stage3/narrow_candidate_datatypes.hh
--- a/stage3/narrow_candidate_datatypes.cc	Wed Aug 21 16:06:43 2013 +0100
+++ b/stage3/narrow_candidate_datatypes.cc	Wed Aug 21 16:08:50 2013 +0100
@@ -1082,14 +1082,59 @@
 /*******************/
 /* B 2.2 Operators */
 /*******************/
+/* Sets the datatype of the il_operand, and calls it recursively!
+ * 
+ * NOTE 1: the il_operand __may__ be pointing to a parenthesized list of IL instructions. 
+ * e.g.  LD 33
+ *       AND ( 45
+ *            OR 56
+ *            )
+ *       When we handle the first 'AND' IL_operator, the il_operand will point to an simple_instr_list_c.
+ *       In this case, when we call il_operand->accept(*this);, the prev_il_instruction pointer will be overwritten!
+ *
+ *       So, if yoy wish to set the prev_il_instruction->datatype = symbol->datatype;
+ *       do it __before__ calling set_il_operand_datatype() (which in turn calls il_operand->accept(*this)) !!
+ */
+void *narrow_candidate_datatypes_c::set_il_operand_datatype(symbol_c *il_operand, symbol_c *datatype) {
+	if (NULL == il_operand) return NULL; /* if no IL operand => error in the source code!! */
+
+	/* If il_operand already has a non-NULL datatype (remember, narrow algorithm runs twice over IL lists!),
+	 * 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 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;
+		/* OK, so both the datatypes are valid, but are they equal? */
+		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;
+	}
+
+	/* Set the il_operand's datatype. Note that the new 'datatype' may even be NULL!!! */
+	il_operand->datatype = datatype;
+	/* Even if we are not able to determine the il_operand's datatype ('datatype' is NULL), we still visit it recursively,
+	 * to give a chance of any complex expressions embedded in the il_operand (e.g. expressions inside array subscripts!) 
+	 * to be narrowed too.
+	 */
+	il_operand->accept(*this);
+	return NULL;
+}
+
+
+
+
 void *narrow_candidate_datatypes_c::narrow_binary_operator(const struct widen_entry widen_table[], symbol_c *symbol, bool *deprecated_operation) {
 	symbol_c *prev_instruction_type, *operand_type;
 	int count = 0;
 
-	if (NULL == symbol->datatype)
-		/* next IL instructions were unable to determine the datatype this instruction should produce */
-		return NULL;
-
         if (NULL != deprecated_operation)
 		*deprecated_operation = false;
 
@@ -1110,26 +1155,29 @@
 	 *         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.
 	 */
-	for(unsigned int i = 0; i < fake_prev_il_instruction->candidate_datatypes.size(); i++) {
-		for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
-			prev_instruction_type = fake_prev_il_instruction->candidate_datatypes[i];
-			operand_type = il_operand->candidate_datatypes[j];
-			if (is_widening_compatible(widen_table, prev_instruction_type, operand_type, symbol->datatype, deprecated_operation)) {
-				/* set the desired datatype of the previous il instruction */
-				set_datatype_in_prev_il_instructions(prev_instruction_type, fake_prev_il_instruction);
-				/* set the datatype for the operand */
-				il_operand->datatype = operand_type;
-				il_operand->accept(*this);
-				
-				/* NOTE: DO NOT search any further! Return immediately!
-				 * Since we support SAFE*** datatypes, multiple entries in the widen_table may be compatible.
-				 * If we try to set more than one distinct datatype on the same symbol, then the datatype will be set to
-				 * an invalid_datatype, which is NOT what we want!
-				 */
-				return NULL;
+	if (NULL != symbol->datatype) { // next IL instructions were able to determine the datatype this instruction should produce
+		for(unsigned int i = 0; i < fake_prev_il_instruction->candidate_datatypes.size(); i++) {
+			for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
+				prev_instruction_type = fake_prev_il_instruction->candidate_datatypes[i];
+				operand_type = il_operand->candidate_datatypes[j];
+				if (is_widening_compatible(widen_table, prev_instruction_type, operand_type, symbol->datatype, deprecated_operation)) {
+					/* set the desired datatype of the previous il instruction */
+					set_datatype_in_prev_il_instructions(prev_instruction_type, fake_prev_il_instruction);
+					/* set the datatype for the operand */
+					set_il_operand_datatype(il_operand, operand_type);
+					
+					/* NOTE: DO NOT search any further! Return immediately!
+					 * Since we support SAFE*** datatypes, multiple entries in the widen_table may be compatible.
+					 * If we try to set more than one distinct datatype on the same symbol, then the datatype will be set to
+					 * an invalid_datatype, which is NOT what we want!
+					 */
+					return NULL;
+				}
 			}
 		}
 	}
+	/* We were not able to determine the required datatype, but we still give the il_operand a chance to be narrowed! */
+	set_il_operand_datatype(il_operand, NULL);
 	return NULL;
 }
 
@@ -1138,93 +1186,55 @@
 
 
 void *narrow_candidate_datatypes_c::handle_il_instruction(symbol_c *symbol) {
-	if (NULL == symbol->datatype) return NULL; /* next IL instructions were unable to determine the datatype this instruction should produce */
-  
-	/* NOTE 1: the il_operand __may__ be pointing to a parenthesized list of IL instructions. 
-	 * e.g.  LD 33
-	 *       AND ( 45
-	 *            OR 56
-	 *            )
-	 *       When we handle the first 'AND' IL_operator, the il_operand will point to an simple_instr_list_c.
-	 *       In this case, when we call il_operand->accept(*this);, the prev_il_instruction pointer will be overwritten!
-	 *
-	 *       We must therefore set the prev_il_instruction->datatype = symbol->datatype;
-	 *       __before__ calling il_operand->accept(*this) !!
-	 *
+	/*
 	 * 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.
 	 */
-	/* set the desired datatype of the previous il instruction */
-	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
-	  
+	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 */
-	if (NULL == il_operand) return NULL; /* if no IL operand => error in the source code!! */
-	il_operand->datatype = symbol->datatype;
-	il_operand->accept(*this);
-	return NULL;
-}
-
-
-
-
-void *narrow_candidate_datatypes_c::visit(LD_operator_c *symbol)   {
-	if (NULL == symbol->datatype) return NULL; /* next IL instructions were unable to determine the datatype this instruction should produce */
-
-	/* set the datatype for the operand */
-	if (NULL == il_operand) return NULL; /* if no IL operand => error in the source code!! */
-	il_operand->datatype = symbol->datatype;
-	il_operand->accept(*this);
-	return NULL;
-}
-
-
-void *narrow_candidate_datatypes_c::visit(LDN_operator_c *symbol)  {
-	if (NULL == symbol->datatype) return NULL; /* next IL instructions were unable to determine the datatype this instruction should produce */
-
-	/* set the datatype for the operand */
-	if (NULL == il_operand) return NULL; /* if no IL operand => error in the source code!! */
-	il_operand->datatype = symbol->datatype;
-	il_operand->accept(*this);
-	return NULL;
-}
+	set_il_operand_datatype(il_operand, symbol->datatype);
+	return NULL;
+}
+
+
+
+
+void *narrow_candidate_datatypes_c::visit( LD_operator_c *symbol)  {return set_il_operand_datatype(il_operand, symbol->datatype);}
+void *narrow_candidate_datatypes_c::visit(LDN_operator_c *symbol)  {return set_il_operand_datatype(il_operand, symbol->datatype);}
 
 void *narrow_candidate_datatypes_c::visit(ST_operator_c *symbol) {
-	if (symbol->candidate_datatypes.size() != 1)
-		return NULL;
-
-	symbol->datatype = symbol->candidate_datatypes[0];
-	/* set the desired datatype of the previous il instruction */
-	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
-	/* In the case of the ST operator, we must set the datatype of the il_instruction_c object that points to this ST_operator_c ourselves,
-	 * since the following il_instruction_c objects have not done it, as is normal/standard for other instructions!
-	 */
-	current_il_instruction->datatype = symbol->datatype;
+	if (symbol->candidate_datatypes.size() == 1) {
+		symbol->datatype = symbol->candidate_datatypes[0];
+		/* set the desired datatype of the previous il instruction */
+		set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
+		/* In the case of the ST operator, we must set the datatype of the il_instruction_c object that points to this ST_operator_c ourselves,
+		 * since the following il_instruction_c objects have not done it, as is normal/standard for other instructions!
+		 */
+		current_il_instruction->datatype = symbol->datatype;
+	}
 	
 	/* set the datatype for the operand */
-	if (NULL == il_operand) return NULL; /* if no IL operand => error in the source code!! */
-	il_operand->datatype = symbol->datatype;
-	il_operand->accept(*this);
-
+	set_il_operand_datatype(il_operand, symbol->datatype);
 	return NULL;
 }
 
 void *narrow_candidate_datatypes_c::visit(STN_operator_c *symbol) {
-	if (symbol->candidate_datatypes.size() != 1)
-		return NULL;
+	if (symbol->candidate_datatypes.size() == 1) {
+		symbol->datatype = symbol->candidate_datatypes[0];
+		/* set the desired datatype of the previous il instruction */
+		set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
+		/* In the case of the ST operator, we must set the datatype of the il_instruction_c object that points to this ST_operator_c ourselves,
+		 * since the following il_instruction_c objects have not done it, as is normal/standard for other instructions!
+		 */
+		current_il_instruction->datatype = symbol->datatype;
+	}
 	
-	symbol->datatype = symbol->candidate_datatypes[0];
-	/* set the desired datatype of the previous il instruction */
-	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
-	/* In the case of the ST operator, we must set the datatype of the il_instruction_c object that points to this ST_operator_c ourselves,
-	 * since the following il_instruction_c objects have not done it, as is normal/standard for other instructions!
-	 */
-	current_il_instruction->datatype = symbol->datatype;
-
 	/* set the datatype for the operand */
-	if (NULL == il_operand) return NULL; /* if no IL operand => error in the source code!! */
-	il_operand->datatype = symbol->datatype;
-	il_operand->accept(*this);
+	set_il_operand_datatype(il_operand, symbol->datatype);
 	return NULL;
 }
 
--- a/stage3/narrow_candidate_datatypes.hh	Wed Aug 21 16:06:43 2013 +0100
+++ b/stage3/narrow_candidate_datatypes.hh	Wed Aug 21 16:08:50 2013 +0100
@@ -72,11 +72,12 @@
     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_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 *handle_il_instruction(symbol_c *symbol);
+    void *set_il_operand_datatype   (symbol_c *il_operand, symbol_c *datatype);
+    void *handle_il_instruction     (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);