Commit 737053d6 by Eric Botcazou Committed by Arnaud Charlet

utils.c (update_pointer_to): Make a copy of the couple of FIELD_DECLs when...

2007-04-06  Eric Botcazou <botcazou@adacore.com>
	    Olivier Hainque  <hainque@adacore.com>

	* utils.c (update_pointer_to): Make a copy of the couple of FIELD_DECLs
	when updating the contents of the old pointer to an unconstrained array.
	(end_subprog_body): Set error_gnat_node to Empty.
	(write_record_type_debug_info): Do not be unduly sparing with our bytes.
	(unchecked_convert): For subtype to base type conversions, require that
	the source be a subtype if it is an integer type.
	(builtin_decls): New global, vector of available builtin functions.
	(gnat_pushdecl): Add global builtin function declaration nodes to the
	builtin_decls list.
	(gnat_install_builtins): Adjust comments.
	(builtin_function): Set DECL_BUILTIN_CLASS and DECL_FUNCTION_CODE before
	calling gnat_pushdecl, so that it knows when it handed a builtin
	function declaration node.
	(builtin_decl_for): Search the builtin_decls list.

From-SVN: r123609
parent 3ce5f966
...@@ -150,6 +150,9 @@ static GTY((deletable)) struct gnat_binding_level *free_binding_level; ...@@ -150,6 +150,9 @@ static GTY((deletable)) struct gnat_binding_level *free_binding_level;
/* An array of global declarations. */ /* An array of global declarations. */
static GTY(()) VEC (tree,gc) *global_decls; static GTY(()) VEC (tree,gc) *global_decls;
/* An array of builtin declarations. */
static GTY(()) VEC (tree,gc) *builtin_decls;
/* An array of global renaming pointers. */ /* An array of global renaming pointers. */
static GTY(()) VEC (tree,gc) *global_renaming_pointers; static GTY(()) VEC (tree,gc) *global_renaming_pointers;
...@@ -441,14 +444,20 @@ gnat_pushdecl (tree decl, Node_Id gnat_node) ...@@ -441,14 +444,20 @@ gnat_pushdecl (tree decl, Node_Id gnat_node)
/* Put the declaration on the list. The list of declarations is in reverse /* Put the declaration on the list. The list of declarations is in reverse
order. The list will be reversed later. Put global variables in the order. The list will be reversed later. Put global variables in the
globals list. Don't put TYPE_DECLs for UNCONSTRAINED_ARRAY_TYPE into the globals list and builtin functions in a dedicated list to speed up
list, as they will cause trouble with the debugger and aren't needed further lookups. Don't put TYPE_DECLs for UNCONSTRAINED_ARRAY_TYPE into
the list, as they will cause trouble with the debugger and aren't needed
anyway. */ anyway. */
if (TREE_CODE (decl) != TYPE_DECL if (TREE_CODE (decl) != TYPE_DECL
|| TREE_CODE (TREE_TYPE (decl)) != UNCONSTRAINED_ARRAY_TYPE) || TREE_CODE (TREE_TYPE (decl)) != UNCONSTRAINED_ARRAY_TYPE)
{ {
if (global_bindings_p ()) if (global_bindings_p ())
VEC_safe_push (tree, gc, global_decls, decl); {
VEC_safe_push (tree, gc, global_decls, decl);
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
VEC_safe_push (tree, gc, builtin_decls, decl);
}
else else
{ {
TREE_CHAIN (decl) = BLOCK_VARS (current_binding_level->block); TREE_CHAIN (decl) = BLOCK_VARS (current_binding_level->block);
...@@ -521,12 +530,12 @@ gnat_init_decl_processing (void) ...@@ -521,12 +530,12 @@ gnat_init_decl_processing (void)
gnat_install_builtins (); gnat_install_builtins ();
} }
/* Install the builtin functions the middle-end needs. */ /* Install the builtin functions we might need. */
static void static void
gnat_install_builtins () gnat_install_builtins ()
{ {
/* Builtins used by generic optimizers. */ /* Builtins used by generic middle-end optimizers. */
build_common_builtin_nodes (); build_common_builtin_nodes ();
/* Target specific builtins, such as the AltiVec family on ppc. */ /* Target specific builtins, such as the AltiVec family on ppc. */
...@@ -1020,7 +1029,30 @@ write_record_type_debug_info (tree record_type) ...@@ -1020,7 +1029,30 @@ write_record_type_debug_info (tree record_type)
if (!pos && TREE_CODE (curpos) == MULT_EXPR if (!pos && TREE_CODE (curpos) == MULT_EXPR
&& TREE_CODE (TREE_OPERAND (curpos, 1)) == INTEGER_CST) && TREE_CODE (TREE_OPERAND (curpos, 1)) == INTEGER_CST)
{ {
align = TREE_INT_CST_LOW (TREE_OPERAND (curpos, 1)); /* An offset which is a bit-and operation with a negative
power of 2 means an alignment corresponding to this power
of 2. */
tree offset = TREE_OPERAND (curpos, 0);
/* Strip off any conversions. */
while (TREE_CODE (offset) == NON_LVALUE_EXPR
|| TREE_CODE (offset) == NOP_EXPR
|| TREE_CODE (offset) == CONVERT_EXPR)
offset = TREE_OPERAND (offset, 0);
if (TREE_CODE (offset) == BIT_AND_EXPR)
{
int p = exact_log2
(- TREE_INT_CST_LOW (TREE_OPERAND (offset, 1)));
if (p < 0)
p = 1;
align = p * TREE_INT_CST_LOW (TREE_OPERAND (curpos, 1));
}
else
align = TREE_INT_CST_LOW (TREE_OPERAND (curpos, 1));
pos = compute_related_constant (curpos, pos = compute_related_constant (curpos,
round_up (last_pos, align)); round_up (last_pos, align));
} }
...@@ -1061,16 +1093,10 @@ write_record_type_debug_info (tree record_type) ...@@ -1061,16 +1093,10 @@ write_record_type_debug_info (tree record_type)
var = true; var = true;
} }
/* The heuristics above might get the alignment wrong.
Adjust the obvious case where align is smaller than the
alignments necessary for objects of field_type. */
if (align < TYPE_ALIGN(field_type))
align = TYPE_ALIGN(field_type);
/* Make a new field name, if necessary. */ /* Make a new field name, if necessary. */
if (var || align != 0) if (var || align != 0)
{ {
char suffix[6]; char suffix[16];
if (align != 0) if (align != 0)
sprintf (suffix, "XV%c%u", var ? 'L' : 'A', sprintf (suffix, "XV%c%u", var ? 'L' : 'A',
...@@ -1103,10 +1129,10 @@ write_record_type_debug_info (tree record_type) ...@@ -1103,10 +1129,10 @@ write_record_type_debug_info (tree record_type)
TYPE_FIELDS (new_record_type) TYPE_FIELDS (new_record_type)
= nreverse (TYPE_FIELDS (new_record_type)); = nreverse (TYPE_FIELDS (new_record_type));
rest_of_type_compilation (new_record_type, global_bindings_p ()); rest_of_type_compilation (new_record_type, true);
} }
rest_of_type_compilation (record_type, global_bindings_p ()); rest_of_type_compilation (record_type, true);
} }
/* Utility function of above to merge LAST_SIZE, the previous size of a record /* Utility function of above to merge LAST_SIZE, the previous size of a record
...@@ -2098,6 +2124,9 @@ end_subprog_body (tree body) ...@@ -2098,6 +2124,9 @@ end_subprog_body (tree body)
current_function_decl = DECL_CONTEXT (fndecl); current_function_decl = DECL_CONTEXT (fndecl);
cfun = NULL; cfun = NULL;
/* We cannot track the location of errors past this point. */
error_gnat_node = Empty;
/* If we're only annotating types, don't actually compile this function. */ /* If we're only annotating types, don't actually compile this function. */
if (type_annotate_only) if (type_annotate_only)
return; return;
...@@ -2924,35 +2953,36 @@ update_pointer_to (tree old_type, tree new_type) ...@@ -2924,35 +2953,36 @@ update_pointer_to (tree old_type, tree new_type)
else else
{ {
tree new_obj_rec = TYPE_OBJECT_RECORD_TYPE (new_type); tree new_obj_rec = TYPE_OBJECT_RECORD_TYPE (new_type);
tree ptr_temp_type; tree fields = TYPE_FIELDS (TYPE_POINTER_TO (new_type));
tree new_ref; tree new_fields, ptr_temp_type, new_ref, bounds, var;
tree var;
SET_DECL_ORIGINAL_FIELD (TYPE_FIELDS (ptr), /* Replace contents of old pointer with those of new pointer. */
TYPE_FIELDS (TYPE_POINTER_TO (new_type))); new_fields = copy_node (fields);
TREE_CHAIN (new_fields) = copy_node (TREE_CHAIN (fields));
SET_DECL_ORIGINAL_FIELD (TYPE_FIELDS (ptr), new_fields);
SET_DECL_ORIGINAL_FIELD (TREE_CHAIN (TYPE_FIELDS (ptr)), SET_DECL_ORIGINAL_FIELD (TREE_CHAIN (TYPE_FIELDS (ptr)),
TREE_CHAIN (TYPE_FIELDS TREE_CHAIN (new_fields));
(TYPE_POINTER_TO (new_type))));
TYPE_FIELDS (ptr) = TYPE_FIELDS (TYPE_POINTER_TO (new_type)); TYPE_FIELDS (ptr) = new_fields;
DECL_CONTEXT (TYPE_FIELDS (ptr)) = ptr; DECL_CONTEXT (new_fields) = ptr;
DECL_CONTEXT (TREE_CHAIN (TYPE_FIELDS (ptr))) = ptr; DECL_CONTEXT (TREE_CHAIN (new_fields)) = ptr;
/* Rework the PLACEHOLDER_EXPR inside the reference to the /* Rework the PLACEHOLDER_EXPR inside the reference to the template
template bounds. bounds and update the pointers to them.
??? This is now the only use of gnat_substitute_in_type, which ??? This is now the only use of gnat_substitute_in_type, which
is now a very "heavy" routine to do this, so it should be replaced is now a very "heavy" routine to do this, so it should be replaced
at some point. */ at some point. */
ptr_temp_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (ptr))); bounds = TREE_TYPE (TREE_TYPE (new_fields));
ptr_temp_type = TREE_TYPE (TREE_CHAIN (new_fields));
new_ref = build3 (COMPONENT_REF, ptr_temp_type, new_ref = build3 (COMPONENT_REF, ptr_temp_type,
build0 (PLACEHOLDER_EXPR, ptr), build0 (PLACEHOLDER_EXPR, ptr),
TREE_CHAIN (TYPE_FIELDS (ptr)), NULL_TREE); TREE_CHAIN (new_fields), NULL_TREE);
update_pointer_to (bounds,
update_pointer_to gnat_substitute_in_type (bounds,
(TREE_TYPE (TREE_TYPE (TYPE_FIELDS (ptr))), TREE_CHAIN (fields),
gnat_substitute_in_type (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (ptr))), new_ref));
TREE_CHAIN (TYPE_FIELDS (ptr)), new_ref));
for (var = TYPE_MAIN_VARIANT (ptr); var; var = TYPE_NEXT_VARIANT (var)) for (var = TYPE_MAIN_VARIANT (ptr); var; var = TYPE_NEXT_VARIANT (var))
{ {
...@@ -2960,7 +2990,7 @@ update_pointer_to (tree old_type, tree new_type) ...@@ -2960,7 +2990,7 @@ update_pointer_to (tree old_type, tree new_type)
/* This may seem a bit gross, in particular wrt DECL_CONTEXT, but /* This may seem a bit gross, in particular wrt DECL_CONTEXT, but
actually is in keeping with what build_qualified_type does. */ actually is in keeping with what build_qualified_type does. */
TYPE_FIELDS (var) = TYPE_FIELDS (ptr); TYPE_FIELDS (var) = new_fields;
} }
TYPE_POINTER_TO (new_type) = TYPE_REFERENCE_TO (new_type) TYPE_POINTER_TO (new_type) = TYPE_REFERENCE_TO (new_type)
...@@ -2974,11 +3004,11 @@ update_pointer_to (tree old_type, tree new_type) ...@@ -2974,11 +3004,11 @@ update_pointer_to (tree old_type, tree new_type)
TREE_TYPE (TYPE_FIELDS (new_obj_rec)) = TREE_TYPE (ptr_temp_type); TREE_TYPE (TYPE_FIELDS (new_obj_rec)) = TREE_TYPE (ptr_temp_type);
TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (new_obj_rec))) TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (new_obj_rec)))
= TREE_TYPE (TREE_TYPE (TYPE_FIELDS (ptr))); = TREE_TYPE (TREE_TYPE (new_fields));
DECL_SIZE (TREE_CHAIN (TYPE_FIELDS (new_obj_rec))) DECL_SIZE (TREE_CHAIN (TYPE_FIELDS (new_obj_rec)))
= TYPE_SIZE (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (ptr)))); = TYPE_SIZE (TREE_TYPE (TREE_TYPE (new_fields)));
DECL_SIZE_UNIT (TREE_CHAIN (TYPE_FIELDS (new_obj_rec))) DECL_SIZE_UNIT (TREE_CHAIN (TYPE_FIELDS (new_obj_rec)))
= TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (ptr)))); = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_fields)));
TYPE_SIZE (new_obj_rec) TYPE_SIZE (new_obj_rec)
= size_binop (PLUS_EXPR, = size_binop (PLUS_EXPR,
...@@ -3096,29 +3126,18 @@ convert (tree type, tree expr) ...@@ -3096,29 +3126,18 @@ convert (tree type, tree expr)
if (type == etype) if (type == etype)
return expr; return expr;
/* If the input type has padding, remove it by doing a component reference /* If both input and output have padding and are of variable size, do this
to the field. If the output type has padding, make a constructor as an unchecked conversion. Likewise if one is a mere variant of the
to build the record. If both input and output have padding and are other, so we avoid a pointless unpad/repad sequence. */
of variable size, do this as an unchecked conversion. */
else if (ecode == RECORD_TYPE && code == RECORD_TYPE else if (ecode == RECORD_TYPE && code == RECORD_TYPE
&& TYPE_IS_PADDING_P (type) && TYPE_IS_PADDING_P (etype) && TYPE_IS_PADDING_P (type) && TYPE_IS_PADDING_P (etype)
&& (!TREE_CONSTANT (TYPE_SIZE (type)) && (!TREE_CONSTANT (TYPE_SIZE (type))
|| !TREE_CONSTANT (TYPE_SIZE (etype)))) || !TREE_CONSTANT (TYPE_SIZE (etype))
|| TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (etype)))
; ;
else if (ecode == RECORD_TYPE && TYPE_IS_PADDING_P (etype))
{ /* If the output type has padding, make a constructor to build the
/* If we have just converted to this padded type, just get record. */
the inner expression. */
if (TREE_CODE (expr) == CONSTRUCTOR
&& !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (expr))
&& VEC_index (constructor_elt, CONSTRUCTOR_ELTS (expr), 0)->index
== TYPE_FIELDS (etype))
return VEC_index (constructor_elt, CONSTRUCTOR_ELTS (expr), 0)->value;
else
return convert (type,
build_component_ref (expr, NULL_TREE,
TYPE_FIELDS (etype), false));
}
else if (code == RECORD_TYPE && TYPE_IS_PADDING_P (type)) else if (code == RECORD_TYPE && TYPE_IS_PADDING_P (type))
{ {
/* If we previously converted from another type and our type is /* If we previously converted from another type and our type is
...@@ -3154,6 +3173,31 @@ convert (tree type, tree expr) ...@@ -3154,6 +3173,31 @@ convert (tree type, tree expr)
NULL_TREE)); NULL_TREE));
} }
/* If the input type has padding, remove it and convert to the output type.
The conditions ordering is arranged to ensure that the output type is not
a padding type here, as it is not clear whether the conversion would
always be correct if this was to happen. */
else if (ecode == RECORD_TYPE && TYPE_IS_PADDING_P (etype))
{
tree unpadded;
/* If we have just converted to this padded type, just get the
inner expression. */
if (TREE_CODE (expr) == CONSTRUCTOR
&& !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (expr))
&& VEC_index (constructor_elt, CONSTRUCTOR_ELTS (expr), 0)->index
== TYPE_FIELDS (etype))
unpadded
= VEC_index (constructor_elt, CONSTRUCTOR_ELTS (expr), 0)->value;
/* Otherwise, build an explicit component reference. */
else
unpadded
= build_component_ref (expr, NULL_TREE, TYPE_FIELDS (etype), false);
return convert (type, unpadded);
}
/* If the input is a biased type, adjust first. */ /* If the input is a biased type, adjust first. */
if (ecode == INTEGER_TYPE && TYPE_BIASED_REPRESENTATION_P (etype)) if (ecode == INTEGER_TYPE && TYPE_BIASED_REPRESENTATION_P (etype))
return convert (type, fold_build2 (PLUS_EXPR, TREE_TYPE (etype), return convert (type, fold_build2 (PLUS_EXPR, TREE_TYPE (etype),
...@@ -3549,6 +3593,7 @@ unchecked_convert (tree type, tree expr, bool notrunc_p) ...@@ -3549,6 +3593,7 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
|| TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE) || TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE)
{ {
tree rtype = type; tree rtype = type;
bool final_unchecked = false;
if (TREE_CODE (etype) == INTEGER_TYPE if (TREE_CODE (etype) == INTEGER_TYPE
&& TYPE_BIASED_REPRESENTATION_P (etype)) && TYPE_BIASED_REPRESENTATION_P (etype))
...@@ -3568,9 +3613,37 @@ unchecked_convert (tree type, tree expr, bool notrunc_p) ...@@ -3568,9 +3613,37 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
TYPE_MAIN_VARIANT (rtype) = rtype; TYPE_MAIN_VARIANT (rtype) = rtype;
} }
/* We have another special case. If we are unchecked converting subtype
into a base type, we need to ensure that VRP doesn't propagate range
information since this conversion may be done precisely to validate
that the object is within the range it is supposed to have. */
else if (TREE_CODE (type) == INTEGER_TYPE && !TREE_TYPE (type)
&& ((TREE_CODE (etype) == INTEGER_TYPE && TREE_TYPE (etype))
|| TREE_CODE (etype) == ENUMERAL_TYPE
|| TREE_CODE (etype) == BOOLEAN_TYPE))
{
/* ??? The pattern to be "preserved" by the middle-end and the
optimizers is a VIEW_CONVERT_EXPR between a pair of different
"base" types (integer types without TREE_TYPE). But this may
raise addressability/aliasing issues because VIEW_CONVERT_EXPR
gets gimplified as an lvalue, thus causing the address of its
operand to be taken if it is deemed addressable and not already
in GIMPLE form. */
rtype = gnat_type_for_mode (TYPE_MODE (type), TYPE_UNSIGNED (type));
if (rtype == type)
{
rtype = copy_type (rtype);
TYPE_MAIN_VARIANT (rtype) = rtype;
}
final_unchecked = true;
}
expr = convert (rtype, expr); expr = convert (rtype, expr);
if (type != rtype) if (type != rtype)
expr = build1 (NOP_EXPR, type, expr); expr = build1 (final_unchecked ? VIEW_CONVERT_EXPR : NOP_EXPR,
type, expr);
} }
/* If we are converting TO an integral type whose precision is not the /* If we are converting TO an integral type whose precision is not the
...@@ -3684,14 +3757,19 @@ unchecked_convert (tree type, tree expr, bool notrunc_p) ...@@ -3684,14 +3757,19 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
return expr; return expr;
} }
/* Search the chain of currently reachable declarations for a builtin /* Search the chain of currently available builtin declarations for a node
FUNCTION_DECL node corresponding to function NAME (an IDENTIFIER_NODE). corresponding to function NAME (an IDENTIFIER_NODE). Return the first node
Return the first node found, if any, or NULL_TREE otherwise. */ found, if any, or NULL_TREE otherwise. */
tree tree
builtin_decl_for (tree name __attribute__ ((unused))) builtin_decl_for (tree name)
{ {
/* ??? not clear yet how to implement this function in tree-ssa, so unsigned i;
return NULL_TREE for now */ tree decl;
for (i = 0; VEC_iterate(tree, builtin_decls, i, decl); i++)
if (DECL_NAME (decl) == name)
return decl;
return NULL_TREE; return NULL_TREE;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment