From b135c1526c104f578167b6834f30ecb3186bd808 Mon Sep 17 00:00:00 2001 From: liuf9 Date: Thu, 21 Dec 2023 19:49:07 +0800 Subject: [PATCH] [Sync] Sync patches from openeuler/gcc. --- ...ugfix-Terminate-kernel-filtering-for.patch | 175 ++ 0169-Struct-Reorg-Fix-several-bugs.patch | 183 +++ 0170-DFE-Add-escape-check.patch | 104 ++ ...-Add-ftree-fold-phiopt-option-to-5-t.patch | 80 + ...minmax-Move-minmax-pattern-to-gimple.patch | 323 ++++ 0173-IPA-Fix-test-completion-1.c.patch | 24 + ...-checked-build-and-comments-from-rev.patch | 71 + ...tending-and-refactoring-of-pass_spli.patch | 1426 +++++++++++++++++ ...-ICP-src-openEuler-gcc-I8PYBF-I8PYLL.patch | 61 + gcc.spec | 28 +- 10 files changed, 2473 insertions(+), 2 deletions(-) create mode 100644 0168-LLC-Allocation-Bugfix-Terminate-kernel-filtering-for.patch create mode 100644 0169-Struct-Reorg-Fix-several-bugs.patch create mode 100644 0170-DFE-Add-escape-check.patch create mode 100644 0171-phiopt-testsuite-Add-ftree-fold-phiopt-option-to-5-t.patch create mode 100644 0172-minmax-Move-minmax-pattern-to-gimple.patch create mode 100644 0173-IPA-Fix-test-completion-1.c.patch create mode 100644 0174-IPA-Fix-fails-on-checked-build-and-comments-from-rev.patch create mode 100644 0175-split-ldp-stp-Extending-and-refactoring-of-pass_spli.patch create mode 100644 0176-Fix-bugs-in-ICP-src-openEuler-gcc-I8PYBF-I8PYLL.patch diff --git a/0168-LLC-Allocation-Bugfix-Terminate-kernel-filtering-for.patch b/0168-LLC-Allocation-Bugfix-Terminate-kernel-filtering-for.patch new file mode 100644 index 0000000..e97d345 --- /dev/null +++ b/0168-LLC-Allocation-Bugfix-Terminate-kernel-filtering-for.patch @@ -0,0 +1,175 @@ +From 4369e823f0883c079c0681bef68cead870d02063 Mon Sep 17 00:00:00 2001 +From: Feiyang Liu +Date: Wed, 20 Dec 2023 09:48:02 +0800 +Subject: [PATCH] [LLC Allocation][Bugfix] Terminate kernel filtering for + same-loop cycle. + +--- + .../gcc.dg/llc-allocate/llc-same-loop-cycle.c | 125 ++++++++++++++++++ + gcc/tree-ssa-llc-allocate.c | 11 +- + 2 files changed, 135 insertions(+), 1 deletion(-) + create mode 100644 gcc/testsuite/gcc.dg/llc-allocate/llc-same-loop-cycle.c + +diff --git a/gcc/testsuite/gcc.dg/llc-allocate/llc-same-loop-cycle.c b/gcc/testsuite/gcc.dg/llc-allocate/llc-same-loop-cycle.c +new file mode 100644 +index 000000000..ba5b5b0c8 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/llc-allocate/llc-same-loop-cycle.c +@@ -0,0 +1,125 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-options "-O3 -fwhole-program -flto-partition=one -fllc-allocate -fdump-tree-llc_allocate-details-lineno --param filter-kernels=1 --param=branch-prob-threshold=50 -c -w" } */ ++ ++typedef unsigned long size_t; ++typedef long scalar_t__; ++ ++typedef struct TYPE_13__ TYPE_3__ ; ++typedef struct TYPE_12__ TYPE_2__ ; ++typedef struct TYPE_11__ TYPE_1__ ; ++ ++struct dom_info {int nodes; int* dfs_parent; int* dfs_order; int* key; int* next_bucket; int* bucket; int* dom; int fake_exit_edge; TYPE_3__** dfs_to_bb; } ; ++typedef enum cdi_direction { ____Placeholder_cdi_direction } cdi_direction ; ++struct TYPE_11__ {scalar_t__ index; } ; ++typedef TYPE_1__ edge_iterator ; ++typedef TYPE_2__* edge ; ++typedef TYPE_3__* basic_block ; ++struct TYPE_13__ {size_t index; int preds; int succs; } ; ++struct TYPE_12__ {TYPE_3__* src; TYPE_3__* dest; } ; ++typedef int TBB ; ++ ++basic_block ENTRY_BLOCK_PTR ; ++basic_block EXIT_BLOCK_PTR ; ++scalar_t__ bitmap_bit_p (int,size_t) ; ++edge ei_edge (edge_iterator) ; ++int ei_end_p (edge_iterator) ; ++int ei_next (edge_iterator*) ; ++edge_iterator ei_start (int) ; ++size_t eval (struct dom_info*,int) ; ++size_t last_basic_block ; ++int link_roots (struct dom_info*,int,int) ; ++ ++__attribute__((used)) static void ++calc_idoms (struct dom_info *di, enum cdi_direction reverse) ++{ ++ TBB v, w, k, par; ++ basic_block en_block; ++ edge_iterator ei, einext; ++ ++ if (reverse) ++ en_block = EXIT_BLOCK_PTR; ++ else ++ en_block = ENTRY_BLOCK_PTR; ++ ++ /* Go backwards in DFS order, to first look at the leafs. */ ++ v = di->nodes; ++ while (v > 1) ++ { ++ basic_block bb = di->dfs_to_bb[v]; ++ edge e; ++ ++ par = di->dfs_parent[v]; ++ k = v; ++ ++ ei = (reverse) ? ei_start (bb->succs) : ei_start (bb->preds); ++ ++ if (reverse) ++ { ++ /* If this block has a fake edge to exit, process that first. */ ++ if (bitmap_bit_p (di->fake_exit_edge, bb->index)) ++ { ++ einext = ei; ++ einext.index = 0; ++ goto do_fake_exit_edge; ++ } ++ } ++ ++ /* Search all direct predecessors for the smallest node with a path ++ to them. That way we have the smallest node with also a path to ++ us only over nodes behind us. In effect we search for our ++ semidominator. */ ++ while (!ei_end_p (ei)) ++ { ++ basic_block b; ++ TBB k1; ++ ++ e = ei_edge (ei); ++ b = (reverse) ? e->dest : e->src; ++ einext = ei; ++ ei_next (&einext); ++ ++ if (b == en_block) ++ { ++ do_fake_exit_edge: ++ k1 = di->dfs_order[last_basic_block]; ++ } ++ else ++ k1 = di->dfs_order[b->index]; ++ ++ /* Call eval() only if really needed. If k1 is above V in DFS tree, ++ then we know, that eval(k1) == k1 and key[k1] == k1. */ ++ if (k1 > v) ++ k1 = di->key[eval (di, k1)]; ++ if (k1 < k) ++ k = k1; ++ ++ ei = einext; ++ } ++ ++ di->key[v] = k; ++ link_roots (di, par, v); ++ di->next_bucket[v] = di->bucket[k]; ++ di->bucket[k] = v; ++ ++ /* Transform semidominators into dominators. */ ++ for (w = di->bucket[par]; w; w = di->next_bucket[w]) ++ { ++ k = eval (di, w); ++ if (di->key[k] < di->key[w]) ++ di->dom[w] = k; ++ else ++ di->dom[w] = par; ++ } ++ /* We don't need to cleanup next_bucket[]. */ ++ di->bucket[par] = 0; ++ v--; ++ } ++ ++ /* Explicitly define the dominators. */ ++ di->dom[1] = 0; ++ for (v = 2; v <= di->nodes; v++) ++ if (di->dom[v] != di->key[v]) ++ di->dom[v] = di->dom[di->dom[v]]; ++} ++ ++/* { dg-final { scan-tree-dump "Find same-loop cycle." "llc_allocate" } } */ +diff --git a/gcc/tree-ssa-llc-allocate.c b/gcc/tree-ssa-llc-allocate.c +index fa8979401..62b5f18ad 100644 +--- a/gcc/tree-ssa-llc-allocate.c ++++ b/gcc/tree-ssa-llc-allocate.c +@@ -1863,6 +1863,7 @@ filter_and_sort_kernels (vector &sorted_kernels, + + set end_bb; + list walked_header_bb; /* Used to record nested loops. */ ++ set walked_non_header_bb_idx; + + for (unsigned i = 0; i < kernels.size (); ++i) + { +@@ -1895,7 +1896,15 @@ filter_and_sort_kernels (vector &sorted_kernels, + /* bb is not the head of the loop, go to the next. */ + if (bb != bb->loop_father->header) + { +- bb = next_high_probability_bb (bb); ++ if (walked_non_header_bb_idx.count (bb->index)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Find same-loop cycle. " ++ "Abort filtering process.\n"); ++ return false; ++ } ++ walked_non_header_bb_idx.insert (bb->index); ++ bb = next_high_probability_bb (bb); + continue; + } + +-- +2.33.0 + diff --git a/0169-Struct-Reorg-Fix-several-bugs.patch b/0169-Struct-Reorg-Fix-several-bugs.patch new file mode 100644 index 0000000..72412e0 --- /dev/null +++ b/0169-Struct-Reorg-Fix-several-bugs.patch @@ -0,0 +1,183 @@ +From 708ffe6f132ee39441b66b6ab6b98847d35916b7 Mon Sep 17 00:00:00 2001 +From: eastb233 +Date: Tue, 19 Dec 2023 17:03:12 +0800 +Subject: [PATCH 1/2] [Struct Reorg] Fix several bugs + +--- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 50 ++++++------------- + gcc/testsuite/gcc.dg/struct/struct_reorg-10.c | 29 +++++++++++ + gcc/testsuite/gcc.dg/struct/struct_reorg-11.c | 16 ++++++ + gcc/testsuite/gcc.dg/struct/struct_reorg-12.c | 26 ++++++++++ + 4 files changed, 85 insertions(+), 36 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/struct/struct_reorg-10.c + create mode 100644 gcc/testsuite/gcc.dg/struct/struct_reorg-11.c + create mode 100644 gcc/testsuite/gcc.dg/struct/struct_reorg-12.c + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 7aba74ff1..0064811ac 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -4105,6 +4105,12 @@ ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt) + maybe_mark_or_record_other_side (rhs, lhs, stmt); + if (TREE_CODE (lhs) == SSA_NAME) + maybe_mark_or_record_other_side (lhs, rhs, stmt); ++ ++ /* Handle missing ARRAY_REF cases. */ ++ if (TREE_CODE (lhs) == ARRAY_REF) ++ mark_type_as_escape (TREE_TYPE (lhs), escape_array, stmt); ++ if (TREE_CODE (rhs) == ARRAY_REF) ++ mark_type_as_escape (TREE_TYPE (rhs), escape_array, stmt); + } + } + +@@ -6169,6 +6175,7 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_ + bool escape_from_base = false; + + tree newbase[max_split]; ++ memset (newbase, 0, sizeof (tree[max_split])); + memset (newexpr, 0, sizeof(tree[max_split])); + + if (TREE_CODE (expr) == CONSTRUCTOR) +@@ -8162,43 +8169,14 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, + should be removed. */ + + bool +-ipa_struct_reorg::rewrite_debug (gimple *stmt, gimple_stmt_iterator *) ++ipa_struct_reorg::rewrite_debug (gimple *, gimple_stmt_iterator *) + { +- if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) +- { +- /* Delete debug gimple now. */ +- return true; +- } +- bool remove = false; +- if (gimple_debug_bind_p (stmt)) +- { +- tree var = gimple_debug_bind_get_var (stmt); +- tree newvar[max_split]; +- if (rewrite_expr (var, newvar, true)) +- remove = true; +- if (gimple_debug_bind_has_value_p (stmt)) +- { +- var = gimple_debug_bind_get_value (stmt); +- if (TREE_CODE (var) == POINTER_PLUS_EXPR) +- var = TREE_OPERAND (var, 0); +- if (rewrite_expr (var, newvar, true)) +- remove = true; +- } +- } +- else if (gimple_debug_source_bind_p (stmt)) +- { +- tree var = gimple_debug_source_bind_get_var (stmt); +- tree newvar[max_split]; +- if (rewrite_expr (var, newvar, true)) +- remove = true; +- var = gimple_debug_source_bind_get_value (stmt); +- if (TREE_CODE (var) == POINTER_PLUS_EXPR) +- var = TREE_OPERAND (var, 0); +- if (rewrite_expr (var, newvar, true)) +- remove = true; +- } +- +- return remove; ++ /* In debug statements, there might be some statements that have ++ been optimized out in gimple but left in debug gimple. Sometimes ++ these statements need to be analyzed to escape, but in rewrite ++ stage it shouldn't happen. It needs to care a lot to handle these ++ cases but seems useless. So now we just delete debug gimple. */ ++ return true; + } + + /* Rewrite PHI nodes, return true if the PHI was replaced. */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-10.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-10.c +new file mode 100644 +index 000000000..ec422f76f +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-10.c +@@ -0,0 +1,29 @@ ++/* { dg-do compile } */ ++/* { dg-options "-w -g -O3 -flto-partition=one -fipa-struct-reorg -fwhole-program -S" } */ ++ ++struct a { ++ int b; ++ char c; ++}; ++struct { ++ double d; ++ _Bool e; ++} * f; ++struct g { ++ struct a h; ++} i; ++long j; ++void k(); ++void l() { k(i); } ++void k(struct a m) { ++ f->e = 0; ++ for (;;) ++ l(); ++} ++int main() { ++ for (; j; f = 0) { ++ struct g *n = 0; ++ char o = n->h.c; ++ } ++ l(); ++} +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-11.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-11.c +new file mode 100644 +index 000000000..3e42aa84a +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-11.c +@@ -0,0 +1,16 @@ ++/* { dg-do compile } */ ++/* { dg-options "-w -g -O3 -flto-partition=one -fipa-struct-reorg -fwhole-program -S" } */ ++ ++struct a { ++ int b; ++ double c; ++}; ++struct d { ++ struct a e; ++}; ++int f; ++int main() { ++ _Bool g; ++ struct d **h = 0; ++ g = *h += f; ++} +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-12.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-12.c +new file mode 100644 +index 000000000..d434f9fe0 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-12.c +@@ -0,0 +1,26 @@ ++/* { dg-do compile } */ ++/* { dg-options "-w -g -O3 -flto-partition=one -fipa-struct-reorg -fwhole-program -S" } */ ++ ++struct foo { ++ long element1; ++ long element2; ++}; ++ ++struct goo { ++ struct foo element_foo; ++}; ++ ++struct goo g1; ++ ++void func () { ++ struct foo (*local)[] = 0; ++ long idx; ++ (g1).element_foo = (*local)[idx]; ++} ++ ++struct foo g2; ++int main () { ++ func (); ++ g2 = g1.element_foo; ++ return 0; ++} +-- +2.33.0 + diff --git a/0170-DFE-Add-escape-check.patch b/0170-DFE-Add-escape-check.patch new file mode 100644 index 0000000..0605fc3 --- /dev/null +++ b/0170-DFE-Add-escape-check.patch @@ -0,0 +1,104 @@ +From e875e4e7f3716aa268ffbbf55ee199ec82b6aeba Mon Sep 17 00:00:00 2001 +From: Mingchuan Wu +Date: Thu, 21 Dec 2023 15:50:34 +0800 +Subject: [PATCH 2/2] [DFE] Add escape check. Fields with escape risks should + not be processed. + +--- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 15 +++++-- + gcc/testsuite/gcc.dg/struct/dfe_escape.c | 50 ++++++++++++++++++++++++ + 2 files changed, 62 insertions(+), 3 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_escape.c + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 0064811ac..dcfa7cd95 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -444,8 +444,13 @@ srtype::has_dead_field (void) + if (!(this_field->field_access & READ_FIELD) + && !FUNCTION_POINTER_TYPE_P (this_field->fieldtype)) + { +- may_dfe = true; +- break; ++ /* Fields with escape risks should not be processed. */ ++ if (this_field->type == NULL ++ || (this_field->type->escapes == does_not_escape)) ++ { ++ may_dfe = true; ++ break; ++ } + } + } + return may_dfe; +@@ -1030,7 +1035,11 @@ srtype::create_new_type (void) + if (current_layout_opt_level & DEAD_FIELD_ELIMINATION + && !(f->field_access & READ_FIELD) + && !FUNCTION_POINTER_TYPE_P (f->fieldtype)) +- continue; ++ { ++ /* Fields with escape risks should not be processed. */ ++ if (f->type == NULL || (f->type->escapes == does_not_escape)) ++ continue; ++ } + f->create_new_fields (newtype, newfields, newlast); + } + +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_escape.c b/gcc/testsuite/gcc.dg/struct/dfe_escape.c +new file mode 100644 +index 000000000..1b143cd26 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_escape.c +@@ -0,0 +1,50 @@ ++/* { dg-do compile } */ ++ ++#include ++#include ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ int x; ++} network_t; ++ ++struct arc ++{ ++ int flow; ++ network_t* net_add; ++}; ++ ++const int MAX = 100; ++ ++/* let it escape_array, "Type is used in an array [not handled yet]". */ ++network_t* net[2]; ++arc_p stop_arcs = NULL; ++ ++int ++main () ++{ ++ net[0] = (network_t*) calloc (1, sizeof(network_t)); ++ stop_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ ++ net[0]->x = 100; ++ ++ for (unsigned i = 0; i < 3; i++) ++ { ++ net[0]->x = net[0]->x + 2; ++ stop_arcs->flow = net[0]->x / 2; ++ stop_arcs->flow = stop_arcs->flow + 20; ++ stop_arcs->net_add = net[0]; ++ stop_arcs++; ++ } ++ ++ if( net[1] != 0 && stop_arcs != 0) ++ { ++ return -1; ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_reorg" } } */ +-- +2.33.0 + diff --git a/0171-phiopt-testsuite-Add-ftree-fold-phiopt-option-to-5-t.patch b/0171-phiopt-testsuite-Add-ftree-fold-phiopt-option-to-5-t.patch new file mode 100644 index 0000000..614ab14 --- /dev/null +++ b/0171-phiopt-testsuite-Add-ftree-fold-phiopt-option-to-5-t.patch @@ -0,0 +1,80 @@ +From 1f4d422fd8008f0af015df53f496c6dce3534b26 Mon Sep 17 00:00:00 2001 +From: Mingchuan Wu +Date: Fri, 22 Dec 2023 11:38:15 +0800 +Subject: [PATCH] [phiopt][testsuite] Add -ftree-fold-phiopt option to 5 test + cases. + +Modified test cases include: +1.gcc.dg/pr45416.c +2.gcc.target/i386/pr65871-3.c +3.g++.dg/opt/pr99305.C +4.gcc.dg/pr107190.c +5.g++.dg/tree-ssa/mull64.C +--- + gcc/testsuite/g++.dg/opt/pr99305.C | 2 +- + gcc/testsuite/g++.dg/tree-ssa/mull64.C | 2 +- + gcc/testsuite/gcc.dg/pr107190.c | 2 +- + gcc/testsuite/gcc.dg/pr45416.c | 2 +- + gcc/testsuite/gcc.target/i386/pr65871-3.c | 2 +- + 5 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/gcc/testsuite/g++.dg/opt/pr99305.C b/gcc/testsuite/g++.dg/opt/pr99305.C +index 6fcdef391..06295116f 100644 +--- a/gcc/testsuite/g++.dg/opt/pr99305.C ++++ b/gcc/testsuite/g++.dg/opt/pr99305.C +@@ -1,6 +1,6 @@ + // PR tree-optimization/99305 + // { dg-do compile } +-// { dg-options "-O3 -fno-ipa-icf -fdump-tree-optimized" } ++// { dg-options "-O3 -ftree-fold-phiopt -fno-ipa-icf -fdump-tree-optimized" } + // { dg-final { scan-tree-dump-times " = \\\(unsigned char\\\) c_\[0-9]*\\\(D\\\);" 3 "optimized" { target { ! unsigned_char } } } } + // { dg-final { scan-tree-dump-times " = \[^\n\r]* \\+ \[0-9]*;" 3 "optimized" } } + // { dg-final { scan-tree-dump-times " = \[^\n\r]* <= 9;" 3 "optimized" } } +diff --git a/gcc/testsuite/g++.dg/tree-ssa/mull64.C b/gcc/testsuite/g++.dg/tree-ssa/mull64.C +index cad891e62..ec359f2ba 100644 +--- a/gcc/testsuite/g++.dg/tree-ssa/mull64.C ++++ b/gcc/testsuite/g++.dg/tree-ssa/mull64.C +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O2 -fmerge-mull -Wno-psabi -fdump-tree-forwprop1-details -fdump-tree-forwprop4-details" } */ ++/* { dg-options "-O2 -ftree-fold-phiopt -fmerge-mull -Wno-psabi -fdump-tree-forwprop1-details -fdump-tree-forwprop4-details" } */ + + # define BN_BITS4 32 + # define BN_MASK2 (0xffffffffffffffffL) +diff --git a/gcc/testsuite/gcc.dg/pr107190.c b/gcc/testsuite/gcc.dg/pr107190.c +index d1e72e5df..d4e5fa0d0 100644 +--- a/gcc/testsuite/gcc.dg/pr107190.c ++++ b/gcc/testsuite/gcc.dg/pr107190.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O2 -fmerge-mull -fexpensive-optimizations -fdump-tree-phiopt2-details" } */ ++/* { dg-options "-O2 -ftree-fold-phiopt -fmerge-mull -fexpensive-optimizations -fdump-tree-phiopt2-details" } */ + + # define BN_BITS4 32 + # define BN_MASK2 (0xffffffffffffffffL) +diff --git a/gcc/testsuite/gcc.dg/pr45416.c b/gcc/testsuite/gcc.dg/pr45416.c +index a3f6a759d..dd37ec534 100644 +--- a/gcc/testsuite/gcc.dg/pr45416.c ++++ b/gcc/testsuite/gcc.dg/pr45416.c +@@ -1,6 +1,6 @@ + /* { dg-do compile } */ + /* { dg-skip-if "Skip for Thumb1." { { arm*-*-* } && { arm_thumb1_ok } } } */ +-/* { dg-options "-O2" } */ ++/* { dg-options "-O2 -ftree-fold-phiopt" } */ + + int foo(long long a) + { +diff --git a/gcc/testsuite/gcc.target/i386/pr65871-3.c b/gcc/testsuite/gcc.target/i386/pr65871-3.c +index c7d9bdd96..4fd3b48f8 100644 +--- a/gcc/testsuite/gcc.target/i386/pr65871-3.c ++++ b/gcc/testsuite/gcc.target/i386/pr65871-3.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O2 -mbmi" } */ ++/* { dg-options "-O2 -ftree-fold-phiopt -mbmi" } */ + + int foo (int x, int y) + { +-- +2.33.0 + diff --git a/0172-minmax-Move-minmax-pattern-to-gimple.patch b/0172-minmax-Move-minmax-pattern-to-gimple.patch new file mode 100644 index 0000000..99e6682 --- /dev/null +++ b/0172-minmax-Move-minmax-pattern-to-gimple.patch @@ -0,0 +1,323 @@ +From df88d29c355c59e262397fdf3b22ee9099ce40c2 Mon Sep 17 00:00:00 2001 +From: Pronin Alexander 00812787 +Date: Tue, 19 Dec 2023 12:19:14 +0300 +Subject: [PATCH 1/5] [minmax] Move minmax pattern to gimple. + +--- + gcc/common.opt | 4 + + gcc/config/aarch64/aarch64-simd.md | 72 ---------------- + gcc/match.pd | 104 ++++++++++++++++++++++++ + gcc/testsuite/gcc.dg/combine-maxmin-1.c | 15 ++++ + gcc/testsuite/gcc.dg/combine-maxmin-2.c | 14 ++++ + gcc/testsuite/gcc.dg/combine-maxmin.c | 19 +++-- + 6 files changed, 151 insertions(+), 77 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/combine-maxmin-1.c + create mode 100644 gcc/testsuite/gcc.dg/combine-maxmin-2.c + +diff --git a/gcc/common.opt b/gcc/common.opt +index a8a2264ee..73234dcc3 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1750,6 +1750,10 @@ fif-conversion-gimple + Common Report Var(flag_if_conversion_gimple) Optimization + Perform conversion of conditional jumps to branchless equivalents during gimple transformations. + ++fconvert-minmax ++Common Report Var(flag_convert_minmax) Optimization ++Convert saturating clipping to min max. ++ + fstack-reuse= + Common Joined RejectNegative Enum(stack_reuse_level) Var(flag_stack_reuse) Init(SR_ALL) Optimization + -fstack-reuse=[all|named_vars|none] Set stack reuse level for local variables. +diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md +index c7503561f..754343abc 100644 +--- a/gcc/config/aarch64/aarch64-simd.md ++++ b/gcc/config/aarch64/aarch64-simd.md +@@ -1535,78 +1535,6 @@ + [(set_attr "type" "neon_minmax")] + ) + +-;; Use sequential smax+smin to replace vector arithmetic operations like this: +-;; a = ((x & ~((1 << 8)-1)) ? (-x)>>31 & ((1 << 8)-1) : x); +-;; TODO: maybe extend to scalar operations. +- +-(define_insn_and_split "*aarch64_maxmin_arith" +- [(set (match_operand:VDQHSD 0 "register_operand" "=w") +- (xor:VDQHSD +- (and:VDQHSD +- (xor:VDQHSD +- (ashiftrt:VDQHSD +- (neg:VDQHSD +- (match_operand:VDQHSD 1 "register_operand")) +- (match_operand:VDQHSD 2 "maxmin_arith_shift_operand")) +- (match_dup 1)) +- (neg:VDQHSD +- (eq:VDQHSD +- (and:VDQHSD +- (match_dup 1) +- (match_operand:VDQHSD 3 "aarch64_bic_imm_for_maxmin")) +- (match_operand:VDQHSD 4 "aarch64_simd_or_scalar_imm_zero")))) +- (ashiftrt:VDQHSD +- (neg:VDQHSD +- (match_dup 1)) +- (match_dup 2))))] +- "TARGET_SIMD && !reload_completed" +- "#" +- "&& true" +- [(set (match_operand:VDQHSD 5 "register_operand" "w") (match_dup 3)) +- (set (match_operand:VDQHSD 6 "register_operand" "w") (match_dup 4)) +- (set (match_operand:VDQHSD 0 "register_operand" "=w") +- (smax:VDQHSD (match_operand:VDQHSD 1 "register_operand" "w") +- (match_operand:VDQHSD 6 "register_operand" "w"))) +- (set (match_operand:VDQHSD 0 "register_operand" "=w") +- (smin:VDQHSD (match_operand:VDQHSD 0 "register_operand" "w") +- (match_operand:VDQHSD 5 "register_operand" "w")))] +- { +- if (can_create_pseudo_p ()) +- { +- int val = INTVAL (CONST_VECTOR_ENCODED_ELT (operands[3], 0)); +- operands[3] = aarch64_simd_gen_const_vector_dup (mode, +- ~val); +- operands[5] = gen_reg_rtx (mode); +- operands[6] = gen_reg_rtx (mode); +- } +- else +- FAIL; +- } +- [(set_attr "type" "neon_minmax")] +-) +- +-;; The helper definition that allows combiner to use the previous pattern. +- +-(define_insn_and_split "*aarch64_maxmin_tmp" +- [(set (match_operand:VDQHSD 0 "register_operand" "=w") +- (ashiftrt:VDQHSD +- (neg:VDQHSD +- (match_operand:VDQHSD 1 "register_operand" "w")) +- (match_operand:VDQHSD 2 "maxmin_arith_shift_operand")))] +- "TARGET_SIMD" +- "#" +- "&& reload_completed" +- [(set (match_operand:VDQHSD 0 "register_operand") +- (neg:VDQHSD +- (match_operand:VDQHSD 1 "register_operand" "w"))) +- (set (match_dup 0) +- (ashiftrt:VDQHSD +- (match_dup 0) +- (match_operand:VDQHSD 2 "maxmin_arith_shift_operand")))] +- "" +- [(set_attr "type" "neon_minmax")] +-) +- + ;; Pairwise FP Max/Min operations. + (define_insn "aarch64_p" + [(set (match_operand:VHSDF 0 "register_operand" "=w") +diff --git a/gcc/match.pd b/gcc/match.pd +index 24ae157af..1097cd926 100644 +--- a/gcc/match.pd ++++ b/gcc/match.pd +@@ -6595,3 +6595,107 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) + (plus:c@4 (op2:c @0 @1) + (plus:c@5 (double_size_mul_overflow_check_lo @0 @1 @3) (op3:c @0 @1)))) + (if (single_use (@4) && single_use (@5))))) ++ ++/* MinMax pattern matching helpers. More info on the transformation below. */ ++ ++/* Match (a & 0b11..100..0) pattern. */ ++(match (minmax_cmp_arg @0 @1) ++ (bit_and @0 INTEGER_CST@1) ++ (if (wi::popcount (~wi::to_widest (@1) + 1) == 1))) ++ ++/* Match (inversed_sign_bit >> sign_bit_pos) pattern. ++ This statement is blocking for the transformation of unsigned integers. ++ Do type check here to avoid unnecessary duplications. */ ++(match (minmax_sat_arg @0) ++ (rshift (negate @0) INTEGER_CST@1) ++ (if (!TYPE_UNSIGNED (TREE_TYPE (@0)) ++ && wi::eq_p (wi::to_widest (@1), TYPE_PRECISION (TREE_TYPE (@0)) - 1)))) ++ ++/* Transform ((x & ~mask) ? (-x)>>31 & mask : x) to (min (max (x, 0), mask)). ++ The matched pattern can be described as saturated clipping. ++ ++ The pattern supports truncation via both casts and bit_and. ++ Also there are patterns for possible inverted conditions. */ ++(if (flag_convert_minmax) ++/* Truncation via casts. Unfortunately convert? cannot be applied here ++ because convert and cond take different number of arguments. */ ++ (simplify ++ (convert ++ (cond ++ (ne (minmax_cmp_arg @0 INTEGER_CST@1) integer_zerop) ++ (convert? (minmax_sat_arg @0)) ++ (convert? @0))) ++ (if (wi::geu_p (~wi::to_widest (@1) + 1, TYPE_PRECISION (type))) ++ (with { tree mask = build_int_cst (integer_type_node, ~tree_to_shwi (@1)); } ++ (convert (min (max @0 { integer_zero_node; }) ++ { mask; }))))) ++ (simplify ++ (cond ++ (ne (minmax_cmp_arg @0 INTEGER_CST@1) integer_zerop) ++ (convert? (minmax_sat_arg @0)) ++ (convert? @0)) ++ (if (wi::geu_p (~wi::to_widest (@1) + 1, TYPE_PRECISION (type))) ++ (with { tree mask = build_int_cst (integer_type_node, ~tree_to_shwi (@1)); } ++ (convert (min (max @0 { integer_zero_node; }) ++ { mask; }))))) ++ ++ (simplify ++ (convert ++ (cond ++ (eq (minmax_cmp_arg @0 INTEGER_CST@1) integer_zerop) ++ (convert? @0) ++ (convert? (minmax_sat_arg @0)))) ++ (if (wi::geu_p (~wi::to_widest (@1) + 1, TYPE_PRECISION (type))) ++ (with { tree mask = build_int_cst (integer_type_node, ~tree_to_shwi (@1)); } ++ (convert (min (max @0 { integer_zero_node; }) ++ { mask; }))))) ++ (simplify ++ (cond ++ (eq (minmax_cmp_arg @0 INTEGER_CST@1) integer_zerop) ++ (convert? @0) ++ (convert? (minmax_sat_arg @0))) ++ (if (wi::geu_p (~wi::to_widest (@1) + 1, TYPE_PRECISION (type))) ++ (with { tree mask = build_int_cst (integer_type_node, ~tree_to_shwi (@1)); } ++ (convert (min (max @0 { integer_zero_node; }) ++ { mask; }))))) ++ ++ /* Truncation via bit_and with mask. Same concerns on convert? here. */ ++ (simplify ++ (convert ++ (cond ++ (ne (minmax_cmp_arg @0 INTEGER_CST@1) integer_zerop) ++ (convert? (bit_and (minmax_sat_arg @0) INTEGER_CST@2)) ++ (convert? @0))) ++ (if (wi::to_widest (@2) == ~wi::to_widest (@1)) ++ (with { tree mask = build_int_cst (integer_type_node, ~tree_to_shwi (@1)); } ++ (convert (min (max @0 { integer_zero_node; }) ++ { mask; }))))) ++ (simplify ++ (cond ++ (ne (minmax_cmp_arg @0 INTEGER_CST@1) integer_zerop) ++ (convert? (bit_and (minmax_sat_arg @0) INTEGER_CST@2)) ++ (convert? @0)) ++ (if (wi::to_widest (@2) == ~wi::to_widest (@1)) ++ (with { tree mask = build_int_cst (integer_type_node, ~tree_to_shwi (@1)); } ++ (convert (min (max @0 { integer_zero_node; }) ++ { mask; }))))) ++ ++ (simplify ++ (convert ++ (cond ++ (eq (minmax_cmp_arg @0 INTEGER_CST@1) integer_zerop) ++ (convert? @0) ++ (convert? (bit_and (minmax_sat_arg @0) INTEGER_CST@2)))) ++ (if (wi::to_widest (@2) == ~wi::to_widest (@1)) ++ (with { tree mask = build_int_cst (integer_type_node, ~tree_to_shwi (@1)); } ++ (convert (min (max @0 { integer_zero_node; }) ++ { mask; }))))) ++ (simplify ++ (cond ++ (eq (minmax_cmp_arg @0 INTEGER_CST@1) integer_zerop) ++ (convert? @0) ++ (convert? (bit_and (minmax_sat_arg @0) INTEGER_CST@2))) ++ (if (wi::to_widest (@2) == ~wi::to_widest (@1)) ++ (with { tree mask = build_int_cst (integer_type_node, ~tree_to_shwi (@1)); } ++ (convert (min (max @0 { integer_zero_node; }) ++ { mask; })))))) +diff --git a/gcc/testsuite/gcc.dg/combine-maxmin-1.c b/gcc/testsuite/gcc.dg/combine-maxmin-1.c +new file mode 100644 +index 000000000..859ff7df8 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/combine-maxmin-1.c +@@ -0,0 +1,15 @@ ++/* { dg-do compile { target aarch64-*-* } } */ ++/* { dg-options "-O3 -fconvert-minmax" } */ ++ ++#include ++ ++__attribute__((noinline)) ++void test (int32_t *restrict a, int32_t *restrict x) ++{ ++ for (int i = 0; i < 4; i++) ++ a[i] = ((((-x[i]) >> 31) ^ x[i]) ++ & (-((int32_t)((x[i] & (~((1 << 8)-1))) == 0)))) ^ ((-x[i]) >> 31); ++} ++ ++/* { dg-final { scan-assembler-not {smax\t} } } */ ++/* { dg-final { scan-assembler-not {smin\t} } } */ +diff --git a/gcc/testsuite/gcc.dg/combine-maxmin-2.c b/gcc/testsuite/gcc.dg/combine-maxmin-2.c +new file mode 100644 +index 000000000..63d4d85b3 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/combine-maxmin-2.c +@@ -0,0 +1,14 @@ ++/* { dg-do compile { target aarch64-*-* } } */ ++/* { dg-options "-O3 -fconvert-minmax" } */ ++ ++#include ++ ++__attribute__((noinline)) ++void test (int8_t *restrict a, int32_t *restrict x) ++{ ++ for (int i = 0; i < 8; i++) ++ a[i] = ((x[i] & ~((1 << 9)-1)) ? (-x[i])>>31 & ((1 << 9)-1) : x[i]); ++} ++ ++/* { dg-final { scan-assembler-times {smax\t} 4 } } */ ++/* { dg-final { scan-assembler-times {smin\t} 4 } } */ +diff --git a/gcc/testsuite/gcc.dg/combine-maxmin.c b/gcc/testsuite/gcc.dg/combine-maxmin.c +index 06bce7029..a984fa560 100755 +--- a/gcc/testsuite/gcc.dg/combine-maxmin.c ++++ b/gcc/testsuite/gcc.dg/combine-maxmin.c +@@ -1,5 +1,5 @@ + /* { dg-do compile { target aarch64-*-* } } */ +-/* { dg-options "-O3 -fdump-rtl-combine-all" } */ ++/* { dg-options "-O3 -fconvert-minmax" } */ + + /* The test checks usage of smax/smin insns for clip evaluation and + * uzp1/uzp2 insns for vector element narrowing. It's inspired by +@@ -19,20 +19,26 @@ void hf (uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, + { + const int pad = (8 > 9) ? (-10 * ((1 << 8)-1)) : 0; + for( int y = 0; y < height; y++ ) { ++ /* This loop is not being vectorized now. */ + for( int x = -2; x < width+3; x++ ) { + int v = ((src)[x-2*stride] + (src)[x+3*stride] - 5*((src)[x-stride] + + (src)[x+2*stride]) + 20*((src)[x] + (src)[x+stride])); + dstv[x] = clip ( (v + 16) >> 5 ); + buf[x+2] = v + pad; + } ++ ++ /* Produces two versions of the code: 3xUZP1/2xMAX/2xMIN + 1xUZP1/1xMAX/1xMIN. */ + for( int x = 0; x < width; x++ ) + dstc[x] = clip ((((buf+2)[x-2*1] + (buf+2)[x+3*1] - 5*((buf+2)[x-1] + + (buf+2)[x+2*1]) + 20*((buf+2)[x] + (buf+2)[x+1])) + - 32*pad + 512) >> 10); ++ ++ /* Priduces two versions of the code: 1xUZP1/2xMAX/2xMIN + 0xUZP1/1xMAX/1xMIN. */ + for( int x = 0; x < width; x++ ) + dsth[x] = clip ((((src)[x-2*1] + (src)[x+3*1] - 5*((src)[x-1] + + (src)[x+2*1]) + 20*((src)[x] + (src)[x+1])) + + 16) >> 5); ++ + dsth += stride; + dstv += stride; + dstc += stride; +@@ -40,7 +46,10 @@ void hf (uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src, + } + } + +-/* { dg-final { scan-assembler-times {smax\t} 4 } } */ +-/* { dg-final { scan-assembler-times {smin\t} 4 } } */ +-/* { dg-final { scan-assembler-times {cmtst\t} 2 } } */ +-/* { dg-final { scan-assembler-times {uzp1\t} 6 } } */ ++/* Max is performed on 0 from signed values, match smax exactly. */ ++/* { dg-final { scan-assembler-times {smax\t} 6 } } */ ++/* Min is performed on signed val>0 and a mask, min sign doesn't matter. */ ++/* { dg-final { scan-assembler-times {[us]min\t} 6 } } */ ++/* All of the vectorized patterns are expected to be matched. */ ++/* { dg-final { scan-assembler-not {cmtst\t} } } */ ++/* { dg-final { scan-assembler-times {uzp1\t} 5 } } */ +-- +2.33.0 + diff --git a/0173-IPA-Fix-test-completion-1.c.patch b/0173-IPA-Fix-test-completion-1.c.patch new file mode 100644 index 0000000..8444b44 --- /dev/null +++ b/0173-IPA-Fix-test-completion-1.c.patch @@ -0,0 +1,24 @@ +From d6ef1c0c182267d3ab68e3ae1d7f1a576a7bbb2a Mon Sep 17 00:00:00 2001 +From: Diachkov Ilia +Date: Wed, 20 Dec 2023 18:44:29 +0800 +Subject: [PATCH 2/5] [IPA] Fix test completion-1.c + +--- + gcc/testsuite/gcc.dg/completion-1.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/gcc/testsuite/gcc.dg/completion-1.c b/gcc/testsuite/gcc.dg/completion-1.c +index 64da64f1c..df2319c76 100644 +--- a/gcc/testsuite/gcc.dg/completion-1.c ++++ b/gcc/testsuite/gcc.dg/completion-1.c +@@ -2,6 +2,7 @@ + /* { dg-options "--completion=-fipa-ic" } */ + + /* { dg-begin-multiline-output "" } ++-fipa-ic + -fipa-icf + -fipa-icf-functions + -fipa-icf-variables +-- +2.33.0 + diff --git a/0174-IPA-Fix-fails-on-checked-build-and-comments-from-rev.patch b/0174-IPA-Fix-fails-on-checked-build-and-comments-from-rev.patch new file mode 100644 index 0000000..54f9d56 --- /dev/null +++ b/0174-IPA-Fix-fails-on-checked-build-and-comments-from-rev.patch @@ -0,0 +1,71 @@ +From ed548cec9d8efe8ef742225c39f5d84aba4be81b Mon Sep 17 00:00:00 2001 +From: Diachkov Ilia WX1215920 +Date: Wed, 20 Dec 2023 13:53:47 +0300 +Subject: [PATCH 3/5] [IPA] Fix fails on checked build and comments from review + +--- + gcc/ipa-prefetch.c | 24 ++++++++++++++++++++++-- + gcc/params.opt | 4 ++-- + 2 files changed, 24 insertions(+), 4 deletions(-) + +diff --git a/gcc/ipa-prefetch.c b/gcc/ipa-prefetch.c +index 93483a6e8..d8bb9a251 100644 +--- a/gcc/ipa-prefetch.c ++++ b/gcc/ipa-prefetch.c +@@ -167,6 +167,7 @@ analyse_cgraph () + } + + /* TODO: maybe remove loop info here. */ ++ n->get_body (); + push_cfun (DECL_STRUCT_FUNCTION (n->decl)); + calculate_dominance_info (CDI_DOMINATORS); + loop_optimizer_init (LOOPS_NORMAL); +@@ -1540,9 +1541,28 @@ optimize_function (cgraph_node *n, function *fn) + return 0; + } + else if (dump_file) +- fprintf (dump_file, "Dominator bb %d for MRs\n", dom_bb->index); ++ { ++ fprintf (dump_file, "Dominator bb %d for MRs:\n", dom_bb->index); ++ gimple_dump_bb (dump_file, dom_bb, 0, dump_flags); ++ fprintf (dump_file, "\n"); ++ } ++ ++ /* Try to find comp_mr's stmt in the dominator bb. */ ++ gimple *last_used = NULL; ++ for (gimple_stmt_iterator si = gsi_last_bb (dom_bb); !gsi_end_p (si); ++ gsi_prev (&si)) ++ if (comp_mr->stmts[0] == gsi_stmt (si)) ++ { ++ last_used = gsi_stmt (si); ++ if (dump_file) ++ { ++ fprintf (dump_file, "Last used stmt in dominator bb:\n"); ++ print_gimple_stmt (dump_file, last_used, 0); ++ } ++ break; ++ } + +- split_block (dom_bb, (gimple *) NULL); ++ split_block (dom_bb, last_used); + gimple_stmt_iterator gsi = gsi_last_bb (dom_bb); + + /* Create new inc var. Insert new_var = old_var + step * factor. */ +diff --git a/gcc/params.opt b/gcc/params.opt +index ef7bea311..76ae925fd 100644 +--- a/gcc/params.opt ++++ b/gcc/params.opt +@@ -251,8 +251,8 @@ Common Joined UInteger Var(param_ipa_prefetch_distance_factor) Init(4) Param Opt + The factor represents the number of inductive variable incrementations to evaluate an indirect memory address for IPA prefetch. + + -param=ipa-prefetch-locality= +-Common Joined UInteger Var(param_ipa_prefetch_locality) Init(3) Param Optimization +-The flag represents temporal locality values in the following way: 0:pstl1strm, 1:pstl3keep, 2:pstl2keep, 3:pstl1keep. ++Common Joined UInteger Var(param_ipa_prefetch_locality) Init(3) IntegerRange(0, 3) Param Optimization ++The flag represents temporal locality value between 0 and 3, the higher value means the higher temporal locality in the data. + + -param=ira-loop-reserved-regs= + Common Joined UInteger Var(param_ira_loop_reserved_regs) Init(2) Param Optimization +-- +2.33.0 + diff --git a/0175-split-ldp-stp-Extending-and-refactoring-of-pass_spli.patch b/0175-split-ldp-stp-Extending-and-refactoring-of-pass_spli.patch new file mode 100644 index 0000000..b5a8054 --- /dev/null +++ b/0175-split-ldp-stp-Extending-and-refactoring-of-pass_spli.patch @@ -0,0 +1,1426 @@ +From abea8f1249a6efc5b7770f2243f31106b3ba9d58 Mon Sep 17 00:00:00 2001 +From: Gadzhiev Emin WX1195297 +Date: Wed, 20 Dec 2023 21:36:07 +0300 +Subject: [PATCH 4/5] [split ldp/stp] Extending and refactoring of + pass_split_complex_instructions + +- Add flag parameter in is_ldp_insn and is_stp_insn to know + if instruction has writeback operation +- Add support of PRE_*, POST_* operands as a memory address + expression +- Split only LDPs that intersect with a dependent store + instruction +- Make the selection of dependent store instructions stricter + so it will be enough to check by BFS that dependent store + instruction appears in search range. +- Add helper methods to retrieve fields of rtx +- Remove redundant iterations in find_dependent_stores_candidates +- Refactor generation of instructions +- Add more test cases +--- + gcc/config/aarch64/aarch64.c | 62 +- + gcc/doc/tm.texi | 12 +- + gcc/sched-rgn.c | 771 +++++++++--------- + gcc/target.def | 14 +- + .../gcc.dg/rtl/aarch64/test-ldp-dont-split.c | 35 +- + .../rtl/aarch64/test-ldp-split-rearrange.c | 2 +- + .../gcc.dg/rtl/aarch64/test-ldp-split.c | 181 +++- + 7 files changed, 603 insertions(+), 474 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 75efbcb97..da4983236 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -23858,39 +23858,59 @@ aarch64_run_selftests (void) + + #endif /* #if CHECKING_P */ + +-/* TODO: refuse to use ranges intead of full list of an instruction codes. */ ++/* TODO: refuse to use ranges instead of full list of an instruction codes. */ + + bool +-is_aarch64_ldp_insn (int icode) ++is_aarch64_ldp_insn (int icode, bool *has_wb) + { + if ((icode >= CODE_FOR_load_pair_sw_sisi +- && icode <= CODE_FOR_load_pair_dw_tftf) ++ && icode <= CODE_FOR_load_pair_sw_sfsf) ++ || (icode >= CODE_FOR_load_pair_dw_didi ++ && icode <= CODE_FOR_load_pair_dw_dfdf) ++ || (icode == CODE_FOR_load_pair_dw_tftf) + || (icode >= CODE_FOR_loadwb_pairsi_si +- && icode <= CODE_FOR_loadwb_pairtf_di) +- || (icode >= CODE_FOR_load_pairv8qiv8qi +- && icode <= CODE_FOR_load_pairdfdf) +- || (icode >= CODE_FOR_load_pairv16qiv16qi +- && icode <= CODE_FOR_load_pairv8bfv2df) +- || (icode >= CODE_FOR_load_pair_lanesv8qi +- && icode <= CODE_FOR_load_pair_lanesdf)) +- return true; ++ && icode <= CODE_FOR_loadwb_pairdi_di) ++ || (icode >= CODE_FOR_loadwb_pairsf_si ++ && icode <= CODE_FOR_loadwb_pairdf_di) ++ || (icode >= CODE_FOR_loadwb_pairti_si ++ && icode <= CODE_FOR_loadwb_pairtf_di)) ++ { ++ if (has_wb) ++ *has_wb = ((icode >= CODE_FOR_loadwb_pairsi_si ++ && icode <= CODE_FOR_loadwb_pairdi_di) ++ || (icode >= CODE_FOR_loadwb_pairsf_si ++ && icode <= CODE_FOR_loadwb_pairdf_di) ++ || (icode >= CODE_FOR_loadwb_pairti_si ++ && icode <= CODE_FOR_loadwb_pairtf_di)); ++ return true; ++ } + return false; + } + + bool +-is_aarch64_stp_insn (int icode) ++is_aarch64_stp_insn (int icode, bool *has_wb) + { + if ((icode >= CODE_FOR_store_pair_sw_sisi +- && icode <= CODE_FOR_store_pair_dw_tftf) ++ && icode <= CODE_FOR_store_pair_sw_sfsf) ++ || (icode >= CODE_FOR_store_pair_dw_didi ++ && icode <= CODE_FOR_store_pair_dw_dfdf) ++ || (icode == CODE_FOR_store_pair_dw_tftf) + || (icode >= CODE_FOR_storewb_pairsi_si +- && icode <= CODE_FOR_storewb_pairtf_di) +- || (icode >= CODE_FOR_vec_store_pairv8qiv8qi +- && icode <= CODE_FOR_vec_store_pairdfdf) +- || (icode >= CODE_FOR_vec_store_pairv16qiv16qi +- && icode <= CODE_FOR_vec_store_pairv8bfv2df) +- || (icode >= CODE_FOR_store_pair_lanesv8qi +- && icode <= CODE_FOR_store_pair_lanesdf)) +- return true; ++ && icode <= CODE_FOR_storewb_pairdi_di) ++ || (icode >= CODE_FOR_storewb_pairsf_si ++ && icode <= CODE_FOR_storewb_pairdf_di) ++ || (icode >= CODE_FOR_storewb_pairti_si ++ && icode <= CODE_FOR_storewb_pairtf_di)) ++ { ++ if (has_wb) ++ *has_wb = ((icode >= CODE_FOR_storewb_pairsi_si ++ && icode <= CODE_FOR_storewb_pairdi_di) ++ || (icode >= CODE_FOR_storewb_pairsf_si ++ && icode <= CODE_FOR_storewb_pairdf_di) ++ || (icode >= CODE_FOR_storewb_pairti_si ++ && icode <= CODE_FOR_storewb_pairtf_di)); ++ return true; ++ } + return false; + } + +diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi +index 4a998aa76..3dfd242ff 100644 +--- a/gcc/doc/tm.texi ++++ b/gcc/doc/tm.texi +@@ -11899,12 +11899,16 @@ This function generate the AES inversed mix columns instruction + of 16 byte elements vector if target supports this. + @end deftypefn + +-@deftypefn {Target Hook} bool TARGET_IS_LDP_INSN (int @var{icode}) +-Return true if icode is corresponding to any of the LDP instruction types. ++@deftypefn {Target Hook} bool TARGET_IS_LDP_INSN (int @var{icode}, bool *@var{has_wb}) ++Return true if @var{icode} is corresponding to any of the LDP instruction ++types. If @var{has_wb} is not NULL then its value is set to true if LDP ++contains post-index or pre-index operation. + @end deftypefn + +-@deftypefn {Target Hook} bool TARGET_IS_STP_INSN (int @var{icode}) +-Return true if icode is corresponding to any of the STP instruction types. ++@deftypefn {Target Hook} bool TARGET_IS_STP_INSN (int @var{icode}, bool *@var{has_wb}) ++Return true if @var{icode} is corresponding to any of the STP instruction ++types. If @var{has_wb} is not NULL then its value is set to true if STP ++contains post-index or pre-index operation. + @end deftypefn + + @deftypefn {Target Hook} bool TARGET_CANNOT_MODIFY_JUMPS_P (void) +diff --git a/gcc/sched-rgn.c b/gcc/sched-rgn.c +index 32f4489d8..43efe3926 100644 +--- a/gcc/sched-rgn.c ++++ b/gcc/sched-rgn.c +@@ -3960,7 +3960,7 @@ make_pass_sched_fusion (gcc::context *ctxt) + + namespace { + +-/* Def-use analisys special functions implementation. */ ++/* Def-use analysis special functions implementation. */ + + static struct df_link * + get_defs (rtx_insn *insn, rtx reg) +@@ -4036,42 +4036,66 @@ const pass_data pass_data_split_complex_instructions = { + (TODO_df_verify | TODO_df_finish), /* Todo_flags_finish. */ + }; + ++/* Pass split_complex_instructions finds LOAD PAIR instructions (LDP) that can ++ be split into two LDR instructions. It splits only those LDP for which one ++ half of the requested memory is contained in the preceding STORE (STR/STP) ++ instruction whose base register has the same definition. This allows ++ to use hardware store-to-load forwarding mechanism and to get one half of ++ requested memory from the store queue of CPU. ++ ++ TODO: Add split of STP. ++ TODO: Add split of vector STP and LDP. */ + class pass_split_complex_instructions : public rtl_opt_pass + { + private: +- enum complex_instructions_t ++ enum mem_access_insn_t + { + UNDEFINED, + LDP, ++ /* LDP with post-index (see loadwb_pair in config/aarch64.md). */ ++ LDP_WB, ++ /* LDP that contains one destination register in RTL IR ++ (see movti_aarch64 in config/aarch64.md). */ + LDP_TI, + STP, ++ /* STP with pre-index (see storewb_pair in config/aarch64.md). */ ++ STP_WB, ++ /* STP that contains one source register in RTL IR ++ (see movti_aarch64 in config/aarch64.md). */ ++ STP_TI, + STR + }; + +- void split_complex_insn (rtx_insn *insn); +- void split_ldp_ti (rtx_insn *insn); +- void split_ldp_with_offset (rtx_insn *ldp_insn); +- void split_simple_ldp (rtx_insn *ldp_insn); +- void split_ldp_stp (rtx_insn *insn); +- complex_instructions_t get_insn_type (rtx_insn *insn); +- +- basic_block bb; +- rtx_insn *insn; + std::set dependent_stores_candidates; + std::set ldp_to_split_list; + +- complex_instructions_t complex_insn_type = UNDEFINED; +- bool is_store_insn (rtx_insn *insn); +- bool is_ldp_dependent_on_store (rtx_insn *ldp_insn, basic_block bb); ++ void split_ldp_ti (rtx_insn *insn); ++ void split_ldp (rtx_insn *ldp_insn); ++ /* Emit a NEW_INSNS chain, recognize instruction code of each new instruction ++ and replace OLD_INSN with the emitted sequence. */ ++ void replace_insn (rtx_insn *old_insn, rtx_insn *new_insns); ++ ++ mem_access_insn_t get_insn_type (rtx_insn *insn); ++ bool is_typeof_ldp (mem_access_insn_t insn_type); ++ bool is_typeof_stp (mem_access_insn_t insn_type); ++ + bool bfs_for_reg_dependent_store (rtx_insn *ldp_insn, basic_block search_bb, + rtx_insn *search_insn, + int search_range + = param_ldp_dependency_search_range); + bool is_store_reg_dependent (rtx_insn *ldp_insn, rtx_insn *str_insn); + void init_df (); +- void find_dependent_stores_candidates (rtx_insn *ldp_insn); +- int get_insn_offset (rtx_insn *insn, complex_instructions_t insn_type, +- int *arith_operation_ptr = NULL); ++ void find_dependent_stores_candidates (rtx_insn *ldp_insn, ++ mem_access_insn_t insn_type); ++ ++ rtx get_memref (rtx_insn *insn, mem_access_insn_t insn_type); ++ rtx get_base_reg (rtx memref); ++ /* Set OFFSET to the offset value. Returns TRUE if MEMREF's address ++ expression is supported, FALSE otherwise. */ ++ bool get_offset (rtx memref, int &offset); ++ /* Return size of memory referenced by MEMREF. Returns -1 if INSN_TYPE ++ wasn't recognized. */ ++ int get_unit_size (rtx memref, mem_access_insn_t insn_type); + + public: + pass_split_complex_instructions (gcc::context *ctxt) +@@ -4084,28 +4108,22 @@ public: + virtual unsigned int + execute (function *) + { +- enum rtx_code ldp_memref_code; ++ basic_block bb; ++ rtx_insn *insn; ++ + init_df (); + ldp_to_split_list.clear (); + FOR_EACH_BB_FN (bb, cfun) + { + FOR_BB_INSNS (bb, insn) + { +- complex_instructions_t insn_type = get_insn_type (insn); +- /* TODO: Add splitting of STP instructions. */ +- if (insn_type != LDP && insn_type != LDP_TI) ++ mem_access_insn_t insn_type = get_insn_type (insn); ++ if (!is_typeof_ldp (insn_type)) + continue; +- /* TODO: Currently support only ldp_ti and ldp with REG or +- PLUS/MINUS offset expression. */ +- if (insn_type == LDP_TI) +- { +- ldp_memref_code = GET_CODE (XEXP (XEXP (PATTERN (insn), 1), +- 0)); +- if (ldp_memref_code != REG && ldp_memref_code != PLUS +- && ldp_memref_code != MINUS) +- continue; +- } +- if (is_ldp_dependent_on_store (insn, bb)) ++ ++ find_dependent_stores_candidates (insn, insn_type); ++ if (!dependent_stores_candidates.empty () ++ && bfs_for_reg_dependent_store (insn, bb, insn)) + { + ldp_to_split_list.insert (insn); + } +@@ -4114,18 +4132,107 @@ public: + + for (std::set::iterator i = ldp_to_split_list.begin (); + i != ldp_to_split_list.end (); ++i) +- split_complex_insn (*i); ++ split_ldp (*i); + + return 0; + } + }; // class pass_split_complex_instructions + + bool +-pass_split_complex_instructions::is_ldp_dependent_on_store (rtx_insn *ldp_insn, +- basic_block bb) ++pass_split_complex_instructions::is_typeof_ldp ( ++ mem_access_insn_t insn_type) + { +- find_dependent_stores_candidates (ldp_insn); +- return bfs_for_reg_dependent_store (ldp_insn, bb, ldp_insn); ++ return (insn_type == LDP || insn_type == LDP_WB || insn_type == LDP_TI); ++} ++ ++bool ++pass_split_complex_instructions::is_typeof_stp ( ++ mem_access_insn_t insn_type) ++{ ++ return (insn_type == STP || insn_type == STP_WB || insn_type == STP_TI); ++} ++ ++rtx ++pass_split_complex_instructions::get_memref ( ++ rtx_insn *insn, mem_access_insn_t insn_type) ++{ ++ rtx insn_pat = PATTERN (insn); ++ rtx memref = NULL; ++ ++ switch (insn_type) ++ { ++ case LDP: ++ memref = SET_SRC (XVECEXP (insn_pat, 0, 0)); ++ break; ++ case LDP_WB: ++ memref = SET_SRC (XVECEXP (insn_pat, 0, 1)); ++ break; ++ case LDP_TI: ++ memref = SET_SRC (insn_pat); ++ break; ++ case STP: ++ memref = SET_DEST (XVECEXP (insn_pat, 0, 0)); ++ break; ++ case STP_WB: ++ memref = SET_DEST (XVECEXP (insn_pat, 0, 1)); ++ break; ++ case STP_TI: ++ case STR: ++ memref = SET_DEST (insn_pat); ++ break; ++ default: ++ break; ++ } ++ ++ if (memref && !MEM_P (memref)) ++ return NULL; ++ return memref; ++} ++ ++rtx ++pass_split_complex_instructions::get_base_reg (rtx memref) ++{ ++ if (!memref || !MEM_P (memref)) ++ return NULL; ++ rtx addr_exp = XEXP (memref, 0); ++ ++ switch (GET_CODE (addr_exp)) ++ { ++ case REG: ++ return addr_exp; ++ case PLUS: ++ case PRE_DEC: ++ case PRE_INC: ++ case POST_DEC: ++ case POST_INC: ++ if (REG_P (XEXP (addr_exp, 0))) ++ return XEXP (addr_exp, 0); ++ default: ++ return NULL; ++ } ++} ++ ++int ++pass_split_complex_instructions::get_unit_size ( ++ rtx memref, mem_access_insn_t insn_type) ++{ ++ if (!memref) ++ return -1; ++ ++ switch (insn_type) ++ { ++ case LDP: ++ case STP: ++ case LDP_WB: ++ case STP_WB: ++ case STR: ++ return GET_MODE_SIZE (GET_MODE (memref)).to_constant (); ++ case LDP_TI: ++ case STP_TI: ++ return GET_MODE_SIZE (E_DImode).to_constant (); ++ default: ++ return -1; ++ } + } + + bool +@@ -4139,9 +4246,9 @@ pass_split_complex_instructions::bfs_for_reg_dependent_store ( + { + if (!current_search_insn) + return false; +- bool checking_result +- = is_store_reg_dependent (ldp_insn, current_search_insn); +- if (checking_result) ++ ++ if (dependent_stores_candidates.find (current_search_insn) ++ != dependent_stores_candidates.end ()) + { + if (dump_file) + { +@@ -4189,30 +4296,29 @@ pass_split_complex_instructions::init_df () + + void + pass_split_complex_instructions::find_dependent_stores_candidates ( +- rtx_insn *ldp_insn) ++ rtx_insn *ldp_insn, mem_access_insn_t insn_type) + { + dependent_stores_candidates.clear (); +- df_ref use; + +- FOR_EACH_INSN_USE (use, ldp_insn) +- { +- df_link *defs = get_defs (ldp_insn, DF_REF_REG (use)); +- if (!defs) +- return; ++ rtx base_reg = get_base_reg (get_memref (ldp_insn, insn_type)); ++ if (!base_reg) ++ return; + +- for (df_link *def = defs; def; def = def->next) +- { +- df_link *uses +- = get_uses (DF_REF_INSN (def->ref), DF_REF_REG (def->ref)); +- if (!uses) +- continue; ++ df_link *defs = get_defs (ldp_insn, base_reg); ++ if (!defs) ++ return; + +- for (df_link *use = uses; use; use = use->next) +- { +- if (DF_REF_CLASS (use->ref) == DF_REF_REGULAR +- && is_store_insn (DF_REF_INSN (use->ref))) +- dependent_stores_candidates.insert (DF_REF_INSN (use->ref)); +- } ++ for (df_link *def = defs; def; def = def->next) ++ { ++ df_link *uses = get_uses (DF_REF_INSN (def->ref), DF_REF_REG (def->ref)); ++ if (!uses) ++ continue; ++ for (df_link *use = uses; use; use = use->next) ++ { ++ if (DF_REF_CLASS (use->ref) == DF_REF_REGULAR ++ && DF_REF_INSN (use->ref) != ldp_insn ++ && is_store_reg_dependent (ldp_insn, DF_REF_INSN (use->ref))) ++ dependent_stores_candidates.insert (DF_REF_INSN (use->ref)); + } + } + } +@@ -4221,423 +4327,274 @@ bool + pass_split_complex_instructions::is_store_reg_dependent (rtx_insn *ldp_insn, + rtx_insn *str_insn) + { +- if (!is_store_insn (str_insn) +- || dependent_stores_candidates.find (str_insn) +- == dependent_stores_candidates.end ()) ++ if (!str_insn) + return false; + +- int ldp_offset_sign = UNDEFINED; +- int ldp_offset +- = get_insn_offset (ldp_insn, get_insn_type (ldp_insn), &ldp_offset_sign); +- if (ldp_offset_sign == MINUS) +- ldp_offset = -ldp_offset; ++ mem_access_insn_t st_type = get_insn_type (str_insn); ++ if (!is_typeof_stp (st_type) && st_type != STR) ++ return false; + +- int str_offset_sign = UNDEFINED; +- int str_offset = get_insn_offset (str_insn, STR, &str_offset_sign); +- if (str_offset_sign == MINUS) +- str_offset = -str_offset; ++ mem_access_insn_t ld_type = get_insn_type (ldp_insn); ++ rtx ld_memref = get_memref (ldp_insn, ld_type); ++ rtx st_memref = get_memref (str_insn, st_type); ++ rtx ld_base_reg = get_base_reg (ld_memref); ++ rtx st_base_reg = get_base_reg (st_memref); + +- if (str_offset == ldp_offset || str_offset == ldp_offset + 8) +- return true; ++ if (!ld_base_reg || !st_base_reg ++ || REGNO (ld_base_reg) != REGNO (st_base_reg)) ++ return false; + +- return false; +-} ++ int ld_offset = 0; ++ int st_offset = 0; ++ if (get_offset (ld_memref, ld_offset) ++ && get_offset (st_memref, st_offset)) ++ { ++ int ld_unit_size = get_unit_size (ld_memref, ld_type); ++ int st_size = get_unit_size (st_memref, st_type); ++ if (st_type != STR) ++ st_size *= 2; + +-bool +-pass_split_complex_instructions::is_store_insn (rtx_insn *insn) +-{ +- if (!insn) +- return false; +- rtx sset_b = single_set (insn); +- /* TODO: The condition below allow to take only store instructions in which +- the memory location's operand is either a register (base) or an plus/minus +- operation (base + #imm). So it might make sense to add support for other +- cases (e.g. multiply and shift). */ +- if (sset_b && MEM_P (SET_DEST (sset_b)) +- && GET_MODE (XEXP (sset_b, 0)) != BLKmode +- && (GET_CODE (XEXP (XEXP (sset_b, 0), 0)) == REG +- || (GET_CODE (XEXP (XEXP (sset_b, 0), 0)) == PLUS +- || GET_CODE (XEXP (XEXP (sset_b, 0), 0)) == MINUS) +- && (GET_CODE (XEXP (XEXP (XEXP (sset_b, 0), 0), 1)) == CONST_INT))) +- return true; ++ if (ld_unit_size < 0 || st_size < 0) ++ return false; ++ ++ bool st_has_low_ld_part = (ld_offset >= st_offset ++ && (ld_offset + ld_unit_size <= st_offset + st_size)); ++ bool st_has_high_ld_part = ((ld_offset + ld_unit_size >= st_offset) ++ && (ld_offset + 2 * ld_unit_size <= st_offset + st_size)); ++ bool st_has_not_full_ld = (ld_offset < st_offset ++ || (ld_offset + 2 * ld_unit_size > st_offset + st_size)); ++ ++ if ((st_has_low_ld_part || st_has_high_ld_part) && st_has_not_full_ld) ++ return true; ++ } + + return false; + } + +-int +-pass_split_complex_instructions::get_insn_offset ( +- rtx_insn *insn, complex_instructions_t insn_type, int *arith_operation_ptr) ++bool ++pass_split_complex_instructions::get_offset (rtx memref, int &offset) + { +- rtx insn_pat = PATTERN (insn); +- int returned_offset = 0; ++ rtx addr_exp = XEXP (memref, 0); + +- rtx offset_expr = NULL; +- rtx offset_value_expr = NULL; +- +- switch (insn_type) ++ switch (GET_CODE (addr_exp)) + { +- case LDP: +- { +- int number_of_sub_insns = XVECLEN (insn_pat, 0); +- +- /* Calculate it's own ofsset of first load insn. */ +- rtx_insn *first_load_insn = NULL; +- if (number_of_sub_insns == 2) ++ case REG: ++ case POST_DEC: ++ case POST_INC: ++ offset = 0; ++ return true; ++ case PRE_DEC: ++ offset = -(GET_MODE_SIZE (GET_MODE (memref)).to_constant ()); ++ return true; ++ case PRE_INC: ++ offset = GET_MODE_SIZE (GET_MODE (memref)).to_constant (); ++ return true; ++ case PLUS: ++ if (CONST_INT_P (XEXP (addr_exp, 1))) + { +- first_load_insn +- = make_insn_raw (copy_rtx (XVECEXP (insn_pat, 0, 0))); +- arith_operation_ptr = NULL; +- +- offset_expr = XEXP (XEXP (PATTERN (first_load_insn), 1), 0); +- if (GET_CODE (offset_expr) == PLUS +- || GET_CODE (offset_expr) == MINUS) +- offset_value_expr +- = XEXP (XEXP (XEXP (PATTERN (first_load_insn), 1), 0), 1); +- else +- offset_expr = NULL; ++ offset = INTVAL (XEXP (addr_exp, 1)); ++ return true; + } +- else if (number_of_sub_insns == 3) +- { +- rtx_insn *offset_sub_insn +- = make_insn_raw (copy_rtx (XVECEXP (insn_pat, 0, 0))); +- +- offset_expr = XEXP (PATTERN (offset_sub_insn), 1); +- offset_value_expr = XEXP (XEXP (PATTERN (offset_sub_insn), 1), 1); +- } +- else +- { +- gcc_assert (false +- && "Wrong number of elements in the ldp_insn vector"); +- } +- break; +- } +- case LDP_TI: +- { +- offset_expr = XEXP (XEXP (insn_pat, 1), 0); +- if (GET_CODE (offset_expr) != PLUS && GET_CODE (offset_expr) != MINUS) +- return 0; +- offset_value_expr = XEXP (XEXP (XEXP (insn_pat, 1), 0), 1); +- break; +- } +- case STR: +- { +- offset_expr = XEXP (XEXP (insn_pat, 0), 0); +- /* If memory location is specified by single base register then the +- offset is zero. */ +- if (GET_CODE (offset_expr) == REG) +- return 0; +- offset_value_expr = XEXP (XEXP (XEXP (insn_pat, 0), 0), 1); +- break; +- } +- default: +- { +- if (dumps_are_enabled && dump_file) +- { +- fprintf (dump_file, "Instruction that was tried to split:\n"); +- print_rtl_single (dump_file, insn); +- } +- gcc_assert (false && "Unsupported instruction type"); +- break; +- } +- } +- +- if (offset_expr != NULL && offset_value_expr +- && GET_CODE (offset_value_expr) == CONST_INT) +- returned_offset = XINT (offset_value_expr, 0); +- +- if (arith_operation_ptr != NULL) +- { +- *arith_operation_ptr = GET_CODE (offset_expr); +- gcc_assert ((*arith_operation_ptr == MINUS +- || *arith_operation_ptr == PLUS) +- && "Unexpected arithmetic operation in the offset expr"); ++ default: ++ return false; + } +- +- return returned_offset; + } + + void +-pass_split_complex_instructions::split_simple_ldp (rtx_insn *ldp_insn) ++pass_split_complex_instructions::replace_insn (rtx_insn *old_insn, ++ rtx_insn *new_insns) + { +- rtx pat = PATTERN (ldp_insn); +- +- rtx_insn *mem_insn_1 = make_insn_raw (copy_rtx (XVECEXP (pat, 0, 0))); +- rtx_insn *mem_insn_2 = make_insn_raw (copy_rtx (XVECEXP (pat, 0, 1))); +- +- int dest_regno = REGNO (SET_DEST (PATTERN (mem_insn_1))); +- int src_regno; +- +- rtx srs_reg_insn = XEXP (SET_SRC (PATTERN (mem_insn_1)), 0); +- +- if (GET_CODE (srs_reg_insn) == REG) +- src_regno = REGNO (srs_reg_insn); +- else +- src_regno = REGNO (XEXP (srs_reg_insn, 0)); +- +- rtx_insn *emited_insn_1, *emited_insn_2; ++ rtx_insn *prev_insn = PREV_INSN (old_insn); ++ start_sequence (); + +- /* in cases like ldp r1,r2,[r1] we emit ldr r2,[r1] first. */ +- if (src_regno == dest_regno) +- std::swap (mem_insn_1, mem_insn_2); ++ emit_insn (new_insns); ++ if (dump_file) ++ { ++ fprintf (dump_file, "Split LDP:\n"); ++ print_rtl_single (dump_file, old_insn); ++ fprintf (dump_file, "Split into:\n"); ++ } + +- emited_insn_1 = emit_insn (PATTERN (mem_insn_1)); +- emited_insn_2 = emit_insn (PATTERN (mem_insn_2)); ++ for (rtx_insn *insn = new_insns; insn; insn = NEXT_INSN (insn)) ++ { ++ INSN_CODE (insn) = recog (PATTERN (insn), insn, NULL); ++ if (dump_file) ++ { ++ print_rtl_single (dump_file, insn); ++ } ++ } + +- int sub_insn_1_code = recog (PATTERN (mem_insn_1), mem_insn_1, 0); +- int sub_insn_2_code = recog (PATTERN (mem_insn_2), mem_insn_2, 0); ++ rtx_insn *seq = get_insns (); ++ unshare_all_rtl_in_chain (seq); ++ end_sequence (); + +- INSN_CODE (emited_insn_1) = sub_insn_1_code; +- INSN_CODE (emited_insn_2) = sub_insn_2_code; ++ emit_insn_after_setloc (seq, prev_insn, INSN_LOCATION (old_insn)); ++ delete_insn_and_edges (old_insn); + } + + void +-pass_split_complex_instructions::split_ldp_with_offset (rtx_insn *ldp_insn) ++pass_split_complex_instructions::split_ldp (rtx_insn *ldp_insn) + { + rtx pat = PATTERN (ldp_insn); +- bool post_index = true; +- +- rtx_insn offset_insn; +- rtx_insn mem_insn_1; +- rtx_insn mem_insn_2; ++ mem_access_insn_t insn_type = get_insn_type (ldp_insn); ++ gcc_assert (is_typeof_ldp (insn_type)); + +- int offset_insn_code; +- int mem_insn_1_code = -1; +- int mem_insn_2_code = -1; ++ rtx load_rtx_1 = NULL; ++ rtx load_rtx_2 = NULL; ++ rtx post_index_rtx = NULL; + +- int offset = 0; +- int arith_operation = UNDEFINED; +- +- for (int i = 0; i < 3; i++) ++ switch (insn_type) + { +- rtx sub_insn = XVECEXP (pat, 0, i); +- rtx_insn *copy_of_sub_insn = make_insn_raw (copy_rtx (sub_insn)); +- int sub_insn_code +- = recog (PATTERN (copy_of_sub_insn), copy_of_sub_insn, 0); +- +- /* If sub_insn is offset related. */ +- if (GET_RTX_CLASS (sub_insn_code) == RTX_UNARY) +- { +- offset_insn = *copy_of_sub_insn; +- offset_insn_code = sub_insn_code; +- gcc_assert (i == 0 +- && "Offset related insn must be the first " +- "element of a parallel insn vector"); +- +- offset = get_insn_offset (ldp_insn, LDP, &arith_operation); +- } +- else +- { +- if (GET_CODE (XEXP (PATTERN (copy_of_sub_insn), 0)) != REG) +- { +- rtx &offset_expr +- = XEXP (XEXP (XEXP (PATTERN (copy_of_sub_insn), 0), 0), 1); +- if (GET_CODE (offset_expr) == CONST_INT) +- { +- int local_offset = XINT (offset_expr, 0); +- offset = (arith_operation == PLUS ? offset : -offset); +- +- offset_expr = GEN_INT (local_offset + offset); +- +- gcc_assert ( +- (arith_operation == MINUS || arith_operation == PLUS) +- && "Unexpected arithmetic operation in offset related " +- "sub_insn"); +- +- if (i == 1) +- post_index = false; +- } +- else +- { +- post_index = true; +- } +- } +- } +- if (i == 1) +- { +- mem_insn_1 = *copy_of_sub_insn; +- mem_insn_1_code = sub_insn_code; +- } +- if (i == 2) +- { +- mem_insn_2 = *copy_of_sub_insn; +- mem_insn_2_code = sub_insn_code; +- } ++ case LDP: ++ load_rtx_1 = copy_rtx (XVECEXP (pat, 0, 0)); ++ load_rtx_2 = copy_rtx (XVECEXP (pat, 0, 1)); ++ break; ++ case LDP_WB: ++ post_index_rtx = copy_rtx (XVECEXP (pat, 0, 0)); ++ load_rtx_1 = copy_rtx (XVECEXP (pat, 0, 1)); ++ load_rtx_2 = copy_rtx (XVECEXP (pat, 0, 2)); ++ break; ++ case LDP_TI: ++ split_ldp_ti (ldp_insn); ++ return; ++ default: ++ return; + } +- gcc_assert (mem_insn_1_code != -1 && mem_insn_2_code != -1 +- && "Uninitialized memory insns"); + +- int dest_regno = REGNO (SET_DEST (PATTERN (&mem_insn_1))); +- int src_regno; +- +- rtx srs_reg_insn = XEXP (SET_SRC (PATTERN (&mem_insn_1)), 0); +- +- if (GET_CODE (srs_reg_insn) == REG) +- src_regno = REGNO (srs_reg_insn); +- else +- src_regno = REGNO (XEXP (srs_reg_insn, 0)); ++ int dest_regno = REGNO (SET_DEST (load_rtx_1)); ++ int base_regno = REGNO (get_base_reg (get_memref (ldp_insn, insn_type))); + +- /* Don't split such weird LDP. */ +- if (src_regno == dest_regno) +- return; +- +- rtx_insn *emited_offset_insn; +- if (!post_index) ++ /* In cases like ldp r1,r2,[r1[, #imm]] emit ldr r2,[r1[, #imm]] first. ++ For LDP with post-index don't split such instruction. */ ++ if (base_regno == dest_regno) + { +- emited_offset_insn = emit_insn (PATTERN (&offset_insn)); +- INSN_CODE (emited_offset_insn) = offset_insn_code; ++ if (insn_type == LDP) ++ std::swap (load_rtx_1, load_rtx_2); ++ else ++ return; + } + +- rtx_insn *emited_insn_1 = emit_insn (PATTERN (&mem_insn_1)); +- rtx_insn *emited_insn_2 = emit_insn (PATTERN (&mem_insn_2)); +- +- +- INSN_CODE (emited_insn_1) = mem_insn_1_code; +- INSN_CODE (emited_insn_2) = mem_insn_2_code; +- +- if (post_index) ++ /* Construct the instruction chain for subsequent emitting. */ ++ rtx_insn *insn_seq = make_insn_raw (load_rtx_1); ++ rtx_insn *load_insn_2 = make_insn_raw (load_rtx_2); ++ SET_NEXT_INSN (insn_seq) = load_insn_2; ++ SET_NEXT_INSN (load_insn_2) = NULL; ++ if (post_index_rtx) + { +- emited_offset_insn = emit_insn (PATTERN (&offset_insn)); +- INSN_CODE (emited_offset_insn) = offset_insn_code; ++ rtx_insn *post_index_insn = make_insn_raw (post_index_rtx); ++ SET_NEXT_INSN (load_insn_2) = post_index_insn; ++ SET_NEXT_INSN (post_index_insn) = NULL; + } +-} +- +-void +-pass_split_complex_instructions::split_ldp_stp (rtx_insn *insn) +-{ +- rtx_insn *prev_insn = PREV_INSN (insn); +- int number_of_sub_insns = XVECLEN (PATTERN (insn), 0); +- +- start_sequence (); + +- if (number_of_sub_insns == 2) +- split_simple_ldp (insn); +- else if (number_of_sub_insns == 3) +- split_ldp_with_offset (insn); +- else +- gcc_assert (false && "Broken complex insn vector"); +- +- rtx_insn *seq = get_insns (); +- unshare_all_rtl_in_chain (seq); +- end_sequence (); +- +- emit_insn_after_setloc (seq, prev_insn, INSN_LOCATION (insn)); +- delete_insn_and_edges (insn); ++ replace_insn (ldp_insn, insn_seq); + } + + void + pass_split_complex_instructions::split_ldp_ti (rtx_insn *insn) + { +- rtx_insn *prev_insn = PREV_INSN (insn); +- rtx_insn *load_insn_1 = make_insn_raw (copy_rtx (PATTERN (insn))); +- rtx_insn *load_insn_2 = make_insn_raw (copy_rtx (PATTERN (insn))); +- +- rtx reg_insn_1 = XEXP (PATTERN (load_insn_1), 0); +- rtx mem_insn_1 = XEXP (PATTERN (load_insn_1), 1); +- rtx mem_insn_2 = XEXP (PATTERN (load_insn_2), 1); +- +- PUT_MODE (mem_insn_1, DImode); +- PUT_MODE (mem_insn_2, DImode); +- +- int reg_no_1 = REGNO (reg_insn_1); ++ rtx pat = PATTERN (insn); ++ rtx memref = get_memref (insn, LDP_TI); ++ int unit_size = get_unit_size (memref, LDP_TI); ++ rtx base_reg = get_base_reg (memref); ++ rtx dest_reg = SET_DEST (pat); ++ ++ rtx reg_index_rtx = NULL; ++ rtx load_rtx_1 = NULL; ++ rtx load_rtx_2 = NULL; ++ bool post_index = false; ++ int offset = 0; + +- XEXP (PATTERN (load_insn_1), 0) = gen_rtx_REG (DImode, reg_no_1); +- XEXP (PATTERN (load_insn_2), 0) = gen_rtx_REG (DImode, reg_no_1 + 1); ++ rtx load_1_memref = gen_rtx_MEM (DImode, base_reg); + +- rtx load_insn_2_plus_expr = XEXP (XEXP (PATTERN (load_insn_2), 1), 0); +- if (GET_CODE (load_insn_2_plus_expr) == REG) ++ rtx addr_expr = XEXP (memref, 0); ++ if (GET_CODE (addr_expr) == PLUS) + { +- XEXP (XEXP (PATTERN (load_insn_2), 1), 0) +- = gen_rtx_PLUS (DImode, +- gen_rtx_REG (DImode, REGNO (load_insn_2_plus_expr)), +- GEN_INT (GET_MODE_SIZE (DImode))); ++ offset = INTVAL (XEXP (addr_expr, 1)); ++ XEXP (load_1_memref, 0) = gen_rtx_PLUS (DImode, base_reg, ++ GEN_INT (offset)); + } +- else +- { +- rtx load_insn_2_offset_expr +- = XEXP (XEXP (XEXP (PATTERN (load_insn_2), 1), 0), 1); + +- if (load_insn_2_offset_expr == NULL) +- return; +- +- if (GET_CODE (load_insn_2_offset_expr) == CONST_INT) +- { +- int load_insn_2_offset = XINT (load_insn_2_offset_expr, 0); +- XEXP (XEXP (XEXP (PATTERN (load_insn_2), 1), 0), 1) +- = GEN_INT (load_insn_2_offset + GET_MODE_SIZE (DImode)); +- } +- } +- +- start_sequence (); ++ rtx load_2_memref = gen_rtx_MEM (DImode, ++ gen_rtx_PLUS (DImode, base_reg, GEN_INT (offset + unit_size))); + +- int src_regno; +- rtx srs_reg_insn = XEXP (XEXP (PATTERN (load_insn_1), 1), 0); ++ load_rtx_1 = gen_rtx_SET (gen_rtx_REG (DImode, REGNO (dest_reg)), ++ load_1_memref); ++ load_rtx_2 = gen_rtx_SET (gen_rtx_REG (DImode, REGNO (dest_reg) + 1), ++ load_2_memref); + +- if (GET_CODE (srs_reg_insn) == REG) +- src_regno = REGNO (srs_reg_insn); +- else +- src_regno = REGNO (XEXP (srs_reg_insn, 0)); ++ if (GET_CODE (addr_expr) == PRE_INC || GET_CODE (addr_expr) == PRE_DEC ++ || GET_CODE (addr_expr) == POST_INC || GET_CODE (addr_expr) == POST_DEC) ++ { ++ /* The amount of increment or decrement is equal to size of ++ machine-mode of the containing MEMREF (see rtl.def). */ ++ int index_offset = GET_MODE_SIZE (GET_MODE (memref)).to_constant (); + +- /* in cases like ldp r1,r2,[r1] we emit ldr r2,[r1] first. */ +- if (src_regno == reg_no_1) +- std::swap (load_insn_1, load_insn_2); ++ if (GET_CODE (addr_expr) == PRE_DEC || GET_CODE (addr_expr) == POST_DEC) ++ index_offset = -index_offset; + +- rtx_insn *emited_load_insn_1 = emit_insn (PATTERN (load_insn_1)); +- rtx_insn *emited_load_insn_2 = emit_insn (PATTERN (load_insn_2)); ++ if (GET_CODE (addr_expr) == POST_INC || GET_CODE (addr_expr) == POST_DEC) ++ post_index = true; + +- INSN_CODE (emited_load_insn_1) +- = recog (PATTERN (emited_load_insn_1), emited_load_insn_1, 0); +- INSN_CODE (emited_load_insn_2) +- = recog (PATTERN (emited_load_insn_2), emited_load_insn_2, 0); ++ reg_index_rtx = gen_rtx_SET (base_reg, ++ gen_rtx_PLUS (DImode, base_reg, ++ GEN_INT (index_offset))); ++ } + +- rtx_insn *seq = get_insns (); +- unshare_all_rtl_in_chain (seq); +- end_sequence (); ++ /* In cases like ldp r1,r2,[r1] we emit ldr r2,[r1] first. */ ++ if (REGNO (base_reg) == REGNO (dest_reg)) ++ std::swap (load_rtx_1, load_rtx_2); + +- emit_insn_after_setloc (seq, prev_insn, INSN_LOCATION (insn)); +- delete_insn_and_edges (insn); +-} ++ /* Construct the instruction chain for subsequent emitting. */ ++ rtx_insn *insn_seq = make_insn_raw (load_rtx_1); ++ rtx_insn *load_insn_2 = make_insn_raw (load_rtx_2); ++ SET_NEXT_INSN (insn_seq) = load_insn_2; ++ SET_NEXT_INSN (load_insn_2) = NULL; ++ if (post_index && reg_index_rtx) ++ { ++ rtx_insn *post_index_insn = make_insn_raw (reg_index_rtx); ++ SET_NEXT_INSN (load_insn_2) = post_index_insn; ++ SET_NEXT_INSN (post_index_insn) = NULL; ++ } ++ else if (!post_index && reg_index_rtx) ++ { ++ rtx_insn *pre_index = make_insn_raw (reg_index_rtx); ++ SET_NEXT_INSN (pre_index) = insn_seq; ++ insn_seq = pre_index; ++ } + +-void +-pass_split_complex_instructions::split_complex_insn (rtx_insn *insn) +-{ +- complex_instructions_t insn_type = get_insn_type (insn); +- /* TODO: Add splitting of STP instructions. */ +- if (insn_type == LDP || insn_type == STP) +- split_ldp_stp (insn); +- else if (insn_type == LDP_TI) +- split_ldp_ti (insn); +- else +- gcc_assert (false && "Unsupported type of insn to split"); ++ replace_insn (insn, insn_seq); + } + +-pass_split_complex_instructions::complex_instructions_t ++pass_split_complex_instructions::mem_access_insn_t + pass_split_complex_instructions::get_insn_type (rtx_insn *insn) + { + if (!INSN_P (insn)) + return UNDEFINED; + +- rtx pat = PATTERN (insn); +- int icode = recog (PATTERN (insn), insn, NULL); ++ int icode = INSN_CODE (insn); ++ if (icode == -1) ++ icode = recog (PATTERN (insn), insn, 0); ++ bool has_wb = false; ++ ++ if (targetm.is_ldp_insn (icode, &has_wb)) ++ return (has_wb ? LDP_WB : LDP); + +- if (GET_CODE (pat) == PARALLEL) ++ if (targetm.is_stp_insn (icode, &has_wb)) ++ return (has_wb ? STP_WB : STP); ++ ++ rtx set_insn = single_set (insn); ++ if (set_insn && (GET_MODE (SET_SRC (set_insn)) == E_TImode ++ || GET_MODE (SET_DEST (set_insn)) == E_TImode)) + { +- if (targetm.is_ldp_insn (icode)) +- { +- return LDP; +- } +- if (targetm.is_stp_insn (icode)) +- { +- return STP; +- } +- else +- { +- return UNDEFINED; +- } ++ if (MEM_P (SET_SRC (set_insn)) && REG_P (SET_DEST (set_insn))) ++ return LDP_TI; ++ if (MEM_P (SET_DEST (set_insn)) && REG_P (SET_SRC (set_insn))) ++ return STP_TI; + } +- rtx set_insn = single_set (insn); +- if (set_insn && GET_CODE (XEXP (set_insn, 1)) == MEM +- && GET_MODE (XEXP (set_insn, 1)) == E_TImode) +- return LDP_TI; ++ ++ if (set_insn && MEM_P (SET_DEST (set_insn)) && REG_P (SET_SRC (set_insn)) ++ && GET_MODE (SET_DEST (set_insn)) != BLKmode) ++ return STR; + + return UNDEFINED; + } +diff --git a/gcc/target.def b/gcc/target.def +index b4dff78ea..2e3eae9f3 100644 +--- a/gcc/target.def ++++ b/gcc/target.def +@@ -2770,13 +2770,19 @@ DEFHOOK + + DEFHOOK + (is_ldp_insn, +- "Return true if icode is corresponding to any of the LDP instruction types.", +- bool, (int icode), NULL) ++ "Return true if @var{icode} is corresponding to any of the LDP instruction\n\ ++types. If @var{has_wb} is not NULL then its value is set to true if LDP\n\ ++contains post-index or pre-index operation.", ++ bool, (int icode, bool *has_wb), ++ NULL) + + DEFHOOK + (is_stp_insn, +- "Return true if icode is corresponding to any of the STP instruction types.", +- bool, (int icode), NULL) ++ "Return true if @var{icode} is corresponding to any of the STP instruction\n\ ++types. If @var{has_wb} is not NULL then its value is set to true if STP\n\ ++contains post-index or pre-index operation.", ++ bool, (int icode, bool *has_wb), ++ NULL) + + DEFHOOK + (gen_ccmp_first, +diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-dont-split.c b/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-dont-split.c +index 3918d43f6..2d42231dc 100644 +--- a/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-dont-split.c ++++ b/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-dont-split.c +@@ -1,5 +1,5 @@ + /* { dg-do compile { target aarch64-*-* } } */ +-/* { dg-additional-options "-fsplit-ldp-stp" } */ ++/* { dg-additional-options "-O1 -fsplit-ldp-stp" } */ + /* + * Tests are: + * Patterns where LDP insns should NOT be split +@@ -15,6 +15,9 @@ simple_ldp_after_store () + (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cinsn 228 (set (reg/i:DI sp) + (reg/i:DI x0))) ++ (cinsn 238 (set (reg/i:DI x1) ++ (reg/i:DI x0))) ++ + (cinsn 101 (set (mem/c:DI + (plus:DI (reg/f:DI sp) + (const_int 32))[1 S4 A32])(reg:DI x0))) +@@ -24,11 +27,27 @@ simple_ldp_after_store () + (set (reg:DI x30) + (mem:DI (plus:DI (reg/f:DI sp) + (const_int 16)) [1 S4 A32]))])) +- (cinsn 11 (use (reg/i:DI sp))) +- (cinsn 12 (use (reg/i:DI cc))) +- (cinsn 13 (use (reg/i:DI x29))) +- (cinsn 14 (use (reg/i:DI x30))) +- (cinsn 15 (use (reg/i:DI x0))) ++ (cinsn 11 (use (reg/i:DI x29))) ++ (cinsn 12 (use (reg/i:DI x30))) ++ ++ /* stp x0, x2, [x1]. */ ++ (cinsn 102 (parallel [ ++ (set (mem:DI (reg/f:DI x1) [1 S4 A32]) ++ (reg:DI x0)) ++ (set (mem:DI (plus:DI (reg/f:DI x1) (const_int 8)) [1 S4 A32]) ++ (reg:DI x2))])) ++ /* ldp x5, x6, [x1]. */ ++ (cinsn 13 (parallel [ ++ (set (reg:DI x5) (mem:DI (reg/f:DI x1) [1 S4 A32])) ++ (set (reg:DI x6) (mem:DI (plus:DI (reg/f:DI x1) ++ (const_int 8)) [1 S4 A32])) ++ ])) ++ (cinsn 14 (use (reg/i:DI x5))) ++ (cinsn 15 (use (reg/i:DI x6))) ++ ++ (cinsn 100 (use (reg/i:DI sp))) ++ (cinsn 200 (use (reg/i:DI cc))) ++ (cinsn 300 (use (reg/i:DI x0))) + (edge-to exit (flags "FALLTHRU")) + ) ;; block 2 + ) ;; insn-chain +@@ -70,5 +89,5 @@ ldp_after_store_in_different_bb () + ) ;; function "ldp_after_store_in_different_bb" + } + +-/* Verify that the output code contains exactly 2 ldp. */ +-/* { dg-final { scan-assembler-times {ldp\t} 2 } } */ +\ No newline at end of file ++/* Verify that the output code contains exactly 3 ldp. */ ++/* { dg-final { scan-assembler-times {ldp\t} 3 } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-split-rearrange.c b/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-split-rearrange.c +index 8c035c3e1..b9d745185 100644 +--- a/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-split-rearrange.c ++++ b/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-split-rearrange.c +@@ -1,5 +1,5 @@ + /* { dg-do compile { target aarch64-*-* } } */ +-/* { dg-additional-options "-fsplit-ldp-stp" } */ ++/* { dg-additional-options "-O1 -fsplit-ldp-stp" } */ + /* + * Test is: + * Pattern where LDP insns should be split with rearrangement in order +diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-split.c b/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-split.c +index 2615e4fa1..0b280022f 100644 +--- a/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-split.c ++++ b/gcc/testsuite/gcc.dg/rtl/aarch64/test-ldp-split.c +@@ -13,48 +13,131 @@ simple_ldp_after_store () + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK) ++ /* mov sp, x0. */ + (cinsn 228 (set (reg/i:DI sp) +- (reg/i:DI x0))) ++ (reg/i:DI x0))) ++ /* mov x1, x0. */ + (cinsn 238 (set (reg/i:DI x1) +- (reg/i:DI x0))) ++ (reg/i:DI x0))) + ++ /* str x0, [sp, 8]. */ + (cinsn 101 (set (mem/c:DI + (plus:DI (reg/f:DI sp) + (const_int 8))[1 S4 A32])(reg:DI x0))) ++ /* ldp x29, x30, [sp, 8]. */ + (cinsn 10 (parallel [ + (set (reg:DI x29) + (mem:DI (plus:DI (reg/f:DI sp) (const_int 8)) [1 S4 A32])) + (set (reg:DI x30) + (mem:DI (plus:DI (reg/f:DI sp) + (const_int 16)) [1 S4 A32]))])) ++ (cinsn 11 (use (reg/i:DI x29))) ++ (cinsn 12 (use (reg/i:DI x30))) + ++ /* str x0, [x1, -16]. */ + (cinsn 102 (set (mem/c:DI (plus:DI (reg/f:DI x1) + (const_int -16)) [1 S4 A32]) + (reg:DI x0))) +- (cinsn 11 (parallel [ ++ /* ldp x3, x4, [x1, -16]. */ ++ (cinsn 13 (parallel [ + (set (reg:DI x3) + (mem:DI (plus:DI (reg/f:DI x1) (const_int -16)) [1 S4 A32])) + (set (reg:DI x4) + (mem:DI (plus:DI (reg/f:DI x1) (const_int -8)) [1 S4 A32])) + ])) ++ (cinsn 14 (use (reg/i:DI x3))) ++ (cinsn 15 (use (reg/i:DI x4))) + ++ /* str x0, [x1]. */ + (cinsn 103 (set (mem/c:DI (reg/f:DI x1) [1 S4 A32]) + (reg:DI x0))) +- (cinsn 12 (parallel [ ++ /* ldp x5, x6, [x1]. */ ++ (cinsn 16 (parallel [ + (set (reg:DI x5) (mem:DI (reg/f:DI x1) [1 S4 A32])) + (set (reg:DI x6) (mem:DI (plus:DI (reg/f:DI x1) + (const_int 8)) [1 S4 A32])) + ])) ++ (cinsn 17 (use (reg/i:DI x5))) ++ (cinsn 18 (use (reg/i:DI x6))) + +- (cinsn 13 (use (reg/i:DI sp))) +- (cinsn 14 (use (reg/i:DI cc))) +- (cinsn 15 (use (reg/i:DI x29))) +- (cinsn 16 (use (reg/i:DI x30))) +- (cinsn 17 (use (reg/i:DI x0))) +- (cinsn 18 (use (reg/i:DI x3))) +- (cinsn 19 (use (reg/i:DI x4))) +- (cinsn 20 (use (reg/i:DI x5))) +- (cinsn 21 (use (reg/i:DI x6))) ++ /* ldp x29, x30, [sp], 96. */ ++ (cinsn 19 (parallel [ ++ (set (reg/f:DI sp) ++ (plus:DI (reg/f:DI sp) (const_int 96))) ++ (set (reg:DI x29) ++ (mem:DI (reg/f:DI sp) [1 S4 A32])) ++ (set (reg:DI x30) ++ (mem:DI (plus:DI (reg/f:DI sp) ++ (const_int 8)) [1 S4 A32]))])) ++ (cinsn 20 (use (reg/i:DI x29))) ++ (cinsn 21 (use (reg/i:DI x30))) ++ ++ /* stp x0, x2, [x1, 128]. */ ++ (cinsn 104 (parallel [ ++ (set (mem:DI (plus:DI (reg/f:DI x1) (const_int 128)) [1 S4 A32]) ++ (reg:DI x0)) ++ (set (mem:DI (plus:DI (reg/f:DI x1) (const_int 136)) [1 S4 A32]) ++ (reg:DI x2))])) ++ /* ldp x29, x30, [x1, 120]. */ ++ (cinsn 22 (parallel [ ++ (set (reg:DI x29) ++ (mem:DI (plus:DI (reg/f:DI x1) (const_int 120)) [1 S4 A32])) ++ (set (reg:DI x30) ++ (mem:DI (plus:DI (reg/f:DI x1) (const_int 128)) [1 S4 A32]))])) ++ (cinsn 23 (use (reg/i:DI x29))) ++ (cinsn 24 (use (reg/i:DI x30))) ++ ++ /* stp x0, x2, [x1, 128]. */ ++ (cinsn 105 (parallel [ ++ (set (mem:DI (plus:DI (reg/f:DI x1) (const_int 128)) [1 S4 A32]) ++ (reg:DI x0)) ++ (set (mem:DI (plus:DI (reg/f:DI x1) (const_int 136)) [1 S4 A32]) ++ (reg:DI x2))])) ++ /* ldp x3, x4, [x1, 136]. */ ++ (cinsn 25 (parallel [ ++ (set (reg:DI x3) ++ (mem:DI (plus:DI (reg/f:DI x1) (const_int 136)) [1 S4 A32])) ++ (set (reg:DI x4) ++ (mem:DI (plus:DI (reg/f:DI x1) (const_int 144)) [1 S4 A32])) ++ ])) ++ (cinsn 26 (use (reg/i:DI x3))) ++ (cinsn 27 (use (reg/i:DI x4))) ++ ++ /* stp w0, w2, [x1, 32]. */ ++ (cinsn 106 (parallel [ ++ (set (mem:SI (plus:DI (reg/f:DI x1) (const_int 32)) [1 S4 A32]) ++ (reg:SI x0)) ++ (set (mem:SI (plus:DI (reg/f:DI x1) (const_int 36)) [1 S4 A32]) ++ (reg:SI x2))])) ++ /* ldp x5, x6, [x1, 32]. */ ++ (cinsn 28 (parallel [ ++ (set (reg:DI x5) (mem:DI (plus:DI (reg/f:DI x1) ++ (const_int 32)) [1 S4 A32])) ++ (set (reg:DI x6) (mem:DI (plus:DI (reg/f:DI x1) ++ (const_int 40)) [1 S4 A32])) ++ ])) ++ (cinsn 29 (use (reg/i:DI x5))) ++ (cinsn 30 (use (reg/i:DI x6))) ++ ++ /* stp w0, w2, [x1, 40]. */ ++ (cinsn 107 (parallel [ ++ (set (mem:SI (plus:DI (reg/f:DI x1) (const_int 40)) [1 S4 A32]) ++ (reg:SI x0)) ++ (set (mem:SI (plus:DI (reg/f:DI x1) (const_int 44)) [1 S4 A32]) ++ (reg:SI x2))])) ++ /* ldp x5, x6, [x1, 32]. */ ++ (cinsn 31 (parallel [ ++ (set (reg:DI x5) (mem:DI (plus:DI (reg/f:DI x1) ++ (const_int 32)) [1 S4 A32])) ++ (set (reg:DI x6) (mem:DI (plus:DI (reg/f:DI x1) ++ (const_int 40)) [1 S4 A32])) ++ ])) ++ (cinsn 32 (use (reg/i:DI x5))) ++ (cinsn 33 (use (reg/i:DI x6))) ++ ++ (cinsn 100 (use (reg/i:DI sp))) ++ (cinsn 200 (use (reg/i:DI cc))) ++ (cinsn 400 (use (reg/i:DI x0))) + (edge-to exit (flags "FALLTHRU")) + ) ;; block 2 + ) ;; insn-chain +@@ -69,43 +152,83 @@ ldp_ti_after_store () + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK) ++ /* mov sp, x0. */ + (cinsn 228 (set (reg/i:DI sp) +- (reg/i:DI x0))) ++ (reg/i:DI x0))) ++ /* mov x2, x0. */ + (cinsn 238 (set (reg/i:DI x2) +- (reg/i:DI x0))) +- ++ (reg/i:DI x0))) ++ /* str x0, [sp, 136]. */ + (cinsn 101 (set (mem/c:DI + (plus:DI (reg/f:DI sp) + (const_int 136))[1 S4 A32])(reg:DI x0))) +- (insn 81 (set (reg:TI x0 [1 S4 A32]) ++ /* ldp x0, x1, [sp, 136]. */ ++ (cinsn 81 (set (reg:TI x0 [1 S4 A32]) + (mem/c:TI (plus:DI (reg/f:DI sp) +- (const_int 136 )) [1 S4 A32])) +- (expr_list:REG_EQUIV (mem/c:TI (plus:DI (reg/f:DI sfp) +- (const_int -24 )) [1 S4 A32]) +- (nil))) +- ++ (const_int 136)) [1 S4 A32]))) ++ /* str x0, [x2, -16]. */ + (cinsn 102 (set (mem/c:DI (plus:DI (reg/f:DI x2) +- (const_int -16)) [1 S4 A32]) ++ (const_int -16)) [1 S4 A32]) + (reg:DI x0))) +- (insn 82 (set (reg:TI x3 [1 S4 A32]) ++ /* ldp x3, x4, [x2, -16]. */ ++ (cinsn 82 (set (reg:TI x3 [1 S4 A32]) + (mem/c:TI (plus:DI (reg/f:DI x2) +- (const_int -16)) [1 S4 A32]))) +- ++ (const_int -16)) [1 S4 A32]))) ++ /* str x0, [x2]. */ + (cinsn 103 (set (mem/c:DI (reg/f:DI x2) [1 S4 A32]) + (reg:DI x0))) +- (insn 83 (set (reg:TI x5 [1 S4 A32]) ++ /* ldp x5, x6, [x2]. */ ++ (cinsn 83 (set (reg:TI x5 [1 S4 A32]) + (mem/c:TI (reg/f:DI x2) [1 S4 A32]))) + ++ /* stp x0, x1, [sp, -8]. */ ++ (cinsn 104 (set (mem:TI (plus:DI (reg/v/f:DI sp) ++ (const_int -8)) [1 S4 A32]) ++ (reg:TI x0))) ++ /* ldp x5, x6, [sp], -16. */ ++ (cinsn 84 (set (reg/v:TI x5 [1 S4 A32]) ++ (mem:TI (post_dec:DI (reg/v/f:DI sp)) [1 S4 A32]))) ++ (cinsn 85 (use (reg/i:DI x5))) ++ (cinsn 86 (use (reg/i:DI x6))) ++ ++ /* stp x0, x1, [sp, 8]. */ ++ (cinsn 105 (set (mem:TI (plus:DI (reg/v/f:DI sp) ++ (const_int 8)) [1 S4 A32]) ++ (reg:TI x0))) ++ /* ldp x5, x6, [sp], -16. */ ++ (cinsn 87 (set (reg/v:TI x5 [1 S4 A32]) ++ (mem:TI (post_dec:DI (reg/v/f:DI sp)) [1 S4 A32]))) ++ (cinsn 88 (use (reg/i:DI x5))) ++ (cinsn 89 (use (reg/i:DI x6))) ++ ++ /* Intersects with insn 102. */ ++ /* ldp x2, x3, [x2, -16]!. */ ++ (cinsn 90 (set (reg/v:TI x2 [1 S4 A32]) ++ (mem:TI (pre_dec:DI (reg/v/f:DI x2)) [1 S4 A32]))) ++ (cinsn 91 (use (reg/i:DI x2))) ++ (cinsn 92 (use (reg/i:DI x3))) ++ ++ /* mov x2, x0. */ ++ (cinsn 248 (set (reg/i:DI x2) ++ (reg/i:DI x0))) ++ /* str x0, [x2, 16]. */ ++ (cinsn 106 (set (mem:DI (plus:DI (reg/v/f:DI x2) ++ (const_int 16)) [1 S4 A32]) ++ (reg:DI x0))) ++ /* ldp x3, x4, [x2, 16]!. */ ++ (cinsn 93 (set (reg/v:TI x3 [1 S4 A32]) ++ (mem:TI (pre_inc:DI (reg/v/f:DI x2)) [1 S4 A32]))) ++ (cinsn 94 (use (reg/i:DI x3))) ++ (cinsn 95 (use (reg/i:DI x4))) ++ + (cinsn 11 (use (reg/i:DI sp))) + (cinsn 12 (use (reg/i:DI cc))) + (cinsn 13 (use (reg/i:DI x29))) + (cinsn 14 (use (reg/i:DI x30))) + (cinsn 15 (use (reg/i:DI x0))) + (cinsn 16 (use (reg/i:DI x3))) +- (cinsn 17 (use (reg/i:DI x5))) + (cinsn 18 (use (reg/i:DI x1))) + (cinsn 19 (use (reg/i:DI x4))) +- (cinsn 20 (use (reg/i:DI x6))) + (edge-to exit (flags "FALLTHRU")) + ) ;; block 2 + ) ;; insn-chain +-- +2.33.0 + diff --git a/0176-Fix-bugs-in-ICP-src-openEuler-gcc-I8PYBF-I8PYLL.patch b/0176-Fix-bugs-in-ICP-src-openEuler-gcc-I8PYBF-I8PYLL.patch new file mode 100644 index 0000000..0b69fe7 --- /dev/null +++ b/0176-Fix-bugs-in-ICP-src-openEuler-gcc-I8PYBF-I8PYLL.patch @@ -0,0 +1,61 @@ +From d2742041454dbd4c4c3c3e0a27b5fb26d1e05832 Mon Sep 17 00:00:00 2001 +From: Diachkov Ilia WX1215920 +Date: Thu, 21 Dec 2023 11:14:06 +0300 +Subject: [PATCH 5/5] Fix bugs in ICP (src-openEuler/gcc: I8PYBF, I8PYLL) + +--- + gcc/ipa-devirt.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c +index fbde7eb94..a18cbe36a 100644 +--- a/gcc/ipa-devirt.c ++++ b/gcc/ipa-devirt.c +@@ -4399,6 +4399,11 @@ print_type_set(unsigned ftype_uid, type_alias_map *map) + if (!map->count (ftype_uid)) + return; + type_set* s = (*map)[ftype_uid]; ++ if (!s) ++ { ++ fprintf (dump_file, "%d (no set)", ftype_uid); ++ return; ++ } + for (type_set::const_iterator it = s->begin (); it != s->end (); it++) + fprintf (dump_file, it == s->begin () ? "%d" : ", %d", *it); + } +@@ -4966,7 +4971,8 @@ analyze_assign_stmt (gimple *stmt) + { + rhs = TREE_OPERAND (rhs, 0); + if (VAR_OR_FUNCTION_DECL_P (rhs) || TREE_CODE (rhs) == STRING_CST +- || TREE_CODE (rhs) == ARRAY_REF || TREE_CODE (rhs) == PARM_DECL) ++ || TREE_CODE (rhs) == ARRAY_REF || TREE_CODE (rhs) == PARM_DECL ++ || TREE_CODE (rhs) == LABEL_DECL) + rhs_type = build_pointer_type (TREE_TYPE (rhs)); + else if (TREE_CODE (rhs) == COMPONENT_REF) + { +@@ -4980,7 +4986,12 @@ analyze_assign_stmt (gimple *stmt) + gcc_assert (POINTER_TYPE_P (rhs_type)); + } + else +- gcc_unreachable(); ++ { ++ fprintf (dump_file, "\nUnsupported rhs type %s in assign stmt: ", ++ get_tree_code_name (TREE_CODE (rhs))); ++ print_gimple_stmt (dump_file, stmt, 0); ++ gcc_unreachable (); ++ } + } + else + rhs_type = TREE_TYPE (rhs); +@@ -5678,6 +5689,8 @@ merge_fs_map_for_ftype_aliases () + decl_set *d_set = it1->second; + tree type = (*type_uid_map)[it1->first]; + type_set *set = (*fta_map)[it1->first]; ++ if (!set) ++ continue; + for (type_set::const_iterator it2 = set->begin (); + it2 != set->end (); it2++) + { +-- +2.33.0 + diff --git a/gcc.spec b/gcc.spec index 25fb1e9..ef64479 100644 --- a/gcc.spec +++ b/gcc.spec @@ -61,7 +61,7 @@ Summary: Various compilers (C, C++, Objective-C, ...) Name: gcc Version: %{gcc_version} -Release: 46 +Release: 47 License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ with exceptions and LGPLv2+ and BSD URL: https://gcc.gnu.org @@ -275,6 +275,15 @@ Patch164: 0164-LLC-Allocation-Fix-some-bugs-and-remove-variable-pre.patch Patch165: 0165-rtl-ifcvt-BugFix-change-def-selection-logic-in-noce_.patch Patch166: 0166-perm-propagation-Bugfix-Check-that-the-arithmetic-op.patch Patch167: 0167-perm-propagation-Bugfix-Fix-shll-shll2-patterns-for-.patch +Patch168: 0168-LLC-Allocation-Bugfix-Terminate-kernel-filtering-for.patch +Patch169: 0169-Struct-Reorg-Fix-several-bugs.patch +Patch170: 0170-DFE-Add-escape-check.patch +Patch171: 0171-phiopt-testsuite-Add-ftree-fold-phiopt-option-to-5-t.patch +Patch172: 0172-minmax-Move-minmax-pattern-to-gimple.patch +Patch173: 0173-IPA-Fix-test-completion-1.c.patch +Patch174: 0174-IPA-Fix-fails-on-checked-build-and-comments-from-rev.patch +Patch175: 0175-split-ldp-stp-Extending-and-refactoring-of-pass_spli.patch +Patch176: 0176-Fix-bugs-in-ICP-src-openEuler-gcc-I8PYBF-I8PYLL.patch %global gcc_target_platform %{_arch}-linux-gnu @@ -895,6 +904,15 @@ not stable, so plugins must be rebuilt any time GCC is updated. %patch165 -p1 %patch166 -p1 %patch167 -p1 +%patch168 -p1 +%patch169 -p1 +%patch170 -p1 +%patch171 -p1 +%patch172 -p1 +%patch173 -p1 +%patch174 -p1 +%patch175 -p1 +%patch176 -p1 %build @@ -2919,6 +2937,12 @@ end %doc rpm.doc/changelogs/libcc1/ChangeLog* %changelog +* Fri Dec 22 2023 Feiyang Liu - 10.3.1-47 +- Type:Sync +- ID:NA +- SUG:NA +- DESC: Sync patch from openeuler/gcc + * Thu Dec 21 2023 Xiong Zhou - 10.3.1-46 - Type:Sync - ID:NA @@ -2947,7 +2971,7 @@ end - Type:Spec - ID:NA - SUG:NA -- DESC: Sync patch from openeuler/gcc, add LLC expending outer loop. +- DESC: Sync patch from openeuler/gcc, add LLC extending outer loop. * Mon Dec 11 2023 Feiyang Liu - 10.3.1-41 - Type:Spec -- Gitee