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