From: Soumya AR <soum...@nvidia.com>

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 <soum...@nvidia.com>

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    | 837 ++++++++++++++++++
 .../aarch64/aarch64-json-tunings-parser.h     |  29 +
 gcc/config/aarch64/aarch64.cc                 |   5 +
 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, 1149 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 4d23b578457..6b13574590a 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -350,7 +350,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-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-cc-fusion.o aarch64-early-ra.o aarch64-ldp-fusion.o 
aarch64-json-tunings-printer.o"
+       extra_objs="aarch64-builtins.o aarch-common.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-cc-fusion.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..f839f9077fe
--- /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.
+
+   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": "uint",
+       "fadda_f16_cost": "uint",
+       "fadda_f32_cost": "uint",
+       "fadda_f64_cost": "uint",
+       "gather_load_x32_cost": "uint",
+       "gather_load_x64_cost": "uint",
+       "gather_load_x32_init_cost": "uint",
+       "gather_load_x64_init_cost": "uint",
+       "scatter_store_elt_cost": "uint"
+      },
+      "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": "string",
+    "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": "string",
+    "stp_policy_model": "string"
+  }
+})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..0d945179652
--- /dev/null
+++ b/gcc/config/aarch64/aarch64-json-tunings-parser.cc
@@ -0,0 +1,837 @@
+/* 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
+#include <iostream>
+#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)                                  
\
+  if ((obj)->get ((key)))                                                      
\
+  (member) = extract_integer ((obj)->get ((key)))
+
+#define PARSE_BOOLEAN_FIELD(obj, key, member)                                  
\
+  if ((obj)->get ((key)))                                                      
\
+  (member) = extract_boolean ((obj)->get ((key)))
+
+#define PARSE_STRING_FIELD(obj, key, member)                                   
\
+  if ((obj)->get ((key)))                                                      
\
+  (member) = extract_string ((obj)->get ((key)))
+
+char *
+extract_string (const json::value *val)
+{
+  if (val && val->get_kind () == json::JSON_STRING)
+    {
+      const json::string *string_val = static_cast<const json::string *> (val);
+      char *result = new char[string_val->get_length () + 1];
+      strcpy (result, string_val->get_string ());
+      return result;
+    }
+  else
+    {
+      warning (0, "expected a string but got something else or NULL");
+      return nullptr;
+    }
+}
+
+int
+extract_integer (const json::value *val)
+{
+  if (val && val->get_kind () == json::JSON_INTEGER)
+    {
+      const json::integer_number *int_val
+       = static_cast<const json::integer_number *> (val);
+      long value = int_val->get ();
+      if (value > INT_MAX)
+       {
+         error ("value exceeds %<INT_MAX%>");
+         return 0;
+       }
+      return value;
+    }
+  else
+    {
+      warning (0, "expected an integer value but got something else or NULL");
+      return 0;
+    }
+}
+
+bool
+extract_boolean (const json::value *val)
+{
+  if (val
+      && (val->get_kind () == json::JSON_TRUE
+         || val->get_kind () == json::JSON_FALSE))
+    {
+      const json::literal *literal_val
+       = static_cast<const json::literal *> (val);
+      return (literal_val->get_kind () == json::JSON_TRUE);
+    }
+  else
+    {
+      warning (0, "expected a boolean value but got something else or NULL");
+      return false;
+    }
+}
+
+static void
+parse_autoprefetcher_model (const json::object *jo, std::string key,
+                           tune_params::aarch64_autoprefetch_model &model)
+{
+  json::value *field_value = jo->get (key.c_str ());
+  if (field_value)
+    {
+      const char *field_string
+       = static_cast<json::string *> (field_value)->get_string ();
+
+      if (strcmp (field_string, "AUTOPREFETCHER_OFF") == 0)
+       model = tune_params::AUTOPREFETCHER_OFF;
+      else if (strcmp (field_string, "AUTOPREFETCHER_WEAK") == 0)
+       model = tune_params::AUTOPREFETCHER_WEAK;
+      else if (strcmp (field_string, "AUTOPREFETCHER_STRONG") == 0)
+       model = tune_params::AUTOPREFETCHER_STRONG;
+      else
+       {
+         warning (0, "autoprefetch model not recognized, defaulting to "
+                     "%<AUTOPREFETCHER_OFF%>");
+         model = tune_params::AUTOPREFETCHER_OFF;
+       }
+    }
+}
+
+static void
+parse_aarch64_ldp_stp_policy (const json::object *jo, std::string key,
+                             aarch64_ldp_stp_policy &policy)
+{
+  json::value *field_value = jo->get (key.c_str ());
+  if (field_value)
+    {
+      const char *field_string
+       = static_cast<json::string *> (field_value)->get_string ();
+
+      if (strcmp (field_string, "AARCH64_LDP_STP_POLICY_DEFAULT") == 0)
+       policy = AARCH64_LDP_STP_POLICY_DEFAULT;
+      else if (strcmp (field_string, "AARCH64_LDP_STP_POLICY_ALIGNED") == 0)
+       policy = AARCH64_LDP_STP_POLICY_ALIGNED;
+      else if (strcmp (field_string, "AARCH64_LDP_STP_POLICY_ALWAYS") == 0)
+       policy = AARCH64_LDP_STP_POLICY_ALWAYS;
+      else if (strcmp (field_string, "AARCH64_LDP_STP_POLICY_NEVER") == 0)
+       policy = AARCH64_LDP_STP_POLICY_NEVER;
+      else
+       {
+         warning (0, "ldp stp policy not recognized, defaulting to "
+                     "%<AARCH64_LDP_STP_POLICY_DEFAULT%>");
+         policy = AARCH64_LDP_STP_POLICY_DEFAULT;
+       }
+    }
+}
+
+template <typename ParserFunc, typename StructType>
+static void
+parse_nested_object (const json::object *parent_obj, const char *key,
+                    ParserFunc parser, StructType &target)
+{
+  const json::value *nested_value = parent_obj->get (key);
+  if (nested_value && nested_value->get_kind () == json::JSON_OBJECT)
+    {
+      const json::object *nested_obj
+       = static_cast<const json::object *> (nested_value);
+      parser (nested_obj, target);
+    }
+}
+
+static void
+parse_addr_scale_costs (const json::object *jo,
+                       scale_addr_mode_cost &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);
+}
+
+static void
+parse_alu_cost_table (const json::object *jo, alu_cost_table &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);
+}
+
+static void
+parse_mult_cost (const json::object *jo, mult_cost_table &mult)
+{
+  PARSE_INTEGER_FIELD (jo, "simple", mult.simple);
+  PARSE_INTEGER_FIELD (jo, "flag_setting", mult.flag_setting);
+  PARSE_INTEGER_FIELD (jo, "extend", mult.extend);
+  PARSE_INTEGER_FIELD (jo, "add", mult.add);
+  PARSE_INTEGER_FIELD (jo, "extend_add", mult.extend_add);
+  PARSE_INTEGER_FIELD (jo, "idiv", mult.idiv);
+}
+
+static void
+parse_ldst_cost_table (const json::object *jo, mem_cost_table &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);
+}
+
+static void
+parse_fp_cost_table (const json::object *jo, fp_cost_table &fp)
+{
+  PARSE_INTEGER_FIELD (jo, "div", fp.div);
+  PARSE_INTEGER_FIELD (jo, "mult", fp.mult);
+  PARSE_INTEGER_FIELD (jo, "mult_addsub", fp.mult_addsub);
+  PARSE_INTEGER_FIELD (jo, "fma", fp.fma);
+  PARSE_INTEGER_FIELD (jo, "addsub", fp.addsub);
+  PARSE_INTEGER_FIELD (jo, "fpconst", fp.fpconst);
+  PARSE_INTEGER_FIELD (jo, "neg", fp.neg);
+  PARSE_INTEGER_FIELD (jo, "compare", fp.compare);
+  PARSE_INTEGER_FIELD (jo, "widen", fp.widen);
+  PARSE_INTEGER_FIELD (jo, "narrow", fp.narrow);
+  PARSE_INTEGER_FIELD (jo, "toint", fp.toint);
+  PARSE_INTEGER_FIELD (jo, "fromint", fp.fromint);
+  PARSE_INTEGER_FIELD (jo, "roundint", fp.roundint);
+}
+
+static void
+parse_vect_cost_table (const json::object *jo, vector_cost_table &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);
+}
+
+static void
+parse_insn_extra_cost (const json::object *jo, cpu_cost_table &insn_extra_cost)
+{
+  parse_nested_object (jo, "alu", parse_alu_cost_table, insn_extra_cost.alu);
+
+  const json::value *mult_array = jo->get ("mult");
+  if (mult_array && mult_array->get_kind () == json::JSON_ARRAY)
+    {
+      const json::array *mults = static_cast<const json::array *> (mult_array);
+      for (size_t i = 0; i < mults->size (); ++i)
+       {
+         parse_mult_cost (static_cast<const json::object *> (mults->get (i)),
+                          insn_extra_cost.mult[i]);
+       }
+    }
+
+  parse_nested_object (jo, "ldst", parse_ldst_cost_table, 
insn_extra_cost.ldst);
+
+  const json::value *fp_array = jo->get ("fp");
+  if (fp_array && fp_array->get_kind () == json::JSON_ARRAY)
+    {
+      const json::array *fps = static_cast<const json::array *> (fp_array);
+      for (size_t i = 0; i < fps->size (); ++i)
+       {
+         parse_fp_cost_table (static_cast<const json::object *> (fps->get (i)),
+                              insn_extra_cost.fp[i]);
+       }
+    }
+
+  parse_nested_object (jo, "vect", parse_vect_cost_table, 
insn_extra_cost.vect);
+}
+
+static void
+parse_addr_cost (const json::object *jo, cpu_addrcost_table &addr_cost)
+{
+  parse_nested_object (jo, "addr_scale_costs", parse_addr_scale_costs,
+                      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);
+}
+
+static void
+parse_advsimd_costs (const json::object *jo, advsimd_vec_cost &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);
+}
+
+static void
+parse_sve_costs (const json::object *jo, sve_vec_cost &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);
+}
+
+static void
+parse_issue_scalar (const json::object *jo, aarch64_base_vec_issue_info 
&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);
+}
+
+static void
+parse_issue_advsimd (const json::object *jo,
+                    aarch64_simd_vec_issue_info &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);
+}
+
+static void
+parse_issue_sve (const json::object *jo, aarch64_sve_vec_issue_info &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);
+}
+
+static void
+parse_issue_info (const json::object *jo, aarch64_vec_issue_info &info)
+{
+  if (info.scalar)
+    parse_nested_object (jo, "scalar", parse_issue_scalar, *info.scalar);
+  if (info.advsimd)
+    parse_nested_object (jo, "advsimd", parse_issue_advsimd, *info.advsimd);
+  if (info.sve)
+    parse_nested_object (jo, "sve", parse_issue_sve, *info.sve);
+}
+
+static void
+parse_vec_costs (const json::object *jo, cpu_vector_cost &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);
+  if (vec_costs.advsimd)
+    parse_nested_object (jo, "advsimd", parse_advsimd_costs,
+                        *vec_costs.advsimd);
+  if (vec_costs.sve)
+    parse_nested_object (jo, "sve", parse_sve_costs, *vec_costs.sve);
+  if (vec_costs.issue_info)
+    parse_nested_object (jo, "issue_info", parse_issue_info,
+                        *vec_costs.issue_info);
+}
+
+static void
+parse_branch_costs (const json::object *jo, cpu_branch_cost &branch_costs)
+{
+  PARSE_INTEGER_FIELD (jo, "predictable", branch_costs.predictable);
+  PARSE_INTEGER_FIELD (jo, "unpredictable", branch_costs.unpredictable);
+}
+
+static void
+parse_regmove_cost (const json::object *jo, cpu_regmove_cost &regmove_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);
+}
+
+static void
+parse_approx_modes (const json::object *jo, cpu_approx_modes &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);
+}
+
+static void
+parse_memmov_cost (const json::object *jo, cpu_memmov_cost &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);
+}
+
+static void
+parse_prefetch (const json::object *jo, cpu_prefetch_tune &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);
+}
+
+static void
+parse_tunings (const json::object *jo, tune_params &tune)
+{
+  if (tune.insn_extra_cost)
+    parse_nested_object (jo, "insn_extra_cost", parse_insn_extra_cost,
+                        *tune.insn_extra_cost);
+  if (tune.regmove_cost)
+    parse_nested_object (jo, "regmove_cost", parse_regmove_cost,
+                        *tune.regmove_cost);
+  if (tune.addr_cost)
+    parse_nested_object (jo, "addr_cost", parse_addr_cost, *tune.addr_cost);
+  if (tune.vec_costs)
+    parse_nested_object (jo, "vec_costs", parse_vec_costs, *tune.vec_costs);
+  if (tune.branch_costs)
+    parse_nested_object (jo, "branch_costs", parse_branch_costs,
+                        *tune.branch_costs);
+  if (tune.approx_modes)
+    parse_nested_object (jo, "approx_modes", parse_approx_modes,
+                        *tune.approx_modes);
+  PARSE_INTEGER_FIELD (jo, "sve_width", tune.sve_width);
+  parse_nested_object (jo, "memmov_cost", parse_memmov_cost, tune.memmov_cost);
+  PARSE_INTEGER_FIELD (jo, "issue_rate", tune.issue_rate);
+  PARSE_INTEGER_FIELD (jo, "fusible_ops", tune.fusible_ops);
+  PARSE_STRING_FIELD (jo, "function_align", tune.function_align);
+  PARSE_STRING_FIELD (jo, "jump_align", tune.jump_align);
+  PARSE_STRING_FIELD (jo, "loop_align", tune.loop_align);
+  PARSE_INTEGER_FIELD (jo, "int_reassoc_width", tune.int_reassoc_width);
+  PARSE_INTEGER_FIELD (jo, "fp_reassoc_width", tune.fp_reassoc_width);
+  PARSE_INTEGER_FIELD (jo, "fma_reassoc_width", tune.fma_reassoc_width);
+  PARSE_INTEGER_FIELD (jo, "vec_reassoc_width", tune.vec_reassoc_width);
+  PARSE_INTEGER_FIELD (jo, "min_div_recip_mul_sf", tune.min_div_recip_mul_sf);
+  PARSE_INTEGER_FIELD (jo, "min_div_recip_mul_df", tune.min_div_recip_mul_df);
+  PARSE_INTEGER_FIELD (jo, "max_case_values", tune.max_case_values);
+  parse_autoprefetcher_model (jo, "autoprefetcher_model",
+                             tune.autoprefetcher_model);
+  PARSE_INTEGER_FIELD (jo, "extra_tuning_flags", tune.extra_tuning_flags);
+  if (tune.prefetch)
+    parse_nested_object (jo, "prefetch", parse_prefetch, *tune.prefetch);
+  parse_aarch64_ldp_stp_policy (jo, "ldp_policy_model", tune.ldp_policy_model);
+  parse_aarch64_ldp_stp_policy (jo, "stp_policy_model", tune.stp_policy_model);
+}
+
+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 (schema_value->get_kind () == json::JSON_OBJECT)
+       {
+         if (json_value->get_kind () != json::JSON_OBJECT)
+           {
+             error ("key %qs expected to be an object", full_key.c_str ());
+             return false;
+           }
+
+         const auto *sub_schema_obj
+           = static_cast<const json::object *> (schema_value);
+         const auto *sub_json_obj
+           = static_cast<const json::object *> (json_value);
+         if (!validate_and_traverse (sub_json_obj, sub_schema_obj, full_key))
+           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 (schema_value->get_kind () == json::JSON_STRING)
+       {
+         const auto *schema_type_str
+           = static_cast<const json::string *> (schema_value)->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
+           {
+             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;
+}
+
+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;
+}
+
+       void
+aarch64_load_tuning_params_from_json_string (const char *json_string,
+                                            const char *schema_string,
+                                            struct tune_params *tune)
+{
+  json::parser_result_t data_result
+    = json::parse_utf8_string (strlen (json_string), json_string, false,
+                              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 || root->get_kind () != json::JSON_OBJECT)
+    {
+      warning (0, "no JSON object found in the provided data");
+      return;
+    }
+  const json::object *root_obj
+    = static_cast<const json::object *> (root.get ());
+
+  json::parser_result_t schema_result (
+    json::parse_utf8_string (strlen (schema_string), schema_string, false,
+                            nullptr));
+
+  if (auto json_err = schema_result.m_err.get ())
+    {
+      error ("error parsing JSON schema: %s", json_err->get_msg ());
+      return;
+    }
+
+  const std::unique_ptr<json::value> &schema_root = schema_result.m_val;
+  if (!schema_root || schema_root->get_kind () != json::JSON_OBJECT)
+    {
+      error ("no JSON object found in the provided schema");
+      return;
+    }
+  const json::object *schema_obj
+    = static_cast<const json::object *> (schema_root.get ());
+
+  json::object *jo
+    = static_cast<json::object *> (root_obj->get ("tune_params"));
+  if (!jo)
+    {
+      warning (0, "key %<tune_params%> not found in JSON data");
+      return;
+    }
+
+  if (!validate_and_traverse (root_obj, schema_obj))
+    {
+      error ("validation failed for the provided JSON data");
+      return;
+    }
+
+  parse_tunings (jo, *tune);
+  return;
+}
+
+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);
+}
+
+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, 
&params);
+
+  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";
+
+  tune_params params;
+  params.insn_extra_cost = new cpu_cost_table;
+
+  aarch64_load_tuning_params_from_json_string (test_json, schema_json, 
&params);
+
+  ASSERT_EQ (params.insn_extra_cost->alu.non_exec_costs_exec, false);
+
+  delete params.insn_extra_cost;
+}
+
+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, 
&params);
+
+  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, 
&params);
+
+  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_boolean ();
+  test_json_strings ();
+  test_json_enums ();
+}
+
+} // namespace selftest
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..3c608ea497b
--- /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 2bbed9d2e54..70dc27f2487 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -98,6 +98,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"
@@ -18580,6 +18581,10 @@ aarch64_override_options_internal (struct gcc_options 
*opts)
   /* Make a copy of the tuning parameters attached to the core, which
      we may later overwrite.  */
   aarch64_tune_params = *(tune->tune);
+  if (opts->x_muser_provided_CPU)
+    aarch64_load_tuning_params_from_json (opts->x_muser_provided_CPU,
+                                         &aarch64_tune_params);
+
   if (tune->tune == &generic_tunings)
     aarch64_adjust_generic_arch_tuning (aarch64_tune_params);
 
diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt
index 4c8ea2eb323..50245cfcf19 100644
--- a/gcc/config/aarch64/aarch64.opt
+++ b/gcc/config/aarch64/aarch64.opt
@@ -192,6 +192,10 @@ fdump-tuning-model=
 Target RejectNegative Negative(fdump-tuning-model=) ToLower Joined 
Var(fdump_tuning_model)
 Dump current tuning model to a JSON file.
 
+muser-provided-CPU=
+Target RejectNegative Negative(muser-provided-CPU=) ToLower Joined 
Var(muser_provided_CPU)
+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 c5002eab595..96685d19274 100644
--- a/gcc/config/aarch64/t-aarch64
+++ b/gcc/config/aarch64/t-aarch64
@@ -206,6 +206,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 c4da84a275e..4d575595539 100644
--- a/gcc/selftest-run-tests.cc
+++ b/gcc/selftest-run-tests.cc
@@ -76,6 +76,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 5adfa908fd3..7baccadf19d 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -241,6 +241,7 @@ extern void hash_set_tests_cc_tests ();
 extern void input_cc_tests ();
 extern void json_cc_tests ();
 extern void lazy_diagnostic_path_cc_tests ();
+extern void json_tunings_tests();
 extern void json_parser_cc_tests ();
 extern void optinfo_emit_json_cc_tests ();
 extern void opts_cc_tests ();
-- 
2.44.0

Reply via email to