summaryrefslogtreecommitdiff
path: root/0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch
diff options
context:
space:
mode:
Diffstat (limited to '0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch')
-rw-r--r--0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch1297
1 files changed, 1297 insertions, 0 deletions
diff --git a/0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch b/0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch
new file mode 100644
index 0000000..05581a4
--- /dev/null
+++ b/0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch
@@ -0,0 +1,1297 @@
+From cebf7903906d0b530fce240b601591d6254ee53f Mon Sep 17 00:00:00 2001
+From: benniaobufeijiushiji <linda7@huawei.com>
+Date: Wed, 30 Nov 2022 22:42:35 +0800
+Subject: [PATCH 35/35] [Struct reorg] Add struct-semi-relayout optimize
+
+Add support for structs with multi-allocation which is escaped in
+complete-relayout.
+Add flag -fipa-struct-reorg=6 and parameter semi-relayout-level.
+---
+ gcc/common.opt | 7 +-
+ gcc/ipa-struct-reorg/ipa-struct-reorg.c | 916 +++++++++++++++++-
+ gcc/ipa-struct-reorg/ipa-struct-reorg.h | 8 +
+ gcc/params.opt | 4 +
+ .../gcc.dg/struct/semi_relayout_rewrite.c | 86 ++
+ gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 4 +
+ 6 files changed, 992 insertions(+), 33 deletions(-)
+ create mode 100644 gcc/testsuite/gcc.dg/struct/semi_relayout_rewrite.c
+
+diff --git a/gcc/common.opt b/gcc/common.opt
+index 384595f16..588e19400 100644
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -1889,9 +1889,10 @@ Common Report 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, 5)
+--fipa-struct-reorg=[0,1,2,3,4,5] adding none, struct-reorg, reorder-fields,
+-dfe, safe-pointer-compression, unsafe-pointer-compression optimizations.
++Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 6)
++-fipa-struct-reorg=[0,1,2,3,4,5,6] adding none, struct-reorg, reorder-fields,
++dfe, safe-pointer-compression, unsafe-pointer-compression, semi-relayout
++optimizations.
+
+ fipa-extend-auto-profile
+ Common Report Var(flag_ipa_extend_auto_profile)
+diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c
+index ee4893dfb..4751711fe 100644
+--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c
++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c
+@@ -265,7 +265,8 @@ enum struct_layout_opt_level
+ STRUCT_REORDER_FIELDS = 1 << 2,
+ DEAD_FIELD_ELIMINATION = 1 << 3,
+ POINTER_COMPRESSION_SAFE = 1 << 4,
+- POINTER_COMPRESSION_UNSAFE = 1 << 5
++ POINTER_COMPRESSION_UNSAFE = 1 << 5,
++ SEMI_RELAYOUT = 1 << 6
+ };
+
+ /* Defines the target pointer size of compressed pointer, which should be 8,
+@@ -280,6 +281,7 @@ void get_base (tree &base, tree expr);
+ static unsigned int current_layout_opt_level;
+
+ hash_map<tree, tree> replace_type_map;
++hash_map<tree, tree> semi_relayout_map;
+
+ /* Return true if one of these types is created by struct-reorg. */
+
+@@ -398,7 +400,9 @@ srtype::srtype (tree type)
+ visited (false),
+ pc_candidate (false),
+ has_legal_alloc_num (false),
+- has_alloc_array (0)
++ has_alloc_array (0),
++ semi_relayout (false),
++ bucket_parts (0)
+ {
+ for (int i = 0; i < max_split; i++)
+ newtype[i] = NULL_TREE;
+@@ -883,6 +887,66 @@ srfield::create_new_optimized_fields (tree newtype[max_split],
+ newfield[0] = field;
+ }
+
++/* Given a struct s whose fields has already reordered by size, we try to
++ combine fields less than 8 bytes together to 8 bytes. Example:
++ struct s {
++ uint64_t a,
++ uint32_t b,
++ uint32_t c,
++ uint32_t d,
++ uint16_t e,
++ uint8_t f
++ }
++
++ We allocate memory for arrays of struct S, before semi-relayout, their
++ layout in memory is shown as below:
++ [a,b,c,d,e,f,padding;a,b,c,d,e,f,padding;...]
++
++ During semi-relayout, we put a number of structs into a same region called
++ bucket. The number is determined by param realyout-bucket-capacity-level.
++ Using 1024 here as example. After semi-relayout, the layout in a bucket is
++ shown as below:
++ part1 [a;a;a...]
++ part2 [b,c;b,c;b,c;...]
++ part3 [d,e,f,pad;d,e,f,pad;d,e,f,pad;...]
++
++ In the last bucket, if the amount of rest structs is less than the capacity
++ of a bucket, the rest of allcated memory will be wasted as padding. */
++
++unsigned
++srtype::calculate_bucket_size ()
++{
++ unsigned parts = 0;
++ unsigned bit_sum = 0;
++ unsigned relayout_offset = 0;
++ /* Currently, limit each 8 bytes with less than 2 fields. */
++ unsigned curr_part_num = 0;
++ unsigned field_num = 0;
++ for (tree f = TYPE_FIELDS (newtype[0]); f; f = DECL_CHAIN (f))
++ {
++ unsigned size = TYPE_PRECISION (TREE_TYPE (f));
++ bit_sum += size;
++ field_num++;
++ if (++curr_part_num > 2 || bit_sum > 64)
++ {
++ bit_sum = size;
++ parts++;
++ relayout_offset = relayout_part_size * parts;
++ curr_part_num = 1;
++ }
++ else
++ {
++ relayout_offset = relayout_part_size * parts + (bit_sum - size) / 8;
++ }
++ new_field_offsets.put (f, relayout_offset);
++ }
++ /* Donnot relayout a struct with only one field after DFE. */
++ if (field_num == 1)
++ return 0;
++ bucket_parts = ++parts;
++ return parts * relayout_part_size;
++}
++
+ /* Create the new TYPE corresponding to THIS type. */
+
+ bool
+@@ -994,6 +1058,15 @@ srtype::create_new_type (void)
+ if (pc_candidate && pc_gptr == NULL_TREE)
+ create_global_ptr_for_pc ();
+
++ if (semi_relayout)
++ {
++ bucket_size = calculate_bucket_size ();
++ if (bucket_size == 0)
++ return false;
++ if (semi_relayout_map.get (this->newtype[0]) == NULL)
++ semi_relayout_map.put (this->newtype[0], this->type);
++ }
++
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Created %d types:\n", maxclusters);
+@@ -1393,7 +1466,7 @@ public:
+ bool should_create = false, bool can_escape = false);
+ bool wholeaccess (tree expr, tree base, tree accesstype, srtype *t);
+
+- void check_alloc_num (gimple *stmt, srtype *type);
++ void check_alloc_num (gimple *stmt, srtype *type, bool ptrptr);
+ void check_definition_assign (srdecl *decl, vec<srdecl*> &worklist);
+ void check_definition_call (srdecl *decl, vec<srdecl*> &worklist);
+ void check_definition (srdecl *decl, vec<srdecl*>&);
+@@ -1440,6 +1513,33 @@ public:
+ tree &);
+ basic_block create_bb_for_compress_nullptr (basic_block, tree &);
+ basic_block create_bb_for_decompress_nullptr (basic_block, tree, tree &);
++
++ // Semi-relayout methods:
++ bool is_semi_relayout_candidate (tree);
++ srtype *get_semi_relayout_candidate_type (tree);
++ void check_and_prune_struct_for_semi_relayout (void);
++ tree rewrite_pointer_diff (gimple_stmt_iterator *, tree, tree, srtype *);
++ tree rewrite_pointer_plus_integer (gimple *, gimple_stmt_iterator *, tree,
++ tree, srtype *);
++ tree build_div_expr (gimple_stmt_iterator *, tree, tree);
++ tree get_true_pointer_base (gimple_stmt_iterator *, tree, srtype *);
++ tree get_real_allocated_ptr (tree, gimple_stmt_iterator *);
++ tree set_ptr_for_use (tree, gimple_stmt_iterator *);
++ void record_allocated_size (tree, gimple_stmt_iterator *, tree);
++ tree read_allocated_size (tree, gimple_stmt_iterator *);
++ gimple *create_aligned_alloc (gimple_stmt_iterator *, srtype *, tree,
++ tree &);
++ void create_memset_zero (tree, gimple_stmt_iterator *, tree);
++ void create_memcpy (tree, tree, tree, gimple_stmt_iterator *);
++ void create_free (tree, gimple_stmt_iterator *);
++ void copy_to_lhs (tree, tree, gimple_stmt_iterator *);
++ srtype *get_relayout_candidate_type (tree);
++ long unsigned int get_true_field_offset (srfield *, srtype *);
++ tree rewrite_address (tree, srfield *, srtype *, gimple_stmt_iterator *);
++ bool check_sr_copy (gimple *);
++ void relayout_field_copy (gimple_stmt_iterator *, gimple *, tree, tree,
++ tree&, tree &);
++ void do_semi_relayout (gimple_stmt_iterator *, gimple *, tree &, tree &);
+ };
+
+ struct ipa_struct_relayout
+@@ -4528,7 +4628,7 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl,
+ }
+
+ void
+-ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type)
++ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type, bool ptrptr)
+ {
+ if (current_layout_opt_level >= COMPLETE_STRUCT_RELAYOUT
+ && handled_allocation_stmt (stmt))
+@@ -4536,6 +4636,14 @@ ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type)
+ tree arg0 = gimple_call_arg (stmt, 0);
+ basic_block bb = gimple_bb (stmt);
+ cgraph_node *node = current_function->node;
++ if (!ptrptr && current_layout_opt_level >= SEMI_RELAYOUT
++ && gimple_call_builtin_p (stmt, BUILT_IN_MALLOC))
++ {
++ /* Malloc is commonly used for allocations of a single struct
++ and semi-relayout will waste a mess of memory, so we skip it. */
++ type->has_alloc_array = -4;
++ return;
++ }
+ if (integer_onep (arg0))
+ {
+ /* Actually NOT an array, but may ruin other array. */
+@@ -4544,6 +4652,10 @@ ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type)
+ else if (bb->loop_father != NULL
+ && loop_outer (bb->loop_father) != NULL)
+ {
++ /* For semi-relayout, do not escape realloc. */
++ if (current_layout_opt_level & SEMI_RELAYOUT
++ && gimple_call_builtin_p (stmt, BUILT_IN_REALLOC))
++ return;
+ /* The allocation is in a loop. */
+ type->has_alloc_array = -2;
+ }
+@@ -4635,6 +4747,13 @@ ipa_struct_reorg::check_definition_assign (srdecl *decl, vec<srdecl*> &worklist)
+ return;
+ }
+
++ if (semi_relayout_map.get (type->type) != NULL)
++ {
++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT)
++ type->mark_escape (escape_unhandled_rewrite, stmt);
++ return;
++ }
++
+ /* d) if the name is from a cast/assignment, make sure it is used as
+ that type or void*
+ i) If void* then push the ssa_name into worklist. */
+@@ -4679,7 +4798,8 @@ ipa_struct_reorg::check_definition_call (srdecl *decl, vec<srdecl*> &worklist)
+ }
+ }
+
+- check_alloc_num (stmt, type);
++ bool ptrptr = isptrptr (decl->orig_type);
++ check_alloc_num (stmt, type, ptrptr);
+ return;
+ }
+
+@@ -6249,6 +6369,53 @@ ipa_struct_reorg::pc_candidate_tree_p (tree xhs)
+ return false;
+ }
+
++srtype *
++ipa_struct_reorg::get_semi_relayout_candidate_type (tree xhs)
++{
++ if (xhs == NULL)
++ return NULL;
++ if (TREE_CODE (xhs) == SSA_NAME || TREE_CODE (xhs) == COMPONENT_REF)
++ {
++ srtype *access_type = find_type (inner_type (TREE_TYPE (xhs)));
++ if (access_type != NULL && access_type->semi_relayout)
++ return access_type;
++ }
++ return NULL;
++}
++
++bool
++ipa_struct_reorg::is_semi_relayout_candidate (tree xhs)
++{
++ if (xhs == NULL)
++ return false;
++
++ if (TREE_CODE (xhs) == SSA_NAME)
++ xhs = TREE_TYPE (xhs);
++
++ if (TREE_CODE (xhs) == POINTER_TYPE)
++ {
++ srtype *var_type = find_type (TREE_TYPE (xhs));
++ if (!var_type || var_type->has_escaped ())
++ return false;
++ if (var_type->semi_relayout)
++ return true;
++ }
++
++ if (TREE_CODE (xhs) == COMPONENT_REF)
++ {
++ tree mem = TREE_OPERAND (xhs, 0);
++ if (TREE_CODE (mem) == MEM_REF)
++ {
++ tree type = TREE_TYPE (mem);
++ srtype *old_type = get_relayout_candidate_type (type);
++ if (types_compatible_p (type, old_type->type)
++ && old_type->semi_relayout)
++ return true;
++ }
++ }
++ return false;
++}
++
+ /* True if xhs is a component_ref that base has escaped but uses a compression
+ candidate type. */
+
+@@ -6782,6 +6949,404 @@ ipa_struct_reorg::try_rewrite_with_pointer_compression (gassign *stmt,
+ }
+ }
+
++tree
++ipa_struct_reorg::rewrite_pointer_diff (gimple_stmt_iterator *gsi, tree ptr1,
++ tree ptr2, srtype *type)
++{
++ tree shifts = build_int_cst (long_integer_type_node, semi_relayout_align);
++ tree pointer_type = build_pointer_type (unsigned_char_type_node);
++ /* addr_high_1 = (intptr_t)ptr1 >> shifts */
++ tree ptr1_cvt = fold_convert (pointer_type, ptr1);
++ tree addr_high_1 = gimplify_build2 (gsi, RSHIFT_EXPR, pointer_type,
++ ptr1_cvt, shifts);
++ /* addr_high_2 = (intptr_t)ptr2 >> shifts */
++ tree ptr2_cvt = fold_convert (pointer_type, ptr2);
++ tree addr_high_2 = gimplify_build2 (gsi, RSHIFT_EXPR, pointer_type,
++ ptr2_cvt, shifts);
++ /* off1 = (intptr_t)ptr1 - (addr_high_1 << shifts) */
++ tree bucket_start_1 = gimplify_build2 (gsi, LSHIFT_EXPR, pointer_type,
++ addr_high_1, shifts);
++ tree off1 = gimplify_build2 (gsi, MINUS_EXPR, long_integer_type_node,
++ ptr1_cvt, bucket_start_1);
++ /* off2 = (intptr_t)ptr2 - (addr_high_2 << shifts) */
++ tree bucket_start_2 = gimplify_build2 (gsi, LSHIFT_EXPR, pointer_type,
++ addr_high_2, shifts);
++ tree off2 = gimplify_build2 (gsi, MINUS_EXPR, long_integer_type_node,
++ ptr2_cvt, bucket_start_2);
++ /* group_diff = (addr_high_1 - addr_high_2) / bucket_parts */
++ tree bucket_sub = gimplify_build2 (gsi, MINUS_EXPR, long_integer_type_node,
++ addr_high_1, addr_high_2);
++ tree bucket_parts = build_int_cst (long_integer_type_node,
++ type->bucket_parts);
++ tree group_diff = gimplify_build2 (gsi, TRUNC_DIV_EXPR,
++ long_integer_type_node,
++ bucket_sub, bucket_parts);
++ /* off_addr_diff = off1 - off2 */
++ tree off_addr_diff = gimplify_build2 (gsi, MINUS_EXPR, long_integer_type_node,
++ off1, off2);
++ /* res = group_diff * bucket_capacity + off_diff / 8 */
++ tree capacity = build_int_cst (long_integer_type_node,
++ relayout_part_size / 8);
++ tree unit_size = build_int_cst (long_integer_type_node, 8);
++ tree bucket_index_diff = gimplify_build2 (gsi, MULT_EXPR,
++ long_integer_type_node,
++ group_diff, capacity);
++ tree off_index = gimplify_build2 (gsi, TRUNC_DIV_EXPR,
++ long_integer_type_node,
++ off_addr_diff, unit_size);
++ tree res = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node,
++ bucket_index_diff, off_index);
++ return res;
++}
++
++basic_block
++create_bb_for_group_diff_eq_0 (basic_block last_bb, tree phi, tree new_granule)
++{
++ basic_block new_bb = create_empty_bb (last_bb);
++ if (last_bb->loop_father != NULL)
++ {
++ add_bb_to_loop (new_bb, last_bb->loop_father);
++ loops_state_set (LOOPS_NEED_FIXUP);
++ }
++ /* Emit res = new_granule; */
++ gimple_stmt_iterator gsi = gsi_last_bb (new_bb);
++ gimple *new_stmt = gimple_build_assign (phi, new_granule);
++ gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
++ return new_bb;
++}
++
++basic_block
++create_bb_for_group_diff_ne_0 (basic_block new_bb, tree &phi, tree ptr,
++ tree group_diff, tree off_times_8, srtype *type)
++{
++ tree shifts = build_int_cst (long_unsigned_type_node, semi_relayout_align);
++ gimple_stmt_iterator gsi = gsi_last_bb (new_bb);
++ gsi_insert_after (&gsi, gimple_build_nop (), GSI_NEW_STMT);
++ /* curr_group_start = (ptr >> shifts) << shifts; */
++ tree ptr_r_1 = gimplify_build2 (&gsi, RSHIFT_EXPR, long_integer_type_node,
++ ptr, shifts);
++ tree curr_group_start = gimplify_build2 (&gsi, LSHIFT_EXPR, long_integer_type_node,
++ ptr_r_1, shifts);
++ /* curr_off_from_group = ptr - curr_group_start; */
++ tree curr_off_from_group = gimplify_build2 (&gsi, MINUS_EXPR,
++ long_integer_type_node,
++ ptr, curr_group_start);
++ /* res = curr_group_start + ((group_diff * parts) << shifts)
++ + ((curr_off_from_group + off_times_8) % shifts); */
++ tree step1 = gimplify_build2 (&gsi, MULT_EXPR, long_integer_type_node,
++ group_diff, build_int_cst (
++ long_integer_type_node, type->bucket_parts));
++ tree step2 = gimplify_build2 (&gsi, LSHIFT_EXPR, long_integer_type_node,
++ step1, shifts);
++ tree step3 = gimplify_build2 (&gsi, PLUS_EXPR, long_integer_type_node,
++ curr_off_from_group, off_times_8);
++ tree step4 = gimplify_build2 (&gsi, TRUNC_MOD_EXPR, long_integer_type_node,
++ step3, build_int_cst (
++ long_integer_type_node, relayout_part_size));
++ tree step5 = gimplify_build2 (&gsi, PLUS_EXPR, long_integer_type_node,
++ step2, step4);
++ tree res_phi1 = gimplify_build2 (&gsi, PLUS_EXPR, long_integer_type_node,
++ curr_group_start, step5);
++ /* if (group_diff < 0) */
++ gcond *cond = gimple_build_cond (LT_EXPR, group_diff,
++ build_int_cst (long_integer_type_node, 0),
++ NULL_TREE, NULL_TREE);
++ gsi_insert_before (&gsi, cond, GSI_SAME_STMT);
++ /* remove nop */
++ gsi_remove (&gsi, true);
++ /* res += shifts */
++ basic_block true_bb = create_empty_bb (new_bb);
++ if (new_bb->loop_father != NULL)
++ {
++ add_bb_to_loop (true_bb, new_bb->loop_father);
++ loops_state_set (LOOPS_NEED_FIXUP);
++ }
++ gimple_stmt_iterator true_gsi = gsi_last_bb (true_bb);
++ tree res_phi2 = make_ssa_name (long_integer_type_node);
++ gimple *new_stmt
++ = gimple_build_assign (res_phi2, PLUS_EXPR, res_phi1,
++ build_int_cst (long_integer_type_node, relayout_part_size));
++ gsi_insert_after (&true_gsi, new_stmt, GSI_NEW_STMT);
++ /* create phi bb */
++ basic_block res_bb = create_empty_bb (true_bb);
++ if (new_bb->loop_father != NULL)
++ {
++ add_bb_to_loop (res_bb, new_bb->loop_father);
++ loops_state_set (LOOPS_NEED_FIXUP);
++ }
++ /* rebuild cfg */
++ edge etrue = make_edge (new_bb, true_bb, EDGE_TRUE_VALUE);
++ etrue->probability = profile_probability::unlikely ();
++ true_bb->count = etrue->count ();
++
++ edge efalse = make_edge (new_bb, res_bb, EDGE_FALSE_VALUE);
++ efalse->probability = profile_probability::likely ();
++ res_bb->count = efalse->count ();
++
++ edge efall = make_single_succ_edge (true_bb, res_bb, EDGE_FALLTHRU);
++
++ phi = make_ssa_name (long_integer_type_node);
++ gphi *phi_node = create_phi_node (phi, res_bb);
++ add_phi_arg (phi_node, res_phi2, efall, UNKNOWN_LOCATION);
++ add_phi_arg (phi_node, res_phi1, efalse, UNKNOWN_LOCATION);
++
++ if (dom_info_available_p (CDI_DOMINATORS))
++ {
++ set_immediate_dominator (CDI_DOMINATORS, true_bb, new_bb);
++ set_immediate_dominator (CDI_DOMINATORS, res_bb, new_bb);
++ }
++ return res_bb;
++}
++
++tree
++ipa_struct_reorg::rewrite_pointer_plus_integer (gimple *stmt,
++ gimple_stmt_iterator *gsi,
++ tree ptr, tree offset,
++ srtype *type)
++{
++ gcc_assert (type->semi_relayout);
++ tree off = fold_convert (long_integer_type_node, offset);
++ tree num_8 = build_int_cst (integer_type_node, 8);
++ tree shifts = build_int_cst (integer_type_node, semi_relayout_align);
++ /* off_times_8 = off * 8; */
++ tree off_times_8 = gimplify_build2 (gsi, MULT_EXPR, long_integer_type_node,
++ off, num_8);
++ /* new_granule = ptr + off * 8; */
++ tree ptr_int = fold_convert (long_integer_type_node, ptr);
++ tree new_granule = gimplify_build2 (gsi, PLUS_EXPR, long_integer_type_node,
++ ptr_int, off_times_8);
++ /* group_diff = (new_granule >> shifts) - (ptr >> shifts); */
++ tree group_diff_rhs_1 = gimplify_build2 (gsi, RSHIFT_EXPR,
++ long_integer_type_node,
++ new_granule, shifts);
++ tree group_diff_rhs_2 = gimplify_build2 (gsi, RSHIFT_EXPR,
++ long_integer_type_node,
++ ptr, shifts);
++ tree group_diff = gimplify_build2 (gsi, MINUS_EXPR, long_integer_type_node,
++ group_diff_rhs_1, group_diff_rhs_2);
++ /* if (group_diff == 0) */
++ gcond *cond = gimple_build_cond (EQ_EXPR, group_diff,
++ build_int_cst (long_integer_type_node, 0),
++ NULL_TREE, NULL_TREE);
++ gimple_set_location (cond, UNKNOWN_LOCATION);
++ gsi_insert_before (gsi, cond, GSI_SAME_STMT);
++
++ gimple *curr_stmt = as_a <gimple *> (cond);
++ edge e = split_block (curr_stmt->bb, curr_stmt);
++ basic_block split_src_bb = e->src;
++ basic_block split_dst_bb = e->dest;
++ remove_edge_raw (e);
++ /* if (group_diff == 0)
++ res = new_granule; */
++ tree res_phi_1 = make_ssa_name (long_integer_type_node);
++ basic_block true_bb = create_bb_for_group_diff_eq_0 (split_src_bb, res_phi_1,
++ new_granule);
++ /* else */
++ tree res_phi_2 = NULL_TREE;
++ basic_block false_bb = create_empty_bb (split_src_bb);
++ if (split_src_bb->loop_father != NULL)
++ {
++ add_bb_to_loop (false_bb, split_src_bb->loop_father);
++ loops_state_set (LOOPS_NEED_FIXUP);
++ }
++
++ edge etrue = make_edge (split_src_bb, true_bb, EDGE_TRUE_VALUE);
++ etrue->probability = profile_probability::very_likely ();
++ true_bb->count = etrue->count ();
++
++ edge efalse = make_edge (split_src_bb, false_bb, EDGE_FALSE_VALUE);
++ efalse->probability = profile_probability::unlikely ();
++ false_bb->count = efalse->count ();
++ basic_block res_bb = create_bb_for_group_diff_ne_0 (false_bb, res_phi_2,
++ ptr_int, group_diff,
++ off_times_8, type);
++ /* rebuild cfg */
++ edge e_true_fall = make_single_succ_edge (true_bb, split_dst_bb,
++ EDGE_FALLTHRU);
++ edge e_false_fall = make_single_succ_edge (res_bb, split_dst_bb,
++ EDGE_FALLTHRU);
++ tree res_int = make_ssa_name (long_integer_type_node);
++ gphi *phi_node = create_phi_node (res_int, split_dst_bb);
++ add_phi_arg (phi_node, res_phi_1, e_true_fall, UNKNOWN_LOCATION);
++ add_phi_arg (phi_node, res_phi_2, e_false_fall, UNKNOWN_LOCATION);
++ if (dom_info_available_p (CDI_DOMINATORS))
++ {
++ set_immediate_dominator (CDI_DOMINATORS, split_dst_bb, split_src_bb);
++ set_immediate_dominator (CDI_DOMINATORS, true_bb, split_src_bb);
++ set_immediate_dominator (CDI_DOMINATORS, false_bb, split_src_bb);
++ }
++ *gsi = gsi_start_bb (split_dst_bb);
++ tree pointer_type = build_pointer_type (unsigned_char_type_node);
++ tree res = gimplify_build1 (gsi, NOP_EXPR, pointer_type, res_int);
++ return res;
++}
++
++tree
++ipa_struct_reorg::build_div_expr (gimple_stmt_iterator *gsi,
++ tree expr, tree orig_size)
++{
++ tree div_expr = build2 (TRUNC_DIV_EXPR, long_unsigned_type_node,
++ expr, orig_size);
++ tree num = make_ssa_name (long_unsigned_type_node);
++ gimple *g = gimple_build_assign (num, div_expr);
++ gsi_insert_before (gsi, g, GSI_SAME_STMT);
++ return num;
++}
++
++srtype *
++ipa_struct_reorg::get_relayout_candidate_type (tree type)
++{
++ if (type == NULL)
++ return NULL;
++ if (TREE_CODE (type) != RECORD_TYPE)
++ return NULL;
++ return find_type (inner_type (type));
++}
++
++long unsigned int
++ipa_struct_reorg::get_true_field_offset (srfield *field, srtype *type)
++{
++ unsigned HOST_WIDE_INT new_offset;
++ new_offset = *(type->new_field_offsets.get (field->newfield[0]));
++ return new_offset;
++}
++
++tree
++ipa_struct_reorg::get_true_pointer_base (gimple_stmt_iterator *gsi,
++ tree mem_ref, srtype *type)
++{
++ tree ptr = TREE_OPERAND (mem_ref, 0);
++ tree off_bytes = TREE_OPERAND (mem_ref, 1);
++ unsigned num = tree_to_shwi (off_bytes);
++ if (num == 0)
++ return ptr;
++ tree orig_size = TYPE_SIZE_UNIT (TREE_TYPE (mem_ref));
++ tree off = build_int_cst (long_integer_type_node,
++ num / tree_to_uhwi (orig_size));
++ gimple *stmt = gsi_stmt (*gsi);
++ tree new_pointer_base = rewrite_pointer_plus_integer (stmt, gsi, ptr,
++ off, type);
++ return new_pointer_base;
++}
++
++tree
++ipa_struct_reorg::rewrite_address (tree pointer_base, srfield *field,
++ srtype *type, gimple_stmt_iterator *gsi)
++{
++ unsigned HOST_WIDE_INT field_offset = get_true_field_offset (field, type);
++
++ tree pointer_ssa = fold_convert (long_unsigned_type_node, pointer_base);
++ tree step1 = gimplify_build1 (gsi, NOP_EXPR, long_unsigned_type_node,
++ pointer_ssa);
++ tree new_offset_ssa = build_int_cst (long_unsigned_type_node, field_offset);
++ tree step2 = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node, step1,
++ new_offset_ssa);
++ tree field_ssa = fold_convert (
++ build_pointer_type (TREE_TYPE (field->newfield[0])), step2);
++ tree step3 = gimplify_build1 (gsi, NOP_EXPR,
++ TREE_TYPE (field_ssa), field_ssa);
++
++ tree new_mem_ref = fold_build2 (MEM_REF, TREE_TYPE (field->newfield[0]),
++ step3, build_int_cst (TREE_TYPE (field_ssa), 0));
++ return new_mem_ref;
++}
++
++bool
++ipa_struct_reorg::check_sr_copy (gimple *stmt)
++{
++ tree lhs = gimple_assign_lhs (stmt);
++ tree rhs = gimple_assign_rhs1 (stmt);
++
++ if (TREE_CODE (lhs) != MEM_REF || TREE_CODE (rhs) != MEM_REF)
++ return false;
++ srtype *t1 = get_relayout_candidate_type (TREE_TYPE (lhs));
++ srtype *t2 = get_relayout_candidate_type (TREE_TYPE (rhs));
++ if (!t1 || !t2 || !t1->semi_relayout || !t2->semi_relayout || t1 != t2)
++ return false;
++ tree pointer1 = TREE_OPERAND (lhs, 0);
++ tree pointer2 = TREE_OPERAND (rhs, 0);
++ if (TREE_CODE (TREE_TYPE (pointer1)) != POINTER_TYPE
++ || TREE_CODE (TREE_TYPE (pointer2)) != POINTER_TYPE)
++ return false;
++
++ tree type1 = TREE_TYPE (TREE_TYPE (pointer1));
++ tree type2 = TREE_TYPE (TREE_TYPE (pointer2));
++
++ srtype *t3 = get_relayout_candidate_type (type1);
++ srtype *t4 = get_relayout_candidate_type (type2);
++
++ if (t3 != t4 || t3 != t1)
++ return false;
++
++ return true;
++}
++
++void
++ipa_struct_reorg::relayout_field_copy (gimple_stmt_iterator *gsi, gimple *stmt,
++ tree lhs, tree rhs,
++ tree &newlhs, tree &newrhs)
++{
++ srtype *type = get_relayout_candidate_type (TREE_TYPE (lhs));
++ tree lhs_base_pointer = get_true_pointer_base (gsi, newlhs, type);
++ tree rhs_base_pointer = get_true_pointer_base (gsi, newrhs, type);
++ tree new_l_mem_ref = NULL_TREE;
++ tree new_r_mem_ref = NULL_TREE;
++ srfield *field = NULL;
++ unsigned i = 0;
++ FOR_EACH_VEC_ELT (type->fields, i, field)
++ {
++ if (!field->newfield[0])
++ continue;
++ new_l_mem_ref = rewrite_address (lhs_base_pointer, field, type, gsi);
++ new_r_mem_ref = rewrite_address (rhs_base_pointer, field, type, gsi);
++ gimple *new_stmt = gimple_build_assign (new_l_mem_ref, new_r_mem_ref);
++ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
++ }
++ newlhs = new_l_mem_ref;
++ newrhs = new_r_mem_ref;
++}
++
++void
++ipa_struct_reorg::do_semi_relayout (gimple_stmt_iterator *gsi, gimple *stmt,
++ tree &newlhs, tree &newrhs)
++{
++ tree lhs = gimple_assign_lhs (stmt);
++ tree rhs = gimple_assign_rhs1 (stmt);
++
++ bool l = TREE_CODE (lhs) == COMPONENT_REF ? is_semi_relayout_candidate (lhs)
++ : false;
++ bool r = TREE_CODE (rhs) == COMPONENT_REF ? is_semi_relayout_candidate (rhs)
++ : false;
++
++ gcc_assert (!(l && r));
++
++ if (!l && !r)
++ {
++ if (check_sr_copy (stmt))
++ relayout_field_copy (gsi, stmt, lhs, rhs, newlhs, newrhs);
++ }
++ else if (l)
++ {
++ srtype *type = get_relayout_candidate_type (
++ TREE_TYPE (TREE_OPERAND (lhs, 0)));
++ srfield *new_field = type->find_field (
++ int_byte_position (TREE_OPERAND (lhs, 1)));
++ tree pointer_base = get_true_pointer_base (
++ gsi, TREE_OPERAND (newlhs, 0), type);
++ newlhs = rewrite_address (pointer_base, new_field, type, gsi);
++ }
++ else if (r)
++ {
++ srtype *type = get_relayout_candidate_type (
++ TREE_TYPE (TREE_OPERAND (rhs, 0)));
++ srfield *new_field = type->find_field (
++ int_byte_position (TREE_OPERAND (rhs, 1)));
++ tree pointer_base = get_true_pointer_base (
++ gsi, TREE_OPERAND (newrhs, 0), type);
++ newrhs = rewrite_address (pointer_base, new_field, type, gsi);
++ }
++}
++
+ bool
+ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
+ {
+@@ -6876,7 +7441,8 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
+ tree size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs)));
+ tree num;
+ /* Check if rhs2 is a multiplication of the size of the type. */
+- if (!is_result_of_mult (rhs2, &num, size))
++ if (!is_result_of_mult (rhs2, &num, size)
++ && !(current_layout_opt_level & SEMI_RELAYOUT))
+ internal_error ("the rhs of pointer was not a multiplicate and it slipped through.");
+
+ /* Add the judgment of num, support for POINTER_DIFF_EXPR.
+@@ -6898,11 +7464,34 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
+ tree newsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (newlhs[i])));
+ newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num,
+ newsize);
++ if (current_layout_opt_level >= SEMI_RELAYOUT)
++ {
++ if (is_semi_relayout_candidate (lhs))
++ {
++ srtype *type = get_semi_relayout_candidate_type (lhs);
++ newrhs[i] = rewrite_pointer_plus_integer (stmt, gsi,
++ newrhs[i], num, type);
++ newsize = build_int_cst (long_unsigned_type_node, 0);
++ }
++ }
+ new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR,
+ newrhs[i], newsize);
+ }
+ else
+ {
++ /* rhs2 is not a const integer */
++ if (current_layout_opt_level >= SEMI_RELAYOUT)
++ {
++ if (is_semi_relayout_candidate (lhs))
++ {
++ num = build_div_expr (gsi, rhs2,
++ build_int_cst (long_unsigned_type_node, 1));
++ srtype *type = get_semi_relayout_candidate_type (lhs);
++ newrhs[i] = rewrite_pointer_plus_integer (stmt,
++ gsi, newrhs[i], num, type);
++ rhs2 = build_int_cst (long_unsigned_type_node, 0);
++ }
++ }
+ new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR,
+ newrhs[i], rhs2);
+ }
+@@ -6952,13 +7541,32 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
+ return false;
+
+ /* The two operands always have pointer/reference type. */
+- for (unsigned i = 0; i < max_split && newrhs1[i] && newrhs2[i]; i++)
++ if (current_layout_opt_level >= SEMI_RELAYOUT
++ && (is_semi_relayout_candidate (rhs1)
++ || is_semi_relayout_candidate (rhs2)))
+ {
+- gimple_assign_set_rhs1 (stmt, newrhs1[i]);
+- gimple_assign_set_rhs2 (stmt, newrhs2[i]);
+- update_stmt (stmt);
++ for (unsigned i = 0; i < max_split && newrhs1[i] &&newrhs2[i]; i++)
++ {
++ srtype *type = get_semi_relayout_candidate_type (rhs1);
++ if (!type)
++ type = get_semi_relayout_candidate_type (rhs2);
++ gcc_assert (type != NULL);
++ tree res = rewrite_pointer_diff (gsi, newrhs1[i],
++ newrhs2[i], type);
++ gimple *g = gimple_build_assign (gimple_assign_lhs (stmt), res);
++ gsi_insert_before (gsi, g, GSI_SAME_STMT);
++ }
++ remove = true;
++ }
++ else
++ {
++ for (unsigned i = 0; i < max_split && newrhs1[i] && newrhs2[i]; i++)
++ {
++ gimple_assign_set_rhs1 (stmt, newrhs1[i]);
++ gimple_assign_set_rhs2 (stmt, newrhs2[i]);
++ update_stmt (stmt);
++ }
+ }
+- remove = false;
+ return remove;
+ }
+
+@@ -6985,6 +7593,8 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
+ fprintf (dump_file, "replaced with:\n");
+ for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++)
+ {
++ if (current_layout_opt_level & SEMI_RELAYOUT)
++ do_semi_relayout (gsi, stmt, newlhs[i], newrhs[i]);
+ if (current_layout_opt_level >= POINTER_COMPRESSION_SAFE)
+ try_rewrite_with_pointer_compression (stmt, gsi, lhs, rhs,
+ newlhs[i], newrhs[i]);
+@@ -7003,6 +7613,108 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
+ return remove;
+ }
+
++tree
++ipa_struct_reorg::get_real_allocated_ptr (tree ptr, gimple_stmt_iterator *gsi)
++{
++ tree ptr_to_int = fold_convert (long_unsigned_type_node, ptr);
++ tree align = build_int_cst (long_unsigned_type_node, relayout_part_size);
++ tree real_addr = gimplify_build2 (gsi, MINUS_EXPR, long_unsigned_type_node,
++ ptr_to_int, align);
++ tree res = gimplify_build1 (gsi, NOP_EXPR,
++ build_pointer_type (long_unsigned_type_node), real_addr);
++ return res;
++}
++
++tree
++ipa_struct_reorg::set_ptr_for_use (tree ptr, gimple_stmt_iterator *gsi)
++{
++ tree ptr_to_int = fold_convert (long_unsigned_type_node, ptr);
++ tree align = build_int_cst (long_unsigned_type_node, relayout_part_size);
++ tree ptr_int = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node,
++ ptr_to_int, align);
++ tree res = gimplify_build1 (gsi, NOP_EXPR,
++ build_pointer_type (long_unsigned_type_node), ptr_int);
++ return res;
++}
++
++void
++ipa_struct_reorg::record_allocated_size (tree ptr, gimple_stmt_iterator *gsi,
++ tree size)
++{
++ tree to_type = build_pointer_type (long_unsigned_type_node);
++ tree type_cast = fold_convert (to_type, ptr);
++ tree lhs = fold_build2 (MEM_REF, long_unsigned_type_node, ptr,
++ build_int_cst (build_pointer_type (long_unsigned_type_node), 0));
++ gimple *stmt = gimple_build_assign (lhs, size);
++ gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
++}
++
++tree
++ipa_struct_reorg::read_allocated_size (tree ptr, gimple_stmt_iterator *gsi)
++{
++ tree to_type = build_pointer_type (long_unsigned_type_node);
++ tree off = build_int_cst (to_type, 0);
++ tree size = gimplify_build2 (gsi, MEM_REF, long_unsigned_type_node,
++ ptr, off);
++ return size;
++}
++
++gimple *
++ipa_struct_reorg::create_aligned_alloc (gimple_stmt_iterator *gsi,
++ srtype *type, tree num, tree &size)
++{
++ tree fn = builtin_decl_implicit (BUILT_IN_ALIGNED_ALLOC);
++
++ tree align = build_int_cst (long_unsigned_type_node, relayout_part_size);
++ unsigned bucket_size = type->bucket_size;
++
++ tree nbuckets = gimplify_build2 (gsi, CEIL_DIV_EXPR, long_unsigned_type_node,
++ num, build_int_cst (long_unsigned_type_node,
++ relayout_part_size / 8));
++ tree use_size = gimplify_build2 (gsi, MULT_EXPR, long_unsigned_type_node,
++ nbuckets, build_int_cst (
++ long_unsigned_type_node, bucket_size));
++ size = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node,
++ use_size, align);
++ gimple *g = gimple_build_call (fn, 2, align, size);
++ gsi_insert_before (gsi, g, GSI_SAME_STMT);
++ return g;
++}
++
++void
++ipa_struct_reorg::create_memset_zero (tree ptr, gimple_stmt_iterator *gsi,
++ tree size)
++{
++ tree fn = builtin_decl_implicit (BUILT_IN_MEMSET);
++ tree val = build_int_cst (long_unsigned_type_node, 0);
++ gimple *g = gimple_build_call (fn, 3, ptr, val, size);
++ gsi_insert_before (gsi, g, GSI_SAME_STMT);
++}
++
++void
++ipa_struct_reorg::create_memcpy (tree src, tree dst, tree size,
++ gimple_stmt_iterator *gsi)
++{
++ tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
++ gimple *g = gimple_build_call (fn, 3, dst, src, size);
++ gsi_insert_before (gsi, g, GSI_SAME_STMT);
++}
++
++void
++ipa_struct_reorg::create_free (tree ptr, gimple_stmt_iterator *gsi)
++{
++ tree fn = builtin_decl_implicit (BUILT_IN_FREE);
++ gimple *g = gimple_build_call (fn, 1, ptr);
++ gsi_insert_before (gsi, g, GSI_SAME_STMT);
++}
++
++void
++ipa_struct_reorg::copy_to_lhs (tree lhs, tree new_lhs, gimple_stmt_iterator *gsi)
++{
++ gimple *g = gimple_build_assign (lhs, new_lhs);
++ gsi_insert_before (gsi, g, GSI_SAME_STMT);
++}
++
+ /* Rewrite function call statement STMT. Return TRUE if the statement
+ is to be removed. */
+
+@@ -7044,24 +7756,77 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi)
+ ? TYPE_SIZE_UNIT (decl->orig_type)
+ : TYPE_SIZE_UNIT (type->newtype[i]);
+ gimple *g;
+- /* Every allocation except for calloc needs the size multiplied out. */
+- if (!gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
+- newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, newsize);
+-
+- if (gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)
+- || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA))
+- g = gimple_build_call (gimple_call_fndecl (stmt),
+- 1, newsize);
+- else if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
+- g = gimple_build_call (gimple_call_fndecl (stmt),
+- 2, num, newsize);
+- else if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC))
+- g = gimple_build_call (gimple_call_fndecl (stmt),
+- 2, newrhs1[i], newsize);
+- else
+- gcc_assert (false);
+- gimple_call_set_lhs (g, decl->newdecl[i]);
+- gsi_insert_before (gsi, g, GSI_SAME_STMT);
++ bool rewrite = false;
++ if (current_layout_opt_level >= SEMI_RELAYOUT
++ && type->semi_relayout)
++ {
++ if (gimple_call_builtin_p (stmt, BUILT_IN_MALLOC))
++ ;
++ else if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
++ {
++ tree rhs2 = gimple_call_arg (stmt, 1);
++ if (tree_to_uhwi (rhs2) == tree_to_uhwi (
++ TYPE_SIZE_UNIT (type->type)))
++ {
++ rewrite = true;
++ tree size = NULL_TREE;
++ g = create_aligned_alloc (gsi, type, num, size);
++ tree real_ptr = make_ssa_name (
++ build_pointer_type (unsigned_char_type_node));
++ gimple_set_lhs (g, real_ptr);
++ create_memset_zero (real_ptr, gsi, size);
++ record_allocated_size (real_ptr, gsi, size);
++ tree lhs_use = set_ptr_for_use (real_ptr, gsi);
++ copy_to_lhs (decl->newdecl[i], lhs_use, gsi);
++ }
++ }
++ else if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC))
++ {
++ rewrite = true;
++ tree size = NULL_TREE;
++ g = create_aligned_alloc (gsi, type, num, size);
++ tree real_ptr = make_ssa_name (
++ build_pointer_type (unsigned_char_type_node));
++ gimple_set_lhs (g, real_ptr);
++ create_memset_zero (real_ptr, gsi, size);
++ tree src = get_real_allocated_ptr (newrhs1[i], gsi);
++ tree old_size = read_allocated_size (src, gsi);
++ create_memcpy (src, real_ptr, old_size, gsi);
++ record_allocated_size (real_ptr, gsi, size);
++ tree lhs_use = set_ptr_for_use (real_ptr, gsi);
++ create_free (src, gsi);
++ copy_to_lhs (decl->newdecl[i], lhs_use, gsi);
++ }
++ else
++ {
++ gcc_assert (false);
++ internal_error ("supported type for semi-relayout.");
++ }
++ }
++ if (!rewrite
++ && (current_layout_opt_level >= STRUCT_REORDER_FIELDS
++ || current_layout_opt_level == STRUCT_SPLIT))
++ {
++ /* Every allocation except for calloc needs the size
++ multiplied out. */
++ if (!gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
++ newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype,
++ num, newsize);
++ if (gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)
++ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA))
++ g = gimple_build_call (gimple_call_fndecl (stmt),
++ 1, newsize);
++ else if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
++ g = gimple_build_call (gimple_call_fndecl (stmt),
++ 2, num, newsize);
++ else if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC))
++ g = gimple_build_call (gimple_call_fndecl (stmt),
++ 2, newrhs1[i], newsize);
++ else
++ gcc_assert (false);
++ gimple_call_set_lhs (g, decl->newdecl[i]);
++ gsi_insert_before (gsi, g, GSI_SAME_STMT);
++ }
+ if (type->pc_candidate)
+ {
+ /* Init global header for pointer compression. */
+@@ -7081,8 +7846,11 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi)
+ if (!rewrite_expr (expr, newexpr))
+ return false;
+
++ srtype *t = find_type (TREE_TYPE (TREE_TYPE (expr)));
+ if (newexpr[1] == NULL)
+ {
++ if (t && t->semi_relayout)
++ newexpr[0] = get_real_allocated_ptr (newexpr[0], gsi);
+ gimple_call_set_arg (stmt, 0, newexpr[0]);
+ update_stmt (stmt);
+ return false;
+@@ -7789,6 +8557,85 @@ ipa_struct_reorg::check_and_prune_struct_for_pointer_compression (void)
+ }
+ }
+
++void
++ipa_struct_reorg::check_and_prune_struct_for_semi_relayout (void)
++{
++ unsigned relayout_transform = 0;
++ for (unsigned i = 0; i < types.length (); i++)
++ {
++ srtype *type = types[i];
++ if (dump_file)
++ {
++ print_generic_expr (dump_file, type->type);
++ }
++ if (type->has_escaped ())
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, " has escaped by %s, skip relayout.\n",
++ type->escape_reason ());
++ }
++ continue;
++ }
++ if (TYPE_FIELDS (type->type) == NULL)
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, " has zero field, skip relayout.\n");
++ }
++ continue;
++ }
++ if (type->chain_type)
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, " is chain_type, skip relayout.\n");
++ }
++ continue;
++ }
++ if (type->has_alloc_array == 0 || type->has_alloc_array == 1
++ || type->has_alloc_array == -1 || type->has_alloc_array == -3
++ || type->has_alloc_array == -4)
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, " has alloc number: %d, skip relayout.\n",
++ type->has_alloc_array);
++ }
++ continue;
++ }
++ if (get_type_name (type->type) == NULL)
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, " has empty struct name,"
++ " skip relayout.\n");
++ }
++ continue;
++ }
++ relayout_transform++;
++ type->semi_relayout = true;
++ if (dump_file)
++ {
++ fprintf (dump_file, " attempts to do semi-relayout.\n");
++ }
++ }
++
++ if (dump_file)
++ {
++ if (relayout_transform)
++ {
++ fprintf (dump_file, "\nNumber of structures to transform in "
++ "semi-relayout is %d\n", relayout_transform);
++ }
++ else
++ {
++ fprintf (dump_file, "\nNo structures to transform in "
++ "semi-relayout.\n");
++ }
++ }
++}
++
+ /* Init pointer size from parameter param_pointer_compression_size. */
+
+ static void
+@@ -7829,7 +8676,8 @@ ipa_struct_reorg::execute (unsigned int opt)
+ }
+ if (opt >= POINTER_COMPRESSION_SAFE)
+ check_and_prune_struct_for_pointer_compression ();
+-
++ if (opt >= SEMI_RELAYOUT)
++ check_and_prune_struct_for_semi_relayout ();
+ ret = rewrite_functions ();
+ }
+ else // do COMPLETE_STRUCT_RELAYOUT
+@@ -7881,6 +8729,8 @@ public:
+ unsigned int level = 0;
+ switch (struct_layout_optimize_level)
+ {
++ case 6: level |= SEMI_RELAYOUT;
++ // FALLTHRU
+ case 5: level |= POINTER_COMPRESSION_UNSAFE;
+ // FALLTHRU
+ case 4: level |= POINTER_COMPRESSION_SAFE;
+@@ -7900,6 +8750,12 @@ public:
+ if (level & POINTER_COMPRESSION_SAFE)
+ init_pointer_size_for_pointer_compression ();
+
++ if (level & SEMI_RELAYOUT)
++ {
++ semi_relayout_align = semi_relayout_level;
++ relayout_part_size = 1 << semi_relayout_level;
++ }
++
+ /* Preserved for backward compatibility, reorder fields needs run before
+ struct split and complete struct relayout. */
+ if (flag_ipa_reorder_fields && level < STRUCT_REORDER_FIELDS)
+diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
+index d88799982..982f43e58 100644
+--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h
++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
+@@ -25,6 +25,9 @@ namespace struct_reorg {
+
+ const int max_split = 2;
+
++unsigned semi_relayout_align = semi_relayout_level;
++unsigned relayout_part_size = 1 << semi_relayout_level;
++
+ template <typename type>
+ struct auto_vec_del : auto_vec<type*>
+ {
+@@ -127,6 +130,10 @@ public:
+ bool pc_candidate;
+ bool has_legal_alloc_num;
+ int has_alloc_array;
++ bool semi_relayout;
++ hash_map<tree, unsigned long> new_field_offsets;
++ unsigned bucket_parts;
++ unsigned bucket_size;
+
+ // Constructors
+ srtype(tree type);
+@@ -148,6 +155,7 @@ public:
+ bool has_dead_field (void);
+ void mark_escape (escape_type, gimple *stmt);
+ void create_global_ptr_for_pc ();
++ unsigned calculate_bucket_size ();
+ bool has_escaped (void)
+ {
+ return escapes != does_not_escape;
+diff --git a/gcc/params.opt b/gcc/params.opt
+index 1d355819c..83fd705ee 100644
+--- a/gcc/params.opt
++++ b/gcc/params.opt
+@@ -988,4 +988,8 @@ Threshold functions of cache miss counts to be analyzed in prefetching.
+ Common Joined UInteger Var(param_pointer_compression_size) Init(32) IntegerRange(8, 32) Param Optimization
+ Target size of compressed pointer, which should be 8, 16 or 32.
+
++-param=semi-relayout-level=
++Common Joined UInteger Var(semi_relayout_level) Init(13) IntegerRange(11, 15) Param Optimization
++Set capacity of each bucket to semi-relayout to (1 << semi-relayout-level) / 8 .
++
+ ; This comment is to ensure we retain the blank line above.
+diff --git a/gcc/testsuite/gcc.dg/struct/semi_relayout_rewrite.c b/gcc/testsuite/gcc.dg/struct/semi_relayout_rewrite.c
+new file mode 100644
+index 000000000..87c756c79
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/struct/semi_relayout_rewrite.c
+@@ -0,0 +1,86 @@
++// Check simplify rewrite chance for semi-relayout
++/* { 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;
++ node = node + 1;
++ arc = arc + 1;
++ }
++
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump "Number of structures to transform in semi-relayout is 1" "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 d7367ed96..281046b48 100644
+--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
+@@ -93,6 +93,10 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \
+ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \
+ "" "-fipa-struct-reorg=5 -fdump-ipa-all -flto-partition=one -fwhole-program"
+
++# -fipa-struct-reorg=6
++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/semi_relayout*.c]] \
++ "" "-fipa-struct-reorg=6 -fdump-ipa-all -flto-partition=one -fwhole-program"
++
+ # All done.
+ torture-finish
+ dg-finish
+--
+2.27.0.windows.1
+