From 6d8660cbcbfd7546fb0d2d39e39e43172c4a1f4d Mon Sep 17 00:00:00 2001 From: Tianle Shi Date: Tue, 2 Jun 2026 01:05:02 +0000 Subject: [PATCH 1/2] [Backport] i386: Add avx512_avoid_vec_perm tune for c86-4g-m7 Reference: https://gcc.gnu.org/cgit/gcc/commit/?id=8d7b042f7c9092e168d2c745bdc3403061e41466 Adapt the AVX512 cross-lane permutation cost model and its tests to the EulerGCC GCC 12 x86 vector cost framework. Signed-off-by: Zhongjie Guo (cherry picked from commit 1ab52ac86f5d3245a2795c3a825c5047e5f9c6f2) --- gcc/config/i386/i386.cc | 87 ++++++++++++++++++- gcc/config/i386/i386.h | 2 + gcc/config/i386/x86-tune.def | 4 + .../gcc.target/i386/avx512_avoid_vec_perm-1.c | 30 +++++++ .../gcc.target/i386/avx512_avoid_vec_perm-2.c | 29 +++++++ .../gcc.target/i386/avx512_avoid_vec_perm-3.c | 35 ++++++++ 6 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-1.c create mode 100644 gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-2.c create mode 100644 gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-3.c diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 169b2dd24b6..d9f1badb229 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "memmodel.h" #include "gimple.h" +#include "gimple-pretty-print.h" #include "cfghooks.h" #include "cfgloop.h" #include "df.h" @@ -23086,14 +23087,26 @@ ix86_noce_conversion_profitable_p (rtx_insn *seq, struct noce_if_info *if_info) /* x86-specific vector costs. */ class ix86_vector_costs : public vector_costs { - using vector_costs::vector_costs; +public: + ix86_vector_costs (vec_info *, bool); unsigned int add_stmt_cost (int count, vect_cost_for_stmt kind, stmt_vec_info stmt_info, slp_tree node, tree vectype, int misalign, vect_cost_model_location where) override; + void finish_cost (const vector_costs *scalar_costs) override; + +private: + /* Number of 512-bit vector permutations. */ + unsigned m_num_avx512_vec_perm[3]; }; +ix86_vector_costs::ix86_vector_costs (vec_info *vinfo, + bool costing_for_scalar) + : vector_costs (vinfo, costing_for_scalar), + m_num_avx512_vec_perm () +{} + /* Implement targetm.vectorize.create_costs. */ static vector_costs * @@ -23102,6 +23115,47 @@ ix86_vectorize_create_costs (vec_info *vinfo, bool costing_for_scalar) return new ix86_vector_costs (vinfo, costing_for_scalar); } +/* Return true if a vec_perm should be counted as a cross-lane vector + permutation for a vector with NUNITS elements. */ +static bool +ix86_count_cross_lane_perm_p (vec_info *vinfo, slp_tree node, unsigned nunits) +{ + /* TODO: For loop vectorization with no SLP load-permutation + information, conservatively treat these perms as cross-lane. + Repeated-index cases such as {0, 0, 0, 0} are emitted as + separate vec_perm_exprs for each index, so we cannot reliably + separate false positives from real cross-lane shuffles yet. */ + if (!node + || !SLP_TREE_LOAD_PERMUTATION (node).exists () + || !is_a (vinfo)) + return true; + + unsigned half = nunits / 2; + bool allsame = true; + unsigned first = SLP_TREE_LOAD_PERMUTATION (node)[0]; + bool cross_lane_p = false; + + for (unsigned i = 0; i != SLP_TREE_LANES (node); i++) + { + unsigned tmp = SLP_TREE_LOAD_PERMUTATION (node)[i]; + /* allsame is just a broadcast. */ + if (tmp != first) + allsame = false; + + /* The load permutation can cover multiple vectors, so compare + source and destination lanes modulo NUNITS. */ + tmp = tmp & (nunits - 1); + unsigned index = i & (nunits - 1); + if ((index < half && tmp >= half) || (index >= half && tmp < half)) + cross_lane_p = true; + + if (!allsame && cross_lane_p) + return true; + } + + return false; +} + unsigned ix86_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, stmt_vec_info stmt_info, slp_tree node, @@ -23335,11 +23389,42 @@ ix86_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, retval = (retval * 17) / 10; } + /* BIT_FIELD_REF with count 0 costs 0 in body. */ + if (kind == vec_perm && vectype + && GET_MODE_SIZE (TYPE_MODE (vectype)) == 64 + && count != 0) + { + unsigned nunits = TYPE_VECTOR_SUBPARTS (vectype).to_constant (); + + if (ix86_count_cross_lane_perm_p (m_vinfo, node, nunits)) + { + m_num_avx512_vec_perm[where] += count; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + "Detected avx512 cross-lane permutation: "); + if (stmt_info) + print_gimple_expr (dump_file, stmt_info->stmt, 0, TDF_SLIM); + fprintf (dump_file, " \n"); + } + } + } + m_costs[where] += retval; return retval; } +void +ix86_vector_costs::finish_cost (const vector_costs *scalar_costs) +{ + for (int i = 0; i != 3; i++) + if (m_num_avx512_vec_perm[i] && TARGET_AVX512_AVOID_VEC_PERM) + m_costs[i] = INT_MAX; + + vector_costs::finish_cost (scalar_costs); +} + /* Validate target specific memory model bits in VAL. */ static unsigned HOST_WIDE_INT diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 34c9f2b0182..8dc1ecdb51d 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -422,6 +422,8 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST]; ix86_tune_features[X86_TUNE_AVX256_SPLIT_REGS] #define TARGET_AVX512_SPLIT_REGS \ ix86_tune_features[X86_TUNE_AVX512_SPLIT_REGS] +#define TARGET_AVX512_AVOID_VEC_PERM \ + ix86_tune_features[X86_TUNE_AVX512_AVOID_VEC_PERM] #define TARGET_GENERAL_REGS_SSE_SPILL \ ix86_tune_features[X86_TUNE_GENERAL_REGS_SSE_SPILL] #define TARGET_AVOID_MEM_OPND_FOR_CMOVE \ diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def index a7c3b252185..071d66527f5 100644 --- a/gcc/config/i386/x86-tune.def +++ b/gcc/config/i386/x86-tune.def @@ -555,6 +555,10 @@ DEF_TUNE (X86_TUNE_AVX256_OPTIMAL, "avx256_optimal", m_CORE_AVX512) DEF_TUNE (X86_TUNE_AVX512_SPLIT_REGS, "avx512_split_regs", m_ZNVER4 | m_C86_4G_M7 | m_C86_4G_M8) +/* X86_TUNE_AVX512_AVOID_VEC_PERM: Avoid using 512-bit cross-lane + vector permutation instructions in the auto-vectorizer. */ +DEF_TUNE (X86_TUNE_AVX512_AVOID_VEC_PERM, "avx512_avoid_vec_perm", m_C86_4G_M7) + /* X86_TUNE_AVX256_MOVE_BY_PIECES: Optimize move_by_pieces with 256-bit AVX instructions. */ DEF_TUNE (X86_TUNE_AVX256_MOVE_BY_PIECES, "avx256_move_by_pieces", diff --git a/gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-1.c b/gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-1.c new file mode 100644 index 00000000000..dcb074e7034 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-1.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=c86-4g-m7 -fdump-tree-vect-details" } */ +/* { dg-final { scan-tree-dump "loop vectorized using 32 byte vectors" "vect" } } */ + +int a[512], b[512]; + +void +foo (void) +{ + int i; + for (i = 0; i < 32; ++i) + { + b[i * 16 + 0] = a[i * 16 + 0]; + b[i * 16 + 1] = a[i * 16 + 0]; + b[i * 16 + 2] = a[i * 16 + 3]; + b[i * 16 + 3] = a[i * 16 + 5]; + b[i * 16 + 4] = a[i * 16 + 4]; + b[i * 16 + 5] = a[i * 16 + 6]; + b[i * 16 + 6] = a[i * 16 + 4]; + b[i * 16 + 7] = a[i * 16 + 9]; + b[i * 16 + 8] = a[i * 16 + 8]; + b[i * 16 + 9] = a[i * 16 + 8]; + b[i * 16 + 10] = a[i * 16 + 11]; + b[i * 16 + 11] = a[i * 16 + 13]; + b[i * 16 + 12] = a[i * 16 + 12]; + b[i * 16 + 13] = a[i * 16 + 14]; + b[i * 16 + 14] = a[i * 16 + 12]; + b[i * 16 + 15] = a[i * 16 + 14]; + } +} diff --git a/gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-2.c b/gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-2.c new file mode 100644 index 00000000000..ed92d525d8f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-2.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-march=c86-4g-m7 -O2 -fdump-tree-slp-details" } */ +/* { dg-final { scan-tree-dump-times {(?n)Detected avx512 cross-lane permutation} 1 "slp2" } } */ + +void +foo (double *a, double *__restrict b, int c, int n) +{ + a[0] = b[100] * b[4]; + a[1] = b[100] * b[5]; + a[2] = b[100] * b[6]; + a[3] = b[100] * b[7]; + a[4] = b[100] * b[0]; + a[5] = b[100] * b[1]; + a[6] = b[100] * b[2]; + a[7] = b[100] * b[3]; +} + +void +foo1 (double *a, double *__restrict b, int c, int n) +{ + a[0] = b[100] * b[0]; + a[1] = b[100] * b[1]; + a[2] = b[100] * b[3]; + a[3] = b[100] * b[2]; + a[4] = b[100] * b[4]; + a[5] = b[100] * b[5]; + a[6] = b[100] * b[7]; + a[7] = b[100] * b[6]; +} diff --git a/gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-3.c b/gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-3.c new file mode 100644 index 00000000000..f5903f6e08b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512_avoid_vec_perm-3.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=c86-4g-m7 -fdump-tree-vect-details" } */ +/* { dg-final { scan-tree-dump "loop vectorized using 64 byte vectors" "vect" { xfail *-*-* } } } */ + +/* This case only has false cross-lane permutations, which should ideally be + excluded from the loop vectorizer cost downgrade. The current loop-vect + handling does not distinguish false cross-lane permutations from real ones, + so the expected full-width vectorization is marked as xfail. */ + +int a[512], b[512]; + +void +foo (void) +{ + int i; + for (i = 0; i < 32; ++i) + { + b[i * 16 + 0] = a[i * 16 + 0]; + b[i * 16 + 1] = a[i * 16 + 0]; + b[i * 16 + 2] = a[i * 16 + 3]; + b[i * 16 + 3] = a[i * 16 + 3]; + b[i * 16 + 4] = a[i * 16 + 4]; + b[i * 16 + 5] = a[i * 16 + 6]; + b[i * 16 + 6] = a[i * 16 + 4]; + b[i * 16 + 7] = a[i * 16 + 6]; + b[i * 16 + 8] = a[i * 16 + 8]; + b[i * 16 + 9] = a[i * 16 + 8]; + b[i * 16 + 10] = a[i * 16 + 11]; + b[i * 16 + 11] = a[i * 16 + 11]; + b[i * 16 + 12] = a[i * 16 + 12]; + b[i * 16 + 13] = a[i * 16 + 14]; + b[i * 16 + 14] = a[i * 16 + 12]; + b[i * 16 + 15] = a[i * 16 + 14]; + } +} -- Gitee From 13ed0c94fdfee198b9c28538ea91ebdfd474486e Mon Sep 17 00:00:00 2001 From: Zhongjie Guo Date: Thu, 13 Aug 2026 16:45:19 +0800 Subject: [PATCH 2/2] [EulerGCC] Preserve SLP metadata for permuted-load costing EulerGCC GCC 12 lacks the later AVX256 vec_perm accounting framework. Preserve the SLP node alongside statement information so the backported AVX512 classifier receives load-permutation metadata. Signed-off-by: Zhongjie Guo (cherry picked from commit a78fb5d71be35e04c9c2d5038b0b042cc3e73e97) --- gcc/tree-vect-stmts.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc index 3099f67434a..b68eea5c15a 100644 --- a/gcc/tree-vect-stmts.cc +++ b/gcc/tree-vect-stmts.cc @@ -1142,7 +1142,9 @@ vect_model_load_cost (vec_info *vinfo, vect_transform_slp_perm_load (vinfo, slp_node, vNULL, NULL, vf, true, &n_perms, &n_loads); inside_cost += record_stmt_cost (cost_vec, n_perms, vec_perm, - first_stmt_info, 0, vect_body); + first_stmt_info, slp_node, + STMT_VINFO_VECTYPE (first_stmt_info), + 0, vect_body); /* And adjust the number of loads performed. This handles redundancies as well as loads that are later dead. */ @@ -13577,4 +13579,3 @@ vect_gen_len (tree len, tree start_index, tree end_index, tree len_limit) return stmts; } - -- Gitee