1 Star 0 Fork 33

baozhaoling/gcc

forked from src-anolis-os/gcc 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
HYGON-0004-function-attribute-judgement.patch 14.92 KB
一键复制 编辑 原始数据 按行查看 历史
baozhaoling 提交于 2024-04-08 11:43 . Add Hygon's supported patches
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
From e3084877691d6be4e337f51fd9c214c9baa9bac1 Mon Sep 17 00:00:00 2001
From: Monama <13440944+monama@user.noreply.gitee.com>
Date: Tue, 21 Nov 2023 02:35:20 +0000
Subject: [PATCH] !7 Add function attribute judgement for INLINE_HINT_kown_hot
hint & loop-elim. * Introduce redundant loop elimination optimization
controlled * Add function attribute judgement for INLINE_HINT_known_hot hint,
---
gcc/common.opt | 4 +
gcc/ipa-inline-analysis.cc | 13 +-
gcc/testsuite/gcc.dg/ipa/inlinehint-6.c | 47 +++
gcc/tree-ssa-phiopt.cc | 448 ++++++++++++++++++++++++
4 files changed, 508 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/ipa/inlinehint-6.c
diff --git a/gcc/common.opt b/gcc/common.opt
index e51fb27c5e3..6343fad3335 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1240,6 +1240,10 @@ fcompare-elim
Common Var(flag_compare_elim_after_reload) Optimization
Perform comparison elimination after register allocation has finished.
+floop-elim
+Common Var(flag_loop_elim) Init(0) Optimization
+Perform redundant loop elimination.
+
fconserve-stack
Common Var(flag_conserve_stack) Optimization
Do not perform optimizations increasing noticeably stack usage.
diff --git a/gcc/ipa-inline-analysis.cc b/gcc/ipa-inline-analysis.cc
index 11d8d09ee43..16ac24cfc6a 100644
--- a/gcc/ipa-inline-analysis.cc
+++ b/gcc/ipa-inline-analysis.cc
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-utils.h"
#include "cfgexpand.h"
#include "gimplify.h"
+#include "attribs.h"
/* Cached node/edge growths. */
fast_call_summary<edge_growth_cache_entry *, va_heap> *edge_growth_cache = NULL;
@@ -249,15 +250,19 @@ do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time)
hints = estimates.hints;
}
- /* When we have profile feedback, we can quite safely identify hot
- edges and for those we disable size limits. Don't do that when
- probability that caller will call the callee is low however, since it
+ /* When we have profile feedback or function attribute, we can quite safely
+ identify hot edges and for those we disable size limits. Don't do that
+ when probability that caller will call the callee is low however, since it
may hurt optimization of the caller's hot path. */
- if (edge->count.ipa ().initialized_p () && edge->maybe_hot_p ()
+ if ((edge->count.ipa ().initialized_p () && edge->maybe_hot_p ()
&& (edge->count.ipa ().apply_scale (2, 1)
> (edge->caller->inlined_to
? edge->caller->inlined_to->count.ipa ()
: edge->caller->count.ipa ())))
+ || (lookup_attribute ("hot", DECL_ATTRIBUTES (edge->caller->decl))
+ != NULL
+ && lookup_attribute ("hot", DECL_ATTRIBUTES (edge->callee->decl))
+ != NULL))
hints |= INLINE_HINT_known_hot;
gcc_checking_assert (size >= 0);
diff --git a/gcc/testsuite/gcc.dg/ipa/inlinehint-6.c b/gcc/testsuite/gcc.dg/ipa/inlinehint-6.c
new file mode 100644
index 00000000000..1f3be641c6d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/inlinehint-6.c
@@ -0,0 +1,47 @@
+/* { dg-options "-O3 -c -fdump-ipa-inline-details -fno-early-inlining -fno-ipa-cp" } */
+/* { dg-add-options bind_pic_locally } */
+
+#define size_t long long int
+
+struct A
+{
+ size_t f1, f2, f3, f4;
+};
+struct C
+{
+ struct A a;
+ size_t b;
+};
+struct C x;
+
+__attribute__((hot)) struct C callee (struct A *a, struct C *c)
+{
+ c->a=(*a);
+
+ if((c->b + 7) & 17)
+ {
+ c->a.f1 = c->a.f2 + c->a.f1;
+ c->a.f2 = c->a.f3 - c->a.f2;
+ c->a.f3 = c->a.f2 + c->a.f3;
+ c->a.f4 = c->a.f2 - c->a.f4;
+ c->b = c->a.f2;
+
+ }
+ return *c;
+}
+
+__attribute__((hot)) struct C caller (size_t d, size_t e, size_t f, size_t g, struct C *c)
+{
+ struct A a;
+ a.f1 = 1 + d;
+ a.f2 = e;
+ a.f3 = 12 + f;
+ a.f4 = 68 + g;
+ if (c->b > 0)
+ return callee (&a, c);
+ else
+ return *c;
+}
+
+/* { dg-final { scan-ipa-dump "known_hot" "inline" } } */
+
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index c56d0b9ff15..cf300d14121 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -77,6 +77,7 @@ static hash_set<tree> * get_non_trapping ();
static void replace_phi_edge_with_variable (basic_block, edge, gphi *, tree);
static void hoist_adjacent_loads (basic_block, basic_block,
basic_block, basic_block);
+static bool do_phiopt_pattern (basic_block, basic_block, basic_block);
static bool gate_hoist_loads (void);
/* This pass tries to transform conditional stores into unconditional
@@ -266,6 +267,10 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p)
hoist_adjacent_loads (bb, bb1, bb2, bb3);
continue;
}
+ else if (flag_loop_elim && do_phiopt_pattern (bb, bb1, bb2))
+ {
+ continue;
+ }
else
continue;
@@ -3767,6 +3772,449 @@ hoist_adjacent_loads (basic_block bb0, basic_block bb1,
}
}
+static bool check_uses (tree, hash_set<tree> *);
+
+/* Check SSA_NAME is used in
+ if (SSA_NAME == 0)
+ ...
+ or
+ if (SSA_NAME != 0)
+ ...
+*/
+static bool
+check_uses_cond (const_tree ssa_name, gimple *stmt,
+ hash_set<tree> *hset ATTRIBUTE_UNUSED)
+{
+ tree_code code = gimple_cond_code (stmt);
+ if (code != EQ_EXPR && code != NE_EXPR)
+ {
+ return false;
+ }
+
+ tree lhs = gimple_cond_lhs (stmt);
+ tree rhs = gimple_cond_rhs (stmt);
+ if ((lhs == ssa_name && integer_zerop (rhs))
+ || (rhs == ssa_name && integer_zerop (lhs)))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/* Check SSA_NAME is used in
+ _tmp = SSA_NAME == 0;
+ or
+ _tmp = SSA_NAME != 0;
+ or
+ _tmp = SSA_NAME | _tmp2;
+*/
+static bool
+check_uses_assign (const_tree ssa_name, gimple *stmt, hash_set<tree> *hset)
+{
+ tree_code code = gimple_assign_rhs_code (stmt);
+ tree lhs, rhs1, rhs2;
+
+ switch (code)
+ {
+ case EQ_EXPR:
+ case NE_EXPR:
+ rhs1 = gimple_assign_rhs1 (stmt);
+ rhs2 = gimple_assign_rhs2 (stmt);
+ if ((rhs1 == ssa_name && integer_zerop (rhs2))
+ || (rhs2 == ssa_name && integer_zerop (rhs1)))
+ {
+ return true;
+ }
+ break;
+
+ case BIT_IOR_EXPR:
+ lhs = gimple_assign_lhs (stmt);
+ if (hset->contains (lhs))
+ {
+ return false;
+ }
+ /* We should check the use of _tmp further. */
+ return check_uses (lhs, hset);
+
+ default:
+ break;
+ }
+ return false;
+}
+
+/* Check SSA_NAME is used in
+ # result = PHI <SSA_NAME (bb1), 0 (bb2), 0 (bb3)>
+*/
+static bool
+check_uses_phi (const_tree ssa_name, gimple *stmt, hash_set<tree> *hset)
+{
+ for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++)
+ {
+ tree arg = gimple_phi_arg_def (stmt, i);
+ if (!integer_zerop (arg) && arg != ssa_name)
+ {
+ return false;
+ }
+ }
+
+ tree result = gimple_phi_result (stmt);
+
+ /* It is used to avoid infinite recursion,
+ <bb 1>
+ if (cond)
+ goto <bb 2>
+ else
+ goto <bb 3>
+
+ <bb 2>
+ # _tmp2 = PHI <0 (bb 1), _tmp3 (bb 3)>
+ {BODY}
+ if (cond)
+ goto <bb 3>
+ else
+ goto <bb 4>
+
+ <bb 3>
+ # _tmp3 = PHI <0 (bb 1), _tmp2 (bb 2)>
+ {BODY}
+ if (cond)
+ goto <bb 2>
+ else
+ goto <bb 4>
+
+ <bb 4>
+ ...
+ */
+ if (hset->contains (result))
+ {
+ return false;
+ }
+
+ return check_uses (result, hset);
+}
+
+/* Check the use of SSA_NAME, it should only be used in comparison
+ operation and PHI node. HSET is used to record the ssa_names
+ that have been already checked. */
+static bool
+check_uses (tree ssa_name, hash_set<tree> *hset)
+{
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+
+ if (TREE_CODE (ssa_name) != SSA_NAME)
+ {
+ return false;
+ }
+
+ if (SSA_NAME_VAR (ssa_name)
+ && is_global_var (SSA_NAME_VAR (ssa_name)))
+ {
+ return false;
+ }
+
+ hset->add (ssa_name);
+
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, ssa_name)
+ {
+ gimple *stmt = USE_STMT (use_p);
+
+ /* Ignore debug gimple statements. */
+ if (is_gimple_debug (stmt))
+ {
+ continue;
+ }
+
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_COND:
+ if (!check_uses_cond (ssa_name, stmt, hset))
+ {
+ return false;
+ }
+ break;
+
+ case GIMPLE_ASSIGN:
+ if (!check_uses_assign (ssa_name, stmt, hset))
+ {
+ return false;
+ }
+ break;
+
+ case GIMPLE_PHI:
+ if (!check_uses_phi (ssa_name, stmt, hset))
+ {
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool
+check_def_gimple (gimple *def1, gimple *def2, const_tree result)
+{
+ /* def1 and def2 should be POINTER_PLUS_EXPR. */
+ if (!is_gimple_assign (def1) || !is_gimple_assign (def2)
+ || gimple_assign_rhs_code (def1) != POINTER_PLUS_EXPR
+ || gimple_assign_rhs_code (def2) != POINTER_PLUS_EXPR)
+ {
+ return false;
+ }
+
+ tree rhs12 = gimple_assign_rhs2 (def1);
+
+ tree rhs21 = gimple_assign_rhs1 (def2);
+ tree rhs22 = gimple_assign_rhs2 (def2);
+
+ if (rhs21 != result)
+ {
+ return false;
+ }
+
+ /* We should have a positive pointer-plus constant to ensure
+ that the pointer value is continuously increasing. */
+ if (TREE_CODE (rhs12) != INTEGER_CST || TREE_CODE (rhs22) != INTEGER_CST
+ || compare_tree_int (rhs12, 0) <= 0 || compare_tree_int (rhs22, 0) <= 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+check_loop_body (basic_block bb0, basic_block bb2, const_tree result)
+{
+ gimple *g01 = first_stmt (bb0);
+ if (!g01 || !is_gimple_assign (g01)
+ || gimple_assign_rhs_code (g01) != MEM_REF
+ || TREE_OPERAND (gimple_assign_rhs1 (g01), 0) != result)
+ {
+ return false;
+ }
+
+ gimple *g02 = g01->next;
+ /* GIMPLE_COND would be the last gimple in a basic block,
+ and have no other side effects on RESULT. */
+ if (!g02 || gimple_code (g02) != GIMPLE_COND)
+ {
+ return false;
+ }
+
+ if (first_stmt (bb2) != last_stmt (bb2))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+/* Pattern is like
+ <pre bb>
+ arg1 = base (rhs11) + cst (rhs12); [def1]
+ goto <bb 0>
+
+ <bb 2>
+ arg2 = result (rhs21) + cst (rhs22); [def2]
+
+ <bb 0>
+ # result = PHI <arg1 (pre bb), arg2 (bb 2)>
+ _v = *result; [g01]
+ if (_v == 0) [g02]
+ goto <bb 1>
+ else
+ goto <bb 2>
+
+ <bb 1>
+ _1 = result - base; [g1]
+ _2 = _1 /[ex] cst; [g2]
+ _3 = (unsigned int) _2; [g3]
+ if (_3 == 0)
+ ...
+*/
+static bool
+check_bb_order (basic_block bb0, basic_block &bb1, basic_block &bb2,
+ gphi *phi_stmt, gimple *&output)
+{
+ /* Start check from PHI node in BB0. */
+ if (gimple_phi_num_args (phi_stmt) != 2
+ || virtual_operand_p (gimple_phi_result (phi_stmt)))
+ {
+ return false;
+ }
+
+ tree result = gimple_phi_result (phi_stmt);
+ tree arg1 = gimple_phi_arg_def (phi_stmt, 0);
+ tree arg2 = gimple_phi_arg_def (phi_stmt, 1);
+
+ if (TREE_CODE (arg1) != SSA_NAME
+ || TREE_CODE (arg2) != SSA_NAME
+ || SSA_NAME_IS_DEFAULT_DEF (arg1)
+ || SSA_NAME_IS_DEFAULT_DEF (arg2))
+ {
+ return false;
+ }
+
+ gimple *def1 = SSA_NAME_DEF_STMT (arg1);
+ gimple *def2 = SSA_NAME_DEF_STMT (arg2);
+
+ /* Swap bb1 and bb2 if pattern is like
+ if (_v != 0)
+ goto <bb 2>
+ else
+ goto <bb 1>
+ */
+ if (gimple_bb (def2) == bb1 && EDGE_SUCC (bb1, 0)->dest == bb0)
+ {
+ std::swap (bb1, bb2);
+ }
+
+ /* prebb[def1] --> bb0 <-- bb2[def2] */
+ if (!gimple_bb (def1)
+ || EDGE_SUCC (gimple_bb (def1), 0)->dest != bb0
+ || gimple_bb (def2) != bb2 || EDGE_SUCC (bb2, 0)->dest != bb0)
+ {
+ return false;
+ }
+
+ /* Check whether define gimple meets the pattern requirements. */
+ if (!check_def_gimple (def1, def2, result))
+ {
+ return false;
+ }
+
+ if (!check_loop_body (bb0, bb2, result))
+ {
+ return false;
+ }
+
+ output = def1;
+ return true;
+}
+
+/* Check pattern
+ <bb 1>
+ _1 = result - base; [g1]
+ _2 = _1 /[ex] cst; [g2]
+ _3 = (unsigned int) _2; [g3]
+ if (_3 == 0)
+ ...
+*/
+static bool
+check_gimple_order (basic_block bb1, const_tree base, const_tree cst,
+ const_tree result, gimple *&output)
+{
+ gimple *g1 = first_stmt (bb1);
+ if (!g1 || !is_gimple_assign (g1)
+ || gimple_assign_rhs_code (g1) != POINTER_DIFF_EXPR
+ || gimple_assign_rhs1 (g1) != result
+ || gimple_assign_rhs2 (g1) != base)
+ {
+ return false;
+ }
+
+ gimple *g2 = g1->next;
+ if (!g2 || !is_gimple_assign (g2)
+ || gimple_assign_rhs_code (g2) != EXACT_DIV_EXPR
+ || gimple_assign_lhs (g1) != gimple_assign_rhs1 (g2)
+ || TREE_CODE (gimple_assign_rhs2 (g2)) != INTEGER_CST)
+ {
+ return false;
+ }
+
+ /* INTEGER_CST cst in gimple def1. */
+ HOST_WIDE_INT num1 = TREE_INT_CST_LOW (cst);
+ /* INTEGER_CST cst in gimple g2. */
+ HOST_WIDE_INT num2 = TREE_INT_CST_LOW (gimple_assign_rhs2 (g2));
+ /* _2 must be at least a positive number. */
+ if (num2 == 0 || num1 / num2 <= 0)
+ {
+ return false;
+ }
+
+ gimple *g3 = g2->next;
+ if (!g3 || !is_gimple_assign (g3)
+ || gimple_assign_rhs_code (g3) != NOP_EXPR
+ || gimple_assign_lhs (g2) != gimple_assign_rhs1 (g3)
+ || TREE_CODE (gimple_assign_lhs (g3)) != SSA_NAME)
+ {
+ return false;
+ }
+
+ /* _3 should only be used in comparison operation or PHI node. */
+ hash_set<tree> *hset = new hash_set<tree>;
+ if (!check_uses (gimple_assign_lhs (g3), hset))
+ {
+ delete hset;
+ return false;
+ }
+ delete hset;
+
+ output = g3;
+ return true;
+}
+
+static bool
+do_phiopt_pattern (basic_block bb0, basic_block bb1, basic_block bb2)
+{
+ gphi_iterator gsi;
+
+ for (gsi = gsi_start_phis (bb0); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gphi *phi_stmt = gsi.phi ();
+ gimple *def1 = NULL;
+ tree base, cst, result;
+
+ if (!check_bb_order (bb0, bb1, bb2, phi_stmt, def1))
+ {
+ continue;
+ }
+
+ base = gimple_assign_rhs1 (def1);
+ cst = gimple_assign_rhs2 (def1);
+ result = gimple_phi_result (phi_stmt);
+
+ gimple *stmt = NULL;
+ if (!check_gimple_order (bb1, base, cst, result, stmt))
+ {
+ continue;
+ }
+
+ gcc_assert (stmt);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "PHIOPT pattern optimization (1) - Rewrite:\n");
+ print_gimple_stmt (dump_file, stmt, 0);
+ fprintf (dump_file, "to\n");
+ }
+
+ /* Rewrite statement
+ _3 = (unsigned int) _2;
+ to
+ _3 = (unsigned int) 1;
+ */
+ tree type = TREE_TYPE (gimple_assign_rhs1 (stmt));
+ gimple_assign_set_rhs1 (stmt, build_int_cst (type, 1));
+ update_stmt (stmt);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ print_gimple_stmt (dump_file, stmt, 0);
+ fprintf (dump_file, "\n");
+ }
+
+ return true;
+ }
+ return false;
+}
+
/* Determine whether we should attempt to hoist adjacent loads out of
diamond patterns in pass_phiopt. Always hoist loads if
-fhoist-adjacent-loads is specified and the target machine has
--
2.22.0
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/baozhaoling/gcc.git
git@gitee.com:baozhaoling/gcc.git
baozhaoling
gcc
gcc
a8

搜索帮助

23e8dbc6 1850385 7e0993f3 1850385