diff options
Diffstat (limited to '0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch')
-rw-r--r-- | 0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch | 1232 |
1 files changed, 1232 insertions, 0 deletions
diff --git a/0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch b/0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch new file mode 100644 index 0000000..2bca621 --- /dev/null +++ b/0030-Struct-Reorg-Add-unsafe-structure-pointer-compressio.patch @@ -0,0 +1,1232 @@ +From 82d6166cd29fb1c3474f29b28cb7e5478d3a551a Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Mon, 25 Dec 2023 11:17:04 +0800 +Subject: [PATCH] [Struct Reorg] Add unsafe structure pointer compression + +Unsafe structure pointer compression allows for some dangerous +conversions for better performance. +Add flag -fipa-struct-reorg=5 to enable unsafe structure pointer +compression. +--- + gcc/common.opt | 6 +- + gcc/ipa-struct-reorg/ipa-struct-reorg.cc | 365 ++++++++++++++---- + gcc/symbol-summary.h | 22 +- + .../gcc.dg/struct/csr_skip_void_struct_name.c | 53 +++ + gcc/testsuite/gcc.dg/struct/pc_cast_int.c | 91 +++++ + .../gcc.dg/struct/pc_compress_and_decomress.c | 90 +++++ + gcc/testsuite/gcc.dg/struct/pc_ptr2void.c | 87 +++++ + .../gcc.dg/struct/pc_simple_rewrite_pc.c | 112 ++++++ + .../gcc.dg/struct/pc_skip_void_struct_name.c | 53 +++ + gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 8 + + 10 files changed, 804 insertions(+), 83 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c + create mode 100644 gcc/testsuite/gcc.dg/struct/pc_cast_int.c + create mode 100644 gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c + create mode 100644 gcc/testsuite/gcc.dg/struct/pc_ptr2void.c + create mode 100644 gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c + create mode 100644 gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c + +diff --git a/gcc/common.opt b/gcc/common.opt +index 56b547506..c7c6bc256 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1993,9 +1993,9 @@ Common Var(flag_ipa_struct_reorg) Init(0) Optimization + Perform structure layout optimizations. + + fipa-struct-reorg= +-Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 4) +--fipa-struct-reorg=[0,1,2,3,4] adding none, struct-reorg, reorder-fields, +-dfe, safe-pointer-compression optimizations. ++Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 5) ++-fipa-struct-reorg=[0,1,2,3,4,5] adding none, struct-reorg, reorder-fields, ++dfe, safe-pointer-compression, unsafe-pointer-compression optimizations. + + fipa-vrp + Common Var(flag_ipa_vrp) Optimization +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc +index 5d451c4c8..fa33f2d35 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc +@@ -293,7 +293,8 @@ enum struct_layout_opt_level + COMPLETE_STRUCT_RELAYOUT = 1 << 1, + STRUCT_REORDER_FIELDS = 1 << 2, + DEAD_FIELD_ELIMINATION = 1 << 3, +- POINTER_COMPRESSION_SAFE = 1 << 4 ++ POINTER_COMPRESSION_SAFE = 1 << 4, ++ POINTER_COMPRESSION_UNSAFE = 1 << 5 + }; + + /* Defines the target pointer size of compressed pointer, which should be 8, +@@ -1267,10 +1268,10 @@ csrtype::init_type_info (void) + + /* Close enough to pad to improve performance. + 33~63 should pad to 64 but 33~48 (first half) are too far away, and +- 65~127 should pad to 128 but 65~96 (first half) are too far away. */ ++ 70~127 should pad to 128 but 65~70 (first half) are too far away. */ + if (old_size > 48 && old_size < 64) + new_size = 64; +- if (old_size > 96 && old_size < 128) ++ if (old_size > 70 && old_size < 128) + new_size = 128; + + /* For performance reasons, only allow structure size +@@ -1423,8 +1424,12 @@ public: + bool pc_candidate_tree_p (tree); + bool pc_type_conversion_candidate_p (tree); + bool pc_direct_rewrite_chance_p (tree, tree &); ++ bool pc_simplify_chance_for_compress_p (gassign *, tree); ++ bool compress_candidate_without_check (gimple_stmt_iterator *, tree, tree &); + bool compress_candidate_with_check (gimple_stmt_iterator *, tree, tree &); + bool compress_candidate (gassign *, gimple_stmt_iterator *, tree, tree &); ++ bool decompress_candidate_without_check (gimple_stmt_iterator *, ++ tree, tree, tree &, tree &); + bool decompress_candidate_with_check (gimple_stmt_iterator *, tree, tree &); + bool decompress_candidate (gimple_stmt_iterator *, tree, tree, tree &, + tree &); +@@ -1924,7 +1929,6 @@ bool + ipa_struct_relayout::maybe_rewrite_cst (tree cst, gimple_stmt_iterator *gsi, + HOST_WIDE_INT ×) + { +- bool ret = false; + gcc_assert (TREE_CODE (cst) == INTEGER_CST); + + gimple *stmt = gsi_stmt (*gsi); +@@ -1948,27 +1952,95 @@ ipa_struct_relayout::maybe_rewrite_cst (tree cst, gimple_stmt_iterator *gsi, + { + if (gsi_one_before_end_p (*gsi)) + return false; +- gsi_next (gsi); +- gimple *stmt2 = gsi_stmt (*gsi); +- +- if (gimple_code (stmt2) == GIMPLE_ASSIGN +- && gimple_assign_rhs_code (stmt2) == POINTER_PLUS_EXPR) ++ // Check uses. ++ imm_use_iterator imm_iter_lhs; ++ use_operand_p use_p_lhs; ++ FOR_EACH_IMM_USE_FAST (use_p_lhs, imm_iter_lhs, gimple_assign_lhs (stmt)) + { +- tree lhs = gimple_assign_lhs (stmt2); +- tree rhs1 = gimple_assign_rhs1 (stmt2); +- if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type) +- || types_compatible_p (inner_type (TREE_TYPE (lhs)), ctype.type)) ++ gimple *stmt2 = USE_STMT (use_p_lhs); ++ if (gimple_code (stmt2) != GIMPLE_ASSIGN) ++ continue; ++ if (gimple_assign_rhs_code (stmt2) == POINTER_PLUS_EXPR) + { +- tree num = NULL; +- if (is_result_of_mult (cst, &num, TYPE_SIZE_UNIT (ctype.type))) ++ tree lhs = gimple_assign_lhs (stmt2); ++ tree rhs1 = gimple_assign_rhs1 (stmt2); ++ if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type) ++ || types_compatible_p (inner_type (TREE_TYPE (lhs)), ++ ctype.type)) + { +- times = TREE_INT_CST_LOW (num); +- ret = true; ++ tree num = NULL; ++ if (is_result_of_mult (cst, &num, ++ TYPE_SIZE_UNIT (ctype.type))) ++ { ++ times = TREE_INT_CST_LOW (num); ++ return true; ++ } ++ } ++ } ++ // For pointer compression, handle plus stmt. ++ else if (gimple_assign_rhs_code (stmt2) == PLUS_EXPR) ++ { ++ // Check uses. ++ imm_use_iterator imm_iter_cast; ++ use_operand_p use_p_cast; ++ FOR_EACH_IMM_USE_FAST (use_p_cast, imm_iter_cast, ++ gimple_assign_lhs (stmt2)) ++ { ++ gimple *stmt_cast = USE_STMT (use_p_cast); ++ if (gimple_code (stmt_cast) != GIMPLE_ASSIGN) ++ continue; ++ if (gimple_assign_cast_p (stmt_cast)) ++ { ++ tree lhs_type = inner_type (TREE_TYPE ( ++ gimple_assign_lhs (stmt_cast))); ++ if (types_compatible_p (lhs_type, ctype.type)) ++ { ++ tree num = NULL; ++ if (is_result_of_mult (cst, &num, ++ TYPE_SIZE_UNIT (ctype.type))) ++ { ++ times = TREE_INT_CST_LOW (num); ++ return true; ++ } ++ } ++ } + } + } + } +- gsi_prev (gsi); +- return ret; ++ } ++ // For pointer compression, handle div stmt. ++ if (gimple_assign_rhs_code (stmt) == TRUNC_DIV_EXPR) ++ { ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ tree lhs = gimple_assign_lhs (stmt); ++ if (lhs == NULL_TREE) ++ return false; ++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs) ++ { ++ gimple *use_stmt = USE_STMT (use_p); ++ if (is_gimple_debug (use_stmt)) ++ continue; ++ if (gimple_code (use_stmt) != GIMPLE_ASSIGN) ++ continue; ++ if (gimple_assign_cast_p (use_stmt)) ++ { ++ tree lhs_type = inner_type (TREE_TYPE ( ++ gimple_assign_lhs (use_stmt))); ++ if (TYPE_UNSIGNED (lhs_type) ++ && TREE_CODE (lhs_type) == INTEGER_TYPE ++ && TYPE_PRECISION (lhs_type) == compressed_size) ++ { ++ tree num = NULL; ++ if (is_result_of_mult (cst, &num, ++ TYPE_SIZE_UNIT (ctype.type))) ++ { ++ times = TREE_INT_CST_LOW (num); ++ return true; ++ } ++ } ++ } ++ } + } + return false; + } +@@ -2967,7 +3039,9 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg) + && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE) + e = escape_separate_instance; + +- if (e != does_not_escape) ++ if (e != does_not_escape ++ && (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT ++ || replace_type_map.get (type->type) == NULL)) + type->mark_escape (e, NULL); + } + +@@ -3629,7 +3703,9 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, + if (TREE_CODE (side) == SSA_NAME + && VOID_POINTER_P (TREE_TYPE (side))) + return; +- d->type->mark_escape (escape_cast_another_ptr, stmt); ++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT ++ || replace_type_map.get (d->type->type) == NULL) ++ d->type->mark_escape (escape_cast_another_ptr, stmt); + return; + } + +@@ -3645,7 +3721,9 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, + } + else + /* *_1 = &MEM[(void *)&x + 8B]. */ +- type->mark_escape (escape_cast_another_ptr, stmt); ++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT ++ || replace_type_map.get (type->type) == NULL) ++ type->mark_escape (escape_cast_another_ptr, stmt); + } + else if (type != d->type) + { +@@ -4364,7 +4442,9 @@ ipa_struct_reorg::check_definition_assign (srdecl *decl, + /* Casts between pointers and integer are escaping. */ + if (gimple_assign_cast_p (stmt)) + { +- type->mark_escape (escape_cast_int, stmt); ++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT ++ || replace_type_map.get (type->type) == NULL) ++ type->mark_escape (escape_cast_int, stmt); + return; + } + +@@ -4684,7 +4764,9 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, + /* Casts between pointers and integer are escaping. */ + if (gimple_assign_cast_p (stmt)) + { +- type->mark_escape (escape_cast_int, stmt); ++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT ++ || replace_type_map.get (type->type) == NULL) ++ type->mark_escape (escape_cast_int, stmt); + return; + } + +@@ -5364,9 +5446,9 @@ ipa_struct_reorg::prune_escaped_types (void) + + /* Prune types that escape, all references to those types + will have been removed in the above loops. */ +- /* The escape type is not deleted in STRUCT_REORDER_FIELDS, +- Then the type that contains the escaped type fields +- can find complete information. */ ++ /* The escape type is not deleted in current_layout_opt_level ++ after STRUCT_REORDER_FIELDS, then the type that contains ++ the escaped type fields can find complete information. */ + if (current_layout_opt_level < STRUCT_REORDER_FIELDS) + { + for (unsigned i = 0; i < types.length ();) +@@ -5842,17 +5924,17 @@ ipa_struct_reorg::compress_ptr_to_offset (tree xhs, srtype *type, + tree step2 = gimplify_build2 (gsi, TRUNC_DIV_EXPR, long_unsigned_type_node, + step1, TYPE_SIZE_UNIT (type->newtype[0])); + +- /* Emit gimple _X3 = _X2 + 1. */ +- tree step3 = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node, +- step2, build_one_cst (long_unsigned_type_node)); ++ /* Emit _X3 = (compressed_size) _X2. */ ++ tree pc_type = make_unsigned_type (compressed_size); ++ tree step3 = gimplify_build1 (gsi, NOP_EXPR, pc_type, step2); + +- /* Emit _X4 = (compressed_size) _X3. */ +- tree step4 = gimplify_build1 (gsi, NOP_EXPR, +- make_unsigned_type (compressed_size), step3); ++ /* Emit gimple _X4 = _X3 + 1. */ ++ tree step4 = gimplify_build2 (gsi, PLUS_EXPR, pc_type, step3, ++ build_one_cst (pc_type)); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- print_generic_expr (dump_file, step3); ++ print_generic_expr (dump_file, step4); + fprintf (dump_file, "\n"); + } + return step4; +@@ -5894,7 +5976,7 @@ ipa_struct_reorg::decompress_offset_to_ptr (tree xhs, srtype *type, + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- print_generic_expr (dump_file, step3); ++ print_generic_expr (dump_file, step4); + fprintf (dump_file, "\n"); + } + return step4; +@@ -5967,7 +6049,10 @@ ipa_struct_reorg::pc_type_conversion_candidate_p (tree xhs) + + if (TREE_CODE (xhs) == COMPONENT_REF) + { +- srtype *base_type = find_type (TREE_TYPE (TREE_OPERAND (xhs, 0))); ++ tree mem = TREE_OPERAND (xhs, 0); ++ if (TREE_CODE (mem) != MEM_REF) ++ return false; ++ srtype *base_type = find_type (TREE_TYPE (mem)); + if (base_type != NULL && base_type->has_escaped ()) + return pc_candidate_st_type_p (TREE_TYPE (xhs)); + +@@ -6057,6 +6142,49 @@ ipa_struct_reorg::pc_direct_rewrite_chance_p (tree rhs, tree &new_rhs) + return false; + } + ++/* The following cases can simplify the checking of null pointer: ++ 1. rhs defined from POINTER_PLUS_EXPR. ++ 2. rhs used as COMPONENT_REF in this basic block. */ ++ ++bool ++ipa_struct_reorg::pc_simplify_chance_for_compress_p (gassign *stmt, ++ tree rhs) ++{ ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ gimple *def_stmt = SSA_NAME_DEF_STMT (rhs); ++ ++ if (def_stmt && is_gimple_assign (def_stmt) ++ && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR) ++ return true; ++ ++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, rhs) ++ { ++ gimple *use_stmt = USE_STMT (use_p); ++ if (use_stmt->bb != stmt->bb || !is_gimple_assign (use_stmt)) ++ continue; ++ ++ tree use_rhs = gimple_assign_rhs1 (use_stmt); ++ if (TREE_CODE (use_rhs) == COMPONENT_REF ++ && TREE_OPERAND (TREE_OPERAND (use_rhs, 0), 0) == rhs) ++ return true; ++ } ++ return false; ++} ++ ++/* Perform compression directly without checking null pointer. */ ++ ++bool ++ipa_struct_reorg::compress_candidate_without_check (gimple_stmt_iterator *gsi, ++ tree rhs, ++ tree &new_rhs) ++{ ++ srtype *type = get_compression_candidate_type (rhs); ++ gcc_assert (type != NULL); ++ new_rhs = compress_ptr_to_offset (new_rhs, type, gsi); ++ return true; ++} ++ + /* Perform pointer compression with check. The conversion will be as shown in + the following example: + Orig bb: +@@ -6157,6 +6285,9 @@ ipa_struct_reorg::compress_candidate (gassign *stmt, gimple_stmt_iterator *gsi, + { + if (pc_direct_rewrite_chance_p (rhs, new_rhs)) + return true; ++ else if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE ++ && pc_simplify_chance_for_compress_p (stmt, rhs)) ++ return compress_candidate_without_check (gsi, rhs, new_rhs); + + return compress_candidate_with_check (gsi, rhs, new_rhs); + } +@@ -6219,6 +6350,80 @@ ipa_struct_reorg::create_bb_for_decompress_candidate (basic_block last_bb, + return new_bb; + } + ++/* Try decompress candidate without check. */ ++ ++bool ++ipa_struct_reorg::decompress_candidate_without_check (gimple_stmt_iterator *gsi, ++ tree lhs, tree rhs, ++ tree &new_lhs, ++ tree &new_rhs) ++{ ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ bool processed = false; ++ ++ if (!gsi_one_before_end_p (*gsi)) ++ { ++ gsi_next (gsi); ++ gimple *next_stmt = gsi_stmt (*gsi); ++ if (gimple_code (next_stmt) == GIMPLE_ASSIGN ++ && gimple_assign_rhs_class (next_stmt) == GIMPLE_SINGLE_RHS) ++ { ++ tree next_rhs = gimple_assign_rhs1 (next_stmt); ++ /* If current lhs is used as rhs in the next stmt: ++ -> _1 = t->s ++ tt->s = _1. */ ++ if (lhs == next_rhs) ++ { ++ /* Check whether: ++ 1. the lhs is only used in the next stmt. ++ 2. the next lhs is candidate type. */ ++ if (has_single_use (lhs) ++ && pc_candidate_tree_p (gimple_assign_lhs (next_stmt))) ++ { ++ processed = true; ++ /* Copy directly without conversion after update type. */ ++ TREE_TYPE (new_lhs) ++ = make_unsigned_type (compressed_size); ++ } ++ } ++ /* -> _1 = t->s ++ _2 = _1->s ++ In this case, _1 might not be nullptr, so decompress it without ++ check. */ ++ else if (TREE_CODE (next_rhs) == COMPONENT_REF) ++ { ++ tree use_base = TREE_OPERAND (TREE_OPERAND (next_rhs, 0), 0); ++ if (use_base == lhs) ++ { ++ srtype *type = get_compression_candidate_type (rhs); ++ gcc_assert (type != NULL); ++ gsi_prev (gsi); ++ tree new_ref = NULL_TREE; ++ if (TREE_CODE (new_rhs) == MEM_REF) ++ new_ref = new_rhs; ++ else ++ { ++ tree base = TREE_OPERAND (TREE_OPERAND (new_rhs, 0), 0); ++ tree new_mem_ref = build_simple_mem_ref (base); ++ new_ref = build3 (COMPONENT_REF, ++ TREE_TYPE (new_rhs), ++ new_mem_ref, ++ TREE_OPERAND (new_rhs, 1), ++ NULL_TREE); ++ } ++ new_rhs = decompress_offset_to_ptr (new_ref, type, gsi); ++ processed = true; ++ gsi_next (gsi); ++ } ++ } ++ } ++ gsi_prev (gsi); ++ return processed; ++ } ++ return false; ++} ++ + /* Perform pointer decompression with check. The conversion will be as shown + in the following example: + Orig bb: +@@ -6320,7 +6525,10 @@ ipa_struct_reorg::decompress_candidate (gimple_stmt_iterator *gsi, + tree lhs, tree rhs, tree &new_lhs, + tree &new_rhs) + { +- // TODO: simplifiy check and rewrite will be pushed in next PR. ++ if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE ++ && decompress_candidate_without_check (gsi, lhs, rhs, new_lhs, new_rhs)) ++ return true; ++ + return decompress_candidate_with_check (gsi, rhs, new_rhs); + } + +@@ -6341,14 +6549,23 @@ ipa_struct_reorg::try_rewrite_with_pointer_compression (gassign *stmt, + if (pc_type_conversion_candidate_p (lhs)) + { + /* Transfer MEM[(struct *)_1].files = _4; +- to MEM[(struct *)_1].files = (struct *)_4; */ +- new_rhs = fold_convert (TREE_TYPE (lhs), tmp_rhs); ++ to _tmp = (struct *)_4; ++ MEM[(struct *)_1].files = _tmp; */ ++ tree tmp_reg = create_tmp_reg (TREE_TYPE (lhs)); ++ tree tmp_rhs_cvt = fold_convert (TREE_TYPE (lhs), tmp_rhs); ++ gimple *copy_stmt = gimple_build_assign (tmp_reg, tmp_rhs_cvt); ++ gsi_insert_before (gsi, copy_stmt, GSI_SAME_STMT); ++ new_rhs = tmp_reg; + } + else if (pc_type_conversion_candidate_p (rhs)) + { + /* Transfer _4 = MEM[(struct *)_1].nodes; +- to _4 = (new_struct *) MEM[(struct *)_1].nodes; */ +- new_rhs = fold_convert (TREE_TYPE (new_lhs), tmp_rhs); ++ to _tmp = MEM[(struct *)_1].nodes; ++ _4 = (new_struct *) _tmp; */ ++ tree tmp_reg = create_tmp_reg (TREE_TYPE (new_lhs)); ++ gimple *copy_stmt = gimple_build_assign (tmp_reg, tmp_rhs); ++ gsi_insert_before (gsi, copy_stmt, GSI_SAME_STMT); ++ new_rhs = fold_convert (TREE_TYPE (new_lhs), tmp_reg); + } + } + else if (l && r) +@@ -6544,7 +6761,7 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "\nrewriting stamtenet:\n"); ++ fprintf (dump_file, "\nrewriting statement:\n"); + print_gimple_stmt (dump_file, stmt, 0); + } + tree newlhs[max_split]; +@@ -6809,7 +7026,8 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + old statement is to be removed. */ + + bool +-ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) ++ipa_struct_reorg::rewrite_cond (gcond *stmt, ++ gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED) + { + tree_code rhs_code = gimple_cond_code (stmt); + +@@ -7039,8 +7257,11 @@ ipa_struct_reorg::rewrite_functions (void) + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nNo rewrite:\n"); +- dump_function_to_file (current_function_decl, dump_file, +- dump_flags | TDF_VOPS); ++ if (current_function_decl) ++ dump_function_to_file (current_function_decl, dump_file, ++ dump_flags | TDF_VOPS); ++ else ++ fprintf (dump_file, " no declaration\n"); + } + pop_cfun (); + } +@@ -7073,11 +7294,13 @@ ipa_struct_reorg::rewrite_functions (void) + push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "==== Before create decls: %dth_%s ====\n\n", ++ fprintf (dump_file, "==== Before create decls: %dth %s ====\n\n", + i, f->node->name ()); + if (current_function_decl) + dump_function_to_file (current_function_decl, dump_file, + dump_flags | TDF_VOPS); ++ else ++ fprintf (dump_file, " no declaration\n"); + } + pop_cfun (); + } +@@ -7109,10 +7332,13 @@ ipa_struct_reorg::rewrite_functions (void) + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "\nBefore rewrite: %dth_%s\n", ++ fprintf (dump_file, "\nBefore rewrite: %dth %s\n", + i, f->node->name ()); +- dump_function_to_file (current_function_decl, dump_file, +- dump_flags | TDF_VOPS); ++ if (current_function_decl) ++ dump_function_to_file (current_function_decl, dump_file, ++ dump_flags | TDF_VOPS); ++ else ++ fprintf (dump_file, " no declaration\n"); + fprintf (dump_file, "\n======== Start to rewrite: %dth_%s ========\n", + i, f->node->name ()); + } +@@ -7187,10 +7413,13 @@ ipa_struct_reorg::rewrite_functions (void) + + if (dump_file) + { +- fprintf (dump_file, "\nAfter rewrite: %dth_%s\n", ++ fprintf (dump_file, "\nAfter rewrite: %dth %s\n", + i, f->node->name ()); +- dump_function_to_file (current_function_decl, dump_file, +- dump_flags | TDF_VOPS); ++ if (current_function_decl) ++ dump_function_to_file (current_function_decl, dump_file, ++ dump_flags | TDF_VOPS); ++ else ++ fprintf (dump_file, " no declaration\n"); + } + + pop_cfun (); +@@ -7309,18 +7538,24 @@ ipa_struct_reorg::check_and_prune_struct_for_pointer_compression (void) + " skip compression.\n"); + continue; + } +- if ((current_layout_opt_level & POINTER_COMPRESSION_SAFE) +- && !type->has_legal_alloc_num) ++ if (!type->has_legal_alloc_num) + { +- if (dump_file) +- fprintf (dump_file, " has illegal struct array size," +- " skip compression.\n"); +- continue; ++ if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE) ++ if (dump_file) ++ fprintf (dump_file, " has unknown alloc size, but" ++ " in unsafe mode, so"); ++ else ++ { ++ if (dump_file) ++ fprintf (dump_file, " has illegal struct array size," ++ " skip compression.\n"); ++ continue; ++ } + } + pc_transform_num++; + type->pc_candidate = true; + if (dump_file) +- fprintf (dump_file, " attemps to do pointer compression.\n"); ++ fprintf (dump_file, " attempts to do pointer compression.\n"); + } + + if (dump_file) +@@ -7342,14 +7577,10 @@ init_pointer_size_for_pointer_compression (void) + switch (param_pointer_compression_size) + { + case 8: +- compressed_size = 8; // sizeof (uint8) +- break; ++ // FALLTHRU + case 16: +- compressed_size = 16; // sizeof (uint16) +- break; +- case 32: +- compressed_size = 32; // sizeof (uint32) +- break; ++ // FALLTHRU ++ case 32: compressed_size = param_pointer_compression_size; break; + default: + error ("Invalid pointer compression size, using the following param: " + "\"--param compressed-pointer-size=[8,16,32]\""); +@@ -7426,6 +7657,8 @@ public: + unsigned int level = 0; + switch (struct_layout_optimize_level) + { ++ case 5: level |= POINTER_COMPRESSION_UNSAFE; ++ // FALLTHRU + case 4: level |= POINTER_COMPRESSION_SAFE; + // FALLTHRU + case 3: level |= DEAD_FIELD_ELIMINATION; +diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h +index 3fe64047c..4f896f4e4 100644 +--- a/gcc/symbol-summary.h ++++ b/gcc/symbol-summary.h +@@ -103,16 +103,15 @@ protected: + /* Allocates new data that are stored within map. */ + T* allocate_new () + { +- /* In structure optimizatons, we call new to ensure that +- the allocated memory is initialized to 0. */ +- if (flag_ipa_struct_reorg) +- return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () +- : new T (); +- + /* Call gcc_internal_because we do not want to call finalizer for + a type T. We call dtor explicitly. */ +- return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () +- : m_allocator.allocate () ; ++ T* allocated = is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () ++ : m_allocator.allocate (); ++ /* In structure optimizatons, we call memset to ensure that ++ the allocated memory is initialized to 0. */ ++ if (flag_ipa_struct_reorg) ++ memset (allocated, 0, sizeof (T)); ++ return allocated; + } + + /* Release an item that is stored within map. */ +@@ -121,12 +120,7 @@ protected: + if (is_ggc ()) + ggc_delete (item); + else +- { +- if (flag_ipa_struct_reorg) +- delete item; +- else +- m_allocator.remove (item); +- } ++ m_allocator.remove (item); + } + + /* Unregister all call-graph hooks. */ +diff --git a/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c b/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c +new file mode 100644 +index 000000000..c5e4968d9 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c +@@ -0,0 +1,53 @@ ++// Structures without names should not be optimized ++/* { dg-do compile } */ ++#include <stdlib.h> ++#include <math.h> ++ ++typedef struct ++{ ++ int a; ++ float b; ++ double s1; ++ double s2; ++ double s3; ++ double s4; ++ double s5; ++ double s6; ++ double s7; ++ double s8; ++} str_t1; ++ ++#define N 1000 ++ ++int num; ++ ++int ++main () ++{ ++ int i, r; ++ ++ r = rand (); ++ num = r > N ? N : r; ++ str_t1 *p1 = calloc (num, sizeof (str_t1)); ++ ++ if (p1 == NULL) ++ return 0; ++ ++ for (i = 0; i < num; i++) ++ p1[i].a = 1; ++ ++ for (i = 0; i < num; i++) ++ p1[i].b = 2; ++ ++ for (i = 0; i < num; i++) ++ if (p1[i].a != 1) ++ abort (); ++ ++ for (i = 0; i < num; i++) ++ if (fabsf (p1[i].b - 2) > 0.0001) ++ abort (); ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform in Complete Structure Relayout." "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/pc_cast_int.c b/gcc/testsuite/gcc.dg/struct/pc_cast_int.c +new file mode 100644 +index 000000000..6f67fc556 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/pc_cast_int.c +@@ -0,0 +1,91 @@ ++// Escape cast int for pointer compression ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++ network_t* net_add; ++}; ++ ++ ++const int MAX = 100; ++network_t* net; ++node_p node; ++ ++int ++main () ++{ ++ net = (network_t*) calloc (1, sizeof(network_t)); ++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->nodes = (node_p) calloc (MAX, sizeof (node_t)); ++ net->arcs->id = 100; ++ ++ node = net->nodes; ++ node_p n1 = (node_p) 0x123456; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ node->pred = n1; ++ node = node + 1; ++ } ++ ++ node = net->nodes; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ if (node->pred != n1) ++ { ++ abort (); ++ } ++ node = node + 1; ++ } ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform in pointer compression" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c b/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c +new file mode 100644 +index 000000000..d0b8d1afa +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c +@@ -0,0 +1,90 @@ ++// Support basic pointer compression and decompression ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++ network_t* net_add; ++}; ++ ++ ++const int MAX = 100; ++network_t* net; ++node_p node; ++ ++int ++main () ++{ ++ net = (network_t*) calloc (1, sizeof(network_t)); ++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->nodes = (node_p) calloc (MAX, sizeof (node_t)); ++ net->arcs->id = 100; ++ ++ node = net->nodes; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ node->pred = node; ++ node = node + 1; ++ } ++ ++ node = net->nodes; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ if (node->pred != node) ++ { ++ abort (); ++ } ++ node = node + 1; ++ } ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c b/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c +new file mode 100644 +index 000000000..5022c1967 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c +@@ -0,0 +1,87 @@ ++// Partially support escape_cast_void for pointer compression. ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs, sorted_arcs; ++ int x; ++ node_p nodes, stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++const int MAX = 100; ++network_t* net = NULL; ++int cnt = 0; ++ ++__attribute__((noinline)) int ++primal_feasible (network_t *net) ++{ ++ void* stop; ++ node_t *node; ++ ++ node = net->nodes; ++ stop = (void *)net->stop_nodes; ++ for( node++; node < (node_t *)stop; node++ ) ++ { ++ net->x = 1; ++ printf( "PRIMAL NETWORK SIMPLEX: "); ++ } ++ return 0; ++} ++ ++int ++main () ++{ ++ net = (network_t*) calloc (1, 20); ++ net->nodes = calloc (MAX, sizeof (node_t)); ++ net->stop_nodes = net->nodes + MAX - 1; ++ cnt = primal_feasible( net ); ++ ++ net = (network_t*) calloc (1, 20); ++ if( !(net->arcs) ) ++ { ++ return -1; ++ } ++ return cnt; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c b/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c +new file mode 100644 +index 000000000..98943c9b8 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c +@@ -0,0 +1,112 @@ ++// Check simplify rewrite chance for pointer compression and decompression ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++ network_t* net_add; ++}; ++ ++ ++const int MAX = 100; ++network_t* net; ++node_p node; ++arc_p arc; ++ ++int ++main () ++{ ++ net = (network_t*) calloc (1, sizeof(network_t)); ++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->nodes = (node_p) calloc (MAX, sizeof (node_t)); ++ net->arcs->id = 100; ++ ++ node = net->nodes; ++ arc = net->arcs; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ arc->head = node; ++ arc->head->child = node; ++ node->potential = i + 1; ++ arc->cost = arc->head->potential; ++ arc->tail = node->sibling; ++ if (i % 2) ++ node->pred = net->nodes + i; ++ else ++ node->pred = NULL; ++ ++ if (node->pred && node->pred->child != NULL) ++ node->number = 0; ++ else ++ node->number = 1; ++ ++ node = node + 1; ++ arc = arc + 1; ++ } ++ ++ node = net->nodes; ++ arc = net->arcs; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ node_p t = i % 2 ? node : NULL; ++ int tt = i % 2 ? 0 : 1; ++ if (arc->head->pred != t || arc->cost == 0 ++ || arc->tail != node->sibling || node->number != tt) ++ { ++ abort (); ++ } ++ arc = arc + 1; ++ node = node + 1; ++ } ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c b/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c +new file mode 100644 +index 000000000..a0e191267 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c +@@ -0,0 +1,53 @@ ++// Structures without names should not be optimized ++/* { dg-do compile } */ ++#include <stdlib.h> ++#include <math.h> ++ ++typedef struct ++{ ++ int a; ++ float b; ++ double s1; ++ double s2; ++ double s3; ++ double s4; ++ double s5; ++ double s6; ++ double s7; ++ double s8; ++} str_t1; ++ ++#define N 1000 ++ ++int num; ++ ++int ++main () ++{ ++ int i, r; ++ ++ r = rand (); ++ num = r > N ? N : r; ++ str_t1 *p1 = calloc (num, sizeof (str_t1)); ++ ++ if (p1 == NULL) ++ return 0; ++ ++ for (i = 0; i < num; i++) ++ p1[i].a = 1; ++ ++ for (i = 0; i < num; i++) ++ p1[i].b = 2; ++ ++ for (i = 0; i < num; i++) ++ if (p1[i].a != 1) ++ abort (); ++ ++ for (i = 0; i < num; i++) ++ if (fabsf (p1[i].b - 2) > 0.0001) ++ abort (); ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform in pointer compression" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +index 278c4e4f5..c40474407 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp ++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +@@ -47,6 +47,14 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf_*.c]] \ + gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/dfe*.c]] \ + "" "-fipa-struct-reorg=3 -fdump-ipa-all -flto-partition=one -fwhole-program" + ++# -fipa-struct-reorg=4 ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \ ++ "" "-fipa-struct-reorg=4 -fdump-ipa-all -flto-partition=one -fwhole-program" ++ ++# -fipa-struct-reorg=5 ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \ ++ "" "-fipa-struct-reorg=5 -fdump-ipa-all -flto-partition=one -fwhole-program" ++ + # All done. + torture-finish + dg-finish +-- +2.33.0 + |