Sync patch from openeuler/gcc - 20221201 (cherry picked from commit 5487e8942c694fd317f2cbf1662e9eaf33f2f612)
1062 lines
29 KiB
Diff
1062 lines
29 KiB
Diff
From 7dc6940ba0f463137ff6cf98032d1e98edecde54 Mon Sep 17 00:00:00 2001
|
|
From: liyancheng <412998149@qq.com>
|
|
Date: Fri, 25 Nov 2022 19:36:59 +0800
|
|
Subject: [PATCH 32/35] [Struct Reorg] Add Unsafe Structure Pointer Compression
|
|
|
|
Unsafe structure pointer compression allows some danger conversions to
|
|
achieve faster performance.
|
|
Add flag -fipa-struct-reorg=5 to enable unsafe structure pointer compression.
|
|
---
|
|
gcc/common.opt | 6 +-
|
|
gcc/ipa-struct-reorg/ipa-struct-reorg.c | 309 +++++++++++++++---
|
|
.../gcc.dg/struct/csr_skip_void_struct_name.c | 53 +++
|
|
gcc/testsuite/gcc.dg/struct/pc_cast_int.c | 91 ++++++
|
|
.../gcc.dg/struct/pc_compress_and_decomress.c | 90 +++++
|
|
gcc/testsuite/gcc.dg/struct/pc_ptr2void.c | 87 +++++
|
|
.../gcc.dg/struct/pc_simple_rewrite_pc.c | 112 +++++++
|
|
.../gcc.dg/struct/pc_skip_void_struct_name.c | 53 +++
|
|
gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 8 +
|
|
9 files changed, 757 insertions(+), 52 deletions(-)
|
|
create mode 100644 gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c
|
|
create mode 100644 gcc/testsuite/gcc.dg/struct/pc_cast_int.c
|
|
create mode 100644 gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c
|
|
create mode 100644 gcc/testsuite/gcc.dg/struct/pc_ptr2void.c
|
|
create mode 100644 gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c
|
|
create mode 100644 gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c
|
|
|
|
diff --git a/gcc/common.opt b/gcc/common.opt
|
|
index c9b099817..384595f16 100644
|
|
--- a/gcc/common.opt
|
|
+++ b/gcc/common.opt
|
|
@@ -1889,9 +1889,9 @@ 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, 4)
|
|
--fipa-struct-reorg=[0,1,2,3,4] adding none, struct-reorg, reorder-fields,
|
|
-dfe, safe-pointer-compression optimizations.
|
|
+Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 5)
|
|
+-fipa-struct-reorg=[0,1,2,3,4,5] adding none, struct-reorg, reorder-fields,
|
|
+dfe, safe-pointer-compression, unsafe-pointer-compression optimizations.
|
|
|
|
fipa-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 3550411dc..ee4893dfb 100644
|
|
--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c
|
|
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c
|
|
@@ -264,7 +264,8 @@ enum struct_layout_opt_level
|
|
COMPLETE_STRUCT_RELAYOUT = 1 << 1,
|
|
STRUCT_REORDER_FIELDS = 1 << 2,
|
|
DEAD_FIELD_ELIMINATION = 1 << 3,
|
|
- POINTER_COMPRESSION_SAFE = 1 << 4
|
|
+ POINTER_COMPRESSION_SAFE = 1 << 4,
|
|
+ POINTER_COMPRESSION_UNSAFE = 1 << 5
|
|
};
|
|
|
|
/* Defines the target pointer size of compressed pointer, which should be 8,
|
|
@@ -1266,12 +1267,12 @@ csrtype::init_type_info (void)
|
|
|
|
/* Close enough to pad to improve performance.
|
|
33~63 should pad to 64 but 33~48 (first half) are too far away, and
|
|
- 65~127 should pad to 128 but 65~80 (first half) are too far away. */
|
|
+ 65~127 should pad to 128 but 65~70 (first half) are too far away. */
|
|
if (old_size > 48 && old_size < 64)
|
|
{
|
|
new_size = 64;
|
|
}
|
|
- if (old_size > 80 && old_size < 128)
|
|
+ if (old_size > 70 && old_size < 128)
|
|
{
|
|
new_size = 128;
|
|
}
|
|
@@ -1421,8 +1422,12 @@ public:
|
|
bool pc_candidate_tree_p (tree);
|
|
bool pc_type_conversion_candidate_p (tree);
|
|
bool pc_direct_rewrite_chance_p (tree, tree &);
|
|
+ bool pc_simplify_chance_for_compress_p (gassign *, tree);
|
|
+ bool compress_candidate_without_check (gimple_stmt_iterator *, tree, tree &);
|
|
bool compress_candidate_with_check (gimple_stmt_iterator *, tree, tree &);
|
|
bool compress_candidate (gassign *, gimple_stmt_iterator *, tree, tree &);
|
|
+ bool decompress_candidate_without_check (gimple_stmt_iterator *,
|
|
+ tree, tree, tree &, tree &);
|
|
bool decompress_candidate_with_check (gimple_stmt_iterator *, tree, tree &);
|
|
bool decompress_candidate (gimple_stmt_iterator *, tree, tree, tree &,
|
|
tree &);
|
|
@@ -1996,27 +2001,95 @@ ipa_struct_relayout::maybe_rewrite_cst (tree cst, gimple_stmt_iterator *gsi,
|
|
{
|
|
return false;
|
|
}
|
|
- gsi_next (gsi);
|
|
- gimple *stmt2 = gsi_stmt (*gsi);
|
|
-
|
|
- if (gimple_code (stmt2) == GIMPLE_ASSIGN
|
|
- && gimple_assign_rhs_code (stmt2) == POINTER_PLUS_EXPR)
|
|
+ // Check uses.
|
|
+ imm_use_iterator imm_iter_lhs;
|
|
+ use_operand_p use_p_lhs;
|
|
+ FOR_EACH_IMM_USE_FAST (use_p_lhs, imm_iter_lhs, gimple_assign_lhs (stmt))
|
|
{
|
|
- tree lhs = gimple_assign_lhs (stmt2);
|
|
- tree rhs1 = gimple_assign_rhs1 (stmt2);
|
|
- if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type)
|
|
- || types_compatible_p (inner_type (TREE_TYPE (lhs)), ctype.type))
|
|
+ gimple *stmt2 = USE_STMT (use_p_lhs);
|
|
+ if (gimple_code (stmt2) != GIMPLE_ASSIGN)
|
|
+ continue;
|
|
+ if (gimple_assign_rhs_code (stmt2) == POINTER_PLUS_EXPR)
|
|
+ {
|
|
+ tree lhs = gimple_assign_lhs (stmt2);
|
|
+ tree rhs1 = gimple_assign_rhs1 (stmt2);
|
|
+ if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type)
|
|
+ || types_compatible_p (inner_type (TREE_TYPE (lhs)),
|
|
+ ctype.type))
|
|
+ {
|
|
+ tree num = NULL;
|
|
+ if (is_result_of_mult (cst, &num,
|
|
+ TYPE_SIZE_UNIT (ctype.type)))
|
|
+ {
|
|
+ times = TREE_INT_CST_LOW (num);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // For pointer compression.
|
|
+ else if (gimple_assign_rhs_code (stmt2) == PLUS_EXPR)
|
|
{
|
|
- tree num = NULL;
|
|
- if (is_result_of_mult (cst, &num, TYPE_SIZE_UNIT (ctype.type)))
|
|
+ // Check uses.
|
|
+ imm_use_iterator imm_iter_cast;
|
|
+ use_operand_p use_p_cast;
|
|
+ FOR_EACH_IMM_USE_FAST (use_p_cast, imm_iter_cast,
|
|
+ gimple_assign_lhs (stmt2))
|
|
{
|
|
- times = TREE_INT_CST_LOW (num);
|
|
- ret = true;
|
|
+ gimple *stmt_cast = USE_STMT (use_p_cast);
|
|
+ if (gimple_code (stmt_cast) != GIMPLE_ASSIGN)
|
|
+ continue;
|
|
+ if (gimple_assign_cast_p (stmt_cast))
|
|
+ {
|
|
+ tree lhs_type = inner_type (TREE_TYPE (
|
|
+ gimple_assign_lhs (stmt_cast)));
|
|
+ if (types_compatible_p (lhs_type, ctype.type))
|
|
+ {
|
|
+ tree num = NULL;
|
|
+ if (is_result_of_mult (cst, &num,
|
|
+ TYPE_SIZE_UNIT (ctype.type)))
|
|
+ {
|
|
+ times = TREE_INT_CST_LOW (num);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // For pointer compression.
|
|
+ if (gimple_assign_rhs_code (stmt) == TRUNC_DIV_EXPR)
|
|
+ {
|
|
+ imm_use_iterator imm_iter;
|
|
+ use_operand_p use_p;
|
|
+ tree lhs = gimple_assign_lhs (stmt);
|
|
+ if (lhs == NULL_TREE)
|
|
+ return false;
|
|
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
|
|
+ {
|
|
+ gimple *use_stmt = USE_STMT (use_p);
|
|
+ if (is_gimple_debug (use_stmt))
|
|
+ continue;
|
|
+ if (gimple_code (use_stmt) != GIMPLE_ASSIGN)
|
|
+ continue;
|
|
+ if (gimple_assign_cast_p (use_stmt))
|
|
+ {
|
|
+ tree lhs_type = inner_type (TREE_TYPE (
|
|
+ gimple_assign_lhs (use_stmt)));
|
|
+ if (TYPE_UNSIGNED (lhs_type)
|
|
+ && TREE_CODE (lhs_type) == INTEGER_TYPE
|
|
+ && TYPE_PRECISION (lhs_type) == compressed_size)
|
|
+ {
|
|
+ tree num = NULL;
|
|
+ if (is_result_of_mult (cst, &num,
|
|
+ TYPE_SIZE_UNIT (ctype.type)))
|
|
+ {
|
|
+ times = TREE_INT_CST_LOW (num);
|
|
+ return true;
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
- gsi_prev (gsi);
|
|
- return ret;
|
|
}
|
|
return false;
|
|
}
|
|
@@ -3110,7 +3183,9 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg)
|
|
e = escape_separate_instance;
|
|
}
|
|
|
|
- if (e != does_not_escape)
|
|
+ if (e != does_not_escape
|
|
+ && (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT
|
|
+ || replace_type_map.get (type->type) == NULL))
|
|
type->mark_escape (e, NULL);
|
|
}
|
|
|
|
@@ -3793,7 +3868,9 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple
|
|
if (TREE_CODE (side) == SSA_NAME
|
|
&& VOID_POINTER_P (TREE_TYPE (side)))
|
|
return;
|
|
- d->type->mark_escape (escape_cast_another_ptr, stmt);
|
|
+ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT
|
|
+ || replace_type_map.get (d->type->type) == NULL)
|
|
+ d->type->mark_escape (escape_cast_another_ptr, stmt);
|
|
return;
|
|
}
|
|
|
|
@@ -3810,7 +3887,9 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple
|
|
else
|
|
{
|
|
/* *_1 = &MEM[(void *)&x + 8B]. */
|
|
- type->mark_escape (escape_cast_another_ptr, stmt);
|
|
+ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT
|
|
+ || replace_type_map.get (type->type) == NULL)
|
|
+ type->mark_escape (escape_cast_another_ptr, stmt);
|
|
}
|
|
}
|
|
else if (type != d->type)
|
|
@@ -4550,7 +4629,9 @@ ipa_struct_reorg::check_definition_assign (srdecl *decl, vec<srdecl*> &worklist)
|
|
/* Casts between pointers and integer are escaping. */
|
|
if (gimple_assign_cast_p (stmt))
|
|
{
|
|
- type->mark_escape (escape_cast_int, stmt);
|
|
+ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT
|
|
+ || replace_type_map.get (type->type) == NULL)
|
|
+ type->mark_escape (escape_cast_int, stmt);
|
|
return;
|
|
}
|
|
|
|
@@ -4897,7 +4978,9 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist)
|
|
/* Casts between pointers and integer are escaping. */
|
|
if (gimple_assign_cast_p (stmt))
|
|
{
|
|
- type->mark_escape (escape_cast_int, stmt);
|
|
+ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT
|
|
+ || replace_type_map.get (type->type) == NULL)
|
|
+ type->mark_escape (escape_cast_int, stmt);
|
|
return;
|
|
}
|
|
|
|
@@ -5566,9 +5649,9 @@ ipa_struct_reorg::prune_escaped_types (void)
|
|
|
|
/* Prune types that escape, all references to those types
|
|
will have been removed in the above loops. */
|
|
- /* The escape type is not deleted in STRUCT_LAYOUT_OPTIMIZE,
|
|
- Then the type that contains the escaped type fields
|
|
- can find complete information. */
|
|
+ /* The escape type is not deleted in current_layout_opt_level after
|
|
+ STRUCT_REORDER_FIELDS, then the type that contains the
|
|
+ escaped type fields can find complete information. */
|
|
if (current_layout_opt_level < STRUCT_REORDER_FIELDS)
|
|
{
|
|
for (unsigned i = 0; i < types.length ();)
|
|
@@ -6052,17 +6135,17 @@ ipa_struct_reorg::compress_ptr_to_offset (tree xhs, srtype *type,
|
|
tree step2 = gimplify_build2 (gsi, TRUNC_DIV_EXPR, long_unsigned_type_node,
|
|
step1, TYPE_SIZE_UNIT (type->newtype[0]));
|
|
|
|
- /* Emit gimple _X3 = _X2 + 1. */
|
|
- tree step3 = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node,
|
|
- step2, build_one_cst (long_unsigned_type_node));
|
|
+ /* Emit _X3 = (compressed_size) _X2. */
|
|
+ tree pc_type = make_unsigned_type (compressed_size);
|
|
+ tree step3 = gimplify_build1 (gsi, NOP_EXPR, pc_type, step2);
|
|
|
|
- /* Emit _X4 = (compressed_size) _X3. */
|
|
- tree step4 = gimplify_build1 (gsi, NOP_EXPR,
|
|
- make_unsigned_type (compressed_size), step3);
|
|
+ /* Emit gimple _X4 = _X3 + 1. */
|
|
+ tree step4 = gimplify_build2 (gsi, PLUS_EXPR, pc_type, step3,
|
|
+ build_one_cst (pc_type));
|
|
|
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
|
{
|
|
- print_generic_expr (dump_file, step3);
|
|
+ print_generic_expr (dump_file, step4);
|
|
fprintf (dump_file, "\n");
|
|
}
|
|
return step4;
|
|
@@ -6104,7 +6187,7 @@ ipa_struct_reorg::decompress_offset_to_ptr (tree xhs, srtype *type,
|
|
|
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
|
{
|
|
- print_generic_expr (dump_file, step3);
|
|
+ print_generic_expr (dump_file, step4);
|
|
fprintf (dump_file, "\n");
|
|
}
|
|
return step4;
|
|
@@ -6267,6 +6350,49 @@ ipa_struct_reorg::pc_direct_rewrite_chance_p (tree rhs, tree &new_rhs)
|
|
return false;
|
|
}
|
|
|
|
+/* The following cases can simplify the checking of null pointer:
|
|
+ 1. rhs defined from POINTER_PLUS_EXPR.
|
|
+ 2. rhs used as COMPONENT_REF in this basic block. */
|
|
+
|
|
+bool
|
|
+ipa_struct_reorg::pc_simplify_chance_for_compress_p (gassign *stmt,
|
|
+ tree rhs)
|
|
+{
|
|
+ imm_use_iterator imm_iter;
|
|
+ use_operand_p use_p;
|
|
+ gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
|
|
+
|
|
+ if (def_stmt && is_gimple_assign (def_stmt)
|
|
+ && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR)
|
|
+ return true;
|
|
+
|
|
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, rhs)
|
|
+ {
|
|
+ gimple *use_stmt = USE_STMT (use_p);
|
|
+ if (use_stmt->bb != stmt->bb || !is_gimple_assign (use_stmt))
|
|
+ continue;
|
|
+
|
|
+ tree use_rhs = gimple_assign_rhs1 (use_stmt);
|
|
+ if (TREE_CODE (use_rhs) == COMPONENT_REF
|
|
+ && TREE_OPERAND (TREE_OPERAND (use_rhs, 0), 0) == rhs)
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+/* Perform compression directly without checking null pointer. */
|
|
+
|
|
+bool
|
|
+ipa_struct_reorg::compress_candidate_without_check (gimple_stmt_iterator *gsi,
|
|
+ tree rhs,
|
|
+ tree &new_rhs)
|
|
+{
|
|
+ srtype *type = get_compression_candidate_type (rhs);
|
|
+ gcc_assert (type != NULL);
|
|
+ new_rhs = compress_ptr_to_offset (new_rhs, type, gsi);
|
|
+ return true;
|
|
+}
|
|
+
|
|
/* Perform pointer compression with check. The conversion will be as shown in
|
|
the following example:
|
|
Orig bb:
|
|
@@ -6368,6 +6494,9 @@ ipa_struct_reorg::compress_candidate (gassign *stmt, gimple_stmt_iterator *gsi,
|
|
{
|
|
if (pc_direct_rewrite_chance_p (rhs, new_rhs))
|
|
return true;
|
|
+ else if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE
|
|
+ && pc_simplify_chance_for_compress_p (stmt, rhs))
|
|
+ return compress_candidate_without_check (gsi, rhs, new_rhs);
|
|
|
|
return compress_candidate_with_check (gsi, rhs, new_rhs);
|
|
}
|
|
@@ -6430,6 +6559,79 @@ ipa_struct_reorg::create_bb_for_decompress_candidate (basic_block last_bb,
|
|
return new_bb;
|
|
}
|
|
|
|
+/* Try decompress candidate without check. */
|
|
+
|
|
+bool
|
|
+ipa_struct_reorg::decompress_candidate_without_check (gimple_stmt_iterator *gsi,
|
|
+ tree lhs, tree rhs,
|
|
+ tree &new_lhs,
|
|
+ tree &new_rhs)
|
|
+{
|
|
+ imm_use_iterator imm_iter;
|
|
+ use_operand_p use_p;
|
|
+ bool processed = false;
|
|
+
|
|
+ if (!gsi_one_before_end_p (*gsi))
|
|
+ {
|
|
+ gsi_next (gsi);
|
|
+ gimple *next_stmt = gsi_stmt (*gsi);
|
|
+ if (gimple_assign_rhs_class (next_stmt) == GIMPLE_SINGLE_RHS)
|
|
+ {
|
|
+ tree next_rhs = gimple_assign_rhs1 (next_stmt);
|
|
+ /* If current lhs is used as rhs in the next stmt:
|
|
+ -> _1 = t->s
|
|
+ tt->s = _1. */
|
|
+ if (lhs == next_rhs)
|
|
+ {
|
|
+ /* Check whether:
|
|
+ 1. the lhs is only used in the next stmt.
|
|
+ 2. the next lhs is candidate type. */
|
|
+ if (has_single_use (lhs)
|
|
+ && pc_candidate_tree_p (gimple_assign_lhs (next_stmt)))
|
|
+ {
|
|
+ processed = true;
|
|
+ /* Copy directly without conversion after update type. */
|
|
+ TREE_TYPE (new_lhs)
|
|
+ = make_unsigned_type (compressed_size);
|
|
+ }
|
|
+ }
|
|
+ /* -> _1 = t->s
|
|
+ _2 = _1->s
|
|
+ In this case, _1 might not be nullptr, so decompress it without
|
|
+ check. */
|
|
+ else if (TREE_CODE (next_rhs) == COMPONENT_REF)
|
|
+ {
|
|
+ tree use_base = TREE_OPERAND (TREE_OPERAND (next_rhs, 0), 0);
|
|
+ if (use_base == lhs)
|
|
+ {
|
|
+ srtype *type = get_compression_candidate_type (rhs);
|
|
+ gcc_assert (type != NULL);
|
|
+ gsi_prev (gsi);
|
|
+ tree new_ref = NULL_TREE;
|
|
+ if (TREE_CODE (new_rhs) == MEM_REF)
|
|
+ new_ref = new_rhs;
|
|
+ else
|
|
+ {
|
|
+ tree base = TREE_OPERAND (TREE_OPERAND (new_rhs, 0), 0);
|
|
+ tree new_mem_ref = build_simple_mem_ref (base);
|
|
+ new_ref = build3 (COMPONENT_REF,
|
|
+ TREE_TYPE (new_rhs),
|
|
+ new_mem_ref,
|
|
+ TREE_OPERAND (new_rhs, 1),
|
|
+ NULL_TREE);
|
|
+ }
|
|
+ new_rhs = decompress_offset_to_ptr (new_ref, type, gsi);
|
|
+ processed = true;
|
|
+ gsi_next (gsi);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ gsi_prev (gsi);
|
|
+ return processed;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
/* Perform pointer decompression with check. The conversion will be as shown
|
|
in the following example:
|
|
Orig bb:
|
|
@@ -6532,7 +6734,10 @@ ipa_struct_reorg::decompress_candidate (gimple_stmt_iterator *gsi,
|
|
tree lhs, tree rhs, tree &new_lhs,
|
|
tree &new_rhs)
|
|
{
|
|
- // TODO: simplifiy check and rewrite will be pushed in next PR.
|
|
+ if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE
|
|
+ && decompress_candidate_without_check (gsi, lhs, rhs, new_lhs, new_rhs))
|
|
+ return true;
|
|
+
|
|
return decompress_candidate_with_check (gsi, rhs, new_rhs);
|
|
}
|
|
|
|
@@ -7551,18 +7756,26 @@ ipa_struct_reorg::check_and_prune_struct_for_pointer_compression (void)
|
|
" skip compression.\n");
|
|
continue;
|
|
}
|
|
- if ((current_layout_opt_level & POINTER_COMPRESSION_SAFE)
|
|
- && !type->has_legal_alloc_num)
|
|
+ if (!type->has_legal_alloc_num)
|
|
{
|
|
- if (dump_file)
|
|
- fprintf (dump_file, " has illegal struct array size,"
|
|
- " skip compression.\n");
|
|
- continue;
|
|
+ if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE)
|
|
+ {
|
|
+ if (dump_file)
|
|
+ fprintf (dump_file, " has unknown alloc size, but"
|
|
+ " in unsafe mode, so");
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (dump_file)
|
|
+ fprintf (dump_file, " has illegal struct array size,"
|
|
+ " skip compression.\n");
|
|
+ continue;
|
|
+ }
|
|
}
|
|
pc_transform_num++;
|
|
type->pc_candidate = true;
|
|
if (dump_file)
|
|
- fprintf (dump_file, " attemps to do pointer compression.\n");
|
|
+ fprintf (dump_file, " attempts to do pointer compression.\n");
|
|
}
|
|
|
|
if (dump_file)
|
|
@@ -7584,14 +7797,10 @@ init_pointer_size_for_pointer_compression (void)
|
|
switch (param_pointer_compression_size)
|
|
{
|
|
case 8:
|
|
- compressed_size = 8; // sizeof (uint8)
|
|
- break;
|
|
+ // FALLTHRU
|
|
case 16:
|
|
- compressed_size = 16; // sizeof (uint16)
|
|
- break;
|
|
- case 32:
|
|
- compressed_size = 32; // sizeof (uint32)
|
|
- break;
|
|
+ // FALLTHRU
|
|
+ case 32: compressed_size = param_pointer_compression_size; break;
|
|
default:
|
|
error ("Invalid pointer compression size, using the following param: "
|
|
"\"--param pointer-compression-size=[8,16,32]\"");
|
|
@@ -7672,6 +7881,8 @@ public:
|
|
unsigned int level = 0;
|
|
switch (struct_layout_optimize_level)
|
|
{
|
|
+ case 5: level |= POINTER_COMPRESSION_UNSAFE;
|
|
+ // FALLTHRU
|
|
case 4: level |= POINTER_COMPRESSION_SAFE;
|
|
// FALLTHRU
|
|
case 3: level |= DEAD_FIELD_ELIMINATION;
|
|
diff --git a/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c b/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c
|
|
new file mode 100644
|
|
index 000000000..c5e4968d9
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c
|
|
@@ -0,0 +1,53 @@
|
|
+// Structures without names should not be optimized
|
|
+/* { dg-do compile } */
|
|
+#include <stdlib.h>
|
|
+#include <math.h>
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ int a;
|
|
+ float b;
|
|
+ double s1;
|
|
+ double s2;
|
|
+ double s3;
|
|
+ double s4;
|
|
+ double s5;
|
|
+ double s6;
|
|
+ double s7;
|
|
+ double s8;
|
|
+} str_t1;
|
|
+
|
|
+#define N 1000
|
|
+
|
|
+int num;
|
|
+
|
|
+int
|
|
+main ()
|
|
+{
|
|
+ int i, r;
|
|
+
|
|
+ r = rand ();
|
|
+ num = r > N ? N : r;
|
|
+ str_t1 *p1 = calloc (num, sizeof (str_t1));
|
|
+
|
|
+ if (p1 == NULL)
|
|
+ return 0;
|
|
+
|
|
+ for (i = 0; i < num; i++)
|
|
+ p1[i].a = 1;
|
|
+
|
|
+ for (i = 0; i < num; i++)
|
|
+ p1[i].b = 2;
|
|
+
|
|
+ for (i = 0; i < num; i++)
|
|
+ if (p1[i].a != 1)
|
|
+ abort ();
|
|
+
|
|
+ for (i = 0; i < num; i++)
|
|
+ if (fabsf (p1[i].b - 2) > 0.0001)
|
|
+ abort ();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* { dg-final { scan-ipa-dump "No structures to transform in Complete Structure Relayout." "struct_reorg" } } */
|
|
\ No newline at end of file
|
|
diff --git a/gcc/testsuite/gcc.dg/struct/pc_cast_int.c b/gcc/testsuite/gcc.dg/struct/pc_cast_int.c
|
|
new file mode 100644
|
|
index 000000000..6f67fc556
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.dg/struct/pc_cast_int.c
|
|
@@ -0,0 +1,91 @@
|
|
+// Escape cast int for pointer compression
|
|
+/* { dg-do compile } */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+
|
|
+typedef struct node node_t;
|
|
+typedef struct node *node_p;
|
|
+
|
|
+typedef struct arc arc_t;
|
|
+typedef struct arc *arc_p;
|
|
+
|
|
+typedef struct network
|
|
+{
|
|
+ arc_p arcs;
|
|
+ arc_p sorted_arcs;
|
|
+ int x;
|
|
+ node_p nodes;
|
|
+ node_p stop_nodes;
|
|
+} network_t;
|
|
+
|
|
+struct node
|
|
+{
|
|
+ int64_t potential;
|
|
+ int orientation;
|
|
+ node_p child;
|
|
+ node_p pred;
|
|
+ node_p sibling;
|
|
+ node_p sibling_prev;
|
|
+ arc_p basic_arc;
|
|
+ arc_p firstout;
|
|
+ arc_p firstin;
|
|
+ arc_p arc_tmp;
|
|
+ int64_t flow;
|
|
+ int64_t depth;
|
|
+ int number;
|
|
+ int time;
|
|
+};
|
|
+
|
|
+struct arc
|
|
+{
|
|
+ int id;
|
|
+ int64_t cost;
|
|
+ node_p tail;
|
|
+ node_p head;
|
|
+ short ident;
|
|
+ arc_p nextout;
|
|
+ arc_p nextin;
|
|
+ int64_t flow;
|
|
+ int64_t org_cost;
|
|
+ network_t* net_add;
|
|
+};
|
|
+
|
|
+
|
|
+const int MAX = 100;
|
|
+network_t* net;
|
|
+node_p node;
|
|
+
|
|
+int
|
|
+main ()
|
|
+{
|
|
+ net = (network_t*) calloc (1, sizeof(network_t));
|
|
+ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
|
|
+ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
|
|
+ net->nodes = (node_p) calloc (MAX, sizeof (node_t));
|
|
+ net->arcs->id = 100;
|
|
+
|
|
+ node = net->nodes;
|
|
+ node_p n1 = (node_p) 0x123456;
|
|
+
|
|
+ for (unsigned i = 0; i < MAX; i++)
|
|
+ {
|
|
+ node->pred = n1;
|
|
+ node = node + 1;
|
|
+ }
|
|
+
|
|
+ node = net->nodes;
|
|
+
|
|
+ for (unsigned i = 0; i < MAX; i++)
|
|
+ {
|
|
+ if (node->pred != n1)
|
|
+ {
|
|
+ abort ();
|
|
+ }
|
|
+ node = node + 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* { dg-final { scan-ipa-dump "No structures to transform in pointer compression" "struct_reorg" } } */
|
|
\ No newline at end of file
|
|
diff --git a/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c b/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c
|
|
new file mode 100644
|
|
index 000000000..d0b8d1afa
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c
|
|
@@ -0,0 +1,90 @@
|
|
+// Support basic pointer compression and decompression
|
|
+/* { dg-do compile } */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+
|
|
+typedef struct node node_t;
|
|
+typedef struct node *node_p;
|
|
+
|
|
+typedef struct arc arc_t;
|
|
+typedef struct arc *arc_p;
|
|
+
|
|
+typedef struct network
|
|
+{
|
|
+ arc_p arcs;
|
|
+ arc_p sorted_arcs;
|
|
+ int x;
|
|
+ node_p nodes;
|
|
+ node_p stop_nodes;
|
|
+} network_t;
|
|
+
|
|
+struct node
|
|
+{
|
|
+ int64_t potential;
|
|
+ int orientation;
|
|
+ node_p child;
|
|
+ node_p pred;
|
|
+ node_p sibling;
|
|
+ node_p sibling_prev;
|
|
+ arc_p basic_arc;
|
|
+ arc_p firstout;
|
|
+ arc_p firstin;
|
|
+ arc_p arc_tmp;
|
|
+ int64_t flow;
|
|
+ int64_t depth;
|
|
+ int number;
|
|
+ int time;
|
|
+};
|
|
+
|
|
+struct arc
|
|
+{
|
|
+ int id;
|
|
+ int64_t cost;
|
|
+ node_p tail;
|
|
+ node_p head;
|
|
+ short ident;
|
|
+ arc_p nextout;
|
|
+ arc_p nextin;
|
|
+ int64_t flow;
|
|
+ int64_t org_cost;
|
|
+ network_t* net_add;
|
|
+};
|
|
+
|
|
+
|
|
+const int MAX = 100;
|
|
+network_t* net;
|
|
+node_p node;
|
|
+
|
|
+int
|
|
+main ()
|
|
+{
|
|
+ net = (network_t*) calloc (1, sizeof(network_t));
|
|
+ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
|
|
+ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
|
|
+ net->nodes = (node_p) calloc (MAX, sizeof (node_t));
|
|
+ net->arcs->id = 100;
|
|
+
|
|
+ node = net->nodes;
|
|
+
|
|
+ for (unsigned i = 0; i < MAX; i++)
|
|
+ {
|
|
+ node->pred = node;
|
|
+ node = node + 1;
|
|
+ }
|
|
+
|
|
+ node = net->nodes;
|
|
+
|
|
+ for (unsigned i = 0; i < MAX; i++)
|
|
+ {
|
|
+ if (node->pred != node)
|
|
+ {
|
|
+ abort ();
|
|
+ }
|
|
+ node = node + 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */
|
|
\ No newline at end of file
|
|
diff --git a/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c b/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c
|
|
new file mode 100644
|
|
index 000000000..5022c1967
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c
|
|
@@ -0,0 +1,87 @@
|
|
+// Partially support escape_cast_void for pointer compression.
|
|
+/* { dg-do compile } */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+
|
|
+typedef struct node node_t;
|
|
+typedef struct node *node_p;
|
|
+
|
|
+typedef struct arc arc_t;
|
|
+typedef struct arc *arc_p;
|
|
+
|
|
+typedef struct network
|
|
+{
|
|
+ arc_p arcs, sorted_arcs;
|
|
+ int x;
|
|
+ node_p nodes, stop_nodes;
|
|
+} network_t;
|
|
+
|
|
+struct node
|
|
+{
|
|
+ int64_t potential;
|
|
+ int orientation;
|
|
+ node_p child;
|
|
+ node_p pred;
|
|
+ node_p sibling;
|
|
+ node_p sibling_prev;
|
|
+ arc_p basic_arc;
|
|
+ arc_p firstout;
|
|
+ arc_p firstin;
|
|
+ arc_p arc_tmp;
|
|
+ int64_t flow;
|
|
+ int64_t depth;
|
|
+ int number;
|
|
+ int time;
|
|
+};
|
|
+
|
|
+struct arc
|
|
+{
|
|
+ int id;
|
|
+ int64_t cost;
|
|
+ node_p tail;
|
|
+ node_p head;
|
|
+ short ident;
|
|
+ arc_p nextout;
|
|
+ arc_p nextin;
|
|
+ int64_t flow;
|
|
+ int64_t org_cost;
|
|
+};
|
|
+
|
|
+const int MAX = 100;
|
|
+network_t* net = NULL;
|
|
+int cnt = 0;
|
|
+
|
|
+__attribute__((noinline)) int
|
|
+primal_feasible (network_t *net)
|
|
+{
|
|
+ void* stop;
|
|
+ node_t *node;
|
|
+
|
|
+ node = net->nodes;
|
|
+ stop = (void *)net->stop_nodes;
|
|
+ for( node++; node < (node_t *)stop; node++ )
|
|
+ {
|
|
+ net->x = 1;
|
|
+ printf( "PRIMAL NETWORK SIMPLEX: ");
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
+main ()
|
|
+{
|
|
+ net = (network_t*) calloc (1, 20);
|
|
+ net->nodes = calloc (MAX, sizeof (node_t));
|
|
+ net->stop_nodes = net->nodes + MAX - 1;
|
|
+ cnt = primal_feasible( net );
|
|
+
|
|
+ net = (network_t*) calloc (1, 20);
|
|
+ if( !(net->arcs) )
|
|
+ {
|
|
+ return -1;
|
|
+ }
|
|
+ return cnt;
|
|
+}
|
|
+
|
|
+/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */
|
|
\ No newline at end of file
|
|
diff --git a/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c b/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c
|
|
new file mode 100644
|
|
index 000000000..98943c9b8
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c
|
|
@@ -0,0 +1,112 @@
|
|
+// Check simplify rewrite chance for pointer compression and decompression
|
|
+/* { dg-do compile } */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+
|
|
+typedef struct node node_t;
|
|
+typedef struct node *node_p;
|
|
+
|
|
+typedef struct arc arc_t;
|
|
+typedef struct arc *arc_p;
|
|
+
|
|
+typedef struct network
|
|
+{
|
|
+ arc_p arcs;
|
|
+ arc_p sorted_arcs;
|
|
+ int x;
|
|
+ node_p nodes;
|
|
+ node_p stop_nodes;
|
|
+} network_t;
|
|
+
|
|
+struct node
|
|
+{
|
|
+ int64_t potential;
|
|
+ int orientation;
|
|
+ node_p child;
|
|
+ node_p pred;
|
|
+ node_p sibling;
|
|
+ node_p sibling_prev;
|
|
+ arc_p basic_arc;
|
|
+ arc_p firstout;
|
|
+ arc_p firstin;
|
|
+ arc_p arc_tmp;
|
|
+ int64_t flow;
|
|
+ int64_t depth;
|
|
+ int number;
|
|
+ int time;
|
|
+};
|
|
+
|
|
+struct arc
|
|
+{
|
|
+ int id;
|
|
+ int64_t cost;
|
|
+ node_p tail;
|
|
+ node_p head;
|
|
+ short ident;
|
|
+ arc_p nextout;
|
|
+ arc_p nextin;
|
|
+ int64_t flow;
|
|
+ int64_t org_cost;
|
|
+ network_t* net_add;
|
|
+};
|
|
+
|
|
+
|
|
+const int MAX = 100;
|
|
+network_t* net;
|
|
+node_p node;
|
|
+arc_p arc;
|
|
+
|
|
+int
|
|
+main ()
|
|
+{
|
|
+ net = (network_t*) calloc (1, sizeof(network_t));
|
|
+ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
|
|
+ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
|
|
+ net->nodes = (node_p) calloc (MAX, sizeof (node_t));
|
|
+ net->arcs->id = 100;
|
|
+
|
|
+ node = net->nodes;
|
|
+ arc = net->arcs;
|
|
+
|
|
+ for (unsigned i = 0; i < MAX; i++)
|
|
+ {
|
|
+ arc->head = node;
|
|
+ arc->head->child = node;
|
|
+ node->potential = i + 1;
|
|
+ arc->cost = arc->head->potential;
|
|
+ arc->tail = node->sibling;
|
|
+ if (i % 2)
|
|
+ node->pred = net->nodes + i;
|
|
+ else
|
|
+ node->pred = NULL;
|
|
+
|
|
+ if (node->pred && node->pred->child != NULL)
|
|
+ node->number = 0;
|
|
+ else
|
|
+ node->number = 1;
|
|
+
|
|
+ node = node + 1;
|
|
+ arc = arc + 1;
|
|
+ }
|
|
+
|
|
+ node = net->nodes;
|
|
+ arc = net->arcs;
|
|
+
|
|
+ for (unsigned i = 0; i < MAX; i++)
|
|
+ {
|
|
+ node_p t = i % 2 ? node : NULL;
|
|
+ int tt = i % 2 ? 0 : 1;
|
|
+ if (arc->head->pred != t || arc->cost == 0
|
|
+ || arc->tail != node->sibling || node->number != tt)
|
|
+ {
|
|
+ abort ();
|
|
+ }
|
|
+ arc = arc + 1;
|
|
+ node = node + 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */
|
|
\ No newline at end of file
|
|
diff --git a/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c b/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c
|
|
new file mode 100644
|
|
index 000000000..a0e191267
|
|
--- /dev/null
|
|
+++ b/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c
|
|
@@ -0,0 +1,53 @@
|
|
+// Structures without names should not be optimized
|
|
+/* { dg-do compile } */
|
|
+#include <stdlib.h>
|
|
+#include <math.h>
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ int a;
|
|
+ float b;
|
|
+ double s1;
|
|
+ double s2;
|
|
+ double s3;
|
|
+ double s4;
|
|
+ double s5;
|
|
+ double s6;
|
|
+ double s7;
|
|
+ double s8;
|
|
+} str_t1;
|
|
+
|
|
+#define N 1000
|
|
+
|
|
+int num;
|
|
+
|
|
+int
|
|
+main ()
|
|
+{
|
|
+ int i, r;
|
|
+
|
|
+ r = rand ();
|
|
+ num = r > N ? N : r;
|
|
+ str_t1 *p1 = calloc (num, sizeof (str_t1));
|
|
+
|
|
+ if (p1 == NULL)
|
|
+ return 0;
|
|
+
|
|
+ for (i = 0; i < num; i++)
|
|
+ p1[i].a = 1;
|
|
+
|
|
+ for (i = 0; i < num; i++)
|
|
+ p1[i].b = 2;
|
|
+
|
|
+ for (i = 0; i < num; i++)
|
|
+ if (p1[i].a != 1)
|
|
+ abort ();
|
|
+
|
|
+ for (i = 0; i < num; i++)
|
|
+ if (fabsf (p1[i].b - 2) > 0.0001)
|
|
+ abort ();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* { dg-final { scan-ipa-dump "No structures to transform in pointer compression" "struct_reorg" } } */
|
|
\ No newline at end of file
|
|
diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
|
|
index 2eebef768..d7367ed96 100644
|
|
--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
|
|
+++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
|
|
@@ -85,6 +85,14 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf*.c]] \
|
|
gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/dfe*.c]] \
|
|
"" "-fipa-struct-reorg=3 -fdump-ipa-all -flto-partition=one -fwhole-program"
|
|
|
|
+# -fipa-struct-reorg=4
|
|
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \
|
|
+ "" "-fipa-struct-reorg=4 -fdump-ipa-all -flto-partition=one -fwhole-program"
|
|
+
|
|
+# -fipa-struct-reorg=5
|
|
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \
|
|
+ "" "-fipa-struct-reorg=5 -fdump-ipa-all -flto-partition=one -fwhole-program"
|
|
+
|
|
# All done.
|
|
torture-finish
|
|
dg-finish
|
|
--
|
|
2.27.0.windows.1
|
|
|