Hi Tamar, Ping.
Thanks, Soumya > On 28 Oct 2025, at 2:55 PM, Soumya AR <[email protected]> wrote: > > > >> On 14 Oct 2025, at 9:07 PM, Tamar Christina <[email protected]> wrote: >> >> External email: Use caution opening links or attachments >> >> >>> -----Original Message----- >>> From: Soumya AR <[email protected]> >>> Sent: 13 October 2025 09:44 >>> To: Tamar Christina <[email protected]> >>> Cc: [email protected]; Kyrylo Tkachov <[email protected]>; >>> [email protected]; [email protected] >>> Subject: Re: [v3 PATCH 4/6] aarch64: Enable parsing of user-provided >>> AArch64 CPU tuning parameters >>> Importance: High >>> >>> >>> >>>> On 29 Sep 2025, at 5:29 PM, Tamar Christina <[email protected]> >>> wrote: >>>> >>>> External email: Use caution opening links or attachments >>>> >>>> >>>> Hi Soumya, >>>> >>>>> -----Original Message----- >>>>> From: [email protected] <[email protected]> >>>>> Sent: 25 August 2025 12:00 >>>>> To: [email protected] >>>>> Cc: [email protected]; [email protected]; >>> [email protected] >>>>> Subject: [v3 PATCH 4/6] aarch64: Enable parsing of user-provided AArch64 >>>>> CPU tuning parameters >>>>> >>>>> From: Soumya AR <[email protected]> >>>>> >>>>> This patch adds support for loading custom CPU tuning parameters from a >>>>> JSON >>>>> file for AArch64 targets. The '-muser-provided-CPU=' flag accepts a user >>>>> provided JSON file and overrides the internal tuning parameters at GCC >>>>> runtime. >>>>> >>>>> This patch was bootstrapped and regtested on aarch64-linux-gnu, no >>>>> regression. >>>>> >>>>> Signed-off-by: Soumya AR <[email protected]> >>>>> >>>>> gcc/ChangeLog: >>>>> >>>>> * config.gcc: Add aarch64-json-tunings-parser.o. >>>>> * config/aarch64/aarch64.cc (aarch64_override_options_internal): >>>>> Invoke >>>>> aarch64_load_tuning_params_from_json if -muser-provided-CPU= is >>>>> specified. >>>>> * config/aarch64/aarch64.opt: New option. >>>>> * config/aarch64/t-aarch64 (aarch64-json-tunings-parser.o): New >>>>> define. >>>>> * selftest-run-tests.cc (selftest::run_tests): Add >>>>> json_tunings_tests(). >>>>> * selftest.h (json_tunings_tests): Declare. >>>>> * config/aarch64/aarch64-json-schema.h: New file. >>>>> * config/aarch64/aarch64-json-tunings-parser.cc: New file. >>>>> * config/aarch64/aarch64-json-tunings-parser.h: New file. >>>>> --- >>>>> gcc/config.gcc | 2 +- >>>>> gcc/config/aarch64/aarch64-json-schema.h | 261 +++++ >>>>> .../aarch64/aarch64-json-tunings-parser.cc | 902 ++++++++++++++++++ >>>>> .../aarch64/aarch64-json-tunings-parser.h | 29 + >>>>> gcc/config/aarch64/aarch64.cc | 16 + >>>>> gcc/config/aarch64/aarch64.opt | 4 + >>>>> gcc/config/aarch64/t-aarch64 | 10 + >>>>> gcc/selftest-run-tests.cc | 1 + >>>>> gcc/selftest.h | 1 + >>>>> 9 files changed, 1225 insertions(+), 1 deletion(-) >>>>> create mode 100644 gcc/config/aarch64/aarch64-json-schema.h >>>>> create mode 100644 gcc/config/aarch64/aarch64-json-tunings-parser.cc >>>>> create mode 100644 gcc/config/aarch64/aarch64-json-tunings-parser.h >>>>> >>>>> diff --git a/gcc/config.gcc b/gcc/config.gcc >>>>> index 698a7bb4b73..39790adb16a 100644 >>>>> --- a/gcc/config.gcc >>>>> +++ b/gcc/config.gcc >>>>> @@ -351,7 +351,7 @@ aarch64*-*-*) >>>>> c_target_objs="aarch64-c.o" >>>>> cxx_target_objs="aarch64-c.o" >>>>> d_target_objs="aarch64-d.o" >>>>> - extra_objs="aarch64-builtins.o aarch-common.o aarch64-elf- >>>>> metadata.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64- >>>>> sve-builtins-base.o aarch64-sve-builtins-sve2.o aarch64-sve-builtins-sme.o >>>>> cortex-a57-fma-steering.o aarch64-speculation.o aarch-bti-insert.o >>> aarch64- >>>>> early-ra.o aarch64-ldp-fusion.o aarch64-json-tunings-printer.o" >>>>> + extra_objs="aarch64-builtins.o aarch-common.o aarch64-elf- >>>>> metadata.o aarch64-sve-builtins.o aarch64-sve-builtins-shapes.o aarch64- >>>>> sve-builtins-base.o aarch64-sve-builtins-sve2.o aarch64-sve-builtins-sme.o >>>>> cortex-a57-fma-steering.o aarch64-speculation.o aarch-bti-insert.o >>> aarch64- >>>>> early-ra.o aarch64-ldp-fusion.o aarch64-json-tunings-printer.o aarch64- >>> json- >>>>> tunings-parser.o" >>>>> target_gtfiles="\$(srcdir)/config/aarch64/aarch64-protos.h >>>>> \$(srcdir)/config/aarch64/aarch64-builtins.h >>>>> \$(srcdir)/config/aarch64/aarch64-builtins.cc >>>>> \$(srcdir)/config/aarch64/aarch64-sve-builtins.h >>>>> \$(srcdir)/config/aarch64/aarch64-sve-builtins.cc" >>>>> target_has_targetm_common=yes >>>>> ;; >>>>> diff --git a/gcc/config/aarch64/aarch64-json-schema.h >>>>> b/gcc/config/aarch64/aarch64-json-schema.h >>>>> new file mode 100644 >>>>> index 00000000000..873756b01a5 >>>>> --- /dev/null >>>>> +++ b/gcc/config/aarch64/aarch64-json-schema.h >>>>> @@ -0,0 +1,261 @@ >>>>> +/* Raw JSON schema for the AArch64 tuning parameters. >>>>> + Copyright The GNU Toolchain Authors. >>>> >>>> Same as the others the copyright year is missing. >>>> >>> >>> I was confused about this too, currently all instances of >>> "Copyright The GNU Toolchain Authors” in GCC don't mention the year. >>> >>> Should we implement this in all files moving forward? >>> >> >> I reached out to ask about this. It turns out that files contributed under >> DCO >> don't need the dates. So this is fine. >> >>> >>>> I'm still going through the code, but notice we don't write a >>>> gcc version out in the json. But the parser is rather unforgiving >>>> to mismatch in expected formats. (i.e. we ICE). >>>> >>>> I think we should write out the version, and reject reading in any >>>> jsons where the versions don't match with a friendly error message. >>>> >>> >>> Thanks, this is a nice suggestion. I have a local working copy that now adds >>> a metadata object to the schema. >>> >>> Currently, it looks something like this: >>> >>> { >>> "metadata": { >>> "gcc_version": "string" >>> }, >>> "tune_params": { ... } >>> } >>> >>> If need be, I can just remove the "metadata" object and directly have a >>> gcc_version string in the root object. The former felt cleaner, let me know >>> which you prefer. >> >> I'm fine with this. I wonder if the gcc_version should be only major version? >> Because we don't tend to change the structures on released versions, but >> there if it breaks during trunk builds we can maybe just issue a warning? >> >> What do you think? >> > > Hi Tamar, > > Yes, I prefer this as well. I'm attaching updated patches with the changes > you suggested. I've also updated aarch64_run_selftests to call the parser > self tests as suggested by Kyrill. > Attaching an interim updated patch series here. Will update with more changes > once you are done reviewing. Thank you! > > Best, > Soumya > >> I'll get through the last of this review this week. >> >> Thanks, >> Tamar >>> >>> Thanks, >>> Soumya >>> >>>> Thanks, >>>> Tamar >>>> >>>>> + >>>>> + 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 AARCH64_JSON_SCHEMA_H >>>>> +#define AARCH64_JSON_SCHEMA_H >>>>> + >>>>> +static const char *schema_json = R"json( >>>>> +{ >>>>> + "tune_params": { >>>>> + "insn_extra_cost": { >>>>> + "alu": { >>>>> + "arith": "int", >>>>> + "logical": "int", >>>>> + "shift": "int", >>>>> + "shift_reg": "int", >>>>> + "arith_shift": "int", >>>>> + "arith_shift_reg": "int", >>>>> + "log_shift": "int", >>>>> + "log_shift_reg": "int", >>>>> + "extend": "int", >>>>> + "extend_arith": "int", >>>>> + "bfi": "int", >>>>> + "bfx": "int", >>>>> + "clz": "int", >>>>> + "rev": "int", >>>>> + "non_exec": "int", >>>>> + "non_exec_costs_exec": "boolean" >>>>> + }, >>>>> + "mult": [ >>>>> + { >>>>> + "simple": "int", >>>>> + "flag_setting": "int", >>>>> + "extend": "int", >>>>> + "add": "int", >>>>> + "extend_add": "int", >>>>> + "idiv": "int" >>>>> + }, >>>>> + { >>>>> + "simple": "int", >>>>> + "flag_setting": "int", >>>>> + "extend": "int", >>>>> + "add": "int", >>>>> + "extend_add": "int", >>>>> + "idiv": "int" >>>>> + } >>>>> + ], >>>>> + "ldst": { >>>>> + "load": "int", >>>>> + "load_sign_extend": "int", >>>>> + "ldrd": "int", >>>>> + "ldm_1st": "int", >>>>> + "ldm_regs_per_insn_1st": "int", >>>>> + "ldm_regs_per_insn_subsequent": "int", >>>>> + "loadf": "int", >>>>> + "loadd": "int", >>>>> + "load_unaligned": "int", >>>>> + "store": "int", >>>>> + "strd": "int", >>>>> + "stm_1st": "int", >>>>> + "stm_regs_per_insn_1st": "int", >>>>> + "stm_regs_per_insn_subsequent": "int", >>>>> + "storef": "int", >>>>> + "stored": "int", >>>>> + "store_unaligned": "int", >>>>> + "loadv": "int", >>>>> + "storev": "int" >>>>> + }, >>>>> + "fp": [ >>>>> + { >>>>> + "div": "int", >>>>> + "mult": "int", >>>>> + "mult_addsub": "int", >>>>> + "fma": "int", >>>>> + "addsub": "int", >>>>> + "fpconst": "int", >>>>> + "neg": "int", >>>>> + "compare": "int", >>>>> + "widen": "int", >>>>> + "narrow": "int", >>>>> + "toint": "int", >>>>> + "fromint": "int", >>>>> + "roundint": "int" >>>>> + }, >>>>> + { >>>>> + "div": "int", >>>>> + "mult": "int", >>>>> + "mult_addsub": "int", >>>>> + "fma": "int", >>>>> + "addsub": "int", >>>>> + "fpconst": "int", >>>>> + "neg": "int", >>>>> + "compare": "int", >>>>> + "widen": "int", >>>>> + "narrow": "int", >>>>> + "toint": "int", >>>>> + "fromint": "int", >>>>> + "roundint": "int" >>>>> + } >>>>> + ], >>>>> + "vect": { >>>>> + "alu": "int", >>>>> + "mult": "int", >>>>> + "movi": "int", >>>>> + "dup": "int", >>>>> + "extract": "int" >>>>> + } >>>>> + }, >>>>> + "addr_cost": { >>>>> + "addr_scale_costs": { >>>>> + "hi": "int", >>>>> + "si": "int", >>>>> + "di": "int", >>>>> + "ti": "int" >>>>> + }, >>>>> + "pre_modify": "int", >>>>> + "post_modify": "int", >>>>> + "post_modify_ld3_st3": "int", >>>>> + "post_modify_ld4_st4": "int", >>>>> + "register_offset": "int", >>>>> + "register_sextend": "int", >>>>> + "register_zextend": "int", >>>>> + "imm_offset": "int" >>>>> + }, >>>>> + "regmove_cost": { >>>>> + "GP2GP": "int", >>>>> + "GP2FP": "int", >>>>> + "FP2GP": "int", >>>>> + "FP2FP": "int" >>>>> + }, >>>>> + "vec_costs": { >>>>> + "scalar_int_stmt_cost": "int", >>>>> + "scalar_fp_stmt_cost": "int", >>>>> + "scalar_load_cost": "int", >>>>> + "scalar_store_cost": "int", >>>>> + "cond_taken_branch_cost": "int", >>>>> + "cond_not_taken_branch_cost": "int", >>>>> + "advsimd": { >>>>> + "int_stmt_cost": "int", >>>>> + "fp_stmt_cost": "int", >>>>> + "ld2_st2_permute_cost": "int", >>>>> + "ld3_st3_permute_cost": "int", >>>>> + "ld4_st4_permute_cost": "int", >>>>> + "permute_cost": "int", >>>>> + "reduc_i8_cost": "int", >>>>> + "reduc_i16_cost": "int", >>>>> + "reduc_i32_cost": "int", >>>>> + "reduc_i64_cost": "int", >>>>> + "reduc_f16_cost": "int", >>>>> + "reduc_f32_cost": "int", >>>>> + "reduc_f64_cost": "int", >>>>> + "store_elt_extra_cost": "int", >>>>> + "vec_to_scalar_cost": "int", >>>>> + "scalar_to_vec_cost": "int", >>>>> + "align_load_cost": "int", >>>>> + "unalign_load_cost": "int", >>>>> + "unalign_store_cost": "int", >>>>> + "store_cost": "int" >>>>> + }, >>>>> + "sve": { >>>>> + "clast_cost": "int", >>>>> + "fadda_f16_cost": "int", >>>>> + "fadda_f32_cost": "int", >>>>> + "fadda_f64_cost": "int", >>>>> + "gather_load_x32_cost": "uint", >>>>> + "gather_load_x64_cost": "uint", >>>>> + "gather_load_x32_init_cost": "int", >>>>> + "gather_load_x64_init_cost": "int", >>>>> + "scatter_store_elt_cost": "int" >>>>> + }, >>>>> + "issue_info": { >>>>> + "scalar": { >>>>> + "loads_stores_per_cycle": "uint", >>>>> + "stores_per_cycle": "uint", >>>>> + "general_ops_per_cycle": "uint", >>>>> + "fp_simd_load_general_ops": "uint", >>>>> + "fp_simd_store_general_ops": "uint" >>>>> + }, >>>>> + "advsimd": { >>>>> + "loads_stores_per_cycle": "uint", >>>>> + "stores_per_cycle": "uint", >>>>> + "general_ops_per_cycle": "uint", >>>>> + "fp_simd_load_general_ops": "uint", >>>>> + "fp_simd_store_general_ops": "uint", >>>>> + "ld2_st2_general_ops": "uint", >>>>> + "ld3_st3_general_ops": "uint", >>>>> + "ld4_st4_general_ops": "uint" >>>>> + }, >>>>> + "sve": { >>>>> + "loads_stores_per_cycle": "uint", >>>>> + "stores_per_cycle": "uint", >>>>> + "general_ops_per_cycle": "uint", >>>>> + "fp_simd_load_general_ops": "uint", >>>>> + "fp_simd_store_general_ops": "uint", >>>>> + "ld2_st2_general_ops": "uint", >>>>> + "ld3_st3_general_ops": "uint", >>>>> + "ld4_st4_general_ops": "uint", >>>>> + "pred_ops_per_cycle": "uint", >>>>> + "while_pred_ops": "uint", >>>>> + "int_cmp_pred_ops": "uint", >>>>> + "fp_cmp_pred_ops": "uint", >>>>> + "gather_scatter_pair_general_ops": "uint", >>>>> + "gather_scatter_pair_pred_ops": "uint" >>>>> + } >>>>> + } >>>>> + }, >>>>> + "branch_costs": { "predictable": "int", "unpredictable": "int" }, >>>>> + "approx_modes": { "division": "int", "sqrt": "int", "recip_sqrt": >>>>> "int" }, >>>>> + "sve_width": "uint", >>>>> + "memmov_cost": { >>>>> + "load_int": "int", >>>>> + "store_int": "int", >>>>> + "load_fp": "int", >>>>> + "store_fp": "int", >>>>> + "load_pred": "int", >>>>> + "store_pred": "int" >>>>> + }, >>>>> + "issue_rate": "int", >>>>> + "fusible_ops": "uint", >>>>> + "function_align": "string", >>>>> + "jump_align": "string", >>>>> + "loop_align": "string", >>>>> + "int_reassoc_width": "int", >>>>> + "fp_reassoc_width": "int", >>>>> + "fma_reassoc_width": "int", >>>>> + "vec_reassoc_width": "int", >>>>> + "min_div_recip_mul_sf": "int", >>>>> + "min_div_recip_mul_df": "int", >>>>> + "max_case_values": "uint", >>>>> + "autoprefetcher_model": "enum", >>>>> + "extra_tuning_flags": "uint", >>>>> + "prefetch": { >>>>> + "num_slots": "int", >>>>> + "l1_cache_size": "int", >>>>> + "l1_cache_line_size": "int", >>>>> + "l2_cache_size": "int", >>>>> + "prefetch_dynamic_strides": "boolean", >>>>> + "minimum_stride": "int", >>>>> + "default_opt_level": "int" >>>>> + }, >>>>> + "ldp_policy_model": "enum", >>>>> + "stp_policy_model": "enum" >>>>> + } >>>>> +})json"; >>>>> + >>>>> +#endif >>>>> \ No newline at end of file >>>>> diff --git a/gcc/config/aarch64/aarch64-json-tunings-parser.cc >>>>> b/gcc/config/aarch64/aarch64-json-tunings-parser.cc >>>>> new file mode 100644 >>>>> index 00000000000..23e742d437f >>>>> --- /dev/null >>>>> +++ b/gcc/config/aarch64/aarch64-json-tunings-parser.cc >>>>> @@ -0,0 +1,902 @@ >>>>> +/* Routines to parse the AArch64 tuning parameters from a JSON file. >>>>> + Copyright The GNU Toolchain Authors. >>>>> + >>>>> + 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/>. */ >>>>> + >>>>> +#define INCLUDE_STRING >>>>> +#define INCLUDE_VECTOR >>>>> +#define INCLUDE_TYPE_TRAITS >>>>> +#include "config.h" >>>>> +#include "system.h" >>>>> +#include "coretypes.h" >>>>> +#include "tm.h" >>>>> +#include "diagnostic-core.h" >>>>> +#include "json-parsing.h" >>>>> +#include "aarch64-json-schema.h" >>>>> +#include "aarch64-json-tunings-parser.h" >>>>> +#include "aarch64-protos.h" >>>>> +#include "config/arm/aarch-common-protos.h" >>>>> +#include "selftest.h" >>>>> + >>>>> +#define PARSE_INTEGER_FIELD(obj, key, member) >>>>> \ >>>>> + { >>>>> \ >>>>> + const json::value *val = obj->get (key); >>>>> \ >>>>> + if (val) >>>>> \ >>>>> + member = extract_integer (val); >>>>> \ >>>>> + } >>>>> + >>>>> +#define PARSE_BOOLEAN_FIELD(obj, key, member) >>>>> \ >>>>> + { >>>>> \ >>>>> + const json::value *val = obj->get (key); >>>>> \ >>>>> + if (val) >>>>> \ >>>>> + member = extract_boolean (val); >>>>> \ >>>>> + } >>>>> + >>>>> +#define PARSE_STRING_FIELD(obj, key, member) >>>>> \ >>>>> + { >>>>> \ >>>>> + const json::value *val = obj->get (key); >>>>> \ >>>>> + if (val) >>>>> \ >>>>> + member = extract_string (val); >>>>> \ >>>>> + } >>>>> + >>>>> +#define PARSE_OBJECT(obj, key, member, parse_func) >>>>> \ >>>>> + { >>>>> \ >>>>> + const json::value *field_value = obj->get (key); >>>>> \ >>>>> + if (field_value) >>>>> \ >>>>> + if (auto *field_obj = dyn_cast<const json::object *> >>>>> (field_value)) \ >>>>> + parse_object_helper (field_obj, (member), (parse_func)); >>>>> \ >>>>> + } >>>>> + >>>>> +#define PARSE_ARRAY_FIELD(obj, key, member, parse_func) >>>>> \ >>>>> + { >>>>> \ >>>>> + const json::value *field_value = obj->get (key); >>>>> \ >>>>> + if (field_value) >>>>> \ >>>>> + if (auto *field_array = dyn_cast<const json::array *> >>>>> (field_value)) \ >>>>> + for (size_t i = 0; i < field_array->size (); ++i) >>>>> \ >>>>> + { >>>>> \ >>>>> + const json::value *elem = field_array->get (i); >>>>> \ >>>>> + if (elem) >>>>> \ >>>>> + if (auto *array_obj = dyn_cast<const json::object *> (elem)) >>>>> \ >>>>> + parse_func (array_obj, member[i]); >>>>> \ >>>>> + } >>>>> \ >>>>> + } >>>>> + >>>>> +#define PARSE_ENUM_FIELD(obj, key, member, mappings) >>>>> \ >>>>> + parse_enum_field (obj, key, member, mappings, >>>>> \ >>>>> + sizeof (mappings) / sizeof (mappings[0])) >>>>> + >>>>> +/* Type alias for parse function pointer. */ >>>>> +template <typename T> >>>>> +using parse_func_type >>>>> + = void (*) (const json::object *, >>>>> + std::remove_const_t<std::remove_pointer_t<T>> &); >>>>> + >>>>> +/* Parse JSON object into non-pointer member type. */ >>>>> +template <typename T> >>>>> +static std::enable_if_t<!std::is_pointer<T>::value> >>>>> +parse_object_helper (const json::object *field_obj, T &member, >>>>> + parse_func_type<T> parse_func) >>>>> +{ >>>>> + parse_func (field_obj, member); >>>>> +} >>>>> + >>>>> +/* Parse JSON object into a const pointer member by creating a temp >>> copy. >>>>> */ >>>>> +template <typename T> >>>>> +static std::enable_if_t<std::is_pointer<T>::value >>>>> + && std::is_const<std::remove_pointer_t<T>>::value> >>>>> +parse_object_helper (const json::object *field_obj, T &member, >>>>> + parse_func_type<T> parse_func) >>>>> +{ >>>>> + if (!member) >>>>> + return; >>>>> + >>>>> + /* Use static storage for the non-const copy. >>>>> + This works because tune_params does not have nested structures of >>> the >>>>> + same type, but has room for errors if we end up having pointers to >>>>> the >>>>> + same structure at some point. */ >>>>> + static bool already_initialized = false; >>>>> + if (already_initialized) >>>>> + { >>>>> + error ("static storage conflict - multiple pointer members of the " >>>>> + "same type cannot be parsed"); >>>>> + return; >>>>> + } >>>>> + already_initialized = true; >>>>> + using NonConstType = std::remove_const_t<std::remove_pointer_t<T>>; >>>>> + static NonConstType new_obj = *member; >>>>> + parse_func (field_obj, new_obj); >>>>> + member = &new_obj; >>>>> +} >>>>> + >>>>> +/* Extract string value from JSON, returning allocated C string. */ >>>>> +char * >>>>> +extract_string (const json::value *val) >>>>> +{ >>>>> + if (auto *string_val = dyn_cast<const json::string *> (val)) >>>>> + return xstrdup (string_val->get_string ()); >>>>> + warning (0, "expected a string but got something else or NULL"); >>>>> + return nullptr; >>>>> +} >>>>> + >>>>> +/* Extract integer value from JSON. */ >>>>> +int >>>>> +extract_integer (const json::value *val) >>>>> +{ >>>>> + if (auto *int_val = dyn_cast<const json::integer_number *> (val)) >>>>> + { >>>>> + long value = int_val->get (); >>>>> + if (value > INT_MAX) >>>>> + { >>>>> + error ("value exceeds %<INT_MAX%>"); >>>>> + return 0; >>>>> + } >>>>> + return value; >>>>> + } >>>>> + warning (0, "expected an integer value but got something else or >>>>> NULL"); >>>>> + return 0; >>>>> +} >>>>> + >>>>> +/* Extract boolean value from JSON literal. */ >>>>> +bool >>>>> +extract_boolean (const json::value *val) >>>>> +{ >>>>> + if (auto *literal_val = dyn_cast<const json::literal *> (val)) >>>>> + { >>>>> + json::kind kind = literal_val->get_kind (); >>>>> + if (kind == json::JSON_TRUE || kind == json::JSON_FALSE) >>>>> + return (kind == json::JSON_TRUE); >>>>> + } >>>>> + warning (0, "expected a boolean value but got something else or NULL"); >>>>> + return false; >>>>> +} >>>>> + >>>>> +template <typename EnumType> struct enum_mapping >>>>> +{ >>>>> + const char *name; >>>>> + EnumType value; >>>>> +}; >>>>> + >>>>> +/* Parse JSON string field into enum value using string-to-enum mappings. >>>>> */ >>>>> +template <typename EnumType> >>>>> +static void >>>>> +parse_enum_field (const json::object *jo, const std::string &key, >>>>> + EnumType &enum_var, const enum_mapping<EnumType> >>>>> *mappings, >>>>> + size_t num_mappings) >>>>> +{ >>>>> + const json::value *field_value = jo->get (key.c_str ()); >>>>> + if (!field_value) >>>>> + return; >>>>> + >>>>> + auto *string_val = dyn_cast<const json::string *> (field_value); >>>>> + if (!string_val) >>>>> + { >>>>> + warning (0, "expected string for enum field %s", key.c_str ()); >>>>> + enum_var = mappings[0].value; >>>>> + return; >>>>> + } >>>>> + >>>>> + const char *field_string = string_val->get_string (); >>>>> + for (size_t i = 0; i < num_mappings; ++i) >>>>> + { >>>>> + if (strcmp (field_string, mappings[i].name) == 0) >>>>> + { >>>>> + enum_var = mappings[i].value; >>>>> + return; >>>>> + } >>>>> + } >>>>> + >>>>> + warning (0, "%s not recognized, defaulting to %qs", key.c_str (), >>>>> + mappings[0].name); >>>>> + enum_var = mappings[0].value; >>>>> +} >>>>> + >>>>> +/* Enum mappings for known tuning parameter enums. */ >>>>> +static const >>> enum_mapping<tune_params::aarch64_autoprefetch_model> >>>>> + autoprefetcher_model_mappings[] >>>>> + = {{"AUTOPREFETCHER_OFF", tune_params::AUTOPREFETCHER_OFF}, >>>>> + {"AUTOPREFETCHER_WEAK", tune_params::AUTOPREFETCHER_WEAK}, >>>>> + {"AUTOPREFETCHER_STRONG", >>>>> tune_params::AUTOPREFETCHER_STRONG}}; >>>>> + >>>>> +static const enum_mapping<aarch64_ldp_stp_policy> >>>>> ldp_policy_model_mappings[] >>>>> + = {{"AARCH64_LDP_STP_POLICY_DEFAULT", >>>>> AARCH64_LDP_STP_POLICY_DEFAULT}, >>>>> + {"AARCH64_LDP_STP_POLICY_ALIGNED", >>>>> AARCH64_LDP_STP_POLICY_ALIGNED}, >>>>> + {"AARCH64_LDP_STP_POLICY_ALWAYS", >>>>> AARCH64_LDP_STP_POLICY_ALWAYS}, >>>>> + {"AARCH64_LDP_STP_POLICY_NEVER", >>>>> AARCH64_LDP_STP_POLICY_NEVER}}; >>>>> + >>>>> +static const enum_mapping<aarch64_ldp_stp_policy> >>>>> stp_policy_model_mappings[] >>>>> + = {{"AARCH64_LDP_STP_POLICY_DEFAULT", >>>>> AARCH64_LDP_STP_POLICY_DEFAULT}, >>>>> + {"AARCH64_LDP_STP_POLICY_ALIGNED", >>>>> AARCH64_LDP_STP_POLICY_ALIGNED}, >>>>> + {"AARCH64_LDP_STP_POLICY_ALWAYS", >>>>> AARCH64_LDP_STP_POLICY_ALWAYS}, >>>>> + {"AARCH64_LDP_STP_POLICY_NEVER", >>>>> AARCH64_LDP_STP_POLICY_NEVER}}; >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_insn_extra_cost_alu (const json::object *jo, T &alu) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "arith", alu.arith); >>>>> + PARSE_INTEGER_FIELD (jo, "logical", alu.logical); >>>>> + PARSE_INTEGER_FIELD (jo, "shift", alu.shift); >>>>> + PARSE_INTEGER_FIELD (jo, "shift_reg", alu.shift_reg); >>>>> + PARSE_INTEGER_FIELD (jo, "arith_shift", alu.arith_shift); >>>>> + PARSE_INTEGER_FIELD (jo, "arith_shift_reg", alu.arith_shift_reg); >>>>> + PARSE_INTEGER_FIELD (jo, "log_shift", alu.log_shift); >>>>> + PARSE_INTEGER_FIELD (jo, "log_shift_reg", alu.log_shift_reg); >>>>> + PARSE_INTEGER_FIELD (jo, "extend", alu.extend); >>>>> + PARSE_INTEGER_FIELD (jo, "extend_arith", alu.extend_arith); >>>>> + PARSE_INTEGER_FIELD (jo, "bfi", alu.bfi); >>>>> + PARSE_INTEGER_FIELD (jo, "bfx", alu.bfx); >>>>> + PARSE_INTEGER_FIELD (jo, "clz", alu.clz); >>>>> + PARSE_INTEGER_FIELD (jo, "rev", alu.rev); >>>>> + PARSE_INTEGER_FIELD (jo, "non_exec", alu.non_exec); >>>>> + PARSE_BOOLEAN_FIELD (jo, "non_exec_costs_exec", >>>>> alu.non_exec_costs_exec); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_insn_extra_cost_mult_element (const json::object *jo, T >>>>> &mult_element) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "simple", mult_element.simple); >>>>> + PARSE_INTEGER_FIELD (jo, "flag_setting", mult_element.flag_setting); >>>>> + PARSE_INTEGER_FIELD (jo, "extend", mult_element.extend); >>>>> + PARSE_INTEGER_FIELD (jo, "add", mult_element.add); >>>>> + PARSE_INTEGER_FIELD (jo, "extend_add", mult_element.extend_add); >>>>> + PARSE_INTEGER_FIELD (jo, "idiv", mult_element.idiv); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_insn_extra_cost_ldst (const json::object *jo, T &ldst) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "load", ldst.load); >>>>> + PARSE_INTEGER_FIELD (jo, "load_sign_extend", ldst.load_sign_extend); >>>>> + PARSE_INTEGER_FIELD (jo, "ldrd", ldst.ldrd); >>>>> + PARSE_INTEGER_FIELD (jo, "ldm_1st", ldst.ldm_1st); >>>>> + PARSE_INTEGER_FIELD (jo, "ldm_regs_per_insn_1st", >>>>> ldst.ldm_regs_per_insn_1st); >>>>> + PARSE_INTEGER_FIELD (jo, "ldm_regs_per_insn_subsequent", >>>>> + ldst.ldm_regs_per_insn_subsequent); >>>>> + PARSE_INTEGER_FIELD (jo, "loadf", ldst.loadf); >>>>> + PARSE_INTEGER_FIELD (jo, "loadd", ldst.loadd); >>>>> + PARSE_INTEGER_FIELD (jo, "load_unaligned", ldst.load_unaligned); >>>>> + PARSE_INTEGER_FIELD (jo, "store", ldst.store); >>>>> + PARSE_INTEGER_FIELD (jo, "strd", ldst.strd); >>>>> + PARSE_INTEGER_FIELD (jo, "stm_1st", ldst.stm_1st); >>>>> + PARSE_INTEGER_FIELD (jo, "stm_regs_per_insn_1st", >>>>> ldst.stm_regs_per_insn_1st); >>>>> + PARSE_INTEGER_FIELD (jo, "stm_regs_per_insn_subsequent", >>>>> + ldst.stm_regs_per_insn_subsequent); >>>>> + PARSE_INTEGER_FIELD (jo, "storef", ldst.storef); >>>>> + PARSE_INTEGER_FIELD (jo, "stored", ldst.stored); >>>>> + PARSE_INTEGER_FIELD (jo, "store_unaligned", ldst.store_unaligned); >>>>> + PARSE_INTEGER_FIELD (jo, "loadv", ldst.loadv); >>>>> + PARSE_INTEGER_FIELD (jo, "storev", ldst.storev); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_insn_extra_cost_fp_element (const json::object *jo, T >>> &fp_element) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "div", fp_element.div); >>>>> + PARSE_INTEGER_FIELD (jo, "mult", fp_element.mult); >>>>> + PARSE_INTEGER_FIELD (jo, "mult_addsub", fp_element.mult_addsub); >>>>> + PARSE_INTEGER_FIELD (jo, "fma", fp_element.fma); >>>>> + PARSE_INTEGER_FIELD (jo, "addsub", fp_element.addsub); >>>>> + PARSE_INTEGER_FIELD (jo, "fpconst", fp_element.fpconst); >>>>> + PARSE_INTEGER_FIELD (jo, "neg", fp_element.neg); >>>>> + PARSE_INTEGER_FIELD (jo, "compare", fp_element.compare); >>>>> + PARSE_INTEGER_FIELD (jo, "widen", fp_element.widen); >>>>> + PARSE_INTEGER_FIELD (jo, "narrow", fp_element.narrow); >>>>> + PARSE_INTEGER_FIELD (jo, "toint", fp_element.toint); >>>>> + PARSE_INTEGER_FIELD (jo, "fromint", fp_element.fromint); >>>>> + PARSE_INTEGER_FIELD (jo, "roundint", fp_element.roundint); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_insn_extra_cost_vect (const json::object *jo, T &vect) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "alu", vect.alu); >>>>> + PARSE_INTEGER_FIELD (jo, "mult", vect.mult); >>>>> + PARSE_INTEGER_FIELD (jo, "movi", vect.movi); >>>>> + PARSE_INTEGER_FIELD (jo, "dup", vect.dup); >>>>> + PARSE_INTEGER_FIELD (jo, "extract", vect.extract); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_addr_cost_addr_scale_costs (const json::object *jo, T >>>>> &addr_scale_costs) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "hi", addr_scale_costs.hi); >>>>> + PARSE_INTEGER_FIELD (jo, "si", addr_scale_costs.si); >>>>> + PARSE_INTEGER_FIELD (jo, "di", addr_scale_costs.di); >>>>> + PARSE_INTEGER_FIELD (jo, "ti", addr_scale_costs.ti); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_regmove_cost (const json::object *jo, T ®move_cost) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "GP2GP", regmove_cost.GP2GP); >>>>> + PARSE_INTEGER_FIELD (jo, "GP2FP", regmove_cost.GP2FP); >>>>> + PARSE_INTEGER_FIELD (jo, "FP2GP", regmove_cost.FP2GP); >>>>> + PARSE_INTEGER_FIELD (jo, "FP2FP", regmove_cost.FP2FP); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_vec_costs_advsimd (const json::object *jo, T &advsimd) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "int_stmt_cost", advsimd.int_stmt_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "fp_stmt_cost", advsimd.fp_stmt_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "ld2_st2_permute_cost", >>>>> + advsimd.ld2_st2_permute_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "ld3_st3_permute_cost", >>>>> + advsimd.ld3_st3_permute_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "ld4_st4_permute_cost", >>>>> + advsimd.ld4_st4_permute_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "permute_cost", advsimd.permute_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "reduc_i8_cost", advsimd.reduc_i8_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "reduc_i16_cost", advsimd.reduc_i16_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "reduc_i32_cost", advsimd.reduc_i32_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "reduc_i64_cost", advsimd.reduc_i64_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "reduc_f16_cost", advsimd.reduc_f16_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "reduc_f32_cost", advsimd.reduc_f32_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "reduc_f64_cost", advsimd.reduc_f64_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "store_elt_extra_cost", >>>>> + advsimd.store_elt_extra_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "vec_to_scalar_cost", >>>>> advsimd.vec_to_scalar_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "scalar_to_vec_cost", >>>>> advsimd.scalar_to_vec_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "align_load_cost", advsimd.align_load_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "unalign_load_cost", >>>>> advsimd.unalign_load_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "unalign_store_cost", >>>>> advsimd.unalign_store_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "store_cost", advsimd.store_cost); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_vec_costs_sve (const json::object *jo, T &sve) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "clast_cost", sve.clast_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "fadda_f16_cost", sve.fadda_f16_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "fadda_f32_cost", sve.fadda_f32_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "fadda_f64_cost", sve.fadda_f64_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "gather_load_x32_cost", >>>>> sve.gather_load_x32_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "gather_load_x64_cost", >>>>> sve.gather_load_x64_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "gather_load_x32_init_cost", >>>>> + sve.gather_load_x32_init_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "gather_load_x64_init_cost", >>>>> + sve.gather_load_x64_init_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "scatter_store_elt_cost", >>>>> + sve.scatter_store_elt_cost); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_vec_costs_issue_info_scalar (const json::object *jo, T &scalar) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "loads_stores_per_cycle", >>>>> + scalar.loads_stores_per_cycle); >>>>> + PARSE_INTEGER_FIELD (jo, "stores_per_cycle", scalar.stores_per_cycle); >>>>> + PARSE_INTEGER_FIELD (jo, "general_ops_per_cycle", >>>>> + scalar.general_ops_per_cycle); >>>>> + PARSE_INTEGER_FIELD (jo, "fp_simd_load_general_ops", >>>>> + scalar.fp_simd_load_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "fp_simd_store_general_ops", >>>>> + scalar.fp_simd_store_general_ops); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_vec_costs_issue_info_advsimd (const json::object *jo, T &advsimd) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "loads_stores_per_cycle", >>>>> + advsimd.loads_stores_per_cycle); >>>>> + PARSE_INTEGER_FIELD (jo, "stores_per_cycle", >>> advsimd.stores_per_cycle); >>>>> + PARSE_INTEGER_FIELD (jo, "general_ops_per_cycle", >>>>> + advsimd.general_ops_per_cycle); >>>>> + PARSE_INTEGER_FIELD (jo, "fp_simd_load_general_ops", >>>>> + advsimd.fp_simd_load_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "fp_simd_store_general_ops", >>>>> + advsimd.fp_simd_store_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "ld2_st2_general_ops", >>>>> advsimd.ld2_st2_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "ld3_st3_general_ops", >>>>> advsimd.ld3_st3_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "ld4_st4_general_ops", >>>>> advsimd.ld4_st4_general_ops); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_vec_costs_issue_info_sve (const json::object *jo, T &sve) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "loads_stores_per_cycle", >>>>> + sve.loads_stores_per_cycle); >>>>> + PARSE_INTEGER_FIELD (jo, "stores_per_cycle", sve.stores_per_cycle); >>>>> + PARSE_INTEGER_FIELD (jo, "general_ops_per_cycle", >>>>> sve.general_ops_per_cycle); >>>>> + PARSE_INTEGER_FIELD (jo, "fp_simd_load_general_ops", >>>>> + sve.fp_simd_load_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "fp_simd_store_general_ops", >>>>> + sve.fp_simd_store_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "ld2_st2_general_ops", >>>>> sve.ld2_st2_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "ld3_st3_general_ops", >>>>> sve.ld3_st3_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "ld4_st4_general_ops", >>>>> sve.ld4_st4_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "pred_ops_per_cycle", >>> sve.pred_ops_per_cycle); >>>>> + PARSE_INTEGER_FIELD (jo, "while_pred_ops", sve.while_pred_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "int_cmp_pred_ops", >>> sve.int_cmp_pred_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "fp_cmp_pred_ops", sve.fp_cmp_pred_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "gather_scatter_pair_general_ops", >>>>> + sve.gather_scatter_pair_general_ops); >>>>> + PARSE_INTEGER_FIELD (jo, "gather_scatter_pair_pred_ops", >>>>> + sve.gather_scatter_pair_pred_ops); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_branch_costs (const json::object *jo, T &branch_costs) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "predictable", branch_costs.predictable); >>>>> + PARSE_INTEGER_FIELD (jo, "unpredictable", >>> branch_costs.unpredictable); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_approx_modes (const json::object *jo, T &approx_modes) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "division", approx_modes.division); >>>>> + PARSE_INTEGER_FIELD (jo, "sqrt", approx_modes.sqrt); >>>>> + PARSE_INTEGER_FIELD (jo, "recip_sqrt", approx_modes.recip_sqrt); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_memmov_cost (const json::object *jo, T &memmov_cost) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "load_int", memmov_cost.load_int); >>>>> + PARSE_INTEGER_FIELD (jo, "store_int", memmov_cost.store_int); >>>>> + PARSE_INTEGER_FIELD (jo, "load_fp", memmov_cost.load_fp); >>>>> + PARSE_INTEGER_FIELD (jo, "store_fp", memmov_cost.store_fp); >>>>> + PARSE_INTEGER_FIELD (jo, "load_pred", memmov_cost.load_pred); >>>>> + PARSE_INTEGER_FIELD (jo, "store_pred", memmov_cost.store_pred); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_prefetch (const json::object *jo, T &prefetch) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "num_slots", prefetch.num_slots); >>>>> + PARSE_INTEGER_FIELD (jo, "l1_cache_size", prefetch.l1_cache_size); >>>>> + PARSE_INTEGER_FIELD (jo, "l1_cache_line_size", >>>>> prefetch.l1_cache_line_size); >>>>> + PARSE_INTEGER_FIELD (jo, "l2_cache_size", prefetch.l2_cache_size); >>>>> + PARSE_BOOLEAN_FIELD (jo, "prefetch_dynamic_strides", >>>>> + prefetch.prefetch_dynamic_strides); >>>>> + PARSE_INTEGER_FIELD (jo, "minimum_stride", >>> prefetch.minimum_stride); >>>>> + PARSE_INTEGER_FIELD (jo, "default_opt_level", >>> prefetch.default_opt_level); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_insn_extra_cost (const json::object *jo, T &insn_extra_cost) >>>>> +{ >>>>> + PARSE_OBJECT (jo, "alu", insn_extra_cost.alu, >>> parse_insn_extra_cost_alu); >>>>> + PARSE_ARRAY_FIELD (jo, "mult", insn_extra_cost.mult, >>>>> + parse_insn_extra_cost_mult_element); >>>>> + PARSE_OBJECT (jo, "ldst", insn_extra_cost.ldst, >>>>> parse_insn_extra_cost_ldst); >>>>> + PARSE_ARRAY_FIELD (jo, "fp", insn_extra_cost.fp, >>>>> + parse_insn_extra_cost_fp_element); >>>>> + PARSE_OBJECT (jo, "vect", insn_extra_cost.vect, >>>>> parse_insn_extra_cost_vect); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_addr_cost (const json::object *jo, T &addr_cost) >>>>> +{ >>>>> + PARSE_OBJECT (jo, "addr_scale_costs", addr_cost.addr_scale_costs, >>>>> + parse_addr_cost_addr_scale_costs); >>>>> + PARSE_INTEGER_FIELD (jo, "pre_modify", addr_cost.pre_modify); >>>>> + PARSE_INTEGER_FIELD (jo, "post_modify", addr_cost.post_modify); >>>>> + PARSE_INTEGER_FIELD (jo, "post_modify_ld3_st3", >>>>> + addr_cost.post_modify_ld3_st3); >>>>> + PARSE_INTEGER_FIELD (jo, "post_modify_ld4_st4", >>>>> + addr_cost.post_modify_ld4_st4); >>>>> + PARSE_INTEGER_FIELD (jo, "register_offset", addr_cost.register_offset); >>>>> + PARSE_INTEGER_FIELD (jo, "register_sextend", >>> addr_cost.register_sextend); >>>>> + PARSE_INTEGER_FIELD (jo, "register_zextend", >>> addr_cost.register_zextend); >>>>> + PARSE_INTEGER_FIELD (jo, "imm_offset", addr_cost.imm_offset); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_vec_costs_issue_info (const json::object *jo, T &issue_info) >>>>> +{ >>>>> + PARSE_OBJECT (jo, "scalar", issue_info.scalar, >>>>> + parse_vec_costs_issue_info_scalar); >>>>> + PARSE_OBJECT (jo, "advsimd", issue_info.advsimd, >>>>> + parse_vec_costs_issue_info_advsimd); >>>>> + PARSE_OBJECT (jo, "sve", issue_info.sve, >>> parse_vec_costs_issue_info_sve); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_vec_costs (const json::object *jo, T &vec_costs) >>>>> +{ >>>>> + PARSE_INTEGER_FIELD (jo, "scalar_int_stmt_cost", >>>>> + vec_costs.scalar_int_stmt_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "scalar_fp_stmt_cost", >>>>> + vec_costs.scalar_fp_stmt_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "scalar_load_cost", >>> vec_costs.scalar_load_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "scalar_store_cost", >>>>> vec_costs.scalar_store_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "cond_taken_branch_cost", >>>>> + vec_costs.cond_taken_branch_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "cond_not_taken_branch_cost", >>>>> + vec_costs.cond_not_taken_branch_cost); >>>>> + PARSE_OBJECT (jo, "advsimd", vec_costs.advsimd, >>>>> parse_vec_costs_advsimd); >>>>> + PARSE_OBJECT (jo, "sve", vec_costs.sve, parse_vec_costs_sve); >>>>> + PARSE_OBJECT (jo, "issue_info", vec_costs.issue_info, >>>>> + parse_vec_costs_issue_info); >>>>> +} >>>>> + >>>>> +template <typename T> >>>>> +static void >>>>> +parse_tunings (const json::object *jo, T &tunings) >>>>> +{ >>>>> + PARSE_OBJECT (jo, "insn_extra_cost", tunings.insn_extra_cost, >>>>> + parse_insn_extra_cost); >>>>> + PARSE_OBJECT (jo, "addr_cost", tunings.addr_cost, parse_addr_cost); >>>>> + PARSE_OBJECT (jo, "regmove_cost", tunings.regmove_cost, >>>>> parse_regmove_cost); >>>>> + PARSE_OBJECT (jo, "vec_costs", tunings.vec_costs, parse_vec_costs); >>>>> + PARSE_OBJECT (jo, "branch_costs", tunings.branch_costs, >>>>> parse_branch_costs); >>>>> + PARSE_OBJECT (jo, "approx_modes", tunings.approx_modes, >>>>> parse_approx_modes); >>>>> + PARSE_INTEGER_FIELD (jo, "sve_width", tunings.sve_width); >>>>> + PARSE_OBJECT (jo, "memmov_cost", tunings.memmov_cost, >>>>> parse_memmov_cost); >>>>> + PARSE_INTEGER_FIELD (jo, "issue_rate", tunings.issue_rate); >>>>> + PARSE_INTEGER_FIELD (jo, "fusible_ops", tunings.fusible_ops); >>>>> + PARSE_STRING_FIELD (jo, "function_align", tunings.function_align); >>>>> + PARSE_STRING_FIELD (jo, "jump_align", tunings.jump_align); >>>>> + PARSE_STRING_FIELD (jo, "loop_align", tunings.loop_align); >>>>> + PARSE_INTEGER_FIELD (jo, "int_reassoc_width", >>>>> tunings.int_reassoc_width); >>>>> + PARSE_INTEGER_FIELD (jo, "fp_reassoc_width", >>> tunings.fp_reassoc_width); >>>>> + PARSE_INTEGER_FIELD (jo, "fma_reassoc_width", >>>>> tunings.fma_reassoc_width); >>>>> + PARSE_INTEGER_FIELD (jo, "vec_reassoc_width", >>>>> tunings.vec_reassoc_width); >>>>> + PARSE_INTEGER_FIELD (jo, "min_div_recip_mul_sf", >>>>> + tunings.min_div_recip_mul_sf); >>>>> + PARSE_INTEGER_FIELD (jo, "min_div_recip_mul_df", >>>>> + tunings.min_div_recip_mul_df); >>>>> + PARSE_INTEGER_FIELD (jo, "max_case_values", >>> tunings.max_case_values); >>>>> + PARSE_ENUM_FIELD (jo, "autoprefetcher_model", >>>>> tunings.autoprefetcher_model, >>>>> + autoprefetcher_model_mappings); >>>>> + PARSE_INTEGER_FIELD (jo, "extra_tuning_flags", >>>>> tunings.extra_tuning_flags); >>>>> + PARSE_OBJECT (jo, "prefetch", tunings.prefetch, parse_prefetch); >>>>> + PARSE_ENUM_FIELD (jo, "ldp_policy_model", tunings.ldp_policy_model, >>>>> + ldp_policy_model_mappings); >>>>> + PARSE_ENUM_FIELD (jo, "stp_policy_model", tunings.stp_policy_model, >>>>> + stp_policy_model_mappings); >>>>> +} >>>>> + >>>>> +/* Validate the user provided JSON data against the present schema. >>>>> + Checks for correct types, fields, and expected format. */ >>>>> +static bool >>>>> +validate_and_traverse (const json::object *json_obj, >>>>> + const json::object *schema_obj, >>>>> + const std::string &parent_key = "") >>>>> +{ >>>>> + for (const auto &json_entry : json_obj->get_map ()) >>>>> + { >>>>> + const std::string &key = json_entry.first; >>>>> + const json::value *json_value = json_entry.second; >>>>> + >>>>> + std::string full_key = parent_key.empty () ? key : parent_key + >>>>> "." + key; >>>>> + >>>>> + const json::value *schema_value = schema_obj->get (key.c_str ()); >>>>> + if (!schema_value) >>>>> + { >>>>> + warning (0, "key %qs is not a tuning parameter, skipping", >>>>> + full_key.c_str ()); >>>>> + continue; >>>>> + } >>>>> + >>>>> + if (auto *sub_schema_obj = dyn_cast<const json::object *> >>>>> (schema_value)) >>>>> + { >>>>> + if (auto *sub_json_obj = dyn_cast<const json::object *> >>>>> (json_value)) >>>>> + { >>>>> + if (!validate_and_traverse (sub_json_obj, sub_schema_obj, >>>>> + full_key)) >>>>> + return false; >>>>> + } >>>>> + else >>>>> + { >>>>> + error ("key %qs expected to be an object", full_key.c_str ()); >>>>> + return false; >>>>> + } >>>>> + } >>>>> + else if (schema_value->get_kind () == json::JSON_ARRAY) >>>>> + { >>>>> + if (json_value->get_kind () != json::JSON_ARRAY) >>>>> + { >>>>> + error ("key %qs expected to be an array", full_key.c_str ()); >>>>> + return false; >>>>> + } >>>>> + } >>>>> + else if (auto *schema_string >>>>> + = dyn_cast<const json::string *> (schema_value)) >>>>> + { >>>>> + const char *schema_type_str = schema_string->get_string (); >>>>> + >>>>> + if (strcmp (schema_type_str, "int") == 0) >>>>> + { >>>>> + if (json_value->get_kind () != json::JSON_INTEGER) >>>>> + { >>>>> + error ("key %qs expected to be an integer", >>>>> + full_key.c_str ()); >>>>> + return false; >>>>> + } >>>>> + } >>>>> + else if (strcmp (schema_type_str, "uint") == 0) >>>>> + { >>>>> + if (json_value->get_kind () != json::JSON_INTEGER >>>>> + || extract_integer (json_value) < 0) >>>>> + { >>>>> + error ("key %qs expected to be an unsigned integer", >>>>> + full_key.c_str ()); >>>>> + return false; >>>>> + } >>>>> + } >>>>> + else if (strcmp (schema_type_str, "string") == 0) >>>>> + { >>>>> + if (json_value->get_kind () != json::JSON_STRING) >>>>> + { >>>>> + error ("key %qs expected to be a string", full_key.c_str >>>>> ()); >>>>> + return false; >>>>> + } >>>>> + } >>>>> + else if (strcmp (schema_type_str, "boolean") == 0) >>>>> + { >>>>> + if (json_value->get_kind () != json::JSON_TRUE >>>>> + && json_value->get_kind () != json::JSON_FALSE) >>>>> + { >>>>> + error ("key %qs expected to be a boolean (true/false)", >>>>> + full_key.c_str ()); >>>>> + return false; >>>>> + } >>>>> + } >>>>> + else if (strcmp (schema_type_str, "enum") == 0) >>>>> + { >>>>> + if (json_value->get_kind () != json::JSON_STRING) >>>>> + { >>>>> + error ("key %qs expected to be an enum (string)", >>>>> + full_key.c_str ()); >>>>> + return false; >>>>> + } >>>>> + } >>>>> + else >>>>> + { >>>>> + error ("key %qs has unsupported type", full_key.c_str ()); >>>>> + return false; >>>>> + } >>>>> + } >>>>> + else >>>>> + { >>>>> + error ("key %qs has unexpected format in schema", full_key.c_str >>>>> ()); >>>>> + return false; >>>>> + } >>>>> + } >>>>> + return true; >>>>> +} >>>>> + >>>>> +/* Helper routine for reading the provided JSON file. */ >>>>> +static std::unique_ptr<std::vector<char>> >>>>> +read_file (const char *path) >>>>> +{ >>>>> + FILE *f_in = fopen (path, "r"); >>>>> + if (!f_in) >>>>> + { >>>>> + error ("could not open file %s", path); >>>>> + return nullptr; >>>>> + } >>>>> + >>>>> + auto result = std::make_unique<std::vector<char>> (); >>>>> + char buf[4096]; >>>>> + >>>>> + while (size_t iter_sz_in = fread (buf, 1, sizeof (buf), f_in)) >>>>> + result->insert (result->end (), buf, buf + iter_sz_in); >>>>> + >>>>> + if (!feof (f_in)) >>>>> + { >>>>> + error ("error reading file %s", path); >>>>> + fclose (f_in); >>>>> + return nullptr; >>>>> + } >>>>> + >>>>> + fclose (f_in); >>>>> + result->push_back ('\0'); >>>>> + return result; >>>>> +} >>>>> + >>>>> +/* Main routine for setting up the parsing of JSON data. */ >>>>> +void >>>>> +aarch64_load_tuning_params_from_json_string (const char *json_string, >>>>> + const char *schema_string, >>>>> + struct tune_params *tune) >>>>> +{ >>>>> + /* Try parsing the JSON string. */ >>>>> + json::parser_result_t data_result >>>>> + = json::parse_utf8_string (strlen (json_string), json_string, true, >>>>> + nullptr); >>>>> + >>>>> + if (auto json_err = data_result.m_err.get ()) >>>>> + { >>>>> + error ("error parsing JSON data: %s", json_err->get_msg ()); >>>>> + return; >>>>> + } >>>>> + >>>>> + const std::unique_ptr<json::value> &root = data_result.m_val; >>>>> + if (!root) >>>>> + { >>>>> + error ("JSON parsing returned null data"); >>>>> + return; >>>>> + } >>>>> + auto *root_obj = dyn_cast<const json::object *> (root.get ()); >>>>> + if (!root_obj) >>>>> + { >>>>> + warning (0, "no JSON object found in the provided data"); >>>>> + return; >>>>> + } >>>>> + >>>>> + json::parser_result_t schema_result >>>>> + = json::parse_utf8_string (strlen (schema_string), schema_string, >>>>> true, >>>>> + nullptr); >>>>> + >>>>> + gcc_assert (!schema_result.m_err.get ()); >>>>> + gcc_assert (schema_result.m_val); >>>>> + >>>>> + auto *schema_obj >>>>> + = dyn_cast<const json::object *> (schema_result.m_val.get ()); >>>>> + gcc_assert (schema_obj); >>>>> + >>>>> + const json::value *tune_params_value = root_obj->get ("tune_params"); >>>>> + if (!tune_params_value) >>>>> + { >>>>> + warning (0, "key %<tune_params%> not found in JSON data"); >>>>> + return; >>>>> + } >>>>> + >>>>> + auto *jo = dyn_cast<const json::object *> (tune_params_value); >>>>> + if (!jo) >>>>> + { >>>>> + error ("key %<tune_params%> is not a JSON object"); >>>>> + return; >>>>> + } >>>>> + >>>>> + if (!validate_and_traverse (root_obj, schema_obj)) >>>>> + { >>>>> + error ("validation failed for the provided JSON data"); >>>>> + return; >>>>> + } >>>>> + >>>>> + parse_tunings (jo, *tune); >>>>> + return; >>>>> +} >>>>> + >>>>> +/* Wrapper for calling aarch64_load_tuning_params_from_json_string. */ >>>>> +void >>>>> +aarch64_load_tuning_params_from_json (const char *data_filename, >>>>> + struct tune_params *tune) >>>>> +{ >>>>> + std::unique_ptr<std::vector<char>> json_data = read_file >>> (data_filename); >>>>> + if (!json_data || !json_data->data ()) >>>>> + { >>>>> + error ("cannot read JSON data in %s", data_filename); >>>>> + return; >>>>> + } >>>>> + aarch64_load_tuning_params_from_json_string ( >>>>> + (const char *) json_data->data (), schema_json, tune); >>>>> +} >>>>> + >>>>> +/* Self-tests to check if the values populated to the tune_params >>>>> structure >>>>> + are correct. */ >>>>> + >>>>> +#if CHECKING_P >>>>> +namespace selftest { >>>>> + >>>>> +void >>>>> +test_json_integers () >>>>> +{ >>>>> + const char *test_json = R"json({ >>>>> + "tune_params": { >>>>> + "sve_width": 256, >>>>> + "issue_rate": 4 >>>>> + } >>>>> + })json"; >>>>> + >>>>> + tune_params params; >>>>> + >>>>> + aarch64_load_tuning_params_from_json_string (test_json, >>> schema_json, >>>>> ¶ms); >>>>> + >>>>> + ASSERT_EQ (params.sve_width, 256); >>>>> + ASSERT_EQ (params.issue_rate, 4); >>>>> +} >>>>> + >>>>> +void >>>>> +test_json_boolean () >>>>> +{ >>>>> + const char *test_json = R"json({ >>>>> + "tune_params": { >>>>> + "insn_extra_cost": { >>>>> + "alu": { >>>>> + "non_exec_costs_exec": false >>>>> + } >>>>> + } >>>>> + } >>>>> + })json"; >>>>> + >>>>> + static const cpu_cost_table default_cost_table = {}; >>>>> + >>>>> + tune_params params; >>>>> + params.insn_extra_cost = &default_cost_table; >>>>> + >>>>> + aarch64_load_tuning_params_from_json_string (test_json, >>> schema_json, >>>>> ¶ms); >>>>> + >>>>> + ASSERT_EQ (params.insn_extra_cost->alu.non_exec_costs_exec, false); >>>>> +} >>>>> + >>>>> +void >>>>> +test_json_strings () >>>>> +{ >>>>> + const char *test_json = R"json({ >>>>> + "tune_params": { >>>>> + "function_align": "16", >>>>> + "jump_align": "2", >>>>> + "loop_align": "8" >>>>> + } >>>>> + })json"; >>>>> + >>>>> + tune_params params; >>>>> + >>>>> + aarch64_load_tuning_params_from_json_string (test_json, >>> schema_json, >>>>> ¶ms); >>>>> + >>>>> + ASSERT_STREQ (params.function_align, "16"); >>>>> + ASSERT_STREQ (params.jump_align, "2"); >>>>> + ASSERT_STREQ (params.loop_align, "8"); >>>>> +} >>>>> + >>>>> +void >>>>> +test_json_enums () >>>>> +{ >>>>> + const char *test_json = R"json({ >>>>> + "tune_params": { >>>>> + "autoprefetcher_model": "AUTOPREFETCHER_OFF", >>>>> + "ldp_policy_model": "AARCH64_LDP_STP_POLICY_NEVER", >>>>> + "stp_policy_model": "AARCH64_LDP_STP_POLICY_DEFAULT" >>>>> + } >>>>> + })json"; >>>>> + >>>>> + tune_params params; >>>>> + >>>>> + aarch64_load_tuning_params_from_json_string (test_json, >>> schema_json, >>>>> ¶ms); >>>>> + >>>>> + ASSERT_EQ (params.autoprefetcher_model, >>>>> tune_params::AUTOPREFETCHER_OFF); >>>>> + ASSERT_EQ (params.ldp_policy_model, >>>>> AARCH64_LDP_STP_POLICY_NEVER); >>>>> + ASSERT_EQ (params.stp_policy_model, >>>>> AARCH64_LDP_STP_POLICY_DEFAULT); >>>>> +} >>>>> + >>>>> +void >>>>> +json_tunings_tests () >>>>> +{ >>>>> + test_json_integers (); >>>>> + test_json_boolean (); >>>>> + test_json_strings (); >>>>> + test_json_enums (); >>>>> +} >>>>> + >>>>> +} // namespace selftest >>>>> + >>>>> +#endif /* CHECKING_P */ >>>>> \ No newline at end of file >>>>> diff --git a/gcc/config/aarch64/aarch64-json-tunings-parser.h >>>>> b/gcc/config/aarch64/aarch64-json-tunings-parser.h >>>>> new file mode 100644 >>>>> index 00000000000..3c5cd4c3c20 >>>>> --- /dev/null >>>>> +++ b/gcc/config/aarch64/aarch64-json-tunings-parser.h >>>>> @@ -0,0 +1,29 @@ >>>>> +/* Routines to parse the AArch64 tuning parameters from a JSON file. >>>>> + Copyright The GNU Toolchain Authors. >>>>> + >>>>> + 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 AARCH64_JSON_TUNINGS_PARSER_H >>>>> +#define AARCH64_JSON_TUNINGS_PARSER_H >>>>> + >>>>> +#include "aarch64-protos.h" >>>>> + >>>>> +void >>>>> +aarch64_load_tuning_params_from_json (const char *data_filename, >>>>> + struct tune_params *tune); >>>>> + >>>>> +#endif >>>>> \ No newline at end of file >>>>> diff --git a/gcc/config/aarch64/aarch64.cc >>> b/gcc/config/aarch64/aarch64.cc >>>>> index 198820b5e5f..a22369cfcb8 100644 >>>>> --- a/gcc/config/aarch64/aarch64.cc >>>>> +++ b/gcc/config/aarch64/aarch64.cc >>>>> @@ -99,6 +99,7 @@ >>>>> #include "ipa-fnsummary.h" >>>>> #include "hash-map.h" >>>>> #include "aarch64-json-tunings-printer.h" >>>>> +#include "aarch64-json-tunings-parser.h" >>>>> >>>>> /* This file should be included last. */ >>>>> #include "target-def.h" >>>>> @@ -19006,6 +19007,21 @@ aarch64_override_options_internal (struct >>>>> gcc_options *opts) >>>>> aarch64_parse_override_string (opts->x_aarch64_override_tune_string, >>>>> &aarch64_tune_params); >>>>> >>>>> + /* We need to parse the JSON file only once per program execution. */ >>>>> + if (opts->x_muser_provided_CPU) >>>>> + { >>>>> + static bool json_parsed = false; >>>>> + static struct tune_params aarch64_json_params; >>>>> + if (!json_parsed) >>>>> + { >>>>> + aarch64_json_params = *(tune->tune); >>>>> + aarch64_load_tuning_params_from_json (opts- >>>>>> x_muser_provided_CPU, >>>>> + &aarch64_json_params); >>>>> + json_parsed = true; >>>>> + } >>>>> + aarch64_tune_params = aarch64_json_params; >>>>> + } >>>>> + >>>>> if (opts->x_aarch64_ldp_policy_param) >>>>> aarch64_tune_params.ldp_policy_model = opts- >>>>>> x_aarch64_ldp_policy_param; >>>>> >>>>> diff --git a/gcc/config/aarch64/aarch64.opt >>>>> b/gcc/config/aarch64/aarch64.opt >>>>> index fd9864cc670..1735d2debe5 100644 >>>>> --- a/gcc/config/aarch64/aarch64.opt >>>>> +++ b/gcc/config/aarch64/aarch64.opt >>>>> @@ -192,6 +192,10 @@ fdump-tuning-model= >>>>> Target Undocumented RejectNegative Negative(fdump-tuning-model=) >>>>> Joined Var(fdump_tuning_model) >>>>> -fdump-tuning-model=<filename> Dump current tuning model to a JSON >>> file. >>>>> >>>>> +muser-provided-CPU= >>>>> +Target Undocumented RejectNegative Negative(muser-provided-CPU=) >>>>> Joined Var(muser_provided_CPU) >>>>> +-muser-provided-CPU=<json-tuning-file> User specific CPU tunings. >>>>> + >>>>> moverride= >>>>> Target RejectNegative ToLower Joined Var(aarch64_override_tune_string) >>>>> Save >>>>> -moverride=<string> Power users only! Override CPU optimization >>>>> parameters. >>>>> diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64 >>>>> index fe95eaee116..ce1e54aba2f 100644 >>>>> --- a/gcc/config/aarch64/t-aarch64 >>>>> +++ b/gcc/config/aarch64/t-aarch64 >>>>> @@ -211,6 +211,16 @@ aarch64-json-tunings-printer.o: >>>>> $(srcdir)/config/aarch64/aarch64-json-tunings-pr >>>>> $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) >>>>> $(INCLUDES) \ >>>>> $(srcdir)/config/aarch64/aarch64-json-tunings-printer.cc >>>>> >>>>> +aarch64-json-tunings-parser.o: $(srcdir)/config/aarch64/aarch64-json- >>>>> tunings-parser.cc \ >>>>> + $(CONFIG_H) $(SYSTEM_H) $(CORETYPES_H) $(TM_H) >>>>> $(DIAGNOSTIC_CORE_H) \ >>>>> + json-parsing.h \ >>>>> + $(srcdir)/config/aarch64/aarch64-json-schema.h \ >>>>> + $(srcdir)/config/aarch64/aarch64-json-tunings-parser.h \ >>>>> + $(srcdir)/config/aarch64/aarch64-protos.h \ >>>>> + $(srcdir)/config/arm/aarch-common-protos.h >>>>> + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) >>>>> $(INCLUDES) \ >>>>> + $(srcdir)/config/aarch64/aarch64-json-tunings-parser.cc >>>>> + >>>>> comma=, >>>>> MULTILIB_OPTIONS = $(subst $(comma),/, $(patsubst %, mabi=%, >>> $(subst >>>>> $(comma),$(comma)mabi=,$(TM_MULTILIB_CONFIG)))) >>>>> MULTILIB_DIRNAMES = $(subst $(comma), ,$(TM_MULTILIB_CONFIG)) >>>>> diff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc >>>>> index c68d3e79a31..e060f260a46 100644 >>>>> --- a/gcc/selftest-run-tests.cc >>>>> +++ b/gcc/selftest-run-tests.cc >>>>> @@ -77,6 +77,7 @@ selftest::run_tests () >>>>> opts_cc_tests (); >>>>> json_cc_tests (); >>>>> json_parser_cc_tests (); >>>>> + json_tunings_tests (); >>>>> cgraph_cc_tests (); >>>>> optinfo_emit_json_cc_tests (); >>>>> ordered_hash_map_tests_cc_tests (); >>>>> diff --git a/gcc/selftest.h b/gcc/selftest.h >>>>> index 4501d34181c..7a2fb3d14f1 100644 >>>>> --- a/gcc/selftest.h >>>>> +++ b/gcc/selftest.h >>>>> @@ -239,6 +239,7 @@ extern void input_cc_tests (); >>>>> extern void ipa_modref_tree_cc_tests (); >>>>> extern void json_cc_tests (); >>>>> extern void json_parser_cc_tests (); >>>>> +extern void json_tunings_tests (); >>>>> extern void opt_suggestions_cc_tests (); >>>>> extern void optinfo_emit_json_cc_tests (); >>>>> extern void opts_cc_tests (); >>>>> -- >>>>> 2.44.0 > <0001-aarch64-arm-Remove-const-keyword-from-tune_params-me.patch><0002-aarch64-Enable-dumping-of-AArch64-CPU-tuning-paramet.patch><0003-json-Add-get_map-method-to-JSON-object-class.patch><0004-aarch64-Enable-parsing-of-user-provided-AArch64-CPU-.patch><0005-aarch64-Regression-tests-for-parsing-of-user-provide.patch><0006-aarch64-Script-to-auto-generate-JSON-tuning-routines.patch>
