struct Elist_Header *elists_ptr, struct Elmt_Item *elmts_ptr,
struct String_Entry *strings_ptr, Char_Code *string_chars_ptr,
struct List_Header *list_headers_ptr, Nat number_file,
- struct File_Info_Type *file_info_ptr, Entity_Id standard_boolean,
- Entity_Id standard_integer, Entity_Id standard_long_long_float,
+ struct File_Info_Type *file_info_ptr,
+ Entity_Id standard_boolean, Entity_Id standard_integer,
+ Entity_Id standard_character, Entity_Id standard_long_long_float,
Entity_Id standard_exception_type, Int gigi_operating_mode)
{
Entity_Id gnat_literal;
double_float_alignment = get_target_double_float_alignment ();
double_scalar_alignment = get_target_double_scalar_alignment ();
- /* Record the builtin types. Define `integer' and `unsigned char' first so
- that dbx will output them first. */
+ /* Record the builtin types. Define `integer' and `character' first so that
+ dbx will output them first. */
record_builtin_type ("integer", integer_type_node);
- record_builtin_type ("unsigned char", char_type_node);
- record_builtin_type ("long integer", long_integer_type_node);
- unsigned_type_node = gnat_type_for_size (INT_TYPE_SIZE, 1);
- record_builtin_type ("unsigned int", unsigned_type_node);
- record_builtin_type (SIZE_TYPE, sizetype);
+ record_builtin_type ("character", unsigned_char_type_node);
record_builtin_type ("boolean", boolean_type_node);
record_builtin_type ("void", void_type_node);
/* Save the type we made for integer as the type for Standard.Integer. */
- save_gnu_tree (Base_Type (standard_integer), TYPE_NAME (integer_type_node),
+ save_gnu_tree (Base_Type (standard_integer),
+ TYPE_NAME (integer_type_node),
false);
- /* Save the type we made for boolean as the type for Standard.Boolean. */
- save_gnu_tree (Base_Type (standard_boolean), TYPE_NAME (boolean_type_node),
+ /* Likewise for character as the type for Standard.Character. */
+ save_gnu_tree (Base_Type (standard_character),
+ TYPE_NAME (unsigned_char_type_node),
+ false);
+
+ /* Likewise for boolean as the type for Standard.Boolean. */
+ save_gnu_tree (Base_Type (standard_boolean),
+ TYPE_NAME (boolean_type_node),
false);
gnat_literal = First_Literal (Base_Type (standard_boolean));
t = UI_To_gnu (Enumeration_Rep (gnat_literal), boolean_type_node);
/* Name of the _Parent field in tagged record types. */
parent_name_id = get_identifier (Get_Name_String (Name_uParent));
+ /* Name of the Exception_Data type defined in System.Standard_Library. */
+ exception_data_name_id
+ = get_identifier ("system__standard_library__exception_data");
+
/* Make the types and functions used for exception processing. */
jmpbuf_type
= build_array_type (gnat_type_for_mode (Pmode, 0),
(get_identifier ("__gnat_last_chance_handler"), NULL_TREE,
build_function_type (void_type_node,
tree_cons (NULL_TREE,
- build_pointer_type (char_type_node),
+ build_pointer_type
+ (unsigned_char_type_node),
tree_cons (NULL_TREE,
integer_type_node,
t))),
build_function_type (void_type_node,
tree_cons (NULL_TREE,
build_pointer_type
- (char_type_node),
+ (unsigned_char_type_node),
tree_cons (NULL_TREE,
integer_type_node,
t))),
TYPE_QUAL_VOLATILE);
}
- /* Set the types that GCC and Gigi use from the front end. We would
- like to do this for char_type_node, but it needs to correspond to
- the C char type. */
+ /* Set the types that GCC and Gigi use from the front end. */
exception_type
= gnat_to_gnu_entity (Base_Type (standard_exception_type), NULL_TREE, 0);
except_type_node = TREE_TYPE (exception_type);
for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; j++)
{
- tree field = create_field_decl (NULL_TREE, ptr_void_ftype,
- fdesc_type_node, 0, 0, 0, 1);
+ tree field
+ = create_field_decl (NULL_TREE, ptr_void_ftype, fdesc_type_node,
+ NULL_TREE, NULL_TREE, 0, 1);
TREE_CHAIN (field) = field_list;
field_list = field;
null_list = tree_cons (field, null_node, null_list);
if (TREE_CODE (gnu_obj_type) == RECORD_TYPE
&& TYPE_CONTAINS_TEMPLATE_P (gnu_obj_type))
{
- tree gnu_char_ptr_type = build_pointer_type (char_type_node);
+ tree gnu_char_ptr_type
+ = build_pointer_type (unsigned_char_type_node);
tree gnu_pos = byte_position (TYPE_FIELDS (gnu_obj_type));
gnu_ptr = convert (gnu_char_ptr_type, gnu_ptr);
gnu_ptr = build_binary_op (POINTER_PLUS_EXPR, gnu_char_ptr_type,
gnu_type
= build_unc_object_type_from_ptr (gnu_ptr_type,
gnu_actual_obj_type,
- get_identifier ("SIZE"));
+ get_identifier ("SIZE"),
+ false);
}
gnu_result = TYPE_SIZE (gnu_type);
tree gnu_subprog_addr = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_subprog);
Entity_Id gnat_formal;
Node_Id gnat_actual;
- tree gnu_actual_list = NULL_TREE;
+ VEC(tree,gc) *gnu_actual_vec = NULL;
tree gnu_name_list = NULL_TREE;
tree gnu_before_list = NULL_TREE;
tree gnu_after_list = NULL_TREE;
if (Nkind (gnat_node) == N_Function_Call && !gnu_target)
{
- *gnu_result_type_p = TREE_TYPE (gnu_subprog_type);
- return build1 (NULL_EXPR, TREE_TYPE (gnu_subprog_type), call_expr);
+ tree gnu_obj_type;
+
+ if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_ret_type)))
+ gnu_obj_type
+ = maybe_pad_type (gnu_ret_type,
+ max_size (TYPE_SIZE (gnu_ret_type), true),
+ 0, Etype (Name (gnat_node)), false, false,
+ false, true);
+ else
+ gnu_obj_type = gnu_ret_type;
+
+ /* ??? We may be about to create a static temporary if we happen to
+ be at the global binding level. That's a regression from what
+ the 3.x back-end would generate in the same situation, but we
+ don't have a mechanism in Gigi for creating automatic variables
+ in the elaboration routines. */
+ gnu_target
+ = create_var_decl (create_tmp_var_name ("LR"), NULL, gnu_obj_type,
+ NULL, false, false, false, false, NULL,
+ gnat_node);
+
+ *gnu_result_type_p = gnu_ret_type;
}
return call_expr;
gnu_actual = convert (DECL_ARG_TYPE (gnu_formal), gnu_actual);
}
- gnu_actual_list = tree_cons (NULL_TREE, gnu_actual, gnu_actual_list);
+ VEC_safe_push (tree, gc, gnu_actual_vec, gnu_actual);
}
- gnu_call = build_call_list (TREE_TYPE (gnu_subprog_type), gnu_subprog_addr,
- nreverse (gnu_actual_list));
- set_expr_location_from_node (gnu_call, gnat_node);
+ gnu_subprog_call = build_call_list (TREE_TYPE (gnu_subprog_type),
+ gnu_subprog_addr,
+ nreverse (gnu_actual_list));
+ set_expr_location_from_node (gnu_subprog_call, gnat_node);
- /* If it's a function call, the result is the call expression unless a target
- is specified, in which case we copy the result into the target and return
- the assignment statement. */
- if (Nkind (gnat_node) == N_Function_Call)
+ /* If we return by passing a target, the result is the target after the
+ call. We must not emit the call directly here because this might be
+ evaluated as part of an expression with conditions to control whether
+ the call should be emitted or not. */
+ if (TYPE_RETURNS_BY_TARGET_PTR_P (gnu_subprog_type))
+ {
+ /* Conceptually, what we need is a COMPOUND_EXPR of the call followed by
+ the target object. Doing so would potentially be inefficient though,
+ as this expression might be wrapped up into a SAVE_EXPR later, which
+ would incur a pointless temporary copy of the whole object.
+
+ What we do instead is build a COMPOUND_EXPR returning the address of
+ the target, and then dereference. Wrapping up the COMPOUND_EXPR into
+ a SAVE_EXPR then only incurs a mere pointer copy. */
+ tree gnu_target_addr = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_target);
+ set_expr_location_from_node (gnu_target_addr, gnat_node);
+ gnu_result = build2 (COMPOUND_EXPR, TREE_TYPE (gnu_target_addr),
+ gnu_subprog_call, gnu_target_addr);
+ return build_unary_op (INDIRECT_REF, NULL_TREE, gnu_result);
+ }
+
+ /* If it is a function call, the result is the call expression unless
+ a target is specified, in which case we copy the result into the target
+ and return the assignment statement. */
+ else if (Nkind (gnat_node) == N_Function_Call)
{
tree gnu_result = gnu_call;
gnu_result
= build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_lhs, gnu_rhs);
- /* If the type being assigned is an array type and the two sides
- are not completely disjoint, play safe and use memmove. */
+ /* If the type being assigned is an array type and the two sides are
+ not completely disjoint, play safe and use memmove. But don't do
+ it for a bit-packed array as it might not be byte-aligned. */
if (TREE_CODE (gnu_result) == MODIFY_EXPR
&& Is_Array_Type (Etype (Name (gnat_node)))
+ && !Is_Bit_Packed_Array (Etype (Name (gnat_node)))
&& !(Forwards_OK (gnat_node) && Backwards_OK (gnat_node)))
{
tree to, from, size, to_ptr, from_ptr, t;
gnu_actual_obj_type
= build_unc_object_type_from_ptr (gnu_ptr_type,
gnu_actual_obj_type,
- get_identifier
- ("DEALLOC"));
+ get_identifier ("DEALLOC"),
+ false);
}
else
gnu_actual_obj_type = gnu_obj_type;
if (TREE_CODE (gnu_obj_type) == RECORD_TYPE
&& TYPE_CONTAINS_TEMPLATE_P (gnu_obj_type))
{
- tree gnu_char_ptr_type = build_pointer_type (char_type_node);
+ tree gnu_char_ptr_type
+ = build_pointer_type (unsigned_char_type_node);
tree gnu_pos = byte_position (TYPE_FIELDS (gnu_obj_type));
gnu_ptr = convert (gnu_char_ptr_type, gnu_ptr);
gnu_ptr = build_binary_op (POINTER_PLUS_EXPR, gnu_char_ptr_type,
the reference is in an elaboration procedure. */
if (TREE_CONSTANT (op))
{
- tree new_var = create_tmp_var_raw (TREE_TYPE (op), "C");
- TREE_ADDRESSABLE (new_var) = 1;
- gimple_add_tmp_var (new_var);
-
- TREE_READONLY (new_var) = 1;
- TREE_STATIC (new_var) = 1;
- DECL_INITIAL (new_var) = op;
-
- TREE_OPERAND (expr, 0) = new_var;
- recompute_tree_invariant_for_addr_expr (expr);
+ tree addr = build_fold_addr_expr (tree_output_constant_def (op));
+ *expr_p = fold_convert (TREE_TYPE (expr), addr);
}
/* Otherwise explicitly create the local temporary. That's required
return exp;
}
\f
+/* Protect EXP from multiple evaluation. This may make a SAVE_EXPR. */
+
+tree
+protect_multiple_eval (tree exp)
+{
+ tree type = TREE_TYPE (exp);
+
+ /* If EXP has no side effects, we theoritically don't need to do anything.
+ However, we may be recursively passed more and more complex expressions
+ involving checks which will be reused multiple times and eventually be
+ unshared for gimplification; in order to avoid a complexity explosion
+ at that point, we protect any expressions more complex than a simple
+ arithmetic expression. */
+ if (!TREE_SIDE_EFFECTS (exp)
+ && (CONSTANT_CLASS_P (exp)
+ || !EXPRESSION_CLASS_P (skip_simple_arithmetic (exp))))
+ return exp;
+
+ /* If this is a conversion, protect what's inside the conversion.
+ Similarly, if we're indirectly referencing something, we only
+ need to protect the address since the data itself can't change
+ in these situations. */
+ if (TREE_CODE (exp) == NON_LVALUE_EXPR
+ || CONVERT_EXPR_P (exp)
+ || TREE_CODE (exp) == VIEW_CONVERT_EXPR
+ || TREE_CODE (exp) == INDIRECT_REF
+ || TREE_CODE (exp) == UNCONSTRAINED_ARRAY_REF)
+ return build1 (TREE_CODE (exp), type,
+ protect_multiple_eval (TREE_OPERAND (exp, 0)));
+
+ /* If this is a fat pointer or something that can be placed in a register,
+ just make a SAVE_EXPR. Likewise for a CALL_EXPR as large objects are
+ returned via invisible reference in most ABIs so the temporary will
+ directly be filled by the callee. */
+ if (TYPE_IS_FAT_POINTER_P (type)
+ || TYPE_MODE (type) != BLKmode
+ || TREE_CODE (exp) == CALL_EXPR)
+ return save_expr (exp);
+
+ /* Otherwise reference, protect the address and dereference. */
+ return
+ build_unary_op (INDIRECT_REF, type,
+ save_expr (build_unary_op (ADDR_EXPR,
+ build_reference_type (type),
+ exp)));
+}
+\f
+/* This is equivalent to stabilize_reference in tree.c, but we know how to
+ handle our own nodes and we take extra arguments. FORCE says whether to
+ force evaluation of everything. We set SUCCESS to true unless we walk
+ through something we don't know how to stabilize. */
+
+tree
+maybe_stabilize_reference (tree ref, bool force, bool *success)
+{
+ tree type = TREE_TYPE (ref);
+ enum tree_code code = TREE_CODE (ref);
+ tree result;
+
+ /* Assume we'll success unless proven otherwise. */
+ *success = true;
+
+ switch (code)
+ {
+ case CONST_DECL:
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ /* No action is needed in this case. */
+ return ref;
+
+ case ADDR_EXPR:
+ CASE_CONVERT:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case VIEW_CONVERT_EXPR:
+ result
+ = build1 (code, type,
+ maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
+ success));
+ break;
+
+ case INDIRECT_REF:
+ case UNCONSTRAINED_ARRAY_REF:
+ result = build1 (code, type,
+ gnat_stabilize_reference_1 (TREE_OPERAND (ref, 0),
+ force));
+ break;
+
+ case COMPONENT_REF:
+ result = build3 (COMPONENT_REF, type,
+ maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
+ success),
+ TREE_OPERAND (ref, 1), NULL_TREE);
+ break;
+
+ case BIT_FIELD_REF:
+ result = build3 (BIT_FIELD_REF, type,
+ maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
+ success),
+ gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
+ force),
+ gnat_stabilize_reference_1 (TREE_OPERAND (ref, 2),
+ force));
+ break;
+
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ result = build4 (code, type,
+ maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
+ success),
+ gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
+ force),
+ NULL_TREE, NULL_TREE);
+ break;
+
+ case CALL_EXPR:
+ case COMPOUND_EXPR:
+ result = gnat_stabilize_reference_1 (ref, force);
+ break;
+
+ case CONSTRUCTOR:
+ /* Constructors with 1 element are used extensively to formally
+ convert objects to special wrapping types. */
+ if (TREE_CODE (type) == RECORD_TYPE
+ && VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ref)) == 1)
+ {
+ tree index
+ = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (ref), 0)->index;
+ tree value
+ = VEC_index (constructor_elt, CONSTRUCTOR_ELTS (ref), 0)->value;
+ result
+ = build_constructor_single (type, index,
+ gnat_stabilize_reference_1 (value,
+ force));
+ }
+ else
+ {
+ *success = false;
+ return ref;
+ }
+ break;
+
+ case ERROR_MARK:
+ ref = error_mark_node;
+
+ /* ... fall through to failure ... */
+
+ /* If arg isn't a kind of lvalue we recognize, make no change.
+ Caller should recognize the error for an invalid lvalue. */
+ default:
+ *success = false;
+ return ref;
+ }
+
+ TREE_READONLY (result) = TREE_READONLY (ref);
+
+ /* TREE_THIS_VOLATILE and TREE_SIDE_EFFECTS attached to the initial
+ expression may not be sustained across some paths, such as the way via
+ build1 for INDIRECT_REF. We re-populate those flags here for the general
+ case, which is consistent with the GCC version of this routine.
+
+ Special care should be taken regarding TREE_SIDE_EFFECTS, because some
+ paths introduce side effects where there was none initially (e.g. calls
+ to save_expr), and we also want to keep track of that. */
+
+ TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
+ TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (ref);
+
+ return result;
+}
+
+/* Wrapper around maybe_stabilize_reference, for common uses without
+ lvalue restrictions and without need to examine the success
+ indication. */
+
+static tree
+gnat_stabilize_reference (tree ref, bool force)
+{
+ bool dummy;
+ return maybe_stabilize_reference (ref, force, &dummy);
+}
+
+/* Similar to stabilize_reference_1 in tree.c, but supports an extra
+ arg to force a SAVE_EXPR for everything. */
+
+static tree
+gnat_stabilize_reference_1 (tree e, bool force)
+{
+ enum tree_code code = TREE_CODE (e);
+ tree type = TREE_TYPE (e);
+ tree result;
+
+ /* We cannot ignore const expressions because it might be a reference
+ to a const array but whose index contains side-effects. But we can
+ ignore things that are actual constant or that already have been
+ handled by this function. */
+
+ if (TREE_CONSTANT (e) || code == SAVE_EXPR)
+ return e;
+
+ switch (TREE_CODE_CLASS (code))
+ {
+ case tcc_exceptional:
+ case tcc_type:
+ case tcc_declaration:
+ case tcc_comparison:
+ case tcc_statement:
+ case tcc_expression:
+ case tcc_reference:
+ case tcc_vl_exp:
+ /* If this is a COMPONENT_REF of a fat pointer, save the entire
+ fat pointer. This may be more efficient, but will also allow
+ us to more easily find the match for the PLACEHOLDER_EXPR. */
+ if (code == COMPONENT_REF
+ && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (e, 0))))
+ result = build3 (COMPONENT_REF, type,
+ gnat_stabilize_reference_1 (TREE_OPERAND (e, 0),
+ force),
+ TREE_OPERAND (e, 1), TREE_OPERAND (e, 2));
+ else if (TREE_SIDE_EFFECTS (e) || force)
+ return save_expr (e);
+ else
+ return e;
+ break;
+
+ case tcc_constant:
+ /* Constants need no processing. In fact, we should never reach
+ here. */
+ return e;
+
+ case tcc_binary:
+ /* Recursively stabilize each operand. */
+ result = build2 (code, type,
+ gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force),
+ gnat_stabilize_reference_1 (TREE_OPERAND (e, 1),
+ force));
+ break;
+
+ case tcc_unary:
+ /* Recursively stabilize each operand. */
+ result = build1 (code, type,
+ gnat_stabilize_reference_1 (TREE_OPERAND (e, 0),
+ force));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ TREE_READONLY (result) = TREE_READONLY (e);
+
+ TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
+ TREE_SIDE_EFFECTS (result) |= TREE_SIDE_EFFECTS (e);
+ return result;
+}
+\f
/* Convert SLOC into LOCUS. Return true if SLOC corresponds to a source code
location and false if it doesn't. In the former case, set the Gigi global
variable REF_FILENAME to the simple debug file name as given by sinput. */