!374 [Sync] Sync patches from openeuler/gcc.

From: @liuf9 
Reviewed-by: @li-yancheng 
Signed-off-by: @li-yancheng
This commit is contained in:
openeuler-ci-bot 2023-12-22 12:16:44 +00:00 committed by Gitee
commit 63f041247e
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
10 changed files with 2473 additions and 2 deletions

View File

@ -0,0 +1,175 @@
From 4369e823f0883c079c0681bef68cead870d02063 Mon Sep 17 00:00:00 2001
From: Feiyang Liu <liufeiyang6@huawei.com>
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<class loop *> &sorted_kernels,
set<basic_block> end_bb;
list<basic_block> walked_header_bb; /* Used to record nested loops. */
+ set<int> walked_non_header_bb_idx;
for (unsigned i = 0; i < kernels.size (); ++i)
{
@@ -1895,7 +1896,15 @@ filter_and_sort_kernels (vector<class loop *> &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

View File

@ -0,0 +1,183 @@
From 708ffe6f132ee39441b66b6ab6b98847d35916b7 Mon Sep 17 00:00:00 2001
From: eastb233 <xiezhiheng@huawei.com>
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

View File

@ -0,0 +1,104 @@
From e875e4e7f3716aa268ffbbf55ee199ec82b6aeba Mon Sep 17 00:00:00 2001
From: Mingchuan Wu <wumingchuan1992@foxmail.com>
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 <stdio.h>
+#include <stdlib.h>
+
+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

View File

@ -0,0 +1,80 @@
From 1f4d422fd8008f0af015df53f496c6dce3534b26 Mon Sep 17 00:00:00 2001
From: Mingchuan Wu <wumingchuan1992@foxmail.com>
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

View File

@ -0,0 +1,323 @@
From df88d29c355c59e262397fdf3b22ee9099ce40c2 Mon Sep 17 00:00:00 2001
From: Pronin Alexander 00812787 <pronin.alexander@huawei.com>
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<q>")]
)
-;; 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<mode>"
- [(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>mode,
- ~val);
- operands[5] = gen_reg_rtx (<MODE>mode);
- operands[6] = gen_reg_rtx (<MODE>mode);
- }
- else
- FAIL;
- }
- [(set_attr "type" "neon_minmax<q>")]
-)
-
-;; The helper definition that allows combiner to use the previous pattern.
-
-(define_insn_and_split "*aarch64_maxmin_tmp<mode>"
- [(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<q>")]
-)
-
;; Pairwise FP Max/Min operations.
(define_insn "aarch64_<maxmin_uns>p<mode>"
[(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 <inttypes.h>
+
+__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 <inttypes.h>
+
+__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

View File

@ -0,0 +1,24 @@
From d6ef1c0c182267d3ab68e3ae1d7f1a576a7bbb2a Mon Sep 17 00:00:00 2001
From: Diachkov Ilia <diachkov.ilia1@huawei-partners.com>
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

View File

@ -0,0 +1,71 @@
From ed548cec9d8efe8ef742225c39f5d84aba4be81b Mon Sep 17 00:00:00 2001
From: Diachkov Ilia WX1215920 <diachkov.ilia1@huawei-partners.com>
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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
From d2742041454dbd4c4c3c3e0a27b5fb26d1e05832 Mon Sep 17 00:00:00 2001
From: Diachkov Ilia WX1215920 <diachkov.ilia1@huawei-partners.com>
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

View File

@ -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 <liufeiyang6@huawei.com> - 10.3.1-47
- Type:Sync
- ID:NA
- SUG:NA
- DESC: Sync patch from openeuler/gcc
* Thu Dec 21 2023 Xiong Zhou <xiongzhou4@huawei.com> - 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 <liufeiyang6@huawei.com> - 10.3.1-41
- Type:Spec