IsConst, IsConstSet, IsProcedure, IsProcType,
IsVar, IsVarParamAny, IsTemporary, IsTuple,
IsEnumeration,
- IsUnbounded, IsArray, IsSet, IsConstructor,
+ IsUnbounded, IsArray, IsSet, IsConstructor, IsConstructorConstant,
IsProcedureVariable,
IsUnboundedParamAny,
IsRecordField, IsFieldVarient, IsVarient, IsRecord,
BuildReturnValueCode, SetLastFunction,
BuildIncludeVarConst, BuildIncludeVarVar,
BuildExcludeVarConst, BuildExcludeVarVar,
- BuildBuiltinCallTree,
+ BuildBuiltinCallTree, CopyByField,
GetParamTree, BuildCleanUp,
BuildTryFinally,
GetLastFunction, SetLastFunction,
FROM m2type IMPORT ChainOnParamValue, GetPointerType, GetIntegerType, AddStatement,
GetCardinalType, GetWordType, GetM2ZType, GetM2RType, GetM2CType,
BuildCharConstant, AddStringToTreeList, BuildArrayStringConstructor,
- GetArrayNoOfElements, GetTreeType ;
+ GetArrayNoOfElements, GetTreeType, IsGccStrictTypeEquivalent ;
FROM m2block IMPORT RememberConstant, pushGlobalScope, popGlobalScope, finishFunctionDecl,
pushFunctionScope, popFunctionScope,
END checkDeclare ;
+(*
+ PerformCodeBecomes -
+*)
+
+PROCEDURE PerformCodeBecomes (location: location_t;
+ virtpos: CARDINAL; des, expr: CARDINAL) ;
+VAR
+ destree, exprtree: tree ;
+BEGIN
+ destree := Mod2Gcc (des) ;
+ exprtree := FoldConstBecomes (virtpos, des, expr) ;
+ IF IsVar (des) AND IsVariableSSA (des)
+ THEN
+ Replace (des, exprtree)
+ ELSIF IsGccStrictTypeEquivalent (destree, exprtree)
+ THEN
+ BuildAssignmentStatement (location, destree, exprtree)
+ ELSE
+ CopyByField (location, destree, exprtree)
+ END
+END PerformCodeBecomes ;
+
+
(*
------------------------------------------------------------------------------
:= Operator
ELSE
IF checkBecomes (des, expr, virtpos, despos, exprpos)
THEN
- IF IsVar (des) AND IsVariableSSA (des)
- THEN
- Replace (des, FoldConstBecomes (virtpos, des, expr))
- ELSE
- BuildAssignmentStatement (location,
- Mod2Gcc (des),
- FoldConstBecomes (virtpos, des, expr))
- END
+ PerformCodeBecomes (location, virtpos, des, expr)
ELSE
SubQuad (quad) (* We don't want multiple errors for the quad. *)
END
static GTY (()) tree gm2_alloca_node;
static GTY (()) tree gm2_memcpy_node;
static GTY (()) tree gm2_memset_node;
+static GTY (()) tree gm2_strncpy_node;
static GTY (()) tree gm2_isfinite_node;
static GTY (()) tree gm2_isnan_node;
static GTY (()) tree gm2_huge_valf_node;
return call;
}
+static tree
+DoBuiltinStrNCopy (location_t location, tree dest, tree src, tree bytes)
+{
+ tree functype = TREE_TYPE (gm2_strncpy_node);
+ tree rettype = TREE_TYPE (functype);
+ tree funcptr
+ = build1 (ADDR_EXPR, build_pointer_type (functype), gm2_strncpy_node);
+ tree call
+ = m2treelib_DoCall3 (location, rettype, funcptr, dest, src, bytes);
+ return call;
+}
+
static tree
DoBuiltinAlloca (location_t location, tree bytes)
{
return call;
}
+/* BuiltinStrNCopy copy at most n chars from address src to dest. */
+
+tree
+m2builtins_BuiltinStrNCopy (location_t location, tree dest, tree src, tree n)
+{
+ return DoBuiltinStrNCopy (location, dest, src, n);
+}
+
static void
create_function_prototype (location_t location,
struct builtin_function_entry *fe)
gm2_alloca_node = find_builtin_tree ("__builtin_alloca");
gm2_memcpy_node = find_builtin_tree ("__builtin_memcpy");
gm2_memset_node = find_builtin_tree ("__builtin_memset");
+ gm2_strncpy_node = find_builtin_tree ("__builtin_strncpy");
gm2_huge_valf_node = find_builtin_tree ("__builtin_huge_valf");
gm2_huge_val_node = find_builtin_tree ("__builtin_huge_val");
gm2_huge_vall_node = find_builtin_tree ("__builtin_huge_vall");
FROM CDataTypes IMPORT CharStar, ConstCharStar ;
FROM gcctypes IMPORT location_t, tree ;
-EXPORT QUALIFIED GetBuiltinConst, GetBuiltinConstType,
- GetBuiltinTypeInfoType, GetBuiltinTypeInfo,
- BuiltinExists, BuildBuiltinTree,
- BuiltinMemCopy, BuiltinMemSet, BuiltInAlloca,
- BuiltInIsfinite ;
-
(*
GetBuiltinConst - returns the gcc tree of a built in constant, name.
PROCEDURE BuiltInIsfinite (location: location_t; e: tree) : tree ;
+(*
+ BuiltinStrNCopy - copy at most n characters from src to dest.
+*)
+
+PROCEDURE BuiltinStrNCopy (location: location_t; dest, src, n: tree) : tree ;
+
+
END m2builtins.
EXTERN tree m2builtins_BuiltInHugeVal (location_t location);
EXTERN tree m2builtins_BuiltInHugeValShort (location_t location);
EXTERN tree m2builtins_BuiltInHugeValLong (location_t location);
+EXTERN tree m2builtins_BuiltinStrNCopy (location_t location, tree dest, tree src, tree n);
+
EXTERN void m2builtins_init (location_t location);
#undef EXTERN
#include "m2treelib.h"
#include "m2type.h"
#include "m2convert.h"
+#include "m2builtins.h"
#include "m2pp.h"
static GTY (()) tree param_list = NULL_TREE; /* Ready for the next time we
cfun->function_end_locus = location;
}
+/* copy_record_fields copy each record field from right to left. */
+
+static
+void
+copy_record_fields (location_t location, tree left, tree right)
+{
+ unsigned int i;
+ tree right_value;
+ tree left_type = TREE_TYPE (left);
+ vec<constructor_elt, va_gc> *values = CONSTRUCTOR_ELTS (right);
+ FOR_EACH_CONSTRUCTOR_VALUE (values, i, right_value)
+ {
+ tree left_field = m2treelib_get_field_no (left_type, NULL_TREE, false, i);
+ tree left_ref = m2expr_BuildComponentRef (location, left, left_field);
+ m2statement_CopyByField (location, left_ref, right_value);
+ }
+}
+
+/* copy_array copy each element of an array from array right to array left. */
+
+static
+void
+copy_array (location_t location, tree left, tree right)
+{
+ unsigned int i;
+ tree value;
+ vec<constructor_elt, va_gc> *values = CONSTRUCTOR_ELTS (right);
+ tree array_type = TREE_TYPE (left);
+ tree index_type = TYPE_DOMAIN (array_type);
+ tree elt_type = TREE_TYPE (array_type);
+ tree low_indice = TYPE_MIN_VALUE (index_type);
+ low_indice
+ = m2convert_BuildConvert (location, index_type, low_indice, false);
+ FOR_EACH_CONSTRUCTOR_VALUE (values, i, value)
+ {
+ tree idx = m2decl_BuildIntegerConstant (i);
+ idx = m2convert_BuildConvert (location, index_type, idx, false);
+ tree array_ref = build4_loc (location, ARRAY_REF, elt_type, left,
+ idx, low_indice, NULL_TREE);
+ m2statement_CopyByField (location, array_ref, value);
+ }
+}
+
+/* copy_array cst into left using strncpy. */
+
+static
+void
+copy_strncpy (location_t location, tree left, tree cst)
+{
+ tree result = m2builtins_BuiltinStrNCopy (location,
+ m2expr_BuildAddr (location, left, false),
+ m2expr_BuildAddr (location, cst, false),
+ m2decl_BuildIntegerConstant (m2expr_StringLength (cst)));
+ TREE_SIDE_EFFECTS (result) = true;
+ TREE_USED (left) = true;
+ TREE_USED (cst) = true;
+ add_stmt (location, result);
+}
+
+/* copy_memcpy copy right into left using builtin_memcpy. */
+
+static
+void
+copy_memcpy (location_t location, tree left, tree right)
+{
+ tree result = m2builtins_BuiltinMemCopy (location,
+ m2expr_BuildAddr (location, left, false),
+ m2expr_BuildAddr (location, right, false),
+ m2expr_GetSizeOf (location, left));
+ TREE_SIDE_EFFECTS (result) = true;
+ TREE_USED (left) = true;
+ TREE_USED (right) = true;
+ add_stmt (location, result);
+}
+
+/* CopyByField_Lower copy right to left using memcpy for unions,
+ strncpy for string cst, field assignment for records,
+ array element assignment for array constructors. For all
+ other types it uses BuildAssignmentStatement. */
+
+static
+void
+CopyByField_Lower (location_t location,
+ tree left, tree right)
+{
+ tree left_type = TREE_TYPE (left);
+ enum tree_code right_code = TREE_CODE (right);
+ enum tree_code left_code = TREE_CODE (left_type);
+
+ if (left_code == RECORD_TYPE && right_code == CONSTRUCTOR)
+ copy_record_fields (location, left, right);
+ else if (left_code == ARRAY_TYPE && right_code == CONSTRUCTOR)
+ copy_array (location, left, right);
+ else if (left_code == UNION_TYPE && right_code == CONSTRUCTOR)
+ copy_memcpy (location, left, right);
+ else if (right_code == STRING_CST)
+ copy_strncpy (location, left, right);
+ else
+ m2statement_BuildAssignmentStatement (location, left, right);
+}
+
+/* CopyByField recursively checks each field to ensure GCC
+ type equivalence and if so it uses assignment.
+ Otherwise use strncpy or memcpy depending upon type. */
+
+void
+m2statement_CopyByField (location_t location, tree des, tree expr)
+{
+ if (m2type_IsGccStrictTypeEquivalent (des, expr))
+ m2statement_BuildAssignmentStatement (location, des, expr);
+ else
+ CopyByField_Lower (location, des, expr);
+}
+
/* BuildAssignmentTree builds the assignment of, des, and, expr.
It returns, des. */
PROCEDURE BuildBuiltinCallTree (func: tree) : tree ;
+(*
+ CopyByField - copy expr to des, if des is a record, union or an array
+ then check fields for GCC type equivalence and if necessary
+ call __builtin_strncpy and __builtin_memcpy.
+ This can occur if an expr contains a constant string
+ which is to be assigned into a field declared as
+ an ARRAY [0..n] OF CHAR.
+*)
+
+PROCEDURE CopyByField (location: location_t; des, expr: tree) ;
+
+
END m2statement.
EXTERN tree m2statement_BuildTryFinally (location_t location, tree call,
tree cleanups);
EXTERN tree m2statement_BuildCleanUp (tree param);
+EXTERN void m2statement_CopyByField (location_t location, tree des, tree expr);
#undef EXTERN
#endif /* m2statement_h. */
/* IsAddress returns true if the type is an ADDRESS. */
-int
+bool
m2type_IsAddress (tree type)
{
return type == ptr_type_node;
}
+/* check_record_fields return true if all the fields in left and right
+ are GCC equivalent. */
+
+static
+bool
+check_record_fields (tree left, tree right)
+{
+ unsigned int i;
+ tree right_value;
+ vec<constructor_elt, va_gc> *values = CONSTRUCTOR_ELTS (right);
+ FOR_EACH_CONSTRUCTOR_VALUE (values, i, right_value)
+ {
+ tree left_field = TREE_TYPE (m2treelib_get_field_no (left, NULL_TREE, false, i));
+ if (! m2type_IsGccStrictTypeEquivalent (left_field, right_value))
+ return false;
+ }
+ return true;
+}
+
+/* check_array_types return true if left and right have the same type and right
+ is not a CST_STRING. */
+
+static
+bool
+check_array_types (tree right)
+{
+ unsigned int i;
+ tree value;
+ vec<constructor_elt, va_gc> *values = CONSTRUCTOR_ELTS (right);
+ FOR_EACH_CONSTRUCTOR_VALUE (values, i, value)
+ {
+ enum tree_code right_code = TREE_CODE (value);
+ if (right_code == STRING_CST)
+ return false;
+ }
+ return true;
+}
+
+bool
+m2type_IsGccStrictTypeEquivalent (tree left, tree right)
+{
+ enum tree_code right_code = TREE_CODE (right);
+ enum tree_code left_code = TREE_CODE (left);
+ if (left_code == VAR_DECL)
+ return m2type_IsGccStrictTypeEquivalent (TREE_TYPE (left), right);
+ if (right_code == VAR_DECL)
+ return m2type_IsGccStrictTypeEquivalent (left, TREE_TYPE (right));
+ if (left_code == RECORD_TYPE && right_code == CONSTRUCTOR)
+ return check_record_fields (left, right);
+ if (left_code == UNION_TYPE && right_code == CONSTRUCTOR)
+ return false;
+ if (left_code == ARRAY_TYPE && right_code == CONSTRUCTOR)
+ return check_array_types (right);
+ if (right_code == STRING_CST)
+ return false;
+ return true;
+}
+
#include "gt-m2-m2type.h"
PROCEDURE SameRealType (a, b: tree) : BOOLEAN ;
+(*
+ IsGccStrictTypeEquivalent - return true if left and right and
+ all their contents have the same type.
+*)
+
+PROCEDURE IsGccStrictTypeEquivalent (left, right: tree) : BOOLEAN ;
+
+
END m2type.
EXTERN tree m2type_BuildProcTypeParameterDeclaration (location_t location,
tree type,
bool isreference);
-EXTERN int m2type_IsAddress (tree type);
+EXTERN bool m2type_IsAddress (tree type);
EXTERN tree m2type_GetCardinalAddressType (void);
EXTERN bool m2type_SameRealType (tree a, tree b);
-
+EXTERN bool m2type_IsGccStrictTypeEquivalent (tree left, tree right);
#undef EXTERN
#endif /* m2type_h */