https://gcc.gnu.org/g:f6788211809dab7ba4568bcefe620ca11f448a32
commit f6788211809dab7ba4568bcefe620ca11f448a32 Author: Mikael Morin <mik...@gcc.gnu.org> Date: Wed Jun 11 11:24:05 2025 +0200 gimple-exec: implementation memcpy et correction gestion mémoire Diff: --- gcc/cgraphunit.cc | 262 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 221 insertions(+), 41 deletions(-) diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc index 268e4d66a419..2a50ea931b44 100644 --- a/gcc/cgraphunit.cc +++ b/gcc/cgraphunit.cc @@ -2450,6 +2450,7 @@ namespace selftest void exec_context_evaluate_unary_tests (); void exec_context_evaluate_binary_tests (); void exec_context_execute_assign_tests (); + void exec_context_print_call_tests (); void exec_context_execute_call_tests (); void exec_context_allocate_tests (); void exec_context_evaluate_condition_tests (); @@ -2462,7 +2463,7 @@ class data_value wide_int constant_mask; wide_int address_mask; wide_int constant_value; - vec<stored_address> addresses; + auto_vec<stored_address> addresses; void set_cst_at (unsigned dest_offset, unsigned value_width, const wide_int &val, unsigned src_offset); stored_address *find_address (HOST_WIDE_INT offset) const; @@ -2583,6 +2584,7 @@ class context_printer friend void selftest::context_printer_print_tests (); friend void selftest::context_printer_print_first_data_ref_part_tests (); friend void selftest::context_printer_print_value_update_tests (); + friend void selftest::exec_context_print_call_tests (); public: context_printer (); @@ -2595,7 +2597,9 @@ public: void print_function_exit (struct function * func); void print_bb_jump (edge e); void print_bb_entry (basic_block bb); - tree print_first_data_ref_part (exec_context & context, tree data_ref, unsigned offset, int * ignored_bits); + tree print_first_data_ref_part (exec_context & context, tree data_ref, + unsigned offset, int * ignored_bits, + enum value_type); void print_ignored_stmt (); void print_value_update (exec_context & context, tree, const data_value &); void end_stmt (gimple *); @@ -2976,7 +2980,8 @@ context_printer::print_bb_entry (basic_block bb) static tree -pick_subref_at (tree var_ref, unsigned offset, int * ignored_bits) +pick_subref_at (tree var_ref, unsigned offset, int * ignored_bits, + unsigned min_size) { tree ref = var_ref; unsigned remaining_offset = offset; @@ -2988,11 +2993,15 @@ pick_subref_at (tree var_ref, unsigned offset, int * ignored_bits) tree elt_type = TREE_TYPE (var_type); unsigned elt_width; gcc_assert (get_constant_type_size (elt_type, elt_width)); + if (elt_width < min_size) + return NULL_TREE; unsigned HOST_WIDE_INT hw_idx = remaining_offset / elt_width; tree t_idx = build_int_cst (integer_type_node, hw_idx); ref = build4 (ARRAY_REF, elt_type, ref, t_idx, NULL_TREE, NULL_TREE); remaining_offset -= hw_idx * elt_width; + if (elt_width == min_size) + break; } else if (TREE_CODE (var_type) == RECORD_TYPE) { @@ -3029,7 +3038,15 @@ pick_subref_at (tree var_ref, unsigned offset, int * ignored_bits) gcc_assert (field != NULL_TREE && field_position >= 0); - ref = build3 (COMPONENT_REF, TREE_TYPE (field), + tree field_type = TREE_TYPE (field); + + unsigned field_width; + if (!get_constant_type_size (field_type, field_width)) + gcc_unreachable (); + else if (field_width < min_size) + return NULL_TREE; + + ref = build3 (COMPONENT_REF, field_type, ref, field, NULL_TREE); if (field_position > remaining_offset) { @@ -3039,6 +3056,9 @@ pick_subref_at (tree var_ref, unsigned offset, int * ignored_bits) } else remaining_offset -= field_position; + + if (field_width == min_size) + break; } else break; @@ -3057,7 +3077,7 @@ pick_subref_at (tree var_ref, unsigned offset, int * ignored_bits) static tree find_mem_ref_replacement (exec_context & context, tree data_ref, - unsigned offset) + unsigned offset, unsigned min_size) { tree ptr = TREE_OPERAND (data_ref, 0); data_value ptr_val = context.evaluate (ptr); @@ -3076,42 +3096,76 @@ find_mem_ref_replacement (exec_context & context, tree data_ref, if (var_type == access_type) return var_ref; else - { - tree access_offset = TREE_OPERAND (data_ref, 1); - gcc_assert (TREE_CONSTANT (access_offset)); - gcc_assert (tree_fits_shwi_p (access_offset)); - HOST_WIDE_INT shwi_offset = tree_to_shwi (access_offset); - gcc_assert (offset < UINT_MAX - shwi_offset); - HOST_WIDE_INT remaining_offset = shwi_offset * CHAR_BIT - + offset + ptr_address->offset; - - return pick_subref_at (var_ref, remaining_offset, nullptr); - } + { + tree access_offset = TREE_OPERAND (data_ref, 1); + gcc_assert (TREE_CONSTANT (access_offset)); + gcc_assert (tree_fits_shwi_p (access_offset)); + HOST_WIDE_INT shwi_offset = tree_to_shwi (access_offset); + gcc_assert (offset < UINT_MAX - shwi_offset); + HOST_WIDE_INT remaining_offset = shwi_offset * CHAR_BIT + + offset + ptr_address->offset; + + return pick_subref_at (var_ref, remaining_offset, nullptr, min_size); + } } tree -context_printer::print_first_data_ref_part (exec_context & context, tree data_ref, unsigned offset, int * ignored_bits) -{ +context_printer::print_first_data_ref_part (exec_context & context, + tree data_ref, unsigned offset, + int * ignored_bits, + enum value_type val_type) +{ + unsigned min_size; + if (val_type == VAL_ADDRESS) + min_size = HOST_BITS_PER_PTR; + else + min_size = CHAR_BIT; + + tree default_ref = NULL_TREE; switch (TREE_CODE (data_ref)) { case MEM_REF: { tree mem_replacement = find_mem_ref_replacement (context, data_ref, - offset); + offset, min_size); if (mem_replacement != NULL_TREE) - return print_first_data_ref_part (context, mem_replacement, 0, ignored_bits); + return print_first_data_ref_part (context, mem_replacement, 0, ignored_bits, + val_type); + + unsigned orig_type_size; + if (!get_constant_type_size (TREE_TYPE (data_ref), orig_type_size)) + gcc_unreachable (); + else if (min_size < orig_type_size) + { + tree elt_type; + if (val_type == VAL_ADDRESS) + elt_type = ptr_type_node; + else + elt_type = char_type_node; + + gcc_assert (offset % CHAR_BIT == 0); + tree ptr_type = build_pointer_type (elt_type); + default_ref = build2 (MEM_REF, elt_type, + TREE_OPERAND (data_ref, 0), + build_int_cst (ptr_type, offset / CHAR_BIT)); + } + else + gcc_assert (min_size == orig_type_size); } /* Fall through. */ default: - tree ref = pick_subref_at (data_ref, offset, ignored_bits); + tree ref = pick_subref_at (data_ref, offset, ignored_bits, min_size); if (ref == NULL_TREE) { - gcc_assert (ignored_bits != nullptr - && *ignored_bits > 0); - return NULL_TREE; + if (ignored_bits != nullptr && *ignored_bits > 0) + return NULL_TREE; + + ref = default_ref; + if (ref == NULL_TREE) + ref = data_ref; } pp_indent (&pp); @@ -3139,10 +3193,10 @@ context_printer::print_value_update (exec_context & context, tree lhs, const dat unsigned width = get_constant_type_size (TREE_TYPE (lhs)); while (previously_done < width) { + enum value_type val_type = value.classify (previously_done, 1); int ignored_bits = 0; - tree type_done = print_first_data_ref_part (context, lhs, - previously_done, - &ignored_bits); + tree type_done = print_first_data_ref_part (context, lhs, previously_done, + &ignored_bits, val_type); if (type_done == NULL_TREE) { gcc_assert (ignored_bits > 0); @@ -3221,7 +3275,7 @@ data_value::data_value (const data_value & other) constant_mask (other.constant_mask), address_mask (other.address_mask), constant_value (other.constant_value), - addresses (other.addresses) + addresses (other.addresses.copy ()) {} @@ -4442,10 +4496,17 @@ exec_context::execute_call (gcall *g) data_storage & storage1 = addr1.storage.get (); data_value src = storage1.get_value (); wide_int wi_len2 = len2.get_cst (); + gcc_assert (wi::fits_shwi_p (wi_len2)); + HOST_WIDE_INT hwi_len2 = wi_len2.to_shwi (); + tree array_len2 = build_array_type_nelts (char_type_node, hwi_len2); + tree data_target = build2 (MEM_REF, array_len2, arg0, + build_zero_cst (ptr_type_node)); wi_len2 *= CHAR_BIT; gcc_assert (wi::fits_uhwi_p (wi_len2)); - dest_val.set_at (0, wi_len2.to_uhwi (), - src, addr1.offset); + unsigned HOST_WIDE_INT uhwi_len2 = wi_len2.to_uhwi (); + data_value data_src = src.get_at (addr1.offset, uhwi_len2); + printer.print_value_update (*this, data_target, data_src); + dest_val.set_at (0, uhwi_len2, src, addr1.offset); storage0.set (dest_val); } else if (gimple_call_builtin_p (g, BUILT_IN_MEMSET)) @@ -6078,7 +6139,8 @@ context_printer_print_first_data_ref_part_tests () pretty_printer & pp1 = printer1.pp; exec_context ctx1 = context_builder ().build (mem1, printer1); - tree res1 = printer1.print_first_data_ref_part (ctx1, var2i, 0, nullptr); + tree res1 = printer1.print_first_data_ref_part (ctx1, var2i, 0, nullptr, + VAL_UNDEFINED); ASSERT_EQ (res1, integer_type_node); const char * str1 = pp_formatted_text (&pp1); @@ -6099,7 +6161,8 @@ context_printer_print_first_data_ref_part_tests () build1 (ADDR_EXPR, ptr_type_node, var2i), build_zero_cst (ptr_type_node)); - tree res2 = printer2.print_first_data_ref_part (ctx2, mem_var2i, 0, nullptr); + tree res2 = printer2.print_first_data_ref_part (ctx2, mem_var2i, 0, nullptr, + VAL_UNDEFINED); ASSERT_EQ (res2, integer_type_node); const char * str2 = pp_formatted_text (&pp2); @@ -6117,7 +6180,8 @@ context_printer_print_first_data_ref_part_tests () build1 (ADDR_EXPR, ptr_type_node, var2i), build_zero_cst (ptr_type_node)); - tree res3 = printer3.print_first_data_ref_part (ctx3, long_var2i, 0, nullptr); + tree res3 = printer3.print_first_data_ref_part (ctx3, long_var2i, 0, nullptr, + VAL_UNDEFINED); ASSERT_EQ (res3, integer_type_node); const char * str3 = pp_formatted_text (&pp3); @@ -6167,7 +6231,8 @@ context_printer_print_first_data_ref_part_tests () build1 (ADDR_EXPR, ptr_type_node, var1d1i), build_zero_cst (ptr_type_node)); - tree res4 = printer4.print_first_data_ref_part (ctx4, mem_var1d1i, 0, nullptr); + tree res4 = printer4.print_first_data_ref_part (ctx4, mem_var1d1i, 0, nullptr, + VAL_UNDEFINED); ASSERT_EQ (res4, short_integer_type_node); const char * str4 = pp_formatted_text (&pp4); @@ -6186,7 +6251,8 @@ context_printer_print_first_data_ref_part_tests () build_int_cst (ptr_type_node, sizeof (short))); - tree res5 = printer5.print_first_data_ref_part (ctx5, mem_var1d1i_s2, 0, nullptr); + tree res5 = printer5.print_first_data_ref_part (ctx5, mem_var1d1i_s2, 0, nullptr, + VAL_UNDEFINED); ASSERT_EQ (res5, short_integer_type_node); const char * str5 = pp_formatted_text (&pp5); @@ -6233,7 +6299,8 @@ context_printer_print_first_data_ref_part_tests () build1 (ADDR_EXPR, ptr_type_node, var4c), build_int_cst (ptr_type_node, 2)); - tree res6 = printer6.print_first_data_ref_part (ctx6, mem_var4c, 0, nullptr); + tree res6 = printer6.print_first_data_ref_part (ctx6, mem_var4c, 0, nullptr, + VAL_UNDEFINED); ASSERT_EQ (res6, char_type_node); const char * str6 = pp_formatted_text (&pp6); @@ -6271,7 +6338,8 @@ context_printer_print_first_data_ref_part_tests () build_int_cst (ptr_type_node, sizeof (int) + 1)); - tree res7 = printer7.print_first_data_ref_part (ctx7, mem_var1i1d, 0, nullptr); + tree res7 = printer7.print_first_data_ref_part (ctx7, mem_var1i1d, 0, nullptr, + VAL_UNDEFINED); ASSERT_EQ (res7, char_type_node); const char * str7 = pp_formatted_text (&pp7); @@ -6297,7 +6365,8 @@ context_printer_print_first_data_ref_part_tests () build_int_cst (ptr_type_node, 3 * sizeof (int))); - tree res8 = printer8.print_first_data_ref_part (ctx8, mem_var_i5, 0, nullptr); + tree res8 = printer8.print_first_data_ref_part (ctx8, mem_var_i5, 0, nullptr, + VAL_UNDEFINED); ASSERT_EQ (res8, integer_type_node); const char * str8 = pp_formatted_text (&pp8); @@ -6317,7 +6386,8 @@ context_printer_print_first_data_ref_part_tests () sizeof (int))); tree res9 = printer9.print_first_data_ref_part (ctx9, mem2_var_i5, - HOST_BITS_PER_INT, nullptr); + HOST_BITS_PER_INT, nullptr, + VAL_UNDEFINED); ASSERT_EQ (res9, integer_type_node); const char * str9 = pp_formatted_text (&pp9); @@ -6357,7 +6427,8 @@ context_printer_print_first_data_ref_part_tests () build_int_cst (ptr_type_node, sizeof (int) + 13)); - tree res10 = printer10.print_first_data_ref_part (ctx10, mem_var_d1i1a5d, 0, nullptr); + tree res10 = printer10.print_first_data_ref_part (ctx10, mem_var_d1i1a5d, 0, + nullptr, VAL_UNDEFINED); ASSERT_EQ (res10, char_type_node); const char * str10 = pp_formatted_text (&pp10); @@ -6390,7 +6461,8 @@ context_printer_print_first_data_ref_part_tests () tree ref_ptr = build2 (MEM_REF, integer_type_node, ptr, build_zero_cst (ptr_type_node)); - tree res11 = printer11.print_first_data_ref_part (ctx11, ref_ptr, 0, nullptr); + tree res11 = printer11.print_first_data_ref_part (ctx11, ref_ptr, 0, nullptr, + VAL_UNDEFINED); ASSERT_EQ (res11, integer_type_node); const char * str11 = pp_formatted_text (&pp11); @@ -6678,6 +6750,53 @@ context_printer_print_value_update_tests () printer8.print_value_update (ctx8, ref8, val8_17); const char *str8 = pp_formatted_text (&pp8); ASSERT_STREQ (str8, "# v5c[1] = 17\n"); + + + heap_memory mem9; + context_printer printer9; + pretty_printer & pp9 = printer9.pp; + pp_buffer (&pp9)->m_flush_p = false; + + tree a17c_9 = build_array_type_nelts (char_type_node, 17); + tree v17c_9 = create_var (a17c_9, "v17c"); + tree p_9 = create_var (ptr_type_node, "p"); + tree i_9 = create_var (integer_type_node, "i"); + + vec<tree> decls9{}; + decls9.safe_push (v17c_9); + decls9.safe_push (p_9); + decls9.safe_push (i_9); + + context_builder builder9; + builder9.add_decls (&decls9); + exec_context ctx9 = builder9.build (mem9, printer9); + + data_storage *strg9_i = ctx9.find_reachable_var (i_9); + gcc_assert (strg9_i != nullptr); + storage_address addr9_i (strg9_i->get_ref (), 0); + + data_value val9_addr_i (ptr_type_node); + val9_addr_i.set_address (addr9_i); + + data_storage *strg9_v17c = ctx9.find_reachable_var (v17c_9); + gcc_assert (strg9_v17c != nullptr); + storage_address addr9_v17c (strg9_v17c->get_ref (), HOST_BITS_PER_PTR); + + data_value val9_addr_v17c (ptr_type_node); + val9_addr_v17c.set_address (addr9_v17c); + + data_storage *strg9_p = ctx9.find_reachable_var (p_9); + gcc_assert (strg9_p != nullptr); + strg9_p->set (val9_addr_v17c); + + tree a8c = build_array_type_nelts (char_type_node, + HOST_BITS_PER_PTR / CHAR_BIT); + tree ref9 = build2 (MEM_REF, a8c, p_9, + build_zero_cst (build_pointer_type (ptr_type_node))); + + printer9.print_value_update (ctx9, ref9, val9_addr_i); + const char *str9 = pp_formatted_text (&pp9); + ASSERT_STREQ (str9, "# v17c[8B:+8B] = &i\n"); } @@ -8488,6 +8607,66 @@ exec_context_execute_assign_tests () ASSERT_EQ (wi10.to_shwi (), 23); } +void +exec_context_print_call_tests () +{ + heap_memory mem1; + context_printer printer1; + pretty_printer & pp1 = printer1.pp; + pp_buffer (&pp1)->m_flush_p = false; + + tree ac5_1 = build_array_type_nelts (char_type_node, 5); + tree v5c_1 = create_var (ac5_1, "v5c"); + tree si_1 = create_var (short_integer_type_node, "s1"); + tree p_1 = create_var (ptr_type_node, "p"); + + vec<tree> decls1{}; + decls1.safe_push (v5c_1); + decls1.safe_push (si_1); + decls1.safe_push (p_1); + + context_builder builder1; + builder1.add_decls (&decls1); + exec_context ctx1 = builder1.build (mem1, printer1); + + wide_int wi3113_1 = wi::shwi (13 * 256 + 31, TYPE_PRECISION (short_integer_type_node)); + + data_value val3113_1 (short_integer_type_node); + val3113_1.set_cst (wi3113_1); + + data_storage *strg1_si = ctx1.find_reachable_var (si_1); + gcc_assert (strg1_si != nullptr); + strg1_si->set (val3113_1); + + data_storage *strg1_v5c = ctx1.find_reachable_var (v5c_1); + gcc_assert (strg1_v5c != nullptr); + storage_address addr1_v5cp1 (strg1_v5c->get_ref (), CHAR_BIT); + + data_value val_v5cp1_1 (ptr_type_node); + val_v5cp1_1.set_address (addr1_v5cp1); + + data_storage *strg1_p = ctx1.find_reachable_var (p_1); + gcc_assert (strg1_p != nullptr); + strg1_p->set (val_v5cp1_1); + + tree addr_si_1 = build1 (ADDR_EXPR, ptr_type_node, si_1); + + tree memcpy_fn = builtin_decl_explicit (BUILT_IN_MEMCPY); + set_decl_built_in_function (memcpy_fn, BUILT_IN_NORMAL, BUILT_IN_MEMCPY); + gcall * memcpy_call1 = gimple_build_call (memcpy_fn, 3, p_1, addr_si_1, + build_int_cst (size_type_node, 2)); + + ctx1.execute (memcpy_call1); + + const char *str1 = pp_formatted_text (&pp1); + ASSERT_STR_STARTSWITH (str1, "__builtin_memcpy ("); + const char *line_end = ");\n"; + ASSERT_STR_CONTAINS (str1, line_end); + const char *sub1 = strstr (str1, line_end); + ASSERT_NE (sub1, nullptr); + ASSERT_STREQ (sub1 + strlen (line_end), " # v5c[1] = 31\n # v5c[2] = 13\n"); +} + void exec_context_execute_call_tests () { @@ -9006,6 +9185,7 @@ gimple_exec_cc_tests () exec_context_evaluate_binary_tests (); exec_context_evaluate_condition_tests (); exec_context_execute_assign_tests (); + exec_context_print_call_tests (); exec_context_execute_call_tests (); exec_context_allocate_tests (); }