summaryrefslogtreecommitdiff
path: root/0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch
diff options
context:
space:
mode:
Diffstat (limited to '0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch')
-rw-r--r--0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch1232
1 files changed, 1232 insertions, 0 deletions
diff --git a/0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch b/0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch
new file mode 100644
index 0000000..2bca621
--- /dev/null
+++ b/0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch
@@ -0,0 +1,1232 @@
+From 82d6166cd29fb1c3474f29b28cb7e5478d3a551a Mon Sep 17 00:00:00 2001
+From: liyancheng <412998149@qq.com>
+Date: Mon, 25 Dec 2023 11:17:04 +0800
+Subject: [PATCH] [Struct Reorg] Add unsafe structure pointer compression
+
+Unsafe structure pointer compression allows for some dangerous
+conversions for better performance.
+Add flag -fipa-struct-reorg=5 to enable unsafe structure pointer
+compression.
+---
+ gcc/common.opt | 6 +-
+ gcc/ipa-struct-reorg/ipa-struct-reorg.cc | 365 ++++++++++++++----
+ gcc/symbol-summary.h | 22 +-
+ .../gcc.dg/struct/csr_skip_void_struct_name.c | 53 +++
+ gcc/testsuite/gcc.dg/struct/pc_cast_int.c | 91 +++++
+ .../gcc.dg/struct/pc_compress_and_decomress.c | 90 +++++
+ gcc/testsuite/gcc.dg/struct/pc_ptr2void.c | 87 +++++
+ .../gcc.dg/struct/pc_simple_rewrite_pc.c | 112 ++++++
+ .../gcc.dg/struct/pc_skip_void_struct_name.c | 53 +++
+ gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 8 +
+ 10 files changed, 804 insertions(+), 83 deletions(-)
+ create mode 100644 gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/pc_cast_int.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/pc_ptr2void.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c
+ create mode 100644 gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c
+
+diff --git a/gcc/common.opt b/gcc/common.opt
+index 56b547506..c7c6bc256 100644
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -1993,9 +1993,9 @@ Common Var(flag_ipa_struct_reorg) Init(0) Optimization
+ Perform structure layout optimizations.
+
+ fipa-struct-reorg=
+-Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 4)
+--fipa-struct-reorg=[0,1,2,3,4] adding none, struct-reorg, reorder-fields,
+-dfe, safe-pointer-compression optimizations.
++Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 5)
++-fipa-struct-reorg=[0,1,2,3,4,5] adding none, struct-reorg, reorder-fields,
++dfe, safe-pointer-compression, unsafe-pointer-compression optimizations.
+
+ fipa-vrp
+ Common Var(flag_ipa_vrp) Optimization
+diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
+index 5d451c4c8..fa33f2d35 100644
+--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
+@@ -293,7 +293,8 @@ enum struct_layout_opt_level
+ COMPLETE_STRUCT_RELAYOUT = 1 << 1,
+ STRUCT_REORDER_FIELDS = 1 << 2,
+ DEAD_FIELD_ELIMINATION = 1 << 3,
+- POINTER_COMPRESSION_SAFE = 1 << 4
++ POINTER_COMPRESSION_SAFE = 1 << 4,
++ POINTER_COMPRESSION_UNSAFE = 1 << 5
+ };
+
+ /* Defines the target pointer size of compressed pointer, which should be 8,
+@@ -1267,10 +1268,10 @@ csrtype::init_type_info (void)
+
+ /* Close enough to pad to improve performance.
+ 33~63 should pad to 64 but 33~48 (first half) are too far away, and
+- 65~127 should pad to 128 but 65~96 (first half) are too far away. */
++ 70~127 should pad to 128 but 65~70 (first half) are too far away. */
+ if (old_size > 48 && old_size < 64)
+ new_size = 64;
+- if (old_size > 96 && old_size < 128)
++ if (old_size > 70 && old_size < 128)
+ new_size = 128;
+
+ /* For performance reasons, only allow structure size
+@@ -1423,8 +1424,12 @@ public:
+ bool pc_candidate_tree_p (tree);
+ bool pc_type_conversion_candidate_p (tree);
+ bool pc_direct_rewrite_chance_p (tree, tree &);
++ bool pc_simplify_chance_for_compress_p (gassign *, tree);
++ bool compress_candidate_without_check (gimple_stmt_iterator *, tree, tree &);
+ bool compress_candidate_with_check (gimple_stmt_iterator *, tree, tree &);
+ bool compress_candidate (gassign *, gimple_stmt_iterator *, tree, tree &);
++ bool decompress_candidate_without_check (gimple_stmt_iterator *,
++ tree, tree, tree &, tree &);
+ bool decompress_candidate_with_check (gimple_stmt_iterator *, tree, tree &);
+ bool decompress_candidate (gimple_stmt_iterator *, tree, tree, tree &,
+ tree &);
+@@ -1924,7 +1929,6 @@ bool
+ ipa_struct_relayout::maybe_rewrite_cst (tree cst, gimple_stmt_iterator *gsi,
+ HOST_WIDE_INT &times)
+ {
+- bool ret = false;
+ gcc_assert (TREE_CODE (cst) == INTEGER_CST);
+
+ gimple *stmt = gsi_stmt (*gsi);
+@@ -1948,27 +1952,95 @@ ipa_struct_relayout::maybe_rewrite_cst (tree cst, gimple_stmt_iterator *gsi,
+ {
+ if (gsi_one_before_end_p (*gsi))
+ return false;
+- gsi_next (gsi);
+- gimple *stmt2 = gsi_stmt (*gsi);
+-
+- if (gimple_code (stmt2) == GIMPLE_ASSIGN
+- && gimple_assign_rhs_code (stmt2) == POINTER_PLUS_EXPR)
++ // Check uses.
++ imm_use_iterator imm_iter_lhs;
++ use_operand_p use_p_lhs;
++ FOR_EACH_IMM_USE_FAST (use_p_lhs, imm_iter_lhs, gimple_assign_lhs (stmt))
+ {
+- tree lhs = gimple_assign_lhs (stmt2);
+- tree rhs1 = gimple_assign_rhs1 (stmt2);
+- if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type)
+- || types_compatible_p (inner_type (TREE_TYPE (lhs)), ctype.type))
++ gimple *stmt2 = USE_STMT (use_p_lhs);
++ if (gimple_code (stmt2) != GIMPLE_ASSIGN)
++ continue;
++ if (gimple_assign_rhs_code (stmt2) == POINTER_PLUS_EXPR)
+ {
+- tree num = NULL;
+- if (is_result_of_mult (cst, &num, TYPE_SIZE_UNIT (ctype.type)))
++ tree lhs = gimple_assign_lhs (stmt2);
++ tree rhs1 = gimple_assign_rhs1 (stmt2);
++ if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type)
++ || types_compatible_p (inner_type (TREE_TYPE (lhs)),
++ ctype.type))
+ {
+- times = TREE_INT_CST_LOW (num);
+- ret = true;
++ tree num = NULL;
++ if (is_result_of_mult (cst, &num,
++ TYPE_SIZE_UNIT (ctype.type)))
++ {
++ times = TREE_INT_CST_LOW (num);
++ return true;
++ }
++ }
++ }
++ // For pointer compression, handle plus stmt.
++ else if (gimple_assign_rhs_code (stmt2) == PLUS_EXPR)
++ {
++ // Check uses.
++ imm_use_iterator imm_iter_cast;
++ use_operand_p use_p_cast;
++ FOR_EACH_IMM_USE_FAST (use_p_cast, imm_iter_cast,
++ gimple_assign_lhs (stmt2))
++ {
++ gimple *stmt_cast = USE_STMT (use_p_cast);
++ if (gimple_code (stmt_cast) != GIMPLE_ASSIGN)
++ continue;
++ if (gimple_assign_cast_p (stmt_cast))
++ {
++ tree lhs_type = inner_type (TREE_TYPE (
++ gimple_assign_lhs (stmt_cast)));
++ if (types_compatible_p (lhs_type, ctype.type))
++ {
++ tree num = NULL;
++ if (is_result_of_mult (cst, &num,
++ TYPE_SIZE_UNIT (ctype.type)))
++ {
++ times = TREE_INT_CST_LOW (num);
++ return true;
++ }
++ }
++ }
+ }
+ }
+ }
+- gsi_prev (gsi);
+- return ret;
++ }
++ // For pointer compression, handle div stmt.
++ if (gimple_assign_rhs_code (stmt) == TRUNC_DIV_EXPR)
++ {
++ imm_use_iterator imm_iter;
++ use_operand_p use_p;
++ tree lhs = gimple_assign_lhs (stmt);
++ if (lhs == NULL_TREE)
++ return false;
++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
++ {
++ gimple *use_stmt = USE_STMT (use_p);
++ if (is_gimple_debug (use_stmt))
++ continue;
++ if (gimple_code (use_stmt) != GIMPLE_ASSIGN)
++ continue;
++ if (gimple_assign_cast_p (use_stmt))
++ {
++ tree lhs_type = inner_type (TREE_TYPE (
++ gimple_assign_lhs (use_stmt)));
++ if (TYPE_UNSIGNED (lhs_type)
++ && TREE_CODE (lhs_type) == INTEGER_TYPE
++ && TYPE_PRECISION (lhs_type) == compressed_size)
++ {
++ tree num = NULL;
++ if (is_result_of_mult (cst, &num,
++ TYPE_SIZE_UNIT (ctype.type)))
++ {
++ times = TREE_INT_CST_LOW (num);
++ return true;
++ }
++ }
++ }
++ }
+ }
+ return false;
+ }
+@@ -2967,7 +3039,9 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg)
+ && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
+ e = escape_separate_instance;
+
+- if (e != does_not_escape)
++ if (e != does_not_escape
++ && (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT
++ || replace_type_map.get (type->type) == NULL))
+ type->mark_escape (e, NULL);
+ }
+
+@@ -3629,7 +3703,9 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other,
+ if (TREE_CODE (side) == SSA_NAME
+ && VOID_POINTER_P (TREE_TYPE (side)))
+ return;
+- d->type->mark_escape (escape_cast_another_ptr, stmt);
++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT
++ || replace_type_map.get (d->type->type) == NULL)
++ d->type->mark_escape (escape_cast_another_ptr, stmt);
+ return;
+ }
+
+@@ -3645,7 +3721,9 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other,
+ }
+ else
+ /* *_1 = &MEM[(void *)&x + 8B]. */
+- type->mark_escape (escape_cast_another_ptr, stmt);
++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT
++ || replace_type_map.get (type->type) == NULL)
++ type->mark_escape (escape_cast_another_ptr, stmt);
+ }
+ else if (type != d->type)
+ {
+@@ -4364,7 +4442,9 @@ ipa_struct_reorg::check_definition_assign (srdecl *decl,
+ /* Casts between pointers and integer are escaping. */
+ if (gimple_assign_cast_p (stmt))
+ {
+- type->mark_escape (escape_cast_int, stmt);
++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT
++ || replace_type_map.get (type->type) == NULL)
++ type->mark_escape (escape_cast_int, stmt);
+ return;
+ }
+
+@@ -4684,7 +4764,9 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt,
+ /* Casts between pointers and integer are escaping. */
+ if (gimple_assign_cast_p (stmt))
+ {
+- type->mark_escape (escape_cast_int, stmt);
++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT
++ || replace_type_map.get (type->type) == NULL)
++ type->mark_escape (escape_cast_int, stmt);
+ return;
+ }
+
+@@ -5364,9 +5446,9 @@ ipa_struct_reorg::prune_escaped_types (void)
+
+ /* Prune types that escape, all references to those types
+ will have been removed in the above loops. */
+- /* The escape type is not deleted in STRUCT_REORDER_FIELDS,
+- Then the type that contains the escaped type fields
+- can find complete information. */
++ /* The escape type is not deleted in current_layout_opt_level
++ after STRUCT_REORDER_FIELDS, then the type that contains
++ the escaped type fields can find complete information. */
+ if (current_layout_opt_level < STRUCT_REORDER_FIELDS)
+ {
+ for (unsigned i = 0; i < types.length ();)
+@@ -5842,17 +5924,17 @@ ipa_struct_reorg::compress_ptr_to_offset (tree xhs, srtype *type,
+ tree step2 = gimplify_build2 (gsi, TRUNC_DIV_EXPR, long_unsigned_type_node,
+ step1, TYPE_SIZE_UNIT (type->newtype[0]));
+
+- /* Emit gimple _X3 = _X2 + 1. */
+- tree step3 = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node,
+- step2, build_one_cst (long_unsigned_type_node));
++ /* Emit _X3 = (compressed_size) _X2. */
++ tree pc_type = make_unsigned_type (compressed_size);
++ tree step3 = gimplify_build1 (gsi, NOP_EXPR, pc_type, step2);
+
+- /* Emit _X4 = (compressed_size) _X3. */
+- tree step4 = gimplify_build1 (gsi, NOP_EXPR,
+- make_unsigned_type (compressed_size), step3);
++ /* Emit gimple _X4 = _X3 + 1. */
++ tree step4 = gimplify_build2 (gsi, PLUS_EXPR, pc_type, step3,
++ build_one_cst (pc_type));
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+- print_generic_expr (dump_file, step3);
++ print_generic_expr (dump_file, step4);
+ fprintf (dump_file, "\n");
+ }
+ return step4;
+@@ -5894,7 +5976,7 @@ ipa_struct_reorg::decompress_offset_to_ptr (tree xhs, srtype *type,
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+- print_generic_expr (dump_file, step3);
++ print_generic_expr (dump_file, step4);
+ fprintf (dump_file, "\n");
+ }
+ return step4;
+@@ -5967,7 +6049,10 @@ ipa_struct_reorg::pc_type_conversion_candidate_p (tree xhs)
+
+ if (TREE_CODE (xhs) == COMPONENT_REF)
+ {
+- srtype *base_type = find_type (TREE_TYPE (TREE_OPERAND (xhs, 0)));
++ tree mem = TREE_OPERAND (xhs, 0);
++ if (TREE_CODE (mem) != MEM_REF)
++ return false;
++ srtype *base_type = find_type (TREE_TYPE (mem));
+ if (base_type != NULL && base_type->has_escaped ())
+ return pc_candidate_st_type_p (TREE_TYPE (xhs));
+
+@@ -6057,6 +6142,49 @@ ipa_struct_reorg::pc_direct_rewrite_chance_p (tree rhs, tree &new_rhs)
+ return false;
+ }
+
++/* The following cases can simplify the checking of null pointer:
++ 1. rhs defined from POINTER_PLUS_EXPR.
++ 2. rhs used as COMPONENT_REF in this basic block. */
++
++bool
++ipa_struct_reorg::pc_simplify_chance_for_compress_p (gassign *stmt,
++ tree rhs)
++{
++ imm_use_iterator imm_iter;
++ use_operand_p use_p;
++ gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
++
++ if (def_stmt && is_gimple_assign (def_stmt)
++ && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR)
++ return true;
++
++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, rhs)
++ {
++ gimple *use_stmt = USE_STMT (use_p);
++ if (use_stmt->bb != stmt->bb || !is_gimple_assign (use_stmt))
++ continue;
++
++ tree use_rhs = gimple_assign_rhs1 (use_stmt);
++ if (TREE_CODE (use_rhs) == COMPONENT_REF
++ && TREE_OPERAND (TREE_OPERAND (use_rhs, 0), 0) == rhs)
++ return true;
++ }
++ return false;
++}
++
++/* Perform compression directly without checking null pointer. */
++
++bool
++ipa_struct_reorg::compress_candidate_without_check (gimple_stmt_iterator *gsi,
++ tree rhs,
++ tree &new_rhs)
++{
++ srtype *type = get_compression_candidate_type (rhs);
++ gcc_assert (type != NULL);
++ new_rhs = compress_ptr_to_offset (new_rhs, type, gsi);
++ return true;
++}
++
+ /* Perform pointer compression with check. The conversion will be as shown in
+ the following example:
+ Orig bb:
+@@ -6157,6 +6285,9 @@ ipa_struct_reorg::compress_candidate (gassign *stmt, gimple_stmt_iterator *gsi,
+ {
+ if (pc_direct_rewrite_chance_p (rhs, new_rhs))
+ return true;
++ else if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE
++ && pc_simplify_chance_for_compress_p (stmt, rhs))
++ return compress_candidate_without_check (gsi, rhs, new_rhs);
+
+ return compress_candidate_with_check (gsi, rhs, new_rhs);
+ }
+@@ -6219,6 +6350,80 @@ ipa_struct_reorg::create_bb_for_decompress_candidate (basic_block last_bb,
+ return new_bb;
+ }
+
++/* Try decompress candidate without check. */
++
++bool
++ipa_struct_reorg::decompress_candidate_without_check (gimple_stmt_iterator *gsi,
++ tree lhs, tree rhs,
++ tree &new_lhs,
++ tree &new_rhs)
++{
++ imm_use_iterator imm_iter;
++ use_operand_p use_p;
++ bool processed = false;
++
++ if (!gsi_one_before_end_p (*gsi))
++ {
++ gsi_next (gsi);
++ gimple *next_stmt = gsi_stmt (*gsi);
++ if (gimple_code (next_stmt) == GIMPLE_ASSIGN
++ && gimple_assign_rhs_class (next_stmt) == GIMPLE_SINGLE_RHS)
++ {
++ tree next_rhs = gimple_assign_rhs1 (next_stmt);
++ /* If current lhs is used as rhs in the next stmt:
++ -> _1 = t->s
++ tt->s = _1. */
++ if (lhs == next_rhs)
++ {
++ /* Check whether:
++ 1. the lhs is only used in the next stmt.
++ 2. the next lhs is candidate type. */
++ if (has_single_use (lhs)
++ && pc_candidate_tree_p (gimple_assign_lhs (next_stmt)))
++ {
++ processed = true;
++ /* Copy directly without conversion after update type. */
++ TREE_TYPE (new_lhs)
++ = make_unsigned_type (compressed_size);
++ }
++ }
++ /* -> _1 = t->s
++ _2 = _1->s
++ In this case, _1 might not be nullptr, so decompress it without
++ check. */
++ else if (TREE_CODE (next_rhs) == COMPONENT_REF)
++ {
++ tree use_base = TREE_OPERAND (TREE_OPERAND (next_rhs, 0), 0);
++ if (use_base == lhs)
++ {
++ srtype *type = get_compression_candidate_type (rhs);
++ gcc_assert (type != NULL);
++ gsi_prev (gsi);
++ tree new_ref = NULL_TREE;
++ if (TREE_CODE (new_rhs) == MEM_REF)
++ new_ref = new_rhs;
++ else
++ {
++ tree base = TREE_OPERAND (TREE_OPERAND (new_rhs, 0), 0);
++ tree new_mem_ref = build_simple_mem_ref (base);
++ new_ref = build3 (COMPONENT_REF,
++ TREE_TYPE (new_rhs),
++ new_mem_ref,
++ TREE_OPERAND (new_rhs, 1),
++ NULL_TREE);
++ }
++ new_rhs = decompress_offset_to_ptr (new_ref, type, gsi);
++ processed = true;
++ gsi_next (gsi);
++ }
++ }
++ }
++ gsi_prev (gsi);
++ return processed;
++ }
++ return false;
++}
++
+ /* Perform pointer decompression with check. The conversion will be as shown
+ in the following example:
+ Orig bb:
+@@ -6320,7 +6525,10 @@ ipa_struct_reorg::decompress_candidate (gimple_stmt_iterator *gsi,
+ tree lhs, tree rhs, tree &new_lhs,
+ tree &new_rhs)
+ {
+- // TODO: simplifiy check and rewrite will be pushed in next PR.
++ if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE
++ && decompress_candidate_without_check (gsi, lhs, rhs, new_lhs, new_rhs))
++ return true;
++
+ return decompress_candidate_with_check (gsi, rhs, new_rhs);
+ }
+
+@@ -6341,14 +6549,23 @@ ipa_struct_reorg::try_rewrite_with_pointer_compression (gassign *stmt,
+ if (pc_type_conversion_candidate_p (lhs))
+ {
+ /* Transfer MEM[(struct *)_1].files = _4;
+- to MEM[(struct *)_1].files = (struct *)_4; */
+- new_rhs = fold_convert (TREE_TYPE (lhs), tmp_rhs);
++ to _tmp = (struct *)_4;
++ MEM[(struct *)_1].files = _tmp; */
++ tree tmp_reg = create_tmp_reg (TREE_TYPE (lhs));
++ tree tmp_rhs_cvt = fold_convert (TREE_TYPE (lhs), tmp_rhs);
++ gimple *copy_stmt = gimple_build_assign (tmp_reg, tmp_rhs_cvt);
++ gsi_insert_before (gsi, copy_stmt, GSI_SAME_STMT);
++ new_rhs = tmp_reg;
+ }
+ else if (pc_type_conversion_candidate_p (rhs))
+ {
+ /* Transfer _4 = MEM[(struct *)_1].nodes;
+- to _4 = (new_struct *) MEM[(struct *)_1].nodes; */
+- new_rhs = fold_convert (TREE_TYPE (new_lhs), tmp_rhs);
++ to _tmp = MEM[(struct *)_1].nodes;
++ _4 = (new_struct *) _tmp; */
++ tree tmp_reg = create_tmp_reg (TREE_TYPE (new_lhs));
++ gimple *copy_stmt = gimple_build_assign (tmp_reg, tmp_rhs);
++ gsi_insert_before (gsi, copy_stmt, GSI_SAME_STMT);
++ new_rhs = fold_convert (TREE_TYPE (new_lhs), tmp_reg);
+ }
+ }
+ else if (l && r)
+@@ -6544,7 +6761,7 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+- fprintf (dump_file, "\nrewriting stamtenet:\n");
++ fprintf (dump_file, "\nrewriting statement:\n");
+ print_gimple_stmt (dump_file, stmt, 0);
+ }
+ tree newlhs[max_split];
+@@ -6809,7 +7026,8 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi)
+ old statement is to be removed. */
+
+ bool
+-ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi)
++ipa_struct_reorg::rewrite_cond (gcond *stmt,
++ gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED)
+ {
+ tree_code rhs_code = gimple_cond_code (stmt);
+
+@@ -7039,8 +7257,11 @@ ipa_struct_reorg::rewrite_functions (void)
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nNo rewrite:\n");
+- dump_function_to_file (current_function_decl, dump_file,
+- dump_flags | TDF_VOPS);
++ if (current_function_decl)
++ dump_function_to_file (current_function_decl, dump_file,
++ dump_flags | TDF_VOPS);
++ else
++ fprintf (dump_file, " no declaration\n");
+ }
+ pop_cfun ();
+ }
+@@ -7073,11 +7294,13 @@ ipa_struct_reorg::rewrite_functions (void)
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+- fprintf (dump_file, "==== Before create decls: %dth_%s ====\n\n",
++ fprintf (dump_file, "==== Before create decls: %dth %s ====\n\n",
+ i, f->node->name ());
+ if (current_function_decl)
+ dump_function_to_file (current_function_decl, dump_file,
+ dump_flags | TDF_VOPS);
++ else
++ fprintf (dump_file, " no declaration\n");
+ }
+ pop_cfun ();
+ }
+@@ -7109,10 +7332,13 @@ ipa_struct_reorg::rewrite_functions (void)
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+- fprintf (dump_file, "\nBefore rewrite: %dth_%s\n",
++ fprintf (dump_file, "\nBefore rewrite: %dth %s\n",
+ i, f->node->name ());
+- dump_function_to_file (current_function_decl, dump_file,
+- dump_flags | TDF_VOPS);
++ if (current_function_decl)
++ dump_function_to_file (current_function_decl, dump_file,
++ dump_flags | TDF_VOPS);
++ else
++ fprintf (dump_file, " no declaration\n");
+ fprintf (dump_file, "\n======== Start to rewrite: %dth_%s ========\n",
+ i, f->node->name ());
+ }
+@@ -7187,10 +7413,13 @@ ipa_struct_reorg::rewrite_functions (void)
+
+ if (dump_file)
+ {
+- fprintf (dump_file, "\nAfter rewrite: %dth_%s\n",
++ fprintf (dump_file, "\nAfter rewrite: %dth %s\n",
+ i, f->node->name ());
+- dump_function_to_file (current_function_decl, dump_file,
+- dump_flags | TDF_VOPS);
++ if (current_function_decl)
++ dump_function_to_file (current_function_decl, dump_file,
++ dump_flags | TDF_VOPS);
++ else
++ fprintf (dump_file, " no declaration\n");
+ }
+
+ pop_cfun ();
+@@ -7309,18 +7538,24 @@ ipa_struct_reorg::check_and_prune_struct_for_pointer_compression (void)
+ " skip compression.\n");
+ continue;
+ }
+- if ((current_layout_opt_level & POINTER_COMPRESSION_SAFE)
+- && !type->has_legal_alloc_num)
++ if (!type->has_legal_alloc_num)
+ {
+- if (dump_file)
+- fprintf (dump_file, " has illegal struct array size,"
+- " skip compression.\n");
+- continue;
++ if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE)
++ if (dump_file)
++ fprintf (dump_file, " has unknown alloc size, but"
++ " in unsafe mode, so");
++ else
++ {
++ if (dump_file)
++ fprintf (dump_file, " has illegal struct array size,"
++ " skip compression.\n");
++ continue;
++ }
+ }
+ pc_transform_num++;
+ type->pc_candidate = true;
+ if (dump_file)
+- fprintf (dump_file, " attemps to do pointer compression.\n");
++ fprintf (dump_file, " attempts to do pointer compression.\n");
+ }
+
+ if (dump_file)
+@@ -7342,14 +7577,10 @@ init_pointer_size_for_pointer_compression (void)
+ switch (param_pointer_compression_size)
+ {
+ case 8:
+- compressed_size = 8; // sizeof (uint8)
+- break;
++ // FALLTHRU
+ case 16:
+- compressed_size = 16; // sizeof (uint16)
+- break;
+- case 32:
+- compressed_size = 32; // sizeof (uint32)
+- break;
++ // FALLTHRU
++ case 32: compressed_size = param_pointer_compression_size; break;
+ default:
+ error ("Invalid pointer compression size, using the following param: "
+ "\"--param compressed-pointer-size=[8,16,32]\"");
+@@ -7426,6 +7657,8 @@ public:
+ unsigned int level = 0;
+ switch (struct_layout_optimize_level)
+ {
++ case 5: level |= POINTER_COMPRESSION_UNSAFE;
++ // FALLTHRU
+ case 4: level |= POINTER_COMPRESSION_SAFE;
+ // FALLTHRU
+ case 3: level |= DEAD_FIELD_ELIMINATION;
+diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h
+index 3fe64047c..4f896f4e4 100644
+--- a/gcc/symbol-summary.h
++++ b/gcc/symbol-summary.h
+@@ -103,16 +103,15 @@ protected:
+ /* Allocates new data that are stored within map. */
+ T* allocate_new ()
+ {
+- /* In structure optimizatons, we call new to ensure that
+- the allocated memory is initialized to 0. */
+- if (flag_ipa_struct_reorg)
+- return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
+- : new T ();
+-
+ /* Call gcc_internal_because we do not want to call finalizer for
+ a type T. We call dtor explicitly. */
+- return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
+- : m_allocator.allocate () ;
++ T* allocated = is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
++ : m_allocator.allocate ();
++ /* In structure optimizatons, we call memset to ensure that
++ the allocated memory is initialized to 0. */
++ if (flag_ipa_struct_reorg)
++ memset (allocated, 0, sizeof (T));
++ return allocated;
+ }
+
+ /* Release an item that is stored within map. */
+@@ -121,12 +120,7 @@ protected:
+ if (is_ggc ())
+ ggc_delete (item);
+ else
+- {
+- if (flag_ipa_struct_reorg)
+- delete item;
+- else
+- m_allocator.remove (item);
+- }
++ m_allocator.remove (item);
+ }
+
+ /* Unregister all call-graph hooks. */
+diff --git a/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c b/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c
+new file mode 100644
+index 000000000..c5e4968d9
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c
+@@ -0,0 +1,53 @@
++// Structures without names should not be optimized
++/* { dg-do compile } */
++#include <stdlib.h>
++#include <math.h>
++
++typedef struct
++{
++ int a;
++ float b;
++ double s1;
++ double s2;
++ double s3;
++ double s4;
++ double s5;
++ double s6;
++ double s7;
++ double s8;
++} str_t1;
++
++#define N 1000
++
++int num;
++
++int
++main ()
++{
++ int i, r;
++
++ r = rand ();
++ num = r > N ? N : r;
++ str_t1 *p1 = calloc (num, sizeof (str_t1));
++
++ if (p1 == NULL)
++ return 0;
++
++ for (i = 0; i < num; i++)
++ p1[i].a = 1;
++
++ for (i = 0; i < num; i++)
++ p1[i].b = 2;
++
++ for (i = 0; i < num; i++)
++ if (p1[i].a != 1)
++ abort ();
++
++ for (i = 0; i < num; i++)
++ if (fabsf (p1[i].b - 2) > 0.0001)
++ abort ();
++
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump "No structures to transform in Complete Structure Relayout." "struct_reorg" } } */
+\ No newline at end of file
+diff --git a/gcc/testsuite/gcc.dg/struct/pc_cast_int.c b/gcc/testsuite/gcc.dg/struct/pc_cast_int.c
+new file mode 100644
+index 000000000..6f67fc556
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/pc_cast_int.c
+@@ -0,0 +1,91 @@
++// Escape cast int for pointer compression
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++typedef struct network
++{
++ arc_p arcs;
++ arc_p sorted_arcs;
++ int x;
++ node_p nodes;
++ node_p stop_nodes;
++} network_t;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++ network_t* net_add;
++};
++
++
++const int MAX = 100;
++network_t* net;
++node_p node;
++
++int
++main ()
++{
++ net = (network_t*) calloc (1, sizeof(network_t));
++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++ net->nodes = (node_p) calloc (MAX, sizeof (node_t));
++ net->arcs->id = 100;
++
++ node = net->nodes;
++ node_p n1 = (node_p) 0x123456;
++
++ for (unsigned i = 0; i < MAX; i++)
++ {
++ node->pred = n1;
++ node = node + 1;
++ }
++
++ node = net->nodes;
++
++ for (unsigned i = 0; i < MAX; i++)
++ {
++ if (node->pred != n1)
++ {
++ abort ();
++ }
++ node = node + 1;
++ }
++
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump "No structures to transform in pointer compression" "struct_reorg" } } */
+\ No newline at end of file
+diff --git a/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c b/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c
+new file mode 100644
+index 000000000..d0b8d1afa
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c
+@@ -0,0 +1,90 @@
++// Support basic pointer compression and decompression
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++typedef struct network
++{
++ arc_p arcs;
++ arc_p sorted_arcs;
++ int x;
++ node_p nodes;
++ node_p stop_nodes;
++} network_t;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++ network_t* net_add;
++};
++
++
++const int MAX = 100;
++network_t* net;
++node_p node;
++
++int
++main ()
++{
++ net = (network_t*) calloc (1, sizeof(network_t));
++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++ net->nodes = (node_p) calloc (MAX, sizeof (node_t));
++ net->arcs->id = 100;
++
++ node = net->nodes;
++
++ for (unsigned i = 0; i < MAX; i++)
++ {
++ node->pred = node;
++ node = node + 1;
++ }
++
++ node = net->nodes;
++
++ for (unsigned i = 0; i < MAX; i++)
++ {
++ if (node->pred != node)
++ {
++ abort ();
++ }
++ node = node + 1;
++ }
++
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */
+\ No newline at end of file
+diff --git a/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c b/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c
+new file mode 100644
+index 000000000..5022c1967
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c
+@@ -0,0 +1,87 @@
++// Partially support escape_cast_void for pointer compression.
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++typedef struct network
++{
++ arc_p arcs, sorted_arcs;
++ int x;
++ node_p nodes, stop_nodes;
++} network_t;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++const int MAX = 100;
++network_t* net = NULL;
++int cnt = 0;
++
++__attribute__((noinline)) int
++primal_feasible (network_t *net)
++{
++ void* stop;
++ node_t *node;
++
++ node = net->nodes;
++ stop = (void *)net->stop_nodes;
++ for( node++; node < (node_t *)stop; node++ )
++ {
++ net->x = 1;
++ printf( "PRIMAL NETWORK SIMPLEX: ");
++ }
++ return 0;
++}
++
++int
++main ()
++{
++ net = (network_t*) calloc (1, 20);
++ net->nodes = calloc (MAX, sizeof (node_t));
++ net->stop_nodes = net->nodes + MAX - 1;
++ cnt = primal_feasible( net );
++
++ net = (network_t*) calloc (1, 20);
++ if( !(net->arcs) )
++ {
++ return -1;
++ }
++ return cnt;
++}
++
++/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */
+\ No newline at end of file
+diff --git a/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c b/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c
+new file mode 100644
+index 000000000..98943c9b8
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c
+@@ -0,0 +1,112 @@
++// Check simplify rewrite chance for pointer compression and decompression
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++typedef struct network
++{
++ arc_p arcs;
++ arc_p sorted_arcs;
++ int x;
++ node_p nodes;
++ node_p stop_nodes;
++} network_t;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++ network_t* net_add;
++};
++
++
++const int MAX = 100;
++network_t* net;
++node_p node;
++arc_p arc;
++
++int
++main ()
++{
++ net = (network_t*) calloc (1, sizeof(network_t));
++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++ net->nodes = (node_p) calloc (MAX, sizeof (node_t));
++ net->arcs->id = 100;
++
++ node = net->nodes;
++ arc = net->arcs;
++
++ for (unsigned i = 0; i < MAX; i++)
++ {
++ arc->head = node;
++ arc->head->child = node;
++ node->potential = i + 1;
++ arc->cost = arc->head->potential;
++ arc->tail = node->sibling;
++ if (i % 2)
++ node->pred = net->nodes + i;
++ else
++ node->pred = NULL;
++
++ if (node->pred && node->pred->child != NULL)
++ node->number = 0;
++ else
++ node->number = 1;
++
++ node = node + 1;
++ arc = arc + 1;
++ }
++
++ node = net->nodes;
++ arc = net->arcs;
++
++ for (unsigned i = 0; i < MAX; i++)
++ {
++ node_p t = i % 2 ? node : NULL;
++ int tt = i % 2 ? 0 : 1;
++ if (arc->head->pred != t || arc->cost == 0
++ || arc->tail != node->sibling || node->number != tt)
++ {
++ abort ();
++ }
++ arc = arc + 1;
++ node = node + 1;
++ }
++
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */
+\ No newline at end of file
+diff --git a/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c b/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c
+new file mode 100644
+index 000000000..a0e191267
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c
+@@ -0,0 +1,53 @@
++// Structures without names should not be optimized
++/* { dg-do compile } */
++#include <stdlib.h>
++#include <math.h>
++
++typedef struct
++{
++ int a;
++ float b;
++ double s1;
++ double s2;
++ double s3;
++ double s4;
++ double s5;
++ double s6;
++ double s7;
++ double s8;
++} str_t1;
++
++#define N 1000
++
++int num;
++
++int
++main ()
++{
++ int i, r;
++
++ r = rand ();
++ num = r > N ? N : r;
++ str_t1 *p1 = calloc (num, sizeof (str_t1));
++
++ if (p1 == NULL)
++ return 0;
++
++ for (i = 0; i < num; i++)
++ p1[i].a = 1;
++
++ for (i = 0; i < num; i++)
++ p1[i].b = 2;
++
++ for (i = 0; i < num; i++)
++ if (p1[i].a != 1)
++ abort ();
++
++ for (i = 0; i < num; i++)
++ if (fabsf (p1[i].b - 2) > 0.0001)
++ abort ();
++
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump "No structures to transform in pointer compression" "struct_reorg" } } */
+\ No newline at end of file
+diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
+index 278c4e4f5..c40474407 100644
+--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
+@@ -47,6 +47,14 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf_*.c]] \
+ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/dfe*.c]] \
+ "" "-fipa-struct-reorg=3 -fdump-ipa-all -flto-partition=one -fwhole-program"
+
++# -fipa-struct-reorg=4
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \
++ "" "-fipa-struct-reorg=4 -fdump-ipa-all -flto-partition=one -fwhole-program"
++
++# -fipa-struct-reorg=5
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \
++ "" "-fipa-struct-reorg=5 -fdump-ipa-all -flto-partition=one -fwhole-program"
++
+ # All done.
+ torture-finish
+ dg-finish
+--
+2.33.0
+