diff options
Diffstat (limited to '0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch')
-rw-r--r-- | 0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch | 1297 |
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 + |