加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
0053-struct-reorg-Add-Semi-Relayout.patch 46.48 KB
一键复制 编辑 原始数据 按行查看 历史
郑晨卉 提交于 2024-04-11 10:45 . [Sync] Sync patch from openeuler/gcc
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366
From c2a0dcc565e0f6274f26644bd389337db8f2940c Mon Sep 17 00:00:00 2001
From: tiancheng-bao <baotiancheng1@huawei.com>
Date: Sat, 30 Mar 2024 11:04:23 +0800
Subject: [PATCH] [struct-reorg] Add Semi Relayout
---
gcc/common.opt | 6 +-
gcc/ipa-struct-reorg/ipa-struct-reorg.cc | 975 +++++++++++++++++-
gcc/ipa-struct-reorg/ipa-struct-reorg.h | 8 +
gcc/params.opt | 5 +
.../gcc.dg/struct/semi_relayout_rewrite.c | 86 ++
gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 4 +
6 files changed, 1040 insertions(+), 44 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/struct/semi_relayout_rewrite.c
diff --git a/gcc/common.opt b/gcc/common.opt
index 38f1e457d..9484df5ad 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2010,9 +2010,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, 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-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 3922873f3..6a202b4bd 100644
--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
@@ -294,7 +294,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,
@@ -308,6 +309,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. */
@@ -426,7 +428,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;
@@ -891,6 +895,66 @@ srfield::create_new_reorder_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
@@ -1001,6 +1065,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 *> &);
@@ -1442,6 +1515,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 &);
+ bool do_semi_relayout (gimple_stmt_iterator *, gimple *, tree &, tree &);
};
struct ipa_struct_relayout
@@ -4355,7 +4455,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))
@@ -4363,13 +4463,28 @@ 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. */
type->has_alloc_array = -1;
else if (bb->loop_father != NULL
&& loop_outer (bb->loop_father) != NULL)
- /* The allocation is in a loop. */
- type->has_alloc_array = -2;
+ {
+ /* 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;
+ }
else if (node->callers != NULL)
type->has_alloc_array = -3;
else
@@ -4448,6 +4563,13 @@ ipa_struct_reorg::check_definition_assign (srdecl *decl,
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. */
@@ -4484,7 +4606,8 @@ ipa_struct_reorg::check_definition_call (srdecl *decl, vec<srdecl *> &worklist)
type->mark_escape (escape_return, stmt);
}
- check_alloc_num (stmt, type);
+ bool ptrptr = isptrptr (decl->orig_type);
+ check_alloc_num (stmt, type, ptrptr);
return;
}
@@ -6038,6 +6161,55 @@ 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 (!old_type)
+ return false;
+ 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. */
@@ -6388,7 +6560,7 @@ ipa_struct_reorg::decompress_candidate_without_check (gimple_stmt_iterator *gsi,
}
}
/* -> _1 = t->s
- _2 = _1->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)
@@ -6582,6 +6754,426 @@ 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);
+ // tree pointer_type = build_pointer_type (long_integer_type_node);
+ tree intptr_type = signed_type_for (pointer_type);
+
+ /* addr_high_1 = (intptr_t)ptr1 >> shifts */
+ tree ptr1_cvt = fold_convert (intptr_type, ptr1);
+ tree addr_high_1 = gimplify_build2 (gsi, RSHIFT_EXPR, intptr_type,
+ ptr1_cvt, shifts);
+ /* addr_high_2 = (intptr_t)ptr2 >> shifts */
+ tree ptr2_cvt = fold_convert (intptr_type, ptr2);
+ tree addr_high_2 = gimplify_build2 (gsi, RSHIFT_EXPR, intptr_type,
+ ptr2_cvt, shifts);
+ /* off1 = (intptr_t)ptr1 - (addr_high_1 << shifts) */
+ tree bucket_start_1 = gimplify_build2 (gsi, LSHIFT_EXPR, intptr_type,
+ addr_high_1, shifts);
+ tree off1 = gimplify_build2 (gsi, MINUS_EXPR, intptr_type,
+ ptr1_cvt, bucket_start_1);
+ /* off2 = (intptr_t)ptr2 - (addr_high_2 << shifts) */
+ tree bucket_start_2 = gimplify_build2 (gsi, LSHIFT_EXPR, intptr_type,
+ addr_high_2, shifts);
+ tree off2 = gimplify_build2 (gsi, MINUS_EXPR, intptr_type,
+ ptr2_cvt, bucket_start_2);
+ /* group_diff = (addr_high_1 - addr_high_2) / bucket_parts */
+ tree bucket_sub = gimplify_build2 (gsi, MINUS_EXPR, intptr_type,
+ addr_high_1, addr_high_2);
+ tree bucket_parts = build_int_cst (intptr_type,
+ type->bucket_parts);
+ tree group_diff = gimplify_build2 (gsi, TRUNC_DIV_EXPR,
+ intptr_type,
+ bucket_sub, bucket_parts);
+ /* off_addr_diff = off1 - off2 */
+ tree off_addr_diff = gimplify_build2 (gsi, MINUS_EXPR, intptr_type,
+ 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,
+ intptr_type,
+ 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, intptr_type,
+ 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 intptr_type = signed_type_for (long_unsigned_type_node);
+ tree shifts = build_int_cst (intptr_type, semi_relayout_align);
+ gimple_stmt_iterator gsi = gsi_last_bb (new_bb);
+ gsi_insert_after (&gsi, gimple_build_nop (), GSI_NEW_STMT);
+ tree ptr_cvt = fold_convert (intptr_type, ptr);
+ /* curr_group_start = (ptr >> shifts) << shifts; */
+ tree ptr_r_1 = gimplify_build2 (&gsi, RSHIFT_EXPR, intptr_type,
+ ptr_cvt, shifts);
+ tree curr_group_start = gimplify_build2 (&gsi, LSHIFT_EXPR, intptr_type,
+ ptr_r_1, shifts);
+ /* curr_off_from_group = ptr - curr_group_start; */
+ tree curr_off_from_group = gimplify_build2 (&gsi, MINUS_EXPR,
+ intptr_type,
+ ptr_cvt, 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 step1_cvt = fold_convert (intptr_type, step1);
+ tree step2 = gimplify_build2 (&gsi, LSHIFT_EXPR, intptr_type,
+ step1_cvt, shifts);
+ tree off_times_8_cvt = fold_convert (intptr_type, off_times_8);
+ tree step3 = gimplify_build2 (&gsi, PLUS_EXPR, intptr_type,
+ curr_off_from_group, off_times_8_cvt);
+ tree step4 = gimplify_build2 (&gsi, TRUNC_MOD_EXPR, intptr_type,
+ step3, build_int_cst (intptr_type,
+ relayout_part_size));
+ tree step5 = gimplify_build2 (&gsi, PLUS_EXPR, intptr_type,
+ 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 (long_integer_type_node, 8);
+ tree shifts = build_int_cst (long_integer_type_node, semi_relayout_align);
+ // 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_int, 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);
+
+ edge e = split_block (cond->bb, cond);
+ 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 ATTRIBUTE_UNUSED,
+ tree lhs, tree rhs ATTRIBUTE_UNUSED,
+ 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);
+ if (!is_gimple_reg (new_l_mem_ref))
+ {
+ tree tmp_reg = create_tmp_reg (TREE_TYPE(new_l_mem_ref));
+ gimple *copy_stmt = gimple_build_assign (tmp_reg, new_r_mem_ref);
+ gsi_insert_before (gsi, copy_stmt, GSI_SAME_STMT);
+ new_r_mem_ref = tmp_reg;
+ }
+ gimple *new_stmt = gimple_build_assign (new_l_mem_ref, new_r_mem_ref);
+ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
+ }
+ gcc_assert (new_l_mem_ref != NULL_TREE && new_r_mem_ref != NULL_TREE);
+ newlhs = new_l_mem_ref;
+ newrhs = new_r_mem_ref;
+}
+
+bool
+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);
+ return true;
+ }
+ }
+ 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);
+ }
+ return false;
+}
+
bool
ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
{
@@ -6677,7 +7269,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 is not a multiplicate and it slips through");
@@ -6698,12 +7291,39 @@ 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
- new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR,
- newrhs[i], rhs2);
+ {
+ /* 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);
+ }
gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
remove = true;
}
@@ -6744,13 +7364,34 @@ 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;
}
@@ -6777,18 +7418,24 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
fprintf (dump_file, "\nreplaced with:\n");
for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++)
{
+ bool fields_copied = false;
+ if (current_layout_opt_level & SEMI_RELAYOUT)
+ fields_copied = 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]);
- gimple *newstmt = gimple_build_assign (newlhs[i] ? newlhs[i] : lhs,
- newrhs[i] ? newrhs[i] : rhs);
+ remove = true;
+ if (fields_copied)
+ continue;
+ tree lhs_expr = newlhs[i] ? newlhs[i] : lhs;
+ tree rhs_expr = newrhs[i] ? newrhs[i] : rhs;
+ gimple *newstmt = gimple_build_assign (lhs_expr, rhs_expr);
if (dump_file && (dump_flags & TDF_DETAILS))
{
print_gimple_stmt (dump_file, newstmt, 0);
fprintf (dump_file, "\n");
}
gsi_insert_before (gsi, newstmt, GSI_SAME_STMT);
- remove = true;
}
return remove;
}
@@ -6796,6 +7443,110 @@ 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 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. */
@@ -6837,25 +7588,74 @@ 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. */
@@ -6875,11 +7675,14 @@ 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)
{
- gimple_call_set_arg (stmt, 0, newexpr[0]);
- update_stmt (stmt);
- return false;
+ 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;
}
for (unsigned i = 0; i < max_split && newexpr[i]; i++)
@@ -7571,6 +8374,86 @@ 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
@@ -7612,6 +8495,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
@@ -7659,6 +8544,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;
@@ -7678,6 +8565,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 6c4469597..e3e6d7afb 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 *>
{
@@ -128,6 +131,10 @@ public:
/* Negative number means it has illegal allocated arrays
that we do not optimize. */
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);
@@ -149,6 +156,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 bb5d82471..82a3d92c5 100644
--- a/gcc/params.opt
+++ b/gcc/params.opt
@@ -1221,4 +1221,9 @@ Target size of compressed pointer, which should be 8, 16 or 32.
-param=param-ldp-dependency-search-range=
Common Joined UInteger Var(param_ldp_dependency_search_range) Init(16) IntegerRange(1, 32) Param Optimization
Range for depended ldp search in split-ldp-stp path.
+
+-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..aca8400ca
--- /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 c40474407..c5a955b00 100644
--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
+++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
@@ -55,6 +55,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.33.0
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化