Hi Claudio,
> -----Original Message-----
> From: Claudio Bantaloukas via Sourceware Forge <forge-bot+rdfm@forge-
> stage.sourceware.org>
> Sent: 12 June 2026 11:51
> To: gcc-patches mailing list <[email protected]>
> Subject: [PATCH v1 1/1] aarch64: Add initial tuning model for cortex-a320
> core
>
> From: Claudio Bantaloukas <[email protected]>
>
> gcc/ChangeLog:
>
> * config/aarch64/aarch64-cores.def (cortex-a320): Update core.
> * config/aarch64/aarch64.cc: Add cortexa320.h.
> * config/aarch64/tuning_models/cortexa320.h: New file.
> ---
> gcc/config/aarch64/aarch64-cores.def | 2 +-
> gcc/config/aarch64/aarch64.cc | 1 +
> gcc/config/aarch64/tuning_models/cortexa320.h | 195
> ++++++++++++++++++
> 3 files changed, 197 insertions(+), 1 deletion(-)
> create mode 100644 gcc/config/aarch64/tuning_models/cortexa320.h
>
> diff --git a/gcc/config/aarch64/aarch64-cores.def
> b/gcc/config/aarch64/aarch64-cores.def
> index 2cae1a38a87d..0fce3204d1eb 100644
> --- a/gcc/config/aarch64/aarch64-cores.def
> +++ b/gcc/config/aarch64/aarch64-cores.def
> @@ -217,7 +217,7 @@ AARCH64_CORE("cortex-a720", cortexa720,
> cortexa57, V9_2A, (SVE2_BITPERM, MEMTA
> AARCH64_CORE("cortex-a720ae", cortexa720ae, cortexa57, V9_2A,
> (SVE2_BITPERM, MEMTAG, PROFILE), neoversen2, 0x41, 0xd89, -1)
> AARCH64_CORE("cortex-a725", cortexa725, cortexa57, V9_2A,
> (SVE2_BITPERM, MEMTAG, PROFILE), neoversen3, 0x41, 0xd87, -1)
>
> -AARCH64_CORE("cortex-a320", cortexa320, cortexa53, V9_2A,
> (SVE2_BITPERM, MEMTAG), cortexa53, 0x41, 0xd8f, -1)
> +AARCH64_CORE("cortex-a320", cortexa320, cortexa53, V9_2A,
> (SVE2_BITPERM, MEMTAG), cortexa320, 0x41, 0xd8f, -1)
>
> AARCH64_CORE("cortex-x2", cortexx2, cortexa57, V9A, (SVE2_BITPERM,
> MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd48, -1)
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 69530ea9d347..08746b657746 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -416,6 +416,7 @@ static const struct aarch64_flag_desc
> aarch64_tuning_flags[] =
> #include "tuning_models/generic.h"
> #include "tuning_models/generic_armv8_a.h"
> #include "tuning_models/generic_armv9_a.h"
> +#include "tuning_models/cortexa320.h"
> #include "tuning_models/cortexa35.h"
> #include "tuning_models/cortexa53.h"
> #include "tuning_models/cortexa57.h"
> diff --git a/gcc/config/aarch64/tuning_models/cortexa320.h
> b/gcc/config/aarch64/tuning_models/cortexa320.h
> new file mode 100644
> index 000000000000..2bd46a20da82
> --- /dev/null
> +++ b/gcc/config/aarch64/tuning_models/cortexa320.h
> @@ -0,0 +1,195 @@
> +/* Tuning model description for AArch64 architecture.
> + Copyright (C) 2009-2026 Free Software Foundation, Inc.
> +
> + This file is part of GCC.
> +
> + GCC is free software; you can redistribute it and/or modify it
> + under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3, or (at your option)
> + any later version.
> +
> + GCC is distributed in the hope that it will be useful, but
> + WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with GCC; see the file COPYING3. If not see
> + <http://www.gnu.org/licenses/>. */
> +
> +#ifndef GCC_AARCH64_H_CORTEXA320
> +#define GCC_AARCH64_H_CORTEXA320
> +
> +#include "generic.h"
> +
> +static const struct cpu_addrcost_table cortexa320_addrcost_table =
> +{
> + {
> + 1, /* hi */
> + 0, /* si */
> + 0, /* di */
> + 1, /* ti */
> + },
> + 0, /* pre_modify */
> + 0, /* post_modify */
> + 2, /* post_modify_ld3_st3 */
> + 2, /* post_modify_ld4_st4 */
> + 0, /* register_offset */
> + 0, /* register_sextend */
> + 0, /* register_zextend */
> + 0 /* imm_offset */
> +};
> +
> +static const struct cpu_regmove_cost cortexa320_regmove_cost =
> +{
> + 5, /* GP2GP */
> + /* Spilling to int<->fp instead of memory is recommended so set
> + realistic costs compared to memmov_cost. */
> + 7, /* GP2FP */
> + 7, /* FP2GP */
> + 7 /* FP2FP */
> +};
> +
Having GP2FP, FP2GP and FP2FP be as expensive looks a bit weird to me.
So a move within FPR is as expensive as changing from GPR to FPR?
Could you double check with the codesize before and after this change.
I'm concerned we may get more spills.
> +static const advsimd_vec_cost cortexa320_advsimd_vector_cost =
> +{
> + 3, /* int_stmt_cost */
> + 4, /* fp_stmt_cost */
> + 1, /* ld2_st2_permute_cost */
> + 2, /* ld3_st3_permute_cost */
> + 3, /* ld4_st4_permute_cost */
> + 3, /* permute_cost */
> + 3, /* reduc_i8_cost */
> + 4, /* reduc_i16_cost */
> + 4, /* reduc_i32_cost */
> + 3, /* reduc_i64_cost */
> + 12, /* reduc_f16_cost */
> + 8, /* reduc_f32_cost */
> + 4, /* reduc_f64_cost */
> + 0, /* store_elt_extra_cost */
> + /* This value is just inherited from the Cortex-A57 table. */
> + 8, /* vec_to_scalar_cost */
> + /* This depends very much on what the scalar value is and
> + where it comes from. E.g. some constants take two dependent
> + instructions or a load, while others might be moved from a GPR.
> + 4 seems to be a reasonable compromise in practice. */
> + 4, /* scalar_to_vec_cost */
> + 5, /* align_load_cost */
> + 5, /* unalign_load_cost */
> + /* Although stores have a latency of 2 and compete for the
> + vector pipes, in practice it's better not to model that. */
> + 2, /* unalign_store_cost */
> + 2 /* store_cost */
> +};
> +
> +static const sve_vec_cost cortexa320_sve_vector_cost =
> +{
> + {
> + 3, /* int_stmt_cost */
> + 4, /* fp_stmt_cost */
> + 1, /* ld2_st2_permute_cost */
> + 2, /* ld3_st3_permute_cost */
> + 3, /* ld4_st4_permute_cost */
> + 3, /* permute_cost */
> + /* Theoretically, a reduction involving 15 scalar ADDs could
> + complete in ~15 cycles and would have a cost of 15. [SU]ADDV
> + completes in 4 cycles, so give it a cost of 15 + -11. */
> + 4, /* reduc_i8_cost */
> + /* Likewise for 7 scalar ADDs (~7 cycles) vs. 4: 7 + -3. */
> + 4, /* reduc_i16_cost */
> + /* Likewise for 3 scalar ADDs (~3 cycles) vs. 4: 3 + 1. */
> + 4, /* reduc_i32_cost */
> + /* Likewise for 1 scalar ADD (~1 cycles) vs. 4: 1 + 3. */
> + 4, /* reduc_i64_cost */
> + /* Theoretically, a reduction involving 7 scalar FADDs could
> + complete in ~28 cycles and would have a cost of 28. FADDV
> + completes in 12 cycles, so give it a cost of 28 + -16. */
> + 12, /* reduc_f16_cost */
> + /* Likewise for 3 scalar FADDs (~12 cycles) vs. 8: 12 + -4. */
> + 8, /* reduc_f32_cost */
> + /* Likewise for 1 scalar FADD (~4 cycles) vs. 4: 4 + 0. */
> + 4, /* reduc_f64_cost */
> + 0, /* store_elt_extra_cost */
> + /* This value is just inherited from the Cortex-A57 table. */
> + 8, /* vec_to_scalar_cost */
> + /* See the comment above the Advanced SIMD versions. */
> + 4, /* scalar_to_vec_cost */
> + 5, /* align_load_cost */
> + 5, /* unalign_load_cost */
> + /* Although stores have a latency of 2 and compete for the
> + vector pipes, in practice it's better not to model that. */
> + 2, /* unalign_store_cost */
> + 2 /* store_cost */
> + },
> + 4, /* clast_cost */
> + 25, /* fadda_f16_cost */
> + 9, /* fadda_f32_cost */
> + 3, /* fadda_f64_cost */
> + /* A strided Advanced SIMD x64 load would take two parallel FP loads
> + (10 cycles) plus an insertion (3 cycles). Assume a 64-bit SVE gather
> + is 1 cycle more. The Advanced SIMD version is costed as 2 scalar loads
> + (cost 10) and a vec_construct (cost 3). Add a full vector operation
> + (cost 3) to that, to avoid the difference being lost in rounding.
> +
> + There is no easy comparison between a strided Advanced SIMD x32 load
> + and an SVE 32-bit gather, but cost an SVE 32-bit gather as 1 vector
> + operation more than a 64-bit gather. */
> + 16, /* gather_load_x32_cost */
> + 19, /* gather_load_x64_cost */
> + 48, /* gather_load_x32_init_cost */
> + 38, /* gather_load_x64_init_cost */
> + 0 /* scatter_store_elt_cost */
> +};
> +
> +/* Cortexa320 costs for vector insn classes. */
> +static const struct cpu_vector_cost cortexa320_vector_cost =
> +{
> + 1, /* scalar_int_stmt_cost */
> + 2, /* scalar_fp_stmt_cost */
> + 4, /* scalar_load_cost */
> + 1, /* scalar_store_cost */
> + 1, /* cond_taken_branch_cost */
> + 1, /* cond_not_taken_branch_cost */
> + &cortexa320_advsimd_vector_cost, /* advsimd */
> + &cortexa320_sve_vector_cost, /* sve */
> + nullptr /* issue_info */
> +};
> +
> +static const struct tune_params cortexa320_tunings =
> +{
> + &cortexa76_extra_costs,
> + &cortexa320_addrcost_table,
> + &cortexa320_regmove_cost,
> + &cortexa320_vector_cost,
> + &generic_branch_cost,
> + &generic_approx_modes,
> + SVE_128, /* sve_width */
> + { 4, /* load_int. */
> + 1, /* store_int. */
> + 5, /* load_fp. */
> + 2, /* store_fp. */
> + 4, /* load_pred. */
> + 1 /* store_pred. */
> + }, /* memmov_cost. */
> + 1, /* issue_rate */
> + AARCH64_FUSE_NEOVERSE_BASE, /* fusible_ops */
> + "32:16", /* function_align. */
> + "4", /* jump_align. */
> + "32:16", /* loop_align. */
> + 1, /* int_reassoc_width. */
> + 1, /* fp_reassoc_width. */
> + 1, /* fma_reassoc_width. */
> + 1, /* vec_reassoc_width. */
Do you really want these 1? The core does have some MAC forwarding,
but even without it you do want MLA/FMAs.
I suggest copying the values from generic_armv8 which are conservative.
I also suggest if you haven't done any experiment yet on codesize to
just use the regmove_cost from generic_armv8 which is the default and
one we know work well.
We can revisit these values later then.
OK with those changes.
Thanks,
Tamar
> + 2, /* min_div_recip_mul_sf. */
> + 2, /* min_div_recip_mul_df. */
> + 0, /* max_case_values. */
> + tune_params::AUTOPREFETCHER_WEAK, /* autoprefetcher_model. */
> + (AARCH64_EXTRA_TUNE_CHEAP_SHIFT_EXTEND
> + | AARCH64_EXTRA_TUNE_CSE_SVE_VL_CONSTANTS
> + | AARCH64_EXTRA_TUNE_MATCHED_VECTOR_THROUGHPUT), /*
> tune_flags. */
> + &generic_armv9a_prefetch_tune,
> + AARCH64_LDP_STP_POLICY_ALWAYS, /* ldp_policy_model. */
> + AARCH64_LDP_STP_POLICY_ALWAYS, /* stp_policy_model. */
> + nullptr /* dispatch_constraints. */
> +};
> +
> +#endif /* GCC_AARCH64_H_CORTEXA320. */
> --
> 2.54.0