From f2f4ef82f2d1a9f54bb8715b1f8b884ed8e1322a Mon Sep 17 00:00:00 2001 From: Olivier Hainque Date: Wed, 6 Jun 2007 12:21:37 +0200 Subject: [PATCH] utils2.c (build_allocator): Provide the extra arguments to make_aligning_type for super-aligned objects... 2007-04-20 Olivier Hainque Eric Botcazou * utils2.c (build_allocator): Provide the extra arguments to make_aligning_type for super-aligned objects allocated from the default pool. Leave enough room for a pointer before the aligning field, and store the system's allocator return value there. (build_call_alloc_dealloc): When releasing a super-aligned object, retrieve the system's allocator return value from where build_allocator has stored it, just ahead of the adjusted address we are passed. (build_call_raise): Handle properly the generation of line numbers when the node is marked No_Location. (compare_elmt_bitpos): Use tree_int_cst_compare. Stabilize the sort by using DECL_UID on ties. (build_binary_op) : Accept fat pointer types with the same main variant. (build_call_raise): Handle converting exception into goto; support new argument KIND. (build_component_ref): Add new arg to build_call_raise. From-SVN: r125383 --- gcc/ada/utils2.c | 193 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 143 insertions(+), 50 deletions(-) diff --git a/gcc/ada/utils2.c b/gcc/ada/utils2.c index 4a4bd7d896c..e49ba30e273 100644 --- a/gcc/ada/utils2.c +++ b/gcc/ada/utils2.c @@ -833,19 +833,22 @@ build_binary_op (enum tree_code op_code, tree result_type, } /* Otherwise, the base types must be the same unless the objects are - records. If we have records, use the best type and convert both - operands to that type. */ + fat pointers or records. If we have records, use the best type and + convert both operands to that type. */ if (left_base_type != right_base_type) { - if (TREE_CODE (left_base_type) == RECORD_TYPE - && TREE_CODE (right_base_type) == RECORD_TYPE) + if (TYPE_FAT_POINTER_P (left_base_type) + && TYPE_FAT_POINTER_P (right_base_type) + && TYPE_MAIN_VARIANT (left_base_type) + == TYPE_MAIN_VARIANT (right_base_type)) + best_type = left_base_type; + else if (TREE_CODE (left_base_type) == RECORD_TYPE + && TREE_CODE (right_base_type) == RECORD_TYPE) { /* The only way these are permitted to be the same is if both types have the same name. In that case, one of them must not be self-referential. Use that one as the best type. Even better is if one is of fixed size. */ - best_type = NULL_TREE; - gcc_assert (TYPE_NAME (left_base_type) && (TYPE_NAME (left_base_type) == TYPE_NAME (right_base_type))); @@ -860,12 +863,12 @@ build_binary_op (enum tree_code op_code, tree result_type, best_type = right_base_type; else gcc_unreachable (); - - left_operand = convert (best_type, left_operand); - right_operand = convert (best_type, right_operand); } else gcc_unreachable (); + + left_operand = convert (best_type, left_operand); + right_operand = convert (best_type, right_operand); } /* If we are comparing a fat pointer against zero, we need to @@ -1459,28 +1462,60 @@ build_call_0_expr (tree fundecl) GNAT_NODE is the gnat node conveying the source location for which the error should be signaled, or Empty in which case the error is signaled on - the current ref_file_name/input_line. */ + the current ref_file_name/input_line. + + KIND says which kind of exception this is for + (N_Raise_{Constraint,Storage,Program}_Error). */ tree -build_call_raise (int msg, Node_Id gnat_node) +build_call_raise (int msg, Node_Id gnat_node, char kind) { tree fndecl = gnat_raise_decls[msg]; + tree label = get_exception_label (kind); + tree filename; + int line_number; + const char *str; + int len; + + /* If this is to be done as a goto, handle that case. */ + if (label) + { + Entity_Id local_raise = Get_Local_Raise_Call_Entity (); + tree gnu_result = build1 (GOTO_EXPR, void_type_node, label); + + /* If Local_Raise is present, generate + Local_Raise (exception'Identity); */ + if (Present (local_raise)) + { + tree gnu_local_raise + = gnat_to_gnu_entity (local_raise, NULL_TREE, 0); + tree gnu_exception_entity + = gnat_to_gnu_entity (Get_RT_Exception_Entity (msg), NULL_TREE, 0); + tree gnu_call + = build_call_1_expr (gnu_local_raise, + build_unary_op (ADDR_EXPR, NULL_TREE, + gnu_exception_entity)); + + gnu_result = build2 (COMPOUND_EXPR, void_type_node, + gnu_call, gnu_result);} + + return gnu_result; + } - const char *str + str = (Debug_Flag_NN || Exception_Locations_Suppressed) ? "" - : (gnat_node != Empty) + : (gnat_node != Empty && Sloc (gnat_node) != No_Location) ? IDENTIFIER_POINTER (get_identifier (Get_Name_String (Debug_Source_Name (Get_Source_File_Index (Sloc (gnat_node)))))) : ref_filename; - int len = strlen (str) + 1; - tree filename = build_string (len, str); - - int line_number - = (gnat_node != Empty) + len = strlen (str) + 1; + filename = build_string (len, str); + line_number + = (gnat_node != Empty && Sloc (gnat_node) != No_Location) ? Get_Logical_Line_Number (Sloc(gnat_node)) : input_line; TREE_TYPE (filename) @@ -1502,16 +1537,12 @@ compare_elmt_bitpos (const PTR rt1, const PTR rt2) { tree elmt1 = * (tree *) rt1; tree elmt2 = * (tree *) rt2; + tree field1 = TREE_PURPOSE (elmt1); + tree field2 = TREE_PURPOSE (elmt2); + int ret; - tree pos_field1 = bit_position (TREE_PURPOSE (elmt1)); - tree pos_field2 = bit_position (TREE_PURPOSE (elmt2)); - - if (tree_int_cst_equal (pos_field1, pos_field2)) - return 0; - else if (tree_int_cst_lt (pos_field1, pos_field2)) - return -1; - else - return 1; + ret = tree_int_cst_compare (bit_position (field1), bit_position (field2)); + return ret ? ret : (int) (DECL_UID (field1) - DECL_UID (field2)); } /* Return a CONSTRUCTOR of TYPE whose list is LIST. */ @@ -1552,13 +1583,11 @@ gnat_build_constructor (tree type, tree list) /* For record types with constant components only, sort field list by increasing bit position. This is necessary to ensure the - constructor can be output as static data, which the gimplifier - might force in various circumstances. */ + constructor can be output as static data. */ if (allconstant && TREE_CODE (type) == RECORD_TYPE && n_elmts > 1) { /* Fill an array with an element tree per index, and ask qsort to order them according to what a bitpos comparison function says. */ - tree *gnu_arr = (tree *) alloca (sizeof (tree) * n_elmts); int i; @@ -1568,7 +1597,6 @@ gnat_build_constructor (tree type, tree list) qsort (gnu_arr, n_elmts, sizeof (tree), compare_elmt_bitpos); /* Then reconstruct the list from the sorted array contents. */ - list = NULL_TREE; for (i = n_elmts - 1; i >= 0; i--) { @@ -1701,7 +1729,8 @@ build_component_ref (tree record_variable, tree component, abort. */ gcc_assert (field); return build1 (NULL_EXPR, TREE_TYPE (field), - build_call_raise (CE_Discriminant_Check_Failed, Empty)); + build_call_raise (CE_Discriminant_Check_Failed, Empty, + N_Raise_Constraint_Error)); } /* Build a GCC tree to call an allocation or deallocation function. @@ -1785,7 +1814,34 @@ build_call_alloc_dealloc (tree gnu_obj, tree gnu_size, unsigned align, } else if (gnu_obj) - return build_call_1_expr (free_decl, gnu_obj); + { + /* If the required alignement was greater than what malloc guarantees, + what we have in gnu_obj here is an address dynamically adjusted to + match the requirement (see build_allocator). What we need to pass + to free is the initial underlying allocator's return value, which + has been stored just in front of the block we have. */ + if (align > BIGGEST_ALIGNMENT) + { + /* We set GNU_OBJ + as * (void **)((void *)GNU_OBJ - (void *)sizeof(void *)) + in two steps: */ + + /* GNU_OBJ (void *) = (void *)GNU_OBJ - (void *)sizeof (void *)) */ + gnu_obj + = build_binary_op (MINUS_EXPR, ptr_void_type_node, + convert (ptr_void_type_node, gnu_obj), + convert (ptr_void_type_node, + TYPE_SIZE_UNIT (ptr_void_type_node))); + + /* GNU_OBJ (void *) = *(void **)GNU_OBJ */ + gnu_obj + = build_unary_op (INDIRECT_REF, NULL_TREE, + convert (build_pointer_type (ptr_void_type_node), + gnu_obj)); + } + + return build_call_1_expr (free_decl, gnu_obj); + } /* ??? For now, disable variable-sized allocators in the stack since we can't yet gimplify an ALLOCATE_EXPR. */ @@ -1936,25 +1992,62 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, if (TREE_CODE (size) == INTEGER_CST && TREE_OVERFLOW (size)) size = ssize_int (-1); - /* If this is a type whose alignment is larger than the - biggest we support in normal alignment and this is in - the default storage pool, make an "aligning type", allocate - it, point to the field we need, and return that. */ - if (TYPE_ALIGN (type) > BIGGEST_ALIGNMENT - && No (gnat_proc)) + /* If this is a type whose alignment is larger than what the underlying + allocator supports and this is in the default storage pool, make an + "aligning" record type with room to store a pointer before the field, + allocate an object of that type, store the system's allocator return + value just in front of the field and return the field's address. */ + + if (TYPE_ALIGN (type) > BIGGEST_ALIGNMENT && No (gnat_proc)) { - tree new_type = make_aligning_type (type, TYPE_ALIGN (type), size); + /* Construct the aligning type with enough room for a pointer ahead + of the field, then allocate. */ + tree record_type + = make_aligning_type (type, TYPE_ALIGN (type), size, + BIGGEST_ALIGNMENT, POINTER_SIZE / BITS_PER_UNIT); - result = build_call_alloc_dealloc (NULL_TREE, TYPE_SIZE_UNIT (new_type), - BIGGEST_ALIGNMENT, Empty, - Empty, gnat_node); - result = save_expr (result); - result = convert (build_pointer_type (new_type), result); - result = build_unary_op (INDIRECT_REF, NULL_TREE, result); - result = build_component_ref (result, NULL_TREE, - TYPE_FIELDS (new_type), 0); - result = convert (result_type, - build_unary_op (ADDR_EXPR, NULL_TREE, result)); + tree record, record_addr; + + record_addr + = build_call_alloc_dealloc (NULL_TREE, TYPE_SIZE_UNIT (record_type), + BIGGEST_ALIGNMENT, Empty, Empty, + gnat_node); + + record_addr + = convert (build_pointer_type (record_type), + save_expr (record_addr)); + + record = build_unary_op (INDIRECT_REF, NULL_TREE, record_addr); + + /* Our RESULT (the Ada allocator's value) is the super-aligned address + of the internal record field ... */ + result + = build_unary_op (ADDR_EXPR, NULL_TREE, + build_component_ref + (record, NULL_TREE, TYPE_FIELDS (record_type), 0)); + result = convert (result_type, result); + + /* ... with the system allocator's return value stored just in + front. */ + { + tree ptr_addr + = build_binary_op (MINUS_EXPR, ptr_void_type_node, + convert (ptr_void_type_node, result), + convert (ptr_void_type_node, + TYPE_SIZE_UNIT (ptr_void_type_node))); + + tree ptr_ref + = convert (build_pointer_type (ptr_void_type_node), ptr_addr); + + result + = build2 (COMPOUND_EXPR, TREE_TYPE (result), + build_binary_op (MODIFY_EXPR, NULL_TREE, + build_unary_op (INDIRECT_REF, NULL_TREE, + ptr_ref), + convert (ptr_void_type_node, + record_addr)), + result); + } } else result = convert (result_type, -- 2.30.2